So, I have a gameOver() method that should when oval goes out of bounds abort game but, as soon as I start the game it runs the gameOver method. I've been looking over it for a while trying different things. I think what stood out to me is removing the abort sequence the game runs mostly as it should after, popup is closed and that if I replace game.gameOver(); with ya = -1 the ball bounces off the wall.
gaveOver()
public void gameOver(){
JOptionPane.showMessageDialog(this, "Game Over", "Game Over", JOptionPane.YES_NO_OPTION);
System.exit(ABORT);
}
move()
package com.edu4java.minitennis1;
import java.awt.Graphics2D;
import java.awt.Rectangle;
public class Ball {
private static final int DIAMETER = 30;
int x = 0;
int y = 0;
int xa = 1; // Represent the speed in which the ball is moving
int ya = 1; // Represent the speed in which the ball is moving
private Game game;
public Ball(Game game){
this.game=game;
}
/*
* If xa=1, the ball moves to the right, one pixel every round of the Game Loop,
* if xa=-1, the ball moves to the left.
* If ya=1 moves the ball down and
* If ya=-1 moves the ball up.
*/
void move(){
if (x + xa < 0) // Makes left bounds
xa = 3; // Moves the ball right
if (x + xa > game.getWidth() - DIAMETER) // Makes right bounds
xa = -3; // Moves the ball left
if(y + ya < 0) // Makes top bounds
ya = 3; // Moves ball down
if(y + ya > game.getHeight() - DIAMETER) // Makes bottom bounds
game.gameOver();
if (collision()){ // Makes collision with Racquet
ya = -3;
y = game.racquet.getTopY() - DIAMETER;
}
x = x + xa;
y = y + ya;
}
private boolean collision(){
return game.racquet.getBounds().intersects(getBoundsBall());
}
public void paint(Graphics2D g){
g.fillOval(x, y, DIAMETER, DIAMETER);
}
public Rectangle getBoundsBall(){
return new Rectangle(x, y, DIAMETER, DIAMETER);
}
}
The problems has been resolved I just went back and rewrote the move() method and replaced it with
void move(){
if(x + xa < 0)// Makes left bounds
xa = 1;// Moves the ball right
if(x + xa == game.getWidth() - DIAMETER)// Makes right bounds
xa = -1;// Moves the ball left
if (y + ya < 0)// Makes top bounds
ya = 1;// Moves ball down
if(y + ya == game.getHeight() - DIAMETER){ // Makes bottom bounds
ya = 0;// Moves ball up
xa = 0;
game.gameOver();
}
Sometimes all you need to do is go back.
You have answered your question yourself I think. Assuming there are no further calls to your gameOver() method than the one that's in your move() method, than gameOver is called from this if block:
if(y + ya > game.getHeight() - DIAMETER)
game.gameOver();
Which means that (y + ya) is greater than (game.getHeight() - DIAMETER). Since I don't know what your variables are supposed to be I can only guess that there might be a problem with your initial values,etc.
Try stepping through your program with a debugger and it will be much easier to see the problem and understand what's going on.
Related
I need to change Ball Direction after collision with another ball or with a edge of the window.
I managed to do something like that:
y += yMove;
x += xMove;
//if the ball moves to the right edge of the window, turn around.
if(x > width - size)
{
x = width - size;
xMove *= -1;
if (xMove > 0) {
xSpeed = xMove + (Math.random() * (1));
}
if (xMove <= 0) {
xSpeed = xMove - (Math.random() * (1));
}
if (yMove > 0) {
ySpeed = yMove + (Math.random() * (1));
}
if (yMove <= 0) {
ySpeed = yMove - (Math.random() * (1));
}
}
And same for another edges.
I'm trying to use same method for changing direction of balls after they collide with each other, but it's just not working / it's weird. Can anyone help me?
When balls collide, make vector connecting ball centers (N) and normalize it (uN)
Components of velocities parallel to N (normal) are exchanged (due to impulse law)
Components of velocities perpendicular to N (tangential) remain the same
To get components in given local system, use scalar and cross product:
V1t = dot(V1, uN)
V2t = dot(V2, uN)
V1n = cross(V1, uN)
V2n = cross(V2, uN)
after collision
V1t' = V2t
V2t' = V1t
V1n' = V1n
V2n' = V2n
To return into global system (I did not checked signs thoroughly):
V1x = V1t` * uN.X + V2n` * uN.Y
V1y = -V1t` * uN.Y + V2n` * uN.X
(This is essentially dot and cross products again, but I expanded expressions to show different bases)
Note that this approach is like to ball-edge collision, when N is normal to the border and you reverse only one component of velocity vector.
For your BouncingBall class, you can have a method like flipDirection(), but you can have a finer directional control by splitting it into 2 methods which filps the direction of the ball vertically and horizontally.
class BouncingBall{
public void horizontalFlip(){
moveX *= -1;
}
public void verticalFlip(){
moveY *= -1;
}
//To have move control over each direction, you can have a method for each direction.
public void moveNorth(){
moveY = Math.abs(moveY) * -1;
}
public void moveSouth(){
moveY = Math.abs(moveY);
}
public void moveWest(){
moveX = Math.abs(moveX) * -1;
}
public void mpveEast(){
moveX = Math.abs(moveX);
}
}
Depending on how you want the ball to bounce off. In a simple bounce off, the balls can bounce towards 4 possible directions:
North West
North East
South West
South East
The direction of the ball to bounce off will be relative to the position of the ball it is colliding with and you do not want 2 collided balls which move in the same direction to switch direction just because they collided. Hence you need to check the positions of the 2 balls, and flipDirection() becomes insufficinet to achieve that.
if(b1.intersects(b2)){
if(b1.getX() < b2.getX()){ // b1 above b2
b1.moveNorth();
b2.moveSouth();
}
else{
b1.moveSouth();
b2.moveNorth();
}
if(b1.getY() < b2.getY()){ // b1 at left side of b2
b1.moveWest();
b2.moveEast();
}
else{
b1.moveEast();
b2.moveWest();
}
}
For example, to change direction when hitting the walls on the left and right:
if(ball.getPosX() <= 0 || ball.getPosX() >= PNL_WIDTH-Ball.SIZE)
ball.horizontalReverse();
Same logic for verticalReverse.
I'm currently working on a Top-Down-Shooter and having some issues with collision.
My world is made of tiles (64x64). The tiles and the entities are rectangles. The player moves with a speed of e.g 2.74 (and not in pixels for smoother movement). But when it comes to the collision between the player (an entity) and a wall i have some issues. To check if there is a collision i take the current position of my player and his movement speed to calculate where his next position would be and if there is any collision. But i check every pixel on the way, so i cant skip an obstacle even if the movement speed is very high. Let's just say the players current position is X:200 Y:200 and he moves 2.74 Pixels a tick in the x direction. My game now checks if there is any collision at X:201 Y:200, X:202 Y:200 or X:202.74 Y:200 and if not moves the player to that position. If I now try to move the player further in the x direction and there is a wall 0.26 Pixels away the player wont move and leave a tiny gap. I tried to calculate the distance between player and wall and add this amount to the players position but for that I need to know which side of the wall the player hits. Also I want the player to be able to move up and down when the wall he hits is in front of him and the other way around.
Here is my collision method (in Java):
public static boolean collision(float ex, float ey, int width, int height) { // ex, ey would be the next position of the player
if (ex < 0 || ex + width > worldWidth || ey < 0 || ey + height > worldHeight) return true; // checks if this position is in the world
int firstTileX = (int) (ex / Tile.TILE_SIZE); // calculates tiles he could possible collide width
int firstTileY = (int) (ey / Tile.TILE_SIZE);
int lastTileX = (int) ((ex + width - 1) / Tile.TILE_SIZE);
int lastTileY = (int) ((ey + height - 1) / Tile.TILE_SIZE);
for (int y = firstTileY; y <= lastTileY; y++) {
if (y < 0) continue; // checks for out of bounds
if (y >= worldTileHeight) break;
for (int x = firstTileX; x <= lastTileX; x++) {
if (x < 0) continue;
if (x >= worldTileWidth) break;
if (tiles[y][x].solid) return true; // if the tile is solid -> collision found
}
}
return false; // no collision found
}
And my movement method:
public void move(float xa, float ya) {
float nx, ny;
while (xa != 0 || ya != 0) {
nx = x;
ny = y;
if (xa != 0) {
if (Math.abs(xa) > 1) { // if the x-speed is greater than 1
nx = x + MathUtil.abs(xa); // returns -1 for negative numbers and 1 for positiv
xa -= MathUtil.abs(xa);
} else { // less than 1
nx = x + xa;
xa = 0;
}
}
if (ya != 0) { // same here
if (Math.abs(ya) > 1) {
ny = y + MathUtil.abs(ya);
ya -= MathUtil.abs(ya);
} else {
ny = y + ya;
ya = 0;
}
}
if (!Level.collision(nx, ny, width, height)) setPosition(nx, ny); // checks if there is an collision and sets the new position if not
else if (!Level.collision(nx, y, width, height)) x = nx; // if there was a collision check if the player can walk in x direction
else if (!Level.collision(x, ny, width, height)) y = ny; // or in y direction
}
}
My problem is the pretty much the same as CoderMusgrove's problem in his post (Pixel-perfect collision and doubles):
Summary & Question
I have a problem where if the speed of an entity isgreater thanthe distance from the tile it is going into, it will leave at least a pixel in between itself and the tile, and I really don't like this. What kind of algorithm could I use that will find the tiniest difference between the entity and the tile?
If you need any additional information, I will be glad to add it.
Thanks for your help!
Easily resolvable by changing your interpretation.
You are retaining a fractional position for the purpose of fine grained speed. Ignore the fraction for the purpose of collision detection and display (if you were to do sub-pixel rendering, do the collision on the subpixel rendering accurarcy level).
int screenX = (int) Math.round(objX);
int screenY = (int) Math.round(objY);
// rendering and collision detection based on rounded position
I'm trying to get the ball bounce of the bat in my mini tennis game. I'm not sure what methods to implement. Currently the ball bounces and both bats move the aim of the game is for a player to get the ball past the oppositions. Is there any special methods?
For implementing the game boundary's simply create a method that checks collisions(say your boundarys are 150 by 150) so
if(x < 0 | x > 150 | y < 0 | y > 150) { // if ball is within boundary's
xa = xa * -1; //switch direction of ball(bounce)
ya = ya * -1;
score += 1;
}
So when the ball hits the boundary the score goes up one and the ball bounces the ball back, but you can also reset the ball with another method.
Btw you can print text on the screen with
g2d.drawString("Score: " + score, 150, 150); // prints score on screen
EDIT this kind of explains collisions for a basic pong game, it might help a little in your case.
Heres the full code http://www.dreamincode.net/forums/topic/172211-programing-an-applet-game-of-pong/
public void checkCollision(){
//remember, our ball is 10*10 and the x and y positions are the
//top-left corners of the ball. If the top left corner y position
//is 0 or 290, we reverse the y- direction that the ball was
//travelling in by multiplying ball.dy by -1
if(ball.getY() == 0 || ball.getY() == 290){
ball.dy = (ball.dy * -1);
}
//if the ball is at the right-hand edge of the human paddle's
//domain and the boolean method hitPaddle() is true, then we
//reverse the dx position of ball by multiplying ball.dx by -1
if((ball.getX() == 40) && hitPaddle()){
ball.dx = (ball.dx * -1);
}
//we already know that the computer paddle can't miss, so if
//the ball reaches the left-hand edge of the paddle, we can make the
//dx switch directions without any additional checks
if(ball.getX() == 460){
ball.dx = (ball.dx * -1);
}
//if the ball is missed by the human paddle and reaches the
//left-hand edge of the applet window, then reset the ball
//and increment the score
if(ball.getX() == 0){
pRight.setScore(pRight.getScore() + 1);
ball.reset();
}
}
public boolean hitPaddle(){
boolean didHit = false;
//this just checks if the ball is lined up between the top and
//bottom right-hand corners of the human paddle
if((pLeft.getPos() - 10) <= ball.getY() && (pLeft.getPos() + 70) > ball.getY()){
//sets didHit to true
didHit = true;
}
return didHit;
}
I am struggling with what must be a basic concept, but can you have a look at my issue?
I have the code where: ai moves the player bat, HEIGHT = total height of Display, and batHeight is the size of the pong paddle/bat:
public void ai(int bally, int HEIGHT, int batHeight) {
if (bally < this.y + ySize / 2) {
if (this.y <= 0) {
System.out.println("Upper Bound");
y = 0;
} else {
y -= 2;
}
}
if (bally > this.y + ySize / 2) {
if (this.y >= HEIGHT - batHeight) {
System.out.println("Lower Bounds");
y = HEIGHT - batHeight;
} else {
y += 2;
}
}
}
The above does exactly what I want it to do. Pong Bat moves up, and when it hits the top of the screen, it prints the console line, and stops the Bat. Exactly the same happens at the bottom of the screen. It prints the console, and stops the bat. It does this every time with no issues.
Now, if I modify the code slightly:
public void ai(int bally, int HEIGHT, int batHeight) {
if (bally < this.y + ySize / 2) {
if (this.y <= 0) {
System.out.println("Upper Bound");
y = 0;
} else {
if(rand.nextInt(2)+1 == 1){
y -= 2;
}else{
y -=3;
}
}
}
if (bally > this.y + ySize / 2) {
if (this.y >= HEIGHT - batHeight) {
System.out.println("Lower Bounds");
y = HEIGHT - batHeight;
} else {
y += 2;
}
}
}
It iterates once, stopping at the top bound, but then it loses itself, and forgets the bounds and the bat moves off the screen. I have Console printing the Bat y position, and it tracks with no issue, accurately displaying its y co-ord, but after the first iteration, it goes to negative y and greater that screen height.
I did have the theory that you cannot nest a IF inside an ELSE statement, so i tried moving it around so that it read:
if(this.y != 0){
if(rand.nextInt(2) + 1 == 1){
//move the paddle at speed 1
} else {
//move paddle at speed 2
}
}else{
//do not move the paddle
}
But that made no difference.
The idea behind the code was to add some chance for the AI bat. Sometimes its fast, and other times it is slower.
Thanks in advance,
Your code from far away looks like this:
for a given time:
if the ball is below the paddle {
if the paddle is below the screen, put it back
else move it down 2 or 3 units
}
if the ball is above the paddle {
if the paddle is above the screen, put it back
else move it up 2 units
}
Imagine the case where the ball is at y = 1 and the paddle is at y = 2. The first if statement will be triggered (1 < 2), the paddle is not outside (2 > 0), so it moves down 2 or 3 units. Let's say 3, for argument's sake. Now, paddle is at y = -1, the ball is still at y = 1. Now, the condition for the second big if is true! So we enter it: the paddle's not above, and we move it up two units. Now, the paddle is at y = 1...
It is clear that it should not have entered the second loop. So, stick an else in front of it, because it should only ever enter one :)
So I understand that I'm not coding this the best way possible at the moment; this is a sort of test run. What I'm trying to do is wall collisions using rectangles and the intersects property (sorry if I'm not using the correct terminology). So far I have 2 rectangles on screen. 1 the player controls and the other which the play is colliding with. When they collide the player stops moving. The problem is that if the player is trying to move into the rectangle while they are already colliding then the player can't move in any direction perpendicular to the movement ie if the player is holding the right arrow key moving into the rectangle, then they cannot move up or down. The game works on the premise that if your x or y coordinates aren't valid, then you will be moved back to the last valid coordinate recorded but I'm having trouble detecting the valid x and y coordinate separately. Here is the code:
public void Collision()
{
if(x < 0)
x = 0;
if(x > 400 - width)
x = 400 - width;
if(y < 0)
y = 0;
if(y > 300 - height)
y = 300 - height;
rect1 = new Rectangle(x, y, 16, 16);
rect2 = new Rectangle(sx, sy, wid, hei);
if(!rect1.intersects(rect2))
{
validX = true;
validY = true;
}
else
{
validX = false;
validY = false;
}
if(validX)
{
lastValidX = x;
}
if(validY)
{
lastValidY = y;
}
if(!validX)
{
x = lastValidX;
}
if(!validY)
{
y = lastValidY;
}
}
The Collision() method in the Guy class is where I'm having the trouble I believe. Yes my code is pretty messy right now but this is only a test.
Thanks, David.
You can implement what you're describing by doing extra logic around here (i.e. detecting cases when one is false and the other is true):
if(!rect1.intersects(rect2))
{
validX = true;
validY = true;
}
else
{
validX = false;
validY = false;
}
However, it seems like maybe you shouldn't be allowing the rectangles to ever be in a "colliding" state in the first place. For example, you can change the Move method to do something like
public void Move()
{
int oldX = x, oldY = y;
x += dx;
y += dy;
if (Collision()) {
x = oldX;
y = oldY;
}
}