I made a simple breakout game for Android, and I have some problems when the ball reaches the bar (paddle). ball, bar are bitmaps. x,y are the positions of the ball, bx and by are the positions of the bar (paddle). speedX and speedY are the speed of the ball. this isn't a very nice solution. Where can I change the code?
if (y + ball.getHeight() >= c.getHeight()
- (10 + bar.getHeight())
&& (x + ball.getWidth() / 2) >= bx - bar.getWidth() / 2
&& (x + ball.getWidth() / 2) <= bx + bar.getWidth() / 2) {
mp.start();
xdirection = (((x + ball.getWidth()) / 2) - ((bx + bar
.getWidth())) / 2) / (bar.getWidth() / 2);
speedY = -speedY;
speedX = (speedX) * Math.abs(xdirection);
Related
I have a game, the map size is 20*36 tiles means 720 tiles.
I have three layers in my game:
The floor layer: Safe zone floor, Regular floor)
Objects (Big rock, Small rock, Action tile) . (Action tile is for example, a tile that shows a wind, so when stepped on that tile, your character will move to the wind direction)
Player's ships
So no, I can't just draw everything in the same loop, like that, because player entities are not using the same list as objects and floor layer, and floor layer is basically an array of 20*36.
The thing is, I could just make them all implement some Drawable interface, and put them all in a list and draw with one loop, but I can't just draw them with a randomized order. The position of the object matters, if to draw the rock over the ship, or the ship over the rock.
Currently that's how I am drawing the objects and sea floor layer:
Cell[][] sea = blockadeMap.getSea();
Wind[][] winds = blockadeMap.getWinds();
Whirlpool[][] whirls = blockadeMap.getWhirls();
for (int i = 0; i < sea.length; i++) {
for(int j = 0; j < sea[i].length; j++) {
TextureRegion region = sea[i][j].getRegion();
int x = (i * GameTile.TILE_WIDTH / 2) - (j * GameTile.TILE_WIDTH / 2) - region.getRegionWidth() / 2;
int y = (i * GameTile.TILE_HEIGHT / 2) + (j * GameTile.TILE_HEIGHT / 2) - region.getRegionHeight() / 2;
batch.draw(region, x, y);
if (winds[i][j] != null) {
region = winds[i][j].getRegion();
x = (i * GameTile.TILE_WIDTH / 2) - (j * GameTile.TILE_WIDTH / 2) - region.getRegionWidth() / 2;
y = (i * GameTile.TILE_HEIGHT / 2) + (j * GameTile.TILE_HEIGHT / 2) - region.getRegionHeight() / 2;
batch.draw(region, x, y);
}
else if (whirls[i][j] != null) {
region = whirls[i][j].getRegion();
x = (i * GameTile.TILE_WIDTH / 2) - (j * GameTile.TILE_WIDTH / 2) - region.getRegionWidth() / 2;
y = (i * GameTile.TILE_HEIGHT / 2) + (j * GameTile.TILE_HEIGHT / 2) - region.getRegionHeight() / 2;
batch.draw(region, x, y);
}
}
}
And this happens every frame draw, iterates 720 times per frame.
I think I really need to find a way to optimize that.
In addition, after this, I have an iterator through all players and draw players.
What is the best way to handle such drawing?
I am working on a Pong-like game, and have implemented the code that moves the paddle (via user input) and the ball. I am currently working on the code for the collision between the ball and the paddle.
Everything seems to be working fine, except when I move the paddle directly onto the ball. This means that the ball collides with the bottom part or top part of the paddle, instead of the side of the paddle, which results in the ball getting stuck inside the paddle and stuttering rapidly.
I know that the motion is caused by the ball changing velocity every frame. I am still having trouble figuring out how to solve it.
I have tried implement a boolean variable to determine whether or not the ball already collided with the paddle during a frame. However, I am having some trouble going about implementing this logic into my code. In my main class, you will see some comments pointing out this boolean variable and what I intended to do with it.
Below are some of the major code snippets pertaining to my problem.
MainApp:
// ...
new AnimationTimer() {
#Override
public void handle(long currentTime) {
ballInfo.setText("Ball (" + ball.getX() + ", " + ball.getY() + ")");
leftPaddleInfo.setText("Left Paddle (" + leftPaddle.getX() + ", " + leftPaddle.getY() + ")");
rightPaddleInfo.setText("Right Paddle (" + rightPaddle.getX() + ", " + rightPaddle.getY() + ")");
// Give point and reset ball.
if (ball.didCollideWithLeftWall(canvas)) {
givePoint(rightPaddle);
rightPaddleScore = rightPaddle.getPoints();
rightPaddleScoreLabel.setText("Player 2 Score: " + rightPaddleScore);
reset();
}
if (ball.didCollideWithRightWall(canvas)) {
givePoint(leftPaddle);
leftPaddleScore = leftPaddle.getPoints();
leftPaddleScoreLabel.setText("Player 1 Score: " + leftPaddleScore);
reset();
}
// Handle bouncing off of top and bottom walls
ball.didCollideWithWalls(canvas);
// Keep paddle in screen bounds
if (leftPaddle.getY() <= canvasBounds.getMinY() + 5)
leftPaddle.setY(canvasBounds.getMinY() + 5);
if (leftPaddle.getY() >= canvasBounds.getMaxY() - 105)
leftPaddle.setY(canvasBounds.getMaxY() - 105);
if (rightPaddle.getY() <= canvasBounds.getMinY() + 5)
rightPaddle.setY(canvasBounds.getMinY() + 5);
if (rightPaddle.getY() >= canvasBounds.getMaxY() - 105)
rightPaddle.setY(canvasBounds.getMaxY() - 105);
if (leftPaddle.didCollideWith(ball)) {
ball.setvX(-ball.getvX());
ball.setX(ball.getX() + ball.getvX());
}
if (rightPaddle.didCollideWith(ball)) {
ball.setvX(-ball.getvX());
ball.setX(ball.getX() + ball.getvX());
}
// Update and render
ball.update(ELAPSED_TIME_SPEED);
leftPaddle.update(ELAPSED_TIME_SPEED);
rightPaddle.update(ELAPSED_TIME_SPEED);
gc.clearRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
gc.setFill(BALL_COLOR);
ball.render(gc);
gc.setFill(LEFT_PADDLE_COLOR);
leftPaddle.render(gc);
gc.setFill(RIGHT_PADDLE_COLOR);
rightPaddle.render(gc);
}
}.start();
Paddle:
#Override
public boolean didCollideWith(Sprite other) {
Ball ball = (Ball) other;
double ballCenterX = ball.getCenterX();
double ballRadius = ball.getRadius();
double ballCenterY = ball.getCenterY();
double halfWidth = this.getHalfWidth();
double halfHeight = this.getHalfHeight();
double centerX = this.getCenterX();
double centerY = this.getCenterY();
if (getName().toLowerCase().equals("left")) {
boolean hitXBounds = ballCenterX - ballRadius <= centerX + halfWidth
&& ballCenterX - ballRadius >= centerX - halfWidth;
boolean hitTopPartOfBall = ballCenterY - ballRadius <= centerY + halfHeight
&& ballCenterY - ballRadius >= centerY - halfHeight;
boolean hitBotPartOfBall = ballCenterY + ballRadius <= centerY + halfHeight
&& ballCenterY + ballRadius >= centerY - halfHeight;
return hitXBounds && (hitTopPartOfBall || hitBotPartOfBall);
}
if (getName().toLowerCase().equals("right")) {
boolean hitXBounds = ballCenterX + ballRadius >= centerX - halfWidth
&& ballCenterX + ballRadius <= centerX + halfWidth;
boolean hitTopPartOfBall = ballCenterY - ballRadius <= centerY + halfHeight
&& ballCenterY - ballRadius >= centerY - halfHeight;
boolean hitBotPartOfBall = ballCenterY + ballRadius <= centerY + halfHeight
&& ballCenterY + ballRadius >= centerY - halfHeight;
return hitXBounds && (hitTopPartOfBall || hitBotPartOfBall);
}
return false;
}
Thank you!
EDIT
I have somewhat fixed the collision code in the Paddle class, so that now it is much more difficult to perform the mentioned bug. However, I am still getting the stuttering bug if the, for instance, the leftmost point of the ball comes right into contact with the rightmost point of the left paddle. If I were to time it just right, I can still get the ball stuck inside the paddle the same way as I could before (by moving it directly on top of/ bottom of it), but it will only create this bug IF the ball is still in front of the paddle.
I have changed the code above as well.
I will keep this quick.
Just making a processing program where the ball bounces off the rectangle.
At the moment I can only figure out how to do the top,left,right and bottom sides but when the ball goes into the corners of the rectangle, it doesn't bounce off but instead goes into the rectangle and after 1 or 2 bounces gets realeased.
I just really want to know how I should go about making the ball deflect off the corners of the rectangle so it doens't glitch
Here is my code :
float x = 100, y = 100, radius = 50;
float vx = 3, vy = 3;
float MX = 0;
float MY = 0;
void setup() {
size(500, 700);
}
void draw() {
background(0);
fill(255);
x += vx;
y += vy;
if (x + radius > width) {
vx = vx * -1;
}
//makes the ball bounce off the right
if (x - radius < 0) {
vx = vx * -1;
}
//makes the ball bounce off the left
if (y + radius > height) {
vy = vy * -1;
y = height - radius;
}
//make the ball bounce off the top
if (y - radius < 0) {
vy = vy * -1;
y = radius;
}
//makes the ball bounce off the top
if (y + radius > MY && x + radius > MX + 50 && x + radius < MX + 150 &&
y + radius < MY + 20) {
vy *= -1;
y = MY - 3 - radius;
} //Top Side
if (x - radius < MX + 100 && y > MY - 10 && y < MY + 10 && x - radius > MX) {
vx *= -1;
} // Right Side
if (y - radius < MY + 20 && x + radius > MX + 50 && x + radius < MX + 150 &&
y - radius > MY) {
vy *= -1;
y = MY + 20 + radius;
} //Bottom Side
if (x + radius > MX && y > MY - 10 && y < MY + 10 && x + radius < MX + 100) {
vx *= -1;
} // Left Side
ellipse(x, y, radius * 2, radius * 2);
rect(MX, MY, 100, 20);
}
void mouseMoved() {
MX = mouseX - 50;
MY = mouseY - 10;
if (MX < 0) {
MX = 0;
}
if (MX > 400) {
MX = 400;
}
if (MY < 0) {
MY = 0;
}
if (MY > 680) {
MY = 680;
}
Sorry I do know know how to insert the code very well, I am new to this site, please have mercy haha :)
Cheers
The problem is not that you need to detect corner collision. You've got two other problems:
Problem 1: When you detect a collision, you need to move the ball so it's not colliding with the rectangle anymore.
If you don't, then when the ball intersects the top of the box, you multiply the vy variable by -1. That causes the circle to start moving up. But the next frame, the circle is still colliding with the rectangle, because it hasn't moved up enough yet. So your code detects that collision, multiples vy by -1 again, and the ball moves back down. Next frame the same thing happens, until the ball eventually stop colliding with the rectangle.
Slow the framerate down to see what I'm talking about:
To fix this, you need to "pop" the ball back to a location that's no longer intersecting with the rectangle. That way you know it won't still be colliding in the next frame.
Problem 2: You shouldn't do collision on each side separately. Instead, do collisions between the entire circle and the entire rectangle, and then check one axis of movement at a time.
Checking against one side at a time will lead to plenty of headaches, including the problem where multiple sides are hit at one time. I would also bet that your code isn't doing what you think it is: try adding println() statements to all of your if statements to make sure they're executing when you think they are.
To fix this problem, I would create a collides() function that takes parameters for the next position of the ball, and returns whether the ball will be colliding with any side of the rectangle. Then pass in the next X and Y positions and flip their speeds. It'll look something like this:
if (collides(circleX + vx, circleY)) {
vx*=-1;
}
else {
circleX += vx;
}
if (collides(circleX, circleY + vy)) {
vy*=-1;
}
else {
circleY += vy;
}
You'd also want to add the logic for "popping" the ball so it's no longer colliding.
PS: Did you try searching for your problem on google or the Stack Overflow search? This question is almost an exact duplicate of your question, to the point where I'm pretty sure you're in the same class!
A quick dirty way i have previously achieved this is by first adding bounding boxes to each side and positioning them in a way that if the ball collides with for example on the top right corner i would then have a condition:
If ball intercepts bounds top and bounds right: do this;
I hope this helps!
I'm trying to program a player that rotates towards the mouse and travels towards the mouse at a certain speed. I am using an orthographic camera, however as soon as I set the camera's position to equal the players position, the player rotation stops working and goes all over the place. I believe it might have something to do with the mouse coordinates using the screen and not the world x and y. I have tried unprojecting Gdx.inout.getY/X to no prevail. Any help is much appreciated.
I am using this code to follow player:
cam.position.x = player.getX();
cam.position.y = player.getY();
cam.update();
And this code for rotation:
float mouseX = Gdx.input.getX();
float mouseY = (480 - Gdx.input.getY());
float originX = getWidth() / 2 + position.x;
float originY = getHeight() / 2 + position.y;
double angle = Math.atan2(mouseY - originY, mouseX - originX) * (180/Math.PI) + 90;
if (angle < 0)
angle += 360;
rotation = (float) angle;
direction.x = mouseX - position.x;
direction.y = mouseY - position.y;
double hyp = Math.sqrt(direction.x * direction.x + direction.y * direction.y);
direction.x /= hyp;
direction.y /= hyp;
position.x += direction.x * 2;
position.y += direction.y * 2;
Have you tried projecting (or unprojecting) the points?
ViewPort viewPort = new ... // which ever ViewPort you're using
Vector2 worldPoint = new Vector2(x, y);
Vector2 projected = viewPort.project(worldPoint);
or
Vector2 screenPoint = new Vector2(x, y);
Vector2 unprojected = viewPort.unproject(screenPoint);
My problem might be simple. I've spent most of today thinking of an algorithm(That will pretty probably be a couple if statements) that will determine the direction the mouse is pointing and shoot a bullet in that direction. I already tested the bullets to make sure they shoot by shooting in a defined direction.
how would i go about calculating if the mouse is on the left side of the player, the right side,top side, bottom side, or if it's on the corners of the player ?
Solved: Thanks for all your help but after a day of thinking I came up with a way my self. What I did is use the if statements to determine when I press the mouse down, is it going to be colliding with the top part of the player,bottom,right,left,or corners. Anyway, here is my code. P.S. I used the variable x1 as the mousex, y1 as mousey, x as playerx, and y as player y. The only other variable I have is dx and dy but you should know what those do.
//top
if (x1 > x && x1 < x + 40 && y1 > y - 250 && y1 < y){
dy = -1;
dx = 0;
}
//right
if (x1 > x + 40 && x1 < x + 250 && y1 > y && y1 < y + 40){
dx = 1;
dy = 0;
}
//bottom
if (x1 > x && x1 < x + 40 && y1 > y+40 && y1 < y+250){
dy = 1;
dx = 0;
}
//left
if (x1 < x && x1 > x - 250 && y1 > y && y1 < y + 40){
dx = -1;
dy = 0;
}
//top right corner
if (x1 > x + 40 && x1 < x + 250 && y1 > y - 250 && y1 < y){
dx = 1;
dy = -1;
}
//top left corner
if (x1 < x && x1 > x - 250 && y1 > y - 250 && y1 < y){
dx = -1;
dy = -1;
}
//bottom right corner
if (x1 > x + 40 && x1 < x + 250 && y1 > y + 40 && y1 < y + 250){
dx = 1;
dy = 1;
}
//bottom left corner
if (x1 < x && x1 > x - 250 && y1 > y + 40 && y1 < y + 250){
dx = -1;
dy = 1;
}
You have to implement Mouse move actionlistener if you want to implement shooting while the mouse button is pressed.
Simple equation of line will do it.
Solution: Get the initial point (x0,y0) when button is pressed. While mouse moves when pressed, get (x1,y1) point where the mouse is moving (this constantly changes) - get the line equation - (you have 2 points so find slope and then use one point to get the equation of the line).
Now the direction the bullet fires is the perpendicular to this line through (x1,y1). So you can find the equation of this perpendicular line when the other equation is known. Now to know whether it has to be fired up or down is relative to finding out which side the gun is pointed (direction be stored in a variable)
After all this, when mouse still moves, old point will now be (x1,y1) and new point will be (x2,y2) and you keep implementing these changes.