godot-karrot-starter-theme/Common/CameraController/CharacterCameraController.cs
2024-11-12 18:09:47 +01:00

134 lines
4.2 KiB
C#

using System.Linq;
using Godot;
namespace KarrotStarterTemplate.Common.CameraController;
[GlobalClass]
public partial class CharacterCameraController : Node3D
{
[ExportCategory("Nodes")]
[Export] public Node3D characterToFollow { get; set; }
[ExportCategory("Properties")]
[ExportGroup("Mouse input")]
[Export] public bool enableInput = true;
[Export] public float mouseSensitivity { get; set; } = .5f;
[Export] public Vector2 cameraTiltLimit { get; set; } = new(-45f, 45f);
[ExportGroup("Player")]
[Export] public bool followPlayer = true;
[Export(PropertyHint.Range, "0, 1")] public float followDelay { get; set; } = .5f;
[Export] public bool rotatePlayer = true;
[Export(PropertyHint.Range, "0, 1")] public float rotateDelay { get; set; } = .5f;
private Camera3D _camera; // todo
private SpringArm3D _springArm;
private Vector2 _mouseInput = Vector2.Zero;
public Camera3D camera => _camera;
public SpringArm3D springArm => _springArm;
// Called when the node enters the scene tree for the first time.
public override void _Ready()
{
if (Engine.IsEditorHint())
{
TopLevel = true;
return;
}
characterToFollow ??= (CharacterBody3D)GetParent();
_springArm = GetChildren().OfType<SpringArm3D>().First();
_camera = _springArm.GetChildren().OfType<Camera3D>().First();
GlobalPosition = characterToFollow.GlobalPosition;
// Input.SetMouseMode(Input.MouseModeEnum.Captured);
}
public override void _UnhandledInput(InputEvent @event)
{
if (Engine.IsEditorHint())
{
return;
}
if (!enableInput)
{
return;
}
if (@event is InputEventMouseMotion mouseMotion)
{
_mouseInput = -mouseMotion.Relative * mouseSensitivity;
}
}
public override void _PhysicsProcess(double delta)
{
if (Engine.IsEditorHint())
{
return;
}
if (followPlayer)
{
float weight = Mathf.Clamp(20 * (1 - followDelay) * (float)delta, 0,1 );
GlobalPosition = followDelay > 0 ? GlobalPosition.Lerp(characterToFollow.GlobalPosition, weight) : characterToFollow.GlobalPosition;
}
if (rotatePlayer)
{
float weight = Mathf.Clamp(20 * (1 - rotateDelay) * (float)delta, 0,1 );
Vector3 v = characterToFollow.GlobalRotation;
characterToFollow.GlobalRotation = new Vector3(v.X, Mathf.LerpAngle(v.Y, _springArm.GlobalRotation.Y, weight) , v.Z);
}
if (enableInput)
{
_springArm.Rotation += new Vector3(_mouseInput.Y * (float)delta, 0f, 0f);
Rotation += new Vector3(0f, _mouseInput.X * (float)delta, characterToFollow.GlobalPosition.Y);
var (x, y, z) = _springArm.RotationDegrees;
_springArm.RotationDegrees = new Vector3(Mathf.Clamp(x, cameraTiltLimit.X, cameraTiltLimit.Y), y, z);
_mouseInput = Vector2.Zero;
}
}
// Called every frame. 'delta' is the elapsed time since the previous frame.
public override void _Process(double delta)
{
if (Engine.IsEditorHint())
{
return;
}
if (Input.IsActionJustPressed("click"))
{
var position2D = GetViewport().GetMousePosition();
var dropPlane = new Plane(new Vector3(0, 10f, 0), 0f);
var position3D =
dropPlane.IntersectsRay(camera.ProjectRayOrigin(position2D), camera.ProjectRayNormal(position2D));
if (position3D != null)
{
GD.Print(position3D);
DebugDraw3D.DrawSphere(position3D ?? Vector3.Zero, .5f, Colors.Aqua, 2f);
}
}
}
}
/*
TODO:
1. Zrobić enuma z presetami
if Input.is_action_pressed("click"):
var position2D = get_viewport().get_mouse_position()
var dropPlane = Plane(Vector3(0, 0, 10), z)
var position3D = dropPlane.intersects_ray(camera.project_ray_origin(position2D),camera.project_ray_normal(position2D))
print(position3D)
*/