How Do I Create A Virtual Controller With Corona?

Hello guys, i would like to create a virtual controller (D-pad?) for my next game for better user experience in controlling my game. Previously i created my own arrow buttons but I believe by creating virtual controller it should be easier for the users to play the game. I tried to google around how to do that with corona and apparently someone ever made a sample code. I found it and i downloaded it but I want to modify it a little bit. This is the thing I’m talking about:

a23o6w.jpg

I would like to know how to create the same virtual controller but when the code detect the movement of the virtual controller around the “upper” area, the player should jump instead of moving to the upper area. How to do that? Any tutorial?

If you’re using something like the one Rob showed in this link:   http://forums.coronalabs.com/topic/32941-virtual-joystick-module-for-games/   (or https://developer.coronalabs.com/category/tags/joystick)

Then you would need to modify the joystick:touch function, under the “phase == moved” section – determine what range of motion counts as an “up” event (and do you have to hold it there for some time period before it jumps?).  In the code from Rob’s comment above, you’ll see the calculation of “angle” … check if that is within 135 to 45 deg (or whatever range you want), and if so, trigger a “moveUp” event.

Without seeing your code, it’s hard to be more specific.  E.g. how are you currently triggering “moveLeft” and “moveRight” events?  dispatchEvent?  calling a function?  setting a variable so that your enterFrame code picks it up?

hello jbp1, i am aware of that thread already. some of the links from the thread aren’t active anymore. The script from dunkelgames, for example, doesnt work, because it is using old codes that dont work with corona latest build anymore. if you notice, the link that Rob gave in the thread also doesnt exist, it just redirect to http://code.coronalabs.com/ where i can’t find anything there.

as for my code, i just got it from googling around. how do i attach the code here? i dont build it myself and to be honest still confused on how it work

If you create controllers watch for accuracy problems!

http://forums.coronalabs.com/topic/51352-corona-sdk-and-accuracy-sliders-touch-events-rounded-values/

Take another look at the forums link … Rob eventually re-posted the source code inside that entry (scroll down about half-way).  That code works for me on the most recent public release.

To insert code in-line with a post, look for the “< >” button in the editor panel – beneath the smiley face.  Otherwise, I think most people just upload it to Dropbox, G-Drive, Github, etc. and put a link in the post.

guys could you tell me please how you made the single one ??, i need it and i cant find it anywhere, Rob´s code also doesnt show any errors but doesnt´show the stick neither !!

“doesn’t show the stick” … Rob’s code used newImageRect, so you needed to grab some images from somewhere (or else change those to newRect or newCircle and then setFillColor to something visible).

Oh, i see…im using this one, can you tell me if its a separated module and i call it from for example the level1.lua or i can paste it in the same file ??

And with what  instruction do i move the character ??

Excuse me,  im really lost with this feature =(

module(…, package.seeall);

function joystick:create(group, imgJoystick, joyWidth, joyHeight, imgBgJoystick, bgWidth, bgHeight)
    local stage = display.getCurrentStage();
    local mMin = math.min;
    local mCos = math.cos;
    local mSin = math.sin;
    local mAtan2 = math.atan2;
    local mSqrt = math.sqrt;
    local mFloor = math.floor;
    local mPi = math.pi;
    
    local joyGroup = display.newGroup();
    group:insert(joyGroup);
    local bgJoystick = display.newImageRect(joyGroup, imgBgJoystick, bgWidth, bgHeight );
    bgJoystick.x, bgJoystick.y = 0, 0;
    local radius = bgJoystick.contentWidth/4;
    joyGroup.radius = radius;
    local radToDeg = 180/mPi;
    local degToRad = mPi/180;
    local joystick = display.newImageRect(joyGroup, imgJoystick, joyWidth, joyHeight );
    
    function joystick:touch(event)
        local phase = event.phase;
        if phase == “moved” then
            if self.isFocus then
                local parent = self.parent;
                local posX, posY = parent:contentToLocal(event.x, event.y);
                local angle = (mAtan2( posX, posY )*radToDeg)-90;
                if angle < 0 then angle = 360 + angle end;
                local distance = mSqrt((posX*posX)+(posY*posY));
                if distance >= radius then
                    local radAngle = angle*degToRad;
                    distance = radius;
                    self.x, self.y = distance*mCos(radAngle), -distance*mSin(radAngle)
                else
                    self.x, self.y = posX, posY;
                end
                parent.angle = angle;
                parent.distance = distance;
            else
                stage:setFocus(event.target, event.id);
                self.isFocus = true;
                self.parent.state = true;
                self.alpha = 0.5;    
            end
        elseif phase == “began” then
            stage:setFocus(event.target, event.id);
            self.isFocus = true;
            self.parent.state = true;
            self.alpha = 0.5;
            local parent = self.parent;
            local posX, posY = parent:contentToLocal(event.x, event.y);
            self.x, self.y = posX, posY;
            local angle = (mAtan2( posX, posY )*radToDeg)-90;
            if angle < 0 then angle = 360 + angle end;
            local distance = mSqrt((posX*posX)+(posY*posY));
            if distance >= radius then
                local radAngle = angle*degToRad;
                distance = radius;
                self.x, self.y = distance*mCos(radAngle), -distance*mSin(radAngle)
            else
                self.x, self.y = posX, posY;
            end
            parent.angle = angle;
            parent.distance = distance;
        else
            self.isFocus = false;
            self.parent.state = false;
            self.x, self.y = 0, 0;
            self.parent.distance = 0;
            self.parent.angle = 0;
            stage:setFocus(nil, event.id);
            self.alpha = 1;
        end
        return true;
    end
    
    joyGroup.activate = function()
        joyGroup[1]:addEventListener(“touch”, joyGroup[2]);
        joyGroup.angle, joyGroup.distance = 0, 0;
    end
    joyGroup.deactivate = function()
        joyGroup[1]:removeEventListener(“touch”, joyGroup[2]);
        joyGroup.angle, joyGroup.distance = 0, 0;
    end
    joyGroup.x, joyGroup.y = joyGroup.contentWidth*0.5, display.contentHeight-joyGroup.contentHeight*0.5;
    return (joyGroup);
end

Here’s a simpler version of Rob’s original code (no images required, removed some nice-ities but it still works):

-- simpleJoystick.lua local Joystick = {} function Joystick.new( innerRadius, outerRadius ) local stage = display.getCurrentStage() local joyGroup = display.newGroup() local bgJoystick = display.newCircle( joyGroup, 0,0, outerRadius ) bgJoystick:setFillColor( .2,.2,.2 ) local radToDeg = 180/math.pi local degToRad = math.pi/180 local joystick = display.newCircle( joyGroup, 0,0, innerRadius ) joystick:setFillColor( .8,.8,.8 ) -- for easy reference later: joyGroup.joystick = joystick -- where should joystick motion be stopped? local stopRadius = outerRadius - innerRadius -- return a direction identifier, angle, distance local directionId = 0 local angle = 0 local distance = 0 function joyGroup.getDirection() return directionId end function joyGroup:getAngle() return angle end function joyGroup:getDistance() return distance/stopRadius end function joystick:touch(event) local phase = event.phase if( (phase=='began') or (phase=="moved") ) then if( phase == 'began' ) then stage:setFocus(event.target, event.id) end local parent = self.parent local posX, posY = parent:contentToLocal(event.x, event.y) angle = (math.atan2( posX, posY )\*radToDeg)-90 if( angle \< 0 ) then angle = 360 + angle end -- could expand to include more directions (e.g. 45-deg) if( (angle\>=45) and (angle\<135) ) then directionId = 2 elseif( (angle\>=135) and (angle\<225) ) then directionId = 3 elseif( (angle\>=225) and (angle\<315) ) then directionId = 4 else directionId = 1 end -- could emit "direction" events here --Runtime:dispatchEvent( {name='direction',directionId=directionId } ) distance = math.sqrt((posX\*posX)+(posY\*posY)) if( distance \>= stopRadius ) then distance = stopRadius local radAngle = angle\*degToRad self.x = distance\*math.cos(radAngle) self.y = -distance\*math.sin(radAngle) else self.x = posX self.y = posY end else self.x = 0 self.y = 0 stage:setFocus(nil, event.id) directionId = 0 angle = 0 distance = 0 end return true end function joyGroup:activate() self:addEventListener("touch", self.joystick ) self.directionId = 0 self.angle = 0 self.distance = 0 end function joyGroup:deactivate() self:removeEventListener("touch", self.joystick ) self.directionId = 0 self.angle = 0 self.distance = 0 end return( joyGroup ) end return Joystick

And:

-- main.lua local jslib = require( "simpleJoystick" ) local js = jslib.new( 100, 200 ) js.x = display.contentWidth/2 js.y = display.contentHeight/2 function catchTimer( e ) print( " joystick info: " .. " dir=" .. js:getDirection() .. " angle=" .. js:getAngle() .. " dist="..js:getDistance() ) return true end js:activate() timer.performWithDelay( 500, catchTimer, -1 )

Would someone be so kind as to put that code up on Github or a GIST and post it to the new code exchange?

http://code.coronalabs.com/

Thanks

Rob

WIll do … or  http://code.coronalabs.com/code/simple-joystick   (links to github)

jbp1 you can´t imagine how much i thank you bro

One last question. When im going to move my character ( called “ship” ) im doin it here :

            if( (angle>=45) and (angle<135) ) then
                ship.x=ship.x +10
            elseif( (angle>=135) and (angle<225) ) then
                ship.x=xhip.x-10
            elseif( (angle>=225) and (angle<315) ) then
                ship.x=xhip.y+10
            else
                ship.x=xhip.y-10
            end

But i get a nil value error, what can i do ?

Ahh … now it depends on what exactly you want to do in your code.  RIght now, the loop is triggering every 500 msec (per the timer).  If you’re doing a FPS or action game, you might just want to read the joystick:getDirection() inside of enterFrame (and do your ship movements there).  Or if you’re doing less of an action game, maybe dispatch events every so often (maybe 500 msec is good?)

Re: the nil error … my guess is it can’t find the ship object  (or the xhip object, possible typo in 3 of the lines?)

jajaja the “xhip” was a paste error but the nil it´s for something else =P  , im gonna check.

Jbp1 again thanks a lot, your´e the best man.

There´s no way to give you stars or calificate here ??  =)

If you’re using something like the one Rob showed in this link:   http://forums.coronalabs.com/topic/32941-virtual-joystick-module-for-games/   (or https://developer.coronalabs.com/category/tags/joystick)

Then you would need to modify the joystick:touch function, under the “phase == moved” section – determine what range of motion counts as an “up” event (and do you have to hold it there for some time period before it jumps?).  In the code from Rob’s comment above, you’ll see the calculation of “angle” … check if that is within 135 to 45 deg (or whatever range you want), and if so, trigger a “moveUp” event.

Without seeing your code, it’s hard to be more specific.  E.g. how are you currently triggering “moveLeft” and “moveRight” events?  dispatchEvent?  calling a function?  setting a variable so that your enterFrame code picks it up?

hello jbp1, i am aware of that thread already. some of the links from the thread aren’t active anymore. The script from dunkelgames, for example, doesnt work, because it is using old codes that dont work with corona latest build anymore. if you notice, the link that Rob gave in the thread also doesnt exist, it just redirect to http://code.coronalabs.com/ where i can’t find anything there.

as for my code, i just got it from googling around. how do i attach the code here? i dont build it myself and to be honest still confused on how it work

If you create controllers watch for accuracy problems!

http://forums.coronalabs.com/topic/51352-corona-sdk-and-accuracy-sliders-touch-events-rounded-values/

Take another look at the forums link … Rob eventually re-posted the source code inside that entry (scroll down about half-way).  That code works for me on the most recent public release.

To insert code in-line with a post, look for the “< >” button in the editor panel – beneath the smiley face.  Otherwise, I think most people just upload it to Dropbox, G-Drive, Github, etc. and put a link in the post.

guys could you tell me please how you made the single one ??, i need it and i cant find it anywhere, Rob´s code also doesnt show any errors but doesnt´show the stick neither !!

“doesn’t show the stick” … Rob’s code used newImageRect, so you needed to grab some images from somewhere (or else change those to newRect or newCircle and then setFillColor to something visible).