What is wrong with my player movement? - c#

I have a small problem that i cannot work out. I'm currently learning to apply vector math and trigonometry to games, To learn i have created a game where the player fly's a space ship of sorts however i have a problem.
My movement seems to be inverted?
He will fly upwards and downwards correctly, However the left and right movement is inverted?
Here is my code:
protected override void Update(GameTime gameTime)
{
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
Exit();
// TODO: Add your update logic here
angleDeg = (float)(angle * (360 / (Math.PI * 2)));
var angleRad = (float)MathHelper.ToRadians(angleDeg);
var delta = (float)gameTime.ElapsedGameTime.TotalSeconds;
xSpeed = (float)Math.Cos(angle) * speed;
ySpeed = (float)Math.Sin(angle) * speed;
position.Y += xSpeed * delta;
position.X += ySpeed * delta;
keyboardState = Keyboard.GetState();
if(angleDeg < -360 || angleDeg > 360)
{
angle = 0;
angleDeg = 0;
}
if(keyboardState.IsKeyDown(Keys.Left))
{
angle -= 1f * delta;
}
if (keyboardState.IsKeyDown(Keys.Right))
{
angle += 1 * delta;
}
if (keyboardState.IsKeyDown(Keys.Up))
{
speed -= 1f;
}
if (keyboardState.IsKeyDown(Keys.Down))
{
speed += 1f;
}
base.Update(gameTime);
}
/// <summary>
/// This is called when the game should draw itself.
/// </summary>
/// <param name="gameTime">Provides a snapshot of timing values.</param>
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.Black);
// TODO: Add your drawing code here
spriteBatch.Begin();
spriteBatch.Draw(player, position, sourceRect, Color.White, angle, origin, 1.0f, SpriteEffects.None, 1);
spriteBatch.DrawString(font, "Rotation: " + angleDeg, new Vector2(10, 5), Color.White);
spriteBatch.End();
base.Draw(gameTime);
}
Anyone have any ideas as to why this is happening?
Thanks in advance.

Mathematician's conventions and screen coordinates sometimes don't match.
Try this:
xSpeed = (float)Math.Sin(angle) * speed;
ySpeed = -(float)Math.Cos(angle) * speed; // notice '-' !
based on this answer.

As Andrew Russell said in this answer:
If you are using maths functions like sin or cos or atan2, then
absolute angles always start from the X+ axis as zero radians, and the
positive rotation direction rotates towards Y+.
The XNA SpriteBatch works in Client Space. Where "up" is Y-, not Y+
(as in Cartesian space, projection space, and what most people usually
select for their world space). This makes the rotation appear as
clockwise (not counter-clockwise as it would in Cartesian space). The
actual coordinates the rotation is producing are the same.
From this piece of your code:
if(keyboardState.IsKeyDown(Keys.Left))
{
angle -= 1f * delta;
}
if (keyboardState.IsKeyDown(Keys.Right))
{
angle += 1 * delta;
}
Left key will turn your space ship clockwise (lower value of angle), and Right key will turn it counterclockwise (higher value of angle).
From your last comment:
My rotations are fine, It just when add speed when i pres the up arrow
and turn, the movement is inverted
I would check this other part of your code:
position.Y += xSpeed * delta;
position.X += ySpeed * delta;
It seems weird to use xSpeed to update position.Y and viceversa, but also maybe you need to use -= to update position.Y

Related

Clamp RotateAround object Unity

I am making a script to rotate my camera around a sphere but I need to clamp the y axis so the camera does not co over the polls of the sphere I am using rotate around to move my camera.
Thanks!
My current code
public float sensitivity = 1;
public float moveSpeed = 10;
public float maxUp = 45f;
public float maxDown = -45f;
public Transform target;
void Update()
{
transform.LookAt(target);
float HorizontalAxis = Input.GetAxis("Horizontal") * moveSpeed;
float VerticalAxis = Input.GetAxis("Vertical") * moveSpeed;
if (HorizontalAxis >= 1 || VerticalAxis >= 1 || HorizontalAxis <= -1 || VerticalAxis <= -1)
{
Quaternion targetPos = transform.rotation;
targetPos.x += HorizontalAxis * sensitivity;
targetPos.y += VerticalAxis * sensitivity;
transform.RotateAround(target.position, Vector3.left, targetPos.y);
transform.RotateAround(target.position, Vector3.up, targetPos.x);
}
}
Your code makes no sense to begin with.
You do
Quaternion targetPos = transform.rotation;
targetPos.x += HorizontalAxis * sensitivity;
targetPos.y += VerticalAxis * sensitivity;
Just to then use these as parameters in
transform.RotateAround(target.position, Vector3.left, targetPos.y);
transform.RotateAround(target.position, Vector3.up, targetPos.x);
A Quaternion has not three but four components x, y, z and w and they move in ranges between -1 and 1. You never touch the individual component of a Quaternion except you really know exactly what you are doing!
You rather simply want to use the HorizontalAxis and VerticalAxis directly as the parameters to RotateAround.
You could rather simply remember and clamp how much you already rotated like e.g.
private float rotatedY;
private void Update()
{
transform.LookAt(target);
// why two different multipliers anyway though?
var HorizontalAxis = Input.GetAxis("Horizontal") * moveSpeed * sensitivity;
var VerticalAxis = Input.GetAxis("Vertical") * moveSpeed * sensitivity;
// would a positive rotation exceed the maxUp?
if(rotatedY + VerticalAxis > maxUp)
{
// then rotate only so much that you terminate exactly on maxUp
VerticalAxis = maxUp - rotatedY;
}
// would a negative rotation exceed the maxDown?
else if(rotatedY + VerticalAxis < maxDown)
{
// then you rotate only that much that you terminate exactly on maxDown
VerticalAxis = maxDown - rotatedY;
}
transform.RotateAround(target.position, Vector3.left, VerticalAxis);
transform.RotateAround(target.position, Vector3.up, HorizontalAxis);
// sum up how much you already rotated vertically
rotatedY += VerticalAxis;
}

How can I limit the rotation on the Y axis so that the player can't continuously spin the camera in Unity

I have an upcoming project that I have to present on Monday and this is the last bug I have to resolve. It would be nice if someone could help me out, and could teach me how to apply an axis limiter, thanks in advance everyone.
The issue is that the camera can spin 360 degrees
Below is my current code that controls the camera
public float sensitivity = 30.0f;
private GameObject cam;
float rotX, rotY;
private void Start()
{
sensitivity = sensitivity * 1.5f;
Cursor.visible = false; // For convenience
}
private void Update()
{
rotX = Input.GetAxis("Mouse X") * sensitivity;
rotY = Input.GetAxis("Mouse Y") * sensitivity;
//Apply rotations
CameraRotation(cam, rotX, rotY);
}
private void CameraRotation(GameObject cam, float rotX, float rotY)
{
//Rotate the player horizontally
transform.Rotate(0, rotX * Time.deltaTime, 0);
//Rotate the players view vertically
cam.transform.Rotate(-rotY * Time.deltaTime, 0, 0);
}
Adding logical clamping to this makes it quite a bit clearer to read through, this method clamps the vertical rotation between 60 and -60 degrees, the comments should help in modifying it if you need
I ended up jumping into Unity to test it this time, instead of going off the top of my head
void CameraRotation(GameObject cam, float rotX, float rotY)
{
//Rotate the player horizontally
transform.Rotate(0, rotX * Time.deltaTime, 0);
//Rotate the players view vertically
cam.transform.Rotate(-rotY * Time.deltaTime, 0, 0);
//Grab current rotation in degrees
Vector3 currentRot = cam.transform.localRotation.eulerAngles;
//If (x-axis > (degreesUp*2) && x-axis < (360-degreesUp))
if (currentRot.x > 120 && currentRot.x < 300) currentRot.x = 300;
//else if (x-axis < (degreesDown*2) && x-axis > (degreesDown))
else if (currentRot.x < 120 && currentRot.x > 60) currentRot.x = 60;
//Set clamped rotation
cam.transform.localRotation = Quaternion.Euler(currentRot);
}
Goodluck with the project

Get WASD keys to follow camera rotation in Unity

I understand there are many answers to this online but I was unable to apply them correctly to my code.
I have tried using pre-made player assets but could not get that to work.
Vector3 pos = transform.position;
public float X;
public float Y;
public float Z;
// Used to tilt camera up and down
float tilt = 0;
if (Input.GetMouseButton(1))
{
transform.Rotate(new Vector3(Input.GetAxis("Mouse Y") * panSpeed, Input.GetAxis("Mouse X") * panSpeed, 0));
X = transform.rotation.eulerAngles.x;
Y = transform.rotation.eulerAngles.y;
Z = transform.rotation.eulerAngles.z;
// Add current position of mouse input
tilt += X;
transform.rotation = Quaternion.Euler(0, Y, tilt);
}
//Spaceship does not go in direction it is facing once panned
if (Input.GetKey("w"))
{
//transform.rotation = Quaternion.Euler(0, Y, tilt);
pos.z += speed * Time.deltaTime;
}
if (Input.GetKey("s"))
{
pos.z -= speed * Time.deltaTime;
}
if (Input.GetKey("d"))
{
pos.x += speed * Time.deltaTime;
// DEBUG Does not work properly while mouse held down
//transform.Rotate(-1, 0, 0);
}
if (Input.GetKey("a"))
{
pos.x -= speed * Time.deltaTime;
}
transform.position = pos;
Assuming here the "Camera" equals transform you can simply use its local axis transform.forward
Returns a normalized vector representing the blue axis of the transform in world space.
and transform.right
Returns a normalized vector representing the red axis of the transform in world space.
like e.g.
private void Update()
{
if (Input.GetMouseButton(1))
{
// NOTE: I DON'T UNDERSTAND THIS CODE BLOCK YET
// YOU KNOW E.G. THAT IF YOU "transform.eulerAngles.x" ALREADY IS "45°"
// THE "tilt" WOULD JUMP EVERY FRAME IN HUGER STEPS (45 -> 90 -> 180 - 360 ....)
// ALSO WHY ROTATE IN X AXIS IF AFTERWARDS YOU RESET THE X ROTATION
// AND RATHER APPLY IT TO Z?
transform.Rotate(new Vector3(Input.GetAxis("Mouse Y") * panSpeed, Input.GetAxis("Mouse X") * panSpeed, 0));
X = transform.eulerAngles.x;
Y = transform.eulerAngles.y;
Z = transform.eulerAngles.z;
// Add current position of mouse input
tilt += X;
transform.rotation = Quaternion.Euler(0, Y, tilt);
}
Vector3 movement = Vector3.zero;
if (Input.GetKey(KeyCode.W))
{
movement += transform.forward;
}
if (Input.GetKey(KeyCode.S))
{
movement -= transform.forward;
}
if (Input.GetKey(KeyCode.D))
{
movement += transform.right;
}
if (Input.GetKey(KeyCode.A))
{
movement -= transform.right;
}
// I would do it like this to make sure that diagonal movement
// does not move faster
transform.position = movement.normalized * speed * Time.deltaTime;
}

Unity Rotation of Parent object along 1 Axis

I'm working on developing a game, and my current roadblock is Camera Rotation. I want the mouse to control the camera, and when the camera turns, I want to rotate the player as well. However, the code I am using rotates the player object COMPLETELY with the player, causing the player to turn like this:
The player rotating forward not only looks strange, but causes clipping problems with the terrain. How do I make my code only rotate the player along one axis, while allowing the camera to rotate along any axis (to allow the audience to look around, without the player object being turned upwards or down).
this is the code that is rotating the player:
Quaternion QT = Quaternion.Euler(_LocalRotation.y, _LocalRotation.x, 0);
this._XForm_Parent.rotation = Quaternion.Lerp(this._XForm_Parent.rotation, QT, Time.deltaTime * OrbitDampening);
if (this._XForm_Camera.localPosition.z != this._CameraDistance * -1f)
{
this._XForm_Camera.localPosition = new Vector3(0f, 0f, Mathf.Lerp(this._XForm_Camera.localPosition.z, this._CameraDistance * -1f, Time.deltaTime * ScrollDampening));
}
and this is the complete script I am using:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CameraOrbit : MonoBehaviour
{
protected Transform _XForm_Camera;
protected Transform _XForm_Parent;
protected Vector3 _LocalRotation;
protected float _CameraDistance = 10f;
public float MouseSensitivity = 4f;
public float ScrollSensitvity = 2f;
public float OrbitDampening = 10f;
public float ScrollDampening = 6f;
public bool CameraDisabled = false;
// Use this for initialization
void Start()
{
this._XForm_Camera = this.transform;
this._XForm_Parent = this.transform.parent;
}
void LateUpdate()
{
if (Input.GetKeyDown(KeyCode.LeftShift))
CameraDisabled = !CameraDisabled;
if (!CameraDisabled)
{
//Rotation of the Camera based on Mouse Coordinates
if (Input.GetAxis("Mouse X") != 0 || Input.GetAxis("Mouse Y") != 0)
{
_LocalRotation.x += Input.GetAxis("Mouse X") * MouseSensitivity;
_LocalRotation.y += Input.GetAxis("Mouse Y") * MouseSensitivity;
//Clamp the y Rotation to horizon and not flipping over at the top
if (_LocalRotation.y < 0f)
_LocalRotation.y = 0f;
else if (_LocalRotation.y > 90f)
_LocalRotation.y = 90f;
}
//Zooming Input from our Mouse Scroll Wheel
if (Input.GetAxis("Mouse ScrollWheel") != 0f)
{
float ScrollAmount = Input.GetAxis("Mouse ScrollWheel") * ScrollSensitvity;
ScrollAmount *= (this._CameraDistance * 0.3f);
this._CameraDistance += ScrollAmount * -1f;
this._CameraDistance = Mathf.Clamp(this._CameraDistance, 1.5f, 100f);
}
}
//Actual Camera Rig Transformations
Quaternion QT = Quaternion.Euler(_LocalRotation.y, _LocalRotation.x, 0);
this._XForm_Parent.rotation = Quaternion.Lerp(this._XForm_Parent.rotation, QT, Time.deltaTime * OrbitDampening);
if (this._XForm_Camera.localPosition.z != this._CameraDistance * -1f)
{
this._XForm_Camera.localPosition = new Vector3(0f, 0f, Mathf.Lerp(this._XForm_Camera.localPosition.z, this._CameraDistance * -1f, Time.deltaTime * ScrollDampening));
}
}
}
A picture of my heirarchy:
(Please note that Player is an empty object containing all of my scripts and physics components, whereas the GFXs component is simply the model, with an animator component clean of any physics components.)
It sounds like what you want is basically to rotate the player around its local Y axis until it is facing the same direction as the camera. You can find out if things are facing the same direction using Vector3.SignedAngle and passing in the axis that you care about. Here is some sample code that should get you going.
float turnThresholdDegrees = 15;
float playerTurnSpeed = 1;
// Get delta angle in degrees on the Y axis between the direction player is facing and the direction camera is facing
float angleDelta = Vector3.SignedAngle(player.transform.forward, camera.transform.forward, Vector3.up);
// Calculate a rotation speed, clamping it to 0 when the angle delta is < some threshold
float rotateSpeed = Mathf.Abs(angleDelta) > turnThresholdDegrees ? Mathf.Sign(angleDelta) * playerTurnSpeed : 0;
// Rotate the player around its local Y axis by the rotation speed
player.transform.Rotate(0, rotateSpeed * Time.deltaTime, 0, Space.Self);

XNA sprite movement gone wrong

Hy everyone, so first off all, here is the image of my sprite:
I scaled it down in my game so its not that big in-game.
So anyway my desired result of the code below:
protected override void Update(GameTime gameTime)
{
// Allows the game to exit
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
spritePos = spriteVelocity + spritePos;
spriteR = new Rectangle((int)spritePos.X, (int)spritePos.Y, spriteT.Width, spriteT.Height);
spriteOrigin = new Vector2(spriteR.Width/2, spriteR.Height / 2);
if (Keyboard.GetState().IsKeyDown(Keys.Right)) rotation += 0.1f;
if (Keyboard.GetState().IsKeyDown(Keys.Left)) rotation -= 0.1f;
if (Keyboard.GetState().IsKeyDown(Keys.Up))
{
spriteVelocity.X = (float)Math.Cos(rotation) * tangentialVelocity;
spriteVelocity.Y = (float)Math.Sin(rotation) * tangentialVelocity;
} else if (spriteVelocity != Vector2.Zero)
{
float i = spriteVelocity.X;
float j = spriteVelocity.Y;
spriteVelocity.X = i -= friction * i;
spriteVelocity.Y = j -= friction * j;
}
base.Update(gameTime);
}
and then Draw method:
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
foreach(Bushes bush in bushes)
{
bush.Draw(spriteBatch);
}
player.Draw(spriteBatch);
spriteBatch.Draw(spriteT, spritePos, null, Color.White, rotation, spriteOrigin, 0.1f, SpriteEffects.None, 0f);
spriteBatch.End();
base.Draw(gameTime);
}
is that when I press 'Up' arrow this little rocket should go into direction in whis it is pointing (becouse I can rotate it with Left and Right arrow to have it pointed where desired), but the result of this code is that when I press Up arrow the sprite moves to the right at first, and when its rotated it doesnt go where its pointed but kinda sideways :/
What am I doing wrong here?
PS. all those variables that arent declared and initialized in code are global variables and initialized in Initialize() and LoadContent() methods :/
If your rotation is initialized at 0, it should point to the right, look at where 0 points at on the trig circle below :)
You could compute your direction with Vector2.Transform and give as value parameter (first) Vector2(0,1) so your reference direction would be up.
Or you rotate your sprite to the right and initialize your angle at Pi/2.

Categories