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 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 |
Strict Import mojo Class VirtualStickTestApp Extends App Const PLAYFIELD_WIDTH:Float = 200 Const PLAYFIELD_HEIGHT:Float = 200 Const PLAYER_SPEED:Float = 5 ' our virtual stick Field mystick:MyStick ' the "player"'s location Field playerX:Float = PLAYFIELD_WIDTH/2 Field playerY:Float = PLAYFIELD_HEIGHT/2 Field playfieldX:Float Field playfieldY:Float = 10 Method OnCreate:Int() mystick = New MyStick mystick.SetRing(100, DeviceHeight()-100, 40) mystick.SetStick(0, 0, 15) mystick.SetDeadZone(0.2) mystick.SetTriggerDistance(5) playfieldX = DeviceWidth()-PLAYFIELD_WIDTH-10 SetUpdateRate 30 Return 0 End Method OnUpdate:Int() ' update the stick usage UpdateStick() ' update the player position If mystick.GetVelocity() <> 0 Then playerX += mystick.GetDX() * PLAYER_SPEED playerY -= mystick.GetDY() * PLAYER_SPEED If playerX < 0 Then playerX = 0 Elseif playerX > PLAYFIELD_WIDTH Then playerX = PLAYFIELD_WIDTH End If playerY < 0 Then playerY = 0 Elseif playerY > PLAYFIELD_HEIGHT Then playerY = PLAYFIELD_HEIGHT End End Return 0 End Method OnRender:Int() Cls(0,0,0) mystick.DoRenderRing() mystick.DoRenderStick() DrawOutlineRect(playfieldX, playfieldY, PLAYFIELD_WIDTH, PLAYFIELD_HEIGHT) DrawCircle(playfieldX + playerX, playfieldY + playerY, 5) ' some test info DrawText("angle="+mystick.GetAngle(), 10, 10) DrawText("vel="+mystick.GetVelocity(), 10, 30) DrawText("dx="+mystick.GetDX(), 10, 50) DrawText("dy="+mystick.GetDY(), 10, 70) Return 0 End Method UpdateStick:Void() If mystick.GetTouchNumber() < 0 Then #if TARGET="android" Then For Local i:Int = 0 To 31 If TouchHit(i) And mystick.GetTouchNumber() < 0 Then mystick.StartTouch(TouchX(i), TouchY(i), i) End End #else If MouseHit(0) Then mystick.StartTouch(MouseX(), MouseY(), 0) End #endif End If mystick.GetTouchNumber() >= 0 Then #if TARGET="android" Then If TouchDown(mystick.GetTouchNumber()) Then mystick.UpdateTouch(TouchX(mystick.GetTouchNumber()), TouchY(mystick.GetTouchNumber())) Else mystick.StopTouch() End #else If MouseDown(0) Then mystick.UpdateTouch(MouseX(), MouseY()) Else mystick.StopTouch() End #endif End End End Class MyStick Extends VirtualStick Method RenderRing:Void(x:Float, y:Float) SetColor 0, 0, 255 Super.RenderRing(x, y) SetColor 255, 255, 255 End Method RenderStick:Void(x:Float, y:Float) SetColor 0, 255, 0 Super.RenderStick(x, y) SetColor 255, 255, 255 End End Class VirtualStick Private ' the coordinates and dimensions for the virtual stick's ring (where the user will first touch) Field ringX:Float Field ringY:Float Field ringRadius:Float ' the coordinates and dimensions for the stick (what the user is pushing around) ' X/Y is relative to the centre of the ring, and positive Y points up Field stickX:Float = 0 Field stickY:Float = 0 Field stickRadius:Float Field stickAngle:Float Field stickPower:Float ' where the user first touched Field firstTouchX:Float Field firstTouchY:Float ' power must always be >= this, or we return 0 Field deadZone:Float ' we need to move the stick this much before it triggers Field triggerDistance:Float = -1 Field triggered:Bool = False ' the index of the touch event that initiated the stick movement Field touchNumber:Int = -1 ' clips the stick to be within the ring, and updates angles, etc. Method UpdateStick:Void() If touchNumber>=0 Then Local length:Float = Sqrt(stickX*stickX+stickY*stickY) stickPower = length/ringRadius If stickPower > 1 Then stickPower = 1 If stickPower < deadZone Then stickPower = 0 stickAngle = 0 stickX = 0 stickY = 0 Else If stickX = 0 And stickY = 0 Then stickAngle = 0 stickPower = 0 Elseif stickX = 0 And stickY > 0 Then stickAngle = 90 Elseif stickX = 0 And stickY < 0 Then stickAngle = 270 Elseif stickY = 0 And stickX > 0 Then stickAngle = 0 Elseif stickY = 0 And stickX < 0 Then stickAngle = 180 Elseif stickX > 0 And stickY > 0 Then stickAngle = ATan(stickY/stickX) Elseif stickX < 0 Then stickAngle = 180+ATan(stickY/stickX) Else stickAngle = 360+ATan(stickY/stickX) End If length > ringRadius Then stickPower = 1 stickX = Cos(stickAngle) * ringRadius stickY = Sin(stickAngle) * ringRadius End End End End Public Method GetTouchNumber:Int() Return touchNumber End ' the angle in degrees that the user is pushing, going counter-clockwise from right Method GetAngle:Float() Return stickAngle End ' the strength of the movement (0 means dead centre, 1 means at the edge of the ring (or past it) Method GetVelocity:Float() Return stickPower End ' based on the angle and velocity, get the DX Method GetDX:Float() Return Cos(stickAngle) * stickPower End ' based on the angle and velocity, get the DY Method GetDY:Float() Return Sin(stickAngle) * stickPower End ' we just touched the screen at point (x,y), so start "controlling" if we touched inside the ring Method StartTouch:Void(x:Float, y:Float, touchnum:Int) If touchNumber < 0 Then If (x-ringX)*(x-ringX) + (y-ringY)*(y-ringY) <= ringRadius*ringRadius Then touchNumber = touchnum firstTouchX = x firstTouchY = y triggered = False If triggerDistance <= 0 Then triggered = True stickX = x-ringX stickY = ringY-y End UpdateStick() End End End ' a touch just moved, so we may need to update the stick Method UpdateTouch:Void(x:Float, y:Float) If touchNumber>=0 Then If Not triggered Then If (x-firstTouchX)*(x-firstTouchX)+(y-firstTouchY)*(y-firstTouchY) > triggerDistance*triggerDistance Then triggered = True End End If triggered Then stickX = x - ringX stickY = ringY - y UpdateStick() End End End ' we just released a touch, which may have been this one Method StopTouch:Void() If touchNumber>=0 Then touchNumber = -1 stickX = 0 stickY = 0 stickAngle = 0 stickPower = 0 triggered = False End End Method DoRenderRing:Void() RenderRing(ringX, ringY) End Method DoRenderStick:Void() RenderStick(ringX+stickX, ringY-stickY) End ' draws the stick (may be overridden to do images, etc.) Method RenderStick:Void(x:Float, y:Float) DrawCircle(x, y, stickRadius) End ' draws the outside ring (may be overridden to do images, etc.) Method RenderRing:Void(x:Float, y:Float) DrawCircle(x, y, ringRadius) End ' set the location and radius of the ring Method SetRing:Void(ringX:Float, ringY:Float, ringRadius:Float) Self.ringX = ringX Self.ringY = ringY Self.ringRadius = ringRadius End ' set the location and radius of the stick Method SetStick:Void(stickX:Float, stickY:Float, stickRadius:Float) Self.stickX = stickX Self.stickY = stickY Self.stickRadius = stickRadius End Method SetDeadZone:Void(deadZone:Float) Self.deadZone = deadZone End Method SetTriggerDistance:Void(triggerDistance:Float) Self.triggerDistance = triggerDistance End End Function Main:Int() New VirtualStickTestApp Return 0 End Function DrawOutlineRect:Void(x:Float, y:Float, width:Float, height:Float) DrawLine(x, y, x+width, y) DrawLine(x, y, x, y+height) DrawLine(x+width, y, x+width, y+height) DrawLine(x, y+height, x+width, y+height) End |