Table of Contents

First person camera

This C# Intermediate tutorial covers the implementation of first person camera.

Explanation

You learn about mouse movement and how to convert that into a 3d rotation. We set up camera angle limits and finally we apply movement to a first person character controller.

Camera controller

// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net)
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
using Stride.Core.Mathematics;
using Stride.Engine;
using Stride.Input;
using Stride.Physics;

namespace CSharpIntermediate.Code
{
    public class FirstPersonCamera : SyncScript
    {
        public float MouseSpeed = 0.6f;
        public float MaxLookUpAngle = -50;
        public float MaxLookDownAngle = 50;
        public bool InvertMouseY = false;

        private Entity firstPersonCameraPivot;
        private Vector3 camRotation;
        private bool isActive = false;
        private Vector2 maxCameraAnglesRadians;
        private CharacterComponent character;

        public override void Start()
        {
            firstPersonCameraPivot = Entity.FindChild("CameraPivot");

            // Convert the Max camera angles from Degress to Radions
            maxCameraAnglesRadians = new Vector2(MathUtil.DegreesToRadians(MaxLookUpAngle), MathUtil.DegreesToRadians(MaxLookDownAngle));
            
            // Store the initial camera rotation
            camRotation = Entity.Transform.RotationEulerXYZ;

            // Set the mouse to the middle of the screen
            Input.MousePosition = new Vector2(0.5f, 0.5f);

            isActive = true;
            Game.IsMouseVisible = false;

            character = Entity.Get<CharacterComponent>();
        }


        public override void Update()
        {
            if (Input.IsKeyPressed(Keys.Escape))
            {
                isActive = !isActive;
                Game.IsMouseVisible = !isActive;
                Input.UnlockMousePosition();
            }

            if (isActive)
            {
                Input.LockMousePosition();
                var mouseMovement = Input.MouseDelta * MouseSpeed;

                // Update camera rotation values
                camRotation.Y += -mouseMovement.X;
                camRotation.X += InvertMouseY ? -mouseMovement.Y : mouseMovement.Y;
                camRotation.X = MathUtil.Clamp(camRotation.X, maxCameraAnglesRadians.X, maxCameraAnglesRadians.Y);

                // Apply Y rotation to character entity
                character.Orientation = Quaternion.RotationY(camRotation.Y);
                // Entity.Transform.Rotation = Quaternion.RotationY(camRotation.Y);

                // Apply X camera rotation to the existing camera rotations
                firstPersonCameraPivot.Transform.Rotation = Quaternion.RotationX(camRotation.X);
            }
        }
    }
}

Character movement

// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net)
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
using Stride.Core.Mathematics;
using Stride.Engine;
using Stride.Input;
using Stride.Physics;

namespace CSharpIntermediate.Code
{
    public class CharacterMovement : SyncScript
    {
        public Vector3 MovementMultiplier = new Vector3(3, 0, 4);
        private CharacterComponent character;

        public override void Start()
        { 
            character = Entity.Get<CharacterComponent>();
        }

        public override void Update()
        {
            var velocity = new Vector3();
            if (Input.IsKeyDown(Keys.W))
            {
                velocity.Z++;
            }
            if (Input.IsKeyDown(Keys.S))
            {
                velocity.Z--;
            }

            if (Input.IsKeyDown(Keys.A))
            {
                velocity.X++;
            }
            if (Input.IsKeyDown(Keys.D))
            {
                velocity.X--;
            }

            velocity.Normalize();
            velocity *= MovementMultiplier;
            velocity = Vector3.Transform(velocity, Entity.Transform.Rotation);
            character.SetVelocity(velocity);
        }
    }
}