im triying to create a simple game, where my player, falls into different platforms. However, rigth now, im only able to detect the first collision.
I've tried making a loop, where i call HandleEvent(), but only works for the first platform.
How could i make it to detect every time the player collides with a platform? Thank you!
Player class:
package com.mygdx.juegoreto;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.math.Intersector;
import com.badlogic.gdx.math.Rectangle;
import java.util.ArrayList;
public class Personaje {
int x;
int y;
int width;
int height;
int xSpeed;
int ySpeed;
Color color;
public Personaje(int x, int y, int width, int height, int xSpeed, int ySpeed) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.xSpeed = xSpeed;
this.ySpeed = ySpeed;
this.color = Color.WHITE;
}
public void setxSpeed(int xSpeed) {
this.xSpeed = xSpeed;
}
public void setySpeed(int ySpeed) {
this.ySpeed = ySpeed;
}
public void update() {
x += xSpeed;
y += ySpeed;
if (x < 0 || x > Gdx.graphics.getWidth() - 70) {
xSpeed = -xSpeed;
}
if (y > Gdx.graphics.getHeight()) {
System.out.println("tas muerto");
}
}
public void draw(ShapeRenderer shape) {
shape.rect(x, y, width, height);
}
public void checkCollision(ArrayList<Plataforma> plats) {
if(collidesWith(plats)){
color = Color.GREEN;
}
else{
color = Color.WHITE;
}
}
private boolean collidesWith(ArrayList<Plataforma> plats) {
System.out.println("collides");
for (Plataforma plat : plats) {
if(x < plat.x + plat.width && y < plat.y + plat.height && x + width > plat.x && y + height > plat.y){
this.setySpeed(plat.ySpeed);
System.out.println("si");
return true;
}else{
this.setySpeed(-3);
System.out.println("no");
return false;
}
}
return true;
}
}
Main class:
package com.mygdx.juegoreto;
import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.physics.box2d.Fixture;
import com.badlogic.gdx.utils.ScreenUtils;
import com.badlogic.gdx.graphics.GL20;
import java.util.ArrayList;
public class MyGame extends ApplicationAdapter {
ShapeRenderer shape;
Personaje player;
Plataforma plat;
ArrayList<Plataforma> plats;
private float timeSeconds = 0f;
private float period = 0f;
#Override
public void create () {
int x = Gdx.graphics.getWidth() / 2;
int y = Gdx.graphics.getHeight() ;
shape = new ShapeRenderer();
player = new Personaje(x, y - 200, 70, 70, 0, 0);
plat = new Plataforma(x - 70, y - 800, 200, 20,2);
plats = new ArrayList<>(1);
int altura = 0;
for(int i = 0; i <= 1 ; i++){
altura -= 160;
plats.add(new Plataforma((int)(Math.random() * Gdx.graphics.getWidth()), altura, 200, 20, 2));
}
}
#Override
public void render () {
ScreenUtils.clear(1, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
player.update();
//plat.update();
shape.begin(ShapeRenderer.ShapeType.Filled);
player.draw(shape);
//plat.draw(shape);
timeSeconds +=Gdx.graphics.getDeltaTime();
if(timeSeconds > period){
timeSeconds-=period;
handleEvent();
}
shape.end();
if (Gdx.input.isTouched()) {
if (Gdx.input.getX() < Gdx.graphics.getWidth() / 2){
player.setxSpeed(-2); //IZQUIERDA
} else {
player.setxSpeed(2); //DERECHA
}
}
if(player.y < -40){
System.out.println("tas muerto je");
}
/*for (Plataforma plat : plats ) {
int x = (int)(Math.random() * Gdx.graphics.getWidth());
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(x);
plat.draw(shape);
}*/
}
#Override
public void dispose () {
}
public void handleEvent() {
for (Plataforma plataforma : plats) {
plataforma.update();
plataforma.draw(shape);
}
player.checkCollision(plats);
}
}
Related
I'm very confused as to why my scoreboard isn't updating on screen. The scores are increasing (I checked with debugger, also the ball is being centered). But the scoreboard isn't updating at all it constantly says "0 : 0"
Pong Class
package com.dheraxysgames.pong;
import java.awt.Dimension;
import javax.swing.JFrame;
public class Pong extends JFrame{
private static final long serialVersionUID = 1L;
//Set Resolution
public static final int width = 300,
height = width / 4 * 3,
scale = 3;
public Pong() {
Dimension size = new Dimension(width * scale, height * scale);
setSize(size);
setTitle("PONG");
setResizable(false);
setVisible(true);
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
add(new GamePanel());
}
public static int getWindowWidth(){
return width * scale;
}
public static int getWindowHeight(){
return height * scale;
}
public static void main(String[] args) {
new Pong();
}
}
GamePanel Class
package com.dheraxysgames.pong;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JPanel;
import javax.swing.Timer;
public class GamePanel extends JPanel implements ActionListener, KeyListener {
private static final long serialVersionUID = 1L;
Ball ball = new Ball();
Player player = new Player();
AI ai = new AI(this);
public GamePanel(){
Timer time = new Timer(50, this);
time.start();
this.addKeyListener(this);
this.setFocusable(true);
}
private void update(){
player.update();
ai.update();
ball.update();
ball.checkCollision(player);
ball.checkCollision(ai);
}
public void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(Color.BLACK);
g.fillRect(0, 0, Pong.getWindowWidth(), Pong.getWindowHeight());
g.setColor(Color.WHITE);
Font font = new Font("IMMORTAL", Font.BOLD, 50);
g.setFont(font);
g.drawString(player.score + " : " + ai.score, Pong.getWindowWidth() / 2 - 60, 50);
player.paint(g);
ai.paint(g);
ball.paint(g);
}
public Ball getBall(){
return ball;
}
public void actionPerformed(ActionEvent e) {
update();
repaint();
}
//Keyboard
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_UP) player.setYVelocity(-10);
if (e.getKeyCode() == KeyEvent.VK_DOWN) player.setYVelocity(10);
}
public void keyReleased(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_UP) player.setYVelocity(0);
if (e.getKeyCode() == KeyEvent.VK_DOWN) player.setYVelocity(0);
}
public void keyTyped(KeyEvent e) {
}
}
Player Class
package com.dheraxysgames.pong;
import java.awt.Color;
import java.awt.Graphics;
public class Player {
public int score = 0;
private static int width = 50,
height = 150;
private int x = 800, y = (Pong.getWindowHeight() / 2) - (height / 2),
yV = 0;
public Player() {
}
public void update(){
y += yV;
}
public void paint(Graphics g){
g.setColor(Color.GREEN);
g.fillRect(x, y, width, height);
}
public int getX(){
return x;
}
public int getY(){
return y;
}
public int getWidth(){
return width;
}
public int getHeight(){
return height;
}
public void setYVelocity(int speed){
yV = speed;
}
}
AI Class
package com.dheraxysgames.pong;
import java.awt.Color;
import java.awt.Graphics;
public class AI {
public int score = 0;
private static int width = 50,
height = 150;
private GamePanel field;
private int x = 50, y = (Pong.getWindowHeight() / 2) - (height / 2),
yV = 0;
public AI(GamePanel game) {
this.field = game;
}
public AI(){
}
public void update(){
if(field.getBall().getY() < this.y) yV = -8;
if(field.getBall().getY() > this.y) yV = 8;
y += yV;
}
public void paint(Graphics g){
g.setColor(Color.GREEN);
g.fillRect(x, y, width, height);
}
public int getX(){
return x;
}
public int getY(){
return y;
}
public int getWidth(){
return width;
}
public int getHeight(){
return height;
}
public void setYVelocity(int speed){
yV = speed;
}
}
Ball Class
package com.dheraxysgames.pong;
import java.awt.Color;
import java.awt.Graphics;
public class Ball {
private int x = Pong.getWindowWidth() / 2, y = Pong.getWindowHeight() / 2,
xV = 10, yV = 10;
private static int size = 40;
Player player = new Player();
AI ai = new AI();
public void update() {
x += xV;
y += yV;
if (x < 0){
reverseXDirection();
player.score++;
x = Pong.getWindowWidth() / 2;
y = Pong.getWindowHeight() / 2;
}
if (x > Pong.getWindowWidth() - size){
reverseXDirection();
ai.score++;
x = Pong.getWindowWidth() / 2;
y = Pong.getWindowHeight() / 2;
}
if (y < 0 || y > Pong.getWindowHeight() - size - 38) reverseYDirection();
}
public void paint(Graphics g){
g.setColor(Color.GREEN);
g.fillOval(x, y, size, size);
}
private void reverseXDirection(){
xV = -xV;
}
private void reverseYDirection(){
yV = -yV;
}
public void checkCollision(Player p) {
if (this.x + size > p.getX() && this.x + size < p.getX() + p.getWidth()){
if (this.y + size > p.getY() && this.y + size < p.getY() + p.getHeight()){
reverseXDirection();
}
}
}
public void checkCollision(AI ai) {
if (this.x > ai.getX() && this.x < ai.getX() + ai.getWidth()){
if (this.y > ai.getY() && this.y < ai.getY() + ai.getHeight()){
reverseXDirection();
}
}
}
public int getX(){
return x;
}
public int getY(){
return y;
}
}
In you're Ball class the score you're updating is not the same score that is being checked in the GamePanel class.
Notice how in both classes you are calling
Player player = new Player();
AI ai = new AI();
player and ai in Ball are seperate instances from the player and ai in GamePanel.
You will need to get the player and ai from the GamePanel class and pass them to the Ball class. The easiest way to do this would probably be to give Ball a constructor like so
Player player;
AI ai;
public Ball(Player player, AI ai) {
this.player = player;
this.ai = ai;
}
And in your GamePanel class change:
Ball ball = new Ball();
Player player = new Player();
AI ai = new AI(this);
To this:
Player player = new Player();
AI ai = new AI(this);
Ball ball = new Ball(player, ai);
It's been a while since I've used java so I'm probably forgetting a simpler way to do this, but this should solve the problem.
I'm recreating Asteroids, the spaceship can move forward and backwards and change it's rotation. When I for example move forward, the velocity keeps increasing until I release the forward key. But it also stops increasing the velocity when I for example hit the rotate left key. I don't understand why it does this, and I want to be able to increase the rotation degrees while increasing or decreasing my velocity (i.e. pressing UP or DOWN arrow). It also stops moving forward or rotating when I shoot (i.e. space bar).
Also, is my code readable and the aproach OO?
Asteroids:
import javax.swing.*;
public class Asteroids {
public static void createAndShowGui() {
GamePanel gamePanel = new GamePanel();
JFrame frame = new JFrame("Asteroids");
frame.getContentPane().add(gamePanel);
frame.pack();
frame.setVisible(true);
frame.setResizable(false);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setLocation(2000, 50);
gamePanel.requestFocusInWindow();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
GamePanel.java
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
public class GamePanel extends JPanel implements ActionListener {
private final int WIDTH = 1600;
private final int HEIGHT = 900;
private ArrayList<Rock> rocks;
private ArrayList<Bullet> bullets;
private SpaceShip spaceShip;
private boolean keyHeld;
private int keyCode;
public GamePanel() {
setPreferredSize(new Dimension(WIDTH, HEIGHT));
setUp();
}
public void setUp() {
Timer animationTimer = new Timer(15, this);
spaceShip = new SpaceShip(WIDTH, HEIGHT);
bullets = new ArrayList<>();
rocks = new ArrayList<>();
addKeyListener(new KeyListener());
for (int i = 0; i < 12; i++) {
rocks.add(new Rock(WIDTH, HEIGHT));
}
animationTimer.start();
}
class KeyListener extends KeyAdapter {
#Override
public void keyPressed(KeyEvent e) {
keyCode = e.getKeyCode();
keyHeld = true;
}
#Override
public void keyReleased(KeyEvent e) {
keyHeld = false;
}
}
#Override
public void actionPerformed(ActionEvent e) {
checkRockCollisions();
for (int i = 0; i < bullets.size(); i++)
checkBulletOffScreen(bullets.get(i));
spaceShip.checkForCollisionWithFrame(WIDTH, HEIGHT);
moveObjects();
checkForPressedKeys();
repaint();
}
public void moveObjects() {
for (Rock rock : rocks)
rock.moveForward();
for (Bullet bullet : bullets)
bullet.moveForward();
spaceShip.moveSpaceShip();
}
public void checkRockCollisions() {
for (int i = 0; i < rocks.size(); i++) {
Rock rock = rocks.get(i);
rocks.stream().filter(rockToCheck -> !rock.equals(rockToCheck)).forEach(rock::checkRockCollision);
for (int j = 0; j < bullets.size(); j++) {
Bullet bullet = bullets.get(j);
if (rock.checkBulletCollision(bullet)) {
rocks.remove(rock);
bullets.remove(bullet);
}
}
if (rock.checkSpaceShipCollision(spaceShip))
resetSpaceShip();
rock.checkFrameCollision(WIDTH, HEIGHT);
}
}
public void checkBulletOffScreen(Bullet bullet) {
if (bullet.getxPos() + bullet.getBulletWidth() < 0 || bullet.getxPos() > WIDTH || bullet.getyPos() + bullet.getBulletHeight() < 0 || bullet.getyPos() > HEIGHT)
bullets.remove(bullet);
}
public void resetSpaceShip() {
spaceShip = new SpaceShip(WIDTH, HEIGHT);
}
public void checkForPressedKeys() {
if (keyHeld) {
switch (keyCode) {
case KeyEvent.VK_RIGHT:
spaceShip.increaseRotationDegree();
break;
case KeyEvent.VK_LEFT:
spaceShip.decreaseRotationDegree();
break;
case KeyEvent.VK_UP:
spaceShip.increaseForwardVelocity();
break;
case KeyEvent.VK_DOWN:
spaceShip.decreaseForwardVelocity();
break;
case KeyEvent.VK_SPACE:
bullets.add(new Bullet(spaceShip.getxPos() + spaceShip.getSpaceShipRadius(), spaceShip.getyPos() + spaceShip.getSpaceShipRadius(), spaceShip.getRotationDegree()));
keyHeld = false;
break;
}
}
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
RenderingHints mainRenderingHints = new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHints(mainRenderingHints);
for (Rock rock : rocks)
rock.display(g2d);
for (Bullet bullet : bullets)
bullet.display(g2d);
spaceShip.display(g2d);
g2d.dispose();
}
}
SpaceShip.java
import java.awt.*;
public class SpaceShip {
private double xPos;
private double yPos;
private double xVelocity;
private double yVelocity;
private int spaceShipDiameter;
private int rotationDegree;
private int spaceShipRadius;
public SpaceShip(final int WIDTH, final int HEIGHT) {
spaceShipDiameter = 30;
spaceShipRadius = spaceShipDiameter / 2;
xPos = WIDTH / 2 - spaceShipRadius;
yPos = HEIGHT / 2 - spaceShipRadius;
rotationDegree = 0;
}
public int getSpaceShipRadius() {
return spaceShipRadius;
}
public double getxPos() {
return xPos;
}
public double getyPos() {
return yPos;
}
public int getRotationDegree() {
return rotationDegree;
}
public void increaseForwardVelocity() {
xVelocity += 0.04 * Math.sin(Math.toRadians(this.rotationDegree));
yVelocity += 0.04 * -Math.cos(Math.toRadians(this.rotationDegree));
}
public void decreaseForwardVelocity() {
xVelocity -= 0.04 * Math.sin(Math.toRadians(this.rotationDegree));
yVelocity -= 0.04 * -Math.cos(Math.toRadians(this.rotationDegree));
}
public void moveSpaceShip() {
this.xPos += xVelocity;
this.yPos += yVelocity;
}
public void increaseRotationDegree() {
if (rotationDegree >= 350)
rotationDegree = 0;
else
rotationDegree+=10;
}
public void decreaseRotationDegree() {
if (rotationDegree <= 0)
rotationDegree = 350;
else
rotationDegree-=10;
}
public void checkForCollisionWithFrame(final int WIDTH, final int HEIGHT) {
if (xPos + spaceShipDiameter < 0)
xPos = WIDTH;
else if (xPos > WIDTH)
xPos = 0 - spaceShipDiameter;
else if (yPos + spaceShipDiameter < 0)
yPos = HEIGHT;
else if (yPos > HEIGHT)
yPos = 0 - spaceShipDiameter;
}
public void display(Graphics2D g2d) {
g2d.setColor(Color.BLACK);
g2d.rotate(Math.toRadians(rotationDegree), xPos + spaceShipRadius, yPos + spaceShipRadius);
g2d.fillOval((int) xPos, (int) yPos, spaceShipDiameter, spaceShipDiameter);
g2d.setColor(Color.YELLOW);
g2d.drawLine((int) xPos + spaceShipRadius, (int) yPos , (int) xPos + spaceShipRadius, (int) yPos + spaceShipRadius);
}
}
Rock.java
import java.awt.*;
import java.util.Random;
public class Rock {
private int xPos;
private int yPos;
private int rockDiameter;
private int xVelocity;
private int yVelocity;
private int rockRadius;
private Color rockColor;
public Rock(int WIDTH, int HEIGHT) {
Random r = new Random();
rockDiameter = r.nextInt(40) + 30;
rockRadius = rockDiameter / 2;
xPos = r.nextInt(WIDTH - rockDiameter);
yPos = r.nextInt(HEIGHT - rockDiameter);
xVelocity = r.nextInt(6) - 3;
yVelocity = r.nextInt(6) - 3;
rockColor = new Color(r.nextInt(255), r.nextInt(255), r.nextInt(255));
}
public void moveForward() {
xPos += xVelocity;
yPos += yVelocity;
}
public void checkRockCollision(Rock rock) {
if (calculateDistances(rock.xPos, rock.yPos, rock.rockRadius))
switchVelocities(rock);
}
public void switchVelocities(Rock rock) {
int tempXVelocity = this.xVelocity;
int tempYVelocity = this.yVelocity;
this.xVelocity = rock.xVelocity;
this.yVelocity = rock.yVelocity;
rock.xVelocity = tempXVelocity;
rock.yVelocity = tempYVelocity;
moveForward();
rock.moveForward();
}
public boolean checkBulletCollision(Bullet bullet) {
return calculateDistances(bullet.getxPos(), bullet.getyPos(), bullet.getBulletRadius());
}
public boolean checkSpaceShipCollision(SpaceShip spaceShip) {
return calculateDistances(spaceShip.getxPos(), spaceShip.getyPos(), spaceShip.getSpaceShipRadius());
}
public boolean calculateDistances(double objectxPos, double objectyPos, int objectRadius) {
int radiusOfBoth = objectRadius + rockRadius;
double horDistance = Math.abs((objectxPos + objectRadius) - (xPos + rockRadius));
double verDistance = Math.abs((objectyPos + objectRadius) - (yPos + rockRadius));
double diagDistance = Math.sqrt(Math.pow(horDistance, 2) + Math.pow(verDistance, 2));
return diagDistance <= radiusOfBoth;
}
public void checkFrameCollision(final int WIDTH, final int HEIGHT) {
if (xPos < 0) {
xVelocity *= -1;
xPos = 0;
} else if (xPos + rockDiameter > WIDTH) {
xVelocity *= -1;
xPos = WIDTH - rockDiameter;
} else if (yPos < 0) {
yVelocity *= -1;
yPos = 0;
} else if (yPos + rockDiameter > HEIGHT) {
yVelocity *= -1;
yPos = HEIGHT - rockDiameter;
}
}
public void display(Graphics2D g2d) {
g2d.setColor(rockColor);
g2d.fillOval(xPos, yPos, rockDiameter, rockDiameter);
}
}
Bullet.java
import java.awt.*;
public class Bullet {
private double xPos;
private double yPos;
private int bulletWidth;
private int bulletHeight;
private double xVelocity;
private double yVelocity;
private int bulletRadius;
public Bullet(double startingXPos, double startingYPos, int rotationDegree) {
bulletHeight = 10;
bulletWidth = 10;
bulletRadius = bulletWidth / 2;
xPos = startingXPos - bulletRadius;
yPos = startingYPos - bulletRadius;
xVelocity = 5 * Math.sin(Math.toRadians(rotationDegree));
yVelocity = 5 * -Math.cos(Math.toRadians(rotationDegree));
}
public void moveForward() {
this.xPos += xVelocity;
this.yPos += yVelocity;
}
public double getxPos() {
return xPos;
}
public double getyPos() {
return yPos;
}
public int getBulletWidth() {
return bulletWidth;
}
public int getBulletHeight() {
return bulletHeight;
}
public int getBulletRadius() {
return bulletRadius;
}
public void display(Graphics2D g2d) {
g2d.setColor(Color.GREEN);
g2d.fillOval((int) xPos, (int) yPos, bulletWidth, bulletHeight);
}
}
You're only keeping track of the most recent key pressed. Instead, you need to keep track of every key being pressed. One way to do that is by using a boolean variable for each key. In your keyPressed() function, set the appropriate boolean to true, and in the keyReleased() function, set it to false. Then in your game loop, just check which booleans are true and take the appropriate action.
I'm trying to fire a projectile in the mouse direction but i am having trouble.
The angles are wrong, and by that I mean it will only go up left or in the top-left corner.
This is my Gun class for which I fire the Bullet.
package assets;
import Reaper.Game;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
public class Gun
{
public ArrayList<Bullet> bullets;
protected double angle;
Mouse mouse = new Mouse();
private BufferedImage image;
private int centerX = Game.WIDTH / 2;
private int centerY = Game.HEIGHT;
public Gun()
{
bullets = new ArrayList<Bullet>();
image = null;
try
{
image = ImageIO.read(new File("assets/gun.png"));
}
catch (IOException e)
{
e.printStackTrace();
}
}
public BufferedImage loadImage()
{
return image;
}
public int getImageWidth()
{
return image.getWidth(null);
}
public int getImageHeight()
{
return image.getHeight(null);
}
public void rotate(Graphics g)
{
angle = Math.atan2(centerY - mouse.getMouseY(), centerX - mouse.getMouseX()) - Math.PI / 2;
((Graphics2D) g).rotate(angle, centerX, centerY);
g.drawImage(image, Game.WIDTH / 2 - image.getWidth() / 2,
900 - image.getHeight(), image.getWidth(), image.getHeight(),
null);
}
public Image getImage()
{
return image;
}
public void update()
{
shoot();
for (int i = 0; i < bullets.size(); i++)
{
Bullet b = bullets.get(i);
b.update();
}
}
public void shoot()
{
if (mouse.mouseB == 1)
{
double dx = mouse.getMouseX() - Game.WIDTH / 2;
double dy = mouse.getMouseY() - Game.HEIGHT / 2;
double dir = Math.atan2(dy, dx);
bullets.add(new Bullet(Game.WIDTH / 2, Game.HEIGHT / 2, dir));
mouse.mouseB = -1;
}
}
public void render(Graphics g)
{
for (int i = 0; i < bullets.size(); i++)
{
bullets.get(i).render(g);
}
rotate(g);
}
}
This is my Bullet class:
package assets;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
public class Bullet
{
private double dx, dy;
private int x, y;
private double dir;
private BufferedImage image;
public Bullet(int x, int y, double angle)
{
this.x = x;
this.y = y;
this.dir = angle;
image = null;
try
{
image = ImageIO.read(new File("assets/bolt.png"));
}
catch (IOException e)
{
e.printStackTrace();
}
dx = Math.cos(dir);
dy = Math.sin(dir);
}
public void update()
{
x += dx;
y += dy;
System.out.println("dx : " + dx + " " + dy);
}
public void render(Graphics g)
{
g.drawImage(image, x, y, image.getWidth(), image.getHeight(), null);
}
public BufferedImage getImage()
{
return image;
}
}
And this is the main Game class:
package Reaper;
import Reaper.graphics.Screen;
import assets.Gun;
import assets.Mouse;
import gameState.MenuState;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferStrategy;
public class Game extends Canvas implements Runnable
{
private static final long serialVersionUID = 1L;
public static int WIDTH = 900;
public static int HEIGHT = 900;
public static int scale = 3;
public int frames = 0;
public int updates = 0;
private boolean running = false;
private Thread thread;
private JFrame frame;
#SuppressWarnings("unused")
private Screen screen;
private Gun gun;
private MenuState mns;
private Mouse mouse;
public Game()
{
Dimension size = new Dimension(WIDTH, HEIGHT);
setPreferredSize(size);
screen = new Screen(WIDTH, HEIGHT);
frame = new JFrame();
gun = new Gun();
mns = new MenuState();
mouse = new Mouse();
addMouseListener(mouse);
addMouseMotionListener(mouse);
}
public static void main(String[] args)
{
Game game = new Game();
game.frame.setResizable(false);
game.frame.add(game);
game.frame.pack();
game.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
game.frame.setVisible(true);
game.frame.setLocationRelativeTo(null);
game.strat();
}
public void strat()
{
running = true;
thread = new Thread(this, "Reaper");
thread.start();
}
public void stop()
{
running = false;
try
{
thread.join();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
public void run()
{
long timer = System.currentTimeMillis();
long lastTime = System.nanoTime();
double ns = 1000000000.0 / 60;
double delta = 0;
while (running)
{
long now = System.nanoTime();
delta += (now - lastTime) / ns;
lastTime = now;
while (delta >= 1)
{
update();
updates++;
delta--;
}
render();
frames++;
if (System.currentTimeMillis() - timer > 1000)
{
timer = System.currentTimeMillis();
frame.setTitle("Reaper! " + " | " + updates + " ups , " + frames + " fps");
updates = 0;
frames = 0;
}
}
stop();
}
public void update()
{
if (mns.play)
{
gun.update();
}
}
public void render()
{
BufferStrategy bs = getBufferStrategy();
if (bs == null)
{
createBufferStrategy(3);
return;
}
Graphics g = bs.getDrawGraphics();
g.fillRect(0, 0, WIDTH, HEIGHT);
if (mns.menu)
{
mns.draw(g);
}
if (mns.play)
{
g.clearRect(0, 0, WIDTH, HEIGHT);
g.drawImage(mns.getImage(), 0, 0, mns.getImageWidth(), mns.getImageHeight(), this);
gun.render(g);
}
if (mns.rules)
{
g.clearRect(0, 0, WIDTH, HEIGHT);
}
bs.show();
}
}
I know it's very badly coded, and I will try to fix it as much as I can, but I am really stuck on this. Searched around the web, tried some of the solutions but it wont work. I guess I'm doing it wrong by putting methods in wrong places and calling them, I guess.
I know it's very badly coded, and I will try to fix it as much as I can, ...
Next time, consider first cleaning up the mess and then asking the question.
(Are the variables storing the values returned by getMouseX() and getMouseY() really static?)
However, the main reason for the actual problem are the x and y values in the Bullet class:
class Bullet
{
private double dx, dy;
private int x, y;
....
public void update()
{
x += dx;
y += dy;
System.out.println("dx : " + dx + " " + dy);
}
...
}
They are declared as int values. Imagine what happens in the update method, for example, when x=0 and dx = 0.75: It will compute 0+0.75 = 0.75, truncate this to be an int value, and the result will be 0.
Thus, the x and y values will never change, unless the dx and dy values are >= 1.0, respectively.
Just changing the type of x and y to double will solve this. You'll have to add casts in the render method accordingly:
g.drawImage(image, (int)x, (int)y, ...);
But you should really clean this up.
After making changes based on a previous post 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);
}
}
Basically, because that's where you're telling them to be created...
verticalBalls.add(new VerticalBall(getX(), getY(), canvasWidth, canvasHeight));
getX() and getY() are getting the component's location (which happens to be close enough to 0x0 for arguments sake)...
Instead, you should be using the MouseEvent information...
public void mousePressed(MouseEvent e) {
if (e.getClickCount() >= 2) {
doubleClick = true;
verticalBalls.add(new VerticalBall(e.getX(), e.getY(), canvasWidth, canvasHeight));
System.out.println("double click");
}
}
This will create an issue for your Timer...
Instead you may need to introduce a couple of variables to hold the position information...
final int x = e.getX();
final int y = e.getX();
if (e.getClickCount() >= 2) {
...
} 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(x, y, canvasWidth, canvasHeight));
/* the second click never happened */
System.out.println("single click");
}
}
});
timer.setRepeats(false);
timer.start();
}
You need to use the getX and getY from the MouseEvent, not from the JPanel.
As a sidenote, your use of a separate Thread to periodically update the gui is bad because you can't use separate threads to call swing methods. use a swing Timer instead.
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();
}