I'm not sure how to calculate an XYZ immediately to my characters left based on the direction they are facing.
I am learning to create a 3D game in Monogame on top of .Net Core 3.1 in c# using MonoGame.Framework.WindowsDX.Core.
Right now I'm just drawing a cube in the game world and learning to wire up the controls to freely move a camera around to look at the cube from different angles.
I believe my math to calculate the camera target based on pitch/yaw from the character's position is correct.
I have wired up the mouse so that if I move the mouse up the camera looks up, and if I move it down the camera looks down, and if I move it left|right the camera rotates left or right (yaw). I am using 360 on the X access and 360 degrees on the Y access for the pitch yaw for now.
Here is my player class.
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using System;
using System.Collections.Generic;
using System.Text;
using YAVBG.Core.Input;
namespace YAVBG.Core.Objects
{
public class Player : Updateable
{
#region Fields
private float _x;
private float _y;
private float _z;
private float _pitch;
private float _yaw;
private float _height;
private float _zoomLevel;
private int _health;
private int _level;
private int _food;
private float _experience;
#endregion
#region Properties
public bool IsMainPlayer { get; private set; }
public Vector3 Position { get => new Vector3(_x, _y, _z); }
public float Pitch { get => _pitch; set => _pitch = value; }
public float Yaw { get => _yaw; set => _yaw = value; }
public float Height { get => _height; set => _height = value; }
public float ZoomLevel { get => _zoomLevel; set => _zoomLevel = value; }
#endregion
#region Constructor/Destructor
public Player(bool isMainPlayer = false) : this()
{
this.IsMainPlayer = isMainPlayer;
}
public Player()
{
_x = 0f;
_y = 0f;
_z = -12f;
_yaw = 0;
_pitch = 0;
_zoomLevel = 500f;
}
#endregion
#region Abstract Implementation
public override void Update(GameTime gameTime)
{
//TODO
}
#endregion
#region Methods
public void StrafeLeft(float units)
{
_x += units;
}
public void StrafeRight(float units)
{
this._x -= units;
}
public void MoveForward(float units)
{
this._z += units;
}
public void MoveBackward(float units)
{
this._z -= units;
}
public void MoveUp(float units)
{
this._y += units;
}
public void MoveDown(float units)
{
this._y -= units;
}
public void MoveYaw(float y)
{
this._yaw += y;
}
public void MovePitch(float x)
{
this._pitch += x;
}
/// <summary>
/// Get the matrix of where the player is looking based on their current position, zoom level, pitch, and yaw
/// </summary>
/// <returns></returns>
public Matrix GetCameraViewMatrix()
{
var position = this.Position;
var zoomLevel = this.ZoomLevel;
var yaw = this.Yaw;
var pitch = this.Pitch;
//todo make headCamera higher than player position
Vector3 headCamera = new Vector3(position.X, position.Y, position.Z);
var cx = Math.Sin(yaw) * Math.Cos(pitch);
var cy = Math.Sin(pitch);
var cz = Math.Cos(yaw) * Math.Cos(pitch);
var pX = zoomLevel * cx;
var pY = zoomLevel * cy;
var pZ = zoomLevel * cz;
var camTarget = new Vector3((float)pX, (float)pY, (float)pZ);
var matrix = Matrix.CreateLookAt(headCamera, camTarget, Vector3.Up);
return matrix;
}
#endregion
}
}
And here is my World Class
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using System;
using System.Collections.Generic;
using System.Text;
using YAVBG.Core.Input;
using YAVBG.Core.Primitives;
namespace YAVBG.Core.Objects
{
public class World : Updateable
{
#region Fields
private Cube _cube;
private InputManager _input;
#endregion
#region Properties
public MainPlayer MainPlayer { get; private set; }
public Matrix ProjectionMatrix { get; private set; }
public Matrix WorldMatrix { get; private set; }
public Cube Cube { get => _cube; }
#endregion
#region Constructor/Destructor
public World(float aspectRatio, float fieldOfView, int gameWidth, int gameHeight)
{
this._input = new InputManager(gameWidth, gameHeight);
this._cube = new Cube();
this.MainPlayer = new MainPlayer();
this.ProjectionMatrix = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(fieldOfView), 1.5f, 0.01f, 10000f);
this.WorldMatrix = Matrix.CreateWorld(new Vector3(0f, 0f, 0f), Vector3.Forward, Vector3.Up);
this._input.KeysBeingHeldDown += InputManager_KeysBeingHeldDown;
this._input.MouseMovedX += _input_MouseMovedX;
this._input.MouseMovedY += _input_MouseMovedY;
}
#endregion
#region Abstract Implementation
public override void Update(GameTime gameTime)
{
this._input.Update(gameTime);
this.MainPlayer.Update(gameTime);
}
#endregion
#region Input Events
private void _input_MouseMovedY(object sender, int e)
{
var modified = e < 0 ? 0.001f : -0.001f;
this.MainPlayer.MovePitch(modified);
}
private void _input_MouseMovedX(object sender, int e)
{
var modified = e < 0 ? 0.001f : -0.001f;
this.MainPlayer.MoveYaw(modified);
}
private void InputManager_KeysBeingHeldDown(object sender, Microsoft.Xna.Framework.Input.Keys e)
{
if (e == Keys.W)
this.MainPlayer.MoveForward(0.1f);
if (e == Keys.A)
this.MainPlayer.StrafeLeft(0.1f);
if (e == Keys.S)
this.MainPlayer.MoveBackward(0.1f);
if (e == Keys.D)
this.MainPlayer.StrafeRight(0.1f);
if (e == Keys.Space)
this.MainPlayer.MoveUp(0.1f);
if (e == Keys.LeftShift)
this.MainPlayer.MoveDown(0.1f);
}
#endregion
}
}
Notice that right now, my code to move the player when pressing "A" to the left (strafe left if you will) is just decreasing x, same thing with the other WASD keys.
This works great if the camera is pointed straight ahead, then you're moving on a 2D plane with WASD.
But when the camera changes positions to any YAW/Pitch, WASD is no longer correct, it will still move you on 1 axis and you're no longer oriented on that access.
So I'm looking for guidance on what kind of math I need to understand to be able to calculate the full xyz that's directly to the left.
Basically I want to calculate a line that is at axis 0 based on orientation. So Say I'm facing 45 degrees to the North East Exactly with 0 yaw (looking straight ahead), then I need to be able to calculate any point on the line exactly to the north west on the x/z plane.
In monogame the Y axis is height, X axis is (left/right) and Z is depth (forward backward).
I might not be using all the correct terms. Been programming for 20 years, this is my first shot at a 3D game.