First of all i want to say that my English isnt that good, and I'm a beginner programmer. So take it easy with me :L
So I'm making a 2D game where ground is randomly spawned. And its made of blocks...
How I do this is first i create the blocks and then I add them to Rectangle ArrayList. Blocks render correctly. But they won't take any collision when player hits them.
At this moment collision doesn't work at all. When i press D (right) player runs towards right ignoring collision complitely. When i press A (left) player don't move at all.
First I make this ArrayList:
static ArrayList<Rectangle> BlockArray = new ArrayList<Rectangle>();
Then I give blocks their X,Y,Width,Height... values in a for loop and after that I add them to the list like this :
BlockArray.add(Block[i]);
Then In player class I run this function every render loop. It should tell if player can move to right or left or none...:
ArrayList<Rectangle> rects = WorldGenerator.BlockArray;
for(int i = 0; i < rects.size(); i++) {
// LEFT
if(player.x >= rects.get(i).getX() + rects.get(i).getWidth() && player.y >= rects.get(i).getY() + rects.get(i).getHeight()){
canGoLeft = true;
}
else{
canGoLeft = false;
}
// RIGHT
if(player.x <= rects.get(i).getX() && player.y >= rects.get(i).getY() + rects.get(i).getHeight()){
canGoRight = true;
}
else{
canGoRight = false;
}
}
And then finally when user gives input it checks if those booleans are true or not :
if (Gdx.input.isKeyPressed(Keys.A) && canGoLeft == true){
player.x -= delta * 350f;
}
if (Gdx.input.isKeyPressed(Keys.D) && canGoRight == true){
player.x += delta * 350f;
}
So thats my code. Hopyfully I didn't forget to mention something. And hopefully someone can help me to solve this problem. Also Like I said before I'm beginner at programming so I might have just a stupid fail in game logic...
As far as your collision logic goes, you are changing canGoRight and canGoLeft for each rectangle regardless of previous collision checks. This means that effectively, the last rectangle in your list is the only one being checked for collisions.
To resolve that issue, you'll want to change it to be like this (I just added a ! to the conditions, you should rework them rather just inverting the final result):
ArrayList<Rectangle> rects = WorldGenerator.BlockArray;
canGoLeft = true;
canGoRight = true;
for(int i = 0; i < rects.size(); i++) {
// LEFT
if(!(player.x >= rects.get(i).getX() + rects.get(i).getWidth() && player.y >= rects.get(i).getY() + rects.get(i).getHeight())) {
canGoLeft = false;
}
// RIGHT
if(!(player.x <= rects.get(i).getX() && player.y >= rects.get(i).getY() + rects.get(i).getHeight())) {
canGoRight = false;
}
}
This way, you assume they can move in a given direction, and any single rectangle that would block that direction will prevent movement that direction.
EDIT: I also looked into your conditions, and it looks like any rectangle to the right of the player will prevent them going to the left, not just a rectangle whose right side is up against the left side of the player. A much better comparison would be the difference between the player's and rectangle's half-widths and half-heights. This article can explain in detail why.
As far as bigger picture goes, I mentioned in a comment that collision detection has already been written many times, and libgdx includes solid collision detection code that you should use, rather than writing your own collision detection code.
Related
I have implemented basic collision detection in my top down 2d scrolling game. If the player moves a large distance, it will skip over the areas around it, because the collision detection checks around the player after the movement. As well as this, the player can get stuck in tiles.
I have tried recursively cutting the motion in half to check if it can find a smaller amount of motion that doesn't end in a collision, but I can't seem to get this to work for either problems. It also causes a StackOverflow error.
In the following code, x() represents the player's X location, from the bottom left. y() is the Y location. size is the player's width and height, and prevX and curX are temporary variables. The tiles method gets all tile locations in a certain radius from the player.
move(motionx, motiony);
if (x() - size()/2 < 0)x(size()/2);
if (y() - size()/2 < 0)y(size()/2);
if (x() + size()/2 > game.mapWidth * game.chunkWidth * size)x(game.mapWidth*game.chunkWidth*size - size()/2);
if (y() + size()/2 > game.mapHeight * game.chunkHeight * size)y(game.mapHeight*game.chunkHeight*size - size()/2);
float curX = x();
boolean updateX = true;
boolean updateY = true;
for (float[] tile : game.tiles((float)Math.ceil((double)size()/(double)size))) {
Tile t = game.tile(tile[0], tile[1]);
if (t == null) continue;
if (t.solid && game.collision(game.coordinate(), tile)) {
factor(1.0f - t.bounce, 1.0f - t.bounce);
x(game.prevX);
updateX = false;
if (t.solid && game.collision(game.coordinate(), tile)) {
x(curX);
updateX = true;
y(game.prevY);
updateY = false;
if (t.solid && game.collision(game.coordinate(), tile)) {
x(game.prevX);
updateX = false;
}
}
}
}
if (updateX)game.prevX = x();
if (updateY)game.prevY = y();
I hoped this would flawlessly prevent a player from moving onto a solid tile, but it obviously has problems. I am not great at collisions, but am willing to try anything. It sometimes skips over tiles and/or gets stuck.
i am creating a brick breaker game in java. I am having a small issue. In scenarios where the ball hits two bricks at once, instead of it bouncing back it goes straight through due to the fact that when the ball hits a brick, its velocity is reversed so when it hits two bricks at the same time, the direction of the ball doesn’t change. Here is my code for that part of the method
// ball hits brick
for (int i = 0; i < bricks.size();i++){
if ((ball.getBounds().intersects(bricks.get(i).getBounds())
&& (!bricks.get(i).getHit()))){
bricks.get(i).Hit();
bricks.get(i).Isvisible();
vy = (vy * -1);
scorein ++;
}
}
Vy represents the Y Axis velocity of the ball, reversing the velocity changes the direction of the ball. Please help me thank you.
You can use a flag to detect a single collision on each update. Something like this:
//On each frame
Update() {
vyUpdated = false;
//other game logic
...
// ball hits brick
for (int i = 0; i < bricks.size();i++){
if ((ball.getBounds().intersects(bricks.get(i).getBounds())
&& (!bricks.get(i).getHit()))){
bricks.get(i).Hit();
bricks.get(i).Isvisible();
if (!vyUpdated)
vy = (vy * -1);
vyUpdated = true;
scorein ++;
}
}
I'm referring to the following open source Android pong game:
https://github.com/Grarak/Pong-Android/tree/master/app/src/main/java/com/grarak/pong
I can understand all of the methods and how they work by debugging the code and seeing which method and which condition fires according to what happens on the screen. But there is one method in the whole project that I cannot figure out its purpose, although it is heavily used whenever the ball hits the edges of the screen. I just can't figure out why it is calculated the way it is, and what is the logic of its algorithm.
The method in question is named "getVelocityY" and it's at the bottom of this page:
https://github.com/Grarak/Pong-Android/blob/master/app/src/main/java/com/grarak/pong/Ball.java
Would appreciate any help you can give in figuring this part out. I'll be glad to answer any question you may have and if you'd like I documented the other methods of the project in simple English, in case you'd want that.
Here is a breakdown of that method, even though this is not really a suitable question for SO....
private double getVelocityY(Paddle paddle, float radius) {
Set up 5 hitboxes to determine in what region the ball hit the padddle
Float[][] hitboxes = new Float[5][2];
for (int i = 0; i < hitboxes.length; i++) {
Calculate the minimum and maximum positions for this hitbox
hitboxes[i][0] = (paddle.getLength() / hitboxes.length) * i + paddle.getHeight();
hitboxes[i][1] = (paddle.getLength() / hitboxes.length) * (i + 1) + paddle.getHeight();
Extend the hitboxes at the edges to make sure that the edgeo of the ball (with given radius) will still hit the paddle. Note: this code could have been moved out of the iteration.
if (i == 0) hitboxes[i][0] -= radius;
else if (i == hitboxes.length - 1) hitboxes[i][1] += radius;
}
Determine the change in velocity based on where the ball hit the paddle. If it hit the center, the velocity is unchanged.
for (int i = 0; i < hitboxes.length; i++) {
if (position.y > hitboxes[i][0] && position.y < hitboxes[i][1])
switch (i) {
case 0:
return -4;
case 4:
return 4;
case 1:
return -2;
case 3:
return 2;
}
}
return 0;
}
I'm trying to make a pinball-style game for a school project for the Android in the SDK in Eclipse.
There's a really weird and super frustrating problem in which objects are moving without any code telling them to. Basically, each Wall instance contains 4 Line objects which are used for collision detection with the Ball. These Lines work the first time, but as soon as the ball collides with them once, then that Line somehow moves to another position on the screen.
I've been debugging it, and wouldn't ask if I hadn't already tried everything, but there is honestly no reason for the Line to shift anywhere. The way I handle a collision is by pushing the Ball to be 1px away from the wall, and then given new dx and dy (velocities) to move away. The code for checking for collisions is below, followed by the function that handles a collision to change the ball's position and velocity. Both are methods in the Ball class.
GameElement[] walls = currLevel.getWalls();
int i, j;
Line[] lines;
Line line;
RectF lineBounds;
boolean hadCollision = false;
for (i = 0; i < walls.length & !hadCollision; i++) {
lines = walls[i].getLines();
for (j = 0; j < lines.length & !hadCollision; j++) {
lineBounds = lines[j].getBounds();
if (lineBounds.intersect(point)) {
paint.setColor(Color.BLUE); // Colour ball blue.
reactToCollision3(lines[j]);
// TEST RESET!!!
//this.x = (float)(648+40);
//this.y = (float)(900-30);
hadCollision = true;
//printWallsLines();
}
}
}
and the function to handle the collision is:
public void reactToCollision3 (Line line) {
float liney = line.sy;
float linex = line.sx;
if (line.rotation == 0.0) { // HORIZONTAL EDGE
if (this.y > liney) { // Ball moving upward hits the bottom of a wall.
this.y = liney + this.radius + 1.0f;
} else { // Ball moving downward hits the top of a wall.
this.y = liney - this.radius - 1.0f;
}
this.dy *= -1.0f;
} else { // VERTICAL EDGE
if (this.x > linex) { // Ball moving leftward hits right edge of a wall.
this.x = linex + this.radius + 1.0f;
} else { // Ball moving rightward hits left edge of a wall.
this.x = linex - this.radius - 1.0f;
}
this.dx *= -1.0f;
}
So when I run this right now, the ball will bounce off a wall the first time it hits it, and then that line (edge of the wall) that it hit will be shifted elsewhere, but is not visible because the Wall is drawn as one unit so the Lines that comprise it don't affect the drawing.
If I comment out the lines for "this.x = ..." and "this.y = ...", then this problem doesn't happen anymore. Also, if I uncomment the test RESET lines for setting the ball's position in the above function, then the line doesn't shift then either. But as soon as I run this, it happens again.
I'm going insane looking for why this would happen. Please give me suggestions.
Thank you!
Did you intend to use bitwise &? (See ** in code) Your test for "!hadCollision" will fail and you will also be masking your wall length. I believe you meant to use &&
for (i = 0; i < walls.length **&** !hadCollision; i++) {
lines = walls[i].getLines();
for (j = 0; j < lines.length **&** !hadCollision; j++) {
lineBounds = lines[j].getBounds();
if (lineBounds.intersect(point)) {
paint.setColor(Color.BLUE); // Colour ball blue.
reactToCollision3(lines[j]);
// TEST RESET!!!
//this.x = (float)(648+40);
//this.y = (float)(900-30);
hadCollision = true;
//printWallsLines();
}
}
}
I'm trying to make a platform game. I have the collision code (almost) but there seems to be a bug. I try this code:
for (int i = 0; i < world.ground.size(); i++) {
if (!world.ground.get(i).intersects((int) x, (int) y, player_width, player_height + (int) dy)) {
y += dy;
if (dy < 4) {
dy += 0.1;
}
} else {
dy = 0;
jumped = false;
}
}
But sometimes my character's foot goes through the ground by 2 or 3 pixels. Is there a better way to do this? Please help, thanks.
It seems like you are using a posteriori (discrete) collision detection. This causes your object penetrate through a little every time becuse it activates only when touched or penetrated. You may think to convert this to a priori (continuous) collision detection. This way, it never penetrates the ground because it checks before the collision then adjusts speed or position in order to avoid penetration.
If you dont want to fiddle with this kind, you can just add a correction function that acts before painting.
void foo()
{
//check if below ground
//if yes, displecement upwards until it is above enough
//now you can paint
//return
}
I see you implemented this:
what_you_need_to_make_it_above_ground=(ground_y-feet_y);
//im not sure if dy is ground level so i added second boolean compare
if ((dy < 4)||(ground_y>feet_y)) {
dy += 0.1; // this isnt enough. should be equal to:
dy +=what_you_need_to_make_it_above_ground;
dy +=if_there_are_other_parameters_think_of_them_too;
}