Force projector implementation

This commit is contained in:
Anuken 2018-09-07 23:24:55 -04:00
parent d046591512
commit 7dd487ccc5
20 changed files with 968 additions and 797 deletions

View file

@ -27,7 +27,7 @@ allprojects {
appName = 'Mindustry'
gdxVersion = '1.9.8'
roboVMVersion = '2.3.0'
uCoreVersion = '33a2bc650be42394821acad06aceb6f9ba74e77a'
uCoreVersion = 'd4c099a41403659e2c35cfd05ae79b610b9c3ae5'
getVersionString = {
String buildVersion = getBuildVersion()

Binary file not shown.

After

Width:  |  Height:  |  Size: 211 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 637 B

After

Width:  |  Height:  |  Size: 631 B

Before After
Before After

View file

@ -289,6 +289,7 @@ text.blocks.liquidcapacity=Liquid Capacity
text.blocks.maxitemssecond=Max Items
text.blocks.powerrange=Power Range
text.blocks.poweruse=Power Use
text.blocks.powerdamage=Power/Damage
text.blocks.inputitemcapacity=Input Item Capacity
text.blocks.outputitemcapacity=Output Item Capacity
text.blocks.itemcapacity=Item Capacity

View file

@ -30,19 +30,19 @@ void main() {
vec2 T = v_texCoord.xy;
vec2 coords = (T * u_texsize) + u_offset;
T += vec2(sin(coords.y / 3.0 + u_time / 20.0) / 240.0, sin(coords.x / 3.0 + u_time / 20.0) / 240.0) * u_scaling;
float si = 1.0 + sin(u_time / 20.0) / 8.0;
float si = sin(u_time / 20.0) / 8.0;
vec4 color = texture2D(u_texture, T) * vec4(si, si, si, 1.0);
vec4 color = texture2D(u_texture, T);
vec2 v = vec2(1.0/u_texsize.x, 1.0/u_texsize.y);
bool any = false;
float thickness = 1.0;
float step = 1.5;
float step = 2.0;
if(texture2D(u_texture, T).a < 0.1 &&
(texture2D(u_texture, T + vec2(0, step) * v).a > 0.1 || texture2D(u_texture, T + vec2(0, -step) * v).a > 0.1 ||
@ -50,7 +50,7 @@ void main() {
any = true;
if(any){
gl_FragColor = u_color * vec4(si, si, si, 1.0);
gl_FragColor = mix(u_color, vec4(1.0), si);
}else{
if(color.a > 0.1){
@ -67,7 +67,7 @@ void main() {
float fin = 1.0 - hit.z;
if(abs(distance(vec2(hit.x, hit.y), coords - u_texsize/2.0) - rad) < 1.0){
color = mix(color, u_color* vec4(si, si, si, 1.0), (1.0 * fin));
color = mix(color, mix(u_color, vec4(1.0), si), (1.0 * fin));
color.a = ALPHA + 0.82 *fin;
}
}

File diff suppressed because it is too large Load diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 98 KiB

After

Width:  |  Height:  |  Size: 97 KiB

Before After
Before After

View file

@ -17,6 +17,7 @@ import io.anuke.mindustry.entities.units.BaseUnit;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.game.Version;
import io.anuke.mindustry.net.Net;
import io.anuke.mindustry.world.blocks.defense.ForceProjector.ShieldEntity;
import io.anuke.ucore.entities.Entities;
import io.anuke.ucore.entities.EntityGroup;
import io.anuke.ucore.entities.impl.EffectEntity;
@ -129,7 +130,7 @@ public class Vars{
public static EntityGroup<EffectEntity> effectGroup;
public static EntityGroup<DrawTrait> groundEffectGroup;
public static EntityGroup<ItemDrop> itemGroup;
public static EntityGroup<ShieldEntity> shieldGroup;
public static EntityGroup<Puddle> puddleGroup;
public static EntityGroup<Fire> fireGroup;
public static EntityGroup<BaseUnit>[] unitGroups;
@ -163,6 +164,7 @@ public class Vars{
groundEffectGroup = Entities.addGroup(DrawTrait.class, false);
puddleGroup = Entities.addGroup(Puddle.class, false).enableMapping();
itemGroup = Entities.addGroup(ItemDrop.class).enableMapping();
shieldGroup = Entities.addGroup(ShieldEntity.class);
fireGroup = Entities.addGroup(Fire.class, false).enableMapping();
unitGroups = new EntityGroup[Team.all.length];

View file

@ -77,13 +77,13 @@ public class DefenseBlocks extends BlockList implements ContentList{
}};
overdriveProjector = new OverdriveProjector("overdrive-projector"){{
consumes.power(0.25f);
consumes.power(0.35f);
size = 2;
consumes.item(Items.phasematter).optional(true);
}};
forceProjector = new ForceProjector("force-projector"){{
consumes.power(0.25f);
consumes.power(0.2f);
size = 3;
consumes.item(Items.phasematter).optional(true);
}};

View file

@ -19,7 +19,8 @@ public class BlockFx extends FxList implements ContentList{
public static Effect reactorsmoke, nuclearsmoke, nuclearcloud, redgeneratespark, generatespark, fuelburn, plasticburn,
pulverize, pulverizeRed, pulverizeRedder, pulverizeSmall, pulverizeMedium, producesmoke, smeltsmoke, formsmoke, blastsmoke,
lava, dooropen, doorclose, dooropenlarge, doorcloselarge, purify, purifyoil, purifystone, generate, mine, mineBig, mineHuge,
smelt, teleportActivate, teleport, teleportOut, ripple, bubble, commandSend, healBlock, healBlockFull, healWaveMend, overdriveWave, overdriveBlockFull;
smelt, teleportActivate, teleport, teleportOut, ripple, bubble, commandSend, healBlock, healBlockFull, healWaveMend, overdriveWave,
overdriveBlockFull, shieldBreak;
@Override
public void load(){
@ -315,9 +316,16 @@ public class BlockFx extends FxList implements ContentList{
overdriveBlockFull = new Effect(60, e -> {
Draw.color(e.color);
Draw.alpha(e.fslope() * 0.5f);
Draw.alpha(e.fslope() * 0.4f);
Fill.square(e.x, e.y, e.rotation * tilesize);
Draw.color();
});
shieldBreak = new Effect(40, e -> {
Draw.color(Color.WHITE);
Lines.stroke(3f * e.fout());
Lines.poly(e.x, e.y, 6, e.rotation, 90);
Draw.reset();
});
}
}

View file

@ -136,6 +136,7 @@ public class Logic extends Module{
}
Entities.update(puddleGroup);
Entities.update(tileGroup);
Entities.update(shieldGroup);
Entities.update(bulletGroup);
Entities.update(fireGroup);
Entities.update(playerGroup);

View file

@ -20,8 +20,12 @@ import io.anuke.mindustry.entities.units.BaseUnit;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.graphics.*;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.blocks.defense.ForceProjector.ShieldEntity;
import io.anuke.mindustry.world.meta.BlockFlag;
import io.anuke.ucore.core.*;
import io.anuke.ucore.core.Core;
import io.anuke.ucore.core.Effects;
import io.anuke.ucore.core.Graphics;
import io.anuke.ucore.core.Settings;
import io.anuke.ucore.entities.EntityDraw;
import io.anuke.ucore.entities.EntityGroup;
import io.anuke.ucore.entities.impl.EffectEntity;
@ -269,6 +273,13 @@ public class Renderer extends RendererModule{
drawAndInterpolate(playerGroup, p -> true, Player::drawBuildRequests);
overlays.drawTop();
Shaders.shield.color.set(Palette.accent);
Graphics.beginShaders(Shaders.shield);
EntityDraw.draw(shieldGroup);
EntityDraw.drawWith(shieldGroup, shield -> true, shield -> ((ShieldEntity)shield).drawOver());
Graphics.endShaders();
if(showPaths && debug) drawDebug();
Graphics.flushSurface();

View file

@ -260,7 +260,7 @@ public class TileEntity extends BaseEntity implements TargetTrait, HealthTrait{
}
timeScaleDuration -= Timers.delta();
if(timeScaleDuration <= 0f){
if(timeScaleDuration <= 0f || !tile.block().canOverdrive){
timeScale = 1f;
}

View file

@ -170,7 +170,7 @@ public class Shaders{
public static class Shield extends Shader{
public static final int MAX_HITS = 3 * 64;
public Color color = new Color();
public FloatArray hits;
public FloatArray hits = new FloatArray();
public Shield(){
super("shield", "default");

View file

@ -103,6 +103,8 @@ public class Block extends BaseBlock {
public boolean turretIcon = false;
/**Whether units target this block.*/
public boolean targetable = true;
/**Whether the overdrive core has any effect on this block.*/
public boolean canOverdrive = true;
protected Array<Tile> tempTiles = new Array<>();
protected Color tempColor = new Color();

View file

@ -1,29 +1,64 @@
package io.anuke.mindustry.world.blocks.defense;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import io.anuke.mindustry.content.fx.BlockFx;
import io.anuke.mindustry.content.fx.BulletFx;
import io.anuke.mindustry.entities.TileEntity;
import io.anuke.mindustry.entities.bullet.Bullet;
import io.anuke.mindustry.entities.traits.SyncTrait;
import io.anuke.mindustry.graphics.Palette;
import io.anuke.mindustry.world.Block;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.consumers.ConsumeLiquidFilter;
import io.anuke.mindustry.world.meta.BlockStat;
import io.anuke.mindustry.world.meta.StatUnit;
import io.anuke.ucore.core.Effects;
import io.anuke.ucore.core.Graphics;
import io.anuke.ucore.core.Timers;
import io.anuke.ucore.entities.EntityGroup;
import io.anuke.ucore.entities.EntityPhysics;
import io.anuke.ucore.entities.impl.BaseEntity;
import io.anuke.ucore.entities.trait.DrawTrait;
import io.anuke.ucore.graphics.Draw;
import io.anuke.ucore.graphics.Fill;
import io.anuke.ucore.util.Mathf;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.io.*;
import static io.anuke.mindustry.Vars.bulletGroup;
import static io.anuke.mindustry.Vars.*;
public class ForceProjector extends Block {
protected float radius = 100f;
protected float breakage = 500f;
protected float cooldownNormal = 1.5f;
protected float cooldownLiquid = 1.5f;
protected float cooldownBrokenBase = 0.3f;
protected float powerDamage = 0.1f;
protected TextureRegion topRegion;
public ForceProjector(String name) {
super(name);
update = true;
solid = true;
hasPower = true;
canOverdrive = false;
hasLiquids = true;
powerCapacity = 60f;
consumes.add(new ConsumeLiquidFilter(liquid -> liquid.temperature <= 0.5f && liquid.flammability < 0.1f, 0.1f)).optional(true).update(false);
}
@Override
public void load(){
super.load();
topRegion = Draw.region(name + "-top");
}
@Override
public void setStats(){
super.setStats();
stats.add(BlockStat.powerDamage, powerDamage, StatUnit.powerUnits);
}
@Override
@ -34,6 +69,83 @@ public class ForceProjector extends Block {
entity.shield = new ShieldEntity(tile);
entity.shield.add();
}
entity.radscl = Mathf.lerpDelta(entity.radscl, entity.broken ? 0f : 1f, 0.05f);
if(Mathf.chance(Timers.delta() * entity.buildup / breakage * 0.1f)){
Effects.effect(BlockFx.reactorsmoke, tile.drawx() + Mathf.range(tilesize/2f), tile.drawy() + Mathf.range(tilesize/2f));
}
if(!entity.cons.valid()){
entity.warmup = Mathf.lerpDelta(entity.warmup, 0f, 0.1f);
if(entity.warmup <= 0.09f){
entity.broken = true;
}
}else{
entity.warmup = Mathf.lerpDelta(entity.warmup, 1f, 0.1f);
float powerUse = Math.min(powerDamage * entity.delta() * (1f + entity.buildup / breakage), powerCapacity);
entity.power.amount -= powerUse;
}
if(entity.buildup > 0){
float scale = !entity.broken ? cooldownNormal : cooldownBrokenBase;
if(consumes.get(ConsumeLiquidFilter.class).valid(this, entity)){
consumes.get(ConsumeLiquidFilter.class).update(this, entity);
scale *= (cooldownLiquid * (1f+(entity.liquids.current().heatCapacity-0.4f)*0.9f));
}
entity.buildup -= Timers.delta()*scale;
}
if(entity.broken && entity.buildup <= 0 && entity.warmup >= 0.9f){
entity.broken = false;
}
if(entity.buildup >= breakage && !entity.broken){
entity.broken = true;
entity.buildup = breakage;
Effects.effect(BlockFx.shieldBreak, tile.drawy(), tile.drawy(), radius);
}
if(entity.hit > 0f){
entity.hit -= 1f/5f * Timers.delta();
}
if(!entity.broken){
EntityPhysics.getNearby(bulletGroup, tile.drawx(), tile.drawy(), radius * entity.radscl*2f, bullet -> {
if(bullet instanceof Bullet && ((Bullet) bullet).getTeam() != tile.getTeam() && isInsideHexagon(bullet.getX(), bullet.getY(), radius * 2f * entity.radscl, tile.drawx(), tile.drawy())){
((Bullet) bullet).absorb();
Effects.effect(BulletFx.absorb, bullet);
float hit = ((Bullet) bullet).getDamage()*powerDamage;
entity.hit = 1f;
entity.power.amount -= Math.min(hit, entity.power.amount);
entity.buildup += ((Bullet) bullet).getDamage() * entity.warmup;
}
});
}
}
boolean isInsideHexagon(float x0, float y0, float d, float x, float y) {
float dx = Math.abs(x - x0)/d;
float dy = Math.abs(y - y0)/d;
float a = 0.25f * Mathf.sqrt3;
return (dy <= a) && (a*dx + 0.25*dy <= 0.5*a);
}
@Override
public void draw(Tile tile){
super.draw(tile);
ForceEntity entity = tile.entity();
if(entity.buildup <= 0f) return;
Draw.alpha(entity.buildup / breakage * 0.75f/* * Mathf.absin(Timers.time(), 10f - (entity.buildup/breakage)*6f, 1f)*/);
Graphics.setAdditiveBlending();
Draw.rect(topRegion, tile.drawx(), tile.drawy());
Graphics.setNormalBlending();
Draw.reset();
}
@Override
@ -43,41 +155,68 @@ public class ForceProjector extends Block {
class ForceEntity extends TileEntity{
ShieldEntity shield;
boolean broken = true;
float buildup = 0f;
float radscl = 0f;
float hit;
float warmup;
@Override
public void write(DataOutputStream stream) throws IOException{
stream.writeBoolean(broken);
stream.writeFloat(buildup);
stream.writeFloat(radscl);
stream.writeFloat(warmup);
}
@Override
public void read(DataInputStream stream) throws IOException{
broken = stream.readBoolean();
buildup = stream.readFloat();
radscl = stream.readFloat();
warmup = stream.readFloat();
}
}
class ShieldEntity extends BaseEntity implements DrawTrait, SyncTrait{
final Tile tile;
final ForceProjector block;
public class ShieldEntity extends BaseEntity implements DrawTrait, SyncTrait{
final ForceEntity entity;
public ShieldEntity(Tile tile){
this.tile = tile;
this.block = (ForceProjector)tile.block();
this.entity = tile.entity();
set(tile.drawx(), tile.drawy());
}
@Override
public void update(){
if(entity.isDead() || !entity.isAdded()){
remove();
}
}
@Override
public float drawSize(){
return radius*2f+2f*entity.radscl;
}
@Override
public void draw(){
Draw.color(Palette.accent);
Draw.alpha(0.5f);
Fill.polyTri(x, y, 6, radius*entity.radscl);
Draw.color();
}
int range = 3;
float rad = 12f;
float space = rad*2-2f;
for (int y = -range; y <= range; y++) {
for (int x = -range; x <= range; x++) {
//if(Mathf.dst(x, y) > range) continue;
float wx = tile.drawx() + x * space + ((y + range) % 2)*space/2f;
float wy = tile.drawy() + y * (space-1);
Fill.poly(wx, wy, 6, rad);
}
}
public void drawOver(){
if(entity.hit <= 0f) return;
Draw.color(Color.WHITE);
Draw.alpha(entity.hit);
Fill.polyTri(x, y, 6, radius*entity.radscl);
Draw.color();
}
@Override
public EntityGroup targetGroup(){
return bulletGroup;
return shieldGroup;
}
@Override

View file

@ -52,7 +52,7 @@ public class MendProjector extends Block{
public void update(Tile tile){
MendEntity entity = tile.entity();
entity.heat = Mathf.lerpDelta(entity.heat, entity.cons.valid() ? 1f : 0f, 0.08f);
entity.charge += entity.heat * Timers.delta();
entity.charge += entity.heat * entity.delta();
entity.phaseHeat = Mathf.lerpDelta(entity.phaseHeat, (float)entity.items.get(consumes.item()) / itemCapacity, 0.1f);

View file

@ -27,9 +27,9 @@ public class OverdriveProjector extends Block{
protected int timerUse = timers ++;
protected TextureRegion topRegion;
protected float reload = 250f;
protected float reload = 260f;
protected float range = 80f;
protected float speedBoost = 2f;
protected float speedBoost = 1.5f;
protected float speedBoostPhase = 0.5f;
protected float useTime = 300f;
@ -39,6 +39,7 @@ public class OverdriveProjector extends Block{
update = true;
hasPower = true;
hasItems = true;
canOverdrive = false;
itemCapacity = 10;
}
@ -67,28 +68,26 @@ public class OverdriveProjector extends Block{
Effects.effect(BlockFx.overdriveWave, Hue.mix(color, phase, entity.phaseHeat), tile.drawx(), tile.drawy(), realRange);
entity.charge = 0f;
Timers.run(10f, () -> {
int tileRange = (int)(realRange / tilesize);
healed.clear();
int tileRange = (int)(realRange / tilesize);
healed.clear();
for(int x = -tileRange + tile.x; x <= tileRange + tile.x; x++){
for(int y = -tileRange + tile.y; y <= tileRange + tile.y; y++){
if(Vector2.dst(x, y, tile.x, tile.y) > realRange) continue;
for(int x = -tileRange + tile.x; x <= tileRange + tile.x; x++){
for(int y = -tileRange + tile.y; y <= tileRange + tile.y; y++){
if(Vector2.dst(x, y, tile.x, tile.y) > realRange) continue;
Tile other = world.tile(x, y);
Tile other = world.tile(x, y);
if(other == null) continue;
other = other.target();
if(other == null) continue;
other = other.target();
if(other.getTeamID() == tile.getTeamID() && !healed.contains(other.packedPosition()) && other.entity != null){
other.entity.timeScaleDuration = Math.max(other.entity.timeScaleDuration, reload + 1f);
other.entity.timeScale = Math.max(other.entity.timeScale, realBoost);
Effects.effect(BlockFx.overdriveBlockFull, Hue.mix(color, phase, entity.phaseHeat), other.drawx(), other.drawy(), other.block().size);
healed.add(other.packedPosition());
}
if(other.getTeamID() == tile.getTeamID() && !healed.contains(other.packedPosition()) && other.entity != null){
other.entity.timeScaleDuration = Math.max(other.entity.timeScaleDuration, reload + 1f);
other.entity.timeScale = Math.max(other.entity.timeScale, realBoost);
Effects.effect(BlockFx.overdriveBlockFull, Hue.mix(color, phase, entity.phaseHeat), other.drawx(), other.drawy(), other.block().size);
healed.add(other.packedPosition());
}
}
});
}
}
}

View file

@ -99,7 +99,7 @@ public class Conveyor extends Block{
ConveyorEntity entity = tile.entity();
byte rotation = tile.getRotation();
int frame = entity.clogHeat <= 0.5f ? (int) ((Timers.time() / 4f) % 4) : 0;
int frame = entity.clogHeat <= 0.5f ? (int) (((Timers.time() * speed * 8f * entity.timeScale)) % 4) : 0;
Draw.rect(regions[Mathf.clamp(entity.blendbits, 0, regions.length - 1)][Mathf.clamp(frame, 0, regions[0].length - 1)], tile.drawx(), tile.drawy(),
tilesize * entity.blendsclx, tilesize * entity.blendscly, rotation*90);
}

View file

@ -23,6 +23,7 @@ public enum BlockStat{
powerCapacity(StatCategory.power),
powerUse(StatCategory.power),
powerDamage(StatCategory.power),
powerRange(StatCategory.power),
powerTransferSpeed(StatCategory.power),
maxPowerGeneration(StatCategory.power),