223 lines
8.5 KiB
C#
223 lines
8.5 KiB
C#
using System.Runtime.InteropServices;
|
|
using Prism;
|
|
|
|
namespace FPSExample
|
|
{
|
|
public class FPSPlayer : Entity
|
|
{
|
|
public float WalkingSpeed = 10.0f;
|
|
public float RunSpeed = 20.0f;
|
|
public float JumpForce = 50.0f;
|
|
|
|
public float m_Radius = 0.5f;
|
|
public float TorqueStrength = 10.0f;
|
|
|
|
[NonSerialized]
|
|
public float MouseSensitivity = 10.0f;
|
|
|
|
public float CameraForwardOffset = 0.5f;
|
|
public float CameraYOffset = 0.5f;
|
|
|
|
private bool m_Colliding = false;
|
|
private float m_CurrentSpeed;
|
|
|
|
private RigidBodyComponent m_RigidBody;
|
|
private TransformComponent m_Transform;
|
|
private TransformComponent m_CameraTransform;
|
|
|
|
private Entity m_CameraEntity;
|
|
|
|
private Vec2 m_LastMousePosition;
|
|
private float m_CurrentYMovement = 0.0f;
|
|
|
|
private Vec2 m_MovementDirection = new Vec2(0.0f);
|
|
private bool m_ShouldJump = false;
|
|
|
|
void OnCreate()
|
|
{
|
|
m_Transform = GetComponent<TransformComponent>();
|
|
m_RigidBody = GetComponent<RigidBodyComponent>();
|
|
|
|
m_CurrentSpeed = WalkingSpeed;
|
|
|
|
AddCollisionBeginCallback((n) => { m_Colliding = true; });
|
|
AddCollisionEndCallback((n) => { m_Colliding = false; });
|
|
|
|
m_CameraEntity = FindEntityByTag("Camera");
|
|
|
|
m_CameraTransform = m_CameraEntity.GetComponent<TransformComponent>();
|
|
m_LastMousePosition = Input.GetMousePosition();
|
|
|
|
Input.SetCursorMode(Input.CursorMode.Locked);
|
|
|
|
int size = Marshal.SizeOf<Transform>();
|
|
Console.WriteLine($"C# size of Transform: {size}");
|
|
}
|
|
|
|
void OnUpdate(float ts)
|
|
{
|
|
if (Input.IsKeyPressed(KeyCode.Escape) && Input.GetCursorMode() == Input.CursorMode.Locked)
|
|
Input.SetCursorMode(Input.CursorMode.Normal);
|
|
|
|
if(Input.IsMouseButtonPressed(Input.MouseButton.Left) && Input.GetCursorMode() == Input.CursorMode.Normal)
|
|
Input.SetCursorMode(Input.CursorMode.Locked);
|
|
|
|
m_CurrentSpeed = Input.IsKeyPressed(KeyCode.LeftControl) ? RunSpeed : WalkingSpeed;
|
|
|
|
|
|
UpdateRayCasting();
|
|
UpdateMovementInput();
|
|
UpdateRotation(ts);
|
|
UpdateCameraTransform();
|
|
}
|
|
|
|
void OnPhysicsUpdate(float fixedTimeStep)
|
|
{
|
|
UpdateMovement();
|
|
}
|
|
|
|
private void UpdateRotation(float ts)
|
|
{
|
|
Vec2 currentMousePosition = Input.GetMousePosition();
|
|
Vec2 delta = m_LastMousePosition - currentMousePosition;
|
|
|
|
m_CurrentYMovement = delta.X * MouseSensitivity * ts;
|
|
float xRotation = delta.Y * MouseSensitivity * ts;
|
|
// m_RigidBody.Rotate(new Vec3(0.0f, m_CurrentYMovement, 0.0f));
|
|
|
|
if (delta.X != 0 || delta.Y != 0)
|
|
{
|
|
m_CameraTransform.Rotation += new Vec3(xRotation, m_CurrentYMovement, 0.0f);
|
|
}
|
|
|
|
m_CameraTransform.Rotation = new Vec3(Mathf.Clamp(m_CameraTransform.Rotation.X, -89.0f, 89.0f), m_CameraTransform.Rotation.YZ);
|
|
|
|
m_LastMousePosition = currentMousePosition;
|
|
}
|
|
|
|
private void UpdateMovementInput()
|
|
{
|
|
if (Input.IsKeyPressed(KeyCode.W)){
|
|
m_MovementDirection.Y -= 1.0f;
|
|
Debug.Log("KeyPressed: W");
|
|
}
|
|
else if (Input.IsKeyPressed(KeyCode.S)){
|
|
m_MovementDirection.Y += 1.0f;
|
|
Debug.Log("KeyPressed: S");
|
|
}
|
|
else
|
|
m_MovementDirection.Y = 0.0f;
|
|
|
|
if(Input.IsKeyPressed(KeyCode.A)){
|
|
m_MovementDirection.X += 1.0f;
|
|
Debug.Log("KeyPressed: A");
|
|
}
|
|
else if (Input.IsKeyPressed(KeyCode.D)){
|
|
m_MovementDirection.X -= 1.0f;
|
|
Debug.Log("KeyPressed: D");
|
|
}
|
|
else
|
|
m_MovementDirection.X = 0.0f;
|
|
|
|
m_ShouldJump = Input.IsKeyPressed(KeyCode.Space) && !m_ShouldJump;
|
|
}
|
|
|
|
Collider[] colliders = new Collider[10];
|
|
|
|
private void UpdateRayCasting()
|
|
{
|
|
RaycastHit hitInfo;
|
|
if (Input.IsKeyPressed(KeyCode.H) &&
|
|
Physics.Raycast(m_CameraTransform.Translation + (m_CameraTransform.Transform.Forward),
|
|
m_CameraTransform.Transform.Forward, 20.0f, out hitInfo))
|
|
{
|
|
FindEntityByID(hitInfo.EntityID).GetComponent<MeshComponent>().Mesh.GetMaterial(0).Set("u_AlbedoColor", new Vec3(1.0f ,0.0f, 0.0f));
|
|
}
|
|
|
|
if (Input.IsKeyPressed(KeyCode.I))
|
|
{
|
|
// NOTE: The NonAlloc version of Overlap functions should be used when possible since it doesn't allocate a new array
|
|
// whenever you call it. The normal versions allocates a brand new array every time.
|
|
|
|
int numColliders = Physics.OverlapBoxNonAlloc(m_Transform.Translation, new Vec3(1.0f), colliders);
|
|
|
|
Console.WriteLine("Colliders: {0}", numColliders);
|
|
// When using NonAlloc it's not safe to use a foreach loop since some of the colliders may not exist
|
|
for (int i = 0; i < numColliders; i++)
|
|
{
|
|
Console.WriteLine(colliders[i]);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
private void UpdateMovement()
|
|
{
|
|
// 2. 计算期望的移动方向(世界坐标系)
|
|
Vec3 desiredDirection = Vec3.Zero;
|
|
|
|
if (m_MovementDirection.LengthSquared() != 0.0f)
|
|
{
|
|
Vec3 right = m_CameraTransform.Transform.Right;
|
|
Vec3 forward = m_CameraTransform.Transform.Forward;
|
|
right.Y = 0; forward.Y = 0;
|
|
right.Normalize(); forward.Normalize();
|
|
|
|
desiredDirection = right * m_MovementDirection.X + forward * m_MovementDirection.Y;
|
|
desiredDirection.Normalize();
|
|
|
|
/*
|
|
Vec3 movement = right * m_MovementDirection.X + forward * m_MovementDirection.Y;
|
|
movement.Normalize();
|
|
Vec3 velocity = movement * m_CurrentSpeed;
|
|
velocity.Y = m_RigidBody.GetLinearVelocity().Y;
|
|
m_RigidBody.SetLinearVelocity(velocity);
|
|
*/
|
|
}
|
|
Vec3 targetAngularVelocity = Vec3.Zero;
|
|
if (desiredDirection.LengthSquared() > 0.01f)
|
|
{
|
|
Vec3 up = Vec3.Up;
|
|
Vec3 rotationAxis = Vec3.Cross(desiredDirection, up).Normalized();
|
|
float angularSpeed = 2 * (m_CurrentSpeed / m_Radius);
|
|
targetAngularVelocity = rotationAxis * angularSpeed;
|
|
|
|
Vec3 currentAngular = m_RigidBody.GetAngularVelocity();
|
|
Vec3 angularDiff = targetAngularVelocity - currentAngular;
|
|
|
|
float inertia = 0.4f * m_RigidBody.Mass * m_Radius * m_Radius;
|
|
Vec3 torque = angularDiff * inertia * TorqueStrength;
|
|
m_RigidBody.AddTorque(torque, RigidBodyComponent.ForceMode.Force);
|
|
}
|
|
|
|
|
|
/*
|
|
// 3. 获取当前角速度,计算需要调整的差值
|
|
Vec3 currentAngular = m_RigidBody.GetAngularVelocity();
|
|
Vec3 angularDiff = targetAngularVelocity - currentAngular;
|
|
|
|
// 4. 施加扭矩:扭矩 = 转动惯量 * 角加速度
|
|
// 球体的转动惯量 I = (2/5) * m * r^2 (实心球)
|
|
float inertia = TorqueStrength * m_RigidBody.Mass * m_Radius * m_Radius;
|
|
// 设定一个系数控制响应速度(可调)
|
|
float torqueStrength = 5.0f;
|
|
Vec3 torque = angularDiff * inertia * torqueStrength;
|
|
m_RigidBody.AddTorque(-torque, RigidBodyComponent.ForceMode.Force);
|
|
*/
|
|
|
|
if (m_ShouldJump && m_Colliding)
|
|
{
|
|
Debug.Log("Jump");
|
|
m_RigidBody.AddForce(Vec3.Up * JumpForce, RigidBodyComponent.ForceMode.Impulse);
|
|
m_ShouldJump = false;
|
|
}
|
|
}
|
|
|
|
private void UpdateCameraTransform(){
|
|
Vec3 position = m_Transform.Translation + m_CameraTransform.Transform.Forward * CameraForwardOffset;
|
|
position.Y += CameraYOffset;
|
|
m_CameraTransform.Translation = position;
|
|
}
|
|
}
|
|
} |