i'm working on a small RPG game, and what i currently have is:
*Character with animation and basic collision;
*A 32x32 box which i test the collision on;
And thats all for now..xD
My character is 32xPixels wide, and 48xPixels tall, 32x38.
And i have Two rectangles, playerRectangle(for collision and movement);
And rectangleAnimation, for the character animation.
Well, my question is, how do i make a collision rectangle that only covers half of the character? Right now my rectangle is 32x48, so how do i make it 32x24, WITHOUT cropping the image?
It gives the illusion of being infront of something, for example a rock, or a tree.
I tried to make a seperate sprite, which is 32x24 and made a rectangle of it and drew two sprites in my player class, but that didn't work...
And my last question, should i make a seperate class, like CollisionHandler.cs for all my solid things, like walls, and boxes?
Here's my movement code for the player(without attempting to make a diffrent sized rectangle):
if (keyState.IsKeyDown(Keys.Left))
{
playerRectangle.X -= playerSpeed;
movingLeft = true;
movingRight = false;
}
else if (keyState.IsKeyDown(Keys.Right))
{
playerRectangle.X += playerSpeed;
movingRight = true;
movingLeft = false;
}
if (keyState.IsKeyDown(Keys.Up))
{
playerRectangle.Y -= playerSpeed;
movingUp = true;
movingDown = false;
}
else if (keyState.IsKeyDown(Keys.Down))
{
playerRectangle.Y += playerSpeed;
movingDown = true;
movingUp = false;
}
(I'm sorry that the code looks messy, i'm new to this site and i don't know how to structure it :/)
And my collision check(Which is in Game1.cs):
if(isColliding())
{
if (player.movingRight)
{
player.playerRectangle.X -= player.playerSpeed;
}
else if (player.movingLeft)
{
player.playerRectangle.X += player.playerSpeed;
}
if (player.movingUp)
{
player.playerRectangle.Y += player.playerSpeed;
}
else if(player.movingDown)
{
player.playerRectangle.Y -= player.playerSpeed;
}
}
I have a method in Game1.cs that's called "isColliding", which checks for collision in another class rectangle and my playerRectangle..
I'm sorry this is so long, but thank you in advance, and tell me if you need to know something else :)
i will write from my head... add this into your sprite class, it will be universal
public Rectangle BoundingBox
{
get { return new Rectangle((int)Position.X + offsetX, (int)Position.Y + offsetY, Texture.Width - offsetWidth, Texture.Height - offsetWidth); }
}
simply changing offsetX, offsetY, offsetWidth, offSetHeight you can adjust collision box. so if you wish collision on top left corner for 5x5 pixels. then offsetX=0, offestY=0, offsetWidth=5, offsetHeight=5
and collide code
foreach (Sprite brick in bricklist)
{
if (player.BoundingBox.Intersects(brick.BoundingBox))
{
// do some stuff
}
}
If you want to change the height of the player rectangle by half, all you do is just divide the playerRectangle.Y value by 2.
Use Vector2.Distance(playerPosition, objectToCheck);
if(Vector2.Distance(playerPosition,objectToCheck < player.rectangle.width/2){
//If the player is too close to the object you wish to check
//Do something...
}
For the collisions, i'd just check in your player's update method whether or not 'he' has collided with anything - using vector.distance^^
You're movement logic is bad:
You should be using velocity.
var velocity = new Vector2(0,0);
var moveSpeed = 5; //Whatever you want
if(player presses right){
velocity.X += moveSpeed;
}
if(player presses up){
velocity.y += moveSpeed;
}
this.position += velocity * Gametime.elapsedGametime; << Think Gametime is correct...
Var origin = new vector2(rectangle.width /2, rectangle.height/2); This will set the origin of the sprite to the center of the rectangle, as opposed to the top left.
Say we have two rectangles both 50x50... to check for a collision between the two you'd do:
if(Vector2.Distance(rectangle1.position, rectangle2.position < rectangle1.width/2){
//If the distance between the two rectangles (from the middle of the rectangle(the origin we just set is less than then half of the width of the rectangle... we have a collision.
}
Haven't used XNA in a few months, so you might have to update the origin in the update method of your classes...
Related
I've been looking through the Source SDK and read through how it handles player collision with the space around it. Inspired by that, I've been writing a character controller that should have similar behavior.
I have code to control a Transform transform by computing its velocity vecVelocity and trying to move it along that vector. I represent the player by a capsule of radius capsuleRadius and sphere centers capsuleStart, capsuleEnd, but I haven't given it a proper collider as of yet
When trying to deal with collisions, I came up with the following function
void TryPlayerMove()
{
Vector3 transDirection;
float transMagnitude;
Vector3 translation;
Vector3 currentMotion = Vector3.zero;
int i, j, maxHits = 4; //Bump up to 4 times before giving up
RaycastHit capsule;
bool collision;
Vector3[] collNormal = new Vector3[maxHits];
float collDistance;
//Find starting translation vector
translation = vecVelocity * Time.deltaTime;
//Store initial displacement
Vector3 oldTranslation = translation;
for (i = 0; i < maxHits; i++)
{
//Find translation vector magnitude and direction
transDirection = translation.normalized;
transMagnitude = translation.magnitude;
//If we wouldn't move anyway, feel free to break the loop
if (transMagnitude == 0)
{
break;
}
//Shoot a capsule to desired endpoint
collision = Physics.CapsuleCast(capsuleStart + currentMotion, capsuleEnd + currentMotion, capsuleRadius, transDirection, out capsule, transMagnitude);
if (collision)
{
//If we hit something, hug it and take off what is left of translation in that direction
collNormal[i] = capsule.normal.normalized;
collDistance = capsule.distance;
//currentMotion += transDirection * collDistance; //WHY DOESN'T THIS WORK???
translation = ClipVector(translation*(1f-collDistance/transMagnitude), collNormal[i]);
Debug.Log(transDirection.magnitude);
//If we're going towards something we've hit before, stop moving so we don't go into weird corner loops
for (j = 0; j < i; j++)
{
if (Vector3.Dot(translation, collNormal[j]) < 0)
{
translation = Vector3.zero;
break;
}
}
}
else
{
//Just move
currentMotion += translation;
break;
}
}
//Translate the player character and take note of its velocity for future computation
vecVelocity = currentMotion / Time.deltaTime;
transform.Translate(currentMotion, Space.World);
}
and the clipping function just makes sure our vector is REALLY not pointing at the collider
Vector3 ClipVector(Vector3 inputVector, Vector3 normalVector)
{
float projection;
Vector3 outputVector;
//Determine how much to take out
projection = Vector3.Dot(inputVector, normalVector);
//Subtract the perpendicular component
outputVector = inputVector - normalVector * projection;
//Iterate once more just to make sure
float adjust = Vector3.Dot(outputVector, normalVector);
if (adjust < 0f)
{
outputVector -= normalVector * adjust;
}
return outputVector;
}
This works fine as it is, and the controls respond quite as I would expect, but with a cosmetic fault: each time the player "collides" with something, it does so stopping at a different distance from the object, I've logged it and it fluctuates around 5-10 percent of the capsule's radius away from the player.
In the TryPlayerMove() function, there is a command that I would expect to make it hug the collider, it's commented and decorated with a note of desperation
//currentMotion += transDirection * collDistance; //WHY DOESN'T THIS WORK???
Whenever I uncomment this, the controller invariably goes through absolutely any collider it touches and completely messes up whatever motion it was supposed to have. I have no idea why this happens, though.
How could I implement a functionality for my player to hug the colliders it touches, seeing this doesn't seem to work at all?
I found a hacky fix for it out of the blue. I have a float deltaGroundI use to check for ground. I changed the command to
currentMotion += transDirection * (collDistance-deltaGround/20f);
but the 20 could have been any reasonably sized number. This makes it much more consistent but introduces some jitter in player motion when I try to ram myself against a wall. Still taking more suggestions.
I had tried Mathf.Epsilon but it didn't fix anything, by the way.
I wrote a collision detection system for a game I am working on, and I am experiencing a weird glitch where, occasionally, projectiles will go through the player or walls scattered throughout the level. Because the projectiles can be fired at any angle, I decomposed the bounding box of each projectile into multiple, smaller bounding boxes that I then rotate around the center of the texture according to the rotation of the projectile in space. For some reason, occasionally a Spear projectile will go through the player or a wall even through others do not.
I use the following methods to determine the rotation of the texture and to translate the bounding boxes:
public double RotateToFaceTarget()
{
double rotation = Math.Atan2((double)_direction.Y, (double)_direction.X);
return rotation;
}
public List<BoundingBox> TranslateBoundingBox(List<BoundingBox> box, double rotation)
{
List<BoundingBox> newBounds = new List<BoundingBox>();
foreach (BoundingBox b in box)
{
Vector2 boundsOrigin = new Vector2(b.Pos.X + b.Size.X / 2, b.Pos.Y + b.Size.Y / 2);
Vector2 texOrigin = new Vector2(_pos.X + _texture.Width / 2, _pos.Y + _texture.Height / 2);
Vector2 newPosBasedOnOrigin = Vector2.Transform(boundsOrigin - texOrigin, Matrix.CreateRotationZ((float)rotation)) + boundsOrigin;
newBounds.Add(new BoundingBox(newPosBasedOnOrigin, b.Size));
}
return newBounds;
}
_direction is calculated by subtracting the position of the projectile from the target location and normalizing. I use this method to determine if the projectile is colliding with another entity:
public bool ProjectileCollision(Entity e, Projectile entity2)
{
if (entity2.CanCollide)
{
foreach(GameObject.BoundingBox b in entity2.BoundingBox)
{
foreach(GameObject.BoundingBox b2 in e.BoundingBox)
{
if (b2.Intersect(b) && (entity2.IgnoredEntities.Contains(e.Type) == false))
{
entity2.IsActive = false;
e.Health -= entity2.Damage;
return true;
}
return false;
}
}
return false;
}
return false;
}
And this is my Bounding Box Intersection method:
public bool Intersect(BoundingBox intersected)
{
if ((_pos.Y < intersected.Pos.Y + intersected.Size.Y) && (_pos.Y + _size.Y > intersected.Pos.Y) && (_pos.X + _size.X > intersected.Pos.X) && (_pos.X < intersected.Pos.X + intersected.Size.X))
{ return true; }
return false;
}
EDIT: On further testing, it seems that the projectile will always detect a hit if the player hits based on the top left corner ( which makes sense now that I look at my intersect code). Is there another way to re-write my Intersect method to use something more accurate than the top left corner?
EDIT2: I drew the hitboxes for certain objects, and this is one instance of when I catch the spear going through the player:
http://imgur.com/a/fAxZw
the player is the larger pink square. The hitboxes are not being translated correctly, but it shouldn't just stop working, for some and not others, right?
It could happen, because of high velocity and small object, projectile could fly through object. Beside of checking if objects are intersecting, you have to check if object will intersect, to check if object is in line of fire. You could achieve this by raycasting.
On those cases like your i had function that check if object is near other. Simple checking if object is inside of some radius of other object. If yes then i was checking if object is flying toward other object, and checking distance between them. When distance is really close then collision happened.
I have script which makes character (gameobject) move right.
How do I make so when he reaches right border, and character starts moving left with playing another animation (moving left)?
Here is my script of character's moving right and left
void MovementRight()
{
_character.transform.Translate (Vector2.right 100f Time.deltaTime);
}
void MovementLeft()
{
_character.transform.Translate (Vector3.left 100f Time.deltaTime);
}
I would suggest you handle animations with Animator, and make the horizontal animation to be handled by a float variable in Animator, (so when it is -1 animate walking left, and 1 animate walking right).
So you will need to make 3 scripts.
//This will handle the animator getting the speed of the character from MovingHandler
AnimationHandler.cs
//This will actually move the character based on input handler
MovingHandler.cs
//Here you will hear to inputs
InputHandler.cs
And to make suere the character won't move outside the screen you will need to get the screenbounds on MovingHandler and make a check before moving the character, if it is in the same spot in x as the bounds of the screen you will make a return; also if it is going to the left and the character is <= than left bound then return; and the same on the right bound >= then return;
Something like this:
Transform charTransform;
float leftHorizontalBound;
float rightHorizontalBound;
void Start()
{
charTransform = this.transform;
leftHorizontalBound = camera.ViewportToWorldPoint (new Vector3 (0,0, camera.nearClipPlane)).x;
rightHorizontalBound= camera.ViewportToWorldPoint (new Vector3 (1,0, camera.nearClipPlane)).x;
}
void Update()
{
if(charTransform.position.x <= leftHorizontalBound)
{
charTransform.position = new vector2(leftHorizontalBound + 0.1f);
return;
}
if(charTransform.position.x >= rightHorizontalBound)
{
charTransform.position = new vector2(rightHorizontalBound - 0.1f);
return;
}
//MAKE HERE YOUR MOVEMENT BASED ON INPUT.
}
Dont use that code just use the idea, since i didn't test it, i just code it here.
I hope it helped.
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");
}