Ball jumps when colliding with the edge of a rectangle - collision

this is my first bigger programming project, so I'm pretty much a beginner who came across a problem which bugs me for weeks now. Maybe someone can help. :)
I'm building a simple 2D-game. You can control a ball via pitching and yawing the smartphone. Whenever the ball hits the exact edge of an rectangle-obstacle-object, it first sinks into it and then jumps randomly out. It does not happen whenever the obstacles build a straight line.
After a while of debugging I'm pretty sure the error must lie somewhere in the physics part of the game. Here is the code:
float var = gameView.screenSize()/2;
// If the player touches the barrier, its speed will invert
for(RectF r : barrier) {
if(playerSpeedX > 0 && playerX > r.left - var && playerX < r.right + var && playerY >= r.top && playerY <= r.bottom) { playerX = r.left - var; playerSpeedX = -playerSpeedX;} // left
if(playerSpeedX < 0 && playerX > r.left - var && playerX < r.right + var && playerY >= r.top && playerY <= r.bottom) { playerX = r.right + var; playerSpeedX = -playerSpeedX;} // right
if(playerSpeedY > 0 && playerY > r.top - var && playerY < r.bottom + var && playerX >= r.left && playerX <= r.right) { playerY = r.top - var; playerSpeedY = -playerSpeedY;} // top
if(playerSpeedY < 0 && playerY > r.top - var && playerY < r.bottom + var && playerX >= r.left && playerX <= r.right) { playerY = r.bottom + var; playerSpeedY = -playerSpeed;} //bottom
}
var describes half of the size of an obstacle.
Maybe someone can help me. Thanks in advance. :)

I have made some assumptions in the absence if necessary information and laid out the code for better comprehensibility and debug capability. This alone may help you resolve the problem yourself, but in any case is probably how toy should present the question if asking others to assist. Only one conditional if block is shown for clarity, the others might follow the same pattern:
// If the player touches the barrier, its speed will invert
for(RectF r : barrier)
{
if( playerSpeedX > 0 && // If moving right and ...
playerX > r.left - var && // ... ball edge past left of r and
playerX < r.right + var && // ... ball edge not past right of r and
playerY >= r.top && // ... ball centre below top of r and
playerY <= r.bottom) // ... ball centre above top of r
{
playerX = r.left - var; // Move ball to the left
playerSpeedX = -playerSpeedX; // Change motion direction
}
...
}
I am not certain these assumptions are correct, but suggest perhaps that the second and third boolean sub-expressions in the conditional might be changed from > to >=, the that the \\Move ball to the left statement is then unnecessary.
An advantage of laying out the code this way apart from clarity and the ability to clearly comment the purpose of each sub-expression is that when stepping the code in a line-oriented source-level debugger, you can verify the behaviour each sub-expression and statement individually rather then having everything happen at once and have no idea why (or at least being less obvious why). Using a debugger is likley in any case to be a far more efficient method of fixing development problems such as this that posting questions on SO.

Related

Polygon contains point algorithm explanation

I have seen variants of this solution on many different SO questions about polygons containing a point, but the issue is none of the authors give any explanation. I cannot seem to figure out how this function works, and seeing that many other commenters have had their questions about this go unanswered, I thought it best to just ask so there would be a concrete explanation.
Also, are there any cases where this function fails?
UPDATE:
I do know how the raycasting method works, there are some very good resources for that, but I am really confused how this code works specifically.
public static bool(ean) PolygonContainsPoint(Point[] polygon, Point point)
{
bool(ean) result = false;
int j = polygon.Count - 1;
for (int i = 0; i < polygon.Count; i++)
{
if (polygon[i].Y < point.Y && polygon[j].Y >= point.Y || polygon[j].Y < point.Y && polygon[i].Y >= point.Y)
{
if (polygon[i].X + (point.Y - polygon[i].Y) / (polygon[j].Y - polygon[i].Y) * (polygon[j].X - polygon[i].X) < point.X)
{
result = !result;
}
}
j = i;
}
return result;
}
It is the ray casting algorithm described on Wikipedia.
The number of intersections for a ray passing from the exterior of the polygon to any point; if odd, it shows that the point lies inside the polygon. If it is even, the point lies outside the polygon; this test also works in three dimensions.
int j = polygon.Count - 1;
for (int i = 0; i < polygon.Count; i++)
{
// ...
j = i;
}
Explanation: The code loops through each line segment of the polygon, with i being index of current point, and j being index of previous point (previous of first point is the last point, since polygon is closed).
if (polygon[i].Y < point.Y && polygon[j].Y >= point.Y ||
polygon[j].Y < point.Y && polygon[i].Y >= point.Y)
Explanation: If the polygon line segment crosses line O, i.e. if it starts above and ends below, or starts below and ends above.
if (polygon[i].X + (point.Y - polygon[i].Y)
/ (polygon[j].Y - polygon[i].Y)
* (polygon[j].X - polygon[i].X)
< point.X)
Explanation: Calculate the X coordinate where the polygon line segment crosses line O, then test if that is to the left of target point.
result = false;
for each segment:
if segment crosses on the left:
result = !result;
return result;
Explanation: If the number of polygon line segments crossing line O to the left of the target point is odd, then the target point is inside the polygon.

Optimise straight corners A* algorithm for pathfinding

I'm working on the pathfinding for placing roads in a grid based RTS city building game, since I already used the A* algorithm for the pathfinding of vehicles I figured it would be convenient to use it for this task as well. Since our roads are just simple squares I couldn't use the original algorithm since the road would be like the picture: Roadplacement
The original algorithm checks every grid square next to it like this:
for (int x = -1; x <= 1; x++)
{
for (int y = -1; y <= 1; y++)
{
if (x == 0 && y == 0))
{ continue; }
//the rest of the code goes here
I figured the easiest way to avoid those diagonal placements was to block the option to use then, every grid square wouldn't check the 8 squares around it but just 4, in a plus sign:
for (int x = -1; x <= 1; x++)
{
for (int y = -1; y <= 1; y++)
{
if ((x == 0 && y == 0)|| (x != 0 && y != 0))
{ continue; }
//the rest of the code goes here
The only problem with this is that the time to find the path increases dramatically, I mean over large distances it jumps from 6 ms to ~70 ms.
Does anyone have a solution that I could use, or a suggestion for another algorithm better suited for this kind of problems?
Thanks in advance!
You can use XOR to optimize this line:
if ((x == 0 && y == 0)|| (x != 0 && y != 0))
by doing something like this:
if (!(x ^ y))
I'm not sure how much this will speed things up, but it's worth a shot!

Is my method of casting rays efficiant? Is there a better way?

So, ive been delving into the depths of ray tracing and ive come to find that my solution of casting a ray is very in-efficient.
for(int y = 0; y < screenHeight; y++) {
for(int x = 0; x < screenWidth; x++) {
vec3 ray((x * (2 / screenWidth)) - 1, (y * (2 / screenHeight)) - 1, 0);
window.setPixel(x, y, RGB(1, 1, 1));
for(int i = 0; i < castDistance; i++) {
ray.z += 1; //ray position goes in diagnol line(Forwards-left)
ray.x -= 1;
if(ray.x >= quad.x && ray.x <= quad.x + quad.size.x &&
ray.y >= quad.y && ray.y <= quad.y + quad.size.y &&
ray.z >= quad.z && ray.z <= quad.z + quad.size.z) {
window.setPixel(x, y, RGB(1, 0, 0));
}
}
}
}
Is there a better way for me to do an operation like this?
There are a couple of things, you want to take into consideration:
First not all rays are sent parallel to the z axis, while doing ray
casting. Instead you shoot them from an origin (eye) through your
virtual screen.
Second the checking for intersections is not done by tracing the ray
step by step but by checking for collisions with objects of your
scene. In your case this would be one single axis aligned box and it
is easy to calculate the intersection of a ray and an axis aligned
box. For example it is described here:
https://tavianator.com/fast-branchless-raybounding-box-intersections/

Trouble with a heightmap adjusting algorithm

I have a 2D grid of integers. The user can pick any location and increase or decrease its number by one. The algorithm should adjust all eight adjacent locations so there is no more than a difference of one between them.
I've go things working mostly but there must be an edge case I'm missing as after making a few adjustments one of the locations can go wonky (much more of a difference than one).
Here is a screenshot of the grid once it goes wonky.
The javascript to so this is
var moveDown = function (x, y) {
var updated = false;
if (x-1 >= 0 && Math.abs(grid[x][y] - grid[x-1][y]) > 1) {
grid[x-1][y] -= 1;
updated = true;
}
if (x+1 < size && Math.abs(grid[x][y] - grid[x+1][y]) > 1) {
grid[x+1][y] -= 1;
updated = true;
}
if (y-1 >= 0 && Math.abs(grid[x][y] - grid[x][y-1]) > 1) {
grid[x][y-1] -= 1;
updated = true;
}
if (y+1 < size && Math.abs(grid[x][y] - grid[x][y+1]) > 1) {
grid[x][y+1] -= 1;
updated = true;
}
if (x-1 >= 0 && y-1 >= 0 && Math.abs(grid[x][y] - grid[x-1][y-1]) > 1) {
grid[x-1][y-1] -= 1;
updated = true;
}
if (x-1 >= 0 && y+1 < size && Math.abs(grid[x][y] - grid[x-1][y+1]) > 1) {
grid[x-1][y+1] -= 1;
updated = true;
}
if (x+1 < size && y-1 >= 0 && Math.abs(grid[x][y] - grid[x+1][y-1]) > 1) {
grid[x+1][y-1] -= 1;
updated = true;
}
if (x+1 < size && y+1 < size && Math.abs(grid[x][y] - grid[x+1][y+1]) > 1) {
grid[x+1][y+1] -= 1;
updated = true;
}
if (updated) {
if (x-1 >= 0) { moveDown(x-1, y); }
if (x+1 < size) { moveDown(x+1, y); }
if (y-1 >= 0) { moveDown(x, y-1); }
if (y+1 < size) { moveDown(x, y+1); }
if (x-1 >= 0 && y-1 >= 0) { moveDown(x-1, y-1); }
if (x-1 >= 0 && y+1 < size) { moveDown(x-1, y+1); }
if (x+1 < size && y-1 >= 0) { moveDown(x+1, y-1); }
if (x+1 < size && y+1 < size) { moveDown(x+1, y+1); }
}
}
I've got a fiddle here that I've been using to play with things.
How can I fix things to make it work properly?
As pointed out in comments, your code is recursive, and in some situations it hits an infinite recursion.
When that infinite recursion is triggered, the outcome depends on the Javascript engine being used. In some versions, an error message "Uncaught RangeError: Maximum call stack size exceeded" will appear in the error console. (This is the case for Chrome.) Other Javascript engines may handle it differently, and maybe in not-so-nice ways.
The unusual numerical values are displayed only if the Javascript engine interrupts the execution and still refreshes the page rendering (without executing the code further).
You can implement your original idea using for-loops, without using recursion.
You can get some ideas from Morphological Image Processing.

Changing Y-axis of spritesheet with click to move

I'm new here and to programming. I have been searching for a while, though I can't find anything to help with the problem.
I'm trying to make my spritesheet cycle through the different walking frames of my spritesheet, I have done it easily with IsKeyDown but when it comes to using the mouse to walk somewhere it took me a while to nut out a 'bad' solution:
if (destination.X > position.X)
currentFrame.Y = 6;
if (destination.X > position.X && destination.Y >= position.Y + 35)
currentFrame.Y = 7;
if (destination.X > position.X && destination.Y <= position.Y - 35)
currentFrame.Y = 5;
It sort of works, but was wondering if there was a better work-around for this.
What I want is to be able to click on the game-screen and the appropriate sprite row be selected, relative to sprites current position and destination, to make it animate the proper way.
Sorry if this has been asked before, but I have searched around for a few hours before posting this and found nothing.
I am a bit unclear as to exactly what you are doing. Do you only have 2 sprites, one for left and one for right? Thats all i can see in your current code, but you are referring to animating. I am going to assume that you have a full set of sprites to animate walking, in which case I think this tutorial will cover what you need:
http://coderplex.blogspot.ca/2010/04/2d-animation-part-1-basics.html
(more specifically, part 4 of the tutorial: http://coderplex.blogspot.ca/2010/04/2d-animation-part-4-sprite-animation.html )
Basically, you are going to need to set timers to control the sprite animation, as with this type of mouse movement there is no more input (related to moving) between the time you click the mouse and the time the object gets to the destination. So you need to use a timer to determine when the next sprite in the walking animation should be called.
Alternatively, you could further elaborate on your if statements (if currentFrame = 1 then currentFrame = 2, if currentFrame = 2 then currentFrame = 3, etc), but it would be messy and pretty difficult to maintain if you ever make changes to the graphic or the way the sprite is pulled from the spritesheet. It also would most likely animate too fast, and you'd have to use timers to slow it down anyway.
Figured it out I think. Here's my code (hoping it's formatted correctly. Sorry if I'm not meant to answer my own question, thought this might be helpful to someone else):
public Vector2 position = new Vector2(200, 200);
Point frameSize = new Point(48, 92);
Point currentFrame = new Point(0, 0);
Point sheetSize = new Point(9, 8);
float speed = 10;
Vector2 direction;
Vector2 destination;
bool mousePressed = false;
float difference;
KeyboardState currentState;
KeyboardState theKeyboardState;
KeyboardState oldKeyboardState;
enum State
{
Walking
}
State mcurrentState = State.Walking;
TimeSpan nextFrameInterval =
TimeSpan.FromSeconds((float)1 / 16);
TimeSpan nextFrame;
MouseState mouseState;
MouseState oldState;
public void Move()
{
direction = destination - position;
direction.Normalize();
position += direction * speed;
float Xdistance = destination.X - position.X;
float Ydistance = destination.Y - position.Y;
difference = (float)Math.Atan2(Ydistance, Xdistance);
float differ;
differ = MathHelper.ToDegrees(difference);
if (destination.X >= position.X || destination.X <= position.X)
{
currentFrame.X++;
if (currentFrame.X >= 9)
currentFrame.X = 0;
//down = 90dg
if (differ >= 67.6 && differ <= 112.5)
currentFrame.Y = 0;
if (differ >= 112.6 && differ <= 157.5)
currentFrame.Y = 1;
if (differ >= 157.6 && differ <= 180 || differ >= -180 && differ <= -157.5)
currentFrame.Y = 2;
if (differ >= -157.4 && differ <= -112.5)
currentFrame.Y = 3;
if (differ >= -112.4 && differ <= -67.5)
currentFrame.Y = 4;
if (differ >= -67.4 && differ <= -22.5)
currentFrame.Y = 5;
if (differ >= -22.4 && differ <= 22.5)
currentFrame.Y = 6;
if (differ >= 22.6 && differ <= 67.5)
currentFrame.Y = 7;
}
}
public void Update()
{
mouseState = Mouse.GetState();
currentState = Keyboard.GetState();
theKeyboardState = Keyboard.GetState();
if (mousePressed == true)
{
if (Vector2.DistanceSquared(destination, position) >= speed * speed)
{
Move();
}
}
if (mouseState.LeftButton == ButtonState.Pressed && oldState.LeftButton == ButtonState.Released)
{
int mouseY = mouseState.Y;
int mouseX = mouseState.X;
destination = new Vector2(mouseX, mouseY);
mousePressed = true;
}
oldState = mouseState;
if (mcurrentState == State.Walking)
{
#region KB animation
if (currentState.IsKeyDown(Keys.Down))
{
mousePressed = false;
currentFrame.X++;
currentFrame.Y = 0;
if (currentFrame.X >= 9)
currentFrame.X = 0;
position.Y += speed;
}
if (currentState.IsKeyDown(Keys.Up))
{
mousePressed = false;
currentFrame.X++;
currentFrame.Y = 4;
if (currentFrame.X >= 9)
currentFrame.X = 0;
position.Y -= speed;
}
if (currentState.IsKeyDown(Keys.Right))
{
mousePressed = false;
currentFrame.X++;
currentFrame.Y = 6;
if (currentState.IsKeyDown(Keys.Down))
currentFrame.Y = 7;
if (currentState.IsKeyDown(Keys.Up))
currentFrame.Y = 5;
if (currentFrame.X >= 9)
currentFrame.X = 0;
position.X += speed;
}
if (currentState.IsKeyDown(Keys.Left))
{
mousePressed = false;
currentFrame.X++;
currentFrame.Y = 2;
if (currentState.IsKeyDown(Keys.Down))
currentFrame.Y = 1;
if (currentState.IsKeyDown(Keys.Up))
currentFrame.Y = 3;
if (currentFrame.X >= 9)
currentFrame.X = 0;
position.X -= speed;
}
}
oldKeyboardState = theKeyboardState;
#endregion
}
public void Draw(SpriteBatch spriteBatch, Texture2D character)
{
spriteBatch.Begin();
spriteBatch.Draw(character, position, new Rectangle(frameSize.X * currentFrame.X,
frameSize.Y * currentFrame.Y, frameSize.X, frameSize.Y), Color.White, 0, new Vector2(frameSize.X / 2, frameSize.Y / 2), 1, SpriteEffects.None, 0);
spriteBatch.End();
}

Resources