Add custom input mapping on top of Godot's InputMap
All checks were successful
/ build (push) Successful in 1m32s
All checks were successful
/ build (push) Successful in 1m32s
This commit is contained in:
parent
de59b2486a
commit
c98d7739aa
6 changed files with 281 additions and 28 deletions
|
@ -1,7 +1,10 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Carotrauma.scripts.libs.input;
|
||||||
using Godot;
|
using Godot;
|
||||||
using System;
|
|
||||||
|
|
||||||
public partial class SandboxPlayer : CharacterBody3D
|
namespace Carotrauma.scenes.sandbox.player;
|
||||||
|
|
||||||
|
public partial class SandboxPlayer : CharacterBody3D, IInputProvider
|
||||||
{
|
{
|
||||||
|
|
||||||
[Export]
|
[Export]
|
||||||
|
@ -9,36 +12,52 @@ public partial class SandboxPlayer : CharacterBody3D
|
||||||
[Export]
|
[Export]
|
||||||
public float JumpVelocity = 4.5f;
|
public float JumpVelocity = 4.5f;
|
||||||
|
|
||||||
|
[Export] public float MouseSensitivity = 0.05f;
|
||||||
|
|
||||||
// Get the gravity from the project settings to be synced with RigidBody nodes.
|
// Get the gravity from the project settings to be synced with RigidBody nodes.
|
||||||
public float gravity = ProjectSettings.GetSetting("physics/3d/default_gravity").AsSingle();
|
public float gravity = ProjectSettings.GetSetting("physics/3d/default_gravity").AsSingle();
|
||||||
|
|
||||||
private float camera_anglev = 0;
|
private float camera_anglev = 0;
|
||||||
|
private Node3D pivot;
|
||||||
private Camera3D cam;
|
private Camera3D cam;
|
||||||
|
|
||||||
public override void _Ready() {
|
private KeyInputAction GrabCursor;
|
||||||
cam = GetChild<Camera3D>(3, true);
|
private KeyInputAction Jump;
|
||||||
|
private VectorInputAction Movement;
|
||||||
|
|
||||||
|
public void CreateInputs() {
|
||||||
|
GrabCursor = this.KeyInput(Key.Escape);
|
||||||
|
Jump = this.KeyInput(Key.Space);
|
||||||
|
Movement = this.VectorKeyInput(Key.D, Key.A, Key.S, Key.W);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void _EnterTree() {
|
||||||
|
CreateInputs();
|
||||||
|
}
|
||||||
|
|
||||||
public static float ToRadians (float degrees) {
|
public override void _Ready() {
|
||||||
// Angle in 10th of a degree
|
pivot = GetChild<Node3D>(2, true);
|
||||||
return (float)((degrees * Math.PI)/180.0f);
|
cam = pivot.GetChild<Camera3D>(0, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void _Input(InputEvent @event) {
|
public override void _Input(InputEvent @event) {
|
||||||
if (@event is InputEventMouseMotion) {
|
if (@event is InputEventMouseMotion && Input.MouseMode == Input.MouseModeEnum.Captured) {
|
||||||
var M = (InputEventMouseMotion)@event;
|
var M = (InputEventMouseMotion)@event;
|
||||||
cam.RotateY(ToRadians(-M.Relative.X * 0.3f));
|
|
||||||
var changeV = -M.Relative.Y * 0.3f;
|
pivot.RotateX(Mathf.DegToRad(-M.Relative.Y * MouseSensitivity));
|
||||||
if (camera_anglev + changeV > -50 && camera_anglev + changeV < 50) {
|
RotateY(Mathf.DegToRad(-M.Relative.X * MouseSensitivity));
|
||||||
camera_anglev += changeV;
|
|
||||||
cam.RotateX(ToRadians(changeV));
|
Vector3 cameraRot = pivot.RotationDegrees;
|
||||||
}
|
cameraRot.X = Mathf.Clamp(cameraRot.X, -70, 70);
|
||||||
GetViewport().SetInputAsHandled();
|
pivot.RotationDegrees = cameraRot;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void _PhysicsProcess(double delta) {
|
public override void _PhysicsProcess(double delta) {
|
||||||
|
|
||||||
|
if (GrabCursor.IsJustPressed())
|
||||||
|
Input.MouseMode = Input.MouseMode == Input.MouseModeEnum.Visible ? Input.MouseModeEnum.Captured : Input.MouseModeEnum.Visible;
|
||||||
|
|
||||||
Vector3 velocity = Velocity;
|
Vector3 velocity = Velocity;
|
||||||
|
|
||||||
// Add the gravity.
|
// Add the gravity.
|
||||||
|
@ -46,12 +65,12 @@ public partial class SandboxPlayer : CharacterBody3D
|
||||||
velocity.Y -= gravity * (float)delta;
|
velocity.Y -= gravity * (float)delta;
|
||||||
|
|
||||||
// Handle Jump.
|
// Handle Jump.
|
||||||
if (Input.IsActionJustPressed("jump") && IsOnFloor())
|
if (Jump.IsJustPressed() && IsOnFloor())
|
||||||
velocity.Y = JumpVelocity;
|
velocity.Y = JumpVelocity;
|
||||||
|
|
||||||
// Get the input direction and handle the movement/deceleration.
|
// Get the input direction and handle the movement/deceleration.
|
||||||
// As good practice, you should replace UI actions with custom gameplay actions.
|
// As good practice, you should replace UI actions with custom gameplay actions.
|
||||||
Vector2 inputDir = Input.GetVector("move_left", "move_right", "move_forward", "move_back");;
|
Vector2 inputDir = Movement.GetStrength();
|
||||||
Vector3 direction = (Transform.Basis * new Vector3(inputDir.X, 0, inputDir.Y)).Normalized();
|
Vector3 direction = (Transform.Basis * new Vector3(inputDir.X, 0, inputDir.Y)).Normalized();
|
||||||
if (direction != Vector3.Zero)
|
if (direction != Vector3.Zero)
|
||||||
{
|
{
|
||||||
|
@ -67,4 +86,7 @@ public partial class SandboxPlayer : CharacterBody3D
|
||||||
Velocity = velocity;
|
Velocity = velocity;
|
||||||
MoveAndSlide();
|
MoveAndSlide();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
public List<InputAction> Actions => _actions;
|
||||||
|
private List<InputAction> _actions = new();
|
||||||
|
}
|
|
@ -1,13 +1,10 @@
|
||||||
[gd_scene load_steps=4 format=3 uid="uid://v5iatrrwgror"]
|
[gd_scene load_steps=3 format=3 uid="uid://v5iatrrwgror"]
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://scenes/sandbox/player/SandboxPlayer.cs" id="1_auraj"]
|
|
||||||
|
|
||||||
[sub_resource type="CapsuleMesh" id="CapsuleMesh_orax3"]
|
[sub_resource type="CapsuleMesh" id="CapsuleMesh_orax3"]
|
||||||
|
|
||||||
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_4fhb2"]
|
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_4fhb2"]
|
||||||
|
|
||||||
[node name="Player" type="CharacterBody3D"]
|
[node name="Player" type="CharacterBody3D"]
|
||||||
script = ExtResource("1_auraj")
|
|
||||||
|
|
||||||
[node name="CSGMesh3D" type="CSGMesh3D" parent="."]
|
[node name="CSGMesh3D" type="CSGMesh3D" parent="."]
|
||||||
mesh = SubResource("CapsuleMesh_orax3")
|
mesh = SubResource("CapsuleMesh_orax3")
|
||||||
|
@ -15,9 +12,12 @@ mesh = SubResource("CapsuleMesh_orax3")
|
||||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
|
||||||
shape = SubResource("CapsuleShape3D_4fhb2")
|
shape = SubResource("CapsuleShape3D_4fhb2")
|
||||||
|
|
||||||
[node name="CSGBox3D" type="CSGBox3D" parent="."]
|
[node name="Pivot" type="Node3D" parent="."]
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.436351, 0.458557, 0)
|
|
||||||
size = Vector3(0.5, 0.25, 0.25)
|
|
||||||
|
|
||||||
[node name="Camera" type="Camera3D" parent="."]
|
[node name="Camera" type="Camera3D" parent="Pivot"]
|
||||||
transform = Transform3D(1, 0, 0, 0, 0.944686, 0.327976, 0, -0.327976, 0.944686, 0, 1.61751, 2.35265)
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.5, 0)
|
||||||
|
|
||||||
|
[node name="CSGBox3D" type="CSGBox3D" parent="Pivot"]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.5, -0.5)
|
||||||
|
visibility_range_begin = 0.5
|
||||||
|
size = Vector3(0.25, 0.25, 0.5)
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
[gd_scene load_steps=6 format=3 uid="uid://c3hv3mdy52mar"]
|
[gd_scene load_steps=8 format=3 uid="uid://c3hv3mdy52mar"]
|
||||||
|
|
||||||
[ext_resource type="PackedScene" uid="uid://v5iatrrwgror" path="res://scenes/sandbox/player/player_scene.tscn" id="1_6lr48"]
|
[ext_resource type="PackedScene" uid="uid://v5iatrrwgror" path="res://scenes/sandbox/player/player_scene.tscn" id="1_6lr48"]
|
||||||
|
[ext_resource type="Script" path="res://scenes/sandbox/player/SandboxPlayer.cs" id="2_3mcgf"]
|
||||||
|
[ext_resource type="Script" path="res://scripts/libs/input/InputContext.cs" id="2_mp2vp"]
|
||||||
|
|
||||||
[sub_resource type="BoxShape3D" id="BoxShape3D_tcgka"]
|
[sub_resource type="BoxShape3D" id="BoxShape3D_tcgka"]
|
||||||
size = Vector3(60, 2, 60)
|
size = Vector3(60, 2, 60)
|
||||||
|
@ -38,3 +40,7 @@ mesh = SubResource("SphereMesh_gsyqq")
|
||||||
|
|
||||||
[node name="Player" parent="." instance=ExtResource("1_6lr48")]
|
[node name="Player" parent="." instance=ExtResource("1_6lr48")]
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2.04543, 0)
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2.04543, 0)
|
||||||
|
script = ExtResource("2_3mcgf")
|
||||||
|
|
||||||
|
[node name="Node" type="Node" parent="Player"]
|
||||||
|
script = ExtResource("2_mp2vp")
|
||||||
|
|
48
scripts/libs/input/IInputProvider.cs
Normal file
48
scripts/libs/input/IInputProvider.cs
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Godot;
|
||||||
|
|
||||||
|
namespace Carotrauma.scripts.libs.input;
|
||||||
|
|
||||||
|
public interface IInputProvider {
|
||||||
|
|
||||||
|
void CreateInputs();
|
||||||
|
|
||||||
|
List<InputAction> Actions { get; }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class IInputProviderExtensions {
|
||||||
|
public static KeyInputAction KeyInput(this IInputProvider self, Key key) {
|
||||||
|
var A = new KeyInputAction
|
||||||
|
{
|
||||||
|
Key = key
|
||||||
|
};
|
||||||
|
self.Actions.Add(A);
|
||||||
|
return A;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MouseButtonInputAction MouseButtonInput(this IInputProvider self, MouseButton button) {
|
||||||
|
var A = new MouseButtonInputAction
|
||||||
|
{
|
||||||
|
Button = button
|
||||||
|
};
|
||||||
|
self.Actions.Add(A);
|
||||||
|
return A;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AxisInputAction AxisKeyInput(this IInputProvider self, Key axisPos,
|
||||||
|
Key axisNeg) {
|
||||||
|
|
||||||
|
var pos = self.KeyInput(axisPos);
|
||||||
|
var neg = self.KeyInput(axisNeg);
|
||||||
|
|
||||||
|
return new AxisInputAction(pos.Name, neg.Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static VectorInputAction VectorKeyInput(this IInputProvider self, Key xPos,
|
||||||
|
Key xNeg, Key yPos, Key yNeg) {
|
||||||
|
|
||||||
|
return new VectorInputAction(self.KeyInput(xPos), self.KeyInput(xNeg), self.KeyInput(yPos), self.KeyInput(yNeg));
|
||||||
|
}
|
||||||
|
}
|
112
scripts/libs/input/InputAction.cs
Normal file
112
scripts/libs/input/InputAction.cs
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Godot;
|
||||||
|
|
||||||
|
namespace Carotrauma.scripts.libs.input;
|
||||||
|
|
||||||
|
public abstract class InputAction {
|
||||||
|
public string Name = Guid.NewGuid().ToString();
|
||||||
|
|
||||||
|
public InputEvent Event => getEvent();
|
||||||
|
|
||||||
|
protected abstract InputEvent getEvent();
|
||||||
|
|
||||||
|
public float GetStrength() {
|
||||||
|
return Input.GetActionStrength(Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static implicit operator String(InputAction a) {
|
||||||
|
return a.Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsPressed() {
|
||||||
|
return Input.IsActionPressed(Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsJustPressed() {
|
||||||
|
return Input.IsActionJustPressed(Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsJustReleased() {
|
||||||
|
return Input.IsActionJustReleased(Name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class InputAction<T> : InputAction where T : new() {
|
||||||
|
|
||||||
|
protected override InputEvent getEvent() {
|
||||||
|
var evt = new T();
|
||||||
|
populateEvent(ref evt);
|
||||||
|
return evt as InputEvent;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void populateEvent(ref T evt) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class KeyInputAction : InputAction<InputEventKey> {
|
||||||
|
public Key Key;
|
||||||
|
|
||||||
|
protected override void populateEvent(ref InputEventKey evt) {
|
||||||
|
evt.Keycode = Key;
|
||||||
|
}
|
||||||
|
//
|
||||||
|
// public bool IsPressed() {
|
||||||
|
// LastPolledPressed = Input.IsKeyPressed(Key);
|
||||||
|
// return LastPolledPressed;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public bool IsJustPressed() {
|
||||||
|
// bool Pressed = Input.IsActionPressed(Key);
|
||||||
|
// bool JustPressed = Pressed && !LastPolledPressed;
|
||||||
|
// LastPolledPressed = Pressed;
|
||||||
|
// return JustPressed;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public bool IsJustReleased() {
|
||||||
|
// bool Pressed = Input.IsKeyPressed(Key);
|
||||||
|
// bool JustReleased = !Pressed && LastPolledPressed;
|
||||||
|
// LastPolledPressed = Pressed;
|
||||||
|
// return JustReleased;
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class MouseButtonInputAction : InputAction<InputEventMouseButton> {
|
||||||
|
public MouseButton Button;
|
||||||
|
|
||||||
|
protected override void populateEvent(ref InputEventMouseButton evt) {
|
||||||
|
evt.ButtonIndex = Button;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class AxisInputAction {
|
||||||
|
|
||||||
|
public AxisInputAction(string positiveActionName, string negativeActionName) {
|
||||||
|
PositiveActionName = positiveActionName;
|
||||||
|
NegativeActionName = negativeActionName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string PositiveActionName;
|
||||||
|
public string NegativeActionName;
|
||||||
|
|
||||||
|
public float GetStrength() {
|
||||||
|
return Input.GetAxis(NegativeActionName, PositiveActionName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class VectorInputAction {
|
||||||
|
private readonly string _positiveXName;
|
||||||
|
private readonly string _negativeXName;
|
||||||
|
private readonly string _positiveYName;
|
||||||
|
private readonly string _negativeYName;
|
||||||
|
|
||||||
|
public VectorInputAction(string positiveXName, string negativeXName, string positiveYName, string negativeYName) {
|
||||||
|
_positiveXName = positiveXName;
|
||||||
|
_negativeXName = negativeXName;
|
||||||
|
_positiveYName = positiveYName;
|
||||||
|
_negativeYName = negativeYName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector2 GetStrength() {
|
||||||
|
return Input.GetVector(_negativeXName, _positiveXName, _negativeYName, _positiveYName);
|
||||||
|
}
|
||||||
|
}
|
65
scripts/libs/input/InputContext.cs
Normal file
65
scripts/libs/input/InputContext.cs
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using Godot;
|
||||||
|
|
||||||
|
namespace Carotrauma.scripts.libs.input;
|
||||||
|
|
||||||
|
public partial class InputContext : Node {
|
||||||
|
|
||||||
|
public override void _Ready() {
|
||||||
|
LoadContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void _ExitTree() {
|
||||||
|
UnloadContext();
|
||||||
|
base._ExitTree();
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<InputAction> _actions;
|
||||||
|
|
||||||
|
private double cooldown = 1;
|
||||||
|
public override void _Process(double delta) {
|
||||||
|
cooldown -= delta;
|
||||||
|
if (cooldown > 0) return;
|
||||||
|
|
||||||
|
cooldown = 5;
|
||||||
|
GD.Print(ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LoadContext() {
|
||||||
|
var provider = GetParentOrNull<Node3D>();
|
||||||
|
if (provider is not IInputProvider inputProvider) return;
|
||||||
|
_actions = inputProvider.Actions;
|
||||||
|
_actions.ForEach(LoadAction);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UnloadContext() {
|
||||||
|
_actions?.ForEach(UnloadAction);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LoadAction(InputAction action) {
|
||||||
|
GD.Print("Add action: " + action.Name);
|
||||||
|
InputMap.AddAction(action.Name);
|
||||||
|
GD.Print("Add event to action: " + action.Name);
|
||||||
|
InputMap.ActionAddEvent(action.Name, action.Event);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UnloadAction(InputAction action) {
|
||||||
|
InputMap.ActionEraseEvent(action.Name, action.Event);
|
||||||
|
InputMap.EraseAction(action.Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString() {
|
||||||
|
if (_actions == null) return "No Actions";
|
||||||
|
StringBuilder sb = new();
|
||||||
|
sb.AppendLine("Input Context:");
|
||||||
|
foreach (InputAction action in _actions) {
|
||||||
|
sb.Append(" - ").AppendLine(action.Name);
|
||||||
|
foreach (var inputEvent in InputMap.ActionGetEvents(action.Name))
|
||||||
|
sb.Append(" - ").AppendLine(inputEvent.AsText());
|
||||||
|
}
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in a new issue