Ways to control a characters movement in a game

i already know that I want movement to be controlled in at least 8 directions, like so: up, down, left, right, up-left, upright, downleft, downright.

things I’m running into are

  • when to move
    – I can create a hidden joystick with buttons centered on where a touch begins.
    – Or i could have visible buttons on the screen
    – if i do have buttons, do i want to split them?

  • if the user starts a touch, moves, but then stops moving, do we keep moving? i think, in most cases, the answer is yes.

  • minimum amount of movement before we consider it as an input

  • once an inout is on, what condition turns it off besides touch.state==ENDED?

One way to move a character is to touch the screen and move your finger a small distance in the direction you want the character to move. A slight finger movement in one of the eight directions will cause the character to move in that direction. As long as your finger is touching the screen, the character will continue in its last direction. Once you lift your finger, the character will stop. Or you can lift your finger and the character will continue in its last direction until you touch the screen again to give it a new direction or it stops if you don’t move your finger far enough in a direction.

here’s a buggy joystick

player={x=512,y=384}
function player:moveAtAngle(angle, left, down)
    --local speed = 2
    
    local velX = 2 * math.cos(angle)
    local velY = 2 * math.sin(angle)
    print('velx='..velX, 'vely='..velY)
    self.x = left and self.x - velX or self.x + velX
    self.y = down and self.y - velY or self.y + velY
end

local joystick = {x=-100, y=-100, w=100, h=100, inittouch=false,
lasttouch=false}
local angle
function joystick:set(touch)
    --touch logic
    if touch.state == BEGAN and not self.inittouch then
        self.inittouch = touch
        self.x = touch.x
        self.y = touch.y
    elseif touch.state == MOVING and self.inittouch then
        local v1 = vec2(touch.x, touch.y)
        
        if v1:dist( vec2(self.x, self.y)) > 26 then
            angle = v1:angleBetween( vec2(self.x, self.y) )
            local left, down = false, false

                left = self.x > v1.x
            if self.y > v1.y then
                down = self.y > v1.y
            end
            player:moveAtAngle(angle, left, down)
        else -- < 16
            player_is_moving = false
        end
    elseif touch.state == ENDED and self.inittouch then
        if touch.id == self.inittouch.id then
            self.inittouch = nil
            self.x = -100
            self.y = -100
        end
    end
end

function joystick:draw()
    fill(255,0,0,100)
    ellipse(self.x, self.y, 10)
    fill(100,100)
    ellipse(CurrentTouch.x, CurrentTouch.y, 50)
end
function draw()
    background(0)
    fill(0,0,222,150)
    rect(player.x, player.y, 10,10)
    joystick:draw()
end

function touched(t)
    joystick:set(t)
end

@xThomas If you want to use a joystick, here’s a version that will allow you to move multiple characters. This is setup to use 5 different characters. Just touch the screen anywhere to move a character. Use one or up to five fingers. A character will appear when you touch the screen.

displayMode(FULLSCREEN)

function setup()
    stab={ 
    readImage("Planet Cute:Character Boy"),
    readImage("Planet Cute:Character Cat Girl"),
    readImage("Planet Cute:Character Pink Girl"),
    readImage("Planet Cute:Character Princess Girl"),
    readImage("Planet Cute:Character Horn Girl")
    }
    rm=-1
    js={}
end

function draw()
    background(40, 40, 50)
    fill(255)
    for a,b in pairs(js) do
        b:draw(a)
   end
end

function touched(t)
    if t.state==BEGAN then
        aa=0
        for a,b in pairs(js) do
            if b.id==0 then
                b.cx=t.x
                b.cy=t.y
                b.id=t.id
                aa=1
                break
            end
        end
        if aa==0 then
            table.insert(js,jst(t.x,t.y,t.id))
        end
    elseif t.state==MOVING or t.state==ENDED then
        for a,b in pairs(js) do
            b:touched(t)
        end
    end
end

jst=class()

function jst:init(cx,cy,id)
    self.cx=cx
    self.cy=cy  
    self.dx=0
    self.dy=0
    self.sx=cx
    self.sy=cy
    self.id=id
end

function jst:draw(a)
    fill(255)
    if self.id>0 then
        fill(255, 255, 255, 50)
        ellipse(self.cx,self.cy,8) -- draw circle center
        noFill()
        stroke(255,255,255,50)
        strokeWidth(4)
        ellipse(self.cx,self.cy,200) -- draw outer circle  
    end 
    self.sx=self.sx+self.dx
    self.sy=self.sy+self.dy
    sprite(stab[a%5+1],self.sx,self.sy)
end

function jst:touched(t)
    if t.state==MOVING then
        if self.id==t.id then
            self.dx=(t.x-self.cx)/10
            self.dy=(t.y-self.cy)/10
        end
    end
    if t.state==ENDED then
        if self.id==t.id then
            rm=t.id
            self.id=0
            self.dx=0
            self.dy=0
            self.cx=0
            self.cy=0
        end
    end   
end

@dave1707 That’s a very interesting idea for controlling multiple characters. I haven’t seen that used in any games. For my fingers, applying more than three takes up too much screen space and feels a bit unnatural, but one to three fingers seems to work well. I may have to experiment with this. Thanks!

@mindless My thoughts was that four people could use this. One person in each corner or edge. Or two people would have no problem, one at opposite sides of the screen. If you really want to squeeze the screen, one person in each corner and one for each side. For over 5 people, more characters would need to be added in the stab table otherwise over 5 would reuse a character.