Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Joystick code + buttons

Hi, so as an alternative control system for people who can't operate their iPhones and iPads using tilt ive been looking into an onscreen joystick that just moves left and right with buttons for shoot and loop the loop for Starsceptre.

I've got a good example for the joystick but when I click on a button it overrides the joystick turning it off.

I'm using touch and not current touch. I'm wondering how I retain two touches. Is it by using touch.id one set for joystick and one each for the two buttons? I'm also trying to fix the joystick in one place and I've almost got that working.

This is the joystick code that creates the stick and locks it to horizontal controls

if controltype=="c" and game== go and touch.y < scY*50 and touch.y > scY*0 and touch.x < scX*35 and touch.x > scX*10 and touch.state == BEGAN then
        control.centre = vec2(touch.x,scY*25)
        control.touch = vec2(scX*25,scY*25)
        control.active = true
    elseif controltype=="c" and game== go and touch.y < scY*50 and touch.y > scY*0 and touch.x < scX*50 and touch.x > scX*0 and touch.state == MOVING then
        control.touch = vec2(touch.x,scY*25)
        if control.touch:dist(control.centre) > control.radius - control.innerRadius then
            control.touch = control.centre + (control.touch - control.centre):normalize()*(control.radius - control.innerRadius)
        end
    else
      control.active = false
    end

And here is the button for shooting. Do both sets need different Touch ID for you each?


if game==go and sh.state ~= sh.deady and sh.state~=sh.jumpin and sh.state~=sh.pullup and sh.state~=sh.dive and paralysis <1 and levelend==false --and CurrentTouch.y < scY*35+yy and (((controltype=="b" or controltype=="c") and touch.y < scY*29 and touch.y > scY*15 and touch.x < scX*78 and touch.x > scX*65) or (controltype=="a" and touch.y < scY*75+yy)) and pauser==false then if touch.state==BEGAN and auto==true then autofire=true if safetybullet==0 then fire=true end end if touch.state==ENDED then if auto==true then autofire=false if (level==3 and timer<5100) then else safetybullet=0 end else if level==3 then if leveltimer<5100 then if safetybullet==0 then fire=true end else if safetybullet==0 then fire = true end end else if safetybullet==0 then fire = true end end end end else autofire=false end

Thanks
Rich

Comments

  • dave1707dave1707 Mod
    Posts: 5,996

    @Majormorgan If you want to keep buttons or any type of screen touch seperate from other ones, then you're correct by saying you need to use Touch ID.

  • Posts: 294

    Thanks @dave1707 !! I'll get on that. Brilliant!!!

  • dave1707dave1707 Mod
    Posts: 5,996

    @Majormorgan Actually, you don't need to use Touch ID. Here's another way. I'm using a name that I give to each button. It might be easier to keep track of each button that way. To use the joyStick, slide your finger back and forth. The shoot button shoots a bullet each time it's hit. The loop button just spins the ship and doesn't let you shoot while spinning.

    supportedOrientations(PORTRAIT_ANY)
    displayMode(FULLSCREEN)
    
    function setup()
        a=0
        miss={}
        rectMode(CENTER)
        jsx,jsy=WIDTH/2,200
        joyStick=button(WIDTH/2,100,400,50,"Joy Stick")
        shoot=button(100,100,100,50,"Shoot")
        loop=button(WIDTH-100,100,100,50,"Loop")
    end
    
    function draw()
        background(40, 40, 50)
        fill(255)
        joyStick:draw()
        for a,b in pairs(miss) do
            sprite("Tyrian Remastered:Fire Rock",b.x,b.y)
            b.y=b.y+10
            if b.y>HEIGHT then
                table.remove(miss,a)
            end
        end
        shoot:draw()
        loop:draw()
        translate(jsx,jsy)
        if looping then
            a=a+10
            rotate(a)
            if a>360 then
                a=0
                looping=false
            end
        end
        sprite("Space Art:Red Ship",0,0)
    end
    
    function touched(t)
        joyStick:touched(t)
        shoot:touched(t)
        loop:touched(t)    
    end
    
    button=class()
    
    function button:init(x,y,w,h,n)
        self.x=x
        self.y=y
        self.w=w
        self.h=h
        self.name=n
    end
    
    function button:draw()
        pushStyle()
        fill(255)
        rect(self.x,self.y,self.w,self.h)
        fill(255,0,0)
        text(self.name,self.x,self.y)
        popStyle()
    end
    
    function button:touched(t)
        if t.x>self.x-self.w/2 and t.x<self.x+self.w/2 and
                t.y>self.y-self.h/2 and t.y<self.y+self.h/2 then
            if t.state==BEGAN then
                if self.name=="Shoot" and not looping then
                    sound("Game Sounds One:Pistol")
                    table.insert(miss,vec2(jsx,240))
                end
                if self.name=="Loop" then
                    looping=true
                end
            end
            if t.state==MOVING then
                if self.name=="Joy Stick" then
                    jsx=jsx+t.deltaX
                end
            end
        end    
    end
    
  • Posts: 294

    Thanks @dave1707

    I'm down the Touch ID route at present. Do I need to create an array to store Touch IDs or am I missed by something simple, I was hoping to assign a touch.id to the joystick and one to fire button and loop button

  • dave1707dave1707 Mod
    Posts: 5,996

    @Majormorgan I think Touch ID is best used when you have multiple objects that don't remain in a fixed position. You might touch multiple objects and move them somewhere on the screen. I can't think of a good example at the moment. As for using an array, that depends. When you touch an object, then the table would need the ID along with other info for that object. If you use a class, then you would save the ID in the instance of the button. I think the easiest way for fixed buttons would be what I show above. You give each button a unique name and you use the name to identify which button is used. The name in this case is replacing the ID number. One thing about a Touch ID, it's a number that's different each time the screen is touched. I don't know how the ID is calculated.

  • Posts: 294

    Ah that makes sense @dave1707 - I'm gonna implement your code! Thank you

  • Posts: 294
    One question @dave1707 is the two buttons will be fixed but the joystick itself is moving. Hence the code for the stick. perhaps if I have the button as the base thing behind like your long and wide button and the circle that will look like the button will intact just be something that sticks to your finger when you move. Hmmmm...
  • dave1707dave1707 Mod
    edited August 4 Posts: 5,996

    I didn't fully understand what you were saying, but were you after something like this.

    supportedOrientations(PORTRAIT_ANY)
    displayMode(FULLSCREEN)
    
    function setup()
        a=0
        miss={}
        rectMode(CENTER)
        jsx,jsy=WIDTH/2,200
        stick=button(WIDTH/2,100,80,100,"Stick")
        shoot=button(100,100,100,50,"Shoot")
        loop=button(WIDTH-100,100,100,50,"Loop")
    end
    
    function draw()
        background(40, 40, 50)
        fill(255)
        stick:draw()
        for a,b in pairs(miss) do
            sprite("Tyrian Remastered:Fire Rock",b.x,b.y)
            b.y=b.y+10
            if b.y>HEIGHT then
                table.remove(miss,a)
            end
        end
        shoot:draw()
        loop:draw()
        translate(jsx,jsy)
        if looping then
            a=a+10
            rotate(a)
            if a>360 then
                a=0
                looping=false
            end
        end
        sprite("Space Art:Red Ship",0,0)
    end
    
    function touched(t)
        stick:touched(t)
        shoot:touched(t)
        loop:touched(t)    
    end
    
    button=class()
    
    function button:init(x,y,w,h,n)
        self.x=x
        self.y=y
        self.w=w
        self.h=h
        self.name=n
    end
    
    function button:draw()
        pushStyle()
        fill(255)
        if self.name=="Stick" then
            ellipse(self.x,self.y,80)
        else
            rect(self.x,self.y,self.w,self.h)
        end
        fill(255,0,0)
        text(self.name,self.x,self.y)
        popStyle()
    end
    
    function button:touched(t)
        if t.x>self.x-self.w/2 and t.x<self.x+self.w/2 and
                t.y>self.y-self.h/2 and t.y<self.y+self.h/2 then
            if t.state==BEGAN then
                if self.name=="Shoot" and not looping then
                    sound("Game Sounds One:Pistol")
                    table.insert(miss,vec2(jsx,240))
                elseif self.name=="Loop" then
                    looping=true
                end
            end
            if t.state==MOVING then
                if self.name=="Stick" then
                    self.x=t.x
                    if self.x<200 then
                        self.x=200
                    end
                    if self.x>WIDTH-200 then
                        self.x=WIDTH-200
                    end
                    jsx=WIDTH/2-(WIDTH/2-self.x)*2
                end
            end
        end    
    end
    
  • Posts: 294

    Hi @dave1707 that works great in its own project and is quite close to my vision, but trying to incorporate that code into my game is proving a bitch as there are a number of things that are affected by the code from different parts of the game engine.

    That's why I'm trying to implement the id aspect to the code I have. Here's a quick video demo:
    https://instagram.com/p/BXXT9wkH79T/

    As I can only detect one touch the joystick control is turning off the autofire but holding down on the joystick still lets me move the ship.

    My two priorities to solve are multi touch or multi hold really, plus when You take your hand off the joystick I'll code it to move back to the centre.

    if I could understand how to code in multi touch using Touch ID that would be ace!

    Thank you so much for all your help

    Best
    Rich

  • dave1707dave1707 Mod
    Posts: 5,996

    @Majormorgan See the Codea example Multi Touch. See if that gives you the info you need. If not let me know and I'll help more.

  • Posts: 294
    Thanks @dave1707 - you advice is helping me understand all this stuff so much better and very much appreciated!

    I'll keep on with the multitouch examples and if I hit any specifics I'll ask.

    One quick question, I still have another touch function running at the same time as this new touch t - and the other touch example is above the touch t code in main. Can two touch codes exist at the same time?

    Thanks
  • Posts: 687

    @Majormorgan -here is an example of multi-touch which does some of what you want.



    function setup() JOYSTICK=1 -- keep track of our touches in this table touches = {} tsup={} -- tracks the characteristics of the touch and associates with the touches table through the touch.id. I can't find a way of associating this additional info directly with the touches table above --player parameters shipx=WIDTH/2 shipy=500 shipspd=0 fireon=0 bullets={} parameter.number("intertia",0.9,1.0,0.9) --the smaller this value the shorter time it takes the ship to slow parameter.number("sensitivity",10,100,50) --how much the ship moves relative to finger movement - larger value closer to finger tracking --button paraemeters firex=WIDTH*0.25 firey=150 firer=100 loopx=WIDTH*0.75 loopy=150 loopr=100 counter=0 end -- This function gets called whenever a touch -- begins or changes state function touched(touch) if touch.state==ENDED or touch.state==CANCELLED then processTouch(touch) touches[touch.id] = nil tsup[touch.id]=nil else touches[touch.id] = touch --if there is no supplementary info associated with the current touch then add it if tsup[touch.id]==nil then --check to see if there is an exisitng touch event assigned to the movement, and log in the "kind variable local k=JOYSTICK for i,ts in pairs (tsup) do if ts.kind==JOYSTICK then k=0 end end tsup[touch.id]={startx=touch.x,starty=touch.y,startt=ElapsedTime,kind=k} --you could add event triggers here for new non-movement assigned touches (e.g. normally a second or subsequent touch) --for example the following switches on the autofire for any second touch --these will only trigger when the new touch initiates if k==0 then fireon=1 end end end end function processTouch(touch) --this is called when the any touch event is ended. You could add in event triggers here too --If you take your finger of over the loop button it will initiate it - doesn't matter how long you hold it for if vec2(tsup[touch.id].startx,tsup[touch.id].starty):dist(vec2(loopx,loopy))<loopr/2 then --initiate the loop the loop here sound(SOUND_POWERUP, 46775) end --example of toggling a switch - needs to be in a certain location and lasting less than a set time if vec2(touch.x,touch.y):dist(vec2(firex,firey))<firer/2 and (ElapsedTime-tsup[touch.id].startt)<0.5 then fireon = fireon + 1 if fireon>1 then fireon=0 end end --what would be really interesting to explore would be to detect a vertical swipe to do your loop the loop end function draw() counter = counter + 1 background(0, 0, 0, 255) stroke(218, 161, 30, 255) strokeWidth(3) fill(255) for i,t in pairs(touches) do ellipse(t.x,t.y,70) line(tsup[i].startx,tsup[i].starty,t.x,t.y) --take some action based on the status of the touch - in this example it can only be 1 (Joystick) or none - you could add more events if tsup[i].kind==JOYSTICK then shipspd=(t.x-tsup[i].startx)/sensitivity end end if fireon==1 then fill(73, 255, 0, 255) else fill(255, 13, 0, 255) end ellipse(firex,firey,firer) fill(0) text("Fire",firex,firey) fill(255, 226, 0, 255) ellipse(loopx,loopy,loopr) fill(0) text("Loop",loopx,loopy) for i,b in pairs(bullets) do sprite("Tyrian Remastered:Bullet Simple B",b.x,b.y) b.y = b.y + 5 if b.y>HEIGHT then table.remove(bullets,i) end end if shipspd>0 then sprite("Tyrian Remastered:Ship D R1",shipx,shipy,50) elseif shipspd<0 then sprite("Tyrian Remastered:Ship D L1",shipx,shipy,50) else sprite("Tyrian Remastered:Ship D",shipx,shipy,50) end shipx = shipx + shipspd if shipx>WIDTH then shipx=WIDTH end if shipx<0 then shipx=0 end shipspd = shipspd *intertia if math.abs(shipspd)<1 then shipspd=0 end if fireon==1 and math.fmod(counter,10)==1 then table.insert(bullets,{x=shipx,y=shipy}) end end

    A purely personal point of view but I'm always a little bit disappointed when I see someone on the forum trying to implement an onscreen joystick. The iPad is a touch driven device, and there are so many possibilities to implement interesting control mechanisms for games, but the default seems to be for an onscreen approximation of a physical joystick.

    IMHO having to hit a specific location on the screen to control your ship seems a bit 'meh' compared to the USP of your game of unique(ish) tilt controls for a shooter. How about detecting gestures to initiate events, e.g. Upward swipe to loop the loop. Tap or second finger hold to toggle auto-fire/fire and primary touch for ship movement.

  • Posts: 294
    Thanks @West - I'll look into that code.

    The onscreen or touch to move controls are only an alternative to the tilt mechanism for the ones that don't like tilting. The titling will always be the main control system for the game, just I've had a lot of resistance to the tilt mechanic only so by making the stick variant, even an invisible one, will go some way to gaining more players.

    I do get about the swipe action and tap to shoot as a good way to ensure a more expressive and mobile way of playing. I've just got to get the balance right as I hate shooters where the ship is stuck to your finger as you obscure the ship and can't see what you are hitting.

    Also the game isn't an auto-shooter like others as you have to conciously make decisions to shoot or not.

    I'll know once I get this code working properly

    Thanks to you and to @dave1707 !!!
  • Posts: 294
    Success! I was being a twat - I didn't ensure that the touch state started checking if it had ENDED first before wrapping the other states under a single Else clause. Instead I had defined all three touch states and it wasn't tracking the touch through all three states.

    So it's meant to be:
    ~~~
    If touch.state==ENDED then
    touches[touch.id] = nil
    else
    touches[touch.id] = touch
    [code goes here...]
    end
    ~~~

    All I have to do now is write code to detect the distance of the joystick as it moves from its centre point so it can adjust the amount the background moves by (slight movement on the stick = slight movement on the background, full movement on the stick = full movement on the background). I'll be able to crack that.

    Thank you both so much for your examples and feedback.

    I can see going forwards with new games that @dave1707 approach to making buttons will be worth investigating.
  • Posts: 294
    I've been a double twat, the code I was using also moves the background almost the way I want, less with less stick, more with more stick, just need to adjust the amount so it is smoother
  • Posts: 294

    And here's the latest code demo that has stick on the left (massive hit area) for left movement plus pull back for tilt. The right side area is a massive hit state for autofire:

  • JohnJohn Admin Mod
    Posts: 411

    Looking at that video it seems like the game runs 1.5 - 2 times faster on my iPad Air 2. No wonder it was so hard :open_mouth:

  • Posts: 294
    Actually @John that video runs slow as it's recording the screen and running the code at the same time. The game runs much faster as you said, even on iPhone 4s and iPad 2.

    There is something running the code slower at the same time as screen record that I'm trying to locate. Not sure what it is yet as a version of starsceptre about 6 months ago plays and records fine at the same time.

    How far did you get in the game?
  • JohnJohn Admin Mod
    Posts: 411

    @Majormorgan I'm not sure what is causing the slowdown exactly but generally you want to use DeltaTime to make sure the game can account for lower than optimal FPS.

    I got up to the minefield level.

  • Posts: 294

    Thanks @John I'll see what I can do with DeltaTime as much of the game is frame based counting.

    I'm still trying to isolate the piece of code that is slowing things down. I'm sure I'll find it soon

    Thanks

Sign In or Register to comment.