So I'm creating a game in XNA using C#, and I have walls that are created in random positions, and I'm trying to stop things walking through them/be teleported to points on the screen when they hit them. (Note, Left and right now works, it's just the top and bottom)
if (collision(wallRect[k], wallColours, pacmanRect, pacmanColor, 0))
//Collision works, not an issue here
{
if (pacmanRect.Bottom > wallRect[k].Top && pacmanRect.Top < wallRect[k].Bottom)
{
if (pacmanRect.Right >= wallRect[k].Left
&& pacmanRect.Right < wallRect[k].Right)
{
pacmanPos.X = wallRect[k].X - frameSize.X;
//frameSize is the size of the pacman sprite
}
else if (pacmanRect.Left <= wallRect[k].Right
&& pacmanRect.Left > wallRect[k].Left)
{
pacmanPos.X = wallRect[k].X + frameSize.X / 8;
}
}
else if (pacmanRect.Right > wallRect[k].Left && pacmanRect.Left < wallRect[k].Right)
{
if (pacmanRect.Bottom >= wallRect[k].Top)
{
pacmanPos.Y = wallRect[k].Y - frameSize.Y / 8;
}
else if (pacmanRect.Top <= wallRect[k].Bottom)
{
pacmanPos.Y = wallRect[k].Y + frameSize.Y / 8;
}
}
playSound(collisionSoundInstance);
}
That is the last point in the game loop where pacmanPos is updated. So how would I make it so that the walls are actual walls, and you can't walk through them?
if (pacmanRect.Bottom > wallRect[k].Top && pacmanRect.Top < wallRect[k].Bottom)
Does this make sense? I don't think it's possible for Pacman to be above the top of the wall, but simultaneously below the bottom of it (unless maybe your y-coordinate system is positive in the down direction, and even then the logic still looks fishy)
I would recommend drawing one of the states out on paper, then going through your code in your mind line-by-line given what you see on your paper. For example, draw the state of Pacman's bottom-most edge overlapping the wall's top-most edge. Then walk through your code and see what happens.
If you have a game which is restricted to two dimensions you should use Box2D which makes your life much easier.
See comment if you want to stay to your own code
Related
(Before you read, I'm very nervous about posting here since my previous question got a lot of negative responses... Please try and be nice. I am a student and can't write "Perfect" code yet)
I'm currently trying to figure out how to make a mosquito (Texture2D) swoop downwards and then come back up to it's original position.
Currently the mosquitoes simply move left and right within the screen bounds, with no Y movement.
I've stepped it through a debugger and observed it's Y coordinate. My mosquitoes are indeed swooping down and then back upwards again... However, they do it so quickly that it isn't visible to the human eye.
Therefore I need a way to smoothly swoop them down so that it's actually visible.
I am currently unable to embed images into my posts, however I have made a GIF demonstrating the effect that I want.
Here's a link to my GIF
Things I've tried:
Copied the first line of my movement code (seen below) and changed it so that it would only affect the Y coordinates.
Result: Mosquitoes were still swooping too fast to see.
Changing my mosquitoe's velocity.Y to include a Y that isn't 0, so that my movement code will also change the Y position instead of just the X position.
Result: Game was stuck in an infinite loop since my movement code is found in the Update() function, and the code never got out of the loop so that it could update the position...
Here's the movement code I have in my Update.
The mosquitoes move all the way to the right, then all the way to the left.
internal void Update(GameTime GameTime)
{
position += velocity * (float)GameTime.ElapsedGameTime.TotalSeconds;
// Reverses the direction of the mosquito if it hits the bounds
if (position.X <= gameBoundingBox.Left ||
position.X + animationSequence.CelWidth > gameBoundingBox.Right)
{
velocity.X *= -1;
}
}
And here's the actual Swoop() code that I have...
internal void Swoop(GameTime gameTime)
{
float originalYPosition = position.Y;
bool currentlySwooping = true;
while (currentlySwooping)
{
position.Y++;
if (this.BoundingBox.Bottom >= gameBoundingBox.Bottom)
{
currentlySwooping = false;
}
}
while (!currentlySwooping && position.Y > originalYPosition)
{
position.Y--;
}
}
I don't ask questions on here too often, so I'm sorry if I'm using an incorrect format or if I've given too little information.
If you need to know anything else then please let me know.
There are many ways of implementing this, but this should do it.
float originalYPosition = position.Y;
int swoopDirection = 0;
internal void Update(GameTime GameTime)
{
/* Same update code */
if (swoopDirection != 0)
{
position.Y += swoopDirection;
if (swoopDirection == 1 && this.BoundingBox.Bottom >= gameBoundingBox.Bottom)
{
swoopDirection = -1;
}
else if (swoopDirection == -1 && position.Y <= originalYPosition)
{
swoopDirection = 0;
}
}
}
internal void Swoop()
{
swoopDirection = 1;
}
Basically, we have a variable swoopDirection that changes depending on the state of the swoop (1 when going down and -1 when going up). In the update method we check that swoopDirection != 0 (we are swooping). If we are swooping we add the direction to the Y axis and check that we aren't out of bounds. If we touch the bottom we set swoopDirection to -1 so we go up. If we are at the original position swoopDirection is set to 0 and we stop swooping.
I'm trying to make it possible to drag an object. This object can only rotate so much. (Similair to a door).
Here is the code abit edited that rotates an object which works.
I have 2 vectors for maxrotation and minrotation.
This code will be called whenever the user is dragging the interactible object. (like update but only when dragged)
if (GestureManager.Instance.IsNavigating &&
HandsManager.Instance.FocusedGameObject == gameObject)
{
//speed and navigiation of rotation
float rotationFactor;
rotationFactor = ManipulationManager.Instance.ManipulationPosition.y * RotationSensitivity;
totransform.Rotate(new Vector3(rotationFactor, 0, 0));
}
It would be great if I could use an if statement here. And I tried quite some things but it's still not working.
As stated the code paste here works. The object should be dragable but only up to a certain points.
totransform is the transform that will be rotated
Any ideas would be great and most appreciated.
Kind regards.
I think you want to look at eulerAngles. Check the values you're getting then set an if-statement before doing the rotation. This is a sample code for you to find the values you want:
if (GestureManager.Instance.IsNavigating &&
HandsManager.Instance.FocusedGameObject == gameObject)
{
//speed and navigiation of rotation
float rotationFactor = ManipulationManager.Instance.ManipulationPosition.y * RotationSensitivity;
Debug.Log(totransform.eulerAngles);
if (totransform.eulerAngles.x < 100) {
totransform.Rotate(new Vector3(rotationFactor, 0, 0));
}
}
So here is the solution that worked for me. First I declare the movement variable (not seen down below, which is 2 in this case). Then I track the distance covered and put a limit on that.
Of course there are some improvements to this code like use movement instead of 2. But because of time constraints I didn't do it.
if (GestureManager.Instance.IsNavigating &&
HandsManager.Instance.FocusedGameObject == gameObject)
{
//here we get the movement direction and set it in movement.
if (GestureManager.Instance.NavigationPosition.y > 0)
{
movement = 2;
}
else if (GestureManager.Instance.NavigationPosition.y < 0)
{
movement = -2;
}
//the first part is false if we reach higher then maxdistance and the movement is going up
//the second part is false if we reach the lower distance and the movement is going down.
if ((!(distance > maxdistance.x) || movement < 0) && ((!(distance < mindistance.x) || movement > 0)))
{
//here we add the movement to the distance so we know if it gets closer or further
distance += movement;
//here we rotate
totransform.Rotate(new Vector3(movement, 0, 0));
}
}
I have to make a game with Windows Forms for school. My game consists of a user having to get through a maze. I'm trying to prevent my user from going straight through the walls using collision detection, but am getting stuck because of the varying shape of the rectangles being used to represent walls. Here's an image of the game. This question may be similar to this one, however with my movement I believe that it is quite different, as I don't have a grid system or graphical map laid out.
As you can see, the walls are fairly thick. Each wall is represented by a C# Rectangle, as is my Player image (the little yellow ghost). I know how to determine if the player is crossing through these walls using C#'s IntersectsWith(Rectangle r) method, but I'm not exactly sure how to use this information in order to handle the collision and STOP the player from moving through the walls at all.
Here's what I've tried:
This is my actual movement code. Because the game is built in WinForm, the movement is triggered by keyboard events such as OnKeyPressed and OnKeyUp
public void Move(Direction dir)
{
HandleCollision(); // Handle collision while player is trying to move.
if (dir == Direction.NORTH)
{
this.y -= moveSpeed;
}
if (dir == Direction.SOUTH)
{
this.y += moveSpeed;
}
if (dir == Direction.EAST)
{
this.x += moveSpeed;
}
if (dir == Direction.WEST)
{
this.x -= moveSpeed;
}
}
This is my collision method, HandleCollision():
private void HandleCollision()
{
// First, check to see if the player is hitting any of the boundaries of the game.
if (this.x <= 0)
{
this.x = 0;
}
if (this.x >= 748)
{
this.x = 748;
}
if (this.y <= 0)
{
this.y = 0;
}
if (this.y >= 405)
{
this.y = 405;
}
// Second, check for wall collision.
foreach (Rectangle wall in mazeWalls)
{
if (playerRectangle.IntersectsWith(wall))
{
if (player.X > wall.X) { player.X += wall.Width; }
else if (player.X < wall.X) { player.X -= wall.Width; }
else if (player.Y > wall.Y) { player.Y += wall.Height; }
else if (player.Y < wall.Y) { player.Y -= wall.Height; }
}
}
}
Now this code above kind of works. However, because the player's coordinates are having the wall's width/height added to it, this makes some weird collision teleportation across the map where the player ends up bouncing around. So what would be the most efficient way of going about implementing a collision detection system which can replace all the code within the if (playerRectangle.IntersectsWith(wall)) { block?
In the move, save the current position, perform the move, check for collision, and if true, restore the old position.
For this to work, HandleCollision would return a Boolean value, true for each successful test (successful=collision detected), false at the end if no condition was met. The method would not modify any x or y value at all. To reflect its new function, this method should be renamed to CheckCollision.
From the gif in your other post it seems that your playing field is divided into squares, and walls and sprite are composed of multiple squares? Then your move should proceed in increments of one square until the intended increment is met. For each square the collision has to be checked.
For a more advanced method with only one check per move you need some linear mathematics. The collision check will need the current point P and the increment d of the move. You need to check if between P and P+d the wall is crossed. This is usually indicated by a sign change in a linear condition. For a vertical wall W to the left of P, if d points to the wall, P.x+d.x-(W.x+W.width) will be negative. Determine s with W.x+W.width<=P.x+s*d.x. For horizontal walls, you have to do the same check in the y-coordinate. Take the minimal s over all objects hit and P+s*d as the new position.
I have 2 images(bar and greenBall1). bar can be move up and down depends on the user response. While, greenBall1 is moving around the screen. I want to do an image collision if both the images touch each other, greenBall1 will change its velocity. The codes that I have for greenBall1 are as below.
private void OnUpdate(object sender, object e)
{
Canvas.SetLeft(this.GreenBall1, this.greenBallVelocityX + Canvas.GetLeft(this.GreenBall1));
Canvas.SetTop(this.GreenBall1, this.greenBallVelocityY + Canvas.GetTop(this.GreenBall1));
var greenBallPositionX1 = Canvas.GetLeft(this.GreenBall1);
var greenBallPositionY1 = Canvas.GetTop(this.GreenBall1);
var maximumGreenBallX = ActualWidth - this.GreenBall1.ActualWidth;
var maximumGreenBallY = 400 - this.GreenBall1.ActualHeight; //Improvise: Instead of 360, get maximum height of canvas
if (greenBallPositionX1 > maximumGreenBallX || greenBallPositionX1 < 0)
{
this.greenBallVelocityX *= -1;
}
if (greenBallPositionY1 > maximumGreenBallY || greenBallPositionY1 < 0)
{
this.greenBallVelocityY *= -1;
}
}
I don't see a reference to the bar object in your code. But the detection of the collision is much easier than the physics of handling the collision. There are several schools of thought to something as simple as Pong collision, and the way you choose to handle it depends on the gameplay you want.
Here is an easy way to detect and handle the collision, simply by negating the X velocity just as you are handling the wall collisions:
if(greenBallPositionX1 < leftBar.X || greenBallPositionX1 > rightBar.X)
{
this.greenBallVelocityX *= -1;
}
Keep in mind you might also have to take into account the width of the bar or the ball depending on where the coordinate is in relation to the image. For example:
if(greenBallPositionX1 < (leftBar.X + leftBar.Width) || greenBallPositionX1 > rightBar.X)
{
this.greenBallVelocityX *= -1;
}
You may also want to at this point move the ball away from the paddle one step to avoid the collision being detected more than once.
Hopefully this answers what you were asking, but if you were looking for a more complex reaction to the collision detection, then you may want to check out the following discussion on Pong type collisions here.
i think this might help you ....
.
Rectangle ballRect = new Rectangle((int)ballposition.X, (int)ballposition.Y, ballsprite.Width, ballsprite.Height);
Rectangle handRect = new Rectangle((int)paddlePosition.X, (int)paddlePosition.Y, paddleSprite.Width, paddleSprite.Height/2);
if (ballRect.Intersects(handRect))
{
// Increase ball speed
ballSpeed.Y += 50;
if (ballSpeed.X < 0)
ballSpeed.X -= 50;
else
ballSpeed.X += 50;
// Send ball back up the screen
ballSpeed.Y *= -1;
}
in this whenever the ball will collide with hand it will increase its speed and change its direction i think that is the think you are looking for as it is also a rectangular collision.
make a class which will give you value that wether two rects will collide or not
public bool Intersects(Rect r1,Rect r2)
{
r1.Intersect(r2);
if(r1.IsEmpty)
{
return false;
}
else
{
return true;
}
}
then you can use
if(Intersects(r1,r2))
{
MessageBox.Show("Collison Detected");
}
I'm currently writing a platforming game in XNA.
My collision testing currently operates by testing the bounding box of the player with every tile's bounding box by running through a foreach loop. However, I can't figure out how to test whether the player is NOT touching any blocks.
How would I run through my array and test for if they player isn't touching any blocks so that I can check if he is in mid air? Any help or advice would be greatly appreciated. Thank you in advance!
/////////////////////////////////////
My collision code is
if (personRectangle.TouchTopOf(newRectangle))
{
onGround = true;
test = false;
test2 = true;
}
The corresponding bool test is
public static bool TouchTopOf(this Rectangle r1, Rectangle r2)
{
return (r1.Bottom >= r2.Top - 1 &&
r1.Bottom <= r2.Top + (r2.Height / 2) &&
r1.Right >= r2.Left + (r2.Width / 5) &&
r1.Left <= r2.Right - (r2.Width / 5));
}
And this piece of code tests collision in the Game1.cs update.
foreach (CollisionTiles tile in map.CollisionTiles)
player.Collision(tile.Rectangle);
Which is a list of tiles in my map class
private List<CollisionTiles> collisionTiles = new List<CollisionTiles>();
XNA Rectangles have a built-in intersects method:
if (rect1.Intersects(rect2)){
...
}
just loop through the tile rectangles and call intersects on each one. To make it more efficient you should map the player coords onto world coords and determine the tiles nearest to the player, doing this you can narrow down the number of tiles you need to loop over.
EDIT: for clarification, you could have:
bool collision=false;
foreach (CollisionTiles tile in map.CollisionTiles) {
if(personRectangle.Intersects(tile.Rectangle)) {
collision =true;
break;
}
}
Then if collision is true you know there was a collision somewhere.
Unless you have a reason not to, keep it simple. Just keep track of how many things you collided with. If your count ends up being 0 then you didn't collide with anything.
Without worrying about modifying / optimizing any of the code you have, it could be something like:
int touchedCount = 0;
foreach (CollisionTiles tile in map.CollisionTiles)
{
if (player.Collision(tile.Rectangle))
{
touchedCount++;
}
}
if (touchedCount == 0)
{
//You did not collide with anything
}
Then inside your collision method do something similar to keep track of your checks and if you collided at all. This would probably be easiest using Rectangle.Intersects as the other answer suggests.