1 module re.input.virtual.joystick;
2 
3 import re.input;
4 import re.math;
5 import std.algorithm;
6 
7 /// a virtual joystick
8 class VirtualJoystick : VirtualInput {
9     // monitors four of inputs to make a joystick
10     static abstract class Node : VirtualInput.Node {
11         @property public Vector2 value();
12     }
13 
14     /// logic-controllable joystick
15     static class LogicJoystick : Node {
16         public Vector2 logic_value = Vector2Zero;
17 
18         @property public override Vector2 value() {
19             return logic_value;
20         }
21     }
22 
23     /// monitors a pair of keyboard keys
24     static class KeyboardKeys : Node {
25         public OverlapBehavior overlap_behavior;
26         public Keys left;
27         public Keys right;
28         public Keys up;
29         public Keys down;
30         private Vector2 _value;
31         private bool _turned_x;
32         private bool _turned_y;
33 
34         /// creates a keyboard keys node
35         this(Keys left, Keys right, Keys up, Keys down,
36                 OverlapBehavior overlap_behavior = OverlapBehavior.init) {
37             this.left = left;
38             this.right = right;
39             this.up = up;
40             this.down = down;
41             this.overlap_behavior = overlap_behavior;
42         }
43 
44         @property public override Vector2 value() {
45             return _value;
46         }
47 
48         public override void update() {
49             // x axis
50             if (Input.is_key_down(left)) {
51                 if (Input.is_key_down(right)) {
52                     switch (overlap_behavior) {
53                     case OverlapBehavior.Cancel:
54                         _value.x = 0;
55                         break;
56                     case OverlapBehavior.Newer:
57                         if (!_turned_x) {
58                             _value.x *= -1;
59                             _turned_x = true;
60                         }
61                         break;
62                     case OverlapBehavior.Older:
63                         break; // we don't touch the value
64                     default:
65                         assert(0);
66                     }
67                 } else {
68                     _turned_x = false;
69                     _value.x = -1;
70                 }
71             } else if (Input.is_key_down(right)) {
72                 _turned_x = false;
73                 _value.x = 1;
74             } else {
75                 _turned_x = false;
76                 _value.x = 0;
77             }
78             // y axis
79             if (Input.is_key_down(up)) {
80                 if (Input.is_key_down(down)) {
81                     switch (overlap_behavior) {
82                     case OverlapBehavior.Cancel:
83                         _value.y = 0;
84                         break;
85                     case OverlapBehavior.Newer:
86                         if (!_turned_y) {
87                             _value.y *= -1;
88                             _turned_y = true;
89                         }
90                         break;
91                     case OverlapBehavior.Older:
92                         break; // we don't touch the value
93                     default:
94                         assert(0);
95                     }
96                 } else {
97                     _turned_y = false;
98                     _value.y = -1;
99                 }
100             } else if (Input.is_key_down(down)) {
101                 _turned_y = false;
102                 _value.y = 1;
103             } else {
104                 _turned_y = false;
105                 _value.y = 0;
106             }
107         }
108     }
109 
110     @property public Vector2 value() {
111         foreach (node; nodes) {
112             auto val = (cast(Node) node).value;
113             if (val != raymath.Vector2Zero()) {
114                 return val;
115             }
116         }
117         return raymath.Vector2Zero();
118     }
119 }
120 
121 @("input-joystick")
122 unittest {
123     auto the_joy = new VirtualJoystick();
124     the_joy.nodes ~= new VirtualJoystick.KeyboardKeys(Keys.KEY_LEFT,
125             Keys.KEY_RIGHT, Keys.KEY_UP, Keys.KEY_DOWN);
126 
127     assert(the_joy.nodes.length > 0);
128 }