Files
FoodFactory/RTSCamera.cs

188 lines
5.7 KiB
C#
Executable File

using Godot;
using System;
using SJK.Math;
using Chickensoft.SaveFileBuilder;
using Chickensoft.Introspection;
using Chickensoft.Serialization;
[Meta, Id("save_data")]
public partial class SaveData
{
[Save("player_transform")]
public Transform3D Transform3D {get;set;}
[Save("player_camera")]
public Transform3D CameraTransform {get;set;}
}
public partial class RTSCamera : Node3D, ISaveable<SaveData>
{
[Export]
public Camera3D camera;
Vector3 positionStartPos;
Vector3 positionOffsetPos;
Vector3 lastTransalation;
Vector3 cameraTargetOffset;
Action Update_CurrentFunc;
//Generic bookkeeping variables;
Vector2 LastMousePostition;
//Camera Dragging Bookkeeping variables
Vector3 LastMouseGroundPlanePositon;
//Camera Rotating Bookkeeping variables
float CameraRotateSpeed = .5f;
bool isDraging;
public override void _Ready()
{
Update_CurrentFunc = Update_DetectModeStart;
}
void Update_DetectModeStart()
{
if (Input.IsActionJustPressed("move_mouse"))
{
//Mouse Left went Down
//Does nothing basicly
}
else if (Input.IsActionPressed("move_mouse") && GetViewport().GetMousePosition() != LastMousePostition)
{
LastMouseGroundPlanePositon = camera.MouseToGroundPlane() ?? Vector3.Zero;
Update_CurrentFunc = Update_CameraDrag;
Update_CurrentFunc();
// GD.Print("1");
}
else if (Input.IsActionPressed("camera_rotate") && GetViewport().GetMousePosition() != LastMousePostition)
{
LastMouseGroundPlanePositon = camera.MouseToGroundPlane() ?? Vector3.Zero;
Update_CurrentFunc = Update_RotateCamera;
Update_CurrentFunc();
// GD.Print("2");
}
}
public override void _Process(double delta)
{
if (Input.IsActionJustPressed("ui_cancel"))
{
CancelUpdateFunc();
}
// GD.PrintS(positionStartPos,positionOffsetPos,lastTransalation,LastMouseGroundPlanePositon,LastMousePostition,cameraTargetOffset,scrollAmount);
Update_CurrentFunc();
Update_CameraScroll((float)delta);
LastMousePostition = GetViewport().GetMousePosition();
camera.Fov = Mathf.Lerp(camera.Fov, Mathf.Lerp(90, 50, (camera.Position.Y - 5) / (80 - 5)), (float)delta * 10);
}
void CancelUpdateFunc()
{
Update_CurrentFunc = Update_DetectModeStart;
}
void Update_CameraDrag()
{
if (Input.IsActionJustReleased("move_mouse"))
{
CancelUpdateFunc();
}
var hitpos = camera.MouseToGroundPlane() ?? Vector3.Zero;
var diff = LastMouseGroundPlanePositon - hitpos;
GlobalTranslate(diff);
LastMouseGroundPlanePositon = hitpos = camera.MouseToGroundPlane() ?? Vector3.Zero;
}
float scrollAmount;
public override void _UnhandledInput(InputEvent @event)
{
scrollAmount += Input.IsActionJustReleased("mouse_scroll_up") ? 1 : 0;
scrollAmount += Input.IsActionJustReleased("mouse_scroll_down") ? -1 : 0;
if (@event is InputEventKey eventKey && eventKey.Keycode == Key.F)
{
GlobalPosition = Vector3.Zero;
camera.Position = Vector3.Zero;
CancelUpdateFunc();
}
}
void Update_CameraScroll(float delta)
{
// Zoom to scrollwheel
// float scrollAmount = Input.IsActionJustReleased("mouse_scroll_up")?1:0;
// scrollAmount += Input.IsActionJustReleased( "mouse_scroll_down")?-1:0;
// GD.Print(scrollAmount);
float minHeight = 2;
float maxHeight = 30;
// Move camera towards hitPos
// var hitPos = camera.MouseToGroundPlane();
// Vector3 dir = hitPos - camera.Translation;
var dir = -camera.GlobalTransform.Basis.Z * .5f;
var p = camera.Position;
// Stop zooming out at a certain distance.
// TODO: Maybe you should still slide around at 20 zoom?
if (scrollAmount > 0 || p.Y < (maxHeight - 0.1f))
{
cameraTargetOffset += dir * scrollAmount;
}
// DebugDraw3D.DrawArrow(Vector3.Zero,cameraTargetOffset);
Vector3 lastCameraPosition = camera.Position;
camera.Position = camera.Position.Lerp(camera.Position + cameraTargetOffset, delta);
cameraTargetOffset -= camera.Position - lastCameraPosition;
p = camera.Position;
if (p.Y < minHeight)
{
p.Y = minHeight;
}
if (p.Y > maxHeight)
{
p.Y = maxHeight;
}
camera.Position = p;
// Change camera angle
camera.RotationDegrees = new Vector3(
Mathf.Lerp(-50, -75, camera.Position.Y / maxHeight),
camera.RotationDegrees.Y,
camera.RotationDegrees.Z
);
scrollAmount = 0;
}
void Update_RotateCamera()
{
if (!Input.IsActionPressed("move_mouse"))
{
CancelUpdateFunc();
}
Vector2 hitpos = GetViewport().GetMousePosition();
Vector2 diff = LastMousePostition - hitpos;
camera.RotationDegrees = new Vector3(
camera.RotationDegrees.X,
camera.RotationDegrees.Y + (diff.X * CameraRotateSpeed),
camera.RotationDegrees.Z
);
LastMousePostition = hitpos = GetViewport().GetMousePosition();
}
public SaveData Save() => new(){Transform3D = Transform, CameraTransform = camera.Transform};
public void Load(in SaveData data)
{
Transform = data.Transform3D;
camera.Transform = data.CameraTransform;
}
}
public static partial class SJKMath
{
public static Vector3? MouseToPlane(this Plane plane, Camera3D viewCamera, Vector2? mousePos = null)
{
var from = viewCamera.ProjectRayOrigin( mousePos ?? viewCamera.GetViewport().GetMousePosition());
var normal = viewCamera.ProjectRayNormal(mousePos ?? viewCamera.GetViewport().GetMousePosition());
return plane.IntersectsRay(from, normal);
}
public static Vector3? MouseToGroundPlane(this Camera3D viewCamera, Vector2? mousePos = null, float offset = 0) =>
(Plane.PlaneXZ with { D = offset }).MouseToPlane(viewCamera, mousePos);
}