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