Jump to content

Recommended Posts

I'm working on adding controller support to Gesture Wheel, but I don't have a controller and I've never used one to play Don't Starve. I've tried to figure out as much about how it works from looking stuff up, but I'm still a little unsure.

 

I think I've managed to get a system for measuring the analog stick's positions:

local function GetControllerDistance(self, gesture, direction)	direction = direction * self.radius	local pos = self:GetPosition()	if gesture ~= nil then		pos = gesture:GetPosition()	else		pos.x = 0		pos.y = 0	end	local dx = pos.x - direction.x	local dy = pos.y - direction.z	return dx*dx + dy*dyend		local xdir = TheInput:GetAnalogControlValue(CONTROL_MOVE_RIGHT) - TheInput:GetAnalogControlValue(CONTROL_MOVE_LEFT)		local ydir = TheInput:GetAnalogControlValue(CONTROL_MOVE_UP) - TheInput:GetAnalogControlValue(CONTROL_MOVE_DOWN)		local deadzone = .3		if math.abs(xdir) >= deadzone or math.abs(ydir) >= deadzone then			local dir = TheCamera:GetRightVec() * xdir - TheCamera:GetDownVec() * ydir			dir = dir:GetNormalized()		--more code, calls to GetControllerDistance(..., dir)		end

 

However, I'm not sure how to go about setting up a control for bringing up the Gesture Wheel. It seems like pretty much all of the buttons are spoken for, except maybe clicking the analog sticks. How does one go about adding a handler for analog clicking? If you use a controller, do you have another button recommendation?

  • Developer

You can probably use CONTROL_OPEN_DEBUG_MENU for now.  That's (R3) on controllers only.  In our next update though, that may be remapped to (L3) by default, and (R3) will be used for the status screen instead.  I suspect button mappings will change slightly again once we figure out text input as well.

@V2C, Thanks Vito! I'm guessing I'd do it like this:

GLOBAL.TheInput:AddControlHandler(GLOBAL.CONTROL_OPEN_DEBUG_MENU, function(down)    if down then ShowGestureWheel()    else HideGestureWheel() endend)

For comparison, this is how I handle the keyboard key:

	GLOBAL.TheInput:AddKeyDownHandler(KEYBOARDTOGGLEKEY, ShowGestureWheel)	GLOBAL.TheInput:AddKeyUpHandler(KEYBOARDTOGGLEKEY, HideGestureWheel)

If I'm using the debug menu's control mapping, will that clash? It would suck to have it open the debug menu every time they want to do an emote. Looking at EventProcessor for the first time... it looks like it would clash. Unless opening the debug menu is something that's actually disabled by default.

Okay, I pushed a build (1.2.1) of Gesture Wheel using CONTROL_OPEN_DEBUG_MENU if anyone with a controller wants to test it. R3, if I understand correctly, is pushing the right stick in, and I think I have it set up to respond to moving the left stick while R3 is held down. Here's the full 1.2.1 modmain code for reference:

Assets = {	Asset( "IMAGE", "images/status_bg.tex"),	Asset("ATLAS", "images/status_bg.xml"),}local KEYBOARDTOGGLEKEY = GetModConfigData("KEYBOARDTOGGLEKEY")-- local CONTROLLERTOGGLEBUTTON = 13--GetModConfigData("CONTROLLERTOGGLEBUTTON")local CENTERWHEEL = GetModConfigData("CENTERWHEEL")local RESTORECURSOR = GetModConfigData("RESTORECURSOR")local RECORDCURSOR = RESTORECURSOR and RESTORECURSOR > 1local ADJUSTCURSOR = RESTORECURSOR and RESTORECURSOR > 2local IMAGETEXT = GetModConfigData("IMAGETEXT")local SHOWIMAGE = not IMAGETEXT or IMAGETEXT > 1local SHOWTEXT = not IMAGETEXT or IMAGETEXT%2 == 1local GestureWheel = GLOBAL.require("widgets/gesturewheel")local cursorx = 0local cursory = 0local centerx = 0local centery = 0local controls = nillocal keydown = falselocal STARTSCALE = 0.25local NORMSCALE = 1local gesture = nillocal EMOTES = {	wave = {anim={"emoteXL_waving1", "emoteXL_waving2"}, randomanim=true},	bye = {anim={"emoteXL_waving4", "emoteXL_waving3"}, randomanim=true},	happy = {anim="emoteXL_happycheer"},	angry = {anim="emoteXL_angry"},	sad = {anim="emoteXL_sad", fx="tears", fxoffset={0,-.8,0}, fxdelay=17*GLOBAL.FRAMES},	annoyed = {anim="emoteXL_annoyed"},	joy = {anim="research", fx=false},	dance = {anim={"run_pre", "run_loop", "run_loop", "run_loop", "run_pst"}},	bonesaw = {anim="emoteXL_bonesaw"},	facepalm = {anim="emoteXL_facepalm"},	kiss = {anim="emoteXL_kiss"},	--TODO: make sure this list is up to date}local function IsDefaultScreen()	return GLOBAL.TheFrontEnd:GetActiveScreen().name:find("HUD") ~= nilendlocal function ShowGestureWheel()	if keydown then return end	keydown = true	if not IsDefaultScreen() then return end		if RECORDCURSOR then		cursorx, cursory = GLOBAL.TheInputProxy:GetOSCursorPos()	end		if CENTERWHEEL then		GLOBAL.TheInputProxy:SetOSCursorPos(centerx, centery)	else		controls.gesturewheel:SetPosition(GLOBAL.TheInput:GetScreenPosition():Get())	end	controls.gesturewheel:Show()	controls.gesturewheel:ScaleTo(STARTSCALE, NORMSCALE, .25)endlocal function HideGestureWheel()	keydown = false	controls.gesturewheel:Hide()	controls.gesturewheel.inst.UITransform:SetScale(STARTSCALE, STARTSCALE, 1)	if not IsDefaultScreen() then return end	if RESTORECURSOR then		if ADJUSTCURSOR then			local x,y = GLOBAL.TheInputProxy:GetOSCursorPos()			local gx, gy = controls.gesturewheel:GetPosition():Get()			local dx, dy = x-gx, y-gy			cursorx = cursorx + dx			cursory = cursory + dy		end		GLOBAL.TheInputProxy:SetOSCursorPos(cursorx, cursory)	end	if controls.gesturewheel.activegesture then		GLOBAL.TheNet:SendSlashCmdToServer("/" .. controls.gesturewheel.activegesture, true)	endendlocal function AddGestureWheel(self)	controls = self -- this just makes controls available in the rest of the modmain's functions	controls.gesturewheel = controls:AddChild(GestureWheel(EMOTES, SHOWIMAGE, SHOWTEXT))	local screenwidth, screenheight = GLOBAL.TheSim:GetScreenSize()	centerx = screenwidth/2	centery = screenheight/2	controls.gesturewheel:SetPosition(centerx, centery, 0)	controls.gesturewheel.inst.UITransform:SetScale(STARTSCALE, STARTSCALE, 1)	controls.gesturewheel:Hide()		-- Keyboard controls	GLOBAL.TheInput:AddKeyDownHandler(KEYBOARDTOGGLEKEY, ShowGestureWheel)	GLOBAL.TheInput:AddKeyUpHandler(KEYBOARDTOGGLEKEY, HideGestureWheel)		-- Controller controls	-- This should be pressing the right stick in, although V2C says it may change to left stick	GLOBAL.TheInput:AddControlHandler(GLOBAL.CONTROL_OPEN_DEBUG_MENU, function(down)		if down then			ShowGestureWheel()		else			HideGestureWheel()		end	end)		local OldOnUpdate = controls.OnUpdate	local function OnUpdate(...)		OldOnUpdate(...)		if keydown then			self.gesturewheel:OnUpdate()		end	end	controls.OnUpdate = OnUpdateendAddClassPostConstruct( "widgets/controls", AddGestureWheel )

Edited by rezecib

@rezecib, I tried it, and indeed clicking the right stick opens the gesture wheel.

Moving the left stick does select a gesture, but the character moves at the same time, and the chosen gesture isn't the one actually pointed at by the stick (seems reversed, but at an angle)

@Jjmarco, Thanks for testing it! I was worried that I might not have matched the coordinate systems... Can you tinker with the math for it in scripts/widgets/gesturewheel.lua? For example, I think maybe I should be getting direction.y instead for this line:

	local dy = pos.y - direction.z

Also, of course, it would make sense to try switching +/-... Maybe the y direction is backwards (e.g. controller is detecting up as positive y, but screen coordinates using up as negative y).

@rezecib, Okay, I tinkered with these lines and got it mostly working like this:

local dx = pos.x + direction.xlocal dy = pos.y + direction.z

However, there is still the issue of the incorrect gesture being highlighted... It seems when I point to a gesture, it's the one to its right that's highlighted, and I can't figure out how to fix that. I tried changing direction.z to direction.y, but then I can't select any gesture but the ones on the left and right of the wheel.

I tried putting offsets, but then some of the gestures become inaccesible.

 

@rezecib, Yep. If I point toward E, it selects F.

 

Edit: Alright! I figured out a fix. :grin:

if TheInput:ControllerAttached() then		local xdir = TheInput:GetAnalogControlValue(CONTROL_MOVE_RIGHT) - TheInput:GetAnalogControlValue(CONTROL_MOVE_LEFT)		local ydir = TheInput:GetAnalogControlValue(CONTROL_MOVE_UP) - TheInput:GetAnalogControlValue(CONTROL_MOVE_DOWN)		local deadzone = .3		if math.abs(xdir) >= deadzone or math.abs(ydir) >= deadzone then			--local dir = TheCamera:GetRightVec() * xdir - TheCamera:GetDownVec() * ydir			local dir = Vector3(xdir, ydir, 0)			dir = dir:GetNormalized()                        -- etc...
local dx = pos.x - direction.xlocal dy = pos.y - direction.y 

I didn't understand why you defined dir like you did (with TheCamera:GetRightVec() and such), so I changed dir to a Vector3 that directly has the coordinates xdir and ydir. And now it works flawlessly!

 

The only problem left is that the character moves while you choose a gesture, but I'm sure it's easy to fix.

Edited by Jjmarco

@Jjmarco, Ah, I defined it that way because I was referencing the way it handled controller movement. But that makes sense that the camera vectors would be more world-space than screen-space...

 

But thanks, awesome work figuring that out!

@rezecib, Oh, I see, you took the code from playercontroller.lua.

So that's why it was shifted to the right, because dir was an offset of the controller's coordinates for world-space movement.

 

Alright, cool! Glad I could help. :-)

  • Developer

BTW, with today's update, there are now extra mappings for controller buttons that can be used for miscellaneous functions, rather than having to hack over the debug menu button.

CONTROL_MENU_MISC_3 (default=L3)

CONTROL_MENU_MISC_4 (default=R3)

 

In our next update, we'll also be adding a mod api call for notifying when your mod has input focus, and that will allow you to use analog stick input without moving the player.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
  • Create New...