So I have an object in Java with a sprite associated to it. I also have an array of 4 different PImages, and I want to gradually change the sprite of that object into each of the PImages in that array (technically “animating” the sprite"), and I want each sprite to last for 0.5 seconds.
Can anyone help me with this?
Here is my approach. "Sprites" is the array containing the 4 images, brickwall is the object, and the event that triggers the sprite change is when a fireball hit the brickwall. I'll provide the code for the parts involved in the question.
for(int i = 0; i < this.fireballs.size(); i++){
//detect collision between fireball and wall
for(int b = 0; b < this.brickwalls.size(); b++){
if((this.fireballs.get(i).getX() <= this.brickwalls.get(b).getX()+10 & this.fireballs.get(i).getX() >= this.brickwalls.get(b).getX()-10) &&
(this.fireballs.get(i).getY() <= this.brickwalls.get(b).getY()+10 & this.fireballs.get(i).getY() >= this.brickwalls.get(b).getY()-10)){
if(this.brickwalls.get(b).counter == 0){
this.brickwalls.get(b).setSprite(wall.sprites[0]);
}
if(this.brickwalls.get(b).counter == 1){
this.brickwalls.get(b).setSprite(wall.sprites[1]);
}
if(this.brickwalls.get(b).counter == 2){
this.brickwalls.get(b).setSprite(wall.sprites[2]);
}
if(this.brickwalls.get(b).counter == 3){
this.brickwalls.get(b).setSprite(wall.sprites[3]);
}
this.fireballs.remove(i);
this.brickwalls.get(b).Exist = false;
//this.brickwalls.remove(b);
if(i == this.fireballs.size()){
break;
}
if(b == this.brickwalls.size()){
break;
}
}
}
}
Here is the wall class. Brickwall is an extension to wall.
package gremlins;
import processing.core.PImage;
import processing.core.PApplet;
public abstract class wall extends PApplet {
protected int x;
protected int y;
protected PImage sprite;
protected int size;
protected boolean Exist = true;
protected int switchTime = 1000;
protected int startTime = 0;
public int savedTime = millis();
public int counter = 0;
public static PImage[] sprites = new PImage[4];
public wall(int x, int y){
this.x = x;
this.y = y;
//load sprites into array
}
public void setSprite(PImage sprite) {
this.sprite = sprite;
}
public void draw(PApplet app){
app.image(this.sprite, this.x, this.y);
if(this.Exist = false){
if(millis() - startTime > 500){
counter++;
startTime = millis();
}
}
}
public int getX(){
return this.x;
}
public int getY(){
return this.y;
}
public void tick(){
}
}
package gremlins;
import processing.core.PImage;
import processing.core.PApplet;
public class brickwall extends wall {
public PImage sprite;
protected PImage[] destroyed = new PImage[4];
public brickwall(int x, int y){
super(x, y);
}
}
Related
I am making a game with android. The player is a rectangle that has to jump over obstacles. When i jump i decrease the height and the y coordinates. When i run the game the rectangle is jumping but when i try to jump over an obstacle its still hitting it. So i think i forget to change a value but i have no idea what value. Sorry for my bad english and i am a beginner at coding.
This is my Player class:
package com.example.niek.speelveld;
import android.graphics.Canvas;
import android.graphics.Paint;
/**
* Created by Niek on 15-8-2017.
*/
public class Player extends GameObject {
private int score;
private boolean up;
private boolean playing;
private long startTime;
private int h = 0;
private boolean jump;
public Player(int x , int y){
super.x = x;
super.y = y;
width = 100;
height = GamePanel.HEIGHT;
score = 0;
startTime = System.nanoTime();
}
public void setUp(boolean b){up = b;}
public void update(){
long elapsed = (System.nanoTime()-startTime)/1000000;
if(elapsed>100){
score++;
startTime = System.nanoTime();
}
if(up && h == 0){
jump = true;
up = false;
}
if (jump) {
if (h < 120) {
h = h + 7;
height = height - 7;
y = y - 7;
} else {
jump = false;
}
} else {
if (h > 0) {
h = h - 7;
height = height + 7;
y = y + 7;
}
}
}
public void draw(Canvas canvas){
Paint myPaint = new Paint();
myPaint.setStyle(Paint.Style.STROKE);
myPaint.setStrokeWidth(7);
canvas.drawRect(x, y, width + x, height, myPaint );
myPaint.setStrokeWidth(1);
canvas.drawText("HIGHSCORE " + score, GamePanel.WIDTH - 100 , 0+myPaint.getTextSize(), myPaint);
}
public int getScore(){return score;}
public boolean getPlaying(){return playing;}
public void setPlaying(boolean b){playing = b;}
//public void resetScore(){score = 0;}
public boolean getJump() {
return jump;
}
}
And in my Gamepanel class i use these 2 methods. When i call the class obstacle.get(i).update(); its only updating the x value so its moving towards the player.
public void update(){
if(player.getPlaying()) {
bg.update();
player.update();
//Add obstacles with timer
long obstacleElapsed = (System.nanoTime()-obstacleStartTime)/1000000;
if(obstacleElapsed >(2000 - player.getScore()/4)){
obstacles.add(new Obstacle(BitmapFactory.decodeResource(getResources(), R.drawable.rsz_spike1), WIDTH + 10, HEIGHT - 51, 14, 51, player.getScore()));
//reset timer
obstacleStartTime = System.nanoTime();
}
}
//Loop through every obstacle and check collision
for(int i = 0; i<obstacles.size(); i++){
obstacles.get(i).update();
if (collision(obstacles.get(i), player)) {
obstacles.remove(i);
player.setPlaying(false);
Intent intent = new Intent(c, Result.class);
intent.putExtra("SCORE", player.getScore());
c.startActivity(intent);
break;
}
//Remove obstacles that are out of the screen
if (obstacles.get(i).getX() < -100) {
obstacles.remove(i);
break;
}
}
}
public boolean collision(GameObject o, GameObject p){
if(Rect.intersects(o.getRectangle(), p.getRectangle())){
return true;
}
return false;
}
#Override
public void draw(Canvas canvas){
//Get Width and Height from screen
final float scaleFactorX = (float)getWidth()/WIDTH;
final float scaleFactorY = (float)getHeight()/HEIGHT;
if(canvas!=null) {
final int savedState = canvas.save();
canvas.scale(scaleFactorX, scaleFactorY);
bg.draw(canvas);
player.draw(canvas);
//Draw obstacles
for(Obstacle o : obstacles ){
o.draw(canvas);
}
canvas.restoreToCount(savedState);
}
}
And finally the Player and the Obstacle class extends Gameobject where i have the getRectangle method.
public Rect getRectangle(){
return new Rect(x, y, x+width, y+height);
}
So here is the code after taking the tips into account.
The map is kept being repainted, the keylistener has changed but there still seems to be a problem.
The problem again is, the little square in the upper left corner will not move, which is the desired outcome.
package schoolgamev2;
import java.awt.BorderLayout;
import java.awt.Graphics;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Spel {
public static void main(String[] args) {
Speelveld map = new Speelveld();
map.Speelveld();
map.GenerateMap();
}
}
class Speelveld extends JPanel {
final int rijen = 16;
final int kolommen = 16;
Speler speler = new Speler();
Loopgebied loopgebied = new Loopgebied();
Blokken blok = new Blokken();
int[][] coordinaten = new int[rijen][kolommen];
public void Speelveld() {
JFrame frame = new JFrame();
frame.setSize(500, 500);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(this);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
setFocusable(true);
addKeyListener(new KeyListener(this));
}
//genereer map
public void GenerateMap() {
Random random = new Random();
int x;
int y;
for (y = 0; y < rijen; y++) { //scan langs y
for (x = 0; x < kolommen; x++) { //scan langs x
//selecteert type blok voor coordinaten x y
coordinaten[x][y] = random.nextInt(4);
//debugprint
}
//debugprint
}
coordinaten[0][0] = 4; //speler begint altijd links boven
coordinaten[15][15] = 5; //finish is altijd rechts onder
}
public int[][] getCoordinaten() {
return coordinaten;
}
public Speler getSpeler2() {
return speler;
}
public int getSpelerX() {
return speler.getX();
}
public int getSpelerY() {
return speler.getY();
}
public void setSpelerX(int x) {
speler.setX(x);
}
public void setSpelerY(int y) {
speler.setY(y);
}
//#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
int x;
int y;
for (y = 0; y < rijen; y++) { //scan langs y
System.out.println("");
for (x = 0; x < kolommen; x++) { //scan langs x
blok.setX(x);
blok.setY(y);
blok.setType(coordinaten[x][y]);
System.out.print(coordinaten[x][y] + " ");
switch (blok.getType()) {
case 0:
loopgebied.teken(g);
break;
case 4:
speler.teken(g);
/*case 5:
eindveld.teken(g);
break;*/
default:
break;
}
}
}
}
}
class Speler extends Blokken {
Blokken blok = new Blokken();
public void teken(Graphics g) {
g.drawRect(blok.getX(), blok.getY(), 10, 10);
}
}
class Loopgebied extends Blokken {
Blokken blok = new Blokken();
public void teken(Graphics g) {
g.drawRect(blok.getX() * size, blok.getY() * size, size, size);
}
}
class Blokken {
private static int x;
private static int y;
private static int type;
public int size = 16;
//setters voor x y en type
public void setX(int xIn) {
x = xIn;
}
public void setY(int yIn) {
y = yIn;
}
public void setType(int typeIn) {
type = typeIn;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public int getType() {
return type;
}
}
class KeyListener extends KeyAdapter {
private static final int SCALE = 3;
private Speelveld speelveld;
public KeyListener(Speelveld speelveld) {
this.speelveld = speelveld;
}
#Override
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
int deltaX = 0;
int deltaY = 0;
if (key == KeyEvent.VK_LEFT) {
deltaX = -1 * SCALE;
deltaY = 0;
} else if (key == KeyEvent.VK_UP) {
deltaX = 0;
deltaY = -1 * SCALE;
} else if (key == KeyEvent.VK_RIGHT) {
deltaX = 1 * SCALE;
deltaY = 0;
} else if (key == KeyEvent.VK_DOWN) {
deltaX = 0;
deltaY = 1 * SCALE;
} else {
return;
}
int x = speelveld.getSpelerX() + deltaX;
int y = speelveld.getSpelerY() + deltaY;
speelveld.setSpelerX(x);
speelveld.setSpelerY(y);
speelveld.repaint();
}
}
As mentioned in comments, you got your player, the Speler class, that extends JPanel and is wired to use a KeyListener, but note that it is not being used as a JPanel, and so the KeyListener is non-functioning, because they only work when they have been added to a visible component that has focus.
Suggestions:
Again as per comments, make Speler a non-GUI logical class. Meaning don't have it extend JPanel or any other Swing component, and certainly don't add a KeyListener to it.
Instead give it code for the player's behavior and for having the player draw itself, and that's it. What I'm suggesting is that you try to separate part of your "Model" here the player from the "View" here the Swing GUI.
Have one JPanel and only one that does drawing. Have it override paintComponent (don't forget to call the super's paintComponent within it), and have it draw each logical component by calling the logical component's draw method (public void verf(Graphics2D g2)? or public void teken(Graphics2D g2)?) within its paintComponent method.
As a general rule, you also don't want your GUI component classes, the JPanel here, directly implementing listener interfaces, such as the KeyListener, but will want to keep them separate.
Either make this drawing JPanel focusable, give it focus and add the KeyListener, a separate class, to it.
Or better, use Key Bindings as per the tutorial: Key Bindings
For example the simple [MCVE] below doesn't use a Swing Timer or change velocities, but rather it uses a KeyListener to change position of the Speler2 object using only one drawing JPanel and a KeyListener. If I were making this more robust and larger, I would use the Swing Timer, would use Key Bindings, and would change the velocities using the key bindings.
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import javax.swing.*;
public class Spel2 {
private static final int VELD_WIDTH = 500;
private static void createAndShowGui() {
Speelveld2 speelveld2 = new Speelveld2(VELD_WIDTH, VELD_WIDTH);
JFrame frame = new JFrame("Spel2");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(speelveld2);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
speelveld2.requestFocusInWindow();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
class MyKeyListener extends KeyAdapter {
private static final int SCALE = 3;
private Speelveld2 speelveld2;
public MyKeyListener(Speelveld2 speelveld2) {
this.speelveld2 = speelveld2;
}
#Override
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
int deltaX = 0;
int deltaY = 0;
if (key == KeyEvent.VK_LEFT) {
deltaX = -1 * SCALE;
deltaY = 0;
} else if (key == KeyEvent.VK_UP) {
deltaX = 0;
deltaY = -1 * SCALE;
} else if (key == KeyEvent.VK_RIGHT) {
deltaX = 1 * SCALE;
deltaY = 0;
} else if (key == KeyEvent.VK_DOWN) {
deltaX = 0;
deltaY = 1 * SCALE;
} else {
return;
}
int x = speelveld2.getSpelerX() + deltaX;
int y = speelveld2.getSpelerY() + deltaY;
speelveld2.setSpelerX(x);
speelveld2.setSpelerY(y);
speelveld2.repaint();
}
}
#SuppressWarnings("serial")
class Speelveld2 extends JPanel {
private int prefW;
private int prefH;
private Speler2 speler2 = new Speler2();
public Speelveld2(int prefW, int prefH) {
this.prefW = prefW;
this.prefH = prefH;
setFocusable(true);
addKeyListener(new MyKeyListener(this));
}
public Speler2 getSpeler2() {
return speler2;
}
public int getSpelerX() {
return speler2.getX();
}
public int getSpelerY() {
return speler2.getY();
}
public void setSpelerX(int x) {
speler2.setX(x);
}
public void setSpelerY(int y) {
speler2.setY(y);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
speler2.teken(g2);
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(prefW, prefH);
}
}
class Speler2 extends Blokken2 {
private static final int RECT_W = 10;
public Speler2() {
super(BlokkenType.SPELER);
}
#Override
public void teken(Graphics2D g2) {
int x = getX();
int y = getY();
g2.drawRect(x, y, RECT_W, RECT_W);
}
}
class Blokken2 {
private int x;
private int y;
private int velx = 0;
private int vely = 0;
private BlokkenType type;
private BufferedImage img;
public Blokken2(BlokkenType type) {
this.type = type;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public int getVelx() {
return velx;
}
public void setVelx(int velx) {
this.velx = velx;
}
public int getVely() {
return vely;
}
public void setVely(int vely) {
this.vely = vely;
}
public BlokkenType getType() {
return type;
}
public void setType(BlokkenType type) {
this.type = type;
}
public void setImg(BufferedImage img) {
this.img = img;
}
public BufferedImage getImg() {
return img;
}
public void teken(Graphics2D g2) {
if (img != null) {
g2.drawImage(img, x, y, null);
}
}
}
enum BlokkenType {
LOOPGEBIED, BARRICADE, MUUR, SLEUTEN, SPELER, EINDVELD
}
Edit: your latest code has an error here:
class Speler extends Blokken {
Blokken blok = new Blokken();
public void teken(Graphics g) {
g.drawRect(blok.getX(), blok.getY(), 10, 10);
}
}
Regarding your edit:
Now when you create a Speler instance, you create TWO Blokken instances, one which is the Speler instance since it extends Blokken and the other which is contained by the Speler instance since it also has a Blokken field.
You update the x/y state of the first one, but you draw with the second one, and that's why no motion is being displayed. The solution is obvious: use one or the other but not both. Either have Speler extend Blokken or have it contain a Blokken instance but don't do both.
I have question about random generation of sprite sheet tiles in java. Whenever I try to use a for loop the random generation changes every millisecond or faster. I am very confused and have no idea where to start from here. If anyone can come up with some easy code for a begginer to grasp the concept of random generation!
Here is the code I am working with for generating a flat map /
public class Map {
Random random = new Random();
public static int mapxDirection;
public static int mapx = 1;
public static int bgSpeed = 20;
public static int grass = 16;
public static int dirt = 0;
public static int stone = 1;
public static int waterup = 2;
public static int waterside = 18;
public static int glass = 17;
public static int chicken = 32;
public static int steak = 33;
public static int mapSpeed = 3;
public static BufferedImage[] sprites;
public void renderMap(Graphics g) {
final int width = 32;
final int height = 32;
final int rows = 16;
final int cols = 16;
sprites = new BufferedImage[rows * cols];
BufferedImage spritesheet = null;
try {
spritesheet = ImageIO.read(new File("res/SpriteSheet.png"));
} catch (IOException e) {
e.printStackTrace();
}
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
sprites[(i * cols) + j] = spritesheet.getSubimage(i * width, j
* height, width, height);
}
}
for (int i = 0; i < 2000; i += 32) {
g.drawImage(sprites[grass], Map.mapx + i, 259, null);
}
for (int i = 0; i < 2000; i += 32) {
for (int j = 291; j <= 508; j += 32) {
g.drawImage(sprites[dirt], Map.mapx + i, j, null);
}
}
for (int i = 0; i < 2000; i += 32) {
for (int j = 508; j <= 540; j += 32) {
g.drawImage(sprites[stone], Map.mapx + i, j - 3, null);
}
}
}
}
There are multiple ways this can be done, it also depends on what type on random generation you want to achieve for example, do you what to completely randomize every tile or do you what to load random chunks. The popular game Minecraft uses the method of random chuck generation.
If your new to game programming, i recommend checking out RealTutsGML Game Programming Tutorials. He teaches you a easy and good way of loading in sprite sheets and also teaches you how to load in and create a level in paint. All though he is making a platformer, you can easily convert the same method into a top down game.
Here is how i would go about creating a random generation map. First i would create a abstract class called GameObject. Every object you make will extend this class.
public abstract class GameObject {
protected float x, y;
protected ObjectId id;
protected float velX= 0, velY = 0;
protected boolean falling = true;
protected boolean jumping = false;
public GameObject(float x, float y, ObjectId id) {
this.x = x;
this.y = y;
this.id = id;
}
public abstract void tick(LinkedList<GameObject> object);
public abstract void render(Graphics g);
public abstract Rectangle getBounds();
public float getX() { return x; }
public float getY() { return y; }
public float getVelX() { return velX; }
public float getVelY() { return velY; }
public boolean isFalling() { return falling; }
public boolean isJumping() { return jumping; }
public void setX(float x) { this.x = x; }
public void setY(float y) { this.y = y; }
public void setVelX(float velX) { this.velX = velX; }
public void setVelY(float velY) { this.velY = velY; }
public void setFalling(boolean falling) { this.falling = falling; }
public void setJumping(boolean jumping) { this.jumping = jumping; }
public ObjectId getId() { return id; }
}
For example if i want to make a object called Block, i would create a class called Block and extends GameObject like this.
public class Block extends GameObject {
private boolean animate = true;
Texture tex = Game.getInstance();
private int type;
public Block(float x, float y, int type, ObjectId id) {
super(x, y, id);
this.type = type;
}
public void tick(LinkedList<GameObject> object) {
bAnimate.runAnimation();
}
public void render(Graphics g) {
if (type == 0) g.drawImage(tex.red_block[0], (int)x, (int)y, null); // Red Block
if (type == 1) g.drawImage(tex.green_block[0], (int)x, (int)y, null); // Blue Block
if (type == 2) g.drawImage(tex.blue_block[0], (int)x, (int)y, null); // Green Block
if (type == 3) g.drawImage(tex.yellow_block[0], (int)x, (int)y, null); // Yellow Block
if (type == 4) g.drawImage(tex.orange_block[0], (int)x, (int)y, null); // Orange Block
if (type == 5) g.drawImage(tex.pink_block[0], (int)x, (int)y, null); // Pink Block
}
public Rectangle getBounds() {
return new Rectangle((int)x, (int)y, 32, 32);
}
}
I then create a LinkedList like this. An also create 2 methods for adding and removing objects for the list.
protected LinkedList<GameObject> object = new LinkedList<GameObject>();
public void addObject(GameObject object) {
this.object.add(object);
}
public void remove(GameObject object) {
this.object.remove(object);
}
I would then simply add objects to the list like this.
addObject(new Block(x * 32, y * 32, random.nextInt(6), ObjectId.Block));
Sense this post is getting kinda big i will leave the rest to you, if you like i can see you the source code of the project i am using. This is also the same method that "RealTutsGML" uses in his tutorials.
I see that you and using Map.mapx instead of that just write the variable mapx no need for the Map. Also your data should always be private or protected. I also recommend making a variable that holds your map size like this.
private static int mapSize = 2000;
It is just so that if you want to change the map size you don't have to replace more than one number.
I hope this helps you out.
Here is a list of java programming books.
I have these two classes, Bullet and EnemyJet. The Bullet class extends the Player class and the EnemyJet class extends an EnemyControl class. They are both using an arraylist which I'm trying to store and get their positions from.
public class Player extends Mob {
public List<Bullet> bullets = new ArrayList<Bullet>();
}
public class EnemyControl extends Mob {
public List<EnemyJet> enemyJet = new ArrayList<EnemyJet>();
}
Would I need to make a new class to store and test the two positions, or maybe use the Mob class they extend? How would I get the same values from the lists to compare them inside the new class?
For example, test for a collision with the bullet and the enemy jet. If so,remove the jet.
EnemyJet Class:
public class EnemyJet extends EnemyControl{
Random rdm = new Random();
private int destx, desty;
private Sprite sprite;
private int counter = 0;
private boolean dead = false;
private boolean setPos = false;
private void newPosition(){
destx = rdm.nextInt(963);
desty = rdm.nextInt(500);
//System.out.println(destx + " " + desty);
}
private void move(){
if(x > destx) x-=3;
if(y > desty) y-=3;
if(x < destx) x+=3;
if(y < desty) y+=3;
// if(x >= )
}
private void setPos(){
if(!setPos){
x = rdm.nextInt(500);
y = rdm.nextInt(100);
setPos = true;
}
}
public void update(){
setPos();
move();
if(counter > rdm.nextInt(20000)){
newPosition();
counter = 0;
}
counter++;
}
public void render(Screen screen){
sprite = Sprite.enemyjet;
screen.renderMob(x, y, sprite);
}
}
Bullet Class:
public class Bullet {
private Sprite sprite;
private boolean removed = false;
public int y = 0, x = 0;
public Bullet(int x, int y){
this.x = x;
this.y = y;
}
public boolean isRemoved(){
return removed;
}
public void update(){
y -= 15;
}
public void render(Screen screen){
sprite = Sprite.jetbullet;
screen.drawBullet(x, y, sprite);
}
}
Player Class:
public class Player extends Mob {
public List<Bullet> bullets = new ArrayList<Bullet>();
private Keyboard input;
private Sprite sprite;
private int counter = 0;
private int fireRate = 4;
public Player(Keyboard input){
this.input = input;
}
public void update(){
int xa = 0, ya = 0;
if(input.up) ya=-7;
if(input.down) ya =+7;
if(input.left) xa=-7;
if(input.right) xa=+7;
if(!input.up && !input.down && !input.left && !input.right)
intensity = 0; else intensity = 8;
move(xa, ya);
if(input.shoot && counter > fireRate){
bullet = new Bullet(x, y);
bullets.add(bullet);
counter = 0;
}
if(bullets.size() > 0){
for(int i = 0; i < bullets.size(); i++){
bullets.get(i).update();
if(bullets.get(i).y < 0){
bullets.remove(i);
}
}
}
counter++;
}
public void render(Screen screen){
sprite = Sprite.jet;
if(bullets.size()>0)
for(int i = 0; i < bullets.size(); i++){
bullets.get(i).render(screen);
}
screen.renderMob(x, y, sprite);
screen.setIntensity(intensity);
}
}
Added all classes Player, EnemyJet and Bullet.
you could go through all bullets and check if they have the same position as the enemyjet and implement a method in Mob that compares them if you will use the comparison repeatedly. Or you just do the compare yourself in your driver class that controls both during runtime, e.g. the main() or where the events are caught and synchronized and presented on screen.
I am almost done with my first little java game for my final project. It is a sidescroller where you have to shoot/avoid asteroids. My last problem is figuring out how to make my array of asteroids collide with the player's lasers. Here's what I have so far, there's an "AWT-EventQueue-0" java.lang.NullPointerException" on line 137, that I can't deal with. Any help is appreciated.
Edit: I added in my other classes, I realize it would be hard to judge the functionality of my code if I didn't show you where it came from.
package ShooterGame;
import java.applet.Applet;
import java.applet.AudioClip;
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import java.util.Random;
import javax.swing.*;
public class Board extends JPanel implements ActionListener
{
Enemy[] baddies = new Enemy[10000];
Player p;
Image img;
int y;
Timer time;
boolean lost = false;
static Font font = new Font("SanSerif", Font.BOLD, 24);
public AudioClip theme, bang, laser;
static ArrayList<Enemy> enemies;
public static int score = 0;
public static int lives = 5;
public Board()
{
p = new Player();
addKeyListener(new ActionListener());
setFocusable(true);
ImageIcon i = new ImageIcon("images/background.png");
img = i.getImage();
time = new Timer(5, this);
time.start();
for(int j = 0; j < baddies.length; j++)
{
Random ran = new Random();
y = ran.nextInt(365)+1;
baddies[j]= new Enemy((100*j + 700), y, "images/asteroid.gif");
}
theme = Applet.newAudioClip(getClass().getResource("theme.mid"));
theme.play();
bang = Applet.newAudioClip(getClass().getResource("bang.wav"));
}
public void actionPerformed(ActionEvent e)
{
checkCollisions();
ArrayList<?> bullets = Player.getBullets();
for(int i = 0; i < bullets.size(); i++)
{
Bullet b = (Bullet)bullets.get(i);
if(b.isVisible() == true)
{
b.move();
}
else
{
bullets.remove(i);
}
}
p.move();
for(int i = 0; i < baddies.length; i++)
{
if(p.x > 400)
{
baddies[i].move(p.getdx());
}
}
repaint();
}
public void paint(Graphics g)
{
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
if(lost)
{
g2d.drawString("You Lose!", 300, 300);
}
if((p.getX() - 590) % 2400 == 0 || (p.getX() - 590) % 2400 == 1)
{
p.nx = 0;
}
if((p.getX() - 1790) % 2400 == 0 ||(p.getX() - 1790) % 2400 == 1)
{
p.nx2 = 0;
}
g2d.drawImage(img, 685-p.nx2, 0, null);
if(p.getX() >= 590)
{
g2d.drawImage(img, 685-p.nx, 0, null);
}
g2d.drawImage(p.getImage(), p.edge, p.getY(), null);
ArrayList<?> bullets = Player.getBullets();
for(int i = 0; i < bullets.size(); i++)
{
Bullet b = (Bullet)bullets.get(i);
g2d.drawImage(b.getImg(), b.getX(), b.getY(), null);
}
for(int i = 0; i < baddies.length; i++)
{
if(baddies[i].isAlive == true)
{
g2d.drawImage(baddies[i].getImg(), baddies[i].getX(), baddies[i].getY(), null);
}
}
g2d.setColor(Color.white);
g2d.drawString("Score: " + score, 0, 320);
g2d.drawString("Lives: " + lives, 80, 320);
}
public void checkCollisions()
{
Rectangle[] rect = new Rectangle[baddies.length];
for(int i = 0; i < baddies.length; i++)
{
Enemy e = (Enemy)baddies[i];
rect[i] = e.getBounds();
}
ArrayList<?> bullets = Player.getBullets();
for (int i = 0; i < bullets.size(); i++)
{
Bullet b = (Bullet) bullets.get(i);
Rectangle b1 = b.getBounds();
if (rect[i].intersects(b1) && baddies[i].isAlive())
{
score++;
baddies[i].isAlive = false;
baddies[i].isVisible = false;
bang.play();
}
Rectangle h = p.getBounds();
if (h.intersects(rect[i]))
{
if(baddies[i].isAlive() == true)
{
lives--;
if(lives < 0)
{
lost = true;
theme.stop();
System.exit(1);
}
}
}
}
}
private class ActionListener extends KeyAdapter
{
public void keyReleased(KeyEvent e)
{
p.keyReleased(e);
}
public void keyPressed(KeyEvent e)
{
p.keyPressed(e);
}
}
}
Enemy
package ShooterGame;
import java.awt.*;
import javax.swing.ImageIcon;
public class Enemy
{
int x, y;
Image img;
boolean isAlive = true;
boolean isVisible = true;
public Enemy(int startX, int startY, String location)
{
x = startX;
y = startY;
ImageIcon l = new ImageIcon(location);
img = l.getImage();
}
public Rectangle getBounds()
{
return new Rectangle(x, y, 60, 60);
}
public int getX()
{
return x;
}
public int getY()
{
return y;
}
public boolean isAlive()
{
return isAlive;
}
public boolean isVisible()
{
return isVisible;
}
public Image getImg()
{
return img;
}
public void move(int dx)
{
x = x - dx;
}
}
Bullet
package ShooterGame;
import java.applet.Applet;
import java.awt.*;
import javax.swing.ImageIcon;
import java.applet.AudioClip;
public class Bullet
{
int x, y;
Image img;
boolean visible;
public Bullet(int startX, int startY)
{
x = startX;
y = startY;
ImageIcon newBullet = new ImageIcon("images/bullet.gif");
img = newBullet.getImage();
visible = true;
}
public Rectangle getBounds()
{
return new Rectangle(x, y, 9, 5);
}
public int getX()
{
return x;
}
public int getY()
{
return y;
}
public Image getImg()
{
return img;
}
public boolean isVisible()
{
return visible;
}
public void move()
{
x = x + 2;
if(x > 700)
{
visible = false;
}
}
public void setVisible(boolean isVisible)
{
visible = isVisible;
}
}
Player
package ShooterGame;
import java.applet.Applet;
import java.applet.AudioClip;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import javax.swing.ImageIcon;
public class Player
{
int x, dx, y, dy, nx2, nx, edge, ceiling;
Image player;
ImageIcon ib = new ImageIcon("images/player1back.gif");
ImageIcon i = new ImageIcon("images/playerstill.gif");
ImageIcon f = new ImageIcon("images/playerforward.gif");
ImageIcon up = new ImageIcon("images/playerup.gif");
ImageIcon down = new ImageIcon("images/playerdown.gif");
public AudioClip laser;
static ArrayList<Bullet> bullets;
public Player()
{laser = Applet.newAudioClip(getClass().getResource("laser.wav"));
player = ib.getImage();
x = 75;
nx = 0;
nx2 = 685;
y = 172;
edge = 150;
ceiling = 0;
bullets = new ArrayList<Bullet>();
}
public static ArrayList<Bullet> getBullets()
{
return bullets;
}
public void fire()
{
Bullet z = new Bullet((edge + 60), (y+17));
bullets.add(z);
}
public Rectangle getBounds()
{
return new Rectangle(edge, y, 43, 39);
}
public void move()
{
y = y + dy;
if(y < ceiling)
{
y = ceiling;
}
if(y > 290)
{
y = 290;
}
if(dx != -1)
{
if(edge + dx <= 151)
{
edge = edge + dx;
}
else
{
x = x + dx;
nx2 = nx2 + dx;
nx = nx + dx;
}
}
else
{
if(edge + dx > 0)
{
edge = edge + dx;
}
}
}
public int getX()
{
return x;
}
public int getdx()
{
return dx;
}
public int getY()
{
return y;
}
public Image getImage()
{
return player;
}
public void keyPressed(KeyEvent e)
{
int key = e.getKeyCode();
if(key == KeyEvent.VK_RIGHT)
{
dx = 2;
player = f.getImage();
}
if(key == KeyEvent.VK_UP)
{
dy = -1;
player = up.getImage();
}
if(key == KeyEvent.VK_DOWN)
{
dy = 1;
player = down.getImage();
}
if(key == KeyEvent.VK_SPACE)
{
fire();
laser.play();
}
}
public void keyReleased(KeyEvent e)
{
int key = e.getKeyCode();
if(key == KeyEvent.VK_RIGHT)
{
dx = 1;
player = ib.getImage();
}
if(key == KeyEvent.VK_UP)
{
dy = 0;
player = ib.getImage();
}
if(key == KeyEvent.VK_DOWN)
{
dy = 0;
player = ib.getImage();
}
}
}
Frame
package ShooterGame;
import javax.swing.*;
public class Frame
{
public AudioClip theme;
public Frame()
{
JFrame frame = new JFrame();
frame.add(new Board());
frame.setTitle("SideShooter");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(700,365);
frame.setVisible(true);
frame.setLocationRelativeTo(null);
}
public static void main(String[] args)
{
new Frame();
}
}
Ok, so the problem is the line mentioned in the other answer, but I believe it is that all the enemies may not be initialised before it checks collisions. Because you are making 10000 of them to start with, I think your action performed method may be checking collisions before they have all be created.
One thing to try could be to bring down the amount of enemies you have and see if it still keeps happening, try 100 or 1000, but this still won't fix the issue.
You really want to be change your game to run in it's own loop though, at the moment you are only checking collisions when the player performs an action. so if the player stops moving, no collision detection...
I would suggest that you find a book called 'Killer Game Programming in Java', there are free ebook version, and just read the first 2 chapters about making a game loop. The book is a bit old, but the basics of the loop are very good.
This question here also contains a very simple loop, and some suggestions in the comments about how to make it better.
The error is on the line
rect[i] = e.getBounds();
Are you not initializing the bounds of your Enemy class correctly? Alternatively, the Enemy you pulled out of the array could be null.