c90e3a4503132749fff7ef11702a450f937528a9
[nit.git] / contrib / tinks / src / client / android_client.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 # Android client with a joystick
16 module android_client is
17 app_name "Tinks!"
18 app_namespace "net.xymus.tinks"
19 android_manifest """<uses-permission android:name="android.permission.INTERNET" />"""
20 android_api_target 10
21 end
22
23 import mnit_android
24 import android::audio
25 import android::vibration
26 import android::landscape
27
28 intrude import client
29 import controls
30
31 redef class App
32
33 # Tank direction control
34 var joystick = new Joystick is lazy
35
36 redef var controls = new Array[Control].with_items(joystick) is lazy
37
38 redef fun input(event)
39 do
40 var local_player = context.local_player
41 var local_tank = local_tank
42 if local_player != null and local_tank != null and event isa ControlEvent then
43 local_player.orders.add new TankDirectionOrder(local_tank, joystick.value_x, joystick.value_y)
44 return true
45 end
46
47 if event isa AndroidKeyEvent then
48 if event.is_back_key then
49 quit = true
50 native_activity.finish
51 return false
52 end
53 end
54
55 return super
56 end
57 end
58
59 redef class ExplosionEvent
60 redef fun client_react(display, turn)
61 do
62 super
63
64 var local_tank = app.local_tank
65 var d = 20
66 if local_tank != null then
67 d = local_tank.pos.dist(pos).to_i
68 d = 100 - d*5
69 d = d.max(10)
70 end
71
72 app.vibrator.vibrate d
73 end
74 end
75
76 # On-demand joystick that popups up when tapping the left border of the screen
77 class Joystick
78 super Control
79
80 # Current position of the joystick from its center on the X axis, in `[-1.0..1.0]`
81 var value_x = 0.0
82
83 # Current position of the joystick from its center on the Y axis, in `[-1.0..1.0]`
84 var value_y = 0.0
85
86 # Deadzone at the center of the joystick where the values are set at 0.0
87 var deadzone = 0.3
88
89 # Position of the center of the joystick, set at where the screen is first tapped
90 var center: nullable ScreenPos
91
92 # Position of the top of the joystick, the one that follows the finger
93 var handle: nullable ScreenPos
94
95 # Id of the pointer/finger that triggered the joystick
96 var captured_pointer: Int = -1
97
98 # Image of the left border
99 var img_zone: Image = app.assets.drawing.joystick_zone
100
101 # Image of the joystick base
102 var img_back: Image = app.assets.drawing.joystick_back
103
104 # Image of the top of the joystick
105 var img_handle: Image = app.assets.drawing.joystick_handle
106
107 # Radius where the top of the joystick can move around the center
108 var radius: Float = img_back.width.to_f / 2.0 - 4.0
109
110 # Width of the left border used to trigger the joystick
111 var capture_width = 400.0
112
113 redef fun draw(display)
114 do
115 display.blit_stretched(img_zone,
116 0, -128,
117 0, display.height+128,
118 capture_width, display.height+128,
119 capture_width, -128)
120
121 var center = center
122 var handle = handle
123 if center != null and handle != null then
124 img_back.scale = 1.0
125 img_handle.scale = 1.0
126 display.blit_centered(img_back, center.x, center.y)
127 display.blit_centered(img_handle, handle.x, handle.y)
128 end
129 end
130
131 redef fun input(event)
132 do
133 if event isa AndroidPointerEvent then
134 var center = center
135 if center == null then
136 # New joystick?
137 print "New joystick? {event.just_went_down} {event.x} < {capture_width}"
138 if event.just_went_down and
139 event.x < capture_width then
140 # Capture it!
141 self.center = new ScreenPos(event.x, event.y)
142 self.captured_pointer = event.pointer_id
143 self.handle = center
144 return true
145 end
146 else
147 # Already down
148
149 # Is it the finger already on the joystick?
150 if captured_pointer != event.pointer_id then return false
151
152 if event.depressed then
153 self.center = null
154 self.handle = null
155 self.value_x = 0.0
156 self.value_y = 0.0
157 else
158 # Update values
159 var dx = center.x - event.x
160 var dy = center.y - event.y # This is inverted, as is the input
161 var d = dx.hypot_with(dy)
162 if d < deadzone then
163 self.value_x = 0.0
164 self.value_y = 0.0
165 self.handle = center
166 else
167 var a = atan2(dx, dy)+pi/2.0
168 self.value_x = a.cos
169 self.value_y = a.sin
170
171 if d > radius then d = radius
172 self.handle = new ScreenPos(center.x+a.cos*d, center.y-a.sin*d)
173 end
174 end
175
176 app.input new ControlEvent(self)
177 return true
178 end
179 end
180
181 return false
182 end
183 end