GameScreen shows Black Screen - java

I'm currently programming a game where you have to avoid asteroids. I had to deal with some messed up coordinates and I had to guess the coordinates for sprites. I now have arbitrary units that describe my world. Unfortunately, my game screen does not work fully. When I want to render my asteroids the game screen shows a black screen.
public class GameScreen extends Screen {
private OrthographicCamera cam;
private Spaceship spaceship;
private Asteroids asteroids;
private Background bg;
#Override
public void create() {
// TODO Auto-generated method stub
bg = new Background();
spaceship = new Spaceship();
asteroids = new Asteroids();
float aspectratio = 16/10;
cam = new OrthographicCamera(100, 100 * aspectratio);
cam.position.set(cam.viewportWidth / 2f, cam.viewportHeight / 2f, 0);
cam.update();
}
#Override
public void render(SpriteBatch batch) {
// TODO Auto-generated method stub
cam.update();
batch.setProjectionMatrix(cam.combined);
batch.begin();
bg.render(batch);
spaceship.render(batch);
batch.end();
}
The shown code above works just fine and shows me this:
When I add the render method for the asteroids in the GameScreen class the GameScreen is just black:
#Override
public void render(SpriteBatch batch) {
// TODO Auto-generated method stub
cam.update();
batch.setProjectionMatrix(cam.combined);
batch.begin();
bg.render(batch);
spaceship.render(batch);
batch.end();
}
Asteroid Class:
public class Asteroid {
private Vector2 p;
private Vector2 v;
private float mass;
private float radius;
public final float maxV = 200;
public final float minV = 50;
public final float rMin = 10;
public final float rMax = 30;
public final float minX = MyGdxGame.WIDTH;
public final float minY = MyGdxGame.HEIGHT;;
float alpha = MathUtils.random(0, 360);
public Asteroid(float maxX, float maxY, List<Asteroid> asteroids) {
do {
radius = MathUtils.random(rMin, rMax);
masse = radius * radius * radius;
float alpha = MathUtils.random(0, 360);
p = new Vector2(MathUtils.random(minX, maxX), MathUtils.random(minY,
maxY));
float vBetrag = MathUtils.random(minV, maxV);
v = new Vector2(vBetrag * MathUtils.cosDeg(alpha),
vBetrag * MathUtils.cosDeg(alpha));
} while (ueberlappMit(asteroids));
}
private boolean ueberlappMit(List<Asteroid> asteroids) {
for(Asteroid a: asteroids){
if(abstand(a) < radius + a.radius + 10){ //!
return true;
}
}
return false;
}
public void update(float deltaT, float xMin, float xMax, float yMin, float yMax) {
p.x += v.x * deltaT;
p.y += v.y * deltaT;
while(p.x > xMax)
{
p.x -= (xMax - xMin);
}
while(p.x < xMin)
{
p.x += (xMax - xMin);
}
while(p.y > yMax)
{
p.y -= (yMax - yMin);
}
while(p.y < yMin)
{
p.y += (yMax - yMin);
}
}
public float abstand(Asteroid a2) {
return p.dst(a2.p);
}
Asteroids Class:
public class Asteroids extends Entity {
private final int numberofAsteroids = 150;
private float xMin, xMax, yMin, yMax;
private List<Asteroid> asteroids = new ArrayList<Asteroid>();
private final int cyclicBoundaryConditionsMultiple = 2;
public Asteroids() {
xMin = MyGdxGame.WIDTH * (-cyclicBoundaryConditionsMultiple);
xMax = MyGdxGame.WIDTH * (cyclicBoundaryConditionsMultiple);
yMin = MyGdxGame.HEIGHT * (-cyclicBoundaryConditionsMultiple);
yMax = MyGdxGame.HEIGHT * (cyclicBoundaryConditionsMultiple);
for (int i = 0; i < anzahl; i++) {
Asteroid a = new Asteroid( xMax, yMax, asteroids);
asteroids.add(a);
}
}
#Override
public void update() {
for (Asteroid a : asteroids) {
a.update(Gdx.graphics.getDeltaTime(), xMin, xMax, yMin, yMax);
}
for (int i = 0; i < numberofAsteroids; i++) {
Asteroid a1 = asteroids.get(i);
for (int j = i + 1; j < anzahl; j++) {
Asteroid a2 = asteroids.get(j);
float abstand = a1.abstand(a2);
if (abstand < a1.getRadius() + a2.getRadius()) {
calculateCollision(a1, a2);
}
}
}
}
}
#Override
public void render(ShapeRenderer renderer) {
for (Asteroid a : asteroids) {
System.out.println("RENDER A");
renderer.setColor(0, 0, 0, 1);
renderer.circle(a.getP().x, a.getP().y, a.getRadius());
}
}

Thx alot for your help Guys, i solved the problem. The method private boolean ueberlappMit(List asteroids) checks if the asteroids overlap and if its the case the Asteroids shoud be created again. The Problem was that by selecting a too high radius the Game got stuck in the do while loop in the Asteroid class.

Related

Rectangle intersects not working while jumping

I am making a game with android. The player is a rectangle that has to jump over obstacles. When i jump i decrease the height and the y coordinates. When i run the game the rectangle is jumping but when i try to jump over an obstacle its still hitting it. So i think i forget to change a value but i have no idea what value. Sorry for my bad english and i am a beginner at coding.
This is my Player class:
package com.example.niek.speelveld;
import android.graphics.Canvas;
import android.graphics.Paint;
/**
* Created by Niek on 15-8-2017.
*/
public class Player extends GameObject {
private int score;
private boolean up;
private boolean playing;
private long startTime;
private int h = 0;
private boolean jump;
public Player(int x , int y){
super.x = x;
super.y = y;
width = 100;
height = GamePanel.HEIGHT;
score = 0;
startTime = System.nanoTime();
}
public void setUp(boolean b){up = b;}
public void update(){
long elapsed = (System.nanoTime()-startTime)/1000000;
if(elapsed>100){
score++;
startTime = System.nanoTime();
}
if(up && h == 0){
jump = true;
up = false;
}
if (jump) {
if (h < 120) {
h = h + 7;
height = height - 7;
y = y - 7;
} else {
jump = false;
}
} else {
if (h > 0) {
h = h - 7;
height = height + 7;
y = y + 7;
}
}
}
public void draw(Canvas canvas){
Paint myPaint = new Paint();
myPaint.setStyle(Paint.Style.STROKE);
myPaint.setStrokeWidth(7);
canvas.drawRect(x, y, width + x, height, myPaint );
myPaint.setStrokeWidth(1);
canvas.drawText("HIGHSCORE " + score, GamePanel.WIDTH - 100 , 0+myPaint.getTextSize(), myPaint);
}
public int getScore(){return score;}
public boolean getPlaying(){return playing;}
public void setPlaying(boolean b){playing = b;}
//public void resetScore(){score = 0;}
public boolean getJump() {
return jump;
}
}
And in my Gamepanel class i use these 2 methods. When i call the class obstacle.get(i).update(); its only updating the x value so its moving towards the player.
public void update(){
if(player.getPlaying()) {
bg.update();
player.update();
//Add obstacles with timer
long obstacleElapsed = (System.nanoTime()-obstacleStartTime)/1000000;
if(obstacleElapsed >(2000 - player.getScore()/4)){
obstacles.add(new Obstacle(BitmapFactory.decodeResource(getResources(), R.drawable.rsz_spike1), WIDTH + 10, HEIGHT - 51, 14, 51, player.getScore()));
//reset timer
obstacleStartTime = System.nanoTime();
}
}
//Loop through every obstacle and check collision
for(int i = 0; i<obstacles.size(); i++){
obstacles.get(i).update();
if (collision(obstacles.get(i), player)) {
obstacles.remove(i);
player.setPlaying(false);
Intent intent = new Intent(c, Result.class);
intent.putExtra("SCORE", player.getScore());
c.startActivity(intent);
break;
}
//Remove obstacles that are out of the screen
if (obstacles.get(i).getX() < -100) {
obstacles.remove(i);
break;
}
}
}
public boolean collision(GameObject o, GameObject p){
if(Rect.intersects(o.getRectangle(), p.getRectangle())){
return true;
}
return false;
}
#Override
public void draw(Canvas canvas){
//Get Width and Height from screen
final float scaleFactorX = (float)getWidth()/WIDTH;
final float scaleFactorY = (float)getHeight()/HEIGHT;
if(canvas!=null) {
final int savedState = canvas.save();
canvas.scale(scaleFactorX, scaleFactorY);
bg.draw(canvas);
player.draw(canvas);
//Draw obstacles
for(Obstacle o : obstacles ){
o.draw(canvas);
}
canvas.restoreToCount(savedState);
}
}
And finally the Player and the Obstacle class extends Gameobject where i have the getRectangle method.
public Rect getRectangle(){
return new Rect(x, y, x+width, y+height);
}

How to spawn collectibles at random positions in Java

I making a game in Android Studio with Java. I am having an issue where my collectible keeps re-spawning in the same position after the player has collected it. I would like for it to re-spawn at random positions on the screen. How can I do this?
The collectible is a fuel can.
Here is the fuel can collectible class
Fuel.java
public class Fuel extends GameObject {
public Fuel(Bitmap res, int w, int h, int numFrames) {
x = GamePanel.WIDTH + 5000;
y = GamePanel.HEIGHT / 2;
dy =(random.nextInt()*(GamePanel.HEIGHT - (maxBorderHeight* 2)+maxBorderHeight));
dx = +GamePanel.MOVESPEED;
height = h;
width = w;
Bitmap[] image = new Bitmap[numFrames];
spritesheet = res;
for (int i = 0; i < image.length; i++)
{
image[i] = Bitmap.createBitmap(spritesheet, 0, i*height, width, height);
}
animation.setFrames(image);
animation.setDelay(100-dx);
animation.update();
}
public void update()
{
if (x < 0) {
reset();
}
x += dx;
dx = dx- 1;
if (dx <= -15) {
dx = -15;
}
animation.update();
}
public void draw(Canvas canvas)
{
try {
canvas.drawBitmap(animation.getImage(),x,y,null);
}catch (Exception e){}
}
public void reset(){
x = GamePanel.WIDTH + 5000;
y = GamePanel.HEIGHT/2 ;
dy = (random.nextInt()*(GamePanel.HEIGHT - (maxBorderHeight* 2)+maxBorderHeight));
dx = +GamePanel.MOVESPEED;
}
public void fuelCollected(){
reset();
}
}
GamePanel.java
public class GamePanel extends SurfaceView implements SurfaceHolder.Callback
{
private Fuel fuel;
#Override
public void surfaceCreated(SurfaceHolder holder){
fuel = new Fuel(BitmapFactory.decodeResource(getResources(), R.drawable.fuel),40,40,1);
}
public void update()
{
fuel.update();
if(collectFuel(player,fuel)){
distance +=100;
}
public boolean collectFuel(GameObject player, GameObject fuel){
if(Rect.intersects(player.getRectangle(),fuel.getRectangle()))
{
fuelCollected();
return true;
}
return false;
}
public void fuelCollected(){fuel.fuelCollected();}
}
#Override
public void draw(Canvas canvas){
// draw fuel can
fuel.draw(canvas);
}
}
Change Fuel reset() method to something like this:
public void reset() {
x = random.nextInt(GamePanel.WIDTH);
y = random.nextInt(GamePanel.HEIGHT);
dy = (random.nextInt()*(GamePanel.HEIGHT - (maxBorderHeight* 2)+maxBorderHeight));
dx = +GamePanel.MOVESPEED;
}
Assuming that x, y are integer variables x will be a random integer between 0 and GamePanel.WIDTH and y a random integer between 0 and GamePanel.HEIGHT.
Why do you add 5000 to the GamePanel.WIDTH ?

Collision Game Errors and Timers

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.

Painted shape keeps vibrating after stopping

I tried to recreate some physics by creating a ball that bounces from the sides and that slows down. The ball stops moving in the x direction, but it keeps vibrating like only 1 pixel up and down in the y direction. Also it does this a little bit above the bottom border.
Also, is my code readable/good practise?
Bouncy.java
package Bouncy;
import javax.swing.*;
public class Bouncy {
private static void createAndShowGui() {
JFrame frame = new JFrame("Bouncy Balls");
Board board = new Board();
frame.getContentPane().add(board);
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.setLocation(2000, 50);
board.requestFocusInWindow();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
Board.java
package Bouncy;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Board extends JPanel implements ActionListener {
public static final int BOARDWIDTH = 800;
public static final int BOARDHEIGHT = 800;
private Ball ball;
public Board() {
Dimension preferedDimension = new Dimension(BOARDWIDTH, BOARDHEIGHT);
setPreferredSize(preferedDimension);
ball = new Ball(15, 0);
Timer animationTimer = new Timer(17, this);
animationTimer.start();
}
public void actionPerformed(ActionEvent e) {
ball.applyPhysics();
repaint();
}
public void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
RenderingHints rh = new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHints(rh);
ball.display(g2d);
g2d.dispose();
}
}
Ball.java
package Bouncy;
import java.awt.*;
public class Ball {
private int xPos;
private int yPos;
private double dx;
private double dy;
private int ballWidth;
private int ballHeight;
public Ball() {
this(0, 0);
}
public Ball(int dx, int dy) {
ballWidth = 50;
ballHeight = ballWidth;
xPos = 0;
yPos = 0;
this.dx = dx;
this.dy = dy;
}
public void applyPhysics() {
bounceX();
applyXFriction();
bounceY();
}
public void bounceX() {
if (xPos > Board.BOARDWIDTH - ballWidth) {
xPos = Board.BOARDWIDTH - ballWidth;
dx = -dx;
} else if (xPos < 0) {
xPos = 0;
dx = -dx;
} else {
xPos += dx;
}
}
public void applyXFriction() {
final double xFriction = .95;
if (yPos == Board.BOARDHEIGHT - ballHeight) {
dx *= xFriction;
if (Math.abs(dx) < .5) {
dx = 0;
}
}
}
public void bounceY() {
final int gravity = 12;
final double energyLoss = .75;
final double dt = .2;
if (yPos > Board.BOARDHEIGHT - ballHeight){
yPos = Board.BOARDHEIGHT - ballHeight;
dy = -dy * energyLoss;
} else if (yPos < 0) {
yPos = 0;
dy *= -energyLoss;
} else {
dy += gravity * dt;
yPos += dy * dt + .5 * gravity * dt * dt;
}
}
public void display(Graphics2D g2d) {
g2d.fillOval(xPos, yPos, ballWidth, ballHeight);
}
}
Inside your apply friction method, where you set dx to 0, also set dy to 0. This will stop the ball moving along both the X and Y axis
if (Math.abs(dx) < .5)
{
dx = 0;
dy = 0;
}
This will stop the ball vibrating:
if (Math.abs(dy * dt + .5 * gravity * dt * dt) < 1.5 && yPos == Board.BOARDHEIGHT - ballHeight)
{
dy = 0;
yPos = Board.BOARDHEIGHT - ballHeight;
}

How to detect a collision?

I'm having a two image(a cat and a dog) inside the world which is in my Board class. The cat moves in a random direction while the dog move only when I press the arrow keys. My problem now is that how can I make the cat disappear whenever there is a collision between the two images? Any answer or idea would be much appreciated.
Here's what I've tried...
public class Cat extends Sprite implements ImageObserver
{
private java.awt.Image catImage;
private final Board board;
private double x;
private double y;
private double speed;
private double angle;
private boolean visible;
public Cat(Board board, double x, double y, double speed)
{
this.board = board;
this.x = x;
this.y = y;
this.speed = convertToMeterPerSecond(speed);
visible = true;
URL iU = this.getClass().getResource("cat.gif");
ImageIcon icon = new ImageIcon(iU);
catImage = icon.getImage();
}
public Image getImage()
{
return catImage;
}
public void move(long dt)
{
double dt_s = dt / 1e9;
double dx_m = speed * dt_s * Math.sin(angle);
double dy_m = speed * dt_s * Math.cos(angle);
final double right_wall = board.x1_world;
final double up_wall = board.y1_world;
final double down_wall = 0.0;
final double left_wall = 0.0;
x += dx_m;
y += dy_m;
if (x >= right_wall)
{
x = right_wall;
setRandomDirection();
}
if (y > up_wall)
{
y = up_wall;
setRandomDirection();
}
if (x <= left_wall)
{
x = left_wall;
setRandomDirection();
}
if (y < down_wall)
{
y = down_wall;
setRandomDirection();
}
}
public void setRandomDirection()
{
Cat myObject = this;
myObject.setAngle(Math.PI * 2 * Math.random());
}
#Override
public void render(Graphics2D g2d)
{
AffineTransform t = g2d.getTransform();
double height = 0.3; //meter
double width = 0.3; //meter
double cat_footy = height;
double cat_footx = width / 2;
int xx = board.convertToPixelX(x - cat_footx);
int yy = board.convertToPixelY(y + cat_footy);
g2d.translate(xx, yy);
double x_expected_pixels = width * board.meter;
double y_expected_pixels = height * board.meter;
double x_s = x_expected_pixels / ((ToolkitImage) catImage).getWidth();
double y_s = y_expected_pixels / ((ToolkitImage) catImage).getHeight();
double w = ((ToolkitImage) catImage).getWidth();
double h = ((ToolkitImage) catImage).getHeight();
g2d.scale(x_s, y_s);
g2d.drawImage(getImage(), 0, 0, this); // upper left corner
g2d.setColor(Color.BLACK);
g2d.drawRect(0, 0, (int) w, (int) h);
g2d.setTransform(t);
}
public void moveAt(double distance_x, double distance_y)
{
this.x = (int) distance_x;
this.y = (int) distance_y;
}
#Override
public Rectangle getBounds()
{
double w = ((ToolkitImage) catImage).getWidth();
double h = ((ToolkitImage) catImage).getHeight();
return new Rectangle((int) x, (int) y, (int) w, (int) h);
}
public void setAngle(double angle)
{
this.angle = angle;
}
public boolean isVisible()
{
return visible;
}
public void setVisible(Boolean visible)
{
this.visible = visible;
}
#Override
public boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height)
{
return true;
}
}
for my Cat class
public class Dog extends Sprite implements ImageObserver
{
private java.awt.Image humanImage;
private final Board board;
private double x;
private double y;
private double speed;
private boolean visible;
private double angle;
private double dx_m;
private double dy_m;
public Dog(Board board, double x, double y, double speed)
{
this.board = board;
this.x = x;
this.y = y;
this.speed = convertToMeterPerSecond(speed);
visible = true;
URL iU = this.getClass().getResource("dog.jpg");
ImageIcon icon = new ImageIcon(iU);
dogImage = icon.getImage();
}
public Image getImage()
{
return dogImage;
}
public void keyPressed(KeyEvent e)
{
int key = e.getKeyCode();
if (key == KeyEvent.VK_LEFT)
{
dx_m = -0.3;
}
if (key == KeyEvent.VK_RIGHT)
{
dx_m = 0.3;
}
if (key == KeyEvent.VK_UP)
{
dy_m = 0.3;
}
if (key == KeyEvent.VK_DOWN)
{
dy_m = -0.3;
}
}
public void keyReleased(KeyEvent e)
{
int key = e.getKeyCode();
if (key == KeyEvent.VK_LEFT)
{
dx_m = 0;
}
if (key == KeyEvent.VK_RIGHT)
{
dx_m = 0;
}
if (key == KeyEvent.VK_UP)
{
dy_m = 0;
}
if (key == KeyEvent.VK_DOWN)
{
dy_m = 0;
}
}
#Override
public void move(long dt)
{
double dt_s = dt / 1e9;
final double right_wall = board.x1_world;
final double up_wall = board.y1_world;
final double down_wall = 0.0;
final double left_wall = 0.0;
x += dx_m;
y += dy_m;
if (x <= left_wall)
{
x = left_wall;
}
if (x >= right_wall)
{
x = right_wall;
}
if (y <= down_wall)
{
y = down_wall;
}
if (y >= up_wall)
{
y=up_wall;
}
}
public void setRandomDirection()
{
Dog myObject = this;
myObject.setAngle(Math.PI * 2 * Math.random());
}
#Override
public void render(Graphics2D g2d)
{
AffineTransform t = g2d.getTransform();
final double dogHeight = 1.6;// meter
final double dogWidth = 1.8; //meter
final double foot_position_y = dogHeight;
final double foot_position_x = dogWidth / 2;
int xx = board.convertToPixelX(x - foot_position_x); // to find the upper-left corner
int yy = board.convertToPixelY(y + foot_position_y); // to find the upper-left corner
g2d.translate(xx, yy);
// ratio for actual Image size
double x_expected_pixels = dogHeight * board.meter;
double y_expected_pixels = dogWidth * board.meter;
double w = ((ToolkitImage) dogImage).getWidth();
double h = ((ToolkitImage) dogImage).getHeight();
double x_s = x_expected_pixels / w;
double y_s = y_expected_pixels / h;
g2d.scale(x_s, y_s);
g2d.drawImage(getImage(), 0, 0, this); // upper left corner
g2d.setColor(Color.BLACK);
g2d.drawRect(0, 0, (int) w, (int) h);
g2d.setTransform(t);
}
#Override
public void moveAt(double distance_x, double distance_y)
{
this.x = distance_x;
this.y = distance_y;
}
public void setAngle(double angle)
{
this.angle = angle;
}
#Override
public Rectangle getBounds()
{
double width = ((ToolkitImage) dogImage).getWidth();
double height = ((ToolkitImage) dogImage).getHeight();
return new Rectangle((int) x, (int) y, (int) width, (int) height);
}
public boolean isVisible()
{
return visible;
}
public void setVisible(Boolean visible)
{
this.visible = visible;
}
#Override
public boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height)
{
return true;
}
}
for my Dog class
public class Board extends Canvas
{
private Cat cat;
public static final long SECOND = 1000 * 1000 * 1000;
public double meter;//PIXEL
private HumanBeing humanBeing;
/**
* ascending from 0 to N
* 0 : most far way...
* N : is the closest (painted the last)
*/
private final java.util.List<Sprite> z_sorted_sprites = new ArrayList<Sprite>();
private BufferStrategy strategy;
int x0_pixel;
int y0_pixel;
int x1_pixel;
int y1_pixel;
double x1_world;
double y1_world;
private final Frame frame;
public Board(Frame frame, double meter)
{
addKeyListener(new TAdapter());
this.frame = frame;
this.setIgnoreRepaint(true);
this.meter = meter;
setFocusable(true);
dog = new Dog(this, 5, 5, 40);
init();
addComponentListener(new ComponentAdapter()
{
#Override
public void componentResized(ComponentEvent e)
{
render();
}
});
}
public void init()
{
z_sorted_sprites.add(new Cat(this, 0, 0, 30));
z_sorted_sprites.add(new Cat(this, 1, 1, 10));
z_sorted_sprites.add(new Cat(this, 2, 2, 20));
z_sorted_sprites.add(new Cat(this, 3, 3, 100));
}
public void render()
{
setupStrategy();
x0_pixel = 0;
y0_pixel = 0;
x1_pixel = getWidth();
y1_pixel = getHeight();
x1_world = x1_pixel / meter;
y1_world = y1_pixel / meter;
Graphics2D g2d = (Graphics2D) strategy.getDrawGraphics();
g2d.setBackground(Color.lightGray);
g2d.clearRect(0, 0, x1_pixel, y1_pixel);
g2d.setColor(Color.BLACK);
for (double x = 0; x < x1_world; x++)
{
for (double y = 0; y < y1_world; y++)
{
int xx = convertToPixelX(x);
int yy = convertToPixelY(y);
g2d.drawOval(xx, yy, 2, 2);
}
}
for (Sprite z_sorted_sprite : z_sorted_sprites)
{
z_sorted_sprite.render(g2d);
}
dog.render(g2d);
g2d.dispose();
strategy.show();
Toolkit.getDefaultToolkit().sync();
}
public int convertToPixelX(double distance)
{
return (int) (distance * meter);
}
public int convertToPixelY(double y_world)
{
return (int) (y1_pixel - (y_world * meter));
}
public void onZoomUpdated(int value)
{
meter = value;
render();
}
private void setupStrategy()
{
if (strategy == null)
{
this.createBufferStrategy(2);
strategy = this.getBufferStrategy();
}
}
public void start() throws InterruptedException
{
long prevLoopStart = System.nanoTime();
Avg avg = new Avg();
while (true)
{
final long loopStart = System.nanoTime();
final long dt = loopStart - prevLoopStart;
for (Sprite sprite : z_sorted_sprites)
{
sprite.move(dt);
}
dog.move(dt);
render();
frame.onFpsUpdated(1.0 / dt * SECOND, avg.add(loopStart));
final long elapsed_ns = System.nanoTime() - loopStart;
long expected_elapsed_ms = 1000 / 60;
long elapsed_ms = (long) (elapsed_ns / (1000.0 * 1000.0));
long sleep_ms = expected_elapsed_ms - elapsed_ms;
if (sleep_ms > 0)
{
Thread.sleep(sleep_ms /* ms */);
}
prevLoopStart = loopStart;
}
}
private void checkCollision()
{
Rectangle r2 = cat.getBounds();
Rectangle r3 = dog.getBounds();
if (r3.intersects(r2))
{
dog.setVisible(false);
cat.setVisible(false);
}
}
static class Avg
{
java.util.List<Long> ticks = new ArrayList<Long>();
/**
* #return the rate for the last second
*/
int add(long tick)
{
ticks.add(0, tick);
if (ticks.size() < 2)
{
return -1;
}
int last = -1;
for (int pos = ticks.size() - 1; pos >= 0; pos--)
{
if (tick - ticks.get(pos) <= SECOND)
{
last = pos;
break;
}
}
while (ticks.size() - 1 > last)
{
ticks.remove(ticks.size() - 1);
}
return ticks.size();
}
}
private class TAdapter extends KeyAdapter
{
public void keyReleased(KeyEvent e)
{
dog.keyReleased(e);
}
public void keyPressed(KeyEvent e)
{
dog.keyPressed(e);
}
}
}
For my Board class
public abstract class Sprite
{
public Sprite()
{
}
public Rectangle getBounds()
{
return new Rectangle();
}
public static double convertToMeterPerSecond(double speed)
{
// 25 km / hour
// 25000 m / 3600 s
return speed / 3.6;
}
public abstract void move(long dt);
public abstract void moveAt(double distance_x, double distance_y);
public abstract void render(Graphics2D g2d);
public abstract void setVisible(Boolean visible);
}
For my sprite class
public boolean checkCollisions(java.util.List<Sprite> sprites)
{
Dog dog = this;
Rectangle r1 = dog.getBounds();
for (int i = 0; i < sprites.size(); i++)
{
Rectangle r2 = sprites.get(i).getBounds();
if (r1.intersects(r2))
{
sprites.remove(i);
}
}
return true;
}
You have given a lot of code, but as Sibbo said, I don't see your checkCollisions method being called anywhere. It should be called every loop of your game.
Check out this tutorial, specifically look at the gameLoop method in the Game class. When I made a sprite based game that required a lot of collision detection this tutorial helped me out a lot.
I'd implement method that detects that positions of cat and dog overlap in the board class since board is the only instance that "knows" both dog and cat. The implementation is pretty simple: compare coordinates (something like dog.x + dog.width < cat.x || dog.x > cat.x + cat.width etc, etc.
If future you can implement more generic method, so if you will wish to add mouse you will be able to reuse the code.
The dog class doesn't overwrite the getBounds() method. So everytime you check if the rectangle (0, 0, 0, 0) intersects for example (3, 4, 50, 50) (if the cat is at (3, 4)).
Where do you call the checkCollision() method?
EDIT:
Create a method like your checkCollision() in your Dog class:
public boolean checkCollision(Sprite s) {...}
It should return true, when a collision is detected. Call this method from the Board.start() method for every Sprite in z_sorted_sprites. IF it returns true, remove the Sprite from the list.

Categories