joystick - attempt to call global 'post' error

I’m getting a joystick.lua:441: attempt to call global ‘post’ error when touching the virtual joystick.  I’m using the virtual joystick created by Roaming Gamer.

At the top of my level1.lua file I have “local joystick = require(‘libs.joystick’)”, which is where my joystick.lua file is located.  The error shows as soon as I touch the on screen joystick. Here’s the code that’s in my function scene:create() section pertaining to the touching of the joystick.

-- create a joystick on the screen joystick.create( group, 200, 200, { eventName = "myJoystickEvent", inUseAlpha = 1, notInUseAlpha = 0.05, useAlphaFadeTime = 250, outerStrokeColor = \_WHITE\_, outerAlpha = 0.5, stickRadius = 65 } ) joystickListener = function( event ) for k,v in ipairs( labelNames ) do print( event.vx ) print( event.vy ) print( event.nx ) print( event.percent ) print( event.phase ) print( event.state ) print( event.angle ) print( event.direction ) end end Runtime:addEventListener("myJoystickEvent", joystickListener)

What am I doing wrong?

I suggest you check the joystick.lua file for any reference to “post” to see what it’s looking for as far as input.

I’m not sure because iv’e never used this joy stick code but here you can try my revision of @Gudicus’s code. 

local actualHD2 = display.actualContentHeight/2 local actualWD2 = display.actualContentWidth/2 local centerX = display.contentCenterX local centerY = display.contentCenterY local checkJoyUse = false local Player = display.newCircle( centerX, centerY, 20 ) Player:setFillColor( 1, 0, 0 ) Player.stroke = { 0, 0, 0.5 } Player.strokeWidth = 4 local border = display.newRoundedRect( centerX - actualWD2 + 70, centerY + actualHD2 - 70, 100, 100, 15) border.alpha = 0.3 border:setFillColor (0.5, 0.5, 0.5 ) local center = display.newCircle( border.x, border.y, 5 ) center:setFillColor(0,0,0) center.alpha = 0.5 local joy = display.newCircle( border.x, border.y, 20 ) joy.alpha=0.5 joy:setFillColor( 0, 0, 0.5 ) local function dragJoystick(event) local joyStickMove = event.target local stage = display.getCurrentStage() if ( event.phase == "began") then checkJoyUse = true stage:setFocus( joyStickMove, event.id ) joyStickMove.isFocus = true elseif event.phase == "moved" then local xMove = event.x local yMove = event.y local leftBorder = border.x - 30 local rightBorder = border.x + 30 local upperBorder = border.y - 30 local lowerBorder = border.y + 30 if ( xMove \< leftBorder ) then xMove = leftBorder end if ( xMove \> rightBorder ) then xMove = rightBorder end if ( yMove \< upperBorder ) then yMove = upperBorder end if ( yMove \> lowerBorder ) then yMove = lowerBorder end joyStickMove.x = xMove joyStickMove.y = yMove elseif event.phase == "ended" or event.phase == "cancelled" then stage:setFocus(joyStickMove, nil) joyStickMove.isFocus = false checkJoyUse = false end return true end joy:addEventListener( "touch", dragJoystick ) local function updatePlayerPos() local speed = 0.3 local getX = ( joy.x - border.x ) \* speed local x = Player.x + getX local getY = ( joy.y - border.y ) \* speed local y = Player.y + getY Player.x = x Player.y = y end local function updateJoystickPos() if checkJoyUse == false then local getX = math.round( ( joy.x - border.x ) / 3 ) local x = border.x + getX local getY = math.round( ( joy.y - border.y ) / 3 ) local y = border.y + getY joy.x = x joy.y = y end end local function updateFrame() updatePlayerPos() updateJoystickPos() end Runtime:addEventListener( "enterFrame", updateFrame )

NOTE – I put this together in a landscape simulator. –

@Alex@Panc - Here’s the code as well as the terminal output of when I’m getting the “joystick.lua:441: attempt to call global ‘post’” error from the post line.

09:50:12.833  eventName = myJoystickEvent angle = 13 vx = 13 vy = -60 nx = 13 ny = -60 percent = 0 phase = moved debugLevel = 0

09:50:12.833  ERROR: Runtime error

if(percent == 0 ) then

print( "eventName = " … eventName … " angle = " … angle … " vx = " … vx … " vy = " … vy … " nx = " … nx … " ny = " … ny … " percent = " … percent … " phase = " … event.phase … " debugLevel = " … debugLevel )

post(eventName, {angle=angle, vx=vx, vy=vy, nx=nx, ny=ny, percent=percent, phase = event.phase, state = “off” },debugLevel)

else

print( "eventName = " … eventName … " angle = " … angle … " vx = " … vx … " vy = " … vy … " nx = " … nx … " ny = " … ny … " percent = " … percent … " phase = " … event.phase … " debugLevel = " … debugLevel )

post(eventName, {angle=angle, vx=vx, vy=vy, nx=nx, ny=ny, percent=percent, phase = event.phase, state = “on” },debugLevel)

end

First, this implies that you have extracted the Joystick code and are not using SSK along with it.  The joystick code relies on the presence of SSK, so if you’ve extracted just the joystick code it not likely to work. 

Second, post() is my shorthand global function for Runtime:dispatchEvent

post( "eventName", { arg1 = 10, arg2 = 20 } ) -- is equivalent to: Runtime:dispatchEvent( { name = "eventName", arg1 = 10, arg2 = 10 } )

So, you have three options:

  1. Use SSK with your project to clear up this and likely other dependencies. 

  2. replace post/listen/ignore calls with appropriate calls to: 

  • post --> Runtime:dispatchEvent()
  • listen–> Runtime:addEventListener()
  • ignore–> Runtime:removeEventListener()
  1. Put this code very early in your project (I suggest putting it in a separate file and requiring that file early in main.lua):

    – Shorthand for Runtime:*() functions – local pairs = _G.pairs _G.listen = function( name, listener ) Runtime:addEventListener( name, listener ) end _G.ignore = function( name, listener ) Runtime:removeEventListener( name, listener ) end _G.autoIgnore = function( name, obj ) if( obj.removeSelf == nil ) then ignore( name, obj ) obj[name] = nil return true end return false end _G.post = function( name, params) params = params or {} local event = { name = name } for k,v in pairs( params ) do event[k] = v end if( not event.time ) then event.time = getTimer() end Runtime:dispatchEvent( event ) end

@roaminggamer - you were correct.  I was attempting to use the joystick code without the SSK.  So I elected to go with option 1, which was to add the ssk (and ssk_core) folders to my project, an I added the line “local joystick = require(‘ssk.RGEasyInputs.joystick’)” to the top of my level1.lua file.

When I go to execute it I still get the runtime error "…\ssk\RGEasyInputs\joystick.lua:439: attempt to call global ‘post’ (a nil value)

14:28:00.127  stack traceback:…"

Did I need to do something else?

  1. You don’t need SSK and SSK Core.  Just include SSK.  If you use both, the one you use second may override the prior.

ssk_core is a lightweight version of ssk I used in a few examples and Corona Geek projects.

  1. Did you add this line line in main.lua near the top?

    require “ssk.loadSSK”

Having the ssk folder (and subfolders) isn’t enough.  You have to load SSK to initialize it.

As you suggested I now just have only the ssk folder in my project, and I added “local joystick = require(‘ssk.loadSSK’)” near the top of my main.lua and to my level1.lua file.  Further down in my level1.lua I have the joystick.create command (referenced in my original post above) which is now producing the runtime error “…:106: attempt to call field ‘create’ (a nil value)”.

@roaminggamer  - I added just “require “ssk.loadSSK”” to my main.lua near the top and in my level1.lua file I added “local joystick = require “ssk.RGEasyInputs.joystick”” to the top.  I’m getting to the joystickListener function, but I’m getting a runtime error "bad argument #1 to ‘ipairs’ (table expected, got nil), when I execute the line “for k,v in ipairs( labelNames ) do”.  It appears nothing is assigned to ipairs.  What’s wrong?

The event table is not numerically indexed (ipairs() is numeric).

Use pairs().

joystickListener = function( event ) for k,v in pairs( event ) do print(k,v) end end

It’s now getting to the joystickListener function, but the onscreen joystick doesn’t seem to be moving in the simulator.  I running Corona on Windows PC and viewing as a NexusOne in the simulator if that helps.  Shouldn’t the image of the joystick move onscreen as you move it?

The code below prints:

phase moved

49

32

49

0

moved

off

124

nil

joystickListener = function( event ) for k,v in pairs( event ) do print( k,v) print( event.vx ) print( event.vy ) print( event.nx ) print( event.percent ) print( event.phase ) print( event.state ) print( event.angle ) print( event.direction ) end end Runtime:addEventListener("myJoystickEvent", joystickListener)

I’m pretty busy right now.  

Tell you what.  Later today I’ll take a break and make a micro example:

  • using latest ssk
  • with joystick on screen
  • moving dot as result of touching joystick.

Then, if there are any issues with joystick code I’ll see and fix them.  If not, you’ll see how it works.

First I need to do client and EAT work.  So, check back tonight.

-Ed

Thank you Ed, I appreciate all of your help!  The biggest issue appears to be with the event.state always having a value of “off”, and the direction appears to always be set to “nil”.

Link to full example:
http://github.com/roaminggamer/RG_FreeStuff/raw/master/AskEd/2016/04/joystick.zip

Video of example:

https://www.youtube.com/watch?v=TM3Z_8w1cd0&feature=youtu.be
 
Pertinent code:

io.output():setvbuf("no") display.setStatusBar(display.HiddenStatusBar) require "ssk.loadSSK" -- 1. Always use groups to contain objects local group = display.newGroup() -- 2. Let's make a background -- centerX, centerY, fullw, fullh - All globals from SSK local back = display.newRect( group, centerX, centerY, fullw, fullh ) back:setFillColor( unpack(\_CYAN\_) ) -- \_CYAN\_ from SSK back.alpha = 0.10 -- 3. It is NOT suggested that you use the joystick code directly. -- Use the oneStick easy input instead. That is why I wrote the easy input helpers. :) -- Yes, I know this stuff is not well documented. -- ssk.easyInputs.oneStick.create( group, { -- Parameters to oneStick builder: eventName = "myJoystickEvent", -- defaults to onJoystick -- Parameters to joystick builder: joyParams = { doNorm = true, -- Calculate normalized vectors and send in event -- This is expensive by default it is false } } ) -- 4. Now make an object to listen for joystick events and to do something -- when it gets them. local bob = display.newImageRect( group, "smiley.png", 48, 48 ) bob.x = centerX bob.y = centerY bob.mx = 0 bob.my = 0 bob.rate = 250 -- pixels-per-second bob.lastTime = system.getTimer() function bob.myJoystickEvent( self, event ) if( autoIgnore( "myJoystickEvent", self) ) then return end -- Table dumper from SSK (for debug) table.dump(event) self.mx = -event.nx self.my = -event.ny self.rotation = event.angle end; listen( "myJoystickEvent", bob ) -- Not a great way to move, but hey its a quick example... -- function bob.enterFrame( self ) if( autoIgnore( "enterFrame", self) ) then return end local curTime = system.getTimer() dt = self.lastTime - curTime self.lastTime = curTime self.x = self.x + self.mx \* self.rate \* dt/1000 self.y = self.y + self.my \* self.rate \* dt/1000 end; listen( "enterFrame", bob )

@roaminggamer - That’s awesome.  Thanks very much for following-up, and I really enjoy your work.  Keep it up!!  

I suggest you check the joystick.lua file for any reference to “post” to see what it’s looking for as far as input.

I’m not sure because iv’e never used this joy stick code but here you can try my revision of @Gudicus’s code. 

local actualHD2 = display.actualContentHeight/2 local actualWD2 = display.actualContentWidth/2 local centerX = display.contentCenterX local centerY = display.contentCenterY local checkJoyUse = false local Player = display.newCircle( centerX, centerY, 20 ) Player:setFillColor( 1, 0, 0 ) Player.stroke = { 0, 0, 0.5 } Player.strokeWidth = 4 local border = display.newRoundedRect( centerX - actualWD2 + 70, centerY + actualHD2 - 70, 100, 100, 15) border.alpha = 0.3 border:setFillColor (0.5, 0.5, 0.5 ) local center = display.newCircle( border.x, border.y, 5 ) center:setFillColor(0,0,0) center.alpha = 0.5 local joy = display.newCircle( border.x, border.y, 20 ) joy.alpha=0.5 joy:setFillColor( 0, 0, 0.5 ) local function dragJoystick(event) local joyStickMove = event.target local stage = display.getCurrentStage() if ( event.phase == "began") then checkJoyUse = true stage:setFocus( joyStickMove, event.id ) joyStickMove.isFocus = true elseif event.phase == "moved" then local xMove = event.x local yMove = event.y local leftBorder = border.x - 30 local rightBorder = border.x + 30 local upperBorder = border.y - 30 local lowerBorder = border.y + 30 if ( xMove \< leftBorder ) then xMove = leftBorder end if ( xMove \> rightBorder ) then xMove = rightBorder end if ( yMove \< upperBorder ) then yMove = upperBorder end if ( yMove \> lowerBorder ) then yMove = lowerBorder end joyStickMove.x = xMove joyStickMove.y = yMove elseif event.phase == "ended" or event.phase == "cancelled" then stage:setFocus(joyStickMove, nil) joyStickMove.isFocus = false checkJoyUse = false end return true end joy:addEventListener( "touch", dragJoystick ) local function updatePlayerPos() local speed = 0.3 local getX = ( joy.x - border.x ) \* speed local x = Player.x + getX local getY = ( joy.y - border.y ) \* speed local y = Player.y + getY Player.x = x Player.y = y end local function updateJoystickPos() if checkJoyUse == false then local getX = math.round( ( joy.x - border.x ) / 3 ) local x = border.x + getX local getY = math.round( ( joy.y - border.y ) / 3 ) local y = border.y + getY joy.x = x joy.y = y end end local function updateFrame() updatePlayerPos() updateJoystickPos() end Runtime:addEventListener( "enterFrame", updateFrame )

NOTE – I put this together in a landscape simulator. –

@Alex@Panc - Here’s the code as well as the terminal output of when I’m getting the “joystick.lua:441: attempt to call global ‘post’” error from the post line.

09:50:12.833  eventName = myJoystickEvent angle = 13 vx = 13 vy = -60 nx = 13 ny = -60 percent = 0 phase = moved debugLevel = 0

09:50:12.833  ERROR: Runtime error

if(percent == 0 ) then

print( "eventName = " … eventName … " angle = " … angle … " vx = " … vx … " vy = " … vy … " nx = " … nx … " ny = " … ny … " percent = " … percent … " phase = " … event.phase … " debugLevel = " … debugLevel )

post(eventName, {angle=angle, vx=vx, vy=vy, nx=nx, ny=ny, percent=percent, phase = event.phase, state = “off” },debugLevel)

else

print( "eventName = " … eventName … " angle = " … angle … " vx = " … vx … " vy = " … vy … " nx = " … nx … " ny = " … ny … " percent = " … percent … " phase = " … event.phase … " debugLevel = " … debugLevel )

post(eventName, {angle=angle, vx=vx, vy=vy, nx=nx, ny=ny, percent=percent, phase = event.phase, state = “on” },debugLevel)

end

First, this implies that you have extracted the Joystick code and are not using SSK along with it.  The joystick code relies on the presence of SSK, so if you’ve extracted just the joystick code it not likely to work. 

Second, post() is my shorthand global function for Runtime:dispatchEvent

post( "eventName", { arg1 = 10, arg2 = 20 } ) -- is equivalent to: Runtime:dispatchEvent( { name = "eventName", arg1 = 10, arg2 = 10 } )

So, you have three options:

  1. Use SSK with your project to clear up this and likely other dependencies. 

  2. replace post/listen/ignore calls with appropriate calls to: 

  • post --> Runtime:dispatchEvent()
  • listen–> Runtime:addEventListener()
  • ignore–> Runtime:removeEventListener()
  1. Put this code very early in your project (I suggest putting it in a separate file and requiring that file early in main.lua):

    – Shorthand for Runtime:*() functions – local pairs = _G.pairs _G.listen = function( name, listener ) Runtime:addEventListener( name, listener ) end _G.ignore = function( name, listener ) Runtime:removeEventListener( name, listener ) end _G.autoIgnore = function( name, obj ) if( obj.removeSelf == nil ) then ignore( name, obj ) obj[name] = nil return true end return false end _G.post = function( name, params) params = params or {} local event = { name = name } for k,v in pairs( params ) do event[k] = v end if( not event.time ) then event.time = getTimer() end Runtime:dispatchEvent( event ) end

@roaminggamer - you were correct.  I was attempting to use the joystick code without the SSK.  So I elected to go with option 1, which was to add the ssk (and ssk_core) folders to my project, an I added the line “local joystick = require(‘ssk.RGEasyInputs.joystick’)” to the top of my level1.lua file.

When I go to execute it I still get the runtime error "…\ssk\RGEasyInputs\joystick.lua:439: attempt to call global ‘post’ (a nil value)

14:28:00.127  stack traceback:…"

Did I need to do something else?