Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
I have been working on a Breakout game and have just about everything done except for the brick collision. The ball bounces of the wall and paddle fine, but when it comes to the brick it goes straight through them. I'm pretty sure the problem is in the checkBrick() part of the main class, but have no idea what to do about it.
Main Class:
import java.awt.*;
import java.awt.event.KeyEvent;
import java.applet.*;
import java.util.Random;
import javax.swing.JOptionPane;
public class Breakout extends Applet implements Runnable {
Ball ball = new Ball();
Paddle paddle = new Paddle(135, 375);
Brick[] brick = new Brick[50];
private int bX[] = new int[50];
private int bY[] = new int[50];
private int bW[] = new int[50];
private int bH[] = new int[50];
Thread t;
Random trajectory = new Random();
boolean lose;
Image buffer = null;
// The life cycle of the Applet
// Sets up window
public void init() {
setSize(377, 500);
buffer = createImage(377, 500);
// setBackground(Color.black);
System.out.println("init()");
}
public void start() {
if (t == null) {
t = new Thread(this);
t.start();
}
System.out.println("start()");
}
public void run() {
System.out.println("run()");
Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
while (!lose) {
ball.move();
paddle.move();
checkWall();
checkPaddle();
checkBrick();
ball.move();
repaint();
try {
Thread.sleep(30);
} catch (InterruptedException ex) {
}
Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
}
JOptionPane.showMessageDialog(null, "Game Over");
System.out.println("Termintated");
System.exit(0);
}
public void stop() {
System.out.println("stop()");
}
public void destroy() {
System.out.println("destroy()");
}
public void paint(Graphics g) {
Graphics screen = null;
screen = g;
g = buffer.getGraphics();
g.setColor(Color.black);
g.fillRect(0, 0, 377, 500);
createBricks(g);
createPaddle(g);
createBall(g);
screen.drawImage(buffer, 0, 0, this);
}
public void update(Graphics g) {
paint(g);
}
private void createBricks(Graphics g) {
int brickIndex = 0;
int brickX = 15, brickY = 160;
int brickW = 30, brickH = 10;
for (int i = 0; i <= 4; i++) {
brickX = 15;
brickY -= 20;
for (int n = 0; n < 10; n++) {
brick[brickIndex] = new Brick();
brick[brickIndex].setBounds(brickX, brickY, brickW, brickH);
bX[brickIndex] = brick[brickIndex].x();
bY[brickIndex] = brick[brickIndex].y();
bW[brickIndex] = brick[brickIndex].w();
bH[brickIndex] = brick[brickIndex].h();
brick[brickIndex].setColor(i);
brick[brickIndex].paint(g);
brickIndex++;
brickX += 35;
}
}
}
private void createPaddle(Graphics g) {
paddle.paint(g);
}
private void createBall(Graphics g) {
ball.paint(g);
}
private void checkWall() {
// If ball hits right wall it will bounce
if ((ball.getX() + ball.getR()) >= 380) {
ball.setVX(trajectory.nextInt(2) + -3);
}
// If ball hits left wall it will bounce
if ((ball.getX() - ball.getR()) < -10) {
ball.setVX(trajectory.nextInt(4) + 1);
}
// If ball hits ceiling it will bounce
if ((ball.getY() + ball.getR()) < 12)
ball.setVY(trajectory.nextInt(5) + 1);
// If ball goes through floor it will subtract a life
if ((ball.getY() + ball.getR()) > 515)
lose = true;
}
private void checkBrick() {
for (int i = 0; i < 50; i++) {
int tempX, tempY, tempW, tempH;
tempX = bX[i];
tempY = bY[i];
tempW = bW[i];
tempH = bH[i];
if ((ball.getX() + ball.getR()) < (tempX + tempW)
&& (ball.getX() + ball.getR()) >= tempX) {
if ((ball.getY() + ball.getR()) > (tempY + tempH)
&& (ball.getY() + ball.getR()) <= tempY) {
System.out.println("Brick " + i + " has been hit.");
}
}
}
}
private void checkPaddle() {
// Check for paddle
if ((ball.getX() + ball.getR()) < (paddle.getX() + 100)
&& (ball.getX() + ball.getR()) >= paddle.getX() + 5) {
if ((ball.getY() + ball.getR()) > (paddle.getY() - 5)
&& (ball.getY() + ball.getR()) <= (paddle.getY() + 5)) {
ball.setVX((trajectory.nextInt(7) + -2) + 1);
ball.setVY(trajectory.nextInt(1) + -3);
}
}
}
// Key Detectors
public boolean keyDown(Event e, int key) {
if (key == Event.RIGHT) {
paddle.setVX(0);
if ((paddle.getX() + 100) < 377)
paddle.setVX(10);
}
if (key == Event.LEFT) {
paddle.setVX(0);
if (paddle.getX() > 0)
paddle.setVX(-10);
}
return true;
}
// To make sure it doesn't just keep moving one way
public boolean keyUp(Event e, int key) {
paddle.setVX(0);
return true;
}
}
Ball Class:
import java.awt.Color;
import java.awt.Graphics;
import java.util.Random;
public class Ball
{
private int x, y; //Position
private int vx, vy; //Velocity
private int r; //radius
//constructor
public Ball()
{
x = 177;
y = 315;
vx = 0;
vy = 5;
r = 15;
}
public void paint(Graphics g)
{
g.setColor(Color.white);
g.fillOval(x, y, r, r);
}
//returns the x of origin
public int getX()
{
return x;
}
//returns the y of origin
public int getY()
{
return y;
}
public int getVX()
{
return vx;
}
//returns the y of origin
public int getVY()
{
return vy;
}
//returns the radius r of the ball
public int getR()
{
return r;
}
//sets the velocity of x to a different value
public void setVX(int vx)
{
this.vx = vx;
}
//sets the velocity of y to a different value
public void setVY(int vy)
{
this.vy = vy;
}
//sets the x value
public void setX(int x)
{
this.x = x;
}
//sets the y value
public void setY(int y)
{
this.y = y;
}
//starts making the ball move by changing its coords
public void move()
{
x+= vx;
y+= vy;
}
}
Paddle Class:
import java.awt.Color;
import java.awt.Graphics;
public class Paddle {
// declares variables for x and y coordinates
int x, y;
//The velocity of to move paddle
int vx;
// constructor that takes in x and y coordinates for paddle
public Paddle(int x, int y)
{
this.x = x;
this.y = y;
}
public void paint(Graphics g)
{
// paints paddle
g.setColor(Color.WHITE);
g.fillRect(x, y, 100, 15);
g.setColor(Color.GREEN);
g.drawRect(x, y, 100, 15);
}
// gets x coordinate of paddle
public int getX() {
return x;
}
// sets x coordinate of paddle
public void setX(int x) {
this.x = x;
}
// gets y coordinate of paddle
public int getY() {
return y;
}
// sets y coordinate of paddle
public void setY(int y) {
this.y = y;
}
public void setVX(int vx)
{
this.vx = vx;
}
//Moves the paddle
public void move()
{
x+=vx;
}
}
Brick Class:
import java.awt.Color;
import java.awt.Graphics;
public class Brick
{
private Color color =(Color.cyan);
private int x, y, w, h;
public Brick()
{
//Garbage values that are there just for declaration
x = 0;
y = 0;
w = 10;
h = 10;
}
//Sets color for the brick
public void setColor(int paintC)
{
switch(paintC)
{
case 0:
color = (Color.magenta);
break;
case 1:
color = (Color.blue);
break;
case 2:
color = (Color.yellow);
break;
case 3:
color = (Color.orange);
break;
default:
color = (Color.red);
break;
}
}
//Sets the location then size of the brick
public void setBounds(int x, int y, int w, int h)
{
this.x = x;
this.y = y;
this.w = w;
this.h = h;
}
//returns x value
public int x()
{
return this.x;
}
//returns y value
public int y()
{
return this.y;
}
//returns width value
public int w()
{
return this.w;
}
//returns height value
public int h()
{
return this.h;
}
//Sets x for the brick
public void setX(int x)
{
this.x = x;
}
//Sets y for the brick
public void setY(int y)
{
this.y = y;
}
public void setW(int w)
{
this.w = w;
}
public void setH(int h)
{
this.h = h;
}
public void paint(Graphics g)
{
g.setColor(color);
g.fillRect(x, y, w, h);
g.setColor(Color.green);
g.drawRect(x, y, w, h);
}
}
I've begin running over your code, quite frankly can't be bothered trying to figure out your logic, but what I believe you're trying to deduce is if the brick "contains" the ball, rather then if the ball intersects with the brick.
You don't care how much of the ball or brick are intersecting, only if the they do...for example...
private void checkBrick() {
int tx = ball.getX();
int ty = ball.getY();
int tw = ball.getR();
int th = ball.getR();
tw += tx;
th += ty;
for (int i = 0; i < 50; i++) {
int tempX, tempY, tempW, tempH;
tempX = bX[i];
tempY = bY[i];
tempW = bW[i];
tempH = bH[i];
int rw = tempW + tempX;
int rh = tempH + tempY;
// overflow || intersect
if ((rw < tempX || rw > tx) &&
(rh < tempY || rh > ty) &&
(tw < tx || tw > tempX) &&
(th < ty || th > tempY)) {
System.out.println("Hit");
}
}
}
Now, I stole this from Rectangle#intersects
Basically, if you used the geometry class from the 2D Graphics API, you could reduce this down to...
private void checkBrick() {
Rectangle b = new Rectangle(ball.getX(), ball.getY(), ball.getR(), ball.getR());
for (int i = 0; i < 50; i++) {
int tempX, tempY, tempW, tempH;
tempX = bX[i];
tempY = bY[i];
tempW = bW[i];
tempH = bH[i];
Rectangle brick = new Rectangle(tempX, tempY, tempW, tempH);
System.out.println("brick = " + brick);
if (b.intersects(brick)) {
System.out.println("Break");
}
}
}
And, yes, I did actually run your code
The problem is that the method checkBrick() is not changing anything, it is just printing if the ball has a collision with the brick.
You may want to change the Ball velocity, as you did within checkWall() and checkPaddle().
private void checkBrick() {
for (int i = 0; i < 50; i++) {
...
if (...) {
ball.setVX(...); // Add these lines setting the correct values
ball.setVY(...);
}
}
}
You may also want to check if your if-conditions are correct, and do what you expected.
Assuming tempH is positive,
((ball.getY() + ball.getR()) > (tempY + tempH)
&& (ball.getY() + ball.getR()) <= tempY)
can't ever be true. The > needs to be < and the <= needs to be >=.
Additionally, you'll need to take some kind of action if the brick is hit, rather than just printing out the fact. Sorry, I'm not sure what's supposed to happen - does the brick disappear? Or the ball bounce? Or both?
Second answer (in addition to other answer which I believe is ALSO a problem), your logic is asking if the ball is contained within a brick, but when you create the ball its radius is greater than the height of a brick, so even correcting that logic won't fix the problem.
You should refactor your code to make it read out like natural language, this would help a lot with debugging (or writing less bugs in the first place!) i.e.
in brick class:
public int bottom()
{
return y;
}
public int top()
{
return y + h;
}
in ball class:
public int bottom()
{
return y - r;
}
public int top() {
return y + r;
}
then in main class:
private boolean withinY(brick) {
return (ball.bottom => brick.bottom() && ball.top =< brick.top());
}
then the logic reads nicer (psuedo):
foreach brick in wall {
if (ball.withinY(brick) and ball.withinX(brick))
BAM!!
}
You're checking if the ball is between the left and right side of the brick, but then checking if the ball is both above AND below the brick, because you've got your greater than and less than's mixed up. Also the center of the ball needs to be subtracted from it's Y position.
if ((ball.getY() + ball.getR()) **>** (tempY + tempH) &&
(ball.getY() **+** ball.getR()) **<=** tempY)
could be
if ((ball.getY() + ball.getR()) < (tempY + tempH) &&
(ball.getY() - ball.getR()) >= tempY)
but I'd suggest finding if the top of the ball is between the top and bottom of the brick, OR if the bottom of the ball is between the top and bottom of the brick:
if (((ball.getY() + ball.getR()) < (tempY + tempH) && (ball.getY() - ball.getR()) >= tempY)) ||
((ball.getY() - ball.getR()) < (tempY + tempH) && (ball.getY() - ball.getR()) >= tempY))) {
CODE
}
And use similar logic for finding between left and right sides of the brick
Related
Currently, I'm making a 2d java game that includes a tank at the top of the screen shooting the oncoming cars from below, I have made a crash method and collision detection which determines to stop the game when the tank crashes or enters the radius of the cars. However, sometimes it works early, sometimes late and other times it doesn't. My question is how can I fix it so that when the tank enters the radius of the car it stops the game with simple code that excludes vectors.
Below are my classes and code.
I'm using Java in Processing.
PImage bg; //loads bakground
PFont f; //loads font
Car[] cars = new Car[3];
//Bullet[] bullets = new Bullet[100];
int x = 0;
int y = 0;
int game = 0;
int running = 0;
int over = 1;
int score = 0;
int move = 20;
int cX, cY;
//int carRadius = 20;
Tank tank;
void setup()
{
size(500,1000);
textSize(40);
bg = loadImage("bg.jpeg"); //loads background
bg.resize(width,height); //the background will fill the height and width of the screen size
tank = new Tank(tankX, tankY, 3, 2); //X pos, Y pos, speedY
for (int i=0; i<cars.length; i++)
{
int cX = (int)random(width-100); //car xpos
int cY = (int)random(900); //car ypos
int speedY = 3; //car speedY
cars[i] = new Car(cX, cY, speedY);
}
cars[0] = new Car((int)random(5, width-100), (int)random(5, height), 2); //X pos, Y pos, speedY
cars[1] = new Car((int)random(5, width-100), (int)random(5, height), 2); //X pos, Y pos, speedY
cars[2] = new Car((int)random(5, width-100), (int)random(5, height), 2); //X pos, Y pos, speedY
f = createFont("Arial", 36, true);
}
void draw()
{
if (game == running)
{
drawBackground(); //background
for (Car c : cars) {
c.draw();
c.move();
}
tank.draw(); //tank
drawScore(); //draw score
//if (bullet.crash(cars[0]) == true) {
// cars.remove(c);
// score++;
//}
if (game == over)
{
tank.speedX = 0;
tank.speedY = 0;
move = 0;
gameOver();
}
//if tank crashes into cars
if(tank.crash(cars[0]))
{
game = over;
gameOver();
}
if(tank.crash(cars[1]))
{
game = over;
gameOver();
}
if(tank.crash(cars[2]))
{
game = over;
gameOver();
}
/*
if(bullet.shoot(cars[0]))
{
cars[0].remove(c);
score++;
}
if(bullet.shoot(cars[1]))
{
cars[1].remove(c);
score++;
}
if(bullet.shoot(cars[2]))
{
cars[2].remove(c);
score++;
}
*/
}
}
void keyReleased() {
tankXD = 0;
tankYD = 0;
}
void keyPressed() //controls for the tank using the arrow keys
{
if(keyCode == LEFT) {
tankXD =- 10;
}
if(keyCode == RIGHT) {
tankXD = 10;
}
if(keyCode == DOWN) {
tankYD = 10;
}
if(keyCode == UP) {
tankYD =- 10;
}
if(keyCode == ' ') {
bulletSPD = 30;
//bullets.add(new Bullet(tank.x+30, tank.y+140, 3));
}
}
//void carFill()
// {
// fill(255,0,0);
// }
void drawBackground()
{
image(bg, y, 0);
}
void drawScore() {
fill(255);
textFont(f);
text("Score: " + String.valueOf(score), 200, 50);
}
void gameOver() {
clear();
textFont(f);
text("Game Over! ", 150, 400);
}
class Car
{
//members
int cX, cY;
int speedY = 2;
int speedX = 0;
int animationCounter = 0;
int carRadius = 30;
PImage image1,image2,image3;
//constructor
Car(int cX, int cY, int speedY)
{
this.cX = cX;
this.cY = cY;
this.speedY = speedY;
image1 = loadImage("c1.png");
image2 = loadImage("c2.png");
image3 = loadImage("c3.png");
}
void update() {
draw();
move();
}
void move()
{
this.cY = this.cY - speedY; //move upwards
if(this.cY < 0 - image1.height)
this.cY = height + image1.height;
if(this.cY > height + image1.height +30)
this.cY = -image1.height;
}
void draw()
{
if (animationCounter >=0 & animationCounter <=8)
{ image(image1,this.cX,this.cY); }
else if (animationCounter >8 & animationCounter <=16)
{ image(image2,this.cX,this.cY); }
else
{ image(image3,this.cX,this.cY); }
animationCounter = animationCounter + 1;
if(animationCounter>20)
animationCounter = 0;
}
}
int tankX = 215; //tank xpos
int tankY = 60; //tank ypos
int tankXD = 0; //tank x dir
int tankYD = 0; //tank y dir
int bulletX = tankX; //bullet xpos
int bulletY = tankY; //bullet ypos
int bulletW = 8; //bullet xpos
int bulletH = 20; //bullet ypos
int bulletSPD = 0; //bullet speed
int bulletRadius = 4;
float bulletDistance = 5;
PImage image1;
class Tank
{
//members
int tankX;
int tankY;
int speedX;
int speedY;
//constructor
Tank (int tankX, int tankY, int speedX, int speedY)
{
this.tankX = tankX;
this.tankY = tankY;
this.speedX = speedX;
this.speedY = speedY;
image1 = loadImage("tank.png");
}
void draw() {
image(image1,tankX, tankY);
tankX+=tankXD;
tankY+=tankYD;
bulletX=tankX;
bulletY+=bulletSPD;
if(bulletY>800) {
bulletX=tankX;
bulletY=tankY;
bulletSPD=0;
}
//draw bullet
fill(255,0,0);
stroke(255,0,0);
rect(bulletX+30, bulletY+140, bulletW, bulletH);
}
//tank crash method
boolean crash(Car other)
{
return (abs(this.tankY-other.cY) <20) && abs(this.tankX-other.cX) <10;
}
/*
boolean shoot (Bullet b, Car c) {
float d = dist(bulletX, bulletY, cX, cY);
if ((d < 5) == true) {
// we have a collision
return true;
} else {
return false;
}
}
*/
/*
boolean shoot(Car c) {
float d = dist(bulletX, bulletY, cX, cY);
if (d < 5) {
// we have a collision
return true;
} else {
return false;
}
}
*/
}
So I believe you want to fix the collision. If you have two circles and you want to see if they collide, you need to see if the radii collide. You can do this by seeing if the distance between the centers is greater than or less than the total of the two radii. Like this:
//returns whether or not two circles collide
//x1, y1, and r1 are for circle 1
boolean colliding(int x1, int y1, int x2, int y2, int r1, int r2) {
return sqrt(pow(x1-x2, 2) + pow(y1-y2, 2)); <= r1 + r2
}
If you wish to use rectangular hitboxes instead, check this link.
I hope this helped, have a good day.
So I am doing circle to circle collision in java. I am aware that there are many similiar questions like mine on this website but my problem is unique from all of them. When I run my code, the circle's collide with each other once every 4 times. Meaning: 3 times they will go through without colliding with one another but one time they will collide. Any help is greatly appreciated.
public class Ball {
float x, y; // coordinates of ball rectangle
float xo, yo;
float vx = 2, vy = 2; // coordinates of velocity vector
Color colour; // ball colour
float d; // diameter of the ball or sizes of ball rectangle
Ellipse2D.Float circle;
// overloaded constructor
Ball(int x, int y, int vx, int vy, int d, Color colour) {
this.x = x;
this.y = y;
this.d = d;
xo = x;
yo = y;
this.setColour(colour);
this.setVelocity(vx, vy);
circle = new Ellipse2D.Float(x, y, d, d);
}
public void setColour(Color colour) {
this.colour = colour;
}
public void setVelocity(int vx, int vy) {
this.vx = vx;
this.vy = vy;
}
public void show(Graphics g) {
((Graphics2D) g).setPaint(colour);
circle.setFrame(x, y, d, d);
((Graphics2D) g).fill(circle);
xo = x;
yo = y;
}
public void hide(Graphics g) {
Color c = ((Graphics2D) g).getBackground();
((Graphics2D) g).setPaint(c);
circle.setFrame(xo, yo, d, d);
((Graphics2D) g).fill(circle);
}
public void setPosition(float x, float y) {
this.x = x;
this.y = y;
}
public void move(int a, int b, int xh, int yh) {
if (vy > 0) {
if (y + d + vy - yh - b > 0) {
y = yh + b - d;
vy = -vy;
} else
y += vy;
} else {
if (y + vy <= b) {
y = b;
vy = -vy;
} else
y += vy;
}
if (vx > 0) {
if (x + d + vx - xh - a > 0) {
x = xh + a - d;
vx = -vx;
} else
x += vx;
} else {
if (x + vx <= a) {
x = a;
vx = -vx;
} else
x += vx;
}
}
The Collision Detector is in the class below
public class Game extends JFrame {
int ah, bh, xh, yh; // parameters of the rectangle frame
Color[] ColorAr = { Color.red, Color.blue, Color.pink, Color.green,
Color.yellow, Color.magenta, Color.black, Color.orange, Color.gray,
Color.cyan };
Ball b[];
int quantity = 4;
public void paint(Graphics g) {
int i;
((Graphics2D) g).setPaint(Color.black);
((Graphics2D) g).drawRect(ah, bh, xh, yh);
for (i = quantity - 1; i >= 0; i--) {
b[i].hide(g);
}
for (i = 0; i < quantity; i++) {
b[i].show(g);
}
}
public void prepare() {
int i;
ah = 20;
bh = 40;
xh = 400;
yh = 400;
b = new Ball[quantity];
for (i = 0; i < quantity; i++) {
b[i] = new Ball((int) (Math.random() * (300 - 1 + 1)) + 1, 100, 1,
1, 26, ColorAr[(int) (Math.random() * 9)]);
}
}
public void collision() {
int radius = 13;
int distance = 2 * radius;
if (b[1].x + distance == b[0].x && b[1].y == b[0].y
|| b[1].x - distance == b[0].x && b[1].y == b[0].y) {
b[1].vx = -b[1].vx;
b[0].vx = -b[0].vx;
}
}
public void run() {
int i;
while (true) {
for (i = 0; i < quantity; i++)
b[i].move(ah, bh, xh, yh);// move balls
collision();
for (int j = 0; j < 10000000; j++)
; // delay;
// collision();
repaint();
}
}
public static void main(String args[]) {
Game frame = new Game();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// frame.setBackground(Color.white);
frame.setSize(450, 470);
frame.prepare();
frame.setVisible(true);
frame.run();
}
}
For two circles:
First calculate the sum of lengths: radius_1 + radius_2 (the first and the second circle).
Collision of two circles can be detected if you calculate the length of (imaginary) line between centers. If THAT length <= radius_1 + radius_2, two circles are colliding.
I'm begginer in java game programming and I have a small actually big problem (for me) with game.
I'm trying making collision between enemy and blocks it doesnt work and i dont know why. It should worked but it just slow game on one fps per second and dont do anything.
I have main class called Game
with this main Init() function
public void init(){
WIDTH = getWidth();
HEIGHT = getHeight();
tex = new Texture();
BufferImageLoader loader = new BufferImageLoader();
level = loader.loadImage("/level.png"); // loading level
cloud = loader.loadImage("/cloud.png"); // loading clouds
handler = new Handler();
cam = new Camera(0,0);
LoadImageLevel(level);
this.addKeyListener(new KeyInput(handler));
}
and than LoadImageLevel function where I read level.png pixel by pixel and by the differents color I'm setting position of every objects.
private void LoadImageLevel (BufferedImage image){
int w = image.getWidth();
int h = image.getHeight();
//System.out.println(w + " , " + h);
for(int xx = 0; xx < h; xx++){
for(int yy = 0; yy < w ; yy++){
int pixel = image.getRGB(xx, yy);
int red = (pixel >> 16) & 0xff;
int green = (pixel >> 8) & 0xff;
int blue = (pixel) & 0xff;
if(red == 255 && green == 255 && blue == 255)
handler.addObject(new Block(xx*32,yy*32,1,ObjectId.Block));
if(red == 0 && green == 0 && blue == 255)
handler.addObject(new Player(xx*32,yy*32,1,handler,ObjectId.Player));
if(red == 0 && green == 255 && blue == 0)
handler.addObject(new Enemy(xx*32,yy*32,handler,ObjectId.Enemy));
}
}
}
In class Player is two important functions tick and collision where in tick is collison called.
public class Player extends GameObject{
private float width = 32, // 48
height = 64; // 96
private float gravity = 0.5f;
private final float MAX_SPEED = 10;
private int facing = 1;
private int last = 0; // last position left or right
private Handler handler;
Texture tex = Game.getInstance();
private int type;
private Animation playerWalk, playerWalkLeft,jump;
public Player(float x, float y,int type , Handler handler ,ObjectId id) {
super(x, y, id);
this.handler = handler;
this.type = type;
playerWalk = new Animation(2,tex.player[2],tex.player[3],
tex.player[4],tex.player[5]);
playerWalkLeft = new Animation(2,tex.player[7],tex.player[8],
tex.player[9],tex.player[10]);
jump = new Animation(2,tex.player[11],tex.player[12]);
}
public void tick(LinkedList<GameObject> object) {
x += velX;
y += velY;
if(velX < 0) facing = -1;
else if(velX > 0) facing = 1;
if(falling || jumping){
velY += gravity;
if(velY > MAX_SPEED){
velY = MAX_SPEED;
}
}
Collision(object);
//System.out.println(velX + " " + velY);
playerWalk.runAnimation();
playerWalkLeft.runAnimation();
jump.runAnimation();
}
private void Collision(LinkedList<GameObject> object){
for(int i = 0; i < handler.object.size();i++){
GameObject tempObject = handler.object.get(i);
if(tempObject.getId() == ObjectId.Block ){
if(getBoundsTop().intersects(tempObject.getBounds())){
y = tempObject.getY() + 32;
velY = 0;
}
if(getBounds().intersects(tempObject.getBounds())){
y = tempObject.getY() - height;
velY = 0;
falling = false;
jumping = false;
}else
falling = true;
if(getBoundsRight().intersects(tempObject.getBounds())){
x = tempObject.getX() - width;
}
if(getBoundsLeft().intersects(tempObject.getBounds())){
x = tempObject.getX() + 35;
}
}
/* new */
}
}
public void render(Graphics g) {
/*
g.setColor(Color.blue);
g.fillRect((int)x,(int)y,(int)width,(int)height);
Graphics2D g2d = (Graphics2D) g;
g.setColor(Color.red);
g2d.draw(getBounds());
g2d.draw(getBoundsRight());
g2d.draw(getBoundsLeft());
g2d.draw(getBoundsTop());
*/
if(velX != 0){
if (facing == 1){
playerWalk.drawAnimation(g,(int) x, (int)y,32,64);
last = 1;
}
else{
playerWalkLeft.drawAnimation(g,(int) x, (int)y,32,64);
last = 0;
}
}
else
if (last == 1)
g.drawImage(tex.player[1], (int)x,(int) y,32,64,null);
else
g.drawImage(tex.player[6], (int)x,(int) y,32,64,null); // 6 ,32,64
//System.out.println("Y: " + y); // 513 je max
if (y >= 513){
g.setColor(Color.red);
g.drawString("Game Over", (int) x, 200);
}
}
public Rectangle getBounds() {
return new Rectangle((int) ((int)x+(width/2)-((width/2)/2)),(int) ((int)y+(height/2)),(int)width/2,(int)height/2);
}
public Rectangle getBoundsTop() {
return new Rectangle((int) ((int)x+(width/2)-((width/2)/2)),(int)y,(int)width/2,(int)height/2);
}
public Rectangle getBoundsRight() {
return new Rectangle((int) ((int)x+width-5),(int)y+5,(int)5,(int)height-10);
}
public Rectangle getBoundsLeft() {
return new Rectangle((int)x,(int)y+5,(int)5,(int)height-10);
}
Player dont have any problem with block collision.
public class Block extends GameObject {
Texture tex = Game.getInstance();
private int type;
public Block(float x, float y,int type,ObjectId id) {
super(x, y, id);
this.type = type;
}
public void tick(LinkedList<GameObject> object) {
}
public void render(Graphics g) {
if(type == 0)
g.drawImage(tex.block[0], (int) x, (int) y ,null);
if(type == 1)
g.drawImage(tex.block[1], (int) x, (int) y ,null);
}
public Rectangle getBounds() {
return new Rectangle((int)x,(int)y,32,32);
}
}
But when i tried created Enemy class and make it same like in Player class I mean collision it just make game slower and nothing else.
public class Enemy extends GameObject{
private Handler handler;
public Enemy(float x, float y,Handler handler, ObjectId id) {
super(x, y, id);
this.handler = handler;
}
public void tick(LinkedList<GameObject> object) {
for(int i = 0; i < handler.object.size();i++){
GameObject tempObject = handler.object.get(i);
if(tempObject.getId() == ObjectId.Block ){
if(getBoundsTop().intersects(tempObject.getBounds())){
}
if(getBounds().intersects(tempObject.getBounds())){
}
if(getBoundsRight().intersects(tempObject.getBounds())){
}
if(getBoundsLeft().intersects(tempObject.getBounds())){
}
}
}
}
public void render(Graphics g) {
g.setColor(Color.red);
g.fillRect((int)x,(int) y, 32, 32);
}
public Rectangle getBoundsTop() {
return new Rectangle((int)x,(int)y,32,32);
}
public Rectangle getBoundsLeft() {
return new Rectangle((int)x,(int)y,32,32);
}
public Rectangle getBoundsRight() {
return new Rectangle((int)x,(int)y,32,32);
}
public Rectangle getBounds() {
return new Rectangle((int)x,(int)y,32,32);
}}
I know that bounds should not have return same "new Rectangle" and that theres no any movements of enemy anyway when i set in tick method x--; for just trying if enemy stop when it come to the edge of block but it doesnt work i dont know whats wrong with it i spend more than two days with fixing this. If it can help you there is a link for whole project (Eclipse) You can download it from dropbox
I just wanted to have an enemy which move left and right and have collison with block it means when he "touch" by his left side to the block he "turn around" and move to right side until he "touch" by his right side etc... other collisions between Player and Enemy is not problem for me. But just this.
I'm so thankful for every advice :)
The problem is with your getBounds() method.
You are saying in getBounds() method to return a rectangle with width=32 and height=32. And since your rectangle is 32 by 32 (as mentioned in fillrect(x,y,32,32) ) so getBounds() returns with the intersection in height and width.
In other words, try not to collide the returned Top left bottom or right bounds with themselves.
And in enemy(), you are declaring set.color = red while in loading you are using green. Try red==255, green==0, blue==0 instead of if(red == 0 && green == 255 && blue == 0)
I can not seem to get my player to move when certain keys are pressed. I did some debugging and placed a System.out.print("Pressed); in the if statements that check if a key is pressed and it prints out the message every time I press the key, they player just is not moving. Can someone help!
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);
}
}
}
and here is the Player class
public class Player extends Mob {
private InputHandler input;
private int r = 10;
public Player(int x, int y, int speed, InputHandler input) {
super("Player", x, y, 1);
this.input = input;
this.x = x;
this.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));
}
}
and here is the Mob class that has the move() method in it
public Mob(String name, int x, int y, int speed) {
this.name = name;
this.speed = speed;
}
public void move(int dx, int dy) {
if (dx != 0 && dy != 0) {
move(dx, 0);
move(dy, 0);
numSteps--;
return;
}
numSteps++;
if (!hasCollided(dx, dy)) {
if (dy < 0)
movingDir = 0;
if (dy > 0)
movingDir = 1;
if (dx < 0)
movingDir = 2;
if (dx > 0)
movingDir = 3;
x += dx * speed;
y += dy * speed;
}
}
public abstract boolean hasCollided(int dx, int dy);
public String getName() {
return _name;
}
}
From where is the render method inside the Player class called? Have you overridded paint(Graphics) or paintComponent(Graphics) somewhere?
Turns out the JFrame didn't have focus. Once it was in focus the code worked beautifully.
This code has all sorts of problems, but the most pressing seems to be that there is refrences to both _x and x. Choose one and make all the methods use that one. This may help, but honestly it is hard to tell exactly what to fix, maybe start with something simpler?
I found one error with your code for move. You call move(dx, 0) and move(dy, 0) inside an if statement, if both of them are not 0. In the ensuing recursion, they are both 0 and nothing is done. Instead, change the && to a ||
public void move(int dx, int dy) {
if (dx != 0 || dy != 0) {
move(dx, 0);
move(dy, 0);
numSteps--;
return;
}
...
}
There's so much code here that it's really too much for a single question.
A better approach would be to go ahead and make each class smaller. Specifically, don't error check for walls. Just move the mob/whatever around. If there's a problem, then the game(?) will throw an error...
In general, I would say that this approach is overly concerned with "what if?" problems rather than the basics of maneuverings a 2d dungeon with x,y coordinate system.
(Just to confuse matters, what if it was in polar coordinates!? Anyhow...)
After getting your code to run, I went ahead and put it on github for you:
https://github.com/THUFIR/Game2D/tree/master/src/genericGame
Feel free to fork it, please do. Git, or any version control, can really help out when your code was working, but something broke...
Here's the output, very simple:
thufir#dur:~/NetBeansProjects/Game2D$
thufir#dur:~/NetBeansProjects/Game2D$ java -jar dist/Game2D.jar
x 1 y 1
x 4 y 6
thufir#dur:~/NetBeansProjects/Game2D$
driver:
package genericGame;
import static java.lang.System.out;
public class Driver {
public static void main(String[] args) {
Player player = new Player(0, 0, 0);
player.move(1, 1);
out.println(player);
player.move(3, 5);
out.println(player);
}
}
and player:
package genericGame;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
public class Player extends Mob {
private int r = 10;
public Player(int x, int y, int speed) {
super("Player", x, y);
this.x = x;
this.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));
}
}
Hope that helps. Please learn git.
I'll read the other answers to see better solutions, I just hit it with a hammer until it compiled. The naming conventions, organization, and access levels to methods, classes and fields are all, well, let's say, opportunities for improvement.
I've been working on this game with LWJGL for a few weeks now. Ever since I added the ability to jump, the upward collision has been giving me a lot of problems.
The game is a 2D tile-based sidescroller. Overall, the collision is almost perfect except for when the player jumps. At first I thought "Oh, maybe I just need to change the jumping mechanics," but then I realized that it only happens when the player is passed a certain x coordinate.
Now, for the actual problem itself: if the player jumps when passed a certain x coordinate, they will pass through the tile and testing for top collision returns false.
This is the entire Player class:
package Minecraft2D;
import static Minecraft2D.World.BLOCK_SIZE;
import Minecraft2D.Tools.Tools;
import Minecraft2D.UI.Inventory;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import static Minecraft2D.Boot.*;
import org.lwjgl.util.Rectangle;
import org.newdawn.slick.opengl.Texture;
import org.newdawn.slick.opengl.TextureLoader;
public class Player {
private float x;
private float y;
public int width = 32;
public int height = 50;
private float DX = 0;
private float DY = 0;
private Texture left = null;
private Texture right = null;
Texture texture = null;
public boolean direction[] = { false, false, false, false };
public boolean collision = false;
public boolean ground = false;
public boolean jump = false;
public boolean top = false;
public Player(float x, float y) {
this.x = x;
this.y = y;
try {
this.left = TextureLoader.getTexture("PNG", new FileInputStream(new File(path + "player_left.png")));
this.right = TextureLoader.getTexture("PNG", new FileInputStream(new File(path + "player_right.png")));
this.texture = this.right;
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public void draw() {
Tools.drawTexture((int)x, (int)y, width, height, texture);
}
public void checkCollision(Player player, Block block) {
if (player.getY() < block.getY() + BLOCK_SIZE && player.getX() < block.getX() + BLOCK_SIZE && player.getY() + this.height > block.getY() && player.getX() + this.width > block.getX() && block.getType() != BlockType.AIR) {
Rectangle top = new Rectangle();
top.setBounds((int) player.x + 4, (int) player.y + 1, this.width - 8, 1);
Rectangle bottom = new Rectangle();
bottom.setBounds((int) player.x + 4, (int) player.y + this.height, this.width - 8, 1);
Rectangle left = new Rectangle();
left.setBounds((int) player.x, (int) player.y + 1, 1, this.height - 5);
Rectangle right = new Rectangle();
right.setBounds((int) player.x + player.width, (int) player.y + 1, 1, this.height - 5);
Rectangle blok = new Rectangle();
blok.setBounds((int) block.getX(), (int) block.getY(), BLOCK_SIZE, BLOCK_SIZE);
if (bottom.intersects(blok)) {
player.setY((block.getY() - this.height - 1));
ground = true;
jump = false;
} else if (top.intersects(blok)) {
DY = 0;
this.top = true;
y -= (player.y) - (block.getY() + BLOCK_SIZE);
}
if (!top.intersects(blok)) {
if (left.intersects(blok)) {
player.setX(block.getX() + this.width);
} else if (right.intersects(blok)) {
player.setX(block.getX() - this.width);
}
}
} else {
collision = false;
ground = false;
}
if (!collision && !jump) {
setDY(.003f);
}
if (ground && !jump) {
DY = 0;
}
if (jump && DY < 0.003f) {
DY += 0.0001;
} else {
// jump = false;
}
if (top) {
DY = 0f;
top = false;
}
x += DX;
y += DY;
if (x > Boot.SCREEN_WIDTH) {
x = 0;
}
if (x < 0) {
x = Boot.SCREEN_WIDTH;
}
}
public float getX() {
return x;
}
public void setX(float x) {
this.x = x;
}
public float getY() {
return y;
}
public void setY(float y) {
this.y = y;
}
public void setDX(float dx) {
this.DX = dx;
}
public void setDY(float dy) {
this.DY = dy;
}
public void setJump() {
if (!jump) {
jump = true;
ground = false;
DY = -0.13f;
y -= 1;
}
}
public void setTexture(int tex) {
if (tex == 0) {
this.texture = this.left;
}
if (tex == 1) {
this.texture = this.right;
}
}
}
==============
EDIT: I have no clue why, but as my character moves closer to the map's 0 x-coordinate, the character's y coordinate increases very slowly. This probably has something to do with the problem I have been getting. I am looking into it and I have a suspicion that it may have something to do when I cast the player's x and y values from doubles to integers for use in the top, bottom, left, and right Rectangles.
EDIT again:
I don't know if this matters, but I have been checking collision like this: (This is in the "Boot" class.)
private void checkCollision() {
for (int x = 0; x < BLOCKS_WIDTH - 1; x++) {
for (int y = 0; y < BLOCKS_HEIGHT - 1; y++) {
Block blk = grid.getAt(x, y);
player.checkCollision(blk);
}
}
}
Why are you passing a player into checkCollision? It seems like you should not be passing in a player, but instead using the members of the player that's calling the checkCollision method. I think that may be leading to some confusion for you. Such as:
y -= (player.y) - (block.getY() + BLOCK_SIZE);
This looks like you are trying to push the player below the block b/c they intersected it during their jump. If that's the case, it should just be
y = (block.getY() + BLOCK_SIZE);
I would remove the player from the function argument and rewrite the function and see what you get. Hope that helps.
EDIT
Your comment states that you can no longer pass the player into the function. Not sure about your exact implementation, but here's what games that I have typically seen look like:
public class Player
{
private int x, y, dx, dy;
public void checkCollision(Block block)
{
if (isTopCollision(block))
fall(block.getY() + block.getHeight());
}
private boolean isTopCollision(Block block)
{
return y > block.getY() + block.getSize() && y < block.getY();
}
private void fall(int adjustedY)
{
y = adjustedY;
top = true;
dy = 0;
// etc
}
}
public class MyGame
{
public void gameloop()
{
for (Block b : blocks)
player.checkCollision(b);
}
}