VirtualRelativeJoystick

From GiderosMobile
Revision as of 14:56, 11 November 2023 by MoKaLux (talk | contribs) (Created page with "__NOTOC__ 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, …) ===...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

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)