I am currently creating a brickbreaker clone (yeah, another) and have the ball-brick collision for 1 brick. I have 4 other bricks commented out, because when the ball collides with the brick I have the right code for, it just removes all bricks rather than the specific one it collided with. Also, the ball only collides with the first brick when the ball is near the top left corner of the game screen (pretty far from the actual brick). I'm really not sure what to do, I have tried spacing the bricks out a bit more but that didn't help.
int score = 0;
if ((ballY > picBrk1.Height) && (ballY < picBrk1.Height + 30) && (ballX > picBrk1.Width) && (ballX < picBrk1.Width + 71))
{
// ball rebounds off brick
yChange = -yChange;
// each brick adds 1 to score
score = score + 1;
lblScore.Text = "Score: " + score;
picBrk1.Visible = false;
}
You need to be very clear about the localisation of your bricks.
I suggest adding a UpperLeft property to your Brick class:
public class Brick
{
/* your other properties here */
public Point UpperLeft {get; set;}
}
Make sure UpperLeft value is properly set to the coordinates of the upper left corner of your brick.
My assumption is that your X and Y follow the standard computer image representation where 0,0 is the top left corner of the image and y increases when you go south (which is different from the usual mathematical standard).
Then your collision check will be:
Point ballRelativeToBrick1 = new Point(
ballX - picBrick1.UpperLeft.X,
ballY - picBrick1.UpperLeft.Y)
bool collide = 0 < ballRelativeToBrick1.X && ballRelativeToBrick1.X < picBrick1.Width
&& 0 < ballRelativeToBrick.Y && ballRelativeToBrick.Y < picBrick1.Height
Related
Hi im building a chess game in Unity and my issue is that the queen can move above a friendly piece.
When a piece is selected, an array of legal moves on the board is generated
legalMoves = piece.Move();
I chose to work with vectors here so any move within the list is a 2d Vector.
Then in a loop, I check if any of the moves are within the boundaries of the board and if the move would place the piece on another friendly piece. If it does, then discard that move but my problem is that it should discard all the moves within that direction.
For example: if the queen is on (3,3) and there is a pawn on (3,5), then all the moves (3,6), (3,7) ... should be discarded but not (3,4).
Similarly, if the black queen is on (7,7) and a pawn is on (7,5) then all moves (7,4), (7,3), (7,2) .. should be discarded but not (7,6).
My intuition here was that when a vector has a friendly piece on it, check the direction and the length of all my legal moves against it:
if (dir.normalized.Equals(temp[j].normalized) && dir.SqrMagnitude() < temp[j].SqrMagnitude())
The idea was to remove all the vectors from the legalmoves with the same direction but with greater length, however this doesn't really seem to work because the normalized vectors will not be equal.
Here is the relevant code
foreach (var dir in legalMoves)
{
if (0 <= dir.x && dir.x <= 7 && 0 <= dir.y && dir.y <= 7)
{
//TODO shrink this to 1d array search
if (board[(int) dir.x, (int) dir.y].getPiece() == null)
{
Instantiate(trail, dir, Quaternion.identity);
}
else
{
List<Vector2> temp = legalMoves.ToList();
GameObject[] trails = GameObject.FindGameObjectsWithTag("bullet");
for (int j = 0; j< temp.Count; j++)
{
if ( dir.normalized.Equals(temp[j].normalized) && dir.SqrMagnitude() < temp[j].SqrMagnitude())
{
foreach(var t in trails)
{
// remove trail
if (t.transform.position.Equals(temp[j])) Destroy(t);
}
// remove the move with the same direction
temp.Remove(temp[j]);
}
}
temp.Remove(dir);
legalMoves = temp.ToArray();
}
}
}
here is my problem visualized chess collision issue
Ok, maybe there could be a better solution, however, the way I managed to do it is the following:
Our queen = q is at (3,0) , obstructed piece = k is at (3,6),
If we calculate the offset from k to q we always get an axis which is 0 (either x or y ) in this case it is x.
Since we know an axis is 0 we can check which one is 0 using a boolean, in this case it is x, and simply discard all the legal moves which are on x and above 6 or below 6 for black pieces.
I haven't thought about how to do it if a piece obstructs horizontally, however I'm sure its just a matter of adding/ substracting the right coordinates as above.
Here's my situation I'm making a 2D maze game(XNA 4.0). I have figured out that the best way to do collision detection is by using per-pixel detection. While searching it up on the internet I have found people explaining or showing code for two things colliding(i.e. mouse & player, player & player, two shapes). What I would like to do is have this collision detect whether the player collides with a wall or not(the background is black but the maze walls are white). Could someone explain how to do this or to give some sort of starting point with the code. Much Appreciated.
P.S. A link to a website or anything relating to my question would also be helpful
The best way to go about this CPU-intensive operation is checking for hitbox collision first, then the per-pixel collision.
Most of this code can be found in this helpful video.
static bool IntersectsPixel(Rectangle hitbox1, Texture2D texture1, Rectangle hitbox2, Texture2D texture2)
{
Color[] colorData1 = new Color[texture1.Width * texture1.Height];
texture1.GetData(colorData1);
Color[] colorData2 = new Color[texture2.Width * texture2.Height];
texture2.GetData(colorData2);
int top = Math.Max(hitbox1.Top, hitbox2.Top);
int bottom = Math.Min(hitbox1.Bottom, hitbox2.Bottom);
int right = Math.Max(hitbox1.Right, hitbox2.Right);
int left = Math.Min(hitbox1.Left, hitbox2.Left);
for(y = top; y< bottom; y++)
{
for(x = left; x < right; x++)
{
Color color1 = colorData1[(x - hitbox1.Left) + (y - hitbox1.Top) * hitbox1.Width]
Color color2 = colorData2[(x - hitbox2.Left) + (y - hitbox2.Top) * hitbox2.Width]
if (color1.A != 0 && color2.A != 0)
return true;
}
}
return false;
}
You can call this method like so:
if (IntersectsPixel(player.hitbox, player.texture, obstacle.hitbox, obstacle.texture))
{
// Action that happens upon collision goes here
}
Hope I could help you out,
- GHC
Create a matrix of bools representing your sprite and a matrix of bools representing your maze (the matrix representing your sprite needs to have the same dimensions as your maze).
then you can do something simple like iterate over all x-y coordinates and check whether or not they're both true
// as an optimization, store a bounding box to minimize the
// coordinates of what you need to check
for(int i = 0; i < width, i++) {
for(int j = 0; j < height, j++) {
if(sprite[i][j] && maze[i][j]) {
collision = true
//you might want to store the coordinates
}
}
}
If you want to be very fancy you can flatten your maze matrix and use bit operations
I have a bouncing ball application and I have to extend it to prevent overlapping of the balls.
When ball overlaps another, they should move away as in real life.
I have to extend the given MoveBall method:
private void MoveBall()
{
prevX = x;
prevY = y;
x += xVelocity;
y += yVelocity;
// Is there too closed ball?
foreach (Ball ball in parentForm.balls)
{
distance = Math.Sqrt(Math.Pow((double)(ball.prevX - prevX), 2) +
Math.Pow((double)(ball.prevY- prevY), 2));
overlap = ((radius + ball.radius) - distance);// +ball.radius;
if (ball.id != this.id &&
ball.id != lastID &&
overlap > 0)
{
lastID = this.id;
if (xVelocity > 0) // roading right
{
xVelocity = -xVelocity;
x -= xVelocity - ball.xVelocity;
}
else if (xVelocity <= 0) // roading left
{
xVelocity = -xVelocity;
x += xVelocity + ball.xVelocity;
}
if (yVelocity > 0)
{ // going up
yVelocity = -yVelocity;
y -= yVelocity - ball.yVelocity;
}
else if (yVelocity <= 0) // down
{
yVelocity = -yVelocity;
y += yVelocity + ball.yVelocity;
}
}
}
// ***********************************************
// ***************** END MY CODE *****************
if (x > parentForm.Width - 10 - (radius) || x < 0)
{
if (x < 0) x = 0;
if (x > parentForm.Width - 10) x = parentForm.Width - 10 - radius;
xVelocity = -xVelocity;
}
if (y > parentForm.Height - 40 - (radius) || y < 0)
{
if (y < 0) y = 0;
if (y > parentForm.Height - 40) y = parentForm.Height - 40 - (radius);
yVelocity = -yVelocity;
}
}
x,y, xVelocity, yVelocity, radius, prevX, prevY declared as int.
overlap, distance as double.
When 2 overlap, they are getting stuck. Why?
Unfortunately, I can't upload all source code because there are lot of modules.
I'm using Visual C# Express 2010.
As no Question is asked explicitly, I will assume the question "Why are the balls sticking together?"
You have only shown one loop in source code, that's not enough ;-) To check all possible collisions, you need to check n*(n-1)/2 possible collisions. That is normally done with two loops. You have to put in careful measures to avoid handling the same collision twice.
The reason that your balls get stuck is that you handle the same collision multiple times. For example two balls colliding exactly horizontal: The left one has velocity 5 and x-position of 100. The other one shall have a position of 110 and velocity of -6. When the collision happens:
x is set to 105.
Collision detected: x is set to 104 and velocity to -5.
The other Ball handles the same collision:
He moves according to his velocity to position 104.
Collision handling: His velocity becomes 6 and position becomes 105.
The balls were at 100 and 110 resp. and have been moved to 104 and 105. While the velocities are now pointing away from each other, the collision handling in the following step will invert them again. So the positions are close together and the velocities are changing sign every frame. The balls seem "stuck to each other".
I hope the answer helps you to understand your problem. For a better implementation of an elastic collision (that handles each collision exactly once) look here: Ball to Ball Collision - Detection and Handling
Having stumbled upon similar issues when I made my first attempts at collision detection algorithms, I'll try to describe what I think is the problem here.
Maybe the balls move fast enough so that, before collision is even detected by your code, they are already partially "inside" each other. When collision detection comes and notices that, it does what it's supposed to do: change the planned trajectories of the objects according to the details of the collision that just happened. The problem is that, because these objects got sort-of "merged" before collision detection caught them, they can't get unstuck because collision detection is fired again, trapping them with each other.
If this is the source of the problem, then maybe the above code would work with a small enough velocity vector. Of course, that's not a real solution, but if it does work for very small velocities, it probably confirms my hypothesis and you have some idea regarding how to proceed.
I have an array for the x co-ordinate of the bricks, an array for the y co-ordinates of the bricks and an array to show weather it is visible. My code reads like this:
if (Visible[0] == 1)
{
paper.DrawRectangle(pen, BrickX[0], BrickY[0], 50, 10);
}
and for my collision for the ball to hit the brick, the code reads:
if (Visible[0] == 1)
{
if ((x >= BrickX[0]) && (x <= BrickX[0] + 50))
{
if ((y >= picDisplayBat.Height - 190) && (y <= BrickY[0] + 10))
yChange = -yChange;
Visible[0] = 0;
This does not seem to work as when the ball comes close the brick, the brick dissapears before the collision has happened and the ball goes straight through it. any suggestions?
You're missing brackets around your second if test.
Regardless of the outcome of the test the brick gets set to invisible. Your code is effectively this:
if ((y >= picDisplayBat.Height - 190) && (y <= BrickY[0] + 10))
{
yChange = -yChange;
}
Visible[0] = 0;
You want this:
if ((y >= picDisplayBat.Height - 190) && (y <= BrickY[0] + 10))
{
yChange = -yChange;
Visible[0] = 0;
}
I won't answer your question exactly, but this might help.
It's kind of unobvious what your code does now. Why always [0]?
Just create a class called Brick and a class called Ball:
class Brick {
public double x, y;
public double size;
public bool visible;
};
class Ball {
public double x, y;
public double size;
};
Now introduce the member in the Brick called bool Intersects(Ball ball), which yields true if the ball intersects with the brick (you could simply check this by their bounding boxes).
Now your checks become extremely simple (I assume you have an array of bricks somewhere called bricks).
foreach (Brick brick in bricks) {
if (brick.visible && brick.Intersects(ball)) {
// Hide the brick
brick.visible = false;
}
}
In short, I think you are doing your steps out of order.
Your second routine is perhaps doing too much. It should only determine a collision, and return an identifier for the target of the collision. Then a consuming routine uses that information to adjust projectile trajectory (reflect it back) and finally turn-off the visibility.
By the way, collision detection is a popular venue for what is known as "double-dispatch" invocations. Consider using the visitor pattern (ala Gang of Four) as a way to code this up.
I am stuck trying to figure out how to alter my collision detection to work correctly, i got all my wall objects stacked inside a List and then when the player moves i loop thru each wall object and call the DetectCollision method, this returns true or false depending on if the object is inside the wall or not.
Wall detect collision (X- and Y-coordinate is the position of the wall)
public bool DetectCollision(float x, float y)
{
if ((x >= this.XCoordinate && x <= (this.XCoordinate + this.BlockWidth)) && (y >= this.YCoordinate && y <= (this.YCoordinate + this.BlockHeight)))
return true;
else
return false;
}
So in my player function when the player tries to move, i add the movement to a temporary X,Y coordinate and check if those Collide against the wall, if they do nothing happens, otherwise i move the player.
But i have noticed that it doesn't work as it should be, if i add a piece of wall inside of the gamefield it only checks the bottom right corner for collision detection?
Player movement method:
float x, y;
if (direction == Direction.E)
{
x = LiveObjects.player.XCoordinate - MovementSpeed;
y = LiveObjects.player.YCoordinate;
}
else if (direction == Direction.W)
{
x = LiveObjects.player.XCoordinate + MovementSpeed;
y = LiveObjects.player.YCoordinate;
}
else if (direction == Direction.N)
{
x = LiveObjects.player.XCoordinate;
y = LiveObjects.player.YCoordinate - MovementSpeed;
}
else
{
x = LiveObjects.player.XCoordinate;
y = LiveObjects.player.YCoordinate + MovementSpeed;
}
if (GameMechanics.DetectWallCollision(x, y) || GameMechanics.DetectWallCollision((x + LiveObjects.player.BlockWidth), (y + LiveObjects.player.BlockHeight))
{
OnPlayerInvalidMove(null, new PlayerEventArgs());
return;
}
and the loop for DetectWallCollision is just:
foreach (Wall wall in LiveObjects.walls)
{
if (wall.DetectCollision(x, y))
return true;
}
return false;
Any ideas?
I'm assuming there isn't anything in your world that is infinitely small (i.e. is the size of a pixel). To have true bounding box collision, you've got to consider the size of both objects, not just one.
boolean intersectsEntity(Entity e)
{
return (e.position.x <= position.x + size.x) &&
(e.position.y <= position.y + size.y) &&
(e.position.x + e.size.x >= position.x) &&
(e.position.y + e.size.y >= position.y);
}
That's of course assuming an Entity has a vector for its position and for its size. So size.x == width, and size.y == height.
There is something that disturbs me, you said that the DetectCollision method gets the position of the wall - but if I interpret your code correctly you hand to the DetectWallCollision the x and y parameter which is the position (after movement) of the player and hand that position down to the DetectCollision method...
have you debugged your code to see what coordinates are passed to the collision methods and traced the routes your if-statements are going?
if it is not possible to debug your code for whatever reason - write a trace file - I think the solution will fall into your lap ;)
Your east and west are the wrong way around. With a coordinate system of 0,0 at the top left, increasing positively as you move down or to the right, then a movement West would normally mean a movement left, which means decreasing values of X, and the reverse for East. You are doing the opposite.