summaryrefslogtreecommitdiff
path: root/WorldCamera.cs
blob: 6675fac28dcbc1c9cb57840f84b5609abf7f7ac1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
using Godot;
using System;

public partial class WorldCamera : Camera3D
{
    [Export]
    Node3D target;
    [Export]
    private Mode mode = Mode.Follow;
    private Vector3 posDest; //current destination of camera
    private Vector3 offset = new Vector3(0, 5, -10); //offset from target
    private Vector3 vel; //current velocity of camera
    private float accelCoeff = 10f; //acceleration coefficient
    private float ct = 0.5f; //time to reach destination
    [Export]
    private float rotateSpeed = 2f; //radians per second
    [Export]
    private float mouseSensitivity = 0.005f;
    private bool midDrag = false;

    private enum Mode
    {
        Follow,
        Fixed,
        Rotate //rotates around target
    }

    public override void _Ready()
    {
        Global.camera = this;
        CallDeferred(nameof(InitTarget));
    }

    private void InitTarget()
    {
        if (target == null){
            target = Global.player;
        }
    }

    public override void _Input(InputEvent @event)
    {
        if (@event is InputEventMouseButton mb && mb.ButtonIndex == MouseButton.Middle)
        {
            midDrag = mb.Pressed;
        }
        else if (@event is InputEventMouseMotion motion && midDrag)
        {
            // Horizontal orbit
            offset = offset.Rotated(Vector3.Up, -motion.Relative.X * mouseSensitivity);

            // Vertical orbit around the axis perpendicular to offset in the XZ plane
            Vector3 right = Vector3.Up.Cross(offset).Normalized();
            if (right.LengthSquared() > 0.001f)
            {
                Vector3 newOffset = offset.Rotated(right, -motion.Relative.Y * mouseSensitivity);
                // Clamp to prevent flipping over top or going below horizontal
                float angle = newOffset.AngleTo(Vector3.Up);
                if (angle > 0.15f && angle < Mathf.Pi * 0.85f)
                    offset = newOffset;
            }
        }
    }

    public override void _Process(double delta)
    {
        float rotInput = Input.GetAxis("cam_rotate_cw", "cam_rotate_ccw");

        switch (mode){
            case Mode.Follow:
            case Mode.Rotate:
                if (rotInput != 0)
                    offset = offset.Rotated(Vector3.Up, rotateSpeed * rotInput * (float)delta);
                break;
            case Mode.Fixed:
                break;
        }
    }

    public override void _PhysicsProcess(double delta)
    {
        if (mode == Mode.Follow){
            posDest = target.GlobalPosition + offset;
            if (posDest != Position){
                Vector3 dir = (posDest - Position).Normalized(); 
                float d = (posDest - Position).Length(); //displacement
                
                //vel =  dir * accelCoeff * (float)delta + (posDest - Position) * .1f;
                vel = (posDest-Position)/ct; // we want to reach the destination in ct seconds
                Position += vel * (float)delta + .5f * accelCoeff * dir * (float)(delta*delta);
                
            }
            LookAt(target.GlobalPosition);
        }
    }
}