I'm working on an assignment for uni where I have to create a Breakout game in Visual Studio 2010 using C# Win Forms. At the moment, I am concentrating on there being only one brick to be destroyed so I have the mechanics down before expanding on it.
To clarify about my current program: I am using a picture box as a Graphics object and a timer to create the animation effect. The ball can skip, at each frame, between 1 and 10 pixels — this is part of creating a random starting vector for the ball.
This works fine until it comes to checking if the ball has 'hit' the brick I have drawn. What I have is an if statement that checks if the ball is at any of the coordinates on the picture box that corresponds to the outline of the brick. I know that the logic is fine because it works some of the time. However, because of the variation in the 'jumping' of the ball's position, I need to add a buffer area of +/- 5 pixels to my if statement.
This is where the problem arises, because my if statement (two, really) is really complicated as it is:
// Checks if ball hits left side or top of brick
if (((x >= brickX) && (x <= (brickX + 50)) && (y == brickY)) ||
((y >= brickY) && (y <= (brickY + 20)) && (x == brickX)))
{
brickHit = true;
}
// Check if ball hits right side or bottom of brick
else if ((((x >= brickX) && (x <= brickX + 50)) && (y == (brickY + 20))) ||
(((y >= brickY) && (y <= brickY + 20)) && (x == brickX + 50)))
{
brickHit = true;
}
For clarification: x and y are the coordinates of the ball and brickX and brickY are the coordinates of the top-left corner of the rectangle brick (which is 50 pixels wide, 10 pixels high).
Is there any way to simplify the above if statements? If I can make them simpler, I know it'll be much easier to add in the 'buffer' (which only needs to be 5 pixels either side of the brick's outline' to allow for the ball's change in position).
If further clarification is needed, please ask — I'm writing this question at 5:12am so I know I might be a little unclear.
One way you could possible simplify this (and I may be misunderstanding your spec), but you can make a Rectangle out of the bounds of the brick and check the Contains for your x,y point.
Rectangle rec = new Rectangle(brickX, brickY, 50, 20);
rec.Offset(-5, -5);
rec.Inflate(10, 10);
if (rec.Contains(new Point(x,y))
{
brickHit = true;
}
brickHit = new Rectangle(brickX,brickY,50,20).Contains(x,y);
Adding a buffer:
int buffer = 5;
brickHit = new Rectangle(brickX,brickY,50,20).Inflate(buffer,buffer).Contains(x,y);
The Rectagle class can come in handy sometimes.
This worked for me:
var rect1 = new System.Drawing.Rectangle(pictureBox1.Location,
pictureBox1.Size);
var rect2 = new System.Drawing.Rectangle(pictureBox2.Location,
pictureBox2.Size);
if (rect1.IntersectsWith(rect2))
{
//code when collided
}
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.
I'm new at this and I'm making a very simple 2D platformer with a level is loaded from a text file. I'm having trouble to try how to figure out how I can have my character sprite collide with the tiles.
This is an example of a .txt that my game will run:
1,1,1,1,1,1,1,1,
1,1,1,0,0,0,0,1,
1,1,0,0,0,1,0,1,
1,0,0,0,0,1,1,1,
1,0,0,0,0,0,0,1,
1,0,0,0,1,0,0,1,
1,S,0,1,1,0,F,1,
1,1,1,1,1,1,1,1,
I've managed to figure out how to successfully draw them onto the page, but cannot progress further.
My current model has my character colliding with the edge of the screen by having a boolean for Collision equal to true when the edge of the sprite touches the edge of the screen and setting its velocity to 0, but I'm not sure how to do that to block that are generated from a .txt
My current model of drawing a level looks like this:
if (currentState == GameState.Playing)
{
for (y = 0; y <= 7; y++)
{
string[] mapchars = maplines[y].Split(','); //where maplines is each row of characters and mapchars is each individual character//
for (x = 0; x <= 7; x++)
{
if (mapchars[x] == "1")
{
spriteBatch.Begin();
spriteBatch.Draw(block, new Vector2((200 + (50 * x)), ((50 * y))), Color.White);
spriteBatch.End();
}
if (mapchars[x] == "F")
{
spriteBatch.Begin();
spriteBatch.Draw(block, new Vector2((200 + (50 * x)), ((50 * y))), Color.Yellow);
spriteBatch.End();
}
if (mapchars[x] == "S")
{
spriteBatch.Begin();
spriteBatch.Draw(sprite, new Rectangle((200 + (50 * x)), ((50 * y)), 40, 40), Color.White*0.5f);
spriteBatch.End();
}
if (x > 7)
{
break;
}
}
if (y > 7)
{
break;
}
}
}
Where maplines[] is each line of the .txt and where mapchars[] is for each individual character on each line.
If anyone knows a solution to this problem, it would be a great help :)
Thanks.
Don't do that like this ! You are wasting a lot of speed with a game coded like this. I have an issue for you.
First, get all your .txt map into a string[] wich is line is an string. Do that with the method File.ReadAllLines(string yourtxtfilepath).
Once you have done this, create an new 2 dimensional array of Block (Block[,]). You have to create an general abstract class Block wich all your types of blocks (rock, air, grass ...) inherits from its.
Create a for loop who checks all chars in all the string of the array of string you got. In that loop check if the character is an '1' or an 'F' or something else by a case statement. For example, if it was an 'F' add a new GrassBlock to your Block 2 dimensional array.
Finally, after the loop you get your map in your 2 dimensional Block array, wich is perfect to get access to all your blocks in the map.
Just put a foreach loop in the Draw() method to draw each block to your screen by incrementing their positions by the width and the heights of your tiles.
If you don't understand what I said, just do some Google searches to get the necessary knowledge so you will understand. Start by acknowledge what I try to explain you and after, you can concentrate yourself on collisions, wich is more advanced.
I'm trying to find out if a point (mouse click) is within the boundaries of a box based on the top left x/y and bottom right x/y of the box. The position could be positive or negative. As you move up, y value increases, as you move down, y decreases. As you move right, x value increases, as you move left, x decreases.
Vector2 positions could be negative or positive depending on where is clicked.
I thought this would simply work but it doesn't seem to like negative numbers. Any suggestions? My brain is fried tonight after doing Vector arithmetic all night on other things. I wish I was one of you who seem to understand this without problem. ;)
if(point.x >= topLeft.x && point.y <= topLeft.y &&
point.x <= bottomRight.x && point.y >= bottomRight.y)
{
// is within box
}
Edit
Here is how the top left and bottom right are calculated. As it turns out, the problem was not with the above but rather I forgot to add the position.y to the top left calculation below.
Vector2 topLeft = new Vector2(transform.position.x - (transform.localScale.x/2),
transform.position.y + (transform.localScale.y/2));
Vector2 bottomRight = new Vector2(transform.position.x + (transform.localScale.x/2),
transform.position.y - (transform.localScale.y/2));
For anyone coming across this thread, the above check is correct.
Example 1:
Example 2:
I think you've wrongly inverted the boolean expression. It's easier to check for all cases where the click is outside the box.
Semantically, a certain point is outside of a rectangle if it is:
Higher than the highest point of the rectangle
Lower than the lowestpoint of the rectangle
More left than the left side of the rectangle
More right than the right side of the rectangle
If one of these is true, it's outside the box.
if(
clickPosition.x < topLeft.x
||
clickPosition.x > bottomRight.x
||
clickPosition.y < bottomRight.y
||
clickPosition.y > topLeft.y
)
{
//Now you're sure the click was outside the box.
}
Why not using a Rectangle and then check if it contains the point?
var rectangle = new Rectangle(-100,0,100,-100);
if(rectangle.Contains(-25,-25))
{
// is within box
}
For the rest, it appears your code should work. Then there may be a problem with the the assignment of the values of point, topLeft and bottomRight.
the problem with the negative numbers is that your top left isn't your top left
if you say
topY = max(corner1y, corner2y, corner3y)
bottomY = min (corner1y, corner2y, corner3y)
after that your check will work fine again.
I believe you're using the wrong signs on the Y checks.
If your topleft is 50, 100 and the bottom right is 100, 50, then 80 (y) still must be between 50 and 100, it doesn't matter which direction your Y is moving in relation to the screen, as long as you're also inverting your definition of top left.
if(point.x >= topLeft.x && point.y >= topLeft.y && //flipped sign in the second condition
point.x <= bottomRight.x && point.y <= bottomRight.y) //flipped sign in the second condition
{
// is within box
}
If you're not inverting your definition of top left, your original code is correct even for negative numbers.
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.