using Godot; using System; namespace Gmtk24 { public partial class Orbit : Node3D { [Signal] public delegate void BlockReleaseEventHandler(BuildingBlock block, uint blockReleaseTypeUint); [Signal] public delegate void DraggingHeldBlockEventHandler(BuildingBlock block); [ExportCategory("Camera")] [Export(PropertyHint.Range, "0,10,0.1")] public float MaxCameraDistance = 1f; [Export(PropertyHint.Range, "0,10,0.1")] public float MinCameraDistance = 0.1f; [Export(PropertyHint.Range, "0,10,0.1")] public float MinCameraHeight = 1.123f; [Export(PropertyHint.Range, "0,10,0.1")] public float MaxCameraHeight = 5f; [Export(PropertyHint.Range, "0,10,0.1")] public float CameraZoomTick = 0.1f; [Export] public Camera3D Camera; [ExportCategory("Hand")] [Export] public Node3D Hand; [Export] public BuildingBlock HeldBlock { private set; get; } [Export] public float RotateAmt = (float)(Math.PI / 12); [Export] public float DragDistanceTreshold = 500f; [ExportCategory("Debug")] [Export] public bool IsEnabled { private set; get; } = false; public Hud Hud; private float CurrentZoom = 1f; private float CurrentHeight = 0; private float CurrentYaw = 0; private float CurrentPitch = 0; private RandomNumberGenerator RNG = new RandomNumberGenerator(); private bool PlacingBlock = false; private Vector2 PlacingMouse = Vector2.Zero; private bool Dragging = false; // Called when the node enters the scene tree for the first time. public override void _Ready() { CurrentPitch = -(float)Math.PI * 0.25f; CurrentYaw = (float)Math.PI * 0.5f; } // Called every frame. 'delta' is the elapsed time since the previous frame. public override void _Process(double delta) { if (Hud != null) { var diff = MaxCameraHeight - MinCameraHeight; CurrentHeight = (float)(Hud.CameraHeightSlider.Value / Hud.CameraHeightSlider.MaxValue * diff + MinCameraHeight); } Position = Vector3.Up * CurrentHeight; Camera.Position = new Vector3(0, 0, CurrentZoom); Quaternion = new Quaternion(Vector3.Up, CurrentYaw) * new Quaternion(Vector3.Right, CurrentPitch); if (HeldBlock != null) { HeldBlock.Position = HeldBlock.Position.Lerp(Vector3.Zero, 0.2f); if (PlacingBlock) { var distance = Camera.GetViewport().GetMousePosition().DistanceSquaredTo(PlacingMouse); if (distance >= DragDistanceTreshold && !Dragging) { Dragging = true; EmitSignal(SignalName.DraggingHeldBlock, HeldBlock); } } else { Dragging = false; } } } public void SetEnabled(bool enabled) { IsEnabled = enabled; Camera.Current = enabled; if (IsEnabled) Input.MouseMode = Input.MouseModeEnum.Visible; else Input.MouseMode = Input.MouseModeEnum.Captured; Hud.CameraHeightContainer.Visible = enabled; } public override void _UnhandledInput(InputEvent @event) { if (!IsEnabled) return; if (@event.IsAction("toggle_pause_menu") && HeldBlock == null) { SetEnabled(false); GetViewport().SetInputAsHandled(); } if (@event.IsActionPressed("drag_orbit")) Input.MouseMode = Input.MouseModeEnum.Captured; if (@event.IsActionReleased("drag_orbit")) Input.MouseMode = Input.MouseModeEnum.Visible; if (Input.IsActionPressed("drag_orbit") && @event is InputEventMouseMotion mouseMotion) { var cameraSensitivity = UserSettings.Singleton.GetCameraSpeedMultipliers(); var mouseMultiplier = 0.0003f; CurrentYaw -= mouseMotion.ScreenRelative.X * mouseMultiplier * cameraSensitivity.X; CurrentPitch -= mouseMotion.ScreenRelative.Y * mouseMultiplier * cameraSensitivity.Y; CurrentPitch = Mathf.Clamp(CurrentPitch, -Mathf.Pi * 0.49f, 0); } if (HeldBlock != null) { if (@event.IsActionPressed("release_block")) { EmitSignal(SignalName.BlockRelease, HeldBlock, (uint)BlockReleaseType.Throw); HeldBlock = null; } if (@event.IsAction("place_block")) { if (@event.IsPressed()) { PlacingBlock = true; PlacingMouse = Camera.GetViewport().GetMousePosition(); } else if (PlacingBlock) { EmitSignal(SignalName.BlockRelease, HeldBlock, (uint)BlockReleaseType.Place); HeldBlock = null; } } if (@event.IsActionPressed("rotate_block_right")) { HeldBlock.RotateY(RotateAmt); } if (@event.IsActionPressed("rotate_block_left")) { HeldBlock.RotateY(-RotateAmt); } } else { if (@event.IsActionPressed("zoom_orbit_out")) { CurrentZoom = Math.Clamp(CurrentZoom - CameraZoomTick, MinCameraDistance, MaxCameraDistance); } if (@event.IsActionPressed("zoom_orbit_in")) { CurrentZoom = Math.Clamp(CurrentZoom + CameraZoomTick, MinCameraDistance, MaxCameraDistance); } } } public bool HoldBlock(BuildingBlock block) { if (HeldBlock != null) return false; // TODO PlacingBlock = false; HeldBlock = block; bool wasPlaced = HeldBlock.Mode == BuildingBlock.BlockMode.Placed; var oldLocalRot = HeldBlock.Quaternion; HeldBlock.SetMode(BuildingBlock.BlockMode.NonPhysical); HeldBlock.Reparent(Hand, true); if (!wasPlaced) HeldBlock.Quaternion = new Quaternion(Vector3.Up, RotateAmt * RNG.RandiRange(0, 100)); else HeldBlock.Quaternion = oldLocalRot; return true; } } public enum BlockReleaseType { Throw = 0, Place = 1, } }