having trouble implementing physics to ball collision program - c#

I'm currently working on a simple ball collision program in C#, where an indeterminate amount of balls bounce around the screen, each being added to the program on a button click. So far I've gotten everything working, and I have a basic collision system. Now, I'm trying to add more realistic physics to the balls.
The thing is, I have little understanding of physics. I've been reading a bit about vector physics and I get the gist of it, but I'm not quite making the connection between what I've read and how I'm supposed to implement these concepts programmatically. Could anybody provide me some resources on how one is actually supposed to implement vector physics to something like a simple ball collision program like I've written?
Here's what I have right now. It's basically just two booleans determining whether my ball goes in one of four directions. When two balls collide, they just pass their directions to each other.
public void newball(PaintEventArgs e, int panelWidth, int panelHeight)
{
//Detects walls of form. if it detects a wall or another ball, it bounces
if (X >= panelWidth)
{
bounceX = true;
}
else if (X <= 25)
{
bounceX = false;
}
if (Y >= panelHeight )
{
bounceY = true;
}
else if (Y <= 25)
{
bounceY = false;
}
//balls only go in four directions right now have to implement vector physics.*/
if (bounceX == false)
{
X = X+2;
}
else if (bounceX == true)
{
X = X -2;
}
if (bounceY == false)
{
Y = Y+2;
}
else if (bounceY == true)
{
Y = Y-2;
}
//this draws the ball on the panel.
Pen clsPen = Pens.Black;
Color color = Color.Black;
SolidBrush brush = new SolidBrush(color);
e.Graphics.DrawEllipse(clsPen, X - 25, Y -25, 25, 25);
e.Graphics.FillEllipse(brush, X-25, Y-25, 25, 25);
}
And here are some of the things I've read:
2D Collisions, Vectors

Related

Best Collision Detection in Monogame

I tried creating an Arknoid game using XNA some years ago. Unfortunately, with the busy life I didn't manage to finish it. I found my old code and tried importing it to Monogame. The problem I'm having is the Collision detection. As you can see the ball is supposed to be deflecting outside the bar but for some reason my code is not working
I have a class called Ball.cs and Below is the code I use to check for Collision. I then pass the rectangle of the bar.
public bool CheckCollision(Rectangle rect)
{
Rectangle rOut;
rOut = Rectangle.Intersect(this.rect, rect);
if (rOut.Width > 0 && rOut.Height > 0)
{
ChangeDirection(false);
//isGoingLeft = !isGoingLeft;
//isGoingUp = !isGoingUp;
return true;
}
return false;
}
UPDATE: Here's the code where it performs the Collision Detection. ballPlayer is the Ball, barPlayer is the blue bar. Brick are bricks. So when it moves
if (ballPlayer.isBallDead == false)
{
ballPlayer.CheckCollision(barPlayer.Rect);
ballPlayer.Draw(spriteBatch);
ballPlayer.hasTouched = false;
for (int x = 0; x < _bricks.Count; x++)
{
if (_bricks[x].Visible == true)
{
if (_bricks[x].CheckCollision(ballPlayer))
{
_bricks[x].ChangeFace(_textures[_bricks[x].BrickLife]);
}
}
_bricks[x].Draw(spriteBatch);
}
}

OverlapSphere centering incorrectly

I am attempting to use an overlapSphere to determine whether a tile within a tile map contains a game object. Then, if the tile is not already occupied, a new game object will be spawned in that tile (if certain other conditions are met). I'm trying to prevent game objects from overlapping with one another. However, I am having trouble centering the spheres about the right location.
for (int x = 0; x < width; x++)
{
for (int y = 0; y < height; y++)
{
Vector3 tilePos = tileMap.GetCellCenterWorld(new Vector3Int(x, y, 0));
if (terrainMap[x, y] == blocked)
{
bool spawn = detectOverlap(tilePos, obstCheckRad);
if (spawn)
{
GameObject obstacle = Instantiate(obstaclePrefab) as GameObject;
obstacle.transform.position = tilePos;
obstacle.transform.eulerAngles = new Vector3(0, 0, (Random.Range(0, 359)));
}
}
}
}
}
public bool detectOverlap (Vector3 center, float radius)
{
Collider[] collider = Physics.OverlapSphere(center, radius);
if (collider.Length == 0)
{
return true;
}
else
{
return false;
}
}
I am using "GetCellCenterWorld" to as the center of my overlapSpheres, however they always seem to originate in the bottom left corner of the map, causing this region of the map to be completely empty, and objects elswhere in the map to still overlap with one another. (see image)
My confusion is based around the fact that I am using the same vector3 (tilePos) to place down the game objects. The objects are all moved to the correct position, however, the overlapSpheres all stay at the bottom left.

Remembering a direction, moving to a point, then changing direction. XNA

I'm making a pacman clone in XNA.
So far I've drawn the tile map using 2D array, added the pills using another 2D array and made a 2D array that allows movement of pacman.
In the actual game you can press right whilst moving up, and it will wait until you're able to move right and the turn.
I have a system in place that allows a turn only when the spritePosition % 32 = 16.
This means the sprite will be centred between the walls.
I need the program to remember the last key pressed or move to the right position before turning, but i cant find a way of doing it.
Here is a bit of the code that covers what I'm trying.
public void MovementCheck()
{
presentKey = Keyboard.GetState();
spritePosition = spriteVelocity + spritePosition;
pacManRec = new Rectangle((int)spritePosition.X, (int)spritePosition.Y, pacManTex.Width, pacManTex.Height);
spriteOrigin = new Vector2(pacManRec.Width / 2, pacManRec.Height / 2);
//Press Right
if (presentKey.IsKeyDown(Keys.Right) && pastKey.IsKeyUp(Keys.Right))
{
Right();
}
}
private void Right()
{
direction = "right";
//if the next block in tile map to the right is a 1, and the sprite is centred - allow a turn
if (inputMap[(int)Math.Floor(spritePosition.Y / 32), (int)Math.Floor(spritePosition.X / 32) + 1] == 1 && (spritePosition.Y % 32 == 16))
{
rotation = ((float)Math.PI / 180);
spriteVelocity.X = 0;
spriteVelocity.Y = 0;
spriteVelocity.X = movementSpeed;
}
}
Only the right key is shown, the others are similar but the directions all change and the checks to the tile map are changed accordingly. (+1 on the X here)
ive tried things like
while (spritePosition.Y % 32 != 16)
{ spritePosition = spriteVelocity + spritePosition; }
but that just makes the sprite shoot up the screen, (kinda obviously) :(
and I tried a new Method before the Right() call
bool RightCheck()
{
if ( CONDITIONS MET HERE )
return true
else
{
//dont remember if I used this line, but something similar
spritePosition = spriteVelocity + spritePosition;
RightCheck()
}
return false; //allows program to build
}
Just an causes infinite recursion.
One solution is adding a int counter = 0; which you update in your gameloop (with counter++;) every frame/time-step. Set to 0 everytime you make a valid input and save that input.
Outlined code:
public class GameClassWhereUpdateIsDone
{
private enum Directions { None, Up, Down, Left, Right };
private int counter = 0;
private Directions currentDirection; // Current movement-direction
private Directions lastInput; // Last direction from input
public void Update(...)
{
var keyboardState = Keyboard.GetState();
if(keyboardState.IsKeyPressed(Keys.Right))
{
counter = 0;
direction = Directions.Right;
}
if(currentDirection != lastInput && counter < 5) // Allow turning 5 updates ahead.
{
// Player want to turn
if(AllowedToTurn(lastInput)
{
currentDirection = lastInput;
}
}
MoveDirection(currentDirection);
counter++;
}
private bool AllowedToTurn(Directions direction)
{
if(direction == Directions.Right)
{
return RightCheck();
}
}
}
The key idea is to keep track of movement direction and last direciton that was input...
In the original Pac-Man "pre-turning" was actually used, meaning you would start moving diagonally if you turned ahead of a corner according to: http://home.comcast.net/~jpittman2/pacman/pacmandossier.html which is an interesting read.

Player does not stop when colliding with block [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 4 years ago.
Improve this question
I'm trying to make it so my player comes to a complete halt when he hits a block, but can become unstuck if he presses a certain key(s). Example: Player is going down and hits a block. He stops, but if presses W, A, or D, he can move up, left, or right. Here's what I currently have for the code.
In this case, sp means speed, blocksp means his speed when he is being blocked. (This.Sprite), in this case, is referring to the block that stops him.
bool Blocked = false;
float Bottom = -32;
float Left = -32;
float Right = This.Sprite.GetWidth() - 32;
float Top = This.Sprite.GetHeight() - 32;
int x = 0;
int y = 0;
float sp = 1.59f;
float blocksp = 0.00f;
Sprite Player = This.Game.FindSprite("GuySprite");
if (This.Sprite.CollisionWithSprite("GuySprite") != null)
{
if (Player.Position.Y > Top)
{
Blocked = true;
Player.Velocity = new Point2D(x, y) * blocksp;
Player.Animation = 0;
if (This.Game.IsPressed(InputKey.W) || This.Game.IsPressed(InputKey.A) || This.Game.IsPressed(InputKey.D))
{
Blocked = false;
Player.Velocity = new Point2D(x, y) * sp;
Player.Position.Y -= 0.85f;
}
}
if (Player.Position.Y < Bottom)
{
Blocked = true;
Player.Velocity = new Point2D(x, y) * blocksp;
Player.Animation = 0;
if (This.Game.IsPressed(InputKey.S) || This.Game.IsPressed(InputKey.A) || This.Game.IsPressed(InputKey.D))
{
Blocked = false;
Player.Velocity = new Point2D(x, y) * sp;
Player.Position.Y += 0.85f;
}
}
if (Player.Position.Y < Right)
{
Blocked = true;
Player.Velocity = new Point2D(x, y) * blocksp;
Player.Animation = 0;
if (This.Game.IsPressed(InputKey.S) || This.Game.IsPressed(InputKey.A) || This.Game.IsPressed(InputKey.W))
{
Blocked = false;
Player.Velocity = new Point2D(x, y) * sp;
Player.Position.Y -= 0.85f;
}
}
if (Player.Position.Y > Left)
{
Blocked = true;
Player.Velocity = new Point2D(x, y) * blocksp;
Player.Animation = 0;
if (This.Game.IsPressed(InputKey.S) || This.Game.IsPressed(InputKey.W) || This.Game.IsPressed(InputKey.D))
{
Blocked = false;
Player.Velocity = new Point2D(x, y) * sp;
Player.Position.X += 0.85f;
}
}
}
Currently, if my player touches any side of the block and continues his movement that the block stops, the player will move in an erratic direction and does not stop at the block. Any ideas?
Edit
Ok
The player is running towards the block so he'll hit the left side in the next frames.
So that the following condition ll be true.
if (This.Sprite.CollisionWithSprite("GuySprite") != null)
Now you have to implement a method to find out which side the player collided with.
Actually your code is confusing me since:
Player.Velocity = new Point2D(x, y) * ...;
will always be the zero vector because x = y = 0
I'd do it like this :
float xDistance=0f, yDistance=0f;//this ll be explained later on
If(Player.Velocity.X > 0) //he is running to the right so he can hit the left side
xDistance=mayHitLeft();
Else If(Player.Velocity.X < 0)
xDistance=mayHitRight();
If(Player.Velocity.Y > 0) //In my case positive Y means downwards so can hit top
yDistance=mayHitTop();
Else If(Player.Velocity.Y < 0)
yDistance=mayHitBot();
Now we have to find out if the player hit the bot/top edge or the left/right edge or maybe both.
let's assume he is falling and was running to the right before.
so Player.Velocity.X > 0 and Player.Velocity.Y > 0
This means the function mayHitLeft(); and mayHitTop();
will be called.
I don't know how the collisionWithSprite function works.
But as always we take the worst case like this one blue is the block and orange the player.
This is the frame before hitting and no collision was detected by now. so in the next frame both functions would detect a collision but which is the right one. As we see it is colliding with the top. So how to detec the right one? Therefore we use the distance or let's say how much overlapping we have in which direction. So less overlap is the right one.
So both functions return a double. Let's look at the mayHitTop() function
private float mayhitTop()
{
//remember that the y coordinate goes downwards so we have to add
float playersBotCoordinate = Player.Position.Y + Player.Sprite.Height;
//the y position is the top so nothing to change
float blocksTopCoordinate = Block.Position.Y;
hitTop=true; //this is a global variable you have 1 for each direction
return Math.Abs(playersBotCoordinate - blocksTopCoordinate);
}
So we have set the xDistance and yDistance and we know that it will hit the top or left.
Now we have to compare everything
// this means there could be 2 sides like our case that can be ths possible collision edge
if((hitLeft || hitRight) && (hitTop || hitBot))
{
//we hit the left or right side
if(xDistance<yDisante)
{
Player.Velocity.X = 0;
}
//we hit top or bottom
else
{
Player.Velocity.Y=0;
}
}
else
{
if(hitLeft || hitRight)...
}
Maybe you have to unstuck the player. Otherwise I think there could be some problems.
So I just wrote it without any template. Don't know if there are any Syntax mistakes. but this shall only give you an overview how to do it ´we can expect this to be pseudocode ;)
Hope it'll help you at least a little.
Old
Ehhhh you are comparing the player position.Y with right and left
this should be the X coordinate if I understood the code ;)
if (Player.Position.Y < Right)
and
if (Player.Position.Y > Left)

Collision Detection, player correction

I am having some problems with collision detection, 2 have 2 types of objects aside from the player it self. Tiles and what I Call MapObjects.
The tiles are all 16x16, where the MapObjects can be any since, but is my problem case are they as well 16x16.
When my player runs apon the mapobjects or tiles dose it get very jaggy. The player is unable to move right, and will get warped forward when moving left.
I have found the problem, and that is my collision detection will move the player left/right if colliding the object from the side, and up/down if collision from up/down.
Now imagen that my player is sating on 2 tiles, at 10,12 and 11,12 and the player is mostly standing on the 11,12 tile. The collision detection will first run on then 10,12 tile, it calculates the collision depth, and finds that is is a collision from the side, and therefore more the object to the right. After will it do collision detection with 11,12 here will it move the character up. So the player will not fall down, but are unable to move right. And when moving left will the same problem make the player warp forward.
This problem have been bugging me for a few days now, and I just can't find a solution!
Here is my code that dose the collision detection.
public void ApplyObjectCollision(IPhysicsObject obj, List<IComponent> mapObjects, TileMap map)
{
PhysicsVaraibales physicsVars = GetPhysicsVariables();
Rectangle bounds = ((IComponent)obj).GetBound();
int leftTile = (int)Math.Floor((float)bounds.Left / map.GetTileSize());
int rightTile = (int)Math.Ceiling(((float)bounds.Right / map.GetTileSize())) - 1;
int topTile = (int)Math.Floor((float)bounds.Top / map.GetTileSize());
int bottomTile = (int)Math.Ceiling(((float)bounds.Bottom / map.GetTileSize())) - 1;
// Reset flag to search for ground collision.
obj.IsOnGround = false;
// For each potentially colliding tile,
for (int y = topTile; y <= bottomTile; ++y)
{
for (int x = leftTile; x <= rightTile; ++x)
{
IComponent tile = map.Get(x, y);
if (tile != null)
{
bounds = HandelCollision(obj, tile, bounds, physicsVars);
}
}
}
// Handel collision for all Moving objects
foreach (IComponent mo in mapObjects)
{
if (mo == obj)
continue;
if (mo.GetBound().Intersects(((IComponent)obj).GetBound()))
{
bounds = HandelCollision(obj, mo, bounds, physicsVars);
}
}
}
private Rectangle HandelCollision(IPhysicsObject obj, IComponent objb, Rectangle bounds, PhysicsVaraibales physicsVars)
{
// If this tile is collidable,
SpriteCollision collision = ((IComponent)objb).GetCollisionType();
if (collision != SpriteCollision.Passable)
{
// Determine collision depth (with direction) and magnitude.
Rectangle tileBounds = ((IComponent)objb).GetBound();
Vector2 depth = bounds.GetIntersectionDepth(tileBounds);
if (depth != Vector2.Zero)
{
float absDepthX = Math.Abs(depth.X);
float absDepthY = Math.Abs(depth.Y);
// Resolve the collision along the shallow axis.
if (absDepthY <= absDepthX || collision == SpriteCollision.Platform)
{
// If we crossed the top of a tile, we are on the ground.
if (obj.PreviousBound.Bottom <= tileBounds.Top)
obj.IsOnGround = true;
// Ignore platforms, unless we are on the ground.
if (collision == SpriteCollision.Impassable || obj.IsOnGround)
{
// Resolve the collision along the Y axis.
((IComponent)obj).Position = new Vector2(((IComponent)obj).Position.X, ((IComponent)obj).Position.Y + depth.Y);
// If we hit something about us, remove all velosity upwards
if (depth.Y > 0 && obj.IsJumping)
{
obj.Velocity = new Vector2(obj.Velocity.X, 0);
obj.JumpTime = physicsVars.MaxJumpTime;
}
// Perform further collisions with the new bounds.
return ((IComponent)obj).GetBound();
}
}
else if (collision == SpriteCollision.Impassable) // Ignore platforms.
{
// Resolve the collision along the X axis.
((IComponent)obj).Position = new Vector2(((IComponent)obj).Position.X + depth.X, ((IComponent)obj).Position.Y);
// Perform further collisions with the new bounds.
return ((IComponent)obj).GetBound();
}
}
}
return bounds;
}

Categories