diff --git a/src/META-INF/MANIFEST.MF b/src/META-INF/MANIFEST.MF new file mode 100644 index 0000000..342ad40 --- /dev/null +++ b/src/META-INF/MANIFEST.MF @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Main-Class: com.youngdev.shooter.Main + diff --git a/src/RETRO.TTF b/src/RETRO.TTF new file mode 100644 index 0000000..87c9280 Binary files /dev/null and b/src/RETRO.TTF differ diff --git a/src/Righteous-Regular.ttf b/src/Righteous-Regular.ttf new file mode 100644 index 0000000..07fc0b4 Binary files /dev/null and b/src/Righteous-Regular.ttf differ diff --git a/src/com/youngdev/shooter/Arrow.java b/src/com/youngdev/shooter/Arrow.java new file mode 100644 index 0000000..bebf1b8 --- /dev/null +++ b/src/com/youngdev/shooter/Arrow.java @@ -0,0 +1,137 @@ +package com.youngdev.shooter; + +import com.engine.libs.game.GameObject; +import com.engine.libs.game.Mask; +import com.engine.libs.input.Input; +import com.engine.libs.math.AdvancedMath; +import com.engine.libs.math.BasicMath; +import com.engine.libs.rendering.Renderer; + +import java.awt.*; +import java.awt.image.BufferedImage; +import java.util.ArrayList; +import java.util.Random; + +public class Arrow extends GameObject { + public int dir, wiggleStep; + private double xD, yD; + public double addX, addY; + private ArrayList particles; + public boolean shotByFriendly; + private static final boolean UseParticles = false; + public Random random; + + public static final float SPEED = 6; + + public Arrow(int x, int y, int dir) { + super(1, 13); + this.x = x; + this.y = y; + this.xD = x; + this.yD = y; + this.dir = dir; + + // HERE: Fix depth + this.random = new Random(); + this.depth = random.nextInt(1023)+depth*1024; + + wiggleStep = random.nextInt(359); + if(UseParticles) + particles = new ArrayList<>(); + + mask = new Mask.Rectangle(x-8, y-8, 16, 16); + } + + @Override + public void update(Input input) { + + wiggleStep = Main.toSlowMotion((wiggleStep+16)%359); + + xD += Main.toSlowMotion(addX); + yD += Main.toSlowMotion(addY); + + addX -= Math.signum(addX)*Main.toSlowMotion(0.25); + addY -= Math.signum(addY)*Main.toSlowMotion(0.25); + + xD += Main.toSlowMotion(Math.cos(Math.toRadians(dir))*SPEED); + yD += Main.toSlowMotion(Math.sin(Math.toRadians(dir))*SPEED); + + + x = (int)xD; + y = (int)yD; + +// System.out.println("X: "+xx); +// System.out.println("Y: "+yy); + + + if(UseParticles) { + int addWiggleX = (int) (Math.cos(Math.toRadians(wiggleStep)) * 4); + int addWiggleY = (int) (Math.sin(Math.toRadians(wiggleStep)) * 4); + if (random.nextBoolean()) { + int dir = random.nextInt(359); + int tone = random.nextInt(20); + int sDir = random.nextInt(359); + int sDistance = random.nextInt(4); + int xx = (int) x + (int) (Math.cos(Math.toRadians(sDir)) * sDistance) + addWiggleX; + int yy = (int) y + (int) (Math.sin(Math.toRadians(sDir)) * sDistance) + addWiggleY; + Color color = new Color(tone, tone, tone); + int fadingSpeed = random.nextInt(8) + 20; + UniParticle.FadingProcess fadingProcess = new UniParticle.FadingProcess(255, fadingSpeed, true); + particles.add(new UniParticle(xx, yy, random.nextBoolean() ? 4 : 2, true, color, fadingProcess)); +// leaf.add(new Particle(xx, yy, 4, dir, tone, Color.red)); + } + + // HERE: Update leaf and remove dead ones + particles.forEach(UniParticle::update); + particles.removeIf(particle -> particle.dead); + } + } + + @Override + public void render(Renderer r) { +// r.drawLine(Main.main.player.xx, Main.main.player.yy, xx, yy, Color.black); +// r.fillRectangle(xx, yy, 16, 16, Color.red); + + if(UseParticles) + particles.forEach(p -> p.render(r)); + else { + double[] xPs1 = new double[]{ + x + Math.cos(Math.toRadians(dir+45))*4, + x + Math.cos(Math.toRadians(dir+135))*4, + x + Math.cos(Math.toRadians(dir+225))*4, + x + Math.cos(Math.toRadians(dir+315))*4 + }; + double[] yPs1 = new double[]{ + y + Math.sin(Math.toRadians(dir+45))*4, + y + Math.sin(Math.toRadians(dir+135))*4, + y + Math.sin(Math.toRadians(dir+225))*4, + y + Math.sin(Math.toRadians(dir+315))*4 + }; + double[] xPs2 = new double[]{ + x + Math.cos(Math.toRadians(dir+45))*2, + x + Math.cos(Math.toRadians(dir+135))*2, + x + Math.cos(Math.toRadians(dir+225))*2, + x + Math.cos(Math.toRadians(dir+315))*2 + }; + double[] yPs2 = new double[]{ + y + Math.sin(Math.toRadians(dir+45))*2, + y + Math.sin(Math.toRadians(dir+135))*2, + y + Math.sin(Math.toRadians(dir+225))*2, + y + Math.sin(Math.toRadians(dir+315))*2 + + }; + r.fillPolygon(xPs1, yPs1, 4, new Color(255, 200, 40)); + r.fillPolygon(xPs2, yPs2, 4, new Color(255, 255, 240)); + } + } + + @Override + public String shareSend() { + return null; + } + + @Override + public void shareReceive(String s) { + + } +} diff --git a/src/com/youngdev/shooter/Camera.java b/src/com/youngdev/shooter/Camera.java new file mode 100644 index 0000000..e9b3367 --- /dev/null +++ b/src/com/youngdev/shooter/Camera.java @@ -0,0 +1,54 @@ +package com.youngdev.shooter; + +import com.engine.libs.game.GameObject; +import com.engine.libs.math.AdvancedMath; +import com.engine.libs.rendering.Renderer; + +import java.util.Random; + +public class Camera { + public double cX, cY; + private double shakeX, shakeY, shakeAmount; + private int width, height; + public float bluishEffect; + public GameObject target; + private Random random; + + public Camera(int width, int height, GameObject target) { + this.width = width; + this.height = height; + this.target = target; + this.cX = target.x-width/2; + this.cY = target.y-height/2; + bluishEffect = 1f; + this.shakeX = 0d; + this.shakeY = 0d; + this.shakeAmount = 0f; + + random = new Random(); + } + + public void update() { + if(shakeAmount != 0) { + shakeX = Main.toSlowMotion(random.nextFloat() * shakeAmount * 2 - shakeAmount); + shakeY = Main.toSlowMotion(random.nextFloat() * shakeAmount * 2 - shakeAmount); + shakeAmount *= Main.toSlowMotion(0.9f); + } else { + shakeX = 0; + shakeY = 0; + } + + cX += Main.toSlowMotion((target.x - cX - width/2d) * 0.1d); + cY += Main.toSlowMotion((target.y - cY - height/2d) * 0.1d); + } + + public void shake(float amount) { + shakeAmount += amount; +// shakeAmount /= amount; + } + + public void apply(Renderer r) { + r.setCamX((int)cX + (int)shakeX); + r.setCamY((int)cY + (int)shakeY); + } +} diff --git a/src/com/youngdev/shooter/Coin.java b/src/com/youngdev/shooter/Coin.java new file mode 100644 index 0000000..c774499 --- /dev/null +++ b/src/com/youngdev/shooter/Coin.java @@ -0,0 +1,123 @@ +package com.youngdev.shooter; + +import com.engine.libs.game.GameObject; +import com.engine.libs.game.Mask; +import com.engine.libs.input.Input; +import com.engine.libs.rendering.Renderer; + +import java.awt.*; +import java.util.Random; + +public class Coin extends GameObject { + + public double speed, rotation, rotationSpeed, xD, yD, angle; + + public Coin(int x, int y, double angle) { + super(2, 11); + + // HERE: Fix depth + Random random = new Random(); + this.depth = random.nextInt(1023)+depth*1024; + + this.x = x; + this.y = y; + this.xD = x; + this.yD = y; + this.angle = angle; + + this.speed = random.nextDouble()+3; + this.rotationSpeed = 8; + this.rotation = random.nextInt(359); + + this.mask = new Mask.Rectangle(x-8, y-8, 16, 16); + } + + @Override + public void update(Input input) { + this.speed *= 0.9; + this.rotationSpeed *= 0.95; + this.rotation += rotationSpeed; + + if(Fly.distance(xD, yD, Main.main.player.x, Main.main.player.y) < 24d) { + if(Fly.distance(xD, yD, Main.main.player.x, Main.main.player.y) < 4d) { + dead = true; + Main.main.player.lastCoinX = xD; + Main.main.player.lastCoinY = yD; + Main.main.player.coinOverlayAlpha = 255; + Main.main.player.money += 2; + } else { + angle = Fly.angle(xD, yD, Main.main.player.x, Main.main.player.y)-180; + speed = 4d; + } + } + + double addX = Math.cos(Math.toRadians(angle))*speed; + double addY = Math.sin(Math.toRadians(angle))*speed; + + this.xD += addX; + this.yD += addY; + + this.x = xD; + this.y = yD; + + this.mask.move(addX, addY); + } + + @Override + public void render(Renderer r) { +// r.fillRectangle(x, y, 8, 8, Color.yellow); + + int x1 = (int)(xD+Math.cos(Math.toRadians(rotation))*5d); + int y1 = (int)(yD+Math.sin(Math.toRadians(rotation))*5d); + int x2 = (int)(xD+Math.cos(Math.toRadians(rotation-90))*5d); + int y2 = (int)(yD+Math.sin(Math.toRadians(rotation-90))*5d); + int x3 = (int)(xD+Math.cos(Math.toRadians(rotation-180))*5d); + int y3 = (int)(yD+Math.sin(Math.toRadians(rotation-180))*5d); + int x4 = (int)(xD+Math.cos(Math.toRadians(rotation-270))*5d); + int y4 = (int)(yD+Math.sin(Math.toRadians(rotation-270))*5d); + + r.fillPolygon(new int[]{x1, x2, x3, x4}, new int[]{y1, y2, y3, y4}, Color.yellow); + + x1 = (int)(xD+Math.cos(Math.toRadians(rotation))*3d); + y1 = (int)(yD+Math.sin(Math.toRadians(rotation))*3d); + x2 = (int)(xD+Math.cos(Math.toRadians(rotation-90))*3d); + y2 = (int)(yD+Math.sin(Math.toRadians(rotation-90))*3d); + x3 = (int)(xD+Math.cos(Math.toRadians(rotation-180))*3d); + y3 = (int)(yD+Math.sin(Math.toRadians(rotation-180))*3d); + x4 = (int)(xD+Math.cos(Math.toRadians(rotation-270))*3d); + y4 = (int)(yD+Math.sin(Math.toRadians(rotation-270))*3d); + + r.fillPolygon(new int[]{x1, x2, x3, x4}, new int[]{y1, y2, y3, y4}, Color.orange); + +// x1 = (int)(xD+Math.cos(Math.toRadians(rotation))*2d); +// y1 = (int)(yD+Math.sin(Math.toRadians(rotation))*2d); +// x2 = (int)(xD+Math.cos(Math.toRadians(rotation-180))*2d); +// y2 = (int)(yD+Math.sin(Math.toRadians(rotation-180))*2d); +// +// r.fillPolygon(new int[]{x1, x2, x2, x1}, new int[]{y1+2, y2+2, y2+6, y1+6}, Color.orange); + + /*int x1 = (int)(xD+Math.cos(Math.toRadians(rotation))*4d); + int y1 = (int)(yD+Math.sin(Math.toRadians(rotation))*4d); + int x2 = (int)(xD+Math.cos(Math.toRadians(rotation-180))*4d); + int y2 = (int)(yD+Math.sin(Math.toRadians(rotation-180))*4d); + + r.fillPolygon(new int[]{x1, x2, x2, x1}, new int[]{y1, y2, y2+8, y1+8}, Color.yellow); + + x1 = (int)(xD+Math.cos(Math.toRadians(rotation))*2d); + y1 = (int)(yD+Math.sin(Math.toRadians(rotation))*2d); + x2 = (int)(xD+Math.cos(Math.toRadians(rotation-180))*2d); + y2 = (int)(yD+Math.sin(Math.toRadians(rotation-180))*2d); + + r.fillPolygon(new int[]{x1, x2, x2, x1}, new int[]{y1+2, y2+2, y2+6, y1+6}, Color.orange);*/ + } + + @Override + public String shareSend() { + return null; + } + + @Override + public void shareReceive(String s) { + + } +} diff --git a/src/com/youngdev/shooter/Cursor.java b/src/com/youngdev/shooter/Cursor.java new file mode 100644 index 0000000..29a4f04 --- /dev/null +++ b/src/com/youngdev/shooter/Cursor.java @@ -0,0 +1,67 @@ +package com.youngdev.shooter; + +import com.engine.libs.input.Input; +import com.engine.libs.rendering.Renderer; + +import java.awt.*; +import java.util.ArrayList; +import java.util.Random; + +public class Cursor { + public ArrayList particles; + private Random random; + + public Cursor() { + particles = new ArrayList<>(); + random = new Random(); + } + + public void update(Input i) { + createParticle(i); + + if(i.isButtonDown(1)) { +// leaf.clear(); +// for(int j = 0; j < 10; j++) { +// +// } +// leaf.forEach(p -> p.impulse(i.getRelativeMouseX(), i.getRelativeMouseY(), 0.5f)); + } + + particles.forEach(UniParticle::update); + particles.removeIf(particle -> particle.dead); + } + + private void createParticle(Input i) { + int x = i.getRelativeMouseX(); + int y = i.getRelativeMouseY(); + int tone = random.nextInt(20); + int dir = random.nextInt(359); + int distance = random.nextInt(8); + int xx = x + (int)(Math.cos(Math.toRadians(dir))*distance); + int yy = y + (int)(Math.sin(Math.toRadians(dir))*distance); + int alpha = random.nextInt(32)+213; + alpha = 255; + int alphaSpeed = 16; + int size = (random.nextInt(2)+1)*2; + Color color = new Color(164+tone, 170+tone, 46+tone); + UniParticle.FadingProcess fadingProcess = new UniParticle.FadingProcess(alpha, alphaSpeed, true); + particles.add(new UniParticle(xx, yy, size, false, color, fadingProcess)); + + + /* + int xx = i.getRelativeMouseX(); + int yy = i.getRelativeMouseY(); + int dir = random.nextInt(359); + float speed = random.nextInt(10)/10f+1f; + int tone = random.nextInt(20); + int sDir = random.nextInt(359); + int sDistance = random.nextInt(8); + int xx = xx + (int)(Math.cos(Math.toRadians(sDir))*sDistance); + int yy = yy + (int)(Math.sin(Math.toRadians(sDir))*sDistance); + leaf.add(new Particle(xx, yy, 4, dir, 0, tone));*/ + } + + public void render(Renderer r) { + particles.forEach(p -> p.render(r)); + } +} diff --git a/src/com/youngdev/shooter/EnemyBolt.java b/src/com/youngdev/shooter/EnemyBolt.java new file mode 100644 index 0000000..82d421e --- /dev/null +++ b/src/com/youngdev/shooter/EnemyBolt.java @@ -0,0 +1,182 @@ +package com.youngdev.shooter; + +import com.engine.libs.game.GameObject; +import com.engine.libs.input.Input; +import com.engine.libs.math.AdvancedMath; +import com.engine.libs.rendering.Renderer; + +import java.awt.*; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.Random; + +/* + * Enemy called "Bolt" is fast but weak. + * */ +public class EnemyBolt extends Healable { + public Healable closestHealable; + + private static final int gotHitTime = 10; + private int gotHitTimer; + private boolean isDead; + private double speedX, speedY, maxSpeed, dir; + private Random random; + + private ArrayList particles; + + public EnemyBolt(int x, int y) { + super(x, y, 32, 32, 50, 3, 12, true); + random = new Random(); + this.dir = random.nextDouble()*360; + maxSpeed = 3f; + isDead = false; + particles = new ArrayList<>(); + } + + @Override + public void update(Input i) { + if(isDead) { + particles.removeIf(o -> { + if(o.dead) { + return true; + } else { + o.update(); + return false; + } + }); + if(particles.size() == 0) { + dead = true; + } + return; + } + + double minDis = Double.MAX_VALUE; + Healable closestEnemy = null; + Iterator it; + GameObject obj; + boolean foundHit = false; + for(it = Main.main.visibleChunkObjects.iterator(); it.hasNext();) { + obj = it.next(); + if(obj instanceof Healable && !((Healable) obj).isEnemy) { + double distance = Math.hypot((x - obj.x), (y - obj.y)); + if(distance <= minDis) { + minDis = distance; + closestEnemy = (Healable) obj; + } + } else if(!foundHit && obj instanceof Arrow) { + if(((Arrow) obj).shotByFriendly) { + if(Math.hypot((x - obj.x), (y - obj.y)) < 12) { + health -= 10; + gotHitTimer = gotHitTime; + + double dir = Math.toRadians(Fly.angle(obj.x, obj.y, x, y)); + x -= Math.cos(dir)*16d; + y -= Math.sin(dir)*16d; + speedX = 0; + speedY = 0; + + foundHit = true; + } + } + } + } + + dir = (dir+Main.toSlowMotion((minDis < 80) ? 4d : 1d)) % 360; + + if(closestEnemy != null) { + double angle = Math.toDegrees(Math.atan2(y - closestEnemy.y, x - closestEnemy.x))-180; + + speedX += Math.cos(Math.toRadians(angle)); + speedY += Math.sin(Math.toRadians(angle)); + + speedX = speedX % maxSpeed; + speedY = speedY % maxSpeed; + + x += speedX * Main.toSlowMotion(1d); + y += speedY * Main.toSlowMotion(1d); + } + + if(!Main.isPixelOnScreen((int)x, (int)y, 2)) { + dead = true; + } + + gotHitTimer = Math.max(0, gotHitTimer-1); + + if(health < 1) { + isDead = true; + for(int j = 0; j < 8; j++) { + int xx = (int)(random.nextDouble()*3-1.5d); + int yy = (int)(random.nextDouble()*3-1.5d); + Color c = (xx > -8 && xx < 8) ? new Color(32, 32, 160) : new Color(20, 20, 80); + + UniParticle.MovingProcess movingProcess = UniParticle.MovingProcess.create((float)xx, (float)yy, -0.025d); + UniParticle.FadingProcess fadingProcess = new UniParticle.FadingProcess(255, 10, false); + + particles.add(new UniParticle((int)x+xx, (int)y+yy, 4, true, c, movingProcess, fadingProcess)); + } + + ArrayList tempList = new ArrayList<>(); + for(int k = 0; k < random.nextInt(3)+3; k++) { + tempList.add(new Coin((int)x, (int)y, random.nextInt(359))); + } + Main.main.addEntities.addAll(tempList); + } + } + + @Override + public void render(Renderer r) { + if(isDead) { + particles.forEach(o -> o.render(r)); + return; + } + double r1 = 10; + double r2 = 8; + double[] xPs1 = new double[]{ + x + Math.cos(Math.toRadians(dir+45))*r1, + x + Math.cos(Math.toRadians(dir+135))*r1, + x + Math.cos(Math.toRadians(dir+225))*r1, + x + Math.cos(Math.toRadians(dir+315))*r1 + }; + double[] yPs1 = new double[]{ + y + Math.sin(Math.toRadians(dir+45))*r1, + y + Math.sin(Math.toRadians(dir+135))*r1, + y + Math.sin(Math.toRadians(dir+225))*r1, + y + Math.sin(Math.toRadians(dir+315))*r1 + }; + double[] xPs2 = new double[]{ + x + Math.cos(Math.toRadians(-dir-45+45))*r2, + x + Math.cos(Math.toRadians(-dir-45+135))*r2, + x + Math.cos(Math.toRadians(-dir-45+225))*r2, + x + Math.cos(Math.toRadians(-dir-45+315))*r2 + }; + double[] yPs2 = new double[]{ + y + Math.sin(Math.toRadians(-dir-45+45))*r2, + y + Math.sin(Math.toRadians(-dir-45+135))*r2, + y + Math.sin(Math.toRadians(-dir-45+225))*r2, + y + Math.sin(Math.toRadians(-dir-45+315))*r2 + + }; + + float value = (float)gotHitTimer / (float)gotHitTime; + + Color color1 = new Color( + calcColorParameter(32, 255, value), + calcColorParameter(32, 0, value), + calcColorParameter(160, 0, value) + ); + + Color color2 = new Color( + calcColorParameter(20, 255, value), + calcColorParameter(20, 0, value), + calcColorParameter(80, 0, value) + ); + + r.fillPolygon(xPs1, yPs1, 4, color1); + r.fillPolygon(xPs2, yPs2, 4, color2); + } + + public static int calcColorParameter(int colorBack, int colorFront, float alpha) { + return (int) AdvancedMath.setRange((int)(alpha * (float)colorFront) + (int)((1f - alpha) * (float)colorBack), 0, 255); + } + +} diff --git a/src/com/youngdev/shooter/Explosion.java b/src/com/youngdev/shooter/Explosion.java new file mode 100644 index 0000000..56c3445 --- /dev/null +++ b/src/com/youngdev/shooter/Explosion.java @@ -0,0 +1,81 @@ +package com.youngdev.shooter; + +import com.engine.libs.game.GameObject; +import com.engine.libs.game.Mask; +import com.engine.libs.input.Input; +import com.engine.libs.rendering.Renderer; + +import java.awt.*; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.Random; + +public class Explosion extends GameObject { + private Random random; + private int size; + private ArrayList particles; + + public Explosion(int x, int y, int depth, boolean useAlpha, int range) { + super(4, depth); + this.x = x; + this.y = y; + + this.size = 0; + + // HERE: Fix depth + this.random = new Random(); + this.depth = random.nextInt(1023)+depth*1024; + + particles = new ArrayList<>(); + + // HERE: Create particles + int numParticles = 120; + for(int i = 0; i < numParticles; i++) { + double angle = random.nextDouble()*360; + double speed = random.nextDouble()*2f+2f; + double spdX = (Math.cos(Math.toRadians(angle))*speed); + double spdY = (Math.sin(Math.toRadians(angle))*speed); + UniParticle.MovingProcess movingProcess = UniParticle.MovingProcess.create( + angle, (float)speed, 0.5 + ); + UniParticle.ColorChangeEffect colorChangeEffect = new UniParticle.ColorChangeEffect( + new Color( 250, 230, 80), new Color(180, 0, 0), 0, random.nextInt(20)+10 + ); + particles.add(new UniParticle(x, y, 4, true, Color.black, movingProcess, colorChangeEffect)); + } + + this.mask = new Mask.Rectangle(x-128, y-128, 256, 256); + } + + @Override + public void update(Input input) { + size = 0; + particles.removeIf(p -> { + if(p.dead) { + return true; + } else { + p.update(); + size++; + return false; + } + }); + if(size == 0) { + dead = true; + } + } + + @Override + public void render(Renderer r) { + particles.forEach(p -> p.render(r)); + } + + @Override + public String shareSend() { + return null; + } + + @Override + public void shareReceive(String s) { + + } +} diff --git a/src/com/youngdev/shooter/Fly.java b/src/com/youngdev/shooter/Fly.java new file mode 100644 index 0000000..3f57dec --- /dev/null +++ b/src/com/youngdev/shooter/Fly.java @@ -0,0 +1,131 @@ +package com.youngdev.shooter; + +import com.engine.libs.game.GameObject; +import com.engine.libs.input.Input; +import com.engine.libs.math.AdvancedMath; +import com.engine.libs.rendering.Renderer; + +import java.awt.*; +import java.util.Iterator; +import java.util.Random; + +public class Fly extends GameObject { + private boolean state; // TRUE - Idle, FALSE - Fly away + private double targetX, targetY, angle, speed; + private Random random; + + public Fly(int x, int y) { + super(3, 15); + this.x = x; + this.y = y; + this.speed = 0; + this.state = true; + + // HERE: Fix depth + this.random = new Random(); + this.depth = random.nextInt(1023)+depth*1024; + + targetX = x + random.nextInt(32) - 16; + targetY = y + random.nextInt(32) - 16; + } + + public Fly(int x, int y, boolean state) { + super(5, 35); + this.x = x; + this.y = y; + this.speed = 0; + this.state = state; + this.random = new Random(); + targetX = x + random.nextInt(32) - 16; + targetY = y + random.nextInt(32) - 16; + + if(!state) { + double minDis = Double.MAX_VALUE; + Healable closestEnemy = null; + Iterator it; + for(it = Main.main.visibleChunkObjects.iterator(); it.hasNext();) { + GameObject obj = it.next(); + if (obj instanceof Healable && !((Healable) obj).isEnemy) { + double distance = Math.hypot((x - obj.x), (y - obj.y)); + if (distance <= minDis) { + minDis = distance; + closestEnemy = (Healable) obj; + } + } + } + angle = angle(closestEnemy.x, closestEnemy.y, + x, y) - 180; + } + } + + @Override + public void update(Input input) { + if(dead) return; + if(state) { + double minDis = Double.MAX_VALUE; + Healable closestEnemy = null; + Iterator it; + for(it = Main.main.visibleChunkObjects.iterator(); it.hasNext();) { + GameObject obj = it.next(); + if(obj instanceof Healable && !((Healable) obj).isEnemy) { + double distance = Math.hypot((x - obj.x), (y - obj.y)); + if(distance <= minDis) { + minDis = distance; + closestEnemy = (Healable) obj; + } + } + } + + if (minDis < 100) { +// dead = true; + state = false; + angle = angle(closestEnemy.x, closestEnemy.y, + x, y)-180; + } else { + if(distance(x, y, targetX, targetY) < 4) { + targetX = x + random.nextInt(16) - 8; + targetY = y + random.nextInt(16) - 8; + } else { + x += Main.toSlowMotion((targetX - x) * 0.05); + y += Main.toSlowMotion((targetY - y) * 0.05); + } + } + } else { + x += Main.toSlowMotion(Math.cos(Math.toRadians(angle))*speed); + y += Main.toSlowMotion(Math.sin(Math.toRadians(angle))*speed); + speed+=0.125; + + Camera camera = Main.main.camera; + if(!AdvancedMath.inRange(x, y, camera.cX, camera.cY, + camera.cX+Main.main.getE().width, + camera.cY+Main.main.getE().height)) { + dead = true; + } + } + } + + @Override + public void render(Renderer renderer) { + if(dead) return; + renderer.fillRectangle((int)x-2, (int)y-2, 4, 4, Color.black); +// System.out.println("Rendered"); + } + + @Override + public String shareSend() { + return null; + } + + @Override + public void shareReceive(String s) { + + } + + public static double distance(double x1, double y1, double x2, double y2) { + return Math.hypot((x1 - x2), (y1 - y2)); + } + + public static double angle(double x1, double y1, double x2, double y2) { + return Math.toDegrees(Math.atan2(y1 - y2, x1 - x2)); + } +} diff --git a/src/com/youngdev/shooter/Healable.java b/src/com/youngdev/shooter/Healable.java new file mode 100644 index 0000000..956d0c4 --- /dev/null +++ b/src/com/youngdev/shooter/Healable.java @@ -0,0 +1,40 @@ +package com.youngdev.shooter; + +import com.engine.libs.game.GameObject; +import com.engine.libs.game.Mask; +import com.engine.libs.input.Input; +import com.engine.libs.rendering.Renderer; + +import java.util.Random; + +public abstract class Healable extends GameObject { + public int health; + private Random random; + public boolean isEnemy; + + public Healable(int x, int y, int w, int h, int health, int index, int depth, boolean isEnemy) { + super(index, depth); + this.x = x; + this.y = y; + this.isEnemy = isEnemy; + this.mask = new Mask.Rectangle(x-w/2d, y-h/2d, w, h); + this.health = health; + + // HERE: Fix depth + this.random = new Random(); + this.depth = random.nextInt(1023)+depth*1024; + } + + public abstract void update(Input i); + public abstract void render(Renderer r); + + @Override + public String shareSend() { + return null; + } + + @Override + public void shareReceive(String s) { + + } +} diff --git a/src/com/youngdev/shooter/Main.java b/src/com/youngdev/shooter/Main.java new file mode 100644 index 0000000..37917d8 --- /dev/null +++ b/src/com/youngdev/shooter/Main.java @@ -0,0 +1,646 @@ +package com.youngdev.shooter; + +import com.engine.Core; +import com.engine.Game; +import com.engine.libs.font.Alignment; +import com.engine.libs.game.GameObject; +import com.engine.libs.game.Mask; +import com.engine.libs.input.Input; +import com.engine.libs.rendering.Filter; +import com.engine.libs.rendering.Renderer; +import com.engine.libs.world.CollisionMap; +import org.omg.PortableInterceptor.SYSTEM_EXCEPTION; + +import java.awt.*; +import java.util.*; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.function.BinaryOperator; + +import static java.awt.event.KeyEvent.*; + +public class Main extends Game { + public static Main main; + + public static int chunkSize = 128; + private int hoverChunkX, hoverChunkY; + private static int chunkXTopLeft; + private static int chunkYTopLeft; + private static int chunkXBottomRight; + private static int chunkYBottomRight; + private int timer, time=120; + private boolean found, findOnScreenBlocked, findOnScreenCalled; + private boolean usesChunkRenderer; + public boolean showDebugInfo; + public static float slowMotionSpeed = 1f; + private Random random; + public Camera camera; + public static CollisionMap collisionMap; + + public Cursor cursor; + + public static Color grassColor = new Color(80, 140, 110); + + public Player player; + + List addEntities, entities, visibleChunkObjects; + private List structuralBlocks,visibleChunkObjectsTemp; + List flies; + + public static void main(String[] args) { + new Main(); + } + + public Map> chunks; + + public Main() { + main = this; + + e.width = 320; + e.height = 240; + e.scale = 4f; + + showDebugInfo = false; + + e.start(); + + // HERE: Init + + GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); + + try { + ge.registerFont(Font.createFont(Font.PLAIN, this.getClass().getClassLoader().getResourceAsStream("/RETRO.ttf"))); + } catch (Exception ignored1) { + try { + ge.registerFont(Font.createFont(Font.PLAIN, this.getClass().getResourceAsStream("/RETRO.ttf"))); + } catch (Exception ignored2) { + try { + ge.registerFont(Font.createFont(Font.PLAIN, this.getClass().getClassLoader().getResourceAsStream("RETRO.ttf"))); + } catch (Exception ignored3) { + try { + ge.registerFont(Font.createFont(Font.PLAIN, this.getClass().getResourceAsStream("RETRO.ttf"))); + } catch (Exception ignored4) {} + } + } + } + + + random = new Random(); + entities = Collections.synchronizedList(new ArrayList<>()); + cursor = new Cursor(); + chunks = new HashMap<>(); + usesChunkRenderer = false; + visibleChunkObjects = Collections.synchronizedList(new ArrayList<>()); + visibleChunkObjectsTemp = Collections.synchronizedList(new ArrayList<>()); + flies = Collections.synchronizedList(new ArrayList<>()); + structuralBlocks = Collections.synchronizedList(new ArrayList<>()); + addEntities = Collections.synchronizedList(new ArrayList<>()); + findOnScreenBlocked = false; + findOnScreenCalled = false; + + collisionMap = new CollisionMap(); + e.getRenderer().setCamX(Integer.MAX_VALUE/2-e.width/2); + e.getRenderer().setCamY(Integer.MAX_VALUE/2-e.height/2); + player = new Player(e.getRenderer().getCamX()+e.width/2, + e.getRenderer().getCamY()+e.height/2); + + camera = new Camera(e.width, e.height, player); + + Graphics2D g2d = (Graphics2D) getE().getRenderer().getG(); + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF); + g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_SPEED); + g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR); + + e.run(); + } + + public void deleteChunk(int x, int y){ + chunks.remove(new Point(x, y)); + } + + public void generateChunk(int x, int y) { + ArrayList chunk = new ArrayList<>(); + + + Random random = new Random(); + + int minX = x*chunkSize; + int minY = y*chunkSize; + + for(int i = 0; i < random.nextInt(4); i++) { + chunk.add(new Tree(random.nextInt(chunkSize)+minX, random.nextInt(chunkSize)+minY)); + } + + for(int i = 0; i < random.nextInt(3); i++) { + chunk.add(new Rocks(random.nextInt(chunkSize)+minX, random.nextInt(chunkSize)+minY)); + } + + for(int i = 0; i < random.nextInt(3); i++) { + Color clr = new Color(random.nextInt(135)+100,random.nextInt(135)+100,random.nextInt(135)+100); +// Color clr = new Color(Color.HSBtoRGB(random.nextFloat(), 1f, 1f)); +// System.out.println(clr); + chunk.add(new Plant(random.nextInt(chunkSize)+minX, random.nextInt(chunkSize)+minY, clr)); + } + + for(int i = 0; i < random.nextInt(2); i++) { + chunk.add(new Terrain(random.nextInt(chunkSize)+minX, random.nextInt(chunkSize)+minY, random.nextInt(2)+1)); + } + + if(random.nextInt(4)==1) { + chunk.add(new Trash(random.nextInt(chunkSize)+minX, random.nextInt(chunkSize)+minY)); + } + + if(random.nextInt(5)==3) { + int xx = random.nextInt(chunkSize); + int yy = random.nextInt(chunkSize); + for(int i = 0; i < random.nextInt(4)+3; i++) { + double angle = random.nextInt(359); + double distance = random.nextInt(chunkSize/4)+chunkSize/4f; + int xxx = minX + xx + (int) (Math.cos(Math.toRadians(angle))*distance); + int yyy = minY + yy + (int) (Math.sin(Math.toRadians(angle))*distance); + flies.add(new Fly(xxx, yyy)); +// System.out.println("Spawned a fly at ("+xxx+","+yyy+")"); + } + } + + if(random.nextInt(7)==3) { + int xx = random.nextInt(chunkSize); + int yy = random.nextInt(chunkSize); + for(int i = 0; i < random.nextInt(4)+3; i++) { + double angle = random.nextInt(359); + double distance = random.nextInt(chunkSize/4)+chunkSize/4f; + int xxx = minX + xx + (int) (Math.cos(Math.toRadians(angle))*distance); + int yyy = minY + yy + (int) (Math.sin(Math.toRadians(angle))*distance); + entities.add(new EnemyBolt(xxx, yyy)); +// flies.add(new Fly(xxx, yyy)); +// System.out.println("Spawned a fly at ("+xxx+","+yyy+")"); + } + } + + getChunkArray(x, y).addAll(chunk); + + if(isOnScreen(x, y, 2)) + findOnScreenObjects(); + } + + public CopyOnWriteArrayList getChunkArray(int x, int y) { + Point loc = new Point(x, y); + if(!chunks.containsKey(loc)) { + chunks.put(loc, new CopyOnWriteArrayList<>()); + } + return chunks.get(loc); + } + + public boolean isOnScreen(int x, int y) { + return (x>=chunkXTopLeft) && (x<=chunkXBottomRight) && + (y>=chunkYTopLeft) && (y<=chunkYBottomRight); + } + + public boolean isPixelOnScreen(int x, int y) { + return (x>=chunkXTopLeft*chunkSize) && (x<=chunkXBottomRight*chunkSize) && + (y>=chunkYTopLeft*chunkSize) && (y<=chunkYBottomRight*chunkSize); + } + + public static boolean isOnScreen(int x, int y, int bufferZoneSize) { + return (x>=chunkXTopLeft-bufferZoneSize) && (x<=chunkXBottomRight+bufferZoneSize) && + (y>=chunkYTopLeft-bufferZoneSize) && (y<=chunkYBottomRight+bufferZoneSize); + } + + public static boolean isPixelOnScreen(int x, int y, int bufferZoneSize) { + return (x>=(chunkXTopLeft-bufferZoneSize)*chunkSize) && (x<=(chunkXBottomRight+bufferZoneSize)*chunkSize) && + (y>=(chunkYTopLeft-bufferZoneSize)*chunkSize) && (y<=(chunkYBottomRight+bufferZoneSize)*chunkSize); + } + + public boolean isFree(int x, int y) { + for (GameObject obj : structuralBlocks) { + if (obj.mask.isColliding(x, y)) { + return false; + } + } + return true; + } + + public GameObject find(int x, int y) { + for (GameObject obj : structuralBlocks) { + if (obj.mask.isColliding(x, y)) { + return obj; + } + } + return null; + } + + public void remove(int x, int y) { + structuralBlocks.removeIf(obj -> obj.mask.isColliding(x, y)); + } + + void findOnScreenObjects() { + findOnScreenCalled = true; + if(findOnScreenBlocked) return; + + collisionMap.empty(); + ArrayList visibleChunksObjectsTemporary = new ArrayList<>(); + ArrayList addQueue = new ArrayList<>(); + addQueue.add(player); + + // HERE: Add chunks that are inside screen to visibleChunkObjects list + for(int xx = chunkXTopLeft; xx < chunkXBottomRight; xx++) { + for(int yy = chunkYTopLeft; yy < chunkYBottomRight; yy++) { + for(GameObject obj : getChunkArray(xx, yy)) { + addQueue.add(obj); + if(obj.aabbComponent != null) { + collisionMap.add(obj.aabbComponent); + } + } +// visibleChunkObjects.addAll(getChunkArray(xx, yy)); + } + } + + // HERE: Add additional ones that are partly on screen + Mask.Rectangle visibleAreaMask = new Mask.Rectangle( + e.getRenderer().getCamX(), + e.getRenderer().getCamY(), + e.getRenderer().getCamX()+e.width, + e.getRenderer().getCamY()+e.height); + for(int xx = chunkXTopLeft-2; xx < chunkXBottomRight+2; xx++) { + for(int yy = chunkYTopLeft-2; yy < chunkYBottomRight+2; yy++) { + if(xx > chunkXTopLeft && yy > chunkYTopLeft && + xx < chunkXBottomRight && yy < chunkYBottomRight) { + continue; + } + + getChunkArray(xx, yy).forEach(obj -> { + if(obj.mask.isColliding(visibleAreaMask)) { + addQueue.add(obj); + if(obj.aabbComponent != null) { + collisionMap.add(obj.aabbComponent); + } + } + }); + } + } + + + int camX = e.getRenderer().getCamX(); + int camY = e.getRenderer().getCamY(); + // HERE: Also add entities + Iterator iterator = entities.iterator(); + while(iterator.hasNext()) { + GameObject obj = iterator.next(); + Point chunkLoc = getChunkLocation((int)obj.x, (int)obj.y); + if(isOnScreen(chunkLoc.x, chunkLoc.y, 2)) { + addQueue.add(obj); + } else if(!(obj instanceof Fly)) { + iterator.remove(); + } + } + + structuralBlocks.forEach(o -> { + if(o.mask.isColliding(visibleAreaMask)) { + addQueue.add(o); + if(o.aabbComponent != null) + collisionMap.add(o.aabbComponent); + } + }); + collisionMap.refresh(); + flies.forEach(f -> { + if(isPixelOnScreen((int)f.x, (int)f.y, 1)) { + addQueue.add(f); + } + }); + visibleChunksObjectsTemporary.addAll(addQueue); + visibleChunksObjectsTemporary.sort(Comparator.comparingInt((o) -> o.depth)); + visibleChunkObjects = visibleChunksObjectsTemporary; + { + visibleChunkObjectsTemp.clear(); + visibleChunkObjectsTemp.addAll(visibleChunksObjectsTemporary); + } + } + + public static Point getChunkLocation(int x, int y) { + return new Point(x/chunkSize, y/chunkSize); + } + + @Override + public void update(Core core) { + entities.addAll(addEntities); + addEntities.clear(); + + findOnScreenBlocked = true; + Input i = core.getInput(); + + int prevCamX = core.getRenderer().getCamX(); + int prevCamY = core.getRenderer().getCamY(); + + timer++; + if(timer >= time) { + timer = 0; + int x = prevCamX - 2*chunkSize + random.nextInt(e.width+4*chunkSize); + int y = prevCamY - 2*chunkSize + random.nextInt(e.height+4*chunkSize); +// entities.add(new Ghost(xx, yy)); +// System.out.println("Ghost spawner"); + } + + Iterator it = flies.iterator(); + while(it.hasNext()) { + Fly fly = it.next(); + if(fly.dead) { + it.remove(); + } else { + fly.update(core.getInput()); + } + } + + Iterator it2 = entities.iterator(); + while(it2.hasNext()) { + GameObject entity = it2.next(); + if(entity.dead) { + it2.remove(); + } else { + entity.update(core.getInput()); + } + } + + player.update(core.getInput()); + Iterator it3; + for(it3 = Main.main.visibleChunkObjects.iterator(); it3.hasNext();) { + GameObject obj = it3.next(); + if(obj instanceof Tree || obj instanceof Plant || obj instanceof Trash) { + obj.update(core.getInput()); + } + }; + cursor.update(i); + + e.getWindow().getFrame().setTitle("Codename SHOOTER - FPS: "+e.getFps()); + +// player.update(i); + + camera.update(); + camera.apply(core.getRenderer()); + + chunkXTopLeft = (int)Math.floor(e.getRenderer().getCamX()/(double)chunkSize); + chunkYTopLeft = (int)Math.floor(e.getRenderer().getCamY()/(double)chunkSize); + chunkXBottomRight = (int)Math.floor((e.width+e.getRenderer().getCamX())/(double)chunkSize); + chunkYBottomRight = (int)Math.floor((e.height+e.getRenderer().getCamY())/(double)chunkSize); + + /*chunkXTopLeft = (int)Math.floor(camera.cX/(double)chunkSize); + chunkYTopLeft = (int)Math.floor(camera.cY/(double)chunkSize); + chunkXBottomRight = (int)Math.floor((e.width+camera.cX)/(double)chunkSize); + chunkYBottomRight = (int)Math.floor((e.height+camera.cY)/(double)chunkSize);*/ + + // HERE: Gather together all chunks that are visible + // HERE: and put them to visibleChunkObjects + + if(i.isKeyDown(VK_F2)) { + showDebugInfo = !showDebugInfo; + } + + if(i.isKeyDown(VK_F4)) { + entities.clear(); + } + + if(i.isButtonDown(2)) { + Arrow arrow = new Arrow(i.getRelativeMouseX(), i.getRelativeMouseY(), + (int)Fly.angle(i.getRelativeMouseX(), i.getRelativeMouseY(), player.x, player.y)-180); + arrow.shotByFriendly = false; + entities.add(arrow); + } + + + if(i.isKeyDown(VK_F3) && showDebugInfo) { + usesChunkRenderer = !usesChunkRenderer; + } + + hoverChunkX=i.getRelativeMouseX()/chunkSize; + hoverChunkY=i.getRelativeMouseY()/chunkSize; + + if(i.isButton(1) && showDebugInfo) { +// // Place new tree, debug only! +// world.add(new Tree(i.getMouseX(), i.getMouseY())); + + // HERE: Generate selected chunk + deleteChunk(hoverChunkX, hoverChunkY); + generateChunk(hoverChunkX, hoverChunkY); + } + +// findOnScreenObjects(); +// int moveX = (i.isKey(VK_D) ? 1 : 0)*8 - (i.isKey(VK_A) ? 1 : 0)*8; +// int moveY = (i.isKey(VK_S) ? 1 : 0)*8 - (i.isKey(VK_W) ? 1 : 0)*8; +// +// core.getRenderer().setCamX(core.getRenderer().getCamX()+moveX); +// core.getRenderer().setCamY(core.getRenderer().getCamY()+moveY); + + + // HERE: Generate new chunks + if(prevCamX != core.getRenderer().getCamX() || prevCamY != core.getRenderer().getCamY()) { + findOnScreenObjects(); + for(int xx = chunkXTopLeft-2; xx < chunkXBottomRight+2; xx++) { + for(int yy = chunkYTopLeft-2; yy < chunkYBottomRight+2; yy++) { + if(getChunkArray(xx, yy).size() == 0) { + generateChunk(xx, yy); + } + } + } + } + + findOnScreenBlocked = false; + if(findOnScreenCalled) findOnScreenObjects(); + } + + public static int toSlowMotion(int amount) { + return (int)(amount*slowMotionSpeed); + } + + public static double toSlowMotion(double amount) { + return amount*slowMotionSpeed; + } + + @Override + public void render(Core core) { + Renderer r = core.getRenderer(); + + r.absolute(); + + Filter grayScale = (newC, oldC) -> { + int cr = newC.getRed(); + int cg = newC.getGreen(); + int cb = newC.getBlue(); + + int grayScaleColor = (int)(((double)(cr+cg+cb))/3d); + + cr = grayScaleColor; + cg = grayScaleColor; + cb = grayScaleColor; + + return new Color(cr, cg, cb); + }; + + + Filter slowMotionOverlay = (newC, oldC) -> { + float amount = camera.bluishEffect; + double cr = newC.getRed() * (1 - 0.45 * amount); + double cg = newC.getGreen() * (1 - 0.45 * amount); + double cb = newC.getBlue() * (1 - 0.45 * amount); + + double grayScaleColor = (cr+cg+cb) / 3d; + + cr = cr*(1-amount)+grayScaleColor*amount; + cg = cg*(1-(amount*0.25))+grayScaleColor*(amount*0.25); + cb = cb*(1-amount)+grayScaleColor*amount; + + cr = Math.max(0, Math.min(255, cr*1.25)); + cg = Math.max(0, Math.min(255, cg)); + cb = Math.max(0, Math.min(255, cb)); + + return new Color((int)cr, (int)cg, (int)cb, newC.getAlpha()); + }; + + r.setFilter(0, slowMotionOverlay); + + /*r.setFilter(0, (newC, oldC) -> { + newC = new Color(64, 64, 64, 64); + + return new Color( + oldC.getRed(), oldC.getGreen(), oldC.getBlue() +// 255, +// UniParticle.calcColorParameter(oldC.getRed(), newC.getRed(), newC.getAlpha()/255f), +// UniParticle.calcColorParameter(oldC.getGreen(), newC.getGreen(), newC.getAlpha()/255f), +// UniParticle.calcColorParameter(oldC.getBlue(), newC.getBlue(), newC.getAlpha()/255f) + ); + + });*/ + + r.fillRectangle(0, 0, e.width, e.height, grassColor); + + r.relative(); + if(showDebugInfo) + r.fillRectangle(hoverChunkX*chunkSize, hoverChunkY*chunkSize, chunkSize, chunkSize, new Color(40, 100, 70)); + + if(usesChunkRenderer) { + // HERE: Render only visible chunks + + Iterator it; + for(it = Main.main.visibleChunkObjects.iterator(); it.hasNext();) { + it.next().render(r); + } +// visibleChunkObjects.forEach(obj -> obj.render(r)); +// flies.forEach(f -> { +// if(isPixelOnScreen((int)f.xx, (int)f.yy, 1)) { +// f.render(r); +// } +// }); + } else { + // HERE: Render all chunks, temporally + chunks.forEach((loc, chunk) -> chunk.forEach(obj -> obj.render(r))); +// flies.forEach(f -> f.render(r)); + } + + // HERE: Render nearby bullet warnings + Filter backup = r.getFilter(0); + r.removeFilter(0); + if(player.blinkingON) { + Iterator it; + for(it = Main.main.visibleChunkObjects.iterator(); it.hasNext();) { + GameObject obj = it.next(); + if (obj instanceof Arrow) + if (!((Arrow) obj).shotByFriendly) + if (Fly.distance(obj.x, obj.y, player.x, player.y) < 160) { + r.drawRectangle(obj.x - 8, obj.y - 8, 16, 16, Color.red); + } + } + } + r.setFilter(0, backup); + + r.setFont(new Font("RETRO", Font.BOLD, 16)); + r.drawText(String.valueOf((int)player.money), player.coinOverlayX, player.coinOverlayY-32, 16, + Alignment.MIDDLE_CENTER, new Color(40, 250, 140, (int)player.coinOverlayAlpha)); + + +// double mouseAngle = Fly.angle(player.x, player.y, e.getInput().getRelativeMouseX(), e.getInput().getRelativeMouseY()); + if(player.clipOverlayAlpha != 0) { + double xx = e.getInput().getRelativeMouseX(); + double yy = e.getInput().getRelativeMouseY(); + double step1 = 360d / player.maxClip; + double addAngle = player.clipOverlayRotation; + for (int i = 0; i < player.clip; i++) { + double angle = step1 * i + addAngle; +// System.out.println("XX: "+xx); +// System.out.println("YY: "+yy); +// System.out.println("Angle: "+angle); + double sizeOuter = 24; + double sizeInner = 12; + double x1 = xx + Math.cos(Math.toRadians(angle + 3)) * sizeOuter; + double y1 = yy + Math.sin(Math.toRadians(angle + 3)) * sizeOuter; + double x2 = xx + Math.cos(Math.toRadians(angle + step1 - 3)) * sizeOuter; + double y2 = yy + Math.sin(Math.toRadians(angle + step1 - 3)) * sizeOuter; + double x3 = xx + Math.cos(Math.toRadians(angle + step1 - 3)) * sizeInner; + double y3 = yy + Math.sin(Math.toRadians(angle + step1 - 3)) * sizeInner; + double x4 = xx + Math.cos(Math.toRadians(angle + 3)) * sizeInner; + double y4 = yy + Math.sin(Math.toRadians(angle + 3)) * sizeInner; + + r.fillPolygon(new double[]{x1, x2, x3, x4}, new double[]{y1, y2, y3, y4}, new Color(64, 64, 64, (int) player.clipOverlayAlpha)); + } + double step2 = 360d/player.maxAmmo; + for (int i = 0; i < player.ammo; i++) { + double angle = step2 * i + addAngle / 1.5d; +// System.out.println("XX: "+xx); +// System.out.println("YY: "+yy); +// System.out.println("Angle: "+angle); + double sizeOuter = 32; + double sizeInner = 28; + double x1 = xx + Math.cos(Math.toRadians(angle + 3)) * sizeInner; + double y1 = yy + Math.sin(Math.toRadians(angle + 3)) * sizeInner; + double x2 = xx + Math.cos(Math.toRadians(angle + 3)) * sizeOuter; + double y2 = yy + Math.sin(Math.toRadians(angle + 3)) * sizeOuter; + + r.drawLineWidth(x1, y1, x2, y2, 1, new Color(80, 80, 64, (int) player.clipOverlayAlpha)); + } + } + r.absolute(); +// r.fillRectangle(0, 0, e.width, e.height, new Color(64, 64, 64, 64)); + + if(showDebugInfo) { + int addY = 16; + int y = 8; + r.setFont(new Font("Arial", Font.PLAIN, 10)); + r.drawText("FPS: " + core.getFps(), 8, y, 10, Color.black); + + y += addY; + r.drawText("X: " + core.getInput().getRelativeMouseX(), 8, y, 10, Color.black); + y += addY; + r.drawText("Y: " + core.getInput().getRelativeMouseY(), 8, y, 10, Color.black); + + y += addY; + r.drawText("Chunk X: " + hoverChunkX, 8, y, 10, Color.black); + y += addY; + r.drawText("Chunk Y: " + hoverChunkY, 8, y, 10, Color.black); + + y += addY; + r.drawText("Uses Chunk Renderer: " + (usesChunkRenderer ? "true" : "false"), 8, y, 10, Color.black); + + y += addY; + r.drawText("Entities: " + entities.size(), 8, y, 10, Color.black); + + y += addY; + r.drawText("CamX: " + camera.cX, 8, y, 10, Color.black); + y += addY; + r.drawText("CamY: " + camera.cY, 8, y, 10, Color.black); + y += addY; + r.drawText("PlayerX: " + player.xx, 8, y, 10, Color.black); + y += addY; + r.drawText("PlayerY: " + player.yy, 8, y, 10, Color.black); + } + r.relative(); + + cursor.render(r); + + /*r.removeFilter(0); + + r.absolute(); + + if(player.inventoryOpen) + player.renderInventory(r); + + r.relative();*/ + + } +} diff --git a/src/com/youngdev/shooter/Particle.java b/src/com/youngdev/shooter/Particle.java new file mode 100644 index 0000000..b373d81 --- /dev/null +++ b/src/com/youngdev/shooter/Particle.java @@ -0,0 +1,157 @@ +package com.youngdev.shooter; + +import com.engine.libs.math.AdvancedMath; +import com.engine.libs.rendering.Renderer; + +import java.awt.*; + +public class Particle { + private int x, y, dir, alpha; + int size, alphaSpeed; + private double xD, yD; + private float speed; + boolean dead; + + Color color, baseColor = new Color(164, 170, 46); + + public Particle(int x, int y, int size, int dir, float speed, int tone, int alphaSpeed) { + this.x = x; + this.y = y; + this.dir = dir; + this.speed = speed; + this.size = size; + this.dead = false; + this.alphaSpeed = alphaSpeed; + xD = x; + yD = y; + alpha = 255; + color = new Color(baseColor.getRed()+tone, + baseColor.getGreen()+tone, + baseColor.getBlue()+tone); + } + + public Particle(int x, int y, int size, int dir, float speed, int tone) { + this.x = x; + this.y = y; + this.dir = dir; + this.speed = speed; + this.size = size; + this.dead = false; + this.alphaSpeed = 16; + xD = x; + yD = y; + alpha = 255; + color = new Color(baseColor.getRed()+tone, + baseColor.getGreen()+tone, + baseColor.getBlue()+tone); + } + + public Particle(int x, int y, int size, int dir, int tone) { + this.x = x; + this.y = y; + this.dir = dir; + this.speed = 0; + this.size = size; + this.dead = false; + this.alphaSpeed = 16; + xD = x; + yD = y; + alpha = 255; + color = new Color(baseColor.getRed()+tone, + baseColor.getGreen()+tone, + baseColor.getBlue()+tone); + } + + public Particle(int x, int y, int size, int dir, float speed, int tone, int alphaSpeed, Color color) { + this.x = x; + this.y = y; + this.dir = dir; + this.speed = speed; + this.size = size; + this.dead = false; + this.alphaSpeed = alphaSpeed; + this.baseColor = color; + xD = x; + yD = y; + alpha = 255; + this.color = new Color(Math.max(0, Math.min(255, baseColor.getRed()+tone)), + Math.max(0, Math.min(255, baseColor.getGreen()+tone)), + Math.max(0, Math.min(255, baseColor.getBlue()+tone))); + } + + public Particle(int x, int y, int size, int dir, float speed, int tone, Color color) { + this.x = x; + this.y = y; + this.dir = dir; + this.speed = speed; + this.size = size; + this.dead = false; + this.alphaSpeed = 16; + this.baseColor = color; + xD = x; + yD = y; + alpha = 255; + this.color = new Color(Math.max(0, Math.min(255, baseColor.getRed()+tone)), + Math.max(0, Math.min(255, baseColor.getGreen()+tone)), + Math.max(0, Math.min(255, baseColor.getBlue()+tone))); + } + + public Particle(int x, int y, int size, int dir, int tone, Color color) { + this.x = x; + this.y = y; + this.dir = dir; + this.speed = 0; + this.size = size; + this.dead = false; + this.alphaSpeed = 16; + this.baseColor = color; + xD = x; + yD = y; + alpha = 255; + this.color = new Color(Math.max(0, Math.min(255, baseColor.getRed()+tone)), + Math.max(0, Math.min(255, baseColor.getGreen()+tone)), + Math.max(0, Math.min(255, baseColor.getBlue()+tone))); + } + + public void impulse(int x, int y, float strength) { + dir = (int)((float)Math.toDegrees(Math.atan2(this.y-y, this.x-x)) + 90.0f); + speed = strength; + alpha = 255; + } + + public void update() { + if(dead) return; + + if(speed != 0) { + xD += Math.cos(Math.toRadians(dir)) * speed; + yD += Math.sin(Math.toRadians(dir)) * speed; + + speed *= 0.995; + } + + alpha -= alphaSpeed; + + if(alpha < 0) { + dead = true; + return; + } + + this.color = new Color( + calcColorParameter(Main.grassColor.getRed(), baseColor.getRed(), alpha/255f), + calcColorParameter(Main.grassColor.getGreen(), baseColor.getGreen(), alpha/255f), + calcColorParameter(Main.grassColor.getBlue(), baseColor.getBlue(), alpha/255f)); +// System.out.println(color); + + x = (int)xD; + y = (int)yD; + } + + public static int calcColorParameter(int colorBack, int colorFront, float alpha) { + return (int)(alpha * colorFront + (1 - alpha) * colorBack); + } + + public void render(Renderer r) { + if(dead) return; + r.fillRectangle(x-size/2, y-size/2, size, size, color); + } +} diff --git a/src/com/youngdev/shooter/Plant.java b/src/com/youngdev/shooter/Plant.java new file mode 100644 index 0000000..115720c --- /dev/null +++ b/src/com/youngdev/shooter/Plant.java @@ -0,0 +1,129 @@ +package com.youngdev.shooter; + +import com.engine.libs.game.GameObject; +import com.engine.libs.game.Mask; +import com.engine.libs.input.Input; +import com.engine.libs.rendering.Renderer; + +import java.awt.*; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.Random; + +public class Plant extends GameObject { + ArrayList leaf; + private boolean prevCollision; + private Random random; + + public Plant(int x, int y, Color color) { + super(6, 6); + this.x = x; + this.y = y; + this.prevCollision = false; + + leaf = new ArrayList<>(); + + // HERE: Fix depth + this.random = new Random(); + this.depth = random.nextInt(1023)+depth*1024; + + int smallestX=Integer.MAX_VALUE, smallestY=Integer.MAX_VALUE, largestX=Integer.MIN_VALUE, largestY=Integer.MIN_VALUE; + + int numLeaf = 10; + for(int i = 0; i < numLeaf; i++) { + int xx = x + random.nextInt(12)-6; + int yy = y + random.nextInt(12)-6; + int size = random.nextInt(2)+5; + int tone = random.nextInt(10); + Color clr = new Color(49+tone, 107+tone, 38+tone); + leaf.add(new Piece(xx, yy, size, clr, random.nextInt(359))); + + smallestX = Math.min(smallestX, xx-size/2); + smallestY = Math.min(smallestY, yy-size/2); + largestX = Math.max(largestX, (int)Math.ceil(xx+size/2d)); + largestY = Math.max(largestY, (int)Math.ceil(yy+size/2d)); + } + + int numBloom = 4; + for(int i = 0; i < numBloom; i++) { + int xx = x + random.nextInt(16)-8; + int yy = y + random.nextInt(16)-8; + int size = random.nextInt(2)+4; + int tone = random.nextInt(10); + Color clr = new Color(color.getRed()+tone, color.getGreen()+tone, color.getBlue()+tone); + leaf.add(new Piece(xx, yy, size, clr, random.nextInt(359))); + + smallestX = Math.min(smallestX, xx-size/2); + smallestY = Math.min(smallestY, yy-size/2); + largestX = Math.max(largestX, (int)Math.ceil(xx+size/2d)); + largestY = Math.max(largestY, (int)Math.ceil(yy+size/2d)); + } + + mask = new Mask.Rectangle(smallestX, smallestY, largestX-smallestX, largestY-smallestY); + } + + @Override + public void update(Input input) { + boolean collision = false; + + Iterator it; + for(it = Main.main.visibleChunkObjects.iterator(); it.hasNext();) { + GameObject obj = it.next(); + if (obj instanceof Arrow || (obj instanceof Healable && obj.depth > this.depth)) + if(obj.mask != null) + if (obj.mask.isColliding(this.mask) || + Fly.distance(x, y, obj.x, obj.y) < 16) { + collision = true; + break; + } + } + + boolean collision_EffectivelyFinal = collision; + + leaf.forEach(leave -> { + if(collision_EffectivelyFinal) {/* && !prevCollision) {*/ + leave.speed = 24d; + } + leave.step+=Main.toSlowMotion(random.nextInt((int) Math.max(1, leave.speed * 10))/10d); + leave.speed=Math.max(0, leave.speed-0.125); + leave.addX = (int)(Math.cos(Math.toRadians(leave.step))*2d); + leave.addY = (int)(Math.sin(Math.toRadians(leave.step))*2d); + }); + + prevCollision = collision; + } + + @Override + public void render(Renderer r) { + leaf.forEach(leave -> r.fillRectangle(leave.x-leave.size/2+leave.addX, leave.y-leave.size/2+leave.addY, + leave.size, leave.size, leave.color)); + } + + @Override + public String shareSend() { + return null; + } + + @Override + public void shareReceive(String s) { + + } + + public class Piece { + public int x, y, addX, addY, size; + public double speed, step; + public Color color; + + public Piece(int x, int y, int size, Color clr, int step) { + this.x = x; + this.y = y; + this.speed = 0; + this.color = clr; + this.step = step; + this.addX = 0; + this.addY = 0; + this.size = size; + + } + } +} diff --git a/src/com/youngdev/shooter/Player.java b/src/com/youngdev/shooter/Player.java new file mode 100644 index 0000000..e9d6676 --- /dev/null +++ b/src/com/youngdev/shooter/Player.java @@ -0,0 +1,401 @@ +package com.youngdev.shooter; + +import com.engine.libs.font.Alignment; +import com.engine.libs.game.GameObject; +import com.engine.libs.game.behaviors.AABBCollisionManager; +import com.engine.libs.input.Input; +import com.engine.libs.math.AdvancedMath; +import com.engine.libs.rendering.Filter; +import com.engine.libs.rendering.Renderer; + +import java.awt.*; + +import java.awt.event.KeyEvent; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.Random; + +public class Player extends Healable { + + public ArrayList particles; + private Random random; + private AABBCollisionManager cm; + boolean blinkingON; + private boolean found; + public boolean buildingMode, inventoryOpen, leftHandShooting, rightHandShooting, clipOverlayOpen; + public int xx, yy, invSize = 24, midX, midY, selectedItem, time=60, timer, leftHandReload, rightHandReload, + reloadTime = 50, bulletTimingCap = 5, leftHandBulletTimingCapCounter, leftHandBulletAmountCounter, + rightHandBulletTimingCapCounter, rightHandBulletAmountCounter, bulletsPerShot = 5, ammo = 34, maxAmmo = 45, clip = 5, maxClip = 10, money; + public double lastCoinX, lastCoinY, coinOverlayAlpha, coinOverlayX, coinOverlayY, clipOverlayAlpha, clipOverlayRotation, clipOverlayRotationSpeed, + clipOverlayRotationTarget; + private int blinkingTime = 30; + public int[] items; + private String[] itemNames; + private StructuralBlock[] itemSamples; + private static final Color baseColor = new Color(130, 32, 78); // 170, 32, 128 + private float speedX, targetSpeedX, speedY, targetSpeedY, maxSpeed, speedStep, blinkingTimer; + + public Player(int x, int y) { + super(x, y, 4, 4, 200, 0, 9, false); + particles = new ArrayList<>(); + + leftHandReload = 0; + rightHandReload = 0; + leftHandShooting = false; + rightHandShooting = false; + leftHandBulletAmountCounter = 0; + rightHandBulletAmountCounter = 0; + leftHandBulletTimingCapCounter = 0; + rightHandBulletTimingCapCounter = 0; + + items = new int[5]; + itemNames = new String[] { + "Empty Hand", + "Rock Wall", + "Wooden Wall", + "Plant Fiber Wall", + "Wood Flooring" + }; + itemSamples = new StructuralBlock[] { + null, + new StructuralBlock(0, 0, StructuralBlock.TYPE_ROCKS), + new StructuralBlock(0, 0, StructuralBlock.TYPE_WOOD), + new StructuralBlock(0, 0, StructuralBlock.TYPE_FIBER), + new StructuralBlock(0, 0, StructuralBlock.TYPE_WOOD_FLOORING) + }; + + inventoryOpen = false; + + midX = Main.main.getE().getWidth()/2; + midY = Main.main.getE().getHeight()/2; + + random = new Random(); + core = Main.main.getE(); + + this.random = new Random(); + + this.buildingMode = true; + + super.x = x; + super.y = y; + + this.xx = x; + this.yy = y; + + this.maxSpeed = 3f; + this.targetSpeedX = 0; + this.targetSpeedY = 0; + this.speedX = 0; + this.speedY = 0; + this.speedStep = 0.5f; + this.blinkingTimer = 0; + + this.clipOverlayAlpha = 0d; + this.clipOverlayOpen = false; + this.clipOverlayRotation = 0; + this.clipOverlayRotationSpeed = 0; + this.clipOverlayRotationTarget = 0; + + cm = new AABBCollisionManager(this, Main.collisionMap); + } + + @Override + public void update(Input i) { +// boolean prevInvOpen = inventoryOpen; + blinkingTimer += 1d/Main.toSlowMotion(1d); + + if(blinkingTimer >= blinkingTime) { + blinkingON = !blinkingON; + blinkingTimer = 0; + } + + // HERE: Use keyboard to move + int moveX = (i.isKey(KeyEvent.VK_D) ? 1 : 0) - (i.isKey(KeyEvent.VK_A) ? 1 : 0); + int moveY = (i.isKey(KeyEvent.VK_S) ? 1 : 0) - (i.isKey(KeyEvent.VK_W) ? 1 : 0); + + /*if(moveX != 0 || moveY != 0) { + inventoryOpen = false; + timer = time; + }*/ + + targetSpeedX = moveX * maxSpeed; + targetSpeedY = moveY * maxSpeed; + + speedX += Math.signum(targetSpeedX - speedX)*speedStep; + speedY += Math.signum(targetSpeedY - speedY)*speedStep; + + speedX = Math.max(-maxSpeed, Math.min(maxSpeed, speedX)); + speedY = Math.max(-maxSpeed, Math.min(maxSpeed, speedY)); + +// System.out.println(Main.collisionMap.size()); + + cm.move(Main.toSlowMotion(speedX), Main.toSlowMotion(speedY)); + + this.xx = (int) x; + this.yy = (int) y; + + for (int j = 0; j < 2; j++) { + int tone = random.nextInt(30)-15; + int sDir = random.nextInt(359); + int sDistance = random.nextInt(8); + int xx = this.xx + (int) (Math.cos(Math.toRadians(sDir)) * sDistance); + int yy = this.yy + (int) (Math.sin(Math.toRadians(sDir)) * sDistance); + int fadingSpeed = random.nextInt(8)+8; + int size = random.nextInt(4)+2; + Color color = new Color(baseColor.getRed()+tone, baseColor.getGreen()+tone, baseColor.getBlue()+tone); + UniParticle.FadingProcess fadingProcess = new UniParticle.FadingProcess(255, fadingSpeed, false); + particles.add(new UniParticle(xx, yy, size, true, color, fadingProcess)); + } + + particles.forEach(UniParticle::update); + particles.removeIf(particle -> particle.dead); + + + + if(i.isButtonDown(1) && ammo > 0) { + ammo--; +// System.out.println("Shot"); + int addX = (int)(Math.cos(Math.toRadians(Fly.angle(x, y, i.getRelativeMouseX(), i.getRelativeMouseY())-180))*10d); + int addY = (int)(Math.sin(Math.toRadians(Fly.angle(x, y, i.getRelativeMouseX(), i.getRelativeMouseY())-180))*10d); + + int dir = (int) Fly.angle(xx+addX, yy+addY, i.getRelativeMouseX(), i.getRelativeMouseY()); + + double knockBackX = Math.cos(Math.toRadians(dir)) * 4d; + double knockBackY = Math.sin(Math.toRadians(dir)) * 4d; + + cm.move(knockBackX, knockBackY); + + Main.main.camera.cX -= knockBackX; + Main.main.camera.cY -= knockBackY; + + Arrow arrow = new Arrow(xx+addX, yy+addY, dir-180); + arrow.shotByFriendly = !isEnemy; + arrow.addX = speedX; + arrow.addY = speedY; + Main.main.entities.add(arrow); + Main.main.findOnScreenObjects(); + Main.main.camera.shake(0.5f); +// Main.main.camera.bluishEffect = 1f; + } + + /*if(!buildingMode) { + if(i.isButton(1)) { + int x = Math.floorDiv(i.getRelativeMouseX(), 16)*16; + int y = Math.floorDiv(i.getRelativeMouseY(), 16)*16; + + GameObject obj = Main.main.find(x+8, y+8); + + boolean pass = obj == null; + if(!pass) pass = (obj.getClass() != itemSamples[selectedItem].getClass()); + + if(pass) { + try { + if(obj != null) { + Main.main.structuralBlocks.remove(obj); + } + Main.main.structuralBlocks.add(itemSamples[selectedItem].getClass(). + getDeclaredConstructor(int.class,int.class,int.class). + newInstance(x, y, itemSamples[selectedItem].type)); + } catch (Exception e) { + e.printStackTrace(); + } + } +// Main.main.structuralBlocks.add(new StructuralBlock(x, y, StructuralBlock.TYPE_ROCKS)); + Main.main.findOnScreenObjects(); + } else if(i.isButton(3)) { + int x = Math.floorDiv(i.getRelativeMouseX(), 16)*16; + int y = Math.floorDiv(i.getRelativeMouseY(), 16)*16; + Main.main.remove(x+8, y+8); + Main.main.findOnScreenObjects(); + } + } else if (i.isButtonDown(3)) { + // HERE: Shoot + int dir = (int) AdvancedMath.angle(xx, yy, i.getRelativeMouseX(), i.getRelativeMouseY()); + Arrow arrow = new Arrow(xx, yy, dir + 90); + Main.main.entities.add(arrow); + Main.main.findOnScreenObjects(); + Main.main.camera.shake(2f); + Main.main.camera.bluishEffect = 1f; + }*/ + + boolean arrowNear = false; + if (Main.main.entities.size() > 0) { + for(GameObject entity : Main.main.entities) { + if(entity instanceof Arrow) { + if(!((Arrow) entity).shotByFriendly) + if(Fly.distance(x, y, entity.x, entity.y) < 80) { + arrowNear = true; + break; + } + } + } + } + + if(arrowNear || inventoryOpen) { + Main.slowMotionSpeed -= 0.05f; + Main.main.camera.bluishEffect += 0.05f; + } else { +// System.out.println("SlMoSp: "+Main.slowMotionSpeed); +// System.out.println("BlFx: "+Main.main.camera.bluishEffect); + Main.slowMotionSpeed += 0.05f; + Main.main.camera.bluishEffect -= 0.05f; + } + + Main.slowMotionSpeed = (float)AdvancedMath.setRange(Main.slowMotionSpeed, 0.25d, 1d); + Main.main.camera.bluishEffect = (float)AdvancedMath.setRange(Main.main.camera.bluishEffect, 0d, 0.5d); + + coinOverlayAlpha = Math.max(0, coinOverlayAlpha-Main.toSlowMotion(2)); + coinOverlayX += (lastCoinX - coinOverlayX) * 0.1d; + coinOverlayY += (lastCoinY - coinOverlayY) * 0.1d; + + clipOverlayOpen = i.isKey(KeyEvent.VK_V); + + if(clipOverlayOpen) { + clipOverlayRotationTarget = 110; + clipOverlayAlpha += 24; + } else { + clipOverlayRotationTarget = 1; + clipOverlayAlpha -= 24; + } + + clipOverlayRotation += (clipOverlayRotationTarget - clipOverlayRotation) * 0.1d; + clipOverlayAlpha = AdvancedMath.setRange(clipOverlayAlpha, 0, 255); + + if(i.isKeyDown(KeyEvent.VK_R)) { + // HERE: Reload + clip--; + ammo = maxAmmo; + } + +/* + if(inventoryOpen) { + timer--; + if (timer < 0) { + inventoryOpen = false; + timer = 0; + } + } + + if(i.scroll > 0) { + selectedItem++; + if(selectedItem > items.length-1) { + selectedItem = 0; + } + + i.scroll = 0; + inventoryOpen = true; + timer = time; + } else if(i.scroll < 0) { + selectedItem--; + if(selectedItem < 0) { + selectedItem = items.length-1; + } + + i.scroll = 0; + inventoryOpen = true; + timer = time; + } + + if(prevInvOpen && !inventoryOpen) { + buildingMode = (itemSamples[selectedItem] == null); + }*/ + +// Main.main.getE().getRenderer().setCamX(xx - core.width/2); +// Main.main.getE().getRenderer().setCamY(yy - core.height/2); + } + + @Override + public void render(Renderer r) { + particles.forEach(p -> p.render(r)); + if(Main.main.showDebugInfo) + r.fillRectangle(xx, yy, 8, 8, Color.red); + int x = Math.floorDiv(Main.main.getE().getInput().getRelativeMouseX(), 16)*16; + int y = Math.floorDiv(Main.main.getE().getInput().getRelativeMouseY(), 16)*16; + r.fillRectangle(x, y, 16, 16, new Color(40, 100, 70)); + } + + public void renderInventory(Renderer r) { + int startX = midX - items.length*invSize/2; + int startY = midY - invSize/2; + int i = 0; + for(StructuralBlock block : itemSamples) { + if(block != null) + block.render(r, startX + i*invSize+4, startY+4); + i++; + } + r.fillRectangle(startX+selectedItem*invSize, startY, invSize, invSize, new Color(64, 64, 64, 128)); + Font old = r.getG().getFont(); + r.setFont(new Font("Verdana", Font.BOLD, 12)); + r.drawText(itemNames[selectedItem], midX, midY-invSize-4, 12, new Alignment( + Alignment.HOR_CENTER, Alignment.VER_MIDDLE), new Color(64, 64, 64)); + r.setFont(old); + } + + @Override + public String shareSend() { + return null; + } + + @Override + public void shareReceive(String s) { + + } + + public class PlayerParticle { + int x, y, dir, alpha, size, alphaSpeed; + double xD, yD; + float speed; + boolean dead; + + Color color, baseColor = new Color(170, 32, 128); + + public PlayerParticle(int x, int y, int size, int dir, float speed, int tone, int alphaSpeed) { + this.x = x; + this.y = y; + this.dir = dir; + this.speed = speed; + this.size = size; + this.dead = false; + this.alphaSpeed = alphaSpeed; + xD = x; + yD = y; + alpha = 255; + color = new Color(baseColor.getRed()+tone, + baseColor.getGreen()+tone, + baseColor.getBlue()+tone); + } + + public void update() { + if(dead) return; +// xD += Math.cos(Math.toRadians(dir))*speed; +// yD += Math.sin(Math.toRadians(dir))*speed; + +// speed /= 0.9; + + alpha -= alphaSpeed; + + if(alpha < 0) { + dead = true; + return; + } + + this.color = new Color( + calcColorParameter(Main.grassColor.getRed(), baseColor.getRed(), alpha/255f), + calcColorParameter(Main.grassColor.getGreen(), baseColor.getGreen(), alpha/255f), + calcColorParameter(Main.grassColor.getBlue(), baseColor.getBlue(), alpha/255f)); +// System.out.println(color); + + x = (int)xD; + y = (int)yD; + } + + public int calcColorParameter(int colorBack, int colorFront, float alpha) { + return (int)(alpha * colorFront + (1 - alpha) * colorBack); + } + + public void render(Renderer r) { + if(dead) return; + r.fillRectangle(x-size/2, y-size/2, size, size, color); + } + } +} diff --git a/src/com/youngdev/shooter/Rocks.java b/src/com/youngdev/shooter/Rocks.java new file mode 100644 index 0000000..34c37ef --- /dev/null +++ b/src/com/youngdev/shooter/Rocks.java @@ -0,0 +1,92 @@ +package com.youngdev.shooter; + +import com.engine.libs.game.GameObject; +import com.engine.libs.game.Mask; +import com.engine.libs.game.behaviors.AABBComponent; +import com.engine.libs.input.Input; +import com.engine.libs.rendering.Renderer; + +import java.awt.*; +import java.util.ArrayList; +import java.util.Random; + +public class Rocks extends GameObject { + + private ArrayList rocks; + + public Rocks(int x, int y) { + super(7, 10); + this.x = x; + this.y = y; + this.solid = true; + + // HERE: Fix depth + Random random = new Random(); + this.depth = random.nextInt(1023)+depth*1024; + + rocks = new ArrayList<>(); + int numRocks = random.nextInt(4)+5; + int smallestX=Integer.MAX_VALUE, smallestY=Integer.MAX_VALUE, largestX=Integer.MIN_VALUE, largestY=Integer.MIN_VALUE; + for(int i = 0; i < numRocks; i++) { + // HERE: Create a leave + int xx = x-random.nextInt(24)+12; + int yy = y-random.nextInt(24)+12; + int size = random.nextInt(6)+12; + rocks.add(new Rock(xx, yy, size, random.nextInt(8)*5)); + + smallestX = Math.min(smallestX, (int)Math.floor(xx-size/2d)); + smallestY = Math.min(smallestY, (int)Math.floor(yy-size/2d)); + largestX = Math.max(largestX, (int)Math.ceil(xx+size/2d)); + largestY = Math.max(largestY, (int)Math.ceil(yy+size/2d)); + } + + this.mask = new Mask.Rectangle(smallestX, smallestY, largestX-smallestX, largestY-smallestY); + this.aabbComponent = new AABBComponent(this.mask); + } + + @Override + public void update(Input input) { + + } + + @Override + public void render(Renderer r) { + for(Rock rock : rocks) { + r.fillRectangle(rock.x-rock.size/2, rock.y-rock.size/2, + rock.size, rock.size, rock.getColor()); + } + + if(Main.main.showDebugInfo) { + r.fillRectangle(this.mask.x, this.mask.y, ((Mask.Rectangle) mask).w, ((Mask.Rectangle) mask).w, Color.red); + } + } + + @Override + public String shareSend() { + return null; + } + + @Override + public void shareReceive(String s) { + + } + + public class Rock { + public int x, y, size, tone; + public Color baseColor = new Color(70, 70, 70); + + public Rock(int x, int y, int size, int tone) { + this.x = x; + this.y = y; + this.size = size; + this.tone = tone; + } + + public Color getColor() { + return new Color( + baseColor.getRed()+tone, + baseColor.getGreen()+tone, + baseColor.getBlue()+tone); + } + } +} diff --git a/src/com/youngdev/shooter/StructuralBlock.java b/src/com/youngdev/shooter/StructuralBlock.java new file mode 100644 index 0000000..ade38de --- /dev/null +++ b/src/com/youngdev/shooter/StructuralBlock.java @@ -0,0 +1,126 @@ +package com.youngdev.shooter; + +import com.engine.libs.game.GameObject; +import com.engine.libs.game.Mask; +import com.engine.libs.game.behaviors.AABBComponent; +import com.engine.libs.input.Input; +import com.engine.libs.rendering.Renderer; + +import java.awt.*; +import java.util.ArrayList; +import java.util.Random; + +public class StructuralBlock extends GameObject { + public int type; + public ArrayList particles; + + public static final int TYPE_ROCKS = 1, TYPE_WOOD = 2, TYPE_FIBER = 3, TYPE_WOOD_FLOORING = 4; + + public StructuralBlock(int x, int y, int type) { + super(8, 14); + this.type = type; + this.x = x; + this.y = y; + + Random random = new Random(); + particles = new ArrayList<>(); + + if(type == TYPE_ROCKS) { + this.solid = true; + this.depth = 14; + int numRocks = random.nextInt(10) + 20; + for (int i = 0; i < numRocks; i++) { + int xx = x + random.nextInt(12) + 3; + int yy = y + random.nextInt(12) + 3; + int tone = random.nextInt(3) - 5; + tone *= 5; + Color color = new Color(80 + tone, 80 + tone, 80 + tone); + particles.add(new UniParticle(xx, yy, random.nextInt(3) + 7, true, color)); + } + } else if (type == TYPE_WOOD) { + this.solid = true; + this.depth = 7; + int numPieces = random.nextInt(10) + 20; + for (int i = 0; i < numPieces; i++) { + int xx = x + random.nextInt(12) + 3; + int yy = y + random.nextInt(12) + 3; + int tone = random.nextInt(3) - 5; + tone *= 5; + Color baseColor = new Color(158, 109, 80); + Color color = new Color( + baseColor.getRed() + tone, + baseColor.getGreen() + tone, + baseColor.getBlue() + tone); + particles.add(new UniParticle(xx, yy, random.nextInt(3) + 7, true, color)); + } + } else if (type == TYPE_FIBER) { + this.solid = true; + this.depth = 7; + int numPieces = random.nextInt(10) + 20; + for (int i = 0; i < numPieces; i++) { + int xx = x + random.nextInt(12) + 3; + int yy = y + random.nextInt(12) + 3; + int tone = random.nextInt(3) - 5; + tone *= 5; + Color baseColor = new Color(128, 79, 50); + Color color = new Color( + baseColor.getRed() + tone, + baseColor.getGreen() + tone, + baseColor.getBlue() + tone); + particles.add(new UniParticle(xx, yy, random.nextInt(3) + 7, true, color)); + } + } else if (type == TYPE_WOOD_FLOORING) { + this.solid = false; + this.depth = 7; + int numPieces = random.nextInt(10) + 20; + for (int i = 0; i < numPieces; i++) { + int xx = x + random.nextInt(12) + 3; + int yy = y + random.nextInt(12) + 3; + int tone = random.nextInt(3) - 5; + tone *= 5; + Color baseColor = new Color(178, 139, 100); + Color color = new Color( + baseColor.getRed() + tone, + baseColor.getGreen() + tone, + baseColor.getBlue() + tone); + particles.add(new UniParticle(xx, yy, random.nextInt(3) + 7, true, color)); + } + } + + // HERE: Fix depth + this.depth = random.nextInt(1023)+depth*1024; + + this.mask = new Mask.Rectangle(x, y, 16, 16); + if(solid) + this.aabbComponent = new AABBComponent(this.mask); + } + + @Override + public void update(Input input) { + particles.removeIf(p -> { + p.update(); + return p.dead; + }); + } + + @Override + public void render(Renderer renderer) { + particles.forEach(p -> p.render(renderer)); + } + + public void render(Renderer r, int x, int y) { + r.shift(x, y); + particles.forEach(p -> p.render(r)); + r.shift(-x, -y); + } + + @Override + public String shareSend() { + return null; + } + + @Override + public void shareReceive(String s) { + + } +} diff --git a/src/com/youngdev/shooter/Terrain.java b/src/com/youngdev/shooter/Terrain.java new file mode 100644 index 0000000..972df60 --- /dev/null +++ b/src/com/youngdev/shooter/Terrain.java @@ -0,0 +1,110 @@ +package com.youngdev.shooter; + +import com.engine.libs.game.GameObject; +import com.engine.libs.game.Mask; +import com.engine.libs.input.Input; +import com.engine.libs.rendering.Renderer; + +import java.awt.*; +import java.util.ArrayList; +import java.util.Random; + +public class Terrain extends GameObject { + private ArrayList patches; + + public static final int TYPE_SMALL_ROCKS = 1, + TYPE_DIRT_PATCH = 2; + + public Terrain(int x, int y, int type) { + super(9, 0); + this.x = x; + this.y = y; + + // HERE: Fix depth + Random random = new Random(); + this.depth = random.nextInt(1023)+depth*1024; + + patches = new ArrayList<>(); + int range = 48; + int smallestX=Integer.MAX_VALUE, smallestY=Integer.MAX_VALUE, largestX=Integer.MIN_VALUE, largestY=Integer.MIN_VALUE; + switch (type) { + case TYPE_DIRT_PATCH: + range = random.nextInt(32)+48; + int num = random.nextInt(24)+24; + for(int i = 0; i < num; i++) { + int xx = x-random.nextInt(range*2)+range; + int yy = y-random.nextInt(range*2)+range; + int size = random.nextInt(6)+5; + int tone = random.nextInt(20); + Color baseColor = new Color(60, 120, 90); + Color color = new Color(baseColor.getRed()+tone, + baseColor.getGreen()+tone, + baseColor.getBlue()+tone); + patches.add(new Patch(xx, yy, size, color)); + smallestX = Math.min(smallestX, xx-size/2); + smallestY = Math.min(smallestY, yy-size/2); + largestX = Math.max(largestX, (int)Math.ceil(xx+size/2d)); + largestY = Math.max(largestY, (int)Math.ceil(yy+size/2d)); + } + break; + case TYPE_SMALL_ROCKS: + range = random.nextInt(16)+32; + num = random.nextInt(24)+12; + for(int i = 0; i < num; i++) { + int xx = x-random.nextInt(range*2)+range; + int yy = y-random.nextInt(range*2)+range; + int size = random.nextInt(1)+2; + int tone = random.nextInt(20); + Color baseColor = new Color(80, 80, 80); + Color color = new Color(baseColor.getRed()+tone, + baseColor.getGreen()+tone, + baseColor.getBlue()+tone); + patches.add(new Patch(xx, yy, size, color)); + patches.add(new Patch(xx, yy, size, color)); + smallestX = Math.min(smallestX, xx-size/2); + smallestY = Math.min(smallestY, yy-size/2); + largestX = Math.max(largestX, (int)Math.ceil(xx+size/2d)); + largestY = Math.max(largestY, (int)Math.ceil(yy+size/2d)); + } + break; + } + + mask = new Mask.Rectangle(smallestX, smallestY, largestX-smallestX, largestY-smallestY); + } + + @Override + public void update(Input input) { + + } + + @Override + public void render(Renderer r) { + patches.forEach(obj -> obj.render(r)); + } + + @Override + public String shareSend() { + return null; + } + + @Override + public void shareReceive(String s) { + + } + + public class Patch { + public int x, y, size; + public Color color; + + public Patch(int x, int y, int size, Color color) { + this.x = x; + this.y = y; + this.size = size; + this.color = color; + } + + public void render(Renderer r) { + r.fillRectangle(x-size/2, y-size/2, size, size, color); + } + } +} diff --git a/src/com/youngdev/shooter/Trash.java b/src/com/youngdev/shooter/Trash.java new file mode 100644 index 0000000..b2c627d --- /dev/null +++ b/src/com/youngdev/shooter/Trash.java @@ -0,0 +1,187 @@ +package com.youngdev.shooter; + +import com.engine.libs.game.GameObject; +import com.engine.libs.game.Mask; +import com.engine.libs.input.Input; +import com.engine.libs.rendering.Renderer; + +import java.awt.*; +import java.util.ArrayList; +import java.util.Random; + +public class Trash extends GameObject { + + private int type; + private Random random; + private ArrayList particles; + + public static final int TYPE_BRANCHES = 1, TYPE_WATER = 2, TYPE_MUD = 3; + + public Trash(int x, int y) { + super(10, 5); + this.x = x; + this.y = y; + random = new Random(); + + // HERE: Fix depth + this.depth = random.nextInt(1023)+depth*1024; + + this.type = random.nextInt(3)+1; +// this.type = TYPE_BRANCHES; + + particles = new ArrayList<>(); + + switch (type) { + case TYPE_BRANCHES: + Color baseColor = new Color(75, 11, 13); + Color c; + + for(int i = 0; i < random.nextInt(4)+10; i++) { + int tone = random.nextInt(20)-10; + c = new Color( + baseColor.getRed()+tone, + baseColor.getGreen()+tone, + baseColor.getBlue()+tone + ); + + int addX = random.nextInt(50)-25; + int addY = random.nextInt(50)-25; + + double length = random.nextDouble()*4+5; + double angle = Math.toRadians(random.nextInt(359)); + int x1 = (int)(Math.cos(angle)*length); + int y1 = (int)(Math.sin(angle)*length); + int x2 = (int)(Math.cos(angle-180)*length); + int y2 = (int)(Math.sin(angle-180)*length); + int width = random.nextInt(2)+2; + + particles.add(new UniParticle(x+addX, y+addY, 0, true, c) { + @Override + public void render(Renderer r) { + r.drawLineWidth(x+x1, y+y1, x+x2, y+y2, width, color); + } + }); + } + this.mask = new Mask.Rectangle(x-30, y-30, 60, 60); + break; + case TYPE_WATER: + baseColor = new Color(150, 150, 230); + baseColor = new Color( + UniParticle.calcColorParameter(Main.grassColor.getRed(), baseColor.getRed(), 0.25f), + UniParticle.calcColorParameter(Main.grassColor.getGreen(), baseColor.getGreen(), 0.25f), + UniParticle.calcColorParameter(Main.grassColor.getBlue(), baseColor.getBlue(), 0.25f) + ); + + for(int i = 0; i < random.nextInt(4)+10; i++) { + int addX = random.nextInt(30)-15; + int addY = random.nextInt(30)-15; + int size = random.nextInt(8)+14; + + UniParticle.Process colorRandomizer = new UniParticle.Process() { + private Color startColor; + private int toneBounds, step; + private double currentTone; + + @Override + public void init() { + startColor = owner.color; + toneBounds = 4; + currentTone = 0; +// step = random.nextInt(359); + } + + @Override + public void render(Renderer r) { + + } + + @Override + public void update() { + step = (step+1)%360; +// currentTone = Math.min(toneBounds, Math.max(-toneBounds, )); + currentTone = Math.cos(Math.toRadians(step))*toneBounds; + owner.color = new Color( + startColor.getRed()+(int)currentTone, + startColor.getGreen()+(int)currentTone, + startColor.getBlue()+(int)currentTone + ); + } + }; + + particles.add(new UniParticle(x+addX, y+addY, size, true, baseColor, colorRandomizer)); + } + this.mask = new Mask.Rectangle(x-30, y-30, 60, 60); + break; + case TYPE_MUD: + baseColor = new Color(99, 27, 23); + baseColor = new Color( + UniParticle.calcColorParameter(Main.grassColor.getRed(), baseColor.getRed(), 0.25f), + UniParticle.calcColorParameter(Main.grassColor.getGreen(), baseColor.getGreen(), 0.25f), + UniParticle.calcColorParameter(Main.grassColor.getBlue(), baseColor.getBlue(), 0.25f) + ); + + for(int i = 0; i < random.nextInt(4)+10; i++) { + int addX = random.nextInt(30)-15; + int addY = random.nextInt(30)-15; + int size = random.nextInt(8)+14; + + UniParticle.Process colorRandomizer = new UniParticle.Process() { + private Color startColor; + private int toneBounds, step; + private double currentTone; + + @Override + public void init() { + startColor = owner.color; + toneBounds = 4; + currentTone = 0; +// step = random.nextInt(359); + } + + @Override + public void render(Renderer r) { + + } + + @Override + public void update() { + step = (step+1)%360; +// currentTone = Math.min(toneBounds, Math.max(-toneBounds, )); + currentTone = Math.cos(Math.toRadians(step))*toneBounds; + owner.color = new Color( + startColor.getRed()+(int)currentTone, + startColor.getGreen()+(int)currentTone, + startColor.getBlue()+(int)currentTone + ); + } + }; + + particles.add(new UniParticle(x+addX, y+addY, size, true, baseColor, colorRandomizer)); + } + this.mask = new Mask.Rectangle(x-30, y-30, 60, 60); + break; + } + } + + @Override + public void update(Input input) { + if(type == TYPE_WATER || type == TYPE_MUD) { + particles.forEach(UniParticle::update); + } + } + + @Override + public void render(Renderer r) { + particles.forEach(o -> o.render(r)); + } + + @Override + public String shareSend() { + return null; + } + + @Override + public void shareReceive(String s) { + + } +} diff --git a/src/com/youngdev/shooter/Tree.java b/src/com/youngdev/shooter/Tree.java new file mode 100644 index 0000000..de9b931 --- /dev/null +++ b/src/com/youngdev/shooter/Tree.java @@ -0,0 +1,138 @@ +package com.youngdev.shooter; + +import com.engine.libs.game.GameObject; +import com.engine.libs.game.Mask; +import com.engine.libs.input.Input; +import com.engine.libs.rendering.Renderer; + +import java.awt.*; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.Random; + +public class Tree extends GameObject { + + private ArrayList leaf; + private Random random; + private boolean prevCollision, fliesInside; + + public Tree(int x, int y) { + super(11, 20); + this.x = x; + this.y = y; + this.fliesInside = true; + + // HERE: Fix depth + this.random = new Random(); + this.depth = random.nextInt(1023)+depth*1024; + + leaf = new ArrayList<>(); + + + // HERE: Tree gen V 1.0 + Rectangle bounds = spawnLeaf(24, 36, 24, 0, 0); + + mask = new Mask.Rectangle((double)bounds.x, (double)bounds.y, bounds.width, bounds.height); + } + + @Override + public void update(Input input) { + boolean collision = false; + + Iterator it; + for(it = Main.main.visibleChunkObjects.iterator(); it.hasNext();) { + GameObject obj = it.next(); + if (obj instanceof Arrow || (obj instanceof Healable && obj.depth > this.depth)) + if(obj.mask != null) + if (obj.mask.isColliding(mask) || + Fly.distance(x, y, obj.x, obj.y) < 64) { + collision = true; + break; + } + } + + boolean collision_EffectivelyFinal = collision; + boolean spawn = random.nextInt(16) == 3; + + leaf.forEach(leave -> { + if(collision_EffectivelyFinal) {/* && !this.prevCollision) {*/ + leave.speed = 24d; + if(fliesInside) { + if (spawn) { + for (int i = 0; i < random.nextInt(5) + 3; i++) { + int xx = (int) x + random.nextInt(24) - 12; + int yy = (int) y + random.nextInt(24) - 12; + Main.main.flies.add(new Fly(xx, yy, false)); + } + fliesInside = false; + } + } + } + leave.step+=Main.toSlowMotion(leave.speed); + leave.speed=Math.max(1, leave.speed-0.25); + leave.addX = (int)(Math.cos(Math.toRadians(leave.step))*2d); + leave.addY = (int)(Math.sin(Math.toRadians(leave.step))*2d); + }); + + this.prevCollision = collision_EffectivelyFinal; + } + + @Override + public void render(Renderer r) { + leaf.forEach(leave -> r.fillRectangle(leave.x-leave.size/2+leave.addX, leave.y-leave.size/2+leave.addY, + leave.size, leave.size, leave.getColor())); + } + + @Override + public String shareSend() { + return null; + } + + @Override + public void shareReceive(String s) { + + } + + private Rectangle spawnLeaf(int minLeaf, int maxLeaf, int distanceLimit, int offX, int offY) { + int numLeaf = random.nextInt(maxLeaf-minLeaf) + minLeaf; + int smallestX=Integer.MAX_VALUE, smallestY=Integer.MAX_VALUE, largestX=Integer.MIN_VALUE, largestY=Integer.MIN_VALUE; + for (int i = 0; i < numLeaf; i++) { + // HERE: Create a leave + int xx = (int)x - random.nextInt(distanceLimit*2) + distanceLimit + offX; + int yy = (int)y - random.nextInt(distanceLimit*2) + distanceLimit + offY; + int size = (int)((random.nextInt(30)+24f)*(i/numLeaf+0.5f)); + leaf.add(new Leaf(xx, yy, size, random.nextInt(15), random.nextInt(359))); + + smallestX = Math.min(smallestX, xx-size/2); + smallestY = Math.min(smallestY, yy-size/2); + largestX = Math.max(largestX, (int)Math.ceil(xx+size/2d)); + largestY = Math.max(largestY, (int)Math.ceil(yy+size/2d)); + } + + return new Rectangle(smallestX, smallestY, largestX-smallestX, largestY-smallestY); + } + + public class Leaf { + public int x, y, addX, addY, size, tone; + public double speed, step; + public Color baseColor = new Color(49, 107, 38); + + public Leaf(int x, int y, int size, int tone, int step) { + this.x = x; + this.y = y; + this.step = step; + this.addX = 0; + this.addY = 0; + this.speed = 1d; + this.size = size; + this.tone = tone; + } + + public Color getColor() { + return new Color( + baseColor.getRed()+tone, + baseColor.getGreen()+tone, + baseColor.getBlue()+tone); + } + } +} diff --git a/src/com/youngdev/shooter/UniParticle.java b/src/com/youngdev/shooter/UniParticle.java new file mode 100644 index 0000000..cfe5ad2 --- /dev/null +++ b/src/com/youngdev/shooter/UniParticle.java @@ -0,0 +1,314 @@ +package com.youngdev.shooter; + +import com.engine.libs.game.GameObject; +import com.engine.libs.game.Mask; +import com.engine.libs.input.Input; +import com.engine.libs.math.AdvancedMath; +import com.engine.libs.rendering.Renderer; + +import java.awt.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Random; + +public class UniParticle { + public int x, y, size; + public Color color; + public ArrayList processes; + public boolean dead, affectedBySlowMotion; + + public UniParticle(int x, int y, int size, boolean affectedBySlowMotion, Color color) { + this.x = x; + this.y = y; + this.dead = false; + this.size = size; + this.affectedBySlowMotion = affectedBySlowMotion; + this.color = color; + processes = new ArrayList<>(); + } + + public UniParticle(int x, int y, int size, boolean affectedBySlowMotion, Color color, Process... processes) { + this.x = x; + this.y = y; + this.dead = false; + this.size = size; + this.affectedBySlowMotion = affectedBySlowMotion; + this.color = color; + this.processes = new ArrayList<>(Arrays.asList(processes)); + this.processes.forEach(p -> { + p.owner = this; + p.init(); + }); + } + + public UniParticleInstance asInstance(int depth) { + return new UniParticleInstance(this, depth); + } + + public void render(Renderer r) { + if(dead) return; + r.fillRectangle(x-size/2, y-size/2, size, size, color); + processes.forEach(p -> p.render(r)); + } + + public void update() { + if(dead) return; + processes.forEach(Process::update); + } + + public static abstract class Process { + UniParticle owner; + public abstract void init(); + public abstract void render(Renderer r); + public abstract void update(); + } + + public static class ColorChangeEffect extends Process { + public Color from, to; + public double step, stepSpeed; + + public ColorChangeEffect(Color from, Color to, double step, double stepSpeed) { + this.from = from; + this.to = to; + this.step = step; + this.stepSpeed = stepSpeed; + } + + @Override + public void init() { + super.owner.color = from; + } + + @Override + public void render(Renderer r) { + + } + + @Override + public void update() { + if(owner.affectedBySlowMotion) + step += Main.toSlowMotion(stepSpeed); + else step += stepSpeed; + if(step >= 255 || step <= 0) { + super.owner.dead = true; + } + + owner.color = new Color( + calcColorParameter(owner.color.getRed(), to.getRed(), 0f + (float)step / 255f), + calcColorParameter(owner.color.getGreen(), to.getGreen(), 0f + (float)step / 255f), + calcColorParameter(owner.color.getBlue(), to.getBlue(), 0f + (float)step / 255f) + ); + } + } + + public static class MovingProcess extends Process { + public double speed, speedAdder; + public double direction, xD, yD; + public double speedX, speedY; + + private MovingProcess(double speedX, double speedY, double direction, + double speed, boolean useXY, double speedAdder) { + this.speedX = speedX; + this.speedY = speedY; + this.direction = direction; + this.speed = speed; + calcSpeeds(useXY); + this.speedAdder = speedAdder; + } + + public static MovingProcess create(float speedX, float speedY) { + return new MovingProcess(speedX, speedY, 0, 0, true, 0); + } + + public static MovingProcess create(double direction, float speed) { + return new MovingProcess(0, 0, direction, speed, false, 0); + } + + public static MovingProcess create(float speedX, float speedY, double speedAdder) { + return new MovingProcess(speedX, speedY, 0, 0, true, speedAdder); + } + + public static MovingProcess create(double direction, float speed, double speedAdder) { + return new MovingProcess(0, 0, direction, speed, false, speedAdder); + } + + public void calcSpeeds(boolean fromXY) { + if(fromXY) { + direction = Fly.angle(0, 0, speedX, speedY); + speed = (float) Fly.distance(0, 0, speedX, speedY); + } else { + speedX = Math.cos(Math.toRadians(direction)) * speed; + speedY = Math.sin(Math.toRadians(direction)) * speed; + } + } + + @Override + public void init() { + xD = super.owner.x; + yD = super.owner.y; + } + + @Override + public void render(Renderer r) { + + } + + @Override + public void update() { + if(owner.affectedBySlowMotion) + speed += Main.toSlowMotion(speedAdder); + else speed += speedAdder; + + if(owner.affectedBySlowMotion) { + xD += Main.toSlowMotion(speedX); + yD += Main.toSlowMotion(speedY); + } else { + xD += speedX; + yD += speedY; + } + + super.owner.x = (int)xD; + super.owner.y = (int)yD; + } + } + + public static class FollowingProcess extends Process { + private GameObject target; + private int targetShiftX, targetShiftY; + private float speed; + private double xD, yD; + + public FollowingProcess(GameObject target, int targetShiftX, int targetShiftY, float speed) { + this.target = target; + this.targetShiftX = targetShiftX; + this.targetShiftY = targetShiftY; + this.speed = speed; + } + + @Override + public void init() { + this.xD = owner.x; + this.yD = owner.y; + } + + @Override + public void render(Renderer r) { + + } + + @Override + public void update() { + xD = owner.x; + yD = owner.y; + + double dir = AdvancedMath.angle(owner.x, owner.y, (int)target.x+targetShiftX, (int)target.y+targetShiftY); + + double addX = Math.cos(Math.toRadians(dir)) * speed; + double addY = Math.sin(Math.toRadians(dir)) * speed; + + if(owner.affectedBySlowMotion) { + xD += Main.toSlowMotion(addX); + yD += Main.toSlowMotion(addY); + } else { + xD += addX; + yD += addY; + } + + owner.x = (int)xD; + owner.y = (int)yD; + } + } + + public static class FadingProcess extends Process { + double alpha, alphaSpeed; + boolean usesAlphaChannel; + + public FadingProcess(int alpha, int alphaSpeed) { + this.alpha = alpha; + this.alphaSpeed = alphaSpeed; + this.usesAlphaChannel = false; + } + + public FadingProcess(int alpha, int alphaSpeed, boolean usesAlphaChannel) { + this.alpha = alpha; + this.alphaSpeed = alphaSpeed; + this.usesAlphaChannel = usesAlphaChannel; + } + + @Override + public void init() { + + } + + @Override + public void render(Renderer r) { + + } + + @Override + public void update() { + +// alpha -= alphaSpeed; + if(owner.affectedBySlowMotion) alpha -= Main.toSlowMotion(alphaSpeed); + else alpha -= alphaSpeed; + + if(alpha < 0d) { + owner.dead = true; + return; + } + + if(usesAlphaChannel) { + owner.color = new Color(owner.color.getRed(), owner.color.getGreen(), owner.color.getBlue(), ((int) alpha)); + } else { + owner.color = new Color( + calcColorParameter(Main.grassColor.getRed(), owner.color.getRed(), (float) (alpha / 255f)), + calcColorParameter(Main.grassColor.getGreen(), owner.color.getGreen(), (float)(alpha / 255f)), + calcColorParameter(Main.grassColor.getBlue(), owner.color.getBlue(), (float)(alpha / 255f)) + ); + } + } + } + + public static int calcColorParameter(int colorBack, int colorFront, float alpha) { + return (int)(alpha * (float)colorFront) + (int)((1f - alpha) * (float)colorBack); + } + + public class UniParticleInstance extends GameObject { + UniParticle owner; + + public UniParticleInstance(UniParticle owner, int depth) { + super(12, depth); + this.owner = owner; + + // HERE: Fix depth + Random random = new Random(); + this.depth = random.nextInt(1023)+depth*1024; + + this.x = owner.x; + this.y = owner.y; + + this.mask = new Mask.Rectangle((int)x-size/2, (int)y-size/2, size, size); + } + + @Override + public void update(Input input) { + owner.update(); + } + + @Override + public void render(Renderer r) { + owner.render(r); + } + + @Override + public String shareSend() { + return null; + } + + @Override + public void shareReceive(String s) { + + } + } + +}