/
anna_klio
/
try
Обзор
Документация
Войти
/
anna_klio
/
try
Код
Запросы
0
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
main
MyGame/BasicCameraController.cs
298 строк
12 KB
Анна Клюковка
Animation of Camera added
08 апр 2024, 22:33
08 апр 2024, 22:33
83e68d1
Код
Авторство
О чём код?
using System; using Stride.Core; using Stride.Core.Mathematics; using Stride.Engine; using Stride.Input; namespace MyGame { /// <summary> /// A script that allows to move and rotate an entity through keyboard, mouse and touch input to provide basic camera navigation. /// </summary> /// <remarks> /// The entity can be moved using W, A, S, D, Q and E, arrow keys, a gamepad's left stick or dragging/scaling using multi-touch. /// Rotation is achieved using the Numpad, the mouse while holding the right mouse button, a gamepad's right stick, or dragging using single-touch. /// </remarks> public class BasicCameraController : SyncScript { private const float MaximumPitch = MathUtil.PiOverTwo * 0.99f; private Vector3 upVector; private Vector3 translation; private float yaw; private float pitch; private bool WeMode = false; public bool Gamepad { get; set; } = false; public Vector3 KeyboardMovementSpeed { get; set; } = new Vector3(5.0f); public Vector3 TouchMovementSpeed { get; set; } = new Vector3(0.7f, 0.7f, 0.3f); public float SpeedFactor { get; set; } = 5.0f; public Vector2 KeyboardRotationSpeed { get; set; } = new Vector2(3.0f); public Vector2 MouseRotationSpeed { get; set; } = new Vector2(1.0f, 1.0f); public Vector2 TouchRotationSpeed { get; set; } = new Vector2(1.0f, 0.7f); public override void Start() { base.Start(); // Default up-direction upVector = Vector3.UnitY; // Configure touch input if (!Platform.IsWindowsDesktop) { Input.Gestures.Add(new GestureConfigDrag()); Input.Gestures.Add(new GestureConfigComposite()); } } public override void Update() { ProcessInput(); UpdateTransform(); } private void ProcessInput() { float deltaTime = (float)Game.UpdateTime.Elapsed.TotalSeconds; translation = Vector3.Zero; yaw = 0f; pitch = 0f; // Keyboard and Gamepad based movement { // Our base speed is: one unit per second: // deltaTime contains the duration of the previous frame, let's say that in this update // or frame it is equal to 1/60, that means that the previous update ran 1/60 of a second ago // and the next will, in most cases, run in around 1/60 of a second from now. Knowing that, // we can move 1/60 of a unit on this frame so that in around 60 frames(1 second) // we will have travelled one whole unit in a second. // If you don't use deltaTime your speed will be dependant on the amount of frames rendered // on screen which often are inconsistent, meaning that if the player has performance issues, // this entity will move around slower. float speed = 1f * deltaTime; Vector3 dir = Vector3.Zero; if (Gamepad && Input.HasGamePad) { GamePadState padState = Input.DefaultGamePad.State; // LeftThumb can be positive or negative on both axis (pushed to the right or to the left) dir.Z += padState.LeftThumb.Y; dir.X += padState.LeftThumb.X; // Triggers are always positive, in this case using one to increase and the other to decrease dir.Y -= padState.LeftTrigger; dir.Y += padState.RightTrigger; // Increase speed when pressing A, LeftShoulder or RightShoulder // Here:does the enum flag 'Buttons' has one of the flag ('A','LeftShoulder' or 'RightShoulder') set if ((padState.Buttons & (GamePadButton.A | GamePadButton.LeftShoulder | GamePadButton.RightShoulder)) != 0) { speed *= SpeedFactor; } } if (Input.HasKeyboard) { // Move with keyboard // Forward/Backward if (Input.IsKeyDown(Keys.W) || Input.IsKeyDown(Keys.Up)) { dir.Z += 1; } if (Input.IsKeyDown(Keys.S) || Input.IsKeyDown(Keys.Down)) { dir.Z -= 1; } // Left/Right if (Input.IsKeyDown(Keys.A) || Input.IsKeyDown(Keys.Left)) { dir.X -= 1; } if (Input.IsKeyDown(Keys.D) || Input.IsKeyDown(Keys.Right)) { dir.X += 1; } // Down/Up if (Input.IsKeyDown(Keys.Q)) { dir.Y -= 1; } if (Input.IsKeyDown(Keys.E)) { dir.Y += 1; } // Increase speed when pressing shift if (Input.IsKeyDown(Keys.LeftShift) || Input.IsKeyDown(Keys.RightShift)) { speed *= SpeedFactor; } // If the player pushes down two or more buttons, the direction and ultimately the base speed // will be greater than one (vector(1, 1) is farther away from zero than vector(0, 1)), // normalizing the vector ensures that whichever direction the player chooses, that direction // will always be at most one unit in length. // We're keeping dir as is if isn't longer than one to retain sub unit movement: // a stick not entirely pushed forward should make the entity move slower. if (dir.Length() > 1f) { dir = Vector3.Normalize(dir); } if (Input.IsKeyPressed(Keys.Escape)) { WeMode = !WeMode; } } // Finally, push all of that to the translation variable which will be used within UpdateTransform() translation += dir * KeyboardMovementSpeed * speed; } // Keyboard and Gamepad based Rotation { // See Keyboard & Gamepad translation's deltaTime usage float speed = 1f * deltaTime; Vector2 rotation = Vector2.Zero; if (Gamepad && Input.HasGamePad) { GamePadState padState = Input.DefaultGamePad.State; rotation.X += padState.RightThumb.Y; rotation.Y += -padState.RightThumb.X; } if (Input.HasKeyboard) { if (Input.IsKeyDown(Keys.NumPad2)) { rotation.X += 1; } if (Input.IsKeyDown(Keys.NumPad8)) { rotation.X -= 1; } if (Input.IsKeyDown(Keys.NumPad4)) { rotation.Y += 1; } if (Input.IsKeyDown(Keys.NumPad6)) { rotation.Y -= 1; } // See Keyboard & Gamepad translation's Normalize() usage if (rotation.Length() > 1f) { rotation = Vector2.Normalize(rotation); } } // Modulate by speed rotation *= KeyboardRotationSpeed * speed; // Finally, push all of that to pitch & yaw which are going to be used within UpdateTransform() pitch += rotation.X; yaw += rotation.Y; } // Mouse movement and gestures { // This type of input should not use delta time at all, they already are frame-rate independent. // Lets say that you are going to move your finger/mouse for one second over 40 units, it doesn't matter // the amount of frames occuring within that time frame, each frame will receive the right amount of delta: // a quarter of a second -> 10 units, half a second -> 20 units, one second -> your 40 units. if (Input.HasMouse) { // Rotate with mouse //if (Input.IsMouseButtonDown(MouseButton.Right)) //{ // Input.LockMousePosition(); // Game.IsMouseVisible = false; // yaw -= Input.MouseDelta.X * MouseRotationSpeed.X; // pitch -= Input.MouseDelta.Y * MouseRotationSpeed.Y; //} //else //{ // Input.UnlockMousePosition(); // Game.IsMouseVisible = true; //} if (WeMode) { Game.IsMouseVisible = true; Input.UnlockMousePosition(); } else { Game.IsMouseVisible = false; Input.LockMousePosition(); yaw -= Input.MouseDelta.X * MouseRotationSpeed.X; pitch -= Input.MouseDelta.Y * MouseRotationSpeed.Y; } } // Handle gestures foreach (var gestureEvent in Input.GestureEvents) { switch (gestureEvent.Type) { // Rotate by dragging case GestureType.Drag: var drag = (GestureEventDrag)gestureEvent; var dragDistance = drag.DeltaTranslation; yaw = -dragDistance.X * TouchRotationSpeed.X; pitch = -dragDistance.Y * TouchRotationSpeed.Y; break; // Move along z-axis by scaling and in xy-plane by multi-touch dragging case GestureType.Composite: var composite = (GestureEventComposite)gestureEvent; translation.X = -composite.DeltaTranslation.X * TouchMovementSpeed.X; translation.Y = -composite.DeltaTranslation.Y * TouchMovementSpeed.Y; translation.Z = MathF.Log(composite.DeltaScale + 1) * TouchMovementSpeed.Z; break; } } } } private void UpdateTransform() { // Get the local coordinate system var rotation = Matrix.RotationQuaternion(Entity.Transform.Rotation); // Enforce the global up-vector by adjusting the local x-axis var right = Vector3.Cross(rotation.Forward, upVector); var up = Vector3.Cross(right, rotation.Forward); // Stabilize right.Normalize(); up.Normalize(); // Adjust pitch. Prevent it from exceeding up and down facing. Stabilize edge cases. var currentPitch = MathUtil.PiOverTwo - MathF.Acos(Vector3.Dot(rotation.Forward, upVector)); pitch = MathUtil.Clamp(currentPitch + pitch, -MaximumPitch, MaximumPitch) - currentPitch; Vector3 finalTranslation = translation; finalTranslation.Z = -finalTranslation.Z; finalTranslation = Vector3.TransformCoordinate(finalTranslation, rotation); // Move in local coordinates Entity.Transform.Position += finalTranslation; // Yaw around global up-vector, pitch and roll in local space Entity.Transform.Rotation *= Quaternion.RotationAxis(right, pitch) * Quaternion.RotationAxis(upVector, yaw); } } }