I know this has been Asked but in my Case i dont know if i Can use the MouseEventArgs since its a Rendering / Input Loop where Im trying to use it Here is the Whole Rendering / Input Loop, I can only Move with the Keyboard which is Rather inconvinient.
public void update()
{
//--do raycast--//
raycast();
//=========================//
//=====take user input=====//
//=========================//
KeyboardState state = Keyboard.GetState();
bool lArrowKeyDown = state.IsKeyDown(Keys.Left) || state.IsKeyDown(Keys.A);
//MouseLeft
if (lArrowKeyDown)
{
rotate(rotSpeed);
}
//MouseRight
bool rArrowKeyDown = state.IsKeyDown(Keys.Right) || state.IsKeyDown(Keys.D);
if (rArrowKeyDown)
{
rotate(-rotSpeed);
}
//MouseUp
bool uArrowKeyDown = state.IsKeyDown(Keys.Up) || state.IsKeyDown(Keys.W);
bool shift = state.IsKeyDown(Keys.LeftShift);
if (uArrowKeyDown)
{
move(moveSpeed);
}
if (uArrowKeyDown && shift)
{
move(moveSpeed+0.01);
}
bool dArrowKeyDown = state.IsKeyDown(Keys.Down) || state.IsKeyDown(Keys.S);
//MouseDown
if (dArrowKeyDown)
{
move(-moveSpeed);
}
//=========================//
//=====user input end======//
//=========================//
}
This is the Whole Rendering / Input Loop, Would it be Possible to add a MouseEventArgs? Im unsure of if a MouseEventArgs Loops too when this Loops. Could someone help me Here?
I’m not entirely sure what you are asking for, but if you want to get movement direction from a mouse event, unless the mouse event has a last position and new position property, you need to keep track of the last position (x and y value) and use it with the current position to calculate the angle.
For calculating the angle, see
Calculating the angle between the line defined by two points
I can provide a better answer with more information.
Related
Still pretty new to Unity and C#. I can usually find my way around when it comes to setting/changing the position of an object, but when it comes to rotation it's still mind boggling to me, with quaternion, eulerangles etc..
I'm trying to check if an object (a head) is facing a certain direction, if it's not facing that direction it needs to set it to that direction depending which way it goes (up, down, left or right). This is for a snake game (like the old top down nokia game) I'm currently developing.
I tried to look it up, but none of the answers are specific to what I'm trying to do.
As of right now this is what I have for player input (a snippet of code):
private int GetAxisRaw(Axis axis)
{
if (axis == Axis.Horizontal)
{
bool left = Input.GetKeyDown(KeyCode.LeftArrow) || Input.GetKeyDown(KeyCode.A);
bool right = Input.GetKeyDown(KeyCode.RightArrow) || Input.GetKeyDown(KeyCode.D);
if (left)
{
snakeHeadRotation.transform.Rotate(0, 180, 0); // Keeps rotating when left is pressed
return -1;
}
if (right)
{
snakeHeadRotation.transform.Rotate(0, -180, 0);
return 1;
}
return 0;
}
As you can see the snakeHeadRotation.transform.Rotate(0, 180, 0); is getting called each time the player presses the left key for instance, thus turning the head of the snake even when the snake is still traveling to the left.
My logic would be to store the rotation value somewhere (type Quaternion/bool maybe) and check to see if that rotation value matches up with the current rotation value set to left (which is snakeHeadRotation.transform.Rotate(0, 180, 0);) If that's the case, don't do anything. If it isn't, set it to snakeHeadRotation.transform.Rotate(0, 180, 0); for instance.
the code would look something like (writing it out):
private int GetAxisRaw(Axis axis)
{
if (axis == Axis.Horizontal)
{
bool left = Input.GetKeyDown(KeyCode.LeftArrow) || Input.GetKeyDown(KeyCode.A);
bool right = Input.GetKeyDown(KeyCode.RightArrow) || Input.GetKeyDown(KeyCode.D);
if (left && rotation is not equal to snakeHeadRotation.transform.Rotate(0, 180, 0))
{
snakeHeadRotation.transform.Rotate(0, 180, 0);
return -1;
}
if (right)
{
snakeHeadRotation.transform.Rotate(0, -180, 0);
return 1;
}
return 0;
}
As said, I'm very unfamiliar with setting or storing rotation values. How can I achieve this? Is this even the right approach or is there a more logical one? I can't figure this one out myself..
I hope I explained it right, I'm usually terrible at explaining things.
Using Transform.Rotate(x) will rotate your head by x degrees relatively to your current head direction.
What you want I suppose is to set the absolute rotation of your head depending on the arrow key you pressed. Thus, even if you press multiple times the same arrow key, the head will stay in the correct direction.
To do that you can create 4 rotations for each head direction and so use them as needed.
For example, if your head is facing forward by default:
// create your directions
private static Quaternion forwardDirection = Quaternion.Identity;
private static Quaternion rightDirection = Quaternion.FromToRotation(Vector3.forward, Vector3.right);
private static Quaternion leftDirection = Quaternion.FromToRotation(Vector3.forward, Vector3.left);
private static Quaternion backDirection = Quaternion.FromToRotation(Vector3.forward, Vector3.back);
...
private int GetAxisRaw(Axis axis)
{
...
if (left)
{
// set the absolute direction of your head to the left
snakeHeadRotation.transform.rotation = leftDirection;
return -1;
}
if (right)
{
// set the absolute direction of your head to the right
snakeHeadRotation.transform.rotation = rightDirection;
return 1;
}
...
}
I would just create 4 quaternions for each direction and set the rotation according to the key pressed (so like hear.rotation = leftQ). This is the simplest way.
I am away from my PC currently but I will try to find another solution when I can
You could compare the current rotation to the known rotations for the 4 directions.
But don't go that way, it's bad practice for several reasons:
what if later you want to add animations, e.g. the head turns in .5 seconds, not instantly?
comparing 4 floats only to check one of 4 possible directions is inefficient.
Create a enum instead:
public enum Direction
{
Up,
Down,
Left,
Right
}
Add a member of this type to your behavior, to keep track of where your snake head is going.
Something like:
Direction direction;
...
private int GetAxisRaw(Axis axis)
{
switch (direction)
{
case Direction.Up:
if (left && !right)
direction = Direction.Left;
... turn snake left ...
else if (right && !left)
direction = Direction.Right;
... turn snake right ...
// ignore inputs for up or down if going up
break;
... repeat for the other directions and possible inputs ...
}
...
}
(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 have run into a slight issue with the collision resolution in my game engine. If two objects collide and that collision causes the velocity to go to zero, the edges of the objects will overlap each other and they'll be stuck.
Is there a way to implement a catchall for this kind of a situation? i.e. move the objects just enough in the right direction so they are not stuck.
Here is how I am checking collisions and moving objects. When update is called on an entity, it moves the (x,y).
public static void Update()
{
for (var iterator = 0; iterator < PhysicsEntities.Count; iterator++)
{
for (var index = iterator + 1; index < PhysicsEntities.Count; index++)
{
if (!Collision.ResolveCollision(PhysicsEntities[iterator],
PhysicsEntities[index], Detection)) continue;
PhysicsEntities[iterator].Update();
PhysicsEntities[iterator].Collided = true;
PhysicsEntities[index].Update();
PhysicsEntities[index].Collided = true;
}
}
foreach (var entity in PhysicsEntities)
{
entity.Update(velocity: true);
entity.Collided = false;
}
}
}
Here is the update function for the entities:
public void Update(bool velocity = false)
{
if(!Movable) return;
if (!Collided)
{
var moveX = Velocity.X / Universe.UpdateInterval;
var moveY = Velocity.Y / Universe.UpdateInterval;
Position.Move(moveX, moveY);
BoundingBox.Move(moveX, moveY);
}
if(velocity) UniversalForces();
}
private void UniversalForces()
{
Velocity.Scale(1 - Universe.Friction);
Velocity.Add(Universe.GravityMag, Universe.GravityDir);
}
Finally, here is a image of one simulation where the objects get stuck. As you can see, it is just the edges that are getting stuck:
The quick solution is to move both objects back to the previous tic's position and any other object that causes a collision with to move back as well. It works, but it looks messy and causes some behavior that looks really bad - things like pushing directly at a wall leaves a gap, but angling towards a wall leaves a smaller gap. Very messy.
The better solution is to move both objects back just far enough along their negative velocity vector so that they are no longer touching. Usually some dot product math can give you what you need for this, though iterating backwards can work (slow).
Long story short, don't ever allow objects to overlap. Take care of it before it happens and you avoid stuck jitters, can't move stuff, etc.
When one object collides with another, get it to backtrack up its own movement vector so that the distance between the centroids of both objects is equal to the two radius. This works if its a circle - if its a complex polygon you really need to do edge collision detection instead of bounding sphere detection. If the bounding spheres collide, then you move to complex edge detection. In the end the trick is the same; check for collision then back up the movement vector until you find the exact (or nearly exact) point of collision.
I was able to figure it out with the suggestions people made. Some of the changes I made include having each object collide with any other object only once per update, and moving the object after the collision until it is no longer colliding. Here is the code that I used to do that, feel free to use this on any project and let me know if you have any questions about it.
public static void Update()
{
foreach (var a in PhysicsEntities)
{
foreach (var b in PhysicsEntities)
{
if (a.Equals(b) ||
!Collision.ResolveCollision(a, b, Detection) || b.Collided) continue;
while (Detection == Detection.BoundingBox ?
Collision.BoundingBox(a, b) :
Collision.PixelPerfect(a, b))
{
const float moveBy = .5F;
var moveX = a.Position.X > b.Position.X ? moveBy : -moveBy;
var moveY = a.Position.Y > b.Position.Y ? moveBy : -moveBy;
if (a.Movable)
{
a.Move(moveX, moveY);
a.Velocity.Scale(-1);
}
else if (b.Movable)
{
b.Move(moveX * -1, moveY * -1);
b.Velocity.Scale(-1);
}
}
a.Update();
b.Update();
a.Collided = a.Movable;
}
}
foreach (var entity in PhysicsEntities)
{
entity.Update(velocity: true);
entity.Collided = false;
}
}
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 been trying to program a way of preventing my character from touching a wall so he couldn't go trough it but I can't find a proper way of doing like you can see in this video (that I recorded). Sorry about the (decent) mic quality : https://youtu.be/jhTSDgSXXa8. Also I said prevent the collision but rather it detects it and stops but you can go through.
The collision code is :
foreach (PictureBox pbMur in pbListeMurs)
{
if (pbCharacterCat.Bounds.IntersectsWith(pbMur.Bounds))
{
if (pbCharacterCat.Right > pbMur.Left)
{
bWalkRight = false;
bIdle = true;
}
}
}
Thank you ! :D
I'm not sure how you are using bIdle and walkRight, but these types of boolean flags are easy to get wrong and it turns your whole code into a complete mess as you typically try to plug holes and end up springing new ones in the process.
First of all, why do you even need them? Wouldn't this be enough?
var newPotentialCharacterBounds =
GetNewBounds(pbCharacterCat.Bounds, movementDirection);
var collidedWalls = pbListeMurs.Where(wall =>
wall.Bounds.IntersectsWith(newPotentialCharacterBounds));
if (!collidedWall.Any())
{
pbCharacterCat.Bounds = newPotentialCharacterBounds
}
//else do nothing
How does this work? Well, the premise is that your character can't start in an invalid position, and if it is never allowed to reach an invalid position then you never need to undo movements or reset positions.
I'd propose you create an enumeration that describes all possible directions:
enum Direction { Up, Down, Left, Right };
When the corresponding direction command is given, get the potential new position of the character (newPotentialCharacterBounds and GetNewBounds). If that position collides with anything, simply do nothing, if it doesn't, move!
UPDATE: Pseudocode follows:
//event handler for move right fires, and calls:
TryMove(pbCharacterCat, Direction.Right)
//event handler for move left fires and calls:
TryMove(pbCharacterCat, Direction.Left)
//etc.
private static Rectangle GetNewBounds(
Rectangle current, Direction direction)
{
switch (direction)
{
case Direction.Right:
{
var newBounds = current;
newBounds.Offset(horizontalDelta, 0);
return newBounds;
}
case Direction.Left:
{
var newBounds = current;
newBounds.Offset(-horizontalDelta, 0);
return newBounds;
}
//etc.
}
//uses System.Linq
private bool TryMove(Control ctrl, Direction direction)
{
var newBounds =
GetNewBounds(ctrl.Bounds, direction);
var collidedWalls = pbListeMurs.Where(wall =>
wall.Bounds.IntersectsWith(newBounds));
if (!collidedWall.Any())
{
ctrl.Bounds = newBounds;
return true;
}
//Can't move in that direction
Debug.Assert(collidedWall.Single); //sanity check
return false;
}
Becuase TryMove returns if the movement was successful or not, now you can leverage that information; different sound effects for instance, etc.