Make camera smoothly follow player

main
copygirl 2 months ago
parent 6decf97524
commit 00579c8559
  1. 17
      player/CameraController.cs
  2. 1
      player/character.tscn
  3. 1
      terrain/Terrain+Editing.cs
  4. 6
      terrain/TerrainChunk.cs
  5. 20
      utility/GodotExtensions.cs
  6. 12
      utility/MathExtensions.cs

@ -1,7 +1,8 @@
public partial class CameraController : SpringArm3D public partial class CameraController : SpringArm3D
{ {
[Export] public Vector2 MouseSensitivity { get; set; } = new(0.2f, 0.2f); // Degrees per pixel. [Export] public Vector2 MouseSensitivity { get; set; } = new(0.2f, 0.2f); // Degrees per pixel.
[Export] public float PitchMinimum { get; set; } = -90; [Export] public float MovementSmoothing { get; set; } = 8.0f;
[Export] public float PitchMinimum { get; set; } = -85;
[Export] public float PitchMaximum { get; set; } = -25; [Export] public float PitchMaximum { get; set; } = -25;
// FIXME: Fix the "snappyness" when moving slowly. // FIXME: Fix the "snappyness" when moving slowly.
@ -12,6 +13,15 @@ public partial class CameraController : SpringArm3D
public static bool IsMouseCaptured public static bool IsMouseCaptured
=> Input.MouseMode == Input.MouseModeEnum.Captured; => Input.MouseMode == Input.MouseModeEnum.Captured;
Vector3 _offset;
Node3D _player;
public override void _Ready()
{
_offset = Position;
_player = this.GetParentOrThrow<Node3D>();
Transform = _player.GlobalTransform.Translated(_offset);
}
public override void _Input(InputEvent ev) public override void _Input(InputEvent ev)
{ {
if (IsMouseCaptured && ev.IsActionPressed("ui_cancel")) { if (IsMouseCaptured && ev.IsActionPressed("ui_cancel")) {
@ -44,4 +54,9 @@ public partial class CameraController : SpringArm3D
pitch = Clamp(pitch, DegToRad(PitchMinimum), DegToRad(PitchMaximum)); pitch = Clamp(pitch, DegToRad(PitchMinimum), DegToRad(PitchMaximum));
Rotation = new(pitch, yaw, 0); Rotation = new(pitch, yaw, 0);
} }
public override void _Process(double delta)
{
Position = Position.Damp(_offset + _player.GlobalPosition, MovementSmoothing, delta);
}
} }

@ -32,6 +32,7 @@ script = ExtResource("1_akh08")
[node name="CameraArm" type="SpringArm3D" parent="."] [node name="CameraArm" type="SpringArm3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 0.766044, 0.642788, 0, -0.642788, 0.766044, 0, 0.1, 0) transform = Transform3D(1, 0, 0, 0, 0.766044, 0.642788, 0, -0.642788, 0.766044, 0, 0.1, 0)
top_level = true
collision_mask = 3 collision_mask = 3
spring_length = 2.0 spring_length = 2.0
margin = 0.05 margin = 0.05

@ -1,5 +1,4 @@
using System.IO; using System.IO;
using System.Runtime.InteropServices;
public partial class Terrain public partial class Terrain
{ {

@ -15,6 +15,12 @@ public partial class TerrainChunk
[Export] public byte[] Data { get; set; } = new byte[SizeInBytes]; [Export] public byte[] Data { get; set; } = new byte[SizeInBytes];
public bool IsEmpty { get {
foreach (var b in Data)
if (b != 0) return false;
return true;
} }
public ref Tile this[TilePos pos] { get { public ref Tile this[TilePos pos] { get {
var tiles = MemoryMarshal.Cast<byte, Tile>(Data); var tiles = MemoryMarshal.Cast<byte, Tile>(Data);
return ref tiles[GetIndex(pos)]; return ref tiles[GetIndex(pos)];

@ -1,7 +1,23 @@
public static class GodotExtensions public static class GodotExtensions
{ {
public static Vector2I RoundToVector2I(this Vector2 vector) public static T GetParentOrThrow<T>(this Node node)
=> new(RoundToInt(vector.X), RoundToInt(vector.Y)); where T : class
{
var parent = node.GetParent();
if (parent == null) throw new InvalidOperationException($"Parent of {node} is null");
if (parent is not T result) throw new InvalidCastException($"Parent of {node} is {node.GetType()}, not {typeof(T)}");
return result;
}
public static T GetNodeOrThrow<T>(this Node parent, NodePath path)
where T : class
{
var node = parent.GetNodeOrNull(path);
if (node == null) throw new InvalidOperationException($"Could not find node {path} from {parent}");
if (node is not T result) throw new InvalidCastException($"Node {path} from {parent} is {node.GetType()}, not {typeof(T)}");
return result;
}
public static (Corner, Corner) GetCorners(this Side side) public static (Corner, Corner) GetCorners(this Side side)
=> side switch { => side switch {

@ -0,0 +1,12 @@
public static class MathExtensions
{
// Framerate independent dampening functions, similar to lerp.
// https://rorydriscoll.com/2016/03/07/frame-rate-independent-damping-using-lerp/
public static float Damp(this float from, float to, float lambda, double delta)
=> Lerp(from, to, 1 - Exp(-lambda * (float)delta));
public static Vector3 Damp(this Vector3 from, Vector3 to, float lambda, double delta)
=> from.Lerp(to, 1 - Exp(-lambda * (float)delta));
public static Vector2I RoundToVector2I(this Vector2 vector)
=> new(RoundToInt(vector.X), RoundToInt(vector.Y));
}
Loading…
Cancel
Save