I am making a little Java Game for practice. Since changing up sprites and what not I am having problems with collision between Enemy and Projectiles. I will provide the Projectile class and can provide more if anyone would like to look! Help would much greatly be appreciated here as I've literally been trying to fix this for hours. Essentially each enemy should take 5 hits then disappear but I can't seem to get it like so. I think the problem lies within the bounds but I really have no idea at the minute what's up.
dn and dn2 are the enemy sprites. r is the projectile fired by my character
public class Projectile {
private int x, y, speedX;
private boolean visible;
private Rectangle r;
public Projectile(int startX, int startY) {
x = startX;
y = startY;
speedX = 7;
visible = true;
r = new Rectangle(0, 0, 0, 0);
}
public void update() {
x += speedX;
r.setBounds(x, y, 10, 5);
if (x > 800) {
visible = false;
r = null;
}
if (x < 800) {
checkCollision();
}
}
private void checkCollision() {
if (r.intersects(StartingClass.dn.r)) {
visible = false;
if (StartingClass.dn.health > 0) {
StartingClass.dn.health -= 1;
}
if (StartingClass.dn.health == 0) {
StartingClass.dn.setCenterX(-100);
StartingClass.score += 5;
}
}
if (r.intersects(StartingClass.dn2.r)) {
visible = false;
if (StartingClass.dn2.health > 0) {
StartingClass.dn2.health -= 1;
}
if (StartingClass.dn2.health == 0) {
StartingClass.dn2.setCenterX(-100);
StartingClass.score += 5;
}
}
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public int getSpeedX() {
return speedX;
}
public boolean isVisible() {
return visible;
}
public void setX(int x) {
this.x = x;
}
public void setY(int y) {
this.y = y;
}
public void setSpeedX(int speedX) {
this.speedX = speedX;
}
public void setVisible(boolean visible) {
this.visible = visible;
}
}
public class Enemy {
private int power, centerX, speedX, centerY;
private Background bg = StartingClass.getBg1();
private Ninja ninja = StartingClass.getNinja();
public static boolean hit = false;
public Rectangle r = new Rectangle(0, 0, 0, 0);
public int health = 5;
private int movementSpeed;
// Behavioral Methods
public void update() {
follow();
centerX += speedX;
speedX = bg.getSpeedX() * 5 + movementSpeed;
r.setBounds(centerX - 25, centerY - 25, 50, 60);
if (r.intersects(Ninja.yellowRed)) {
checkCollision();
}
}
private void checkCollision() {
if (r.intersects(Ninja.rect) || r.intersects(Ninja.rect2) || r.intersects(Ninja.rect3) || r.intersects(Ninja.rect4)){
System.out.println("collision");
hit = true;
}
}
public void follow() {
if (centerX < -95 || centerX > 810) {
movementSpeed = 0;
}
else if (Math.abs(ninja.getCenterX() - centerX) < 5) {
movementSpeed = 0;
}
else {
if (ninja.getCenterX() >= centerX) {
movementSpeed = 1;
} else {
movementSpeed = -1;
}
}
}
public class Ninja {
// Constants are Here
final int JUMPSPEED = -20;
final int MOVESPEED = 5;
private int centerX = 100;
private int centerY = 377;
private boolean jumped = false;
private boolean movingLeft = false;
private boolean movingRight = false;
private boolean ducked = false;
private boolean readyToFire = true;
private int speedX = 0;
private int speedY = 0;
public static Rectangle rect = new Rectangle(0, 0, 0, 0);
public static Rectangle rect2 = new Rectangle(0, 0, 0, 0);
public static Rectangle rect3 = new Rectangle(0, 0, 0, 0);
public static Rectangle rect4 = new Rectangle(0, 0, 0, 0);
public static Rectangle yellowRed = new Rectangle(0, 0, 0, 0);
public static Rectangle footleft = new Rectangle(0, 0, 0, 0);
public static Rectangle footright = new Rectangle(0, 0, 0, 0);
private Background bg1 = StartingClass.getBg1();
private Background bg2 = StartingClass.getBg2();
public Rectangle r = new Rectangle(0, 0, 0, 0);
private ArrayList<Projectile> projectiles = new ArrayList<Projectile>();
public void update() {
// Moves Character or Scrolls Background accordingly.
if (speedX < 0) {
centerX += speedX;
}
if (speedX == 0 || speedX < 0) {
bg1.setSpeedX(0);
bg2.setSpeedX(0);
}
if (centerX <= 200 && speedX > 0) {
centerX += speedX;
}
if (speedX > 0 && centerX > 200) {
bg1.setSpeedX(-MOVESPEED / 5);
bg2.setSpeedX(-MOVESPEED / 5);
}
// Updates Y Position
centerY += speedY;
// Handles Jumping
speedY += 1;
if (speedY > 3) {
jumped = true;
}
// Prevents going beyond X coordinate of 0
if (centerX + speedX <= 60) {
centerX = 61;
}
rect.setRect(centerX - 34, centerY - 30, 67, 62);
rect2.setRect(rect.getX(), rect.getY() + 63, 68, 63);
rect3.setRect(rect.getX() - 26, rect.getY() + 32, 26, 20);
rect4.setRect(rect.getX() + 68, rect.getY() + 32, 26, 20);
yellowRed.setRect(centerX - 100, centerY - 110, 180, 180);
footleft.setRect(centerX - 50, centerY + 20, 50, 15);
footright.setRect(centerX, centerY + 20, 50, 15);
}
public void moveRight() {
if (ducked == false) {
speedX = MOVESPEED;
}
}
public void moveLeft() {
if (ducked == false) {
speedX = -MOVESPEED;
}
}
public void stopRight() {
setMovingRight(false);
stop();
}
public void stopLeft() {
setMovingLeft(false);
stop();
}
private void stop() {
if (isMovingRight() == false && isMovingLeft() == false) {
speedX = 0;
}
if (isMovingRight() == false && isMovingLeft() == true) {
moveLeft();
}
if (isMovingRight() == true && isMovingLeft() == false) {
moveRight();
}
}
public void jump() {
if (jumped == false) {
speedY = JUMPSPEED;
jumped = true;
}
}
public void shoot() {
if (readyToFire) {
Projectile p = new Projectile(centerX + 40, centerY + 80);
projectiles.add(p);
}
}
Problem solved . It lay within my enemy class in r.setBounds(). Just painted that rectangle to screen and adjusted coordinates and all was good
Related
In my game I have two problems. First I am getting some errors that I have no idea how to resolve. Secondly my goal for this project is to add a ball every 30 seconds the player survives. However I have tried several methods in doing so (timers and for loops). However these methods have resulted in graphics not appearing but the rest of the functions working (an invisible ball). If anyone could help me fix these issues it would be much appreciated.
import java.awt.*;
import java.lang.*;
import java.awt.event.KeyEvent;
import java.util.Formatter;
import javax.swing.*;
import java.awt.event.*;
import java.awt.Polygon;
import java.awt.geom.Area;
public class Man implements KeyListener {
private static final int BOX_WIDTH = 640;
private static final int BOX_HEIGHT = 480;
private float ballSpeedX3 = 7;
private float ballSpeedY3 = 7;
private double ball3Radius = 20;
private double ball3X = 320 ;
private double ball3Y = 120 ;
private float ballSpeedX4 = -10;
private float ballSpeedY4 = 10;
private double ball4Radius = 15;
private double ball4X = 600 ;
private double ball4Y = 300 ;
private float ballSpeedX = 0;
private float ballSpeedY = 0;
private double ballRadius = 20;
private double ballX = 120;
private double ballY = 140;
private float ballSpeed1X = 10;
private float ballSpeed1Y = -10;
private double ballRadius1 = 20;
private double ball1X = 320;
private double ball1Y = 340;
private float ballSpeed2X = -3;
private float ballSpeed2Y = -3;
private double ballRadius2 = 50;
private double ball2X = 50;
private double ball2Y = 400;
private static final int UPDATE_RATE = 30;
public Man() {
this.setPreferredSize(new Dimension(BOX_WIDTH, BOX_HEIGHT));
Thread gameThread = new Thread() {
public void run() {
while(true){
if ( Math.sqrt( (Math.pow((ballX- ball1X), 2)) + Math.pow((ballY-ball1Y), 2)) <= (ballRadius1 + ballRadius)) {
System.exit(0);}
if ( Math.sqrt( (Math.pow((ball4X- ballX), 2)) + Math.pow((ball4Y-ballY), 2)) <= (ball4Radius + ballRadius)) {
System.exit(0);}
if ( Math.sqrt( (Math.pow((ball2X- ballX), 2)) + Math.pow((ball2Y-ballY), 2)) <= (ballRadius2 + ballRadius)) {
System.exit(0);}
ball4X += ballSpeedX4;
ball4Y += ballSpeedY4;
if (ball4X - ball4Radius < 0) {
ballSpeedX4 = -ballSpeedX4;
ball4X = ball4Radius;
} else if (ball4X + ball4Radius > BOX_WIDTH) {
ballSpeedX4 = -ballSpeedX4;
ball4X = BOX_WIDTH - ball4Radius;
}
if (ball4Y - ball4Radius < 0) {
ballSpeedY4 = -ballSpeedY4;
ball4Y = ball4Radius;
} else if (ball4Y + ball4Radius > BOX_HEIGHT) {
ballSpeedY4 = -ballSpeedY4;
ball4Y = BOX_HEIGHT - ball4Radius;
}
if ( Math.sqrt( (Math.pow((ball3X- ballX), 2)) + Math.pow((ball3Y-ballY), 2)) <= (ball3Radius + ballRadius)) {
System.exit(0);}
ball3X += ballSpeedX3;
ball3Y += ballSpeedY3;
if (ball3X - ball3Radius < 0) {
ballSpeedX3 = -ballSpeedX3;
ball3X = ball3Radius;
} else if (ball3X + ball3Radius > BOX_WIDTH) {
ballSpeedX3 = -ballSpeedX3;
ball3X = BOX_WIDTH - ball3Radius;
}
if (ball3Y - ball3Radius < 0) {
ballSpeedY3 = -ballSpeedY3;
ball3Y = ball3Radius;
} else if (ball3Y + ball3Radius > BOX_HEIGHT) {
ballSpeedY3 = -ballSpeedY3;
ball3Y = BOX_HEIGHT - ball3Radius;
}
ballX += ballSpeedX;
ballY += ballSpeedY;
if (ballX - ballRadius < 0) {
ballX = ballRadius;
} else if (ballX + ballRadius > BOX_WIDTH) {
ballX = BOX_WIDTH - ballRadius;
}
if (ballY - ballRadius < 0) {
ballY = ballRadius;
} else if (ballY + ballRadius > BOX_HEIGHT) {
ballY = BOX_HEIGHT - ballRadius;
}
ball1X += ballSpeed1X;
ball1Y += ballSpeed1Y;
if (ball1X - ballRadius1 < 0) {
ballSpeed1X = -ballSpeed1X;
ball1X = ballRadius1;
} else if (ball1X + ballRadius1 > BOX_WIDTH) {
ballSpeed1X = -ballSpeed1X;
ball1X = BOX_WIDTH - ballRadius1;
}
if (ball1Y - ballRadius1 < 0) {
ballSpeed1Y = -ballSpeed1Y;
ball1Y = ballRadius1;
} else if (ball1Y + ballRadius1 > BOX_HEIGHT) {
ballSpeed1Y = -ballSpeed1Y;
ball1Y = BOX_HEIGHT - ballRadius1;
}
ball2X += ballSpeed2X;
ball2Y += ballSpeed2Y;
if (ball2X - ballRadius2 < 0) {
ballSpeed2X = -ballSpeed2X;
ball2X = ballRadius2;
} else if (ball2X + ballRadius2 > BOX_WIDTH) {
ballSpeed2X = -ballSpeed2X;
ball2X = BOX_WIDTH - ballRadius2;
}
if (ball2Y - ballRadius2 < 0) {
ballSpeed2Y = -ballSpeed2Y;
ball2Y = ballRadius2;
} else if (ball2Y + ballRadius2 > BOX_HEIGHT) {
ballSpeed2Y = -ballSpeed2Y;
ball2Y = BOX_HEIGHT - ballRadius2;
}
repaint();
try {
Thread.sleep(1000 / UPDATE_RATE);
} catch (InterruptedException ex) { }
}
}
};
gameThread.start();
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLACK);
g.fillRect(0, 0, BOX_WIDTH, BOX_HEIGHT);
g.setColor(Color.BLUE);
g.fillOval((int) (ballX - ballRadius), (int) (ballY - ballRadius),
(int)(2 * ballRadius), (int)(2 * ballRadius));
g.setColor(Color.RED);
g.fillOval((int) (ball1X - ballRadius1), (int) (ball1Y - ballRadius1),
(int)(2 * ballRadius1), (int)(2 * ballRadius1));
g.setColor(Color.PINK);
g.fillOval((int) (ball2X - ballRadius2), (int) (ball2Y - ballRadius2),
(int)(2 * ballRadius2), (int)(2 * ballRadius2));
g.setColor(Color.GREEN);
g.fillOval((int) (ball3X - ball3Radius), (int) (ball3Y - ball3Radius),
(int)(2 * ball3Radius), (int)(2 * ball3Radius));
g.setColor(Color.YELLOW);
g.fillOval((int) (ball4X - ball4Radius), (int) (ball4Y - ball4Radius),
(int)(2 * ball4Radius), (int)(2 * ball4Radius));
}
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_RIGHT ) {
ballSpeedX = 5;
}
else if (e.getKeyCode() == KeyEvent.VK_LEFT ) {
ballSpeedX = -5;
}
else if (e.getKeyCode() == KeyEvent.VK_UP ) {
ballSpeedY = -5;
}
else if (e.getKeyCode() == KeyEvent.VK_DOWN ) {
ballSpeedY = 5;
}
}
public void keyReleased(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_RIGHT ) {
ballSpeedX = 0;
}
else if (e.getKeyCode() == KeyEvent.VK_LEFT ) {
ballSpeedX = 0;
}
else if (e.getKeyCode() == KeyEvent.VK_UP ) {
ballSpeedY = 0;
}
else if (e.getKeyCode() == KeyEvent.VK_DOWN ) {
ballSpeedY = 0;
}
}
public void keyTyped(KeyEvent e) { }
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame frame = new JFrame("Collision");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Man man = new Man();
frame.setContentPane(man);
frame.pack();
frame.addKeyListener(man);
frame.setVisible(true);
}
});
}
}
I reworked your code and created the following GUI.
The red ball hit the pink player, which ended the animation.
All of your code was in one large class. It was too difficult for me to understand what was going on, so I broke your code up into 7 classes. That way, each class could do one thing and do it well. Don't be afraid to use classes and methods to simplify your code and make it easier to find problems.
Here are the changes I made.
I created a Player class to define the player.
I created a Ball class to hold the values of a Ball; the X and Y position, the color, the radius, and the X and Y speed of the ball.
I created a GameModel class to hold an instance of Player and a List of Ball instances. Whenever you're creating a game, you should use the model / view / controller pattern. This pattern allows you to separate your code and focus on one part of the code at a time.
I renamed your Main class to CollisionGame. The only code left in the CollisionGame class is the code to create the game model, create the JFrame and drawing panel, and start the animation.
I created a DrawingPanel from a JPanel. You should always draw on a JPanel. You should never draw on a JFrame.
I put the KeyListener in it's own class. I added the KeyListener to the JPanel. I made sure that the JPanel would have focus.
I put the animation in its own Animation class.
Here's the code. I put all the classes in one file so it would be easier for me to copy and paste. These classes should be put in separate files.
package com.ggl.testing;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class CollisionGame {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new CollisionGame();
}
});
}
private static final int BOX_WIDTH = 640;
private static final int BOX_HEIGHT = 480;
public CollisionGame() {
GameModel gameModel = new GameModel();
JFrame frame = new JFrame("Collision");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
DrawingPanel drawingPanel = new DrawingPanel(gameModel, BOX_WIDTH,
BOX_HEIGHT);
frame.add(drawingPanel);
frame.pack();
frame.setVisible(true);
Animation animation = new Animation(drawingPanel, gameModel, BOX_WIDTH,
BOX_HEIGHT);
new Thread(animation).start();
}
public class DrawingPanel extends JPanel {
private static final long serialVersionUID = -8219208002512324440L;
private int width;
private int height;
private GameModel gameModel;
public DrawingPanel(GameModel gameModel, int width, int height) {
this.gameModel = gameModel;
this.width = width;
this.height = height;
this.setFocusable(true);
this.requestFocusInWindow();
this.addKeyListener(new GameKeyListener(gameModel.getPlayer()));
this.setPreferredSize(new Dimension(width, height));
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLACK);
g.fillRect(0, 0, width, height);
Player player = gameModel.getPlayer();
g.setColor(player.getColor());
double playerRadius = player.getRadius();
double playerDiameter = playerRadius + playerRadius;
g.fillOval((int) (player.getPositionX() - playerRadius),
(int) (player.getPositionY() - playerRadius),
(int) (playerDiameter), (int) (playerDiameter));
for (Ball ball : gameModel.getBalls()) {
g.setColor(ball.getColor());
double ballRadius = ball.getRadius();
double ballDiameter = ballRadius + ballRadius;
g.fillOval((int) (ball.getPositionX() - ballRadius),
(int) (ball.getPositionY() - ballRadius),
(int) (ballDiameter), (int) (ballDiameter));
}
}
}
public class Animation implements Runnable {
private static final long UPDATE_RATE = 30;
private boolean running;
private double width;
private double height;
private DrawingPanel drawingPanel;
private GameModel gameModel;
public Animation(DrawingPanel drawingPanel, GameModel gameModel,
double width, double height) {
this.drawingPanel = drawingPanel;
this.gameModel = gameModel;
this.width = width;
this.height = height;
this.running = true;
}
#Override
public void run() {
sleep(1000L);
long ballTime = System.currentTimeMillis();
long nextBallTime = 30000L;
gameModel.addBall();
while (running) {
long elapsedTime = System.currentTimeMillis() - ballTime;
if (elapsedTime >= nextBallTime) {
gameModel.addBall();
ballTime += nextBallTime;
}
movePlayer(gameModel.getPlayer());
for (Ball ball : gameModel.getBalls()) {
moveBall(ball);
}
repaint();
if (isPlayerHit()) {
running = false;
} else {
sleep(1000L / UPDATE_RATE);
}
}
}
private void movePlayer(Player player) {
player.setPositionX(player.getPositionX() + player.getSpeedX());
player.setPositionY(player.getPositionY() + player.getSpeedY());
double radius = player.getRadius();
if (player.getPositionX() - radius < 0) {
player.setSpeedX(-player.getSpeedX());
player.setPositionX(radius);
} else if (player.getPositionX() + radius > width) {
player.setSpeedX(-player.getSpeedX());
player.setPositionX(width - radius);
}
if (player.getPositionY() - radius < 0) {
player.setSpeedY(-player.getSpeedY());
player.setPositionY(radius);
} else if (player.getPositionY() + radius > height) {
player.setSpeedY(-player.getSpeedY());
player.setPositionY(height - radius);
}
}
private void moveBall(Ball ball) {
ball.setPositionX(ball.getPositionX() + ball.getSpeedX());
ball.setPositionY(ball.getPositionY() + ball.getSpeedY());
double radius = ball.getRadius();
if (ball.getPositionX() - radius < 0) {
ball.setSpeedX(-ball.getSpeedX());
ball.setPositionX(radius);
} else if (ball.getPositionX() + radius > width) {
ball.setSpeedX(-ball.getSpeedX());
ball.setPositionX(width - radius);
}
if (ball.getPositionY() - radius < 0) {
ball.setSpeedY(-ball.getSpeedY());
ball.setPositionY(radius);
} else if (ball.getPositionY() + radius > height) {
ball.setSpeedY(-ball.getSpeedY());
ball.setPositionY(height - radius);
}
}
private boolean isPlayerHit() {
Player player = gameModel.getPlayer();
for (Ball ball : gameModel.getBalls()) {
double radiusSquared = Math.pow(
ball.getRadius() + player.getRadius(), 2D);
double distanceSquared = Math.pow(
(ball.getPositionX() - player.getPositionX()), 2D)
+ Math.pow(ball.getPositionY() - player.getPositionY(),
2D);
if (distanceSquared <= radiusSquared) {
return true;
}
}
return false;
}
private void repaint() {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
drawingPanel.repaint();
}
});
}
private void sleep(long sleepTime) {
try {
Thread.sleep(sleepTime);
} catch (InterruptedException e) {
}
}
}
public class GameKeyListener implements KeyListener {
private float playerSpeedX;
private float playerSpeedY;
private Player player;
public GameKeyListener(Player player) {
this.player = player;
}
#Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
playerSpeedX = 5;
} else if (e.getKeyCode() == KeyEvent.VK_LEFT) {
playerSpeedX = -5;
} else if (e.getKeyCode() == KeyEvent.VK_UP) {
playerSpeedY = -5;
} else if (e.getKeyCode() == KeyEvent.VK_DOWN) {
playerSpeedY = 5;
}
updatePlayer();
}
#Override
public void keyReleased(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
playerSpeedX = 0;
} else if (e.getKeyCode() == KeyEvent.VK_LEFT) {
playerSpeedX = 0;
} else if (e.getKeyCode() == KeyEvent.VK_UP) {
playerSpeedY = 0;
} else if (e.getKeyCode() == KeyEvent.VK_DOWN) {
playerSpeedY = 0;
}
updatePlayer();
}
#Override
public void keyTyped(KeyEvent e) {
}
private void updatePlayer() {
player.setSpeedX(playerSpeedX);
player.setSpeedY(playerSpeedY);
}
}
public class GameModel {
private List<Ball> balls;
private List<Ball> newBalls;
private Player player;
public GameModel() {
this.balls = new ArrayList<>();
this.newBalls = createBalls();
this.player = new Player(Color.PINK, 120, 140, 20, 0, 0);
}
private List<Ball> createBalls() {
List<Ball> balls = new ArrayList<>();
balls.add(new Ball(Color.BLUE, 320, 120, 20, 7, 7));
balls.add(new Ball(Color.RED, 600, 300, 15, -10, 10));
balls.add(new Ball(Color.GREEN, 320, 340, 20, 10, -10));
balls.add(new Ball(Color.YELLOW, 50, 400, 50, -3, -3));
return balls;
}
public void addBall() {
if (!newBalls.isEmpty()) {
balls.add(newBalls.get(0));
newBalls.remove(0);
}
}
public List<Ball> getBalls() {
return balls;
}
public Player getPlayer() {
return player;
}
}
public class Player {
private float speedX;
private float speedY;
private double radius;
private double positionX;
private double positionY;
private Color color;
public Player(Color color, double positionX, double positionY,
double radius, float speedX, float speedY) {
this.color = color;
this.positionX = positionX;
this.positionY = positionY;
this.radius = radius;
this.speedX = speedX;
this.speedY = speedY;
}
public float getSpeedX() {
return speedX;
}
public void setSpeedX(float speedX) {
this.speedX = speedX;
}
public float getSpeedY() {
return speedY;
}
public void setSpeedY(float speedY) {
this.speedY = speedY;
}
public double getRadius() {
return radius;
}
public double getPositionX() {
return positionX;
}
public void setPositionX(double positionX) {
this.positionX = positionX;
}
public double getPositionY() {
return positionY;
}
public void setPositionY(double positionY) {
this.positionY = positionY;
}
public Color getColor() {
return color;
}
}
public class Ball {
private float speedX;
private float speedY;
private double radius;
private double positionX;
private double positionY;
private Color color;
public Ball(Color color, double positionX, double positionY,
double radius, float speedX, float speedY) {
this.color = color;
this.positionX = positionX;
this.positionY = positionY;
this.radius = radius;
this.speedX = speedX;
this.speedY = speedY;
}
public float getSpeedX() {
return speedX;
}
public void setSpeedX(float speedX) {
this.speedX = speedX;
}
public float getSpeedY() {
return speedY;
}
public void setSpeedY(float speedY) {
this.speedY = speedY;
}
public double getRadius() {
return radius;
}
public double getPositionX() {
return positionX;
}
public void setPositionX(double positionX) {
this.positionX = positionX;
}
public double getPositionY() {
return positionY;
}
public void setPositionY(double positionY) {
this.positionY = positionY;
}
public Color getColor() {
return color;
}
}
}
The Man class you're trying to paint on isn't actually a displayable component. What other errors are you getting? They could all be related.
public class Man extends JComponent implements KeyListener {
This will allow the balls to be displayed and the game to start working. As for adding new balls, you may want to create a Ball Object as well as draw methods. You can then add multiple balls to the List and then draw each ball on the list each time your game needs to refresh itself.
So I've been having some trouble with positioning the "camera" on the player since this is my first time trying to accomplish this. Whenever I launch my game and I move my player, the camera doesn't seem to center on the player like I hope it to do and I don't know what is wrong with it. I've tried looking through online resources and checked out many questions on stack overflow but I could not find what I did wrong :/ . I am using Java and using the Slick2D engine. Here are my class files:
Camera.class:
private float offsetMaxX;
private float offsetMaxY;
private float offsetMinX = 0;
private float offsetMinY = 0;
public float camX;
public float camY;
public Camera () {
super ();
}
public void update (float playerX, float playerY, float mapX, float mapY){
offsetMaxX = mapX - Main.WIDTH;
offsetMaxY = mapY - Main.HEIGHT;
camX = playerX - Main.WIDTH/2;
camY = playerY - Main.HEIGHT/2;
if (camX > offsetMaxX) {
camX = offsetMaxX;
} else if (camX < offsetMinX) {
camX = offsetMinX;
}
if (camY > offsetMaxY) {
camY = offsetMaxY;
} else if (camY < offsetMinY) {
camY = offsetMinY;
}
}
public float getCamX() {
return camX;
}
public float getCamY() {
return camY;
}
public float getOffsetMaxX() {
return offsetMaxX;
}
public float getOffsetMaxY() {
return offsetMaxY;
}
public float getOffsetMinX() {
return offsetMinX;
}
public float getOffsetMinY() {
return offsetMinY;
}
public void setOffsetMaxX(float offsetMaxX) {
this.offsetMaxX = offsetMaxX;
}
public void setOffsetMaxY(float offsetMaxY) {
this.offsetMaxY = offsetMaxY;
}
public void setOffsetMinX(float offsetMinX) {
this.offsetMinX = offsetMinX;
}
public void setOffsetMinY(float offsetMinY) {
this.offsetMinY = offsetMinY;
}
And my Game.class:
// Player variables
public SpriteSheet playerSS = null;
protected InputHandler inputHandler;
public float playerX = Main.WIDTH/2, playerY = Main.HEIGHT/2;
private Animation sprite, runningAnimationLEFT, runningAnimationRIGHT, runningAnimationUP, runningAnimationDOWN;
private Animation standLEFT, standRIGHT, standUP, standDOWN; //THIS IS TO PREVENT ANIMATIONS FROM CONTINUING AFTER THE PLAYER STOPS
private int duration = 300;
public boolean isMoving, isLeft, isRight, isUp, isDown;
//Map
private Image testMap; //This is a test map
private float mapX = 1024, mapY = 1024;
//Camera
public Camera camera;
public Game (int stateID) {}
#Override
public int getID() {
return Main.game; //GAMESTATE = 1
}
#Override
public void init(GameContainer gameContainer, StateBasedGame stateBasedGame) throws SlickException {
playerSS = new SpriteSheet("res/characters/player_sprite_sheet.png", 50, 75);
testMap = new Image ("res/grassMap.png");
camera = new Camera();
// ANIMATIONS
runningAnimationDOWN = new Animation();
runningAnimationDOWN.setAutoUpdate(true);
runningAnimationDOWN.addFrame(playerSS.getSprite(1, 0), duration);
runningAnimationDOWN.addFrame(playerSS.getSprite(0, 0), duration);
runningAnimationDOWN.addFrame(playerSS.getSprite(2, 0), duration);
runningAnimationLEFT = new Animation();
runningAnimationLEFT.setAutoUpdate(true);
runningAnimationLEFT.addFrame(playerSS.getSprite(1, 1), duration);
runningAnimationLEFT.addFrame(playerSS.getSprite(0, 1), duration);
runningAnimationLEFT.addFrame(playerSS.getSprite(2, 1), duration);
runningAnimationRIGHT = new Animation();
runningAnimationRIGHT.setAutoUpdate(true);
runningAnimationRIGHT.addFrame(playerSS.getSprite(1, 2), duration);
runningAnimationRIGHT.addFrame(playerSS.getSprite(0, 2), duration);
runningAnimationRIGHT.addFrame(playerSS.getSprite(2, 2), duration);
runningAnimationUP = new Animation();
runningAnimationUP.setAutoUpdate(true);
runningAnimationUP.addFrame(playerSS.getSprite(1, 3), duration);
runningAnimationUP.addFrame(playerSS.getSprite(0, 3), duration);
runningAnimationUP.addFrame(playerSS.getSprite(2, 3), duration);
standDOWN = new Animation();
standDOWN.setAutoUpdate(true);
standDOWN.addFrame(playerSS.getSprite(1, 0), duration);
standLEFT = new Animation();
standLEFT.setAutoUpdate(true);
standLEFT.addFrame(playerSS.getSprite(1, 1), duration);
standRIGHT = new Animation();
standRIGHT.setAutoUpdate(true);
standRIGHT.addFrame(playerSS.getSprite(1, 2), duration);
standUP = new Animation();
standUP.setAutoUpdate(true);
standUP.addFrame(playerSS.getSprite(1, 3), duration);
sprite = standDOWN;
}
#Override
public void update(GameContainer gameContainer, StateBasedGame stateBasedGame, int delta) throws SlickException {
inputHandler.updateKeyboardRelay(gameContainer);
isMoving = false;
if (inputHandler.keyUP) {
isUp = true;
isDown = false;
isLeft = false;
isRight = false;
isMoving = true;
playerY -= delta * 0.1f;
} else if (inputHandler.keyDOWN) {
isDown = true;
isUp = false;
isLeft = false;
isRight = false;
isMoving = true;
playerY += delta * 0.1f;
} else if (inputHandler.keyLEFT) {
isLeft = true;
isUp = false;
isDown = false;
isRight = false;
isMoving = true;
playerX -= delta * 0.1f;
} else if (inputHandler.keyRIGHT) {
isRight = true;
isUp = false;
isDown = false;
isLeft = false;
isMoving = true;
playerX += delta * 0.1f;
}
if (isMoving) {
if (inputHandler.keyUP) {
sprite = runningAnimationUP;
sprite.update(delta);
} else if (inputHandler.keyDOWN) {
sprite = runningAnimationDOWN;
sprite.update(delta);
} else if (inputHandler.keyLEFT) {
sprite = runningAnimationLEFT;
sprite.update(delta);
} else if (inputHandler.keyRIGHT) {
sprite = runningAnimationRIGHT;
sprite.update(delta);
}
} else {
if (isDown) {
sprite = standDOWN;
sprite.update(delta);
} else if (isUp) {
sprite = standUP;
sprite.update(delta);
} else if (isLeft) {
sprite = standLEFT;
sprite.update(delta);
} else if (isRight) {
sprite = standRIGHT;
sprite.update(delta);
}
}
// Map Boundaries
if (playerX > mapX) {
playerX = mapX;
} else if (playerX < 0) {
playerX = 0;
}
if (playerY > mapY) {
playerY = mapY;
} else if (playerY < 0) {
playerY = 0;
}
camera.update(playerX, playerY, mapX, mapY);
}
#Override
public void render(GameContainer gameContainer, StateBasedGame stateBasedGame, Graphics graphics) throws SlickException {
testMap.draw(mapX - 1024, mapY - 1024);
graphics.translate(camera.getCamX(), camera.getCamY());
sprite.draw(playerX, playerY);
graphics.translate(-camera.getCamX(), -camera.getCamY());
graphics.drawString("Player X: " + playerX, 400, 400);
graphics.drawString("Player Y: " + playerY, 400, 415);
}
I feel like there is something specifically wrong in my Camera.class and my update(...) & render(...) methods, but I don't know what.
Here in your camera class in the update method try changing
camX = playerX - Main.WIDTH/2;
camY = playerY - Main.HEIGHT/2;
to
camX = playerX;
camY = playerY;
tell me if this does not work.
Okay so, I've my main class which loads everything in from my framework. What I'm having trouble with now is my collision detection; I've got it so if it hits something, something will happen. I've a method that calls a GameOverUI in the GameScreen class, but I want to use that in my Enemy.class .. I've created a new instance for the object but it's saying its undefined. What I dont get is the class has no definition but a method called GameScreen is defined by (Game game).
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import android.graphics.Color;
import android.graphics.Paint;
import com.vaughanslater.framework.Game;
import com.vaughanslater.framework.Graphics;
import com.vaughanslater.framework.Image;
import com.vaughanslater.framework.Input.TouchEvent;
import com.vaughanslater.framework.Screen;
public class GameScreen extends Screen {
enum GameState {
Ready, Running, Paused, GameOver
}
GameState state = GameState.Ready;
// Variable Setup
private static Background bg1, bg2;
private static Robot robot;
public static Heliboy hb, hb2;
private Image currentSprite, character, character2, character3, heliboy,
heliboy2, heliboy3, heliboy4, heliboy5;
private Animation anim, hanim;
private ArrayList tilearray = new ArrayList();
int livesLeft = 1;
Paint paint, paint2;
public GameScreen(Game game) {
super(game);
// Initialize game objects here
bg1 = new Background(0, 0);
bg2 = new Background(2160, 0);
robot = new Robot();
hb = new Heliboy(340, 360);
hb2 = new Heliboy(700, 360);
character = Assets.character;
character2 = Assets.character2;
character3 = Assets.character3;
heliboy = Assets.heliboy;
heliboy2 = Assets.heliboy2;
heliboy3 = Assets.heliboy3;
heliboy4 = Assets.heliboy4;
heliboy5 = Assets.heliboy5;
anim = new Animation();
anim.addFrame(character, 1250);
anim.addFrame(character2, 50);
anim.addFrame(character3, 50);
anim.addFrame(character2, 50);
hanim = new Animation();
hanim.addFrame(heliboy, 100);
hanim.addFrame(heliboy2, 100);
hanim.addFrame(heliboy3, 100);
hanim.addFrame(heliboy4, 100);
hanim.addFrame(heliboy5, 100);
hanim.addFrame(heliboy4, 100);
hanim.addFrame(heliboy3, 100);
hanim.addFrame(heliboy2, 100);
currentSprite = anim.getImage();
loadMap();
// Defining a paint object
paint = new Paint();
paint.setTextSize(30);
paint.setTextAlign(Paint.Align.CENTER);
paint.setAntiAlias(true);
paint.setColor(Color.WHITE);
paint2 = new Paint();
paint2.setTextSize(100);
paint2.setTextAlign(Paint.Align.CENTER);
paint2.setAntiAlias(true);
paint2.setColor(Color.WHITE);
}
private void loadMap() {
ArrayList lines = new ArrayList();
int width = 0;
int height = 0;
Scanner scanner = new Scanner(SampleGame.map);
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
// no more lines to read
if (line == null) {
break;
}
if (!line.startsWith("!")) {
lines.add(line);
width = Math.max(width, line.length());
}
}
height = lines.size();
for (int j = 0; j < 12; j++) {
String line = (String) lines.get(j);
for (int i = 0; i < width; i++) {
if (i < line.length()) {
char ch = line.charAt(i);
Tile t = new Tile(i, j, Character.getNumericValue(ch));
tilearray.add(t);
}
}
}
}
#Override
public void update(float deltaTime) {
List touchEvents = game.getInput().getTouchEvents();
// We have four separate update methods in this example.
// Depending on the state of the game, we call different update methods.
// Refer to Unit 3's code. We did a similar thing without separating the
// update methods.
if (state == GameState.Ready)
updateReady(touchEvents);
if (state == GameState.Running)
updateRunning(touchEvents, deltaTime);
if (state == GameState.Paused)
updatePaused(touchEvents);
if (state == GameState.GameOver)
updateGameOver(touchEvents);
}
private void updateReady(List touchEvents) {
// This example starts with a "Ready" screen.
// When the user touches the screen, the game begins.
// state now becomes GameState.Running.
// Now the updateRunning() method will be called!
if (touchEvents.size() > 0)
state = GameState.Running;
}
private void updateRunning(List touchEvents, float deltaTime) {
// This is identical to the update() method from our Unit 2/3 game.
// 1. All touch input is handled here:
int len = touchEvents.size();
for (int i = 0; i < len; i++) {
TouchEvent event = (TouchEvent) touchEvents.get(i);
if (event.type == TouchEvent.TOUCH_DOWN) {
if (event.x > 400) {
robot.jump();
currentSprite = anim.getImage();
robot.setDucked(false);
}
else if (inBounds(event, 0, 350, 65, 65)) {
if (robot.isDucked() == false && robot.isJumped() == false
&& robot.isReadyToFire()) {
robot.shoot();
}
}
else if (event.x < 400
&& robot.isJumped() == false) {
currentSprite = Assets.characterDown;
robot.setDucked(true);
robot.setSpeedX(0);
}
//if (event.x > 400) {
// Move right.
// robot.moveRight();
// robot.setMovingRight(true);
//}
}
if (event.type == TouchEvent.TOUCH_UP) {
if (event.x < 400) {
currentSprite = anim.getImage();
robot.setDucked(false);
}
if (inBounds(event, 0, 0, 35, 35)) {
pause();
}
if (event.x > 400) {
// Move right.
robot.stopRight();
}
}
}
// 2. Check miscellaneous events like death:
if (livesLeft == 0) {
state = GameState.GameOver;
}
// 3. Call individual update() methods here.
// This is where all the game updates happen.
// For example, robot.update();
robot.update();
if (robot.isJumped()) {
currentSprite = Assets.characterJump;
} else if (robot.isJumped() == false && robot.isDucked() == false) {
currentSprite = anim.getImage();
}
ArrayList projectiles = robot.getProjectiles();
for (int i = 0; i < projectiles.size(); i++) {
Projectile p = (Projectile) projectiles.get(i);
if (p.isVisible() == true) {
p.update();
} else {
projectiles.remove(i);
}
}
updateTiles();
hb.update();
hb2.update();
bg1.update();
bg2.update();
animate();
if (robot.getCenterY() > 500) {
state = GameState.GameOver;
}
}
private boolean inBounds(TouchEvent event, int x, int y, int width,
int height) {
if (event.x > x && event.x < x + width - 1 && event.y > y
&& event.y < y + height - 1)
return true;
else
return false;
}
private void updatePaused(List touchEvents) {
int len = touchEvents.size();
for (int i = 0; i < len; i++) {
TouchEvent event = (TouchEvent) touchEvents.get(i);
if (event.type == TouchEvent.TOUCH_UP) {
if (inBounds(event, 0, 0, 800, 240)) {
if (!inBounds(event, 0, 0, 35, 35)) {
resume();
}
}
if (inBounds(event, 0, 240, 800, 240)) {
nullify();
goToMenu();
}
}
}
}
private void updateGameOver(List touchEvents) {
int len = touchEvents.size();
for (int i = 0; i < len; i++) {
TouchEvent event = (TouchEvent) touchEvents.get(i);
if (event.type == TouchEvent.TOUCH_DOWN) {
if (inBounds(event, 0, 0, 800, 480)) {
nullify();
game.setScreen(new MainMenuScreen(game));
return;
}
}
}
}
private void updateTiles() {
for (int i = 0; i < tilearray.size(); i++) {
Tile t = (Tile) tilearray.get(i);
t.update();
}
}
#Override
public void paint(float deltaTime) {
Graphics g = game.getGraphics();
g.drawImage(Assets.background, bg1.getBgX(), bg1.getBgY());
g.drawImage(Assets.background, bg2.getBgX(), bg2.getBgY());
paintTiles(g);
ArrayList projectiles = robot.getProjectiles();
for (int i = 0; i < projectiles.size(); i++) {
Projectile p = (Projectile) projectiles.get(i);
g.drawRect(p.getX(), p.getY(), 10, 5, Color.YELLOW);
}
// First draw the game elements.
g.drawImage(currentSprite, robot.getCenterX() - -15,
robot.getCenterY() - -17);
g.drawImage(hanim.getImage(), hb.getCenterX() - 48,
hb.getCenterY() - 48);
g.drawImage(hanim.getImage(), hb2.getCenterX() - 48,
hb2.getCenterY() - 48);
// Example:
// g.drawImage(Assets.background, 0, 0);
// g.drawImage(Assets.character, characterX, characterY);
// Secondly, draw the UI above the game elements.
if (state == GameState.Ready)
drawReadyUI();
if (state == GameState.Running)
drawRunningUI();
if (state == GameState.Paused)
drawPausedUI();
if (state == GameState.GameOver)
drawGameOverUI();
}
private void paintTiles(Graphics g) {
for (int i = 0; i < tilearray.size(); i++) {
Tile t = (Tile) tilearray.get(i);
if (t.type != 0) {
g.drawImage(t.getTileImage(), t.getTileX(), t.getTileY());
}
}
}
public void animate() {
anim.update(10);
hanim.update(50);
}
private void nullify() {
// Set all variables to null. You will be recreating them in the
// constructor.
paint = null;
bg1 = null;
bg2 = null;
robot = null;
hb = null;
hb2 = null;
currentSprite = null;
character = null;
character2 = null;
character3 = null;
heliboy = null;
heliboy2 = null;
heliboy3 = null;
heliboy4 = null;
heliboy5 = null;
anim = null;
hanim = null;
// Call garbage collector to clean up memory.
System.gc();
}
private void drawReadyUI() {
Graphics g = game.getGraphics();
g.drawARGB(155, 0, 0, 0);
g.drawString("Tap to Start.", 400, 240, paint);
}
private void drawRunningUI() {
Graphics g = game.getGraphics();
//g.drawImage(Assets.button, 0, 285, 0, 0, 65, 65);
//g.drawImage(Assets.button, 0, 350, 0, 65, 65, 65);
//g.drawImage(Assets.button, 0, 415, 0, 130, 65, 65);
g.drawImage(Assets.button, 0, 0, 0, 195, 35, 35);
}
private void drawPausedUI() {
Graphics g = game.getGraphics();
// Darken the entire screen so you can display the Paused screen.
g.drawARGB(155, 0, 0, 0);
g.drawString("Resume", 400, 165, paint2);
g.drawString("Menu", 400, 360, paint2);
}
public void drawGameOverUI() {
Graphics g = game.getGraphics();
g.drawRect(0, 0, 1281, 801, Color.BLACK);
g.drawString("GAME OVER.", 400, 240, paint2);
g.drawString("Tap to return.", 400, 290, paint);
}
#Override
public void pause() {
if (state == GameState.Running)
state = GameState.Paused;
}
#Override
public void resume() {
if (state == GameState.Paused)
state = GameState.Running;
}
public GameState getState() {
return state;
}
public void setState(GameState state) {
this.state = state;
}
#Override
public void dispose() {
}
#Override
public void backButton() {
pause();
}
private void goToMenu() {
// TODO Auto-generated method stub
game.setScreen(new MainMenuScreen(game));
}
public static Background getBg1() {
// TODO Auto-generated method stub
return bg1;
}
public static Background getBg2() {
// TODO Auto-generated method stub
return bg2;
}
public static Robot getRobot() {
// TODO Auto-generated method stub
return robot;
}
}
Heres my enemy class too:
import android.graphics.Rect;
public class Enemy {
private int power, centerX, speedX, centerY;
private Background bg = GameScreen.getBg1();
private Robot robot = GameScreen.getRobot();
public Rect r = new Rect(0, 0, 0, 0);
public int health = 5;
private int movementSpeed;
// Behavioural Methods
public void update() {
follow();
centerX += speedX;
speedX = bg.getSpeedX() * 5 + movementSpeed;
r.set(centerX - 25, centerY - 25, centerX + 25, centerY + 35);
if (Rect.intersects(r, Robot.yellowRed)) {
checkCollision();
}
}
private void checkCollision() {
if (Rect.intersects(r, Robot.rect) || Rect.intersects(r, Robot.rect2)
|| Rect.intersects(r, Robot.rect3)
|| Rect.intersects(r, Robot.rect4)) {
GameScreen state = new GameScreen(); // This is where it errors
}
}
public void follow() {
if (centerX < -95 || centerX > 810) {
movementSpeed = 0;
}
else if (Math.abs(robot.getCenterX() - centerX) < 5) {
movementSpeed = 0;
}
else {
if (robot.getCenterX() >= centerX) {
movementSpeed = 1;
} else {
movementSpeed = -1;
}
}
}
public void die() {
}
public void attack() {
}
public int getPower() {
return power;
}
public int getSpeedX() {
return speedX;
}
public int getCenterX() {
return centerX;
}
public int getCenterY() {
return centerY;
}
public Background getBg() {
return bg;
}
public void setPower(int power) {
this.power = power;
}
public void setSpeedX(int speedX) {
this.speedX = speedX;
}
public void setCenterX(int centerX) {
this.centerX = centerX;
}
public void setCenterY(int centerY) {
this.centerY = centerY;
}
public void setBg(Background bg) {
this.bg = bg;
}
}
So here is where it errors:
GameScreen state = new GameScreen(); // This is where it errors
I dont get it, I'm not calling the method GameScreen(Game game) which is defined, but I'm calling the class which isn't. I want to use the drawGameOverUI();.
Sorry for the wall of code.. atleast you can see everthing.
If you define any constructor , default constructor is never used. Please define implementation of GameScreen() or remove the implementation of GameScreen(Game game).
Define a default constructor like this -
public GameScreen() {
super();
// Initialize game objects here
bg1 = new Background(0, 0);
bg2 = new Background(2160, 0);
robot = new Robot();
hb = new Heliboy(340, 360);
hb2 = new Heliboy(700, 360);
character = Assets.character;
character2 = Assets.character2;
character3 = Assets.character3;
heliboy = Assets.heliboy;
heliboy2 = Assets.heliboy2;
heliboy3 = Assets.heliboy3;
heliboy4 = Assets.heliboy4;
heliboy5 = Assets.heliboy5;
anim = new Animation();
anim.addFrame(character, 1250);
anim.addFrame(character2, 50);
anim.addFrame(character3, 50);
anim.addFrame(character2, 50);
hanim = new Animation();
hanim.addFrame(heliboy, 100);
hanim.addFrame(heliboy2, 100);
hanim.addFrame(heliboy3, 100);
hanim.addFrame(heliboy4, 100);
hanim.addFrame(heliboy5, 100);
hanim.addFrame(heliboy4, 100);
hanim.addFrame(heliboy3, 100);
hanim.addFrame(heliboy2, 100);
currentSprite = anim.getImage();
loadMap();
// Defining a paint object
paint = new Paint();
paint.setTextSize(30);
paint.setTextAlign(Paint.Align.CENTER);
paint.setAntiAlias(true);
paint.setColor(Color.WHITE);
paint2 = new Paint();
paint2.setTextSize(100);
paint2.setTextAlign(Paint.Align.CENTER);
paint2.setAntiAlias(true);
paint2.setColor(Color.WHITE);
}
By defining a constructor that accepts an argument you are forcing users to call it.
If you want one without a mandatory game param, define one.
I keep getting a NPE when I run this very basic 2D game. It has something to do with the Key Events but I am not sure how to fix this. Can someone help me? It says the NPE is on this line if (_input.up.isPressed()) {
Here is the InputHandler Class
public class InputHandler implements KeyListener {
public InputHandler(Game game) {
game.addKeyListener(this);
}
public class Key {
private boolean pressed = false;
public void toggle(boolean isPressed) {
pressed = isPressed;
}
public boolean isPressed() {
return pressed;
}
}
// public List<Key> keys = new ArrayList<Key>();
public Key up = new Key();
public Key down = new Key();
public Key left = new Key();
public Key right = new Key();
public void keyPressed(KeyEvent e) {
toggleKey(e.getKeyCode(), true);
}
public void keyReleased(KeyEvent e) {
toggleKey(e.getKeyCode(), false);
}
public void keyTyped(KeyEvent e) {
}
public void toggleKey(int keyCode, boolean isPressed) {
if (keyCode == KeyEvent.VK_W) {
up.toggle(isPressed);
} else if (keyCode == KeyEvent.VK_S) {
down.toggle(isPressed);
} else if (keyCode == KeyEvent.VK_A) {
left.toggle(isPressed);
} else if (keyCode == KeyEvent.VK_D) {
right.toggle(isPressed);
}
}
}
here is the Player Class
public class Player extends Mob {
private InputHandler _input;
private int _speed;
private int _r = 10;
private int _x, _y;
public Player(int x, int y, int speed, InputHandler input) {
super("Player", x, y, 1);
_input = input;
_speed = speed;
_x = x;
_y = y;
}
public boolean hasCollided(int dx, int dy) {
return false;
}
public void update() {
int dx = 0;
int dy = 0;
if (_input.up.isPressed()) {
dy--;
} else if (_input.down.isPressed()) {
dy++;
} else if (_input.left.isPressed()) {
dx--;
} else if (_input.right.isPressed()) {
dx++;
}
if (dx != 0 || dy != 0) {
move(dx, dy);
isMoving = true;
} else {
isMoving = false;
}
if (_x < _r)
_x = _r;
if (_y < _r)
_y = _r;
if (_x > Game.WIDTH - _r)
_x = Game.WIDTH - _r;
if (_y > Game.HEIGHT - _r)
_y = Game.HEIGHT - _r;
}
public void render(Graphics2D g) {
g.setColor(Color.BLACK);
g.fillOval(x - _r, y - _r, 2 * _r, 2 * _r);
g.setStroke(new BasicStroke(3));
g.setColor(Color.GRAY);
g.drawOval(x - _r, y - _r, 2 * _r, 2 * _r);
g.setStroke(new BasicStroke(1));
}
}
here is the game class which creates the player
public class Game extends Canvas implements Runnable {
private static Game _instance;
private static final String TITLE = "ProjectG";
public static final int WIDTH = 960;
public static final int HEIGHT = WIDTH * 3 / 4;
private static final int SCALE = 1;
// to make it have a higher resolution double the width and height but half
// the scale. You are doubling the width and height but keeping the same
// window size by reducing the scale
public static final Dimension SIZE = new Dimension(WIDTH * SCALE, HEIGHT * SCALE);
private static final int UPDATE_RATE = 60;
private static final int RENDER_RATE = 60;
private JFrame _frame;
private Thread _thread;
private boolean _running = false;
private int _tps = 0;
private int _fps = 0;
private int _totalTicks = 0;
private BufferedImage image;
private Graphics2D g;
public InputHandler input;
private Player player;
public Game() {
_instance = this;
setPreferredSize(SIZE);
setMinimumSize(SIZE);
setMaximumSize(SIZE);
_frame = new JFrame(TITLE);
_frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
_frame.setLayout(new BorderLayout());
_frame.add(_instance, BorderLayout.CENTER);
_frame.pack();
_frame.setResizable(false);
_frame.setLocationRelativeTo(null);
_frame.setVisible(true);
player = new Player(Game.WIDTH / 2, Game.HEIGHT / 2, 1, input);
}
public synchronized void start() {
_running = true;
_thread = new Thread(this, TITLE + "_main");
_thread.start();
}
public synchronized void stop() {
_running = false;
if (_thread != null) {
try {
_thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void run() {
double lastUpdateTime = System.nanoTime();
double lastRenderTime = System.nanoTime();
final int ns = 1000000000;
final double nsPerUpdate = (double) ns / UPDATE_RATE;
final double nsPerRender = (double) ns / RENDER_RATE;
final int maxUpdatesBeforeRender = 1;
int lastSecond = (int) lastUpdateTime / ns;
int tickCount = 0;
int renderCount = 0;
image = new BufferedImage(WIDTH * SCALE, HEIGHT * SCALE, BufferedImage.TYPE_INT_RGB);
g = (Graphics2D) image.getGraphics();
while (_running) {
long currTime = System.nanoTime();
int tps = 0;
while ((currTime - lastUpdateTime) > nsPerUpdate && tps < maxUpdatesBeforeRender) {
update();
tickCount++;
_totalTicks++;
tps++;
lastUpdateTime += nsPerUpdate;
}
if (currTime - lastUpdateTime > nsPerUpdate) {
lastUpdateTime = currTime - nsPerUpdate;
}
float interpolation = Math.min(1.0F, (float) ((currTime - lastUpdateTime) / nsPerUpdate));
render(interpolation);
draw();
renderCount++;
lastRenderTime = currTime;
int currSecond = (int) (lastUpdateTime / ns);
if (currSecond > lastSecond) {
_tps = tickCount;
_fps = renderCount;
tickCount = 0;
renderCount = 0;
lastSecond = currSecond;
System.out.println(_tps + " TPS " + _fps + " FPS");
}
while (currTime - lastRenderTime < nsPerRender && currTime - lastUpdateTime < nsPerUpdate) {
Thread.yield();
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
currTime = System.nanoTime();
}
}
}
public void update() {
player.update();
}
public void render(float interpolation) {
BufferStrategy bs = getBufferStrategy();
if (bs == null) {
createBufferStrategy(3);
}
g.setColor(Color.WHITE);
g.fillRect(0, 0, WIDTH * SCALE, HEIGHT * SCALE);
g.setColor(Color.BLACK);
g.drawString("TPS: " + _fps + " FPS: " + _fps, 10, 20);
player.render(g);
}
public void draw() {
Graphics g2 = this.getGraphics();
g2.drawImage(image, 0, 0, null);
g2.dispose();
}
public Game getGame() {
return this;
}
}
You haven't initialized input, so what you pass to
player = new Player(Game.WIDTH / 2, Game.HEIGHT / 2, 1, input);
is null. You need to initialize it before
input = new InputHandler(this);
After making changes based on user suggestions I have taken the following code a few steps further by introducing single/double click recognition. Why are the balls being created in the top left corner and not where the mouse is clicked?
BouncingBalls.java
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
public class BouncingBalls extends JPanel implements MouseListener {
protected List<RandomBall> randomBalls = new ArrayList<RandomBall>(20);
protected List<VerticalBall> verticalBalls = new ArrayList<VerticalBall>(20);
private Container container;
private DrawCanvas canvas;
private Boolean doubleClick = false;
private final Integer waitTime = (Integer) Toolkit.getDefaultToolkit()
.getDesktopProperty("awt.multiClickInterval");
private static int canvasWidth = 500;
private static int canvasHeight = 500;
public static final int UPDATE_RATE = 30;
int count = 0;
public static int random(int maxRange) {
return (int) Math.round((Math.random() * maxRange));
}
public BouncingBalls(int width, int height) {
canvasWidth = width;
canvasHeight = height;
container = new Container();
canvas = new DrawCanvas();
this.setLayout(new BorderLayout());
this.add(canvas, BorderLayout.CENTER);
this.addMouseListener(this);
start();
}
public void start() {
Thread t = new Thread() {
public void run() {
while (true) {
update();
repaint();
try {
Thread.sleep(1000 / UPDATE_RATE);
} catch (InterruptedException e) {
}
}
}
};
t.start();
}
public void update() {
for (RandomBall ball : randomBalls) {
ball.ballBounce(container);
}
for (VerticalBall ball : verticalBalls) {
ball.verticalBounce(container);
}
}
class DrawCanvas extends JPanel {
public void paintComponent(Graphics g) {
super.paintComponent(g);
container.draw(g);
for (RandomBall ball : randomBalls) {
ball.draw(g);
}
for (VerticalBall ball : verticalBalls) {
ball.draw(g);
}
}
public Dimension getPreferredSize() {
return (new Dimension(canvasWidth, canvasHeight));
}
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame f = new JFrame("Stack Answer 2");
f.setDefaultCloseOperation(f.EXIT_ON_CLOSE);
f.setContentPane(new BouncingBalls(canvasHeight, canvasWidth));
f.pack();
f.setVisible(true);
}
});
}
#Override
public void mouseClicked(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mousePressed(MouseEvent e) {
if (e.getClickCount() >= 2) {
doubleClick = true;
verticalBalls.add(new VerticalBall(getX(), getY(), canvasWidth, canvasHeight));
System.out.println("double click");
} else {
Timer timer = new Timer(waitTime, new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (doubleClick) {
/* we are the first click of a double click */
doubleClick = false;
} else {
count++;
randomBalls.add(new RandomBall(getX(), getY(), canvasWidth, canvasHeight));
/* the second click never happened */
System.out.println("single click");
}
}
});
timer.setRepeats(false);
timer.start();
}
}
#Override
public void mouseReleased(MouseEvent e) {
// TODO Auto-generated method stub
}
}
RandomBall.java
import java.awt.Color;
import java.awt.Graphics;
public class RandomBall {
public static int random(int maxRange) {
return (int) Math.round((Math.random() * maxRange));
}
private int x;
private int y;
private int canvasWidth = 500;
private int canvasHeight = 500;
private boolean leftRight;
private boolean upDown;
private int deltaX;
private int deltaY;
private int radius = 20;
private int red = random(255);
private int green = random(255);
private int blue = random(255);
RandomBall(int x, int y, int width, int height) {
this(x, y, width, height, false, false);
}
RandomBall(int x, int y, int width, int height, boolean leftRight, boolean upDown) {
this.x = x;
this.y = y;
this.canvasWidth = width;
this.canvasHeight = height;
this.leftRight = leftRight;
this.upDown = upDown;
updateDelta();
}
public void draw(Graphics g) {
g.setColor(new Color(red, green, blue));
g.fillOval((int) (x - radius), (int) (y - radius), (int) (2 * radius),
(int) (2 * radius));
}
private void updateDelta() {
final int minimumMovement = 5;
final int maxExtra = 10;
deltaY = minimumMovement + (int) (Math.random() * maxExtra);
deltaX = minimumMovement + (int) (Math.random() * maxExtra);
}
public void ballBounce(Container container) {
// controls horizontal ball motion
if (leftRight) {
x += deltaX;
if (x >= getWidth()) {
leftRight = false;
updateDelta();
}
} else {
x += -deltaX;
if (x <= 0) {
leftRight = true;
updateDelta();
}
}
// controls vertical ball motion
if (upDown) {
y += deltaY;
if (y >= getHeight()) {
upDown = false;
updateDelta();
}
} else {
y += -deltaY;
if (y <= 0) {
upDown = true;
updateDelta();
}
}
}
public void verticalBounce(Container container) {
// controls vertical ball motion
if (upDown) {
y += deltaY;
if (y >= getHeight()) {
upDown = false;
updateDelta();
}
} else {
y += -deltaY;
if (y <= 0) {
upDown = true;
updateDelta();
}
}
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public int getWidth() {
return canvasWidth;
}
public int getHeight() {
return canvasHeight;
}
}
VerticalBall.java
import java.awt.Color;
import java.awt.Graphics;
public class VerticalBall {
public static int random(int maxRange) {
return (int) Math.round((Math.random() * maxRange));
}
private int x;
private int y;
private int canvasWidth = 500;
private int canvasHeight = 500;
private boolean upDown;
private int deltaY;
private int radius = 20;
private int red = random(255);
private int green = random(255);
private int blue = random(255);
VerticalBall(int x, int y, int width, int height) {
this(x, y, width, height, false);
}
VerticalBall(int x, int y, int width, int height, boolean upDown) {
this.x = x;
this.y = y;
this.canvasWidth = width;
this.canvasHeight = height;
this.upDown = upDown;
updateDelta();
}
public void draw(Graphics g) {
g.setColor(new Color(red, green, blue));
g.fillOval((int) (x - radius), (int) (y - radius), (int) (2 * radius),
(int) (2 * radius));
}
private void updateDelta() {
final int minimumMovement = 5;
final int maxExtra = 10;
deltaY = minimumMovement + (int) (Math.random() * maxExtra);
}
public void verticalBounce(Container container) {
// controls vertical ball motion
if (upDown) {
y += deltaY;
if (y >= getHeight()) {
upDown = false;
updateDelta();
}
} else {
y += -deltaY;
if (y <= 0) {
upDown = true;
updateDelta();
}
}
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public int getWidth() {
return canvasWidth;
}
public int getHeight() {
return canvasHeight;
}
}
Container.java
import java.awt.Color;
import java.awt.Graphics;
public class Container {
private static final int HEIGHT = 500;
private static final int WIDTH = 500;
private static final Color COLOR = Color.WHITE;
public void draw(Graphics g) {
g.setColor(COLOR);
g.fillRect(0, 0, WIDTH, HEIGHT);
}
}
Change your move method in the Ball class with this one (your conditions are not corrects) :
public void move(Container container) {
if (leftRight) {
x += deltaX;
if (x >= canvasWidth) {
leftRight = false;
updateDelta();
}
} else {
x += -deltaX;
if (x <= 0) {
leftRight = true;
updateDelta();
}
}
if (upDown) {
y += deltaY;
upDown = !(y >= (canvasHeight));
if (y >= (canvasHeight)) {
upDown = false;
updateDelta();
}
} else {
y += -deltaY;
if (y <= 0) {
upDown = true;
updateDelta();
}
}
}
I run it and it works
Your movement logic is overly complicated for simply moving a ball, you should think about conservation of momentum if you want it to bounce off the walls.
The problem is
x >= (Ball.this.getWidth() - canvasWidth / 2)` and `y >= (Ball.this.getHeight() - canvasHeight / 2)
You are creating balls using the first constructor
balls.add(new Ball(x, y, canvasWidth, canvasHeight));
So you are just checking if x>=0 and y>=0, it will keep bouncing around with +- deltax/deltay positions.
A simpler way of making it bounce off walls would be
public void move(Container container) {
if(x>=canvasWidth || x<=0){
deltaX = -1*deltaX;
}
if(y>=canvasHeight || y<=0){
deltaY = -1*deltaY;
}
x+= deltaX;
y+= deltaY;
}
change
public void move(Container container) {
if (leftRight) {
x += deltaX;
if (x >= (Ball.this.getWidth() - canvasWidth / 2)) {
leftRight = false;
updateDelta();
}
} else {
x += -deltaX;
if (x <= 0) {
leftRight = true;
updateDelta();
}
}
if (upDown) {
y += deltaY;
upDown = !(y >= (Ball.this.getHeight() - canvasHeight / 2));
if (y >= (Ball.this.getHeight() - canvasHeight / 2)) {
upDown = false;
updateDelta();
}
} else {
y += -deltaY;
if (y <= 0) {
upDown = true;
updateDelta();
}
}
}
to
public void move(Container container) {
if (leftRight) {
x += deltaX;
if (x >= getWidth()) {
leftRight = false;
updateDelta();
}
} else {
x += -deltaX;
if (x <= 0) {
leftRight = true;
updateDelta();
}
}
if (upDown) {
y += deltaY;
if (y >= getHeight()) {
upDown = false;
updateDelta();
}
} else {
y += -deltaY;
if (y <= 0) {
upDown = true;
updateDelta();
}
}
}
It's because you're using Ball.this.getWidth() and getHeight()...which are set to the canvas height in the constructor. If you use the radius instead, it works. For example:
if ( x >= ( canvasWidth - radius ) )
{
leftRight = false;
updateDelta();
}
And:
if ( y >= ( canvasHeight - radius ) )
{
upDown = false;
updateDelta();
}