Compare commits

...

3 Commits

  1. 14
      CameraController.cs
  2. 19
      level.tscn
  3. 69
      player/CameraController.cs
  4. 2
      player/MovementController.cs
  5. 21
      player/character.tscn
  6. 1
      project.godot
  7. 1
      terrain/Terrain+Editing.cs
  8. 6
      terrain/TerrainChunk.cs
  9. 116
      terrain/terrain_material.tres
  10. 20
      utility/GodotExtensions.cs
  11. 12
      utility/MathExtensions.cs
  12. 1
      utility/PhysicsLayer.cs

@ -1,14 +0,0 @@
public partial class CameraController : Node3D
{
private Vector3 Offset;
public override void _Ready()
{
Offset = Position;
}
public override void _Process(double delta)
{
var target = GetParent<Node3D>().GlobalPosition + Offset;
GlobalPosition = GlobalPosition.Lerp(target, 1 - Pow(0.05f, (float)delta));
}
}

@ -1,7 +1,6 @@
[gd_scene load_steps=9 format=3 uid="uid://cmootlmme7yid"]
[gd_scene load_steps=8 format=3 uid="uid://cmootlmme7yid"]
[ext_resource type="PackedScene" uid="uid://daihc7acaxfns" path="res://character.tscn" id="1_ymqel"]
[ext_resource type="Script" path="res://CameraController.cs" id="2_wn05g"]
[ext_resource type="PackedScene" uid="uid://daihc7acaxfns" path="res://player/character.tscn" id="1_ymqel"]
[ext_resource type="Resource" uid="uid://54xdqxlq2y2g" path="res://level_terrain_data.tres" id="4_axdnd"]
[ext_resource type="Material" uid="uid://doe8owgx4jeu1" path="res://terrain/terrain_material.tres" id="4_edbby"]
[ext_resource type="PackedScene" uid="uid://c732i0mrp6klk" path="res://objects/tree_oak_round.tscn" id="6_xbyit"]
@ -14,26 +13,12 @@
[node name="DirectionalLight3D" type="DirectionalLight3D" parent="."]
transform = Transform3D(0.573576, -0.67101, 0.469846, 0, 0.573576, 0.819152, -0.819152, -0.469846, 0.32899, 0, 8, 0)
shadow_enabled = true
shadow_blur = 1.5
directional_shadow_mode = 0
[node name="Character" parent="." instance=ExtResource("1_ymqel")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -7, -1, -5)
collision_layer = 0
collision_mask = 255
[node name="CameraAnchor" type="Node3D" parent="Character"]
transform = Transform3D(0.707107, 0.5, 0.5, 0, 0.707107, -0.707107, -0.707107, 0.5, 0.5, 0, 0.12, 0)
script = ExtResource("2_wn05g")
[node name="Camera" type="Camera3D" parent="Character/CameraAnchor"]
transform = Transform3D(1, 0, 0, 0, -4.37114e-08, 1, 0, -1, -4.37114e-08, 0, 20, 0)
projection = 1
current = true
size = 4.5
near = 1.0
far = 50.0
[node name="Terrain" type="StaticBody3D" parent="."]
collision_mask = 0
script = ExtResource("9_rniku")

@ -0,0 +1,69 @@
public partial class CameraController : SpringArm3D
{
[Export] public float MovementSmoothing { get; set; } = 8.0f;
[Export] public Vector2 MouseSensitivity { get; set; } = new(0.2f, 0.2f); // Degrees per pixel.
[Export] public float PitchMinimum { get; set; } = 30;
[Export] public float PitchMaximum { get; set; } = 65;
[Export] public float PitchSmoothing { get; set; } = 12.0f;
// FIXME: Fix the "snappyness" when moving slowly.
// FIXME: Fix spring arm clipping through terrain and similar.
// TODO: Gradually return to maximum spring length.
// TODO: Turn player transparent as the camera moves closer.
public static bool IsMouseCaptured
=> 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)
{
if (IsMouseCaptured && ev.IsActionPressed("ui_cancel")) {
// When escape is pressed, release the mouse.
Input.MouseMode = Input.MouseModeEnum.Visible;
GetViewport().SetInputAsHandled();
}
}
public override void _UnhandledInput(InputEvent ev)
{
switch (ev) {
case InputEventMouseButton { ButtonIndex: MouseButton.Left, Pressed: true } when !IsMouseCaptured:
// When left mouse button is pressed, capture the mouse.
Input.MouseMode = Input.MouseModeEnum.Captured;
GetViewport().SetInputAsHandled();
break;
case InputEventMouseMotion motion when IsMouseCaptured:
ApplyRotation(-motion.Relative * MouseSensitivity);
break;
}
}
void ApplyRotation(Vector2 delta)
{
var (pitch, yaw, _) = RotationDegrees;
pitch += delta.Y;
yaw += delta.X;
RotationDegrees = new(pitch, yaw, 0);
}
public override void _Process(double delta)
{
Position = Position.Damp(_offset + _player.GlobalPosition, MovementSmoothing, delta);
var pitch = RotationDegrees.X;
var (min, max) = (-PitchMaximum, -PitchMinimum);
if (pitch < min) pitch = pitch.Damp(min, PitchSmoothing, delta);
if (pitch > max) pitch = pitch.Damp(max, PitchSmoothing, delta);
RotationDegrees = RotationDegrees with { X = pitch };
}
}

@ -41,7 +41,7 @@ public partial class MovementController : Node
var input = Input.GetVector("move_left", "move_right", "move_forward", "move_back");
var camera = GetViewport().GetCamera3D();
var target = input.Rotated(camera.GlobalRotation.Y - Tau / 4) * MaxSpeed;
var target = input.Rotated(-camera.GlobalRotation.Y) * MaxSpeed;
var isOnFloor = Player.IsOnFloor();
var isMoving = target.Dot(horVelocity) > 0.0f;

@ -1,6 +1,7 @@
[gd_scene load_steps=5 format=3 uid="uid://daihc7acaxfns"]
[gd_scene load_steps=6 format=3 uid="uid://daihc7acaxfns"]
[ext_resource type="Script" path="res://MovementController.cs" id="1_akh08"]
[ext_resource type="Script" path="res://player/MovementController.cs" id="1_akh08"]
[ext_resource type="Script" path="res://player/CameraController.cs" id="2_2din1"]
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_urpcu"]
albedo_color = Color(0.25098, 0.690196, 0.12549, 0.815686)
@ -14,6 +15,8 @@ height = 0.35
radius = 0.2
[node name="Character" type="CharacterBody3D"]
collision_layer = 4
collision_mask = 3
floor_max_angle = 0.698132
[node name="MeshInstance3D" type="MeshInstance3D" parent="."]
@ -26,3 +29,17 @@ shape = SubResource("SphereShape3D_6qbb2")
[node name="MovementController" type="Node" parent="."]
script = ExtResource("1_akh08")
[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)
top_level = true
collision_mask = 3
spring_length = 2.0
margin = 0.05
script = ExtResource("2_2din1")
[node name="Camera" type="Camera3D" parent="CameraArm"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 2)
current = true
size = 4.5
far = 500.0

@ -60,6 +60,7 @@ move_jump={
3d_physics/layer_1="Terrain"
3d_physics/layer_2="Objects"
3d_physics/layer_3="Player"
[rendering]

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

@ -15,6 +15,12 @@ public partial class TerrainChunk
[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 {
var tiles = MemoryMarshal.Cast<byte, Tile>(Data);
return ref tiles[GetIndex(pos)];

File diff suppressed because one or more lines are too long

@ -1,7 +1,23 @@
public static class GodotExtensions
{
public static Vector2I RoundToVector2I(this Vector2 vector)
=> new(RoundToInt(vector.X), RoundToInt(vector.Y));
public static T GetParentOrThrow<T>(this Node node)
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)
=> 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));
}

@ -3,4 +3,5 @@ public enum PhysicsLayer
{
Terrain = 0b0000_0001,
Objects = 0b0000_0010,
Player = 0b0000_0100,
}

Loading…
Cancel
Save