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;
}
Related
I have recently started programming games in java. I come from a C# / XNA background and i already have experience in game development.
However I have a problem in my java game. I have a bouncing script which makes a in-game "particle" bounce upon collision with a solid surface, such as the ground.
Here is a snippet of the code that manages the bouncing.
private final void respondY(Rectangle r)
{
if(!r.intersects(getBounds())) // If not colliding, return
return;
if(Yvel > 0) // If falling...
{
if(r.y < Y + Height) //Another collision test
{
Y = r.y - Height; // Set Y to top of object
Yvel *= -bounce; // Bounce (Here is the problem)
onFloor = true;
}
}
else if(Yvel < 0) // If hit ceiling
{
if(Y < r.y + r.height) // Collision test
{
Y = r.y + r.height; // Set Y to bottom of object
Yvel = 0; // No bouncing here
}
}
}
The problem is that the object bounces upon the floor as it should, but after a while the object bounces constantly at the same height where I want it to stop bouncing when it got to that constant height.
NOTE:
Yvel is a int that is the vertical velocity of the object
Bounce is a float that controls how "bouncy" a object is. e.g. 0.5 means that it bounces half as high as it fell
Thanks in advance! Please note that this is my first post so if I make mistakes please point them out in a constructive manner.
The float (and double) types are imprecise. This especially causes problems when dealing with very small numbers - in fact there's a smallest representable number and a finite quantity of possible numbers that can be represented (and bit like quantum physics). The number stored by a float is actually the closest number possible to represent to the calculation result.
What's happening is the velocity calculation never reaches zero, because the result of multiplying the smallest number float can represent by a value >= .5 is itself.
I would force it to zero by putting a low threshold on the calculation result:
Yvel = Yvel * -bounce;
if (Yvel < .000001F)
Yvel = 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();
}
}
}
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.
I've noticed some very strange behaviour with a simple piece of code, I've stripped it down to remove any variables, time-step, acceleration, etc.
I have a shape on the screen, pressing the left side of the screen thrusts the shape right, pressing the right side thrusts left. For some reason the shape favours moving left (speed < 0). It seems to be that it decelerates properly when moving right but when moving left it finishes decelerating then continues for maybe 0.3 seconds before stopping.
float speed;
int x;
Update method for the shape:
speed *= 0.9f;
if (Math.abs(speed) < 0.1f)
speed = 0;
if (Gdx.input.isTouched()) {
if (Gdx.input.getX() < Gdx.graphics.getWidth() / 2) {
speed = 10;
} else {
speed = -10;
}
}
x += speed;
x should be defined as float. I used int because the viewport is set to the screen size but finally realised it needs to have the precision.
I have given a diagram of my current small problem that I need help with. My main purpose is to keep the point from going outside the circle. Nothing else.
The center of the circle is positioned at (x, y).
I only solved a little bit of the problem, and that is the collision detection part of my problem, as given below:
public void bound(Point p, Circle c){
double distance = Math.hypot(p.x - c.x, p.y - c.y);
if (distance >= c.radius){
//Clueless from here on out.
}
}
The part where I left a comment is the spot I couldn't figure anything out. I did tried to set the point's velocityX and velocityY to 0, but I realized the point will just stay put whenever it touches the circle.
So, I'm sort of stuck.
I have resolved this issue.
public void reflect(Hole h){
//R = -2*(V dot N)*N + V
//N is normalized.
double nx = (this.position[0]+this.diameter/2) - (h.x+16);
double ny = (this.position[1]+this.diameter/2) - (h.y+16);
double nd = Math.hypot(nx, ny);
if (nd == 0)
nd = 1;
nx /= nd;
ny /= nd;
double dotProduct = this.speed[0]*nx+this.speed[1]*ny;
this.speed[0] += (float)(-2*dotProduct*nx);
this.speed[1] += (float)(-2*dotProduct*ny);
}
public void reflectResponse() {
for (int i = 0; i <= 1; i++) {
position[i] -= speed[i];
speed[i] *= 0.992f;
}
}
I tried Oli Charlesworth's method from the comments, but it made things more... "complicated" than I expected. Someone else mentioned I used a completely 100%, vector-based algorithm, since I'm relying a lot on vector-based movements.
TIPS TO THOSE WHO DO READ THIS:
If you're working on object movements and collisions with vectors, seek vector-based algorithms.
If you're working with angles (either degrees or radians), use Oli Charlesworth's method.