Move an image from one place to another - java

I have a class called enemy and another class called "goal". The goal is that the enemy has to move towards the "goal". So I got the X and Y position of the "goal" but and when I implement that in the enemy class the enemy should move but it doesn't. Why is that?
Here is what I have done so far.
Main Class:
public class GameManager extends JFrame implements KeyListener {
private int canvasWidth;
private int canvasHeight;
private int borderLeft;
private int borderTop;
private BufferedImage canvas;
private Stage stage;
private Enemy[] enemies;
private Player player;
private Goal goal;
private Graphics gameGraphics;
private Graphics canvasGraphics;
private int numEnemies;
private boolean continueGame;
public static void main(String[] args) {
// During development, you can adjust the values provided in the brackets below
// as needed. However, your code must work with different/valid combinations
// of values.
GameManager managerObj = new GameManager(1980, 1280, 30);
}
public GameManager(int preferredWidth, int preferredHeight, int maxEnemies) {
this.borderLeft = getInsets().left;
this.borderTop = getInsets().top;
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
if (screenSize.width < preferredWidth)
this.canvasWidth = screenSize.width - getInsets().left - getInsets().right;
else
this.canvasWidth = preferredWidth - getInsets().left - getInsets().right;
if (screenSize.height < preferredHeight)
this.canvasHeight = screenSize.height - getInsets().top - getInsets().bottom;
else
this.canvasHeight = preferredHeight - getInsets().top - getInsets().bottom;
setSize(this.canvasWidth, this.canvasHeight);
setResizable(false);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
addKeyListener(this);
Random rng = new Random(2);
this.canvas = new BufferedImage(this.canvasWidth, this.canvasHeight, BufferedImage.TYPE_INT_RGB);
// Create a Stage object to hold the background images
this.stage = new Stage();
// Create a Goal object with its initial x and y coordinates
this.goal = new Goal(this.canvasWidth / 2, Math.abs(rng.nextInt()) % this.canvasHeight);
// Create a Player object with its initial x and y coordinates
this.player = new Player(this.canvasWidth - (Math.abs(rng.nextInt()) % (this.canvasWidth / 2)),
(Math.abs(rng.nextInt()) % this.canvasHeight));
// Create the Enemy objects, each with a reference to this (GameManager) object
// and their initial x and y coordinates.
this.numEnemies = maxEnemies;
this.enemies = new Enemy[this.numEnemies];
for (int i = 0; i < this.numEnemies; i++) {
this.enemies[i] = new Enemy(this, Math.abs(rng.nextInt()) % (this.canvasWidth / 4),
Math.abs(rng.nextInt()) % this.canvasHeight);
}
this.gameGraphics = getGraphics();
this.canvasGraphics = this.canvas.getGraphics();
this.continueGame = true;
while (this.continueGame) {
updateCanvas();
}
this.stage.setGameOverBackground();
updateCanvas();
}
public void updateCanvas() {
long start = System.nanoTime();
// If the player is alive, this should move the player in the direction of the
// key that has been pressed
// Note: See keyPressed and keyReleased methods in the GameManager class.
this.player.performAction();
// If the enemy is alive, the enemy must move towards the goal. The goal object
// is obtained via the GameManager object that is given at the time of creating
// an Enemy object.
// Note: The amount that the enemy moves must be much smaller than that of
// the player above or else the game becomes hard to play.
for (int i = 0; i < this.numEnemies; i++) {
this.enemies[i].performAction();
}
if ((Math.abs(this.goal.getX() - this.player.getX()) < (this.goal.getCurrentImage().getWidth() / 2))
&& (Math.abs(this.goal.getY() - this.player.getY()) < (this.goal.getCurrentImage().getWidth() / 2))) {
for (int i = 0; i < this.numEnemies; i++) {
// Sets the image of the enemy to the "dead" image and sets its status to
// indicate dead
this.enemies[i].die();
}
// Sets the image of the enemy to the "dead" image and sets its status to
// indicate dead
this.goal.die();
// Sets the background of the stage to the finished game background.
this.stage.setGameOverBackground();
this.continueGame = false;
}
// If an enemy is close to the goal, the player and goal die
int j = 0;
while (j < this.numEnemies) {
if ((Math.abs(this.goal.getX() - this.enemies[j].getX()) < (this.goal.getCurrentImage().getWidth() / 2))
&& (Math.abs(this.goal.getY() - this.enemies[j].getY()) < (this.goal.getCurrentImage().getWidth()
/ 2))) {
this.player.die();
this.goal.die();
this.stage.setGameOverBackground();
j = this.numEnemies;
this.continueGame = false;
}
j++;
}
try {
// Draw stage
this.canvasGraphics.drawImage(stage.getCurrentImage(), 0, 0, null);
// Draw player
this.canvasGraphics.drawImage(player.getCurrentImage(),
this.player.getX() - (this.player.getCurrentImage().getWidth() / 2),
this.player.getY() - (this.player.getCurrentImage().getHeight() / 2), null);
// Draw enemies
for (int i = 0; i < this.numEnemies; i++) {
this.canvasGraphics.drawImage(this.enemies[i].getCurrentImage(),
this.enemies[i].getX() - (this.enemies[i].getCurrentImage().getWidth() / 2),
this.enemies[i].getY() - (this.enemies[i].getCurrentImage().getHeight() / 2), null);
}
// Draw goal
this.canvasGraphics.drawImage(this.goal.getCurrentImage(),
this.goal.getX() - (this.goal.getCurrentImage().getWidth() / 2),
this.goal.getY() - (this.goal.getCurrentImage().getHeight() / 2), null);
} catch (Exception e) {
System.err.println(e.getMessage());
}
// Draw everything.
this.gameGraphics.drawImage(this.canvas, this.borderLeft, this.borderTop, this);
long end = System.nanoTime();
this.gameGraphics.drawString("FPS: " + String.format("%2d", (int) (1000000000.0 / (end - start))),
this.borderLeft + 50, this.borderTop + 50);
}
public Goal getGoal() {
return this.goal;
}
public void keyPressed(KeyEvent ke) {
// Below, the setKey method is used to tell the Player object which key is
// currently pressed.
// The Player object must keep track of the pressed key and use it for
// determining the direction
// to move.
if (ke.getKeyCode() == KeyEvent.VK_LEFT)
this.player.setKey('L', true);
if (ke.getKeyCode() == KeyEvent.VK_RIGHT)
this.player.setKey('R', true);
if (ke.getKeyCode() == KeyEvent.VK_UP)
this.player.setKey('U', true);
if (ke.getKeyCode() == KeyEvent.VK_DOWN)
this.player.setKey('D', true);
if (ke.getKeyCode() == KeyEvent.VK_ESCAPE)
this.continueGame = false;
}
#Override
public void keyReleased(KeyEvent ke) {
// Below, the setKey method is used to tell the Player object which key is
// currently released.
// The Player object must keep track of the pressed key and use it for
// determining the direction
// to move.
if (ke.getKeyCode() == KeyEvent.VK_LEFT)
this.player.setKey('L', false);
if (ke.getKeyCode() == KeyEvent.VK_RIGHT)
this.player.setKey('R', false);
if (ke.getKeyCode() == KeyEvent.VK_UP)
this.player.setKey('U', false);
if (ke.getKeyCode() == KeyEvent.VK_DOWN)
this.player.setKey('D', false);
}
#Override
public void keyTyped(KeyEvent ke) {
}
}
Player Class:
private int myX;
private int myY;
private char d;
public Player(int i, int j) {
// TODO Auto-generated constructor stub
try {
this.imageRunning = ImageIO.read(new File(
"/Users/Desktop/images/player-alive.png"));
this.imageOver = ImageIO.read(new File(
"/Users/Desktop/images/player-dead.png"));
} catch (IOException e) {
e.printStackTrace();
}
this.imageCurrent = this.imageRunning;
myX = i;
myY = j;
}
public void performAction() {
}
public int getX() {
return myX;
}
public int getY() {
return myY;
}
public BufferedImage getCurrentImage() {
return this.imageCurrent;
}
public void die() {
this.imageCurrent = this.imageOver;
}
public void setKey(char c, boolean b) {
}

That simply changes the variables gmX and gmY. Nothing more. You need to update the frame after setting the new gmX and gmY values. Assuming frameis your JFrame object, you need something like:
public void performAction() {
gmX += 40;
gmY += 40;
frame.repaint();
}

You need to redraw graphics on the component:
gmY += 40;
repaint(); /* add this where you want to redraw */

Related

Collisions in processing

My game is a shooting game for school. I need help on the collision between my bullet and my enemy. I have placed the bullet class with my player but for some reason it keeps on passing through it and not disappearing. The first example below shows the weapon class which is for the bullet and the one underneath that is the main.
class Weapons{
PImage bullet;
int speed;
int imageSize = 20;
float x = 20;
float y = 20;
float m;
int damage = 5;
int[] src = new int[2];
float[] dest = new float[2];
Weapons(int x, int y){
speed = 12;
dest[0] = mouseX;
dest[1] = mouseY;
src[0] = x;
src[1] = y;
m = (dest[1]-src[1]) / (dest[0]-src[0]);
this.x = x;
this.y = y;
bullet = loadImage("bullet.png");
bullet.resize(imageSize,imageSize);
}
boolean shooting(){
image(bullet, x, y); // if attack is true then renfer the image
x += speed;
y = (m * (x - dest[0])) + dest[1];
return (x > width || y > height);
}
boolean crash(Enemy enemies) {
//// return the result of checking if the plane has crashed into the bird
return abs(this.x-enemies.x) < bullet.width && abs(this.y - enemies.y) < bullet.height;
}
}
Maincharacter MC;
Goal G;
ArrayList<Enemy> enemies = new ArrayList<>();
ArrayList<Weapons> bullets = new ArrayList<>();
final int Playing = 0;
final int Finish = 1;
int gameMode = Playing;
//Enemy[] enemies = new Enemy[10];
PImage background; // creating background
int bgX = 0;
void setup(){
size(800,500);
MC = new Maincharacter(100,3);
//E1 = new Enemy();
G = new Goal(100,20);
background = loadImage("Battleground1.png");
background.resize(width*2,height); //set image to be same size as the canvas
for(int i = 0; i<2; i++){ // i represent how many enemy I want.
enemies.add(new Enemy((int)random(200,850), (int)random(0, height- 150) ) );
}
//for(int i=0 ; i < enemies.length ; i++){
//enemies[i] = new Enemy(); }
}
void draw(){
if(gameMode == Playing){
background();
MC.display();
G.display();
for(Enemy E : enemies){
E.update();
if (MC.crash(E)){
gameMode = Finish;
}
}
for(Weapons W: bullets){
W.update();
if(enemies.crash(W)){ // doesnt exist
gameMode = Finish;
}
}
// for(int i=0 ; i < enemies.length ; i++){
//enemies[i].update(); }
}}
void keyPressed(){
// creating the movemnt for my main charcter
MC.move();
if (keyCode == RIGHT || keyCode == 68 ){
MC.x += 10;
} else if (keyCode == UP || keyCode == 87) {
MC.y -=10;
} else if (keyCode == LEFT || keyCode == 65){
MC.x -= 10;
} else if(keyCode == DOWN || keyCode == 83 ){
MC.y += 10;
} else if (keyCode == 32) { // space bar
MC.attack_function(); // call attack function to create bullet object
}// make an attack
}
void mousePressed(){ // when mouse is pressed call attack function to create bullet object
MC.attack_function();
}
void background(){
//scrolling background image
image(background, bgX, height/2); //draw image to fill the canvas
//draw image again off the right of the canvas
image(background, bgX+background.width, height/2);
bgX -= 4;
if(bgX == -background.width ) //if first image completely off the canvas
{
bgX=0; //reset back to initial value background
}
}
What I want is to have bullet colliding with the enemies and then disappearing.
You are trying to call the method enemies.crash(W) but enemies is some collection of Enemy instances. Enemy does not provide the method crash as well.
You have to loop for each of your enemies all of your weapons and call the method crash on the Weapon instance giving the current enemy, something like:
for (Enemy enemy: enemies){
enemy.update();
if (mainCharacter.crash(enemy)) {
gameMode = Finish;
}
for (Weapons weapon: bullets) {
weapon.update();
if (weapon.crash(enemy)) {
gameMode = Finish;
// TODO: are you sure that killing an enemy finishes the game?
}
}
}
(Please note that I used mainCharacter instead of MC here for better readability.)

Cannot get sprite to collide with map images (java)

I am creating a 2D game which the zombie moves with WASD keys and is supposed to collide with the walls and not enter them, as well as collide with the brains and removes them. Every type of code I have used does not create collision. I am using a zombie sprite sheet i found on google as well as 2 backgroundless images for walls and brains.
After I figure out collision, I then then to implement a autorun sequence to where it bounces around like a screensaver and does the same thing just automatically until all brains are collected.
The EZ is just a library that is utilized by UH Manoa, that can be found here: EZ Graphics
Main
import java.awt.Color;
import java.io.FileReader;
import java.util.Scanner;
public class ZombieMain {
static EZImage[] walls = new EZImage[500];
static EZImage[] sideWalls = new EZImage[500];
static EZImage[] brains = new EZImage[50];
static int wallsCount = 0;
static int sideWallsCount = 0;
static int brainsCount = 0;
/*public static void addWall(EZImage wall) {
walls[wallsCount] = wall;
wallsCount++;
}
public static void addCoin(EZImage brain) {
brains[brainsCount] = brain;
brainsCount++;
}*/
/*public static void CollisingCoin(EZImage me) {
int x = me.getXCenter();
int y = me.getYCenter();
for (int i = 0; i < brainsCount; i++) {
if ((brains[i].isPointInElement(me.getXCenter() - 30, me.getYCenter() - 30))
|| (brains[i].isPointInElement(me.getXCenter() + 30, me.getYCenter() - 30))
|| (brains[i].isPointInElement(me.getXCenter() - 30, me.getYCenter() + 30))
|| (brains[i].isPointInElement(me.getXCenter() + 30, me.getYCenter() + 30))) {
brains[i].translateTo(-20, -20);
System.out.println("You ate a brain!");
}
}
}*/
public static void main(String[] args) throws java.io.IOException {
//initialize scanner
Scanner fScanner = new Scanner(new FileReader("boundaries.txt"));
int w = fScanner.nextInt();
int h = fScanner.nextInt();
String inputText = fScanner.nextLine();
//create backdrop
EZ.initialize(w*33,h*32);
EZ.setBackgroundColor(new Color(0, 0,0));
Zombie me = new Zombie("zombieSheet.png", 650, 450, 65, 63, 10);
//set reading parameters and establish results of case readings
int row = 0;
while(fScanner.hasNext()) {
inputText = fScanner.nextLine();
for (int column = 0; column < inputText.length(); column++){
char ch = inputText.charAt(column);
switch(ch){
case 'W':
walls[wallsCount] = EZ.addImage("barbwire.jpg", column*32, row*32);
wallsCount++;
break;
case 'M':
sideWalls[wallsCount] = EZ.addImage("barb.jpg", column*32, row*32);
wallsCount++;
break;
case 'B':
brains[brainsCount] = EZ.addImage("brains.png", column*32, row*32);
brainsCount++;
break;
default:
// Do nothing
break;
}
//printed count of walls, side walls, and brains
System.out.println("W = " + wallsCount);
System.out.println("M = " + sideWallsCount);
System.out.println("B = " + brainsCount);
}
row++;
}
fScanner.close();
while (true) {
// check if going to collide with wall
// we want to check this before we actually move
// otherwise, we get "stuck" in a situation where we can't move
// if no collision, we can move
/*if (EZInteraction.isKeyDown('a')) {
if (!isCollisingWall(me, -2, 0)) {
me.translateBy(-2, 0);
}
} else if (EZInteraction.isKeyDown('d')) {
if (!isCollisingWall(me, 2, 0)) {
me.translateBy(2, 0);
}
} else if (EZInteraction.isKeyDown('w')) {
if (!isCollisingWall(me, 0, -2)) {
me.translateBy(0, -2);
}
} else if (EZInteraction.isKeyDown('s')) {
if (!isCollisingWall(me, 0, 2)) {
me.translateBy(0, 2);
}
}*/
me.go();
EZ.refreshScreen();
}
}
}
Sprite
public class Zombie {
EZImage zombieSheet;
int x = 0; // Position of Sprite
int y = 0;
int zombieWidth; // Width of each sprite
int zombieHeight; // Height of each sprite
int direction = 0; // Direction character is walking in
int walkSequence = 0; // Walk sequence counter
int cycleSteps; // Number of steps before cycling to next animation step
int counter = 0; // Cycle counter
Zombie(String imgFile, int startX, int startY, int width, int height, int steps) {
x = startX; // position of the sprite character on the screen
y = startY;
zombieWidth = width; // Width of the sprite character
zombieHeight = height; // Height of the sprite character
cycleSteps = steps; // How many pixel movement steps to move before changing the sprite graphic
zombieSheet = EZ.addImage(imgFile, x, y);
setImagePosition();
}
private void setImagePosition() {
// Move the entire sprite sheet
zombieSheet.translateTo(x, y);
// Show only a portion of the sprite sheet.
// Portion is determined by setFocus which takes 4 parameters:
// The 1st two numbers is the top left hand corner of the focus region.
// The 2nd two numbers is the bottom right hand corner of the focus region.
zombieSheet.setFocus(walkSequence * zombieWidth, direction, walkSequence * zombieWidth + zombieWidth, direction + zombieHeight);
}
public void moveDown(int stepSize) {
y = y + stepSize;
direction = 0;
if ((counter % cycleSteps) == 0) {
walkSequence++;
if (walkSequence > 6)
walkSequence = 0;
}
counter++;
setImagePosition();
}
public void moveLeft(int stepSize) {
x = x - stepSize;
direction = zombieHeight * 2;
if ((counter % cycleSteps) == 0) {
walkSequence--;
if (walkSequence < 0)
walkSequence = 6;
}
counter++;
setImagePosition();
}
public void moveRight(int stepSize) {
x = x + stepSize;
direction = zombieHeight;
if ((counter % cycleSteps) == 0) {
walkSequence++;
if (walkSequence > 6)
walkSequence = 0;
}
counter++;
setImagePosition();
}
public void moveUp(int stepSize) {
y = y - stepSize;
direction = zombieHeight * 3;
if ((counter % cycleSteps) == 0) {
walkSequence--;
if (walkSequence < 0)
walkSequence = 6;
}
setImagePosition();
counter++;
}
// Keyboard controls for moving the character.
public void go() {
if (EZInteraction.isKeyDown('w')) {
moveUp(2);
} else if (EZInteraction.isKeyDown('a')) {
moveLeft(2);
} else if (EZInteraction.isKeyDown('s')) {
moveDown(2);
} else if (EZInteraction.isKeyDown('d')) {
moveRight(2);
}
}
public void translateBy(int i, int j) {
// TODO Auto-generated method stub
}
public int getXCenter() {
// TODO Auto-generated method stub
return x;
}
public int getYCenter() {
// TODO Auto-generated method stub
return y;
}
public int getWidth() {
// TODO Auto-generated method stub
return 0;
}
public int getHeight() {
// TODO Auto-generated method stub
return 0;
}
}
EZElement provides a getBounds property, which returns a java.awt.Shape object; why is this important? Because the Java 2D Graphics API already provides some hit detection.
From this, we then need to determine the player shape's intersection with any other shapes. To do this, we need to wrap both shapes in a Area and use it to make the final determinations.
Area meArea = new Area(me.getBounds());
Area checkArea = new Area(elementToCheck.getBounds());
checkArea(meArea);
if (!checkArea.isEmpty()) {
//... We have collision
}
Obviously, this should all be wrapped up in some kind of method to handle the core functionality, but you could have a helper method which simply took two EZElements and return true/false if the collide
For brevity and testing, I stripped back your example, but the basic idea should continue to work
import java.awt.Color;
import java.awt.Shape;
import java.awt.geom.Area;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class Test {
private List<EZImage> brains = new ArrayList<>(25);
private Zombie me;
public static void main(String[] args) throws java.io.IOException {
new Test();
}
public Test() {
int w = 10;
int h = 10;
//create backdrop
EZ.initialize(w * 33, h * 32);
EZ.setBackgroundColor(new Color(0, 0, 0));
me = new Zombie("Zombie.png", 0, 0);
brains.add(EZ.addImage("Brains.png", (w * 33) / 2, (h * 32 / 2)));
while (true) {
detectCollision();
// check if going to collide with wall
// we want to check this before we actually move
// otherwise, we get "stuck" in a situation where we can't move
// if no collision, we can move
/*if (EZInteraction.isKeyDown('a')) {
if (!isCollisingWall(me, -2, 0)) {
me.translateBy(-2, 0);
}
} else if (EZInteraction.isKeyDown('d')) {
if (!isCollisingWall(me, 2, 0)) {
me.translateBy(2, 0);
}
} else if (EZInteraction.isKeyDown('w')) {
if (!isCollisingWall(me, 0, -2)) {
me.translateBy(0, -2);
}
} else if (EZInteraction.isKeyDown('s')) {
if (!isCollisingWall(me, 0, 2)) {
me.translateBy(0, 2);
}
}*/
me.go();
EZ.refreshScreen();
}
}
public boolean doesCollide(EZElement element, EZElement with) {
Area a = new Area(element.getBounds());
Area b = new Area(with.getBounds());
a.intersect(b);
return !a.isEmpty();
}
public void detectCollision() {
Iterator<EZImage> obstacles = brains.iterator();
while (obstacles.hasNext()) {
EZElement next = obstacles.next();
if (doesCollide(me.zombieSheet, next)) {
System.out.println("Me = " + me.getBounds().getBounds());
System.out.println("next = " + next.getBounds().getBounds());
EZ.removeEZElement(next);
obstacles.remove();
}
}
}
public class Zombie {
EZImage zombieSheet;
int x = 0; // Position of Sprite
int y = 0;
Zombie(String imgFile, int startX, int startY) {
x = startX; // position of the sprite character on the screen
y = startY;
zombieSheet = EZ.addImage(imgFile, x, y);
setImagePosition();
}
public Shape getBounds() {
return zombieSheet.getBounds();
}
private void setImagePosition() {
// Move the entire sprite sheet
zombieSheet.translateTo(x, y);
}
public void moveDown(int stepSize) {
y = y + stepSize;
setImagePosition();
}
public void moveLeft(int stepSize) {
x = x - stepSize;
setImagePosition();
}
public void moveRight(int stepSize) {
x = x + stepSize;
setImagePosition();
}
public void moveUp(int stepSize) {
y = y - stepSize;
setImagePosition();
}
// Keyboard controls for moving the character.
public void go() {
if (EZInteraction.isKeyDown('w')) {
moveUp(2);
} else if (EZInteraction.isKeyDown('a')) {
moveLeft(2);
} else if (EZInteraction.isKeyDown('s')) {
moveDown(2);
} else if (EZInteraction.isKeyDown('d')) {
moveRight(2);
}
}
}
}
I would recommend that you give each entity (and block/tile) a collision box, then test if a specific entity's bounding box collided with another entity's bounding box, then make it so that the entities can't move in that direction until there isn't a bounding box in a direction, if that made any since.
Do the same for testing for the brains, though I recommend making an ArrayList of brains, and removing specific ones if that brain had been touched.

Brick breaker brick color

I am trying to have each brick in my game have a random color, however when I try to do this the whole set of bricks become the same color. How do I make each individual brick a random color? Any help is appreciated.
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
public class Game extends JoeApplet implements KeyListener
{
String status;
int ballx = 294; // ball spawn x coordinate
int bally = 640; // ball spawn y coordinate
int batx = 294;
int baty = 654;
int brickx = 32;
int bricky = 50;
double movex = -16; // x speed of ball
double movey = -16; //y speed of ball
int count = 0;
int currentLevel=0;
int score=0; //starts score at 0
int lives=3; //lives start at 3
static boolean right = false;
static boolean left = false;
boolean ballFallDown = false;
boolean bricksOver = false;
Rectangle Ball = new Rectangle(ballx, bally, 14, 14); //creates ball
Rectangle Bat = new Rectangle(batx, baty, 100, 12); //creates bat(paddle)
Rectangle[] Brick = new Rectangle[49]; //creates desired number of bricks
public void paint(Graphics art)
{
switch(currentLevel)
{
case 0:
menuScreen(art);
break;
case 1:
game(art);
break;
}
}
public void menuScreen(Graphics art)
{
setSize(700, 700);
art.setColor(Color.BLACK);
art.fillRect(0, 0, 698, 698);
Color ballcolor=new Color(0,0,66);
art.setColor(ballcolor);
art.fillOval(Ball.x, Ball.y, Ball.width, Ball.height);
Color batcolor=new Color(0,0,66);
art.setColor(batcolor);
art.fill3DRect(Bat.x, Bat.y, Bat.width, Bat.height, true);
art.setColor(Color.green);
art.drawRect(0, 0, 698, 698);
art.setColor(Color.yellow);
Font menu = new Font("Arial", Font.BOLD, 20);
art.setFont(menu);
art.drawString("Brick Breaker", 100,400);
art.drawString("Press P to Play", 100,425);
art.drawString("Press Q to Quit game", 100,450);
for (int i = 0; i < Brick.length; i++)
{
if (Brick[i] != null)
{
Color mycolor=new Color(100,0,0);
art.setColor(mycolor);
art.fill3DRect(Brick[i].x, Brick[i].y, Brick[i].width,
Brick[i].height, true);
}
}
art.setColor(Color.YELLOW);
if (ballFallDown || bricksOver)
{
Font f = new Font("Arial", Font.BOLD, 20);
art.setFont(f);
art.drawString(status, 294, 349);
ballFallDown = false;
bricksOver = false;
}
}
public void game(Graphics art)
{
setSize(700, 700);
art.setColor(Color.BLACK);
art.fillRect(0, 0, 698, 698);
Color ballcolor=new Color(0,0,225);
art.setColor(ballcolor);
art.fillOval(Ball.x, Ball.y, Ball.width, Ball.height);
Color batcolor=new Color(0,0,139);
art.setColor(batcolor);
art.fill3DRect(Bat.x, Bat.y, Bat.width, Bat.height, true);
art.setColor(Color.green);
art.drawRect(0, 0, 698, 698);
for (int i = 0; i < Brick.length; i++)
{
if (Brick[i] != null)
{
Color mycolor=new Color(200,0,0);
art.setColor(mycolor);
art.fill3DRect(Brick[i].x, Brick[i].y, Brick[i].width,
Brick[i].height, true);
}
}
if (ballFallDown || bricksOver)
{
Font f = new Font("Arial", Font.BOLD, 20);
art.setFont(f);
art.drawString(status, 100,425);
ballFallDown = false;
bricksOver = false;
}
for (int i = 0; i < Brick.length; i++)
{
if (Brick[i] != null)
{
if (Brick[i].intersects(Ball))
{
score=score+10;
Brick[i] = null;
movey = -movey;
count++;
}
}
}
if (count == Brick.length)
{
bricksOver = true;
movex=0;
movey=0;
art.setColor(Color.green);
status = "YOU BEAT THE LEVEL!!";
art.drawString("Press E to Exit", 100,450);
art.drawString("Press N for Next Level", 100,475);
repaint();
}
repaint();
Font f = new Font("Arial", Font.BOLD, 20);
art.setFont(f);
art.setColor(Color.white);
art.drawString("Score:"+score, 600, 684);
Ball.x += movex;
Ball.y += movey;
if (left == true)
{
Bat.x -= 18;
right = false;
}
if (right == true)
{
Bat.x += 18;
left = false;
}
if (Bat.x <= 4)
{
Bat.x = 4;
}
else if (Bat.x >= 586)
{
Bat.x = 596;
}
if (Ball.intersects(Bat))
{
movey = -movey-.1;
}
if (Ball.x <= 0 || Ball.x + Ball.height >= 698)
{
movex = -movex;
}
if (Ball.y <= 0)
{
movey = -movey;
}
Font f1 = new Font("Arial", Font.BOLD, 20);
art.setFont(f1);
art.setColor(Color.white);
art.drawString("Lives:"+ lives, 5, 684);
if (Ball.y >= 698 && (bricksOver==false) && lives>0)
{
ballFallDown = true;
art.setColor(Color.red);
status = "";
art.drawString("", 100,450);
lives=lives-1;
ballx = 294;
bally = 640;
Ball = new Rectangle(ballx, bally, 14, 14);
movex = -16;
movey = -16;
repaint();
}
if(lives==0 && Ball.y >= 698)
{
art.setColor(Color.red);
art.drawString("You lost!!", 100,425);
art.drawString("Press E to Exit", 100,450);
}
}
public void init()
{
addKeyListener(this);
for (int i = 0; i < Brick.length; i++) //creates bricks
{
Brick[i] = new Rectangle(brickx, bricky, 40, 20);
if (i == 12) //1st row of bricks
{
brickx = 32;
bricky = 84;
}
if (i == 23) //2nd row of bricks
{
brickx = 82;
bricky = 118;
}
if (i == 32) //3rd row of bricks
{
brickx = 132;
bricky = 152;
}
if (i == 39) //4th row of bricks
{
brickx = 182;
bricky = 186;
}
if (i == 44) //5th row of bricks
{
brickx = 232;
bricky = 220;
}
if (i == 47) //6th row of bricks
{
brickx = 282;
bricky = 254;
}
if (i == 48) //7th row of bricks
{
brickx = 144;
bricky = 132;
}
brickx += 50; //spacing between each brick
}
}
public void restart()
{
ballx = 294;
bally = 640;
batx = 294;
baty = 654;
brickx = 32;
bricky = 50;
Ball = new Rectangle(ballx, bally, 14, 14);
Bat = new Rectangle(batx, baty, 100, 12);
movex = -16;
movey = -16;
ballFallDown = false;
bricksOver = false;
count = 0;
status = null;
for (int i = 0; i < Brick.length; i++) //recreates bricks
{
Brick[i] = new Rectangle(brickx, bricky, 40, 20);
if (i == 12)
{
brickx = 32;
bricky = 84;
}
if (i == 23)
{
brickx = 82;
bricky = 118;
}
if (i == 32)
{
brickx = 132;
bricky = 152;
}
if (i == 39)
{
brickx = 182;
bricky = 186;
}
if (i == 44)
{
brickx = 232;
bricky = 220;
}
if (i == 47)
{
brickx = 282;
bricky = 254;
}
if (i == 48)
{
brickx = 144;
bricky = 132;
}
brickx += 50;
}
repaint();
}
#Override
public void keyPressed(KeyEvent e) //allows each key to do desired action
{
int keyCode = e.getKeyCode();
if (keyCode == KeyEvent.VK_LEFT)
{
left = true;
}
if (keyCode == KeyEvent.VK_RIGHT)
{
right = true;
}
if (keyCode == e.VK_P && currentLevel == 0)
{
currentLevel = 1;
}
else if (keyCode == e.VK_E && currentLevel == 1)
{
currentLevel = 0;
score=0;
lives=3;
restart();
}
else if(keyCode == e.VK_Q)
{
System.exit(0);
}
}
#Override
public void keyReleased(KeyEvent e)
{
int keyCode = e.getKeyCode();
if (keyCode == KeyEvent.VK_LEFT)
{
left = false;
}
if (keyCode == KeyEvent.VK_RIGHT)
{
right = false;
}
}
#Override
public void keyTyped(KeyEvent e)
{
}
public static void main(String[] args)
{
Game prog = new Game();
prog.init();
}
}
I'd throw that code out and start over as you've got both program logic and repaints within your painting methods, neither of which will help you, and your code appears to be one big huge "God" class, all of which will leave you with code that's a horrific nightmare to debug. Recommendations:
Create at least two separate JPanels to display your program with, a GamePanel and a MenuPanel.
Swap these JPanels using a CardLayout.
Do all graphics within a JPanel's paintComponent method and not within a JFrame's or JApplet's paint method.
Don't forget to call the super's painting method, the same method as your override within your override. This is to clean up any dirty pixels.
Separate your program logic from your GUI
This means that you should have a logical non-GUI representation of a single Brick class as well as a collection of these non-GUI bricks.
You can always give your Brick class a Color field, one that the view or gui uses to paint it with.
Create a game-loop, one that you can control, one that doesn't involve calling repaint() within a painting method, since this leads to a completely uncontrollable loop.
Favor use of Key Bindings over KeyListeners.
Try to avoid use of "magic" numbers, such as hard-coding your brick width and spacing in the class itself. Better to use constants as this too makes debugging and enhancing much easier.
For example, some code that's just to demonstrate showing random colors:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import javax.swing.*;
public class BrickBreak {
private static void createAndShowGui() {
GamePanel gamePanel = new GamePanel();
JFrame frame = new JFrame("Brick Break");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(gamePanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
// JPanel that draws the game
class GamePanel extends JPanel {
private static final long serialVersionUID = 1L;
private static final Color BACK_GRND = Color.BLACK;
private int prefW;
private int prefH;
private Bricks bricks = new Bricks();
public GamePanel() {
// wide enough to hold the complete top-row of Bricks
// using constants, so GUI automatically resizes if any sizes change
prefW = (Brick.WIDTH + Bricks.X_SPACING) * Bricks.ROW_COUNTS[0] + Bricks.X_SPACING;
prefH = prefW;
setBackground(BACK_GRND);
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(prefW, prefH);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
for (Brick brick : bricks) {
brick.draw(g2);
}
}
}
// non-GUI class that represents a logical Brick
class Brick {
public static final int WIDTH = 40;
public static final int HEIGHT = 20;
private int x;
private int y;
private Color color;
private Rectangle boundingRectangle;
public Brick(int x, int y, Color color) {
this.x = x;
this.y = y;
this.color = color;
boundingRectangle = new Rectangle(x, y, WIDTH, HEIGHT);
}
// yeah, I'm mixing some view with model here.
public void draw(Graphics2D g2) {
g2.setColor(color);
g2.fill3DRect(x, y, WIDTH, HEIGHT, true);
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public Color getColor() {
return color;
}
// use this to test for collisions
public boolean contains(Point p) {
return boundingRectangle.contains(p);
}
#Override
public String toString() {
return "Brick [x=" + x + ", y=" + y + ", color=" + color + "]";
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + x;
result = prime * result + y;
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Brick other = (Brick) obj;
if (x != other.x)
return false;
if (y != other.y)
return false;
return true;
}
}
// logical class that holds all Bricks
// Have class implement Iterable<Brick> so we can easily iterate through its containing
// Brick objects in a for-each loop
class Bricks implements Iterable<Brick> {
public static final int X_SPACING = 10;
public static final int Y_SPACING = X_SPACING;
public static final int[] ROW_COUNTS = {13, 11, 9, 7, 5, 3, 1};
private static final float MIN_SAT = 0.8f;
private List<Brick> brickList;
private Random random = new Random();
public Bricks() {
init(); // safe to call since it's final
}
public final void init() {
// recreate the brickList ArrayList
brickList = new ArrayList<>();
int y = Y_SPACING;
// for each row of bricks
for (int row = 0; row < ROW_COUNTS.length; row++) {
int x = X_SPACING + ((ROW_COUNTS[0] - ROW_COUNTS[row]) / 2) * (X_SPACING + Brick.WIDTH);
// for each column
for (int j = 0; j < ROW_COUNTS[row]; j++) {
// create a random color
float hue = random.nextFloat();
float saturation = MIN_SAT + random.nextFloat() * (1f - MIN_SAT);
float brightness = MIN_SAT + random.nextFloat() * (1f - MIN_SAT);
Color color = Color.getHSBColor(hue, saturation, brightness);
Brick brick = new Brick(x, y, color); // create a new Brick with this Color
brickList.add(brick);
x += X_SPACING + Brick.WIDTH;
}
y += Y_SPACING + Brick.HEIGHT;
}
}
// returns null if no collision
public Brick collision(Point p) {
for (Brick brick : brickList) {
if (brick.contains(p)) {
return brick;
}
}
return null;
}
#Override
public Iterator<Brick> iterator() {
return brickList.iterator();
}
public boolean remove(Brick brick) {
// because Brick implements equals and hashCode, we can do this
return brickList.remove(brick);
}
}
Note that I like using Color's static getHSBColor(float h, float s, float b) method for creating random Colors as this helps me to avoid creating dull Colors, since I can guarantee that the saturation and brightness are above minimum values. All three parameters must be float values between 0f and 1.0f
float hue = random.nextFloat();
float saturation = MIN_SAT + random.nextFloat() * (1f - MIN_SAT);
float brightness = MIN_SAT + random.nextFloat() * (1f - MIN_SAT);
Color color = Color.getHSBColor(hue, saturation, brightness);
Your code has quite a lot of issues, which #HovercaftFullOfEels answer already points out.
As for why your code doesn't work:
for (int i = 0; i < Brick.length; i++)
{
if (Brick[i] != null)
{
Color mycolor=new Color(100,0,0);
art.setColor(mycolor);
art.fill3DRect(Brick[i].x, Brick[i].y, Brick[i].width,
Brick[i].height, true);
}
}
This is the part that renders the bricks. You never create a random-number, but use the same Color for each brick (new Color(100, 0, 0);). Instead introduce a new variable into Brick that specifies the color of each brick and is initialized once with a random color.
The Brick-class would afterwards look like this:
public class Brick{
public int x;
public int y;
...
public Color color;
...
}
The ... are just placeholders for other code that may be content of the class. Regarding public access of Class-variables: Encapsulation is a fundamental concept of OOP and should be used (on encapsulation). E.g. instead of giving direct access to Brick.x consider introducing a method Brick#getX().

Java game slows down when player moves

I'm trying to write my first game in Java. I followed some tutorials and learned how to load and update a background using a Canvas and how to load and move a player sprite. I did these two separately and they worked fine, but when I put the two together and try to move the player, the game slows down to the point that it is unplayable. This only happens when I hold down an arrow key to move the player; the game actually runs "smoothly" if I rapidly tap the arrow key. After quite a bit of testing, I'm convinced that the problem occurs when the background is redrawn each frame. Any other improvements would also be appreciated.
Code (All of it):
Game.Java:
package Game;
import Level.Level;
import Player.Player;
import Sprites.SpriteSheetLoader;
import java.awt.Canvas;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;
import javax.swing.JFrame;
public class Game extends Canvas implements Runnable {
// Set dimensions of the game.
public static final int HEIGHT = 320;
public static final int WIDTH = 480;
public static final int SCALE = 2;
public static Dimension GAME_DIM = new Dimension(WIDTH * SCALE, HEIGHT * SCALE);
private BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_ARGB);
private int[] pixels = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();
public SpriteSheetLoader loader;
public Screen screen;
public Level level;
public InputHandler input = new InputHandler(this);
public Player player = new Player();
private boolean running = false;
private boolean moving = true;
private int FPS = 60;
private long targetTime = 1000 / FPS;
// Set character's starting position at the center. I have no idea why I had to add the "- 50" to each value.
public int x = GAME_DIM.width / 2 - 50;
public int y = GAME_DIM.height / 2 - 50;
public int xScroll = 0;
public int yScroll = 0;
public int col = 0;
public int row = 0;
public int ticks = 0;
public int frame = 0;
public static void main(String[] args) {
Game game = new Game();
game.setPreferredSize(new Dimension(GAME_DIM));
game.setMaximumSize(new Dimension(GAME_DIM));
game.setMinimumSize(new Dimension(GAME_DIM));
JFrame frame = new JFrame("Valkyrie Game");
frame.add(game);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setResizable(true);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
game.start();
}
public void start() {
running = true;
new Thread(this).start();
}
public Game() {
}
public void init() {
loader = new SpriteSheetLoader();
screen = new Screen(WIDTH, HEIGHT);
level = new Level(16, 16);
}
public void run() {
init();
long start, elapsed, wait;
while (running) {
start = System.nanoTime();
render();
tick();
elapsed = System.nanoTime() - start;
//System.out.println("Elapsed: " + elapsed);
wait = targetTime - elapsed / 1000000;
if(wait < 0) {
wait = 5;
}
try {
Thread.sleep(wait);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void stop() {
running = false;
}
public void tick() {
// Movement
if (input.right) {
xScroll++;
player.setAnimation(player.walkRight);
//x++;
row = 2;
ticks++;
if(ticks < 10) {
frame = 1;
} else if(ticks == 10) {
frame = 2;
} else if(ticks == 20) {
frame = 3;
} else if(ticks == 30) {
frame = 2;
} else if(ticks == 40) {
frame = 1;
} else if(ticks == 50) {
ticks = 0;
frame = 0;
}
moving = true;
} else if (input.left) {
xScroll--;
player.setAnimation(player.walkLeft);
//x--;
row = 1;
ticks++;
if(ticks < 10) {
frame = 1;
} else if(ticks == 10) {
frame = 2;
} else if(ticks == 20) {
frame = 3;
} else if(ticks == 30) {
frame = 2;
} else if(ticks == 40) {
frame = 1;
} else if(ticks == 50) {
ticks = 0;
frame = 0;
}
moving = true;
} else if (input.up) {
yScroll--;
player.setAnimation(player.walkUp);
//y--;
row = 3;
ticks++;
if(ticks < 10) {
frame = 1;
} else if(ticks == 10) {
frame = 2;
} else if(ticks == 20) {
frame = 3;
} else if(ticks == 30) {
frame = 2;
} else if(ticks == 40) {
frame = 1;
} else if(ticks == 50) {
ticks = 0;
frame = 0;
}
moving = true;
} else if (input.down) {
yScroll++;
player.setAnimation(player.walkDown);
//y++;
row = 0;
ticks++;
if(ticks < 10) {
frame = 1;
} else if(ticks == 10) {
frame = 2;
} else if(ticks == 20) {
frame = 3;
} else if(ticks == 30) {
frame = 2;
} else if(ticks == 40) {
frame = 1;
} else if(ticks == 50) {
ticks = 0;
frame = 0;
}
moving = true;
}
if (!input.down && !input.left && !input.right && !input.up) {
player.setAnimation(player.stand);
frame = 0;
ticks = 1;
moving = false;
}
//System.out.println("Tick: " + ticks);
}
public void render() {
BufferStrategy bs = getBufferStrategy();
if (bs == null) {
createBufferStrategy(3);
requestFocus();
return;
}
do {
Graphics g = bs.getDrawGraphics();
try {
for (int i = 0; i < ticks; i++) {
g.drawImage(image, 0, 0, getWidth(), getHeight(), null);
g.drawImage(player.Player(frame, row), x, y, null);
level.renderBackground(xScroll, yScroll, screen);
for (int y = 0; y < this.screen.h; y++) {
for (int x = 0; x < screen.w; x++) {
pixels[x + (y * WIDTH)] = screen.pixels[x + (y * screen.w)];
}
}
}
} finally {
g.dispose();
}
bs.show();
this.update(bs.getDrawGraphics());
} while (bs.contentsLost());
// Graphics g = bs.getDrawGraphics();
//
// g.dispose();
// bs.show();
}
}
InputHandler.Java:
package Game;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
public class InputHandler implements KeyListener {
public boolean up = false;
public boolean down = false;
public boolean left = false;
public boolean right = false;
public InputHandler(Game game) {
game.addKeyListener(this);
}
public void toggle(KeyEvent ke, boolean pressed) {
int keyCode = ke.getKeyCode();
if(keyCode == KeyEvent.VK_UP) up = pressed;
if(keyCode == KeyEvent.VK_DOWN) down = pressed;
if(keyCode == KeyEvent.VK_LEFT) left = pressed;
if(keyCode == KeyEvent.VK_RIGHT) right = pressed;
}
public void keyTyped(KeyEvent e) {
}
public void keyPressed(KeyEvent e) {
toggle(e, true);
}
public void keyReleased(KeyEvent e) {
toggle(e, false);
}
}
Screen.Java:
package Game;
import Sprites.Sprite;
public class Screen {
public int w, h;
int xOffset = 0;
int yOffset = 0;
public int[] pixels;
public Screen(int w, int h) {
this.w = w; // 480
this.h = h; // 320
pixels = new int[w * h]; // 153600
}
public void renderSprite(int xPos, int yPos, Sprite sprite) {
int height = sprite.h;
int width = sprite.w;
xPos -= xOffset;
yPos -= yOffset;
for(int y = 0; y < height; y++) {
if(yPos + y < 0 || yPos + y >= h) continue;
for(int x = 0; x < width; x++) {
if(xPos + x < 0 || xPos + x >= w) continue;
int col = sprite.pixels[x + (y * height)];
if(col != -65281 && col < 0) pixels[(x + xPos) + (y + yPos) *w]= col;
}
}
}
public void setOffs(int xOffs, int yOffs) {
xOffset = xOffs;
yOffset = yOffs;
}
}
Level.Java:
package Level;
import Game.Screen;
import Sprites.Sprite;
import Sprites.Sprites;
import Tiles.Tile;
public class Level {
int w, h;
public int[] tiles;
public Level(int w, int h) {
this.w = w;
this.h = h;
tiles = new int[w * h];
loadMap(0, 0, 0, 0);
}
public void renderBackground(int xScroll, int yScroll, Screen screen) {
int xo = xScroll >> 4;
int yo = yScroll >> 4;
int w = (screen.w + 15) >> 4;
int h = (screen.h + 15) >> 4;
screen.setOffs(xScroll, yScroll);
for(int y = yo; y <= h + yo; y++) {
for(int x = xo; x <= w + xo; x++) {
getTile(x, y).render(x, y, screen);
}
}
screen.setOffs(0, 0);
}
public Tile getTile(int x, int y) {
if(x < 0 || y < 0 || x >= w || y >= h) return Tile.rockTile;
return Tile.tiles[tiles[x + y * w]];
}
public void loadMap(int x0, int y0, int x1, int y1) {
Sprite sprite = Sprites.level[x0][y0];
for(int y = 0; y < sprite.h; y++) {
for(int x = 0; x < sprite.w; x++) {
if(sprite.pixels[x + y * sprite.h] == -9276814) {
tiles[x + x1 + (y + y1) * h] = Tile.rockTile.id;
} else {
tiles[x + x1 + (y + y1) * h] = Tile.grassTile.id;
}
}
}
}
}
Player.Java:
package Player;
import Animation.Animation;
import Sprites.Sprite;
import java.awt.image.BufferedImage;
public class Player {
// Images for each animation
private BufferedImage[] walkingLeft = {Sprite.getSprite(0, 1), Sprite.getSprite(1, 1), Sprite.getSprite(2, 1)}; // Gets the upper left images of my sprite sheet
private BufferedImage[] walkingRight = {Sprite.getSprite(0, 2), Sprite.getSprite(1, 2), Sprite.getSprite(2, 2)};
private BufferedImage[] walkingUp = {Sprite.getSprite(0, 3), Sprite.getSprite(1, 3), Sprite.getSprite(2, 3)};
private BufferedImage[] walkingDown = {Sprite.getSprite(0, 0), Sprite.getSprite(1, 0), Sprite.getSprite(2, 0)};
private BufferedImage[] standing = {Sprite.getSprite(1, 0)};
// These are animation states.
public Animation walkLeft = new Animation(walkingLeft, 10);
public Animation walkRight = new Animation(walkingRight, 10);
public Animation walkUp = new Animation(walkingUp, 10);
public Animation walkDown = new Animation(walkingDown, 10);
public Animation stand = new Animation(standing, 10);
// This is the actual animation
public Animation animation = stand;
public BufferedImage Player(int x, int y) {
BufferedImage player = Sprite.getSprite(x, y);
return player;
}
public void update() {
animation.update();
}
public void render() {
}
public void setAnimation(Animation animation) {
this.animation = animation;
}
}
Sprite.Java:
package Sprites;
import Game.Game;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
public class Sprite {
public int w, h;
public int[] pixels;
public static BufferedImage sprite = null;
public Sprite(int w, int h) {
this.w = w;
this.h = h;
pixels = new int[w * h];
}
public void clear(int color) {
for(int i = 0; i < pixels.length; i++) {
pixels[i] = color;
}
}
private static BufferedImage spriteSheet;
private static final int TILE_SIZE = 80;
public static BufferedImage loadSprite() {
try {
sprite = ImageIO.read(Game.class.getResource("/valkyrie.png"));
} catch (IOException e) {
e.printStackTrace();
}
return sprite;
}
public static BufferedImage getSprite(int xGrid, int yGrid) {
if(spriteSheet == null) {
spriteSheet = loadSprite();
}
// xGrid and yGrid refer to each individual sprite
return spriteSheet.getSubimage(xGrid * TILE_SIZE, yGrid * TILE_SIZE, TILE_SIZE, TILE_SIZE);
}
}
This is going to require double buffering. Any game with a lot going on needs double buffering.
How do you double buffer in java for a game?
Although I couldn't go through the code completely, it seems you do not do double buffering which affect performance drastically.
Try this in the relevant part of your program:
JFrame frame = new JFrame("Valkyrie Game");
frame.add(game);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setResizable(true);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
frame.setDoubleBuffered(true); //added line, rest is the same
game.start();
You really should use Timer. It will solve all your problems.
Every tick, you redraw all what you need.
And every tick, you should just check, which keys are pressed and which are not, instead of adding listeners. To keep tracking this, you always have to remember the keys pressed "before".
You can even create two Timers, one for graphic redraw and one for game logic.
Even timers can be delayed or something, the usual approach is to find out, how much time elapsed (System.nanoTime for example) and count how much of game logic you should forward to keep game always unlaggy and fluent.

Asteroid game NullPointerException error

I am having some serious problems with my Asteroid game. I'm trying to call my Game.java run() method in my main method in Asteroid.java but I keep getting the same error:
Exception in thread "main" java.lang.NullPointerException
at asteroids.Asteroids.main(Asteroids.java:15)
Java Result: 1
Can someone help me figure out why this is happening?
here is my code:
Asteroids.java
package asteroids;
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.io.IOException;
#SuppressWarnings("serial")
public class Asteroids {
Game game = null;
public static void main(String[] args){
new Asteroids ().game.run ();
}
}
//NEW Game.java//
package asteroids;
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.Point2D;
import java.util.ArrayList;
//#SuppressWarnings("serial")
public class Game extends Applet implements Runnable, KeyListener {
//timing variables
Thread thread;
long startTime, endTime, framePeriod;
//graphics variables
Image img;
Dimension dim;
int width, height;
Graphics g;
//text items
int level, lives, score;
SpaceShip ship;
boolean shipCollision, shipExplode;
//ArrayList to hold asteroids
ArrayList<Asteroid> asteroids = new ArrayList<>();
int numOfAsteroids = 1;
//ArrayList to hold the lasers
ArrayList<Laser> lasers = new ArrayList<>();
final double rateOfFire = 10; //limits rate of fire
double rateOfFireRemaining; //decrements rate of fire
//ArrayList to hold explosion particles
ArrayList<AsteroidExplosion> explodingLines = new ArrayList<>();
//ArrayList to hold ship explosions
ArrayList<ShipExplosion> shipExplosion = new ArrayList<>();
public void Game ()
{
init();
}
public void init() {
resize(900,700); //set size of the applet
dim = getSize(); //get dimension of the applet
width = dim.width;
height = dim.height;
framePeriod = 25; //set refresh rate
addKeyListener(this); //to get commands from keyboard
setFocusable(true);
ship = new SpaceShip(width/2, height/2, 0, .15, .5, .15, .98); //add ship to game
shipCollision = false;
shipExplode = false;
level = numOfAsteroids;
lives = 3;
addAsteroids();
img = createImage(width, height); //create an off-screen image for double-buffering
g = img.getGraphics(); //assign the off-screen image
thread = new Thread(this);
thread.start();
}
#Override
public void paint(Graphics gfx) {
Graphics2D g2d = (Graphics2D) g;
//give the graphics smooth edges
RenderingHints rh = new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
rh.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHints(rh);
g2d.setColor(Color.BLACK);
g2d.fillRect(0, 0, width, height); //add a black background
//add text for lives, score, and level
g2d.setColor(Color.WHITE);
g2d.drawString("Level : " + level, 10, 690);
g2d.drawString("Lives : " + lives, 110, 690);
g2d.drawString("Score : " + score, 210, 690);
for(Asteroid a: asteroids) { //draw asteroids
a.draw(g2d);
}
for(Laser l : lasers) { //draw lasers
l.draw(g2d);
}
for(AsteroidExplosion e : explodingLines) {
e.draw(g2d);
}
for(ShipExplosion ex : shipExplosion)
ex.draw(g2d);
ship.draw(g2d); //draw ship
if(shipCollision) {
shipExplosion.add(new ShipExplosion(ship.getX(), ship.getY(), 10, 10));
ship.setX(width/2);
ship.setY(height/2);
shipCollision = false;
lives--;
}
gfx.drawImage(img, 0, 0, this); //draw the off-screen image (double-buffering) onto the applet
}
#Override
public void update(Graphics gfx) {
paint(gfx); //gets rid of white flickering
}
#Override
public void run(){
for( ; ; ) {
startTime = System.currentTimeMillis(); //timestamp
ship.move(width, height); //ship movement
for(Asteroid a : asteroids) { //asteroid movement
a.move(width, height);
}
for(Laser l : lasers) { //laser movement
l.move(width, height);
}
for(int i = 0 ; i<lasers.size() ; i++) { //laser removal
if(!lasers.get(i).getActive())
lasers.remove(i);
}
for(AsteroidExplosion e : explodingLines) { //asteroid explosion floating lines movement
e.move();
}
for(int i = 0 ; i<explodingLines.size(); i++) { //asteroid explosion floating lines removal
if(explodingLines.get(i).getLifeLeft() <= 0)
explodingLines.remove(i);
}
for(ShipExplosion ex : shipExplosion){ //ship explosion expansion
ex.expand();
}
for(int i = 0 ; i<shipExplosion.size() ; i++) {
if(shipExplosion.get(i).getLifeLeft() <= 0)
shipExplosion.remove(i);
}
rateOfFireRemaining--;
collisionCheck();
if(asteroids.isEmpty()) {
numOfAsteroids++;
addAsteroids();
level = numOfAsteroids;
}
repaint();
try {
endTime = System.currentTimeMillis(); //new timestamp
if(framePeriod - (endTime-startTime) > 0) //if there is time left over after repaint, then sleep
Thread.sleep(framePeriod - (endTime - startTime)); //for whatever is remaining in framePeriod
} catch(InterruptedException e) {}
}
}
#Override
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
//fires laser
if(key == KeyEvent.VK_SPACE) {
if(rateOfFireRemaining <= 0 ) {
lasers.add(ship.fire());
rateOfFireRemaining = rateOfFire;
}
}
if(key == KeyEvent.VK_UP)
ship.setAccelerating(true);
if(key == KeyEvent.VK_RIGHT)
ship.setTurningRight(true);
if(key == KeyEvent.VK_LEFT)
ship.setTurningLeft(true);
if(key == KeyEvent.VK_DOWN)
ship.setDecelerating(true);
}
#Override
public void keyReleased(KeyEvent e) {
int key = e.getKeyCode();
if(key == KeyEvent.VK_UP)
ship.setAccelerating(false);
if(key == KeyEvent.VK_RIGHT)
ship.setTurningRight(false);
if(key == KeyEvent.VK_LEFT)
ship.setTurningLeft(false);
if(key == KeyEvent.VK_DOWN)
ship.setDecelerating(false);
}
#Override
public void keyTyped(KeyEvent e) {
}
public void addAsteroids() {
int numAsteroidsLeft = numOfAsteroids;
int size;
for(int i=0 ; i<numOfAsteroids ; i++) { //add asteroids to game
//randomize starting position
int asteroidX = (int)(Math.random() * width) + 1;
int asteroidY = (int)(Math.random() * height) + 1;
//randomize speed and direction
double xVelocity = Math.random() + 1; //horizontal velocity
double yVelocity = Math.random() + 1; //vertical velocity
//used starting direction
int xDirection = (int)(Math.random() * 2);
int yDirection = (int)(Math.random() * 2);
//randomize horizontal direction
if (xDirection == 1)
xVelocity *= (-1);
//randomize vertical direction
if (yDirection == 1)
yVelocity *= (-1);
//if there are more then four asteroids, any new ones are MEGA asteroids
if(numAsteroidsLeft > 4) {
size = 2;
} else { size = 1;
}
asteroids.add(new Asteroid(size, asteroidX, asteroidY, 0, .1, xVelocity, yVelocity));
numAsteroidsLeft--;
//Make sure that no asteroids can appear right on top of the ship
//get center of recently created asteroid and ship and check the distance between them
Point2D asteroidCenter = asteroids.get(i).getCenter();
Point2D shipCenter = ship.getCenter();
double distanceBetween = asteroidCenter.distance(shipCenter);
//if asteroid center is within 80 pixels of ship's center, remove it from the ArrayList and rebuild it
if(distanceBetween <= 80) {
asteroids.remove(i);
i--;
numAsteroidsLeft++;
}
}
}
public void collisionCheck() {
//cycle through active asteroids checking for collisions
for(int i = 0 ; i < asteroids.size() ; i++) {
Asteroid a = asteroids.get(i);
Point2D aCenter = a.getCenter();
//check for collisions between lasers and asteroids
for(int j = 0 ; j < lasers.size() ; j++) {
Laser l = lasers.get(j);
Point2D lCenter = l.getCenter();
double distanceBetween = aCenter.distance(lCenter);
if(distanceBetween <= (a.getRadius() + l.getRadius())) {
//split larger asteroids into smaller ones, remove smaller asteroids from screen
if(a.getRadius() >= 60) {
for(int k = 0 ; k < 3 ; k++)
explodingLines.add(a.explode());
split(i);
score += 200;
} else if(a.getRadius() >= 30){
for(int k = 0 ; k < 3 ; k++)
explodingLines.add(a.explode());
split(i);
score += 100;
} else {
for(int k = 0 ; k < 3 ; k++)
explodingLines.add(a.explode());
asteroids.remove(i);
score += 50;
}
lasers.remove(j); //remove laser from screen
}
}
//check for collisions between ship and asteroid
Point2D sCenter = ship.getCenter();
double distanceBetween = aCenter.distance(sCenter);
if(distanceBetween <= (a.getRadius() + ship.getRadius())) {
shipCollision = true;
shipExplode = true;
}
}
}
public void split(int i) {
Asteroid a = asteroids.get(i);
double bigAsteroidX = a.getX();
double bigAsteroidY = a.getY();
int size = (a.getSize() / 2);
asteroids.remove(i);
for(int j = 0 ; j<2 ; j++) {
//randomize speed and direction
double xVelocity = Math.random() + 1; //horizontal velocity
double yVelocity = Math.random() + 1; //vertical velocity
//used randomize starting direction
int xDirection = (int)(Math.random() * 2);
int yDirection = (int)(Math.random() * 2);
//randomize horizontal direction
if (xDirection == 1)
xVelocity *= (-1);
//randomize vertical direction
if (yDirection == 1)
yVelocity *= (-1);
asteroids.add(new Asteroid(size, bigAsteroidX, bigAsteroidY, 0, .1, xVelocity, yVelocity));
}
}
}
//Edit Update//
Okay I tried a lot of stuff and discovered that even though the game works when I debug Game.java and it doesn't work when I run it through Asteroids.java. I found that img = createIimg = createImage(width, height); and g = img.getGraphics(); are returning null and that GraphicsEnvironment.isHeadless() is returning true. How should I change my to fix this issue?
Error
Exception in thread "main" java.lang.NullPointerException
at asteroids.Game.init(Game.java:67)
at asteroids.Game.Game(Game.java:45)
at asteroids.Asteroids.main(Asteroids.java:15)
Java Result: 1
You have the var "game" null, and you tried to call the method "run" on this var (game.run); obviously if "game" is null, you can't get the method, and throws nullpointer exception.
Game game=new Game();
that's all you need. Your final code is:
Game game = new Game();//<----- here is the change
public static void main(String[] args){
new Asteroids ().game.run ();
}
This thing is null.
new Asteroids ().game
That's why you get this NullPointerException when you call run on it.
Game game = null;
public static void main(String[] args){
new Asteroids ().game.run ();
}
The prgram is running from the main method. game is null.
Maybe you should have
Game game = new Game(); // instead of null
Try it may be help
Game game = null;
public static void main(String[] args){
If( Asteroids ().game != null ){
new Asteroids ().game.run ();
}
}

Categories