Skip to content

Instantly share code, notes, and snippets.

@jimgong92
Created June 18, 2014 14:04
Show Gist options
  • Save jimgong92/3a17eb7b04b00444ca02 to your computer and use it in GitHub Desktop.
Save jimgong92/3a17eb7b04b00444ca02 to your computer and use it in GitHub Desktop.
Aerial View Game - In Development
package com.jimgong.rain.graphics;
public class AnimatedSprite extends Sprite {
private int animate_step = 0;
private int animate_speed = 32;
private int frame_length = animate_speed >> 2;
private boolean animate = false;
//direction = column (N - 0, E - 1, S - 2, W - 3)
//animation step = row
public AnimatedSprite(int size, int x, int y, SpriteSheet sheet) {
super(size, x, y, sheet);
}
public void update(int direction) {
if (animate_step++ >= 2100) animate_step = 0;
//Update direction
x = direction * SIZE;
//If supposed to be animating,
if (animate) y = ((animate_step % animate_speed)/ frame_length) * SIZE;
else y = 0;
load();
}
public void animateControl(boolean moving) {
animate = moving;
}
}
package com.jimgong.rain.entity.mob;
import java.util.List;
import com.jimgong.rain.entity.valuebar.Hitpoints;
import com.jimgong.rain.graphics.AnimatedSprite;
import com.jimgong.rain.graphics.Screen;
import com.jimgong.rain.graphics.SpriteSheet;
public class Chaser extends Mob {
private int time = 0;
private AnimatedSprite animSprite;
private int xa, ya;
//chases within 10 tile radius
private int chaseRadius = 10 << 4;
public Chaser(int x, int y) {
this.x = x << 4;
this.y = y << 4;
animSprite = new AnimatedSprite(16, 0, 0, SpriteSheet.charmander);
sprite = animSprite;
hp = new Hitpoints(16, x, y);
}
//chase player
private void chase() {
xa = 0; ya = 0;
List<Player> players = level.getPlayersInRadius(this, chaseRadius);
if (players.size() > 0) {
Player player = players.get(0);
if (x < player.getX()) xa++;
if (x > player.getX()) xa--;
if (y < player.getY()) ya++;
if (y > player.getY()) ya--;
}
}
private void attack() {
List<Player> attackRadius = level.getPlayersInRadius(this, 8);
for (int i = 0; i < attackRadius.size(); i++) {
attackRadius.get(i).getHitpoints().setPoints(1);
}
}
public void update() {
if (time++ > 210000) time = 0;
chase();
if (xa != 0 || ya != 0) moving = true;
else moving = false;
if (moving) {
if (ya < 0) dir = NORTH;
if (ya > 0) dir = SOUTH;
if (xa < 0) dir = WEST;
if (xa > 0) dir = EAST;
move(xa, ya);
}
animSprite.update(dir);
animSprite.animateControl(moving);
if (!hp.isDead()) hp.update(x + Hitpoints.X_OFFSET, y + Hitpoints.Y_OFFSET);
else remove();
if (time >= 10) {
attack();
time = 0;
}
}
public void render(Screen screen) {
//Center sprite
int xx = x - sprite.SIZE / 2;
int yy = y - sprite.SIZE / 2;
screen.renderMob(xx, yy, this);
}
}
package com.jimgong.rain.entity.mob;
import com.jimgong.rain.entity.valuebar.Hitpoints;
import com.jimgong.rain.graphics.AnimatedSprite;
import com.jimgong.rain.graphics.Screen;
import com.jimgong.rain.graphics.SpriteSheet;
public class Dummy extends Mob {
private int animate_step = 0;
private int animate_speed = 30;
private AnimatedSprite sprite;
//x & y are starting coordinates
public Dummy(int x, int y) {
//Shift left by 4 (x16) to adjust for tile size
this.x = x << 4;
this.y = y << 4;
sprite = new AnimatedSprite(16, 0, 0, SpriteSheet.charmander);
hp = new Hitpoints(16, x, y);
}
public void update() {
//Note direction sprite is supposed to move
int xa = 0, ya = 0;
//Update animation, prevent crashing
if (animate_step++ >= 2100) animate_step = 0;
//at every animate_speed interval, randomly generate a new direction and if moving
if (animate_step % animate_speed == 0) {
dir = random.nextInt(4);
//1 in 3 chance to not move
if (random.nextInt(3) == 2) moving = false;
else moving = true;
}
if (moving) {
if (dir == NORTH) ya--;
if (dir == SOUTH) ya++;
if (dir == WEST) xa--;
if (dir == EAST) xa++;
move(xa, ya);
}
sprite.update(dir);
sprite.animateControl(moving);
if (!hp.isDead()) hp.update(x + Hitpoints.X_OFFSET, y + Hitpoints.Y_OFFSET);
else remove();
}
public void render(Screen screen) {
//Center sprite
int xx = x - sprite.SIZE / 2;
int yy = y - sprite.SIZE / 2;
screen.renderMob(xx, yy, sprite, 0);
}
}
package com.jimgong.rain.entity;
import java.util.Random;
import com.jimgong.rain.graphics.Screen;
import com.jimgong.rain.level.Level;
public abstract class Entity {
protected int x, y; //Location of particular entity
protected boolean removed = false;
protected Level level;
protected final Random random = new Random();
public void update() {
}
public void render(Screen screen) {
}
public void remove() {
//Removes entity from level
removed = true;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public boolean isRemoved() {
return removed;
}
public void init(Level level) {
this.level = level;
}
}
package com.jimgong.rain.level.tile;
import com.jimgong.rain.graphics.Screen;
import com.jimgong.rain.graphics.Sprite;
public class FlowerTile extends Tile {
public FlowerTile(Sprite sprite) {
super(sprite);
}
public void render(int x, int y, Screen screen) {
screen.renderTile(x << 4, y << 4, this);
}
}
package com.jimgong.rain;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;
import javax.swing.JFrame;
import com.jimgong.rain.entity.mob.Player;
import com.jimgong.rain.graphics.Screen;
import com.jimgong.rain.graphics.Sprite;
import com.jimgong.rain.input.Keyboard;
import com.jimgong.rain.input.Mouse;
import com.jimgong.rain.level.Level;
import com.jimgong.rain.level.TileCoordinate;
//
public class Game extends Canvas implements Runnable {
private static final long serialVersionUID = 1L;
//Screen Resolution 16 x 9 ratio
private static int width = 300;
private static int height = width / 16 * 9; //168
private static int scale = 3;
public static String title = "Rain";
private Thread gameThread;
private JFrame frame;
private Keyboard key;
private Level level;
private Player player;
private boolean running = false;
private Screen screen;
private BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
private int[] pixels = ((DataBufferInt)image.getRaster().getDataBuffer()).getData();
public Game() {
Dimension size = new Dimension(width * scale, height * scale);
setPreferredSize(size);
screen = new Screen(width, height);
frame = new JFrame();
key = new Keyboard();
//level = new RandomLevel(64, 64);
level = Level.spawn;
TileCoordinate playerSpawn = new TileCoordinate(19,30);
player = new Player(playerSpawn.x(), playerSpawn.y(), key);
level.add(player);
addKeyListener(key);
Mouse mouse = new Mouse();
addMouseListener(mouse);
addMouseMotionListener(mouse);
}
public static int getWindowWidth() {
return width * scale;
}
public static int getWindowHeight() {
return height * scale;
}
public synchronized void start() {
running = true;
gameThread = new Thread(this, "Display");
gameThread.start();
}
//Method to stop the applet
public synchronized void stop() {
running = false;
try {
gameThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//Run method
public void run() {
//Store time
long lastTime = System.nanoTime();
long timer = System.currentTimeMillis();
final double ns = 1000000000.0 / 60.0;
double delta = 0; //Accumulator
int frames = 0;
int updates = 0;
requestFocus();
while (running) {
long now = System.nanoTime();
delta += (now - lastTime) / ns;
lastTime = now; //Update lastTime
while (delta >= 1) {
update(); //Restrict to 60fps
updates++;
delta--;
}
render();
frames++;
if (System.currentTimeMillis() - timer > 1000) {
timer += 1000;
frame.setTitle(title + " | " + updates + " ups " + frames + " fps"); //display fps in window title
updates = 0; frames = 0;
}
}
}
public void update() {
key.update();
level.update();
}
public void render() {
BufferStrategy bs = getBufferStrategy();
if (bs == null) { //If no buffer strategy on canvas
createBufferStrategy(3); //3 is number of buffers
return;
}
screen.clear();
//Center player
int xScroll = player.getX() - screen.width / 2;
int yScroll = player.getY() - screen.height / 2;
level.render(xScroll, yScroll, screen);
for (int i = 0; i < pixels.length; i++) {
pixels[i] = screen.pixels[i];
}
Graphics g = bs.getDrawGraphics();
g.drawImage(image, 0, 0, getWidth(), getHeight(), null);
g.setColor(Color.WHITE);
g.setFont(new Font("Verdana", 0, 20));
g.drawString("Button: " + Mouse.getButton(), 20, 20);
g.drawString("X: " + player.getX() + ", Y: " + player.getY(), 350, 300);
g.dispose();
bs.show();
}
/** Main Method */
public static void main(String[] args) {
Game game = new Game();
game.frame.setResizable(false);
game.frame.setTitle(Game.title);
game.frame.add(game);
game.frame.pack();
game.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
game.frame.setLocationRelativeTo(null);
game.frame.setVisible(true);
game.start();
}
}
//Grass tile has no collision, so no need to override solid method
package com.jimgong.rain.level.tile;
import com.jimgong.rain.graphics.Screen;
import com.jimgong.rain.graphics.Sprite;
public class GrassTile extends Tile{
public GrassTile(Sprite sprite) {
super(sprite);
}
public void render(int x, int y, Screen screen) {
screen.renderTile(x << 4, y << 4, this);
}
}
package com.jimgong.rain.entity.valuebar;
public class Hitpoints extends ValueBar {
public static final int HITPOINTS_COLOR = 0xFFFF0000;
public static final int EMPTY_COLOR = 0xFFFF8080;
public static final int X_OFFSET = 9;
public static final int Y_OFFSET = -8;
//x & y visibility coordinates relative to the Mob to whom it belongs
//HP bar visible to the right of the player
public Hitpoints (int hitpoints, int x, int y) {
//2 pixels wide, offset by 2 pixels from player
super(hitpoints, x + X_OFFSET, y + Y_OFFSET, HITPOINTS_COLOR, EMPTY_COLOR);
point_color = HITPOINTS_COLOR;
empty_color = EMPTY_COLOR;
}
public boolean isDead() {
if (points <= 0) return true;
else return false;
}
}
package com.jimgong.rain.input;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
public class Keyboard implements KeyListener {
//Array for keystroke states
private boolean[] keys = new boolean[120];
public boolean up, down, left, right;
public boolean space;
public boolean shift;
public void update() {
up = keys[KeyEvent.VK_UP] || keys[KeyEvent.VK_W];
down = keys[KeyEvent.VK_DOWN] || keys[KeyEvent.VK_S];
left = keys[KeyEvent.VK_LEFT] || keys[KeyEvent.VK_A];
right = keys[KeyEvent.VK_RIGHT] || keys[KeyEvent.VK_D];
space = keys[KeyEvent.VK_SPACE];
shift = keys[KeyEvent.VK_SHIFT];
for (int i = 0; i < keys.length; i++) {
if (keys[i]) {
System.out.println("KEY: " + i);
}
}
}
@Override
public void keyPressed(KeyEvent e) {
keys[e.getKeyCode()] = true;
}
@Override
public void keyReleased(KeyEvent e) {
keys[e.getKeyCode()] = false;
}
@Override
public void keyTyped(KeyEvent e) {
}
}
package com.jimgong.rain.level;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import com.jimgong.rain.entity.Entity;
import com.jimgong.rain.entity.mob.Chaser;
import com.jimgong.rain.entity.mob.Mob;
import com.jimgong.rain.entity.mob.Player;
import com.jimgong.rain.entity.particle.Particle;
import com.jimgong.rain.entity.projectile.Projectile;
import com.jimgong.rain.graphics.Screen;
import com.jimgong.rain.level.tile.Tile;
public class Level {
protected int width, height;
protected int[] tilesInt; //For rand levels
protected int[] tiles;
protected final Random random = new Random();
protected int time = 0;
//Array of all entities to have on the level
private List<Entity> entities = new ArrayList<Entity>();
private List<Projectile> projectiles = new ArrayList<Projectile>();
private List<Particle> particles = new ArrayList<Particle>();
private List<Mob> nonPlayerMobs = new ArrayList<Mob>();
private List<Player> players = new ArrayList<Player>();
public static Level spawn = new SpawnLevel("/levels/spawn.png");
//Random level
public Level(int width, int height) {
this.width = width;
this.height = height;
tilesInt = new int[width * height];
generateLevel();
}
//Custom level
public Level(String path) {
loadLevel(path);
generateLevel();
}
protected void generateLevel() {
}
protected void loadLevel(String path) {
}
public void update() {
//time based events
if (time++ > 2100) time = 0;
//spawn new chaser mob every half second
if (time % 30 == 0) {
if (nonPlayerMobs.size() < 20) add(new Chaser(random.nextInt(3) + 15, random.nextInt(10) + 10));
}
for (int i = 0; i < entities.size(); i++) {
entities.get(i).update();
}
for (int i = 0; i < projectiles.size(); i++) {
projectiles.get(i).update();
}
for (int i = 0; i < particles.size(); i++) {
particles.get(i).update();
}
for (int i = 0; i < nonPlayerMobs.size(); i++) {
nonPlayerMobs.get(i).update();
}
for (int i = 0; i < players.size(); i++) {
players.get(i).update();
}
remove();
}
private void remove() {
for (int i = 0; i < entities.size(); i++) {
if (entities.get(i).isRemoved()) entities.remove(i);
}
for (int i = 0; i < projectiles.size(); i++) {
if (projectiles.get(i).isRemoved()) projectiles.remove(i);
}
for (int i = 0; i < particles.size(); i++) {
if (particles.get(i).isRemoved()) particles.remove(i);
}
for (int i = 0; i < nonPlayerMobs.size(); i++) {
if (nonPlayerMobs.get(i).isRemoved()) nonPlayerMobs.remove(i);
}
for (int i = 0; i < players.size(); i++) {
if (players.get(i).isRemoved()) players.remove(i);
}
}
public List<Projectile> getProjectiles() {
return projectiles;
}
//The offsets adjust for the unrendered (pink) area of the sprite
public boolean tileCollision(int x, int y, int size, int xOffset, int yOffset) {
boolean solid = false;
//Corner precision
for (int corner = 0; corner < 4; corner++) {
int xt = (x - corner % 2 * size + xOffset) >> 4;
int yt = (y - corner / 2 * size + yOffset) >> 4;
if (getTile((int) xt,(int) yt).solid()) solid = true;
}
return solid;
}
//Scroll indicates coordinate of player
public void render(int xScroll, int yScroll, Screen screen) {
screen.setOffset(xScroll, yScroll);
//Set cornerpins
int x0 = xScroll >> 4; //same as xScroll / 16, shifting bit 4 places to right
//Aggregates pixels into tiles, 16 is size of a tile to render an extra tile for offsetting
int x1 = (xScroll + screen.width + 16) >> 4;
int y0 = yScroll >> 4;
int y1 = (yScroll + screen.height + 16) >> 4;
for (int y = y0; y < y1; y++) {
for (int x = x0; x < x1; x++) {
getTile(x, y).render(x, y, screen);
}
}
//Render entities
for (int i = 0; i < entities.size(); i++) {
entities.get(i).render(screen);
}
//Render projectiles
for (int i = 0; i < projectiles.size(); i++) {
projectiles.get(i).render(screen);
}
//Render particles
for (int i = 0; i < particles.size(); i++) {
particles.get(i).render(screen);
}
//Render non-player mobs
for (int i = 0; i < nonPlayerMobs.size(); i++) {
nonPlayerMobs.get(i).render(screen);
}
//Render players
for (int i = 0; i < players.size(); i++) {
players.get(i).render(screen);
}
}
public void add(Entity e) {
e.init(this);
if (e instanceof Particle) {
particles.add((Particle)e);
}
else if (e instanceof Projectile) {
projectiles.add((Projectile)e);
}
else if (e instanceof Player) {
players.add((Player)e);
}
else if (e instanceof Mob) {
nonPlayerMobs.add((Mob)e);
}
else entities.add(e);
}
public List<Player> getPlayers() {
return players;
}
public Player getPlayerAt(int index) {
return players.get(index);
}
public Player getClientPlayer() {
return players.get(0);
}
public List<Mob> getMobs() {
return nonPlayerMobs;
}
//Returns entities within a certain radius
public List<Entity> getEntitiesInRadius (Entity e, int radius) {
List<Entity> result = new ArrayList<Entity>();
//x and y coordinates of e
int ex = e.getX(), ey = e.getY();
for (int i = 0; i < entities.size(); i++) {
Entity entity = entities.get(i);
int x = entity.getX();
int y = entity.getY();
double distance = Math.sqrt((x-ex)*(x-ex) + (y-ey)*(y-ey));
//if entity is within radius, add
if (radius >= distance) {
result.add(entity);
}
}
return result;
}
//Returns mobs within a certain radius
public List<Mob> getMobsInRadius (Entity e, int radius) {
List<Mob> result = new ArrayList<Mob>();
//x and y coordinates of e
int ex = e.getX(), ey = e.getY();
for (int i = 0; i < nonPlayerMobs.size(); i++) {
Mob mob = nonPlayerMobs.get(i);
int x = mob.getX();
int y = mob.getY();
double distance = Math.sqrt((x-ex)*(x-ex) + (y-ey)*(y-ey));
//if entity is within radius, add
if (radius >= distance) {
result.add(mob);
}
}
return result;
}
//Returns mobs within a certain radius for a given coordinate
public List<Mob> getMobsInRadius (int ex, int ey, int radius) {
List<Mob> result = new ArrayList<Mob>();
for (int i = 0; i < nonPlayerMobs.size(); i++) {
Mob mob = nonPlayerMobs.get(i);
int x = mob.getX();
int y = mob.getY();
double distance = Math.sqrt((x-ex)*(x-ex) + (y-ey)*(y-ey));
//if entity is within radius, add
if (radius >= distance) {
result.add(mob);
}
}
return result;
}
//Returns player entities within a certain radius
public List<Player> getPlayersInRadius (Entity e, int radius) {
List<Player> result = new ArrayList<Player>();
//x and y coordinates of e
int ex = e.getX(), ey = e.getY();
for (int i = 0; i < players.size(); i++) {
Player player = players.get(i);
int x = player.getX();
int y = player.getY();
double distance = Math.sqrt((x-ex)*(x-ex) + (y-ey)*(y-ey));
//if entity is within radius, add
if (radius >= distance) {
result.add(player);
}
}
return result;
}
public Tile getTile(int x, int y) {
if (x < 0 || y < 0 || x >= width || y >= height) return Tile.voidTile;
if (tiles[x + y * width] == Tile.col_spawn_floor) return Tile.spawn_floor;
if (tiles[x + y * width] == Tile.col_spawn_flower) return Tile.spawn_flower;
if (tiles[x + y * width] == Tile.col_spawn_grass) return Tile.spawn_grass;
if (tiles[x + y * width] == Tile.col_spawn_rock) return Tile.spawn_rock;
if (tiles[x + y * width] == Tile.col_spawn_wall) return Tile.spawn_wall;
if (tiles[x + y * width] == Tile.col_spawn_water) return Tile.spawn_water;
return Tile.voidTile;
}
}
package com.jimgong.rain.entity.valuebar;
public class Mana extends ValueBar{
public static final int MANA_COLOR = 0xFF0000FF;
public static final int EMPTY_COLOR = 0xFF8080FF;
public static final int X_OFFSET = 11;
public static final int Y_OFFSET = -8;
//x & y visibility coordinates relative to the Mob to whom it belongs
//HP bar visible to the right of the player
public Mana (int manaPoints, int x, int y) {
//2 pixels wide, offset by 2 pixels from player
super(manaPoints, x + X_OFFSET, y + Y_OFFSET, MANA_COLOR, EMPTY_COLOR);
point_color = MANA_COLOR;
empty_color = EMPTY_COLOR;
}
public boolean isEmpty() {
if (points <= 0) return true;
else return false;
}
}
package com.jimgong.rain.entity.mob;
import com.jimgong.rain.entity.Entity;
import com.jimgong.rain.entity.particle.Particle;
import com.jimgong.rain.entity.projectile.Projectile;
import com.jimgong.rain.entity.projectile.WizardProjectile;
import com.jimgong.rain.entity.spawner.ParticleSpawner;
import com.jimgong.rain.entity.valuebar.Hitpoints;
import com.jimgong.rain.graphics.Screen;
import com.jimgong.rain.graphics.Sprite;
public abstract class Mob extends Entity {
protected static final int NORTH = 0;
protected static final int EAST = 1;
protected static final int SOUTH = 2;
protected static final int WEST = 3;
protected Sprite sprite;
protected int dir = 0; //Entity's direction 0-N, 1-E, 2-S, 3-W
protected boolean moving = false;
protected Hitpoints hp;
//xa,ya denote where the player is moving on the x and y axis
public void move(int xa, int ya) {
//if trying to move on two axis
if (xa != 0 && ya != 0) {
//separate movement so collision on one axis is not a mutual relationship
move(xa, 0);
move(0,ya);
return;
}
if (xa > 0) dir = EAST; //Going right
if (xa < 0) dir = WEST; //Going left
if (ya > 0) dir = SOUTH; //Going down
if (ya < 0) dir = NORTH; //Going up
if (!collision(xa, ya)) {
//xa = -1, 0, 1 passed as arguments (moving left, staying still, moving right)
x += xa;
y += ya;
}
}
public void update() {
}
protected void shoot(int x, int y, double dir) {
//dir *= 180 / Math.PI;
Projectile p = new WizardProjectile(x, y, dir);
level.add(p);
}
private boolean collision(int xa, int ya) {
boolean solid = false;
//Corner precision
for (int corner = 0; corner < 4; corner++) {
int xt = ((x + xa) + corner % 2 * 14 - 8 ) >> 4;
int yt = ((y + ya) + corner % 2 / 10 + (ya * 4 + 3)) >> 4;
if (level.getTile(xt, yt).solid()) solid = true;
}
return solid;
}
public abstract void render(Screen screen);
public Sprite getSprite() {
return sprite;
}
public Hitpoints getHitpoints() {
return hp;
}
public boolean isRemoved() {
if (removed) level.add(new ParticleSpawner(x, y, 60, 50, level));
return removed;
}
}
package com.jimgong.rain.input;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
public class Mouse implements MouseListener, MouseMotionListener {
//static because we can only have one mouse
private static int mouseX = -1, mouseY = -1;
private static int mouseB = -1;
public static int getX() {
return mouseX;
}
public static int getY() {
return mouseY;
}
public static int getButton() {
return mouseB;
}
@Override
public void mouseDragged(MouseEvent e) {
mouseX = e.getX();
mouseY = e.getY();
}
@Override
public void mouseMoved(MouseEvent e) {
mouseX = e.getX();
mouseY = e.getY();
}
@Override
public void mouseClicked(MouseEvent e) {
}
@Override
public void mouseEntered(MouseEvent e) {
}
@Override
public void mouseExited(MouseEvent e) {
}
@Override
public void mousePressed(MouseEvent e) {
mouseB = e.getButton();
}
@Override
public void mouseReleased(MouseEvent e) {
mouseB = -1;
}
}
package com.jimgong.rain.entity.particle;
import com.jimgong.rain.entity.Entity;
import com.jimgong.rain.graphics.Screen;
import com.jimgong.rain.graphics.Sprite;
public class Particle extends Entity {
private Sprite sprite;
//Duration (called "life" in Cherno's videos) indicates how long particles last
protected int duration;
private int time = 0;
//Actual x and y locations
//zed models gravity
protected double xx, yy, zz;
//Amount of pixels particle moves in the x and y axes
protected double xa, ya, za;
public Particle(int x, int y, int duration) {
this.x = x;
this.y = y;
this.xx = x;
this.yy = y;
this.duration = duration + (random.nextInt(duration) - duration / 2);
sprite = Sprite.particle_normal;
//Gives a random number between - and 1, but gives a normal distribution
//more likely for number to be around 0 than -1 or 1
this.xa = random.nextGaussian();
this.ya = random.nextGaussian();
this.zz = random.nextFloat() + 5;
}
public void update() {
time++;
if (time >= 2100) time = 0;
if (time > duration) remove();
za -= 0.1;
if(zz < 0) {
zz = 0;
za *= -0.6;
xa *= 0.4;
ya *= 0.4;
}
move((xx + xa), (yy + ya) + (za));
}
private void move(double x, double y) {
if (collision(x, y)) {
this.xa *= -0.5;
this.ya *= -0.5;
this.za *= -0.5;
}
this.xx += xa;
this.yy += ya;
this.zz += za;
}
public boolean collision(double x, double y) {
boolean solid = false;
/*
* Corner precision
* If corner % 2 == 0, checking left side
* If corner / 2 == 0, checking top side
*/
for (int corner = 0; corner < 4; corner++) {
double xt = (x - corner % 2 * 16) / 16;
double yt = (y - corner / 2 * 16) / 16;
int ix = (int) Math.ceil(xt); //Math.ceil rounds up before casting
int iy = (int) Math.ceil(yt);
if (corner % 2 == 0) ix = (int)xt;
if (corner / 2 == 0) iy = (int)yt;
if (level.getTile(ix, iy).solid()) solid = true;
}
return solid;
}
public void render(Screen screen) {
screen.renderSprite((int) xx, (int) yy, sprite, true);
}
}
package com.jimgong.rain.entity.spawner;
import com.jimgong.rain.entity.particle.Particle;
import com.jimgong.rain.entity.spawner.Spawner.Type;
import com.jimgong.rain.level.Level;
public class ParticleSpawner extends Spawner {
private int duration;
public ParticleSpawner(int x, int y, int duration, int amount, Level level) {
super(x, y, Type.PARTICLE, amount, level);
this.duration = duration;
for (int i = 0; i < amount; i++) {
level.add(new Particle(x, y, duration));
}
}
}
package com.jimgong.rain.entity.mob;
import java.util.ArrayList;
import java.util.List;
import com.jimgong.rain.Game;
import com.jimgong.rain.entity.projectile.Projectile;
import com.jimgong.rain.entity.projectile.WizardProjectile;
import com.jimgong.rain.entity.valuebar.Hitpoints;
import com.jimgong.rain.entity.valuebar.Mana;
import com.jimgong.rain.graphics.AnimatedSprite;
import com.jimgong.rain.graphics.Screen;
import com.jimgong.rain.graphics.SpriteSheet;
import com.jimgong.rain.input.Keyboard;
import com.jimgong.rain.input.Mouse;
public class Player extends Mob {
private Keyboard input;
private int animate_step = 0;
private AnimatedSprite sprite;
private Mana mana;
private int manaRegenRate = -2;
public static final int RUN_SPEED = 3;
public static final int WALK_SPEED = 1;
private int movespeed = WALK_SPEED;
public Player(Keyboard input) {
this.input = input;
sprite = new AnimatedSprite(16, 0, 0, SpriteSheet.player);
}
//Constructor to be used if player spawns at new coordinate
public Player (int x, int y, Keyboard input) {
this.x = x;
this.y = y;
this.input = input;
sprite = new AnimatedSprite(16, 0, 0, SpriteSheet.player);
//instantiate hitpoints and mana
hp = new Hitpoints(16, x, y);
mana = new Mana(16, x, y);
}
public void update() {
//Note direction player is supposed to move
int xa = 0, ya = 0;
//Update animation, prevent crashing
if (animate_step++ >= 2100) animate_step = 0;
if (input.up) ya--;
if (input.down) ya++;
if (input.left) xa--;
if (input.right) xa++;
if (input.space) movespeed = RUN_SPEED;
else movespeed = WALK_SPEED;
if (xa != 0 || ya != 0) {
for (int i = 0; i < movespeed; i++) {
move(xa, ya);
moving = true;
}
}
else moving = false;
clear();
//shoot at max speed of once every 10 frames
updateShooting();
sprite.update(dir);
sprite.animateControl(moving);
//Hitpoints and mana update
if (!hp.isDead()) hp.update(x + Hitpoints.X_OFFSET, y + Hitpoints.Y_OFFSET);
else remove();
mana.update(x + Mana.X_OFFSET, y + Mana.Y_OFFSET);
if (animate_step % 60 == 0) {
//regen mana
if (mana.getPoints() - mana.getCapacity() <= manaRegenRate) mana.setPoints(manaRegenRate);
else if (mana.getPoints() < mana.getCapacity()) mana.setPoints(-1);
}
}
private void clear() {
for (int i = 0; i < level.getProjectiles().size(); i++) {
Projectile p = level.getProjectiles().get(i);
if (p.isRemoved()) {
level.getProjectiles().remove(i);
}
}
}
//Shoot if clicking left mouse button
private void updateShooting() {
//if out of mana, stop shooting
if (mana.isEmpty()) return;
if (Mouse.getButton() == 1 && animate_step % WizardProjectile.FIRE_RATE == 0) {
double dx = Mouse.getX() - Game.getWindowWidth() / 2;
double dy = Mouse.getY() - Game.getWindowHeight() / 2;
double dir = Math.atan2(dy, dx);
shoot(x, y, dir);
//mana shoot
mana.setPoints(1);
}
}
public void render(Screen screen) {
//Center player
int xx = x - sprite.SIZE / 2;
int yy = y - sprite.SIZE / 2;
screen.renderMob(xx, yy, sprite, 0);
if (input.shift) {
//render hp and mana bars
hp.render(screen);
mana.render(screen);
List<Mob> hpToggle = level.getMobsInRadius(this, Game.getWindowWidth());
for (int i = 0; i < hpToggle.size(); i++) {
hpToggle.get(i).getHitpoints().render(screen);
}
}
}
}
package com.jimgong.rain.entity.projectile;
import java.util.Random;
import com.jimgong.rain.entity.Entity;
import com.jimgong.rain.graphics.Sprite;
public abstract class Projectile extends Entity {
//where projectile spawns
protected final int xOrigin, yOrigin;
protected double angle;
protected Sprite sprite;
protected double x, y;
protected final Random random = new Random();
//vector
protected double nx, ny;
//Distance projectile has traveled from origin
protected double distance;
//speed, range, damage
protected double speed, range, damage;
public Projectile(int x, int y, double dir) {
xOrigin = x;
yOrigin = y;
angle = dir;
this.x = x;
this.y = y;
}
protected void move() {
}
public Sprite getSprite() {
return sprite;
}
public int getSpriteSize() {
return sprite.SIZE;
}
}
package com.jimgong.rain.level;
import java.util.Random;
public class RandomLevel extends Level {
private static final Random random = new Random();
public RandomLevel(int width, int height) {
super(width, height);
}
@Override
protected void generateLevel() {
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
tilesInt[x + y * width] = random.nextInt(4);
}
}
}
}
package com.jimgong.rain.level.tile;
import com.jimgong.rain.graphics.Screen;
import com.jimgong.rain.graphics.Sprite;
public class RockTile extends Tile {
public RockTile(Sprite sprite) {
super(sprite);
}
public void render(int x, int y, Screen screen) {
screen.renderTile(x << 4, y << 4, this);
}
public boolean solid() {
return true;
}
}
package com.jimgong.rain.graphics;
import java.util.Random;
import com.jimgong.rain.entity.mob.Chaser;
import com.jimgong.rain.entity.mob.Mob;
import com.jimgong.rain.entity.projectile.Projectile;
import com.jimgong.rain.level.tile.Tile;
public class Screen {
public int width, height;
public int[] pixels;
public final int MAP_SIZE = 64;
public final int MAP_SIZE_MASK = MAP_SIZE - 1;
public int[] tiles = new int[MAP_SIZE * MAP_SIZE];
public int xOffset, yOffset;
private Random random = new Random();
public Screen(int width, int height) {
this.width = width;
this.height = height;
pixels = new int[width * height]; //50400 pixels total for 300x168
for (int i = 0; i < tiles.length; i++) {
tiles[i] = random.nextInt(0xFFFFFF);
}
}
public void clear() {
for (int i = 0; i < pixels.length; i++) {
pixels[i] = 0;
}
}
public void renderSprite(int xp, int yp, Sprite sprite, boolean fixed) {
//Offsets it so it renders at the area the map currently is
if (fixed) {
xp -= xOffset;
yp -= yOffset;
}
for (int y = 0; y < sprite.getHeight(); y++) {
int ya = y + yp;
for (int x = 0; x < sprite.getWidth(); x++) {
int xa = x + xp;
if (xa < 0 || xa >= width || ya < 0 || ya >= height) continue;
pixels[xa + ya * width] = sprite.pixels[x + y * sprite.getWidth()];
}
}
}
/*
* Render individual tiles
* xa/ya are the absolute position of the tile
* x/y are the pixels being rendered
* xp/yp are the offsets
*/
public void renderTile(int xp, int yp, Tile tile) {
xp -= xOffset;
yp -= yOffset;
for (int y = 0; y < tile.sprite.SIZE; y++) {
int ya = y + yp;
for (int x = 0; x < tile.sprite.SIZE; x++) {
int xa = x + xp;
/*Prevent program from rendering entire map
* at once; just show immediate screen area
*/
if (xa < -tile.sprite.SIZE || xa >= width || ya < 0 || ya >= height) break;
if (xa < 0) xa = 0;
pixels[xa + ya * width] = tile.sprite.pixels[x + y * tile.sprite.SIZE];
//pixel on screen getting rendered; pixel on sprite getting rendered
}
}
}
//Render projectiles
public void renderProjectile(int xp, int yp, Projectile p) {
xp -= xOffset;
yp -= yOffset;
for (int y = 0; y < p.getSpriteSize(); y++) {
int ya = y + yp;
for (int x = 0; x < p.getSpriteSize(); x++) {
int xa = x + xp;
/*Prevent program from rendering entire map
* at once; just show immediate screen area
*/
if (xa < -p.getSpriteSize() || xa >= width || ya < 0 || ya >= height) break;
if (xa < 0) xa = 0;
int col = p.getSprite().pixels[x + y * p.getSpriteSize()];
if (col != 0xFFFF00FF) pixels[xa + ya * width] = col;
}
}
}
public void renderMob(int xp, int yp, Mob mob) {
xp -= xOffset;
yp -= yOffset;
for (int y = 0; y < mob.getSprite().SIZE; y++) {
int ya = y + yp;
for (int x = 0; x < mob.getSprite().SIZE; x++) {
int xa = x + xp;
/*Prevent program from rendering entire map
* at once; just show immediate screen area
*/
if (xa < -(mob.getSprite().SIZE) || xa >= width || ya < 0 || ya >= height) break;
if (xa < 0) xa = 0;
//Prevent the pink pixels in spritesheet from being rendered
int col = mob.getSprite().pixels[x + y * mob.getSprite().SIZE];
//Change color of chasers
if (mob instanceof Chaser && col == 0xffe02828) col = 0xff054bff;
if (col != 0xFFFF00FF)
pixels[xa + ya * width] = col;
}
}
}
public void renderMob(int xp, int yp, Sprite sprite, int flip) {
xp -= xOffset;
yp -= yOffset;
for (int y = 0; y < sprite.SIZE; y++) {
int ya = y + yp;
int ys = y;
if (flip == 2 || flip == 3) ys = 15 - y;
for (int x = 0; x < sprite.SIZE; x++) {
int xa = x + xp;
/*Prevent program from rendering entire map
* at once; just show immediate screen area
*/
int xs = x;
if (flip == 1 || flip == 3) xs = 15 - x;
if (xa < -sprite.SIZE || xa >= width || ya < 0 || ya >= height) break;
if (xa < 0) xa = 0;
//Prevent the pink pixels in spritesheet from being rendered
int col = sprite.pixels[xs + ys * sprite.SIZE];
if (col != 0xFFFF00FF)
pixels[xa + ya * width] = col;
}
}
}
//set Offset
public void setOffset(int xOffset, int yOffset) {
this.xOffset = xOffset;
this.yOffset = yOffset;
}
}
package com.jimgong.rain.entity.spawner;
import com.jimgong.rain.entity.Entity;
import com.jimgong.rain.entity.particle.Particle;
import com.jimgong.rain.level.Level;
public class Spawner extends Entity {
public enum Type {
MOB, PARTICLE
}
private Type type;
public Spawner (int x, int y, Type type, int amount, Level level) {
init(level);
this.x = x;
this.y = y;
this.type = type;
}
}
package com.jimgong.rain.level.tile.spawn_level;
import com.jimgong.rain.graphics.Screen;
import com.jimgong.rain.graphics.Sprite;
import com.jimgong.rain.level.tile.Tile;
public class SpawnFloorTile extends Tile {
public SpawnFloorTile(Sprite sprite) {
super(sprite);
}
public void render(int x, int y, Screen screen) {
screen.renderTile(x << 4, y << 4, this);
}
}
package com.jimgong.rain.level.tile.spawn_level;
import com.jimgong.rain.graphics.Screen;
import com.jimgong.rain.graphics.Sprite;
import com.jimgong.rain.level.tile.Tile;
public class SpawnFlowerTile extends Tile{
public SpawnFlowerTile(Sprite sprite) {
super(sprite);
}
public void render(int x, int y, Screen screen) {
screen.renderTile(x << 4, y << 4, this);
}
}
package com.jimgong.rain.level.tile.spawn_level;
import com.jimgong.rain.graphics.Screen;
import com.jimgong.rain.graphics.Sprite;
import com.jimgong.rain.level.tile.Tile;
public class SpawnGrassTile extends Tile {
public SpawnGrassTile(Sprite sprite) {
super(sprite);
}
public void render(int x, int y, Screen screen) {
screen.renderTile(x << 4, y << 4, this);
}
}
package com.jimgong.rain.level;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import com.jimgong.rain.entity.mob.Chaser;
import com.jimgong.rain.entity.mob.Dummy;
public class SpawnLevel extends Level{
public SpawnLevel (String path) {
super(path);
}
protected void loadLevel(String path) {
try {
BufferedImage image = ImageIO.read(SpawnLevel.class.getResource(path));
width = image.getWidth();
height = image.getHeight();
tiles = new int[width * height];
image.getRGB(0, 0, width, height, tiles, 0 , width);
} catch (IOException e) {
e.printStackTrace();
System.out.println("Exception! Could not load level file!");
}
//load dummies in 5 random locations
for (int i = 0; i < 1; i++) {
add(new Chaser(19, 25));
add(new Dummy(19, 25));
}
}
//Grass = 0xFF00FF00
//Flower = 0xFFFFFF00
//Rock = 0xFF7F7F00
protected void generateLevel() {
}
}
package com.jimgong.rain.level.tile.spawn_level;
import com.jimgong.rain.graphics.Screen;
import com.jimgong.rain.graphics.Sprite;
import com.jimgong.rain.level.tile.Tile;
public class SpawnRockTile extends Tile {
public SpawnRockTile(Sprite sprite) {
super(sprite);
}
public void render(int x, int y, Screen screen) {
screen.renderTile(x << 4, y << 4, this);
}
public boolean solid() {
return true;
}
}
package com.jimgong.rain.level.tile.spawn_level;
import com.jimgong.rain.graphics.Screen;
import com.jimgong.rain.graphics.Sprite;
import com.jimgong.rain.level.tile.Tile;
public class SpawnWallTile extends Tile {
public SpawnWallTile(Sprite sprite) {
super(sprite);
}
public void render(int x, int y, Screen screen) {
screen.renderTile(x << 4, y << 4, this);
}
public boolean solid() {
return true;
}
}
package com.jimgong.rain.level.tile.spawn_level;
import com.jimgong.rain.graphics.Screen;
import com.jimgong.rain.graphics.Sprite;
import com.jimgong.rain.level.tile.Tile;
public class SpawnWaterTile extends Tile{
public SpawnWaterTile(Sprite sprite) {
super(sprite);
}
public void render(int x, int y, Screen screen) {
screen.renderTile(x << 4, y << 4, this);
}
}
package com.jimgong.rain.graphics;
import com.jimgong.rain.entity.valuebar.Hitpoints;
import com.jimgong.rain.entity.valuebar.ValueBar;
public class Sprite {
//Size of the particular sprite
public final int SIZE;
//width and height
private int width, height;
//Coordinates of sprite
protected int x, y;
public int[] pixels;
private SpriteSheet sheet;
public static Sprite grass = new Sprite(16, 0, 1, SpriteSheet.tiles);
public static Sprite flower = new Sprite(16, 1, 1, SpriteSheet.tiles);
public static Sprite rock = new Sprite(16, 2, 1, SpriteSheet.tiles);
public static Sprite voidSprite = new Sprite(16, 16, 0x1B87E0);
//Spawn level sprites
public static Sprite spawn_grass = new Sprite(16, 0, 0, SpriteSheet.spawn_level);
public static Sprite spawn_flower = new Sprite(16, 0, 1, SpriteSheet.spawn_level);
public static Sprite spawn_rock = new Sprite(16, 0, 2, SpriteSheet.spawn_level);
public static Sprite spawn_wall = new Sprite(16, 1, 0, SpriteSheet.spawn_level);
public static Sprite spawn_floor = new Sprite(16, 1, 1, SpriteSheet.spawn_level);
public static Sprite spawn_water = new Sprite(16, 2, 0, SpriteSheet.spawn_level);
//Projectile Sprites
public static Sprite projectile_wizard = new Sprite(16, 0, 2, SpriteSheet.projectile_wizard);
//Particle sprites
public static Sprite particle_normal = new Sprite(1, 1, 0xCC3130);
public Sprite(int size, int x, int y, SpriteSheet sheet) {
SIZE = size;
this.width = SIZE;
this.height = SIZE;
pixels = new int[SIZE * SIZE];
//Set location of target sprite in sprite sheet
this.x = x * size;
this.y = y * size;
this.sheet = sheet;
load();
}
public Sprite(int width, int height, int color) {
SIZE = width * height;
this.width = width;
this.height = height;
pixels = new int[SIZE * SIZE];
setColor(color);
}
//for Bar sprites
//emptyValue designates amount of points empty from capacity
public Sprite(int width, int height, int fillColor, int emptyColor, int emptyValue) {
SIZE = width * height;
this.width = width;
this.height = height;
pixels = new int[SIZE];
setColor(fillColor, emptyColor, emptyValue * ValueBar.BAR_WIDTH);
}
private void setColor(int color) {
for (int i = 0; i < SIZE; i++) {
pixels[i] = color;
}
}
//for Bar sprites
private void setColor(int fillColor, int emptyColor, int limit) {
//top pixels empty
for (int i = 0; i < limit; i++) {
pixels[i] = emptyColor;
}
//bottom pixels filled
for (int i = limit; i < SIZE; i++) {
pixels[i] = fillColor;
}
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
//Access spritesheet pixels and find right sprite
protected void load() {
for (int y = 0; y < SIZE; y++) {
for (int x = 0; x < SIZE; x++) {
//Extract single sprite from sprite sheet
pixels[x + y * SIZE] = sheet.pixels[(x + this.x) + (y + this.y) * sheet.SIZE];
}
}
}
}
package com.jimgong.rain.graphics;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
public class SpriteSheet {
/** Specify path */
private String path;
public final int SIZE;
public final int WIDTH, HEIGHT;
public int[] pixels;
//Tiles spritesheet
public static SpriteSheet tiles = new SpriteSheet("/textures/sheets/spritesheet.png", 256);
public static SpriteSheet spawn_level = new SpriteSheet("/textures/sheets/spawn_level.png", 48);
//Player spritesheet
public static SpriteSheet player = new SpriteSheet("/textures/sheets/player.png", 64);
//Projectiles
public static SpriteSheet projectile_wizard = new SpriteSheet("/textures/sheets/projectiles/wizard.png", 48);
//Charmander - used for Dummy NPC
public static SpriteSheet charmander = new SpriteSheet("/textures/sheets/charmander.png", 64);
/**Constructor*/
public SpriteSheet(String path, int size) {
this.path = path;
SIZE = size;
WIDTH = SIZE;
HEIGHT = SIZE;
pixels = new int[SIZE * SIZE];
load();
}
/** Load spritesheet */
private void load() {
//Create new buffered image object and set it equal to image of path
try {
BufferedImage image = ImageIO.read(SpriteSheet.class.getResource(path));
int w = image.getWidth();
int h = image.getHeight();
//Translate loaded image into pixels
image.getRGB(0, 0, w, h, pixels, 0, w);
}
catch (IOException e) {
e.printStackTrace();
}
}
}
/*
* Each tile should have a position and a sprite
* Say whether it is collidable (i.e. something can pass through it)
*/
package com.jimgong.rain.level.tile;
import com.jimgong.rain.graphics.Screen;
import com.jimgong.rain.graphics.Sprite;
import com.jimgong.rain.level.tile.spawn_level.SpawnFloorTile;
import com.jimgong.rain.level.tile.spawn_level.SpawnFlowerTile;
import com.jimgong.rain.level.tile.spawn_level.SpawnGrassTile;
import com.jimgong.rain.level.tile.spawn_level.SpawnRockTile;
import com.jimgong.rain.level.tile.spawn_level.SpawnWallTile;
import com.jimgong.rain.level.tile.spawn_level.SpawnWaterTile;
public class Tile {
public int x, y;
public Sprite sprite;
public static Tile grass = new GrassTile(Sprite.grass);
public static Tile flower = new FlowerTile(Sprite.flower);
public static Tile rock = new RockTile(Sprite.rock);
public static Tile voidTile = new VoidTile(Sprite.voidSprite);
//Spawn level tiles
public static Tile spawn_grass = new SpawnGrassTile(Sprite.spawn_grass);
public static Tile spawn_flower = new SpawnFlowerTile(Sprite.spawn_flower);
public static Tile spawn_rock = new SpawnRockTile(Sprite.spawn_rock);
public static Tile spawn_wall = new SpawnWallTile(Sprite.spawn_wall);
public static Tile spawn_floor = new SpawnFloorTile(Sprite.spawn_floor);
public static Tile spawn_water = new SpawnWaterTile(Sprite.spawn_water);
//color recognition
public static final int col_spawn_grass = 0xFF00FF00;
public static final int col_spawn_flower = 0xFFFFFF00;
public static final int col_spawn_rock = 0xFFFF0000;
public static final int col_spawn_wall = 0xFF808080;
public static final int col_spawn_floor = 0xFF7F3300;
public static final int col_spawn_water = 0xFF0000FF;
//Constructor
public Tile(Sprite sprite) {
this.sprite = sprite;
}
public void render(int x, int y, Screen screen) {
}
//Whether collidable
public boolean solid() {
return false;
}
}
package com.jimgong.rain.level;
public class TileCoordinate {
private int x, y;
private final int TILE_SIZE = 16;
public TileCoordinate(int x, int y) {
this.x = x * TILE_SIZE;
this.y = y * TILE_SIZE;
}
public int x() {
return x;
}
public int y() {
return y;
}
public int[] xy() {
return new int[] {x,y};
}
}
package com.jimgong.rain.entity.valuebar;
import com.jimgong.rain.entity.Entity;
import com.jimgong.rain.graphics.Screen;
import com.jimgong.rain.graphics.Sprite;
public class ValueBar extends Entity {
protected int capacity;
protected int points;
protected Sprite sprite;
protected int point_color;
protected int empty_color;
public final static int BAR_WIDTH = 1;
//Construct full value bar (loaded to capacity)
//x & y designate visibility coordinates
public ValueBar(int capacity, int x, int y, int point_color, int empty_color) {
this.capacity = capacity;
this.points = capacity;
this.x = x;
this.y = y;
sprite = new Sprite(BAR_WIDTH, capacity, point_color, empty_color, 0);
}
public void update(int x, int y) {
sprite = new Sprite(BAR_WIDTH, capacity, point_color, empty_color, capacity - points);
this.x = x;
this.y = y;
}
public int getCapacity() {
return capacity;
}
public int getPoints() {
return points;
}
//positive value = damage, negative value = heal
public void setPoints(int value) {
points -= value;
}
public void render(Screen screen) {
screen.renderSprite(x, y, sprite, true);
}
}
package com.jimgong.rain.level.tile;
import com.jimgong.rain.graphics.Screen;
import com.jimgong.rain.graphics.Sprite;
public class VoidTile extends Tile{
public VoidTile(Sprite sprite) {
super(sprite);
}
public void render(int x, int y, Screen screen) {
screen.renderTile(x << 4, y << 4, this);
}
}
package com.jimgong.rain.entity.projectile;
import java.util.List;
import com.jimgong.rain.entity.mob.Mob;
import com.jimgong.rain.entity.spawner.ParticleSpawner;
import com.jimgong.rain.graphics.Screen;
import com.jimgong.rain.graphics.Sprite;
public class WizardProjectile extends Projectile{
public static final int FIRE_RATE = 6; //10 per second at 60fps
public WizardProjectile(int x, int y, double dir) {
super(x, y, dir);
//varying range
range = 150;
speed = 3;
damage = 2;
sprite = Sprite.projectile_wizard;
nx = speed * Math.cos(angle);
ny = speed * Math.sin(angle);
}
public void update() {
if (level.tileCollision((int)(x + nx), (int)(y + ny), 8, 4, 4)) {
level.add(new ParticleSpawner((int)x, (int)y, 60, 50, level));
remove();
}
else move();
List<Mob> hitbox = level.getMobsInRadius((int)x, (int)y, 8);
for (int i = 0; i < hitbox.size(); i++) {
hitbox.get(i).getHitpoints().setPoints((int)damage);
}
}
protected void move() {
x += nx;
y += ny;
if (getDistance() > range) remove();
}
private double getDistance() {
double dist = 0;
dist = Math.sqrt((xOrigin - x) * (xOrigin - x) + (yOrigin - y) * (yOrigin - y));
return dist;
}
public void render(Screen screen) {
//x y render projectile relative to character
screen.renderProjectile((int)x - 8, (int)y - 8, this);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment