02.12.2012 22:54:00 • Categories: Monkey X, 2D Game SDK / Framework, Multiplatform • Tags: Monkey
Monkey: virtual stick
Strict Import mojoClass 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(stickXstickX+stickYstickY) 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