VirtualRelativeJoystick
From GiderosMobile
Here you will find various resources to help you create games and apps in Gideros Studio.
note: you may have to provide your own assets (fonts, gfx, …)
Description
This is a VirtualRelativeJoystick Class for Gideros by @snooks and @antix (https://forum.gideros.rocks/discussion/7171/virtual-onscreen-controls-gamepad-does-anybody-want-to-share-theirs).
The Onscreen joystick only appears when the lower left or right quadrant of the screen is touched.
-- VirtualRelativeJoystick for Gideros
--
-- Onscreen joystick that only appears when lower left or right quadrant
-- of screen is touched
--
VirtualRelativeJoystick = Core.class(Sprite)
function VirtualRelativeJoystick:init(options)
-- default options
self.x = 100
self.y = 100
self.outerRadius = 100
self.padColor = 0xaaaadd
self.knobColor = 0xaaddaa
self.onPressed = nil
self.onDragged = nil
self.onReleased = nil
self.left = false -- displays joystick on right side of the screen by default
self.xpos = 0
self.ypos = 0
self.strength = 0
self.angle = 0
self.enabled = false
-- set user supplied options
if options then
for key, value in pairs(options) do self[key]= value end
end
self.outerCircle = self:getNewCircle(self.outerRadius, self.padColor, false)
self:addChild(self.outerCircle)
self.innerNubbin = self:getNewCircle(self.outerRadius * .5, self.knobColor, true)
self:addChild(self.innerNubbin)
self:setPosition(self.x, self.y)
self:setVisible(false)
self:addEventListener(Event.TOUCHES_BEGIN, self.onTouchesBegin, self)
self:addEventListener(Event.TOUCHES_MOVE, self.onTouchesMove, self)
self:addEventListener(Event.TOUCHES_END, self.onTouchesEnd, self)
end
function VirtualRelativeJoystick:onTouchesCancel(e)
self:onTouchesEnd(e)
end
function VirtualRelativeJoystick:onTouchesBegin(e)
local tx, ty = e.touch.x, e.touch.y
local mx, my = application:getContentWidth() * 0.5, application:getContentHeight() * 0.5
if self.left then
if tx > mx or ty < my then return end
else
if tx < mx or ty < my then return end
end
self.controlTouchId = e.touch.id
self:setPosition(tx, ty)
self:setVisible(true)
self.enabled = true -- enable control
if self.onPressed then self.onPressed() end -- run code
e:stopPropagation()
end
function VirtualRelativeJoystick:onTouchesMove(e)
local cos, sin, sqrt, atan2 = math.cos, math.sin, math.sqrt, math.atan2
if not self.enabled then return end
if e.touch.id == self.controlTouchId then
local x, y = self:globalToLocal(e.touch.x, e.touch.y)
local radius = self.outerRadius
local distance = sqrt(x * x + y * y) >< radius -- limit distance to outer radius
-- normalized strength for use with angle
local strength = (distance >< radius) / radius
local angle = ^>atan2(y, x) + 90
local ra = ^< self.angle
y = -distance * cos(ra)
x = distance * sin(ra)
self.innerNubbin:setPosition(x, y)
self.xpos, self.ypos = x / radius, -y / radius
if self.onPressed then
self.onDragged(angle, distance, strength) -- run code
end
self.angle, self.distance, self.strength = angle, distance, strength
e:stopPropagation()
end
end
function VirtualRelativeJoystick:onTouchesEnd(e)
if not self.enabled then return end
if e.touch.id == self.controlTouchId then
self.innerNubbin:setPosition(0, 0)
self.xpos, self.ypos = 0, 0
self:setVisible(false)
self.enabled = false
if self.onReleased then self.onReleased() end -- run code
e:stopPropagation()
end
self.controlTouchId = nil
end
function VirtualRelativeJoystick:getNewCircle(r, color, fill)
local p = Path2D.new()
p:setSvgPath(("M %s 0 a %s %s 0 0 0 %s 0 a %s %s 0 0 0 %s 0 Z"):format(-r, r, r, 2 * r, r, r, -2 * r))
p:setLineThickness(10) -- Outline width
p:setFillColor(color, fill and .6 or .0) --Fill color
p:setLineColor(color, .6) --Line color
return p
end
--
-- VirtualRelativeJoystick demo
--
local options = {}
options.padColor = 0xff0000
options.knobColor = 0x00ff00
options.outerRadius = 50
options.left = true
local jp = VirtualRelativeJoystick.new(options)
-- sprite
local sprite = Pixel.new(0x0000ff, 1, 32, 32)
-- postion
sprite:setPosition(application:getContentWidth()/2, application:getContentHeight()/2)
-- order
stage:addChild(sprite)
stage:addChild(jp)
-- game loop
local x, y = sprite:getPosition()
stage:addEventListener(Event.ENTER_FRAME, function(e)
if jp.enabled then
-- print(jp.angle, jp.distance, jp.strength)
x += math.cos(^<(jp.angle-90)) * jp.strength
y += math.sin(^<(jp.angle-90)) * jp.strength
sprite:setPosition(x, y)
end
end)