Multiplayer Space Game

Hello all,
Recently I have been trying to code a sort of space game where both players have a steering wheel they can use to control their spaceship. First, I programmed the first player’s spaceship and steering wheel, and then I added the second players.

-- Driving

-- Use this function to perform your initial setup
function setup()
    print("Hello World!")
    carOne=vec2(WIDTH/2,HEIGHT/2)
    carTwo=vec2(WIDTH/2,HEIGHT/2)
    velOne,accOne=vec2(0,0)
    rotatOne=0
    rotatTwo=0
    touches={}
    velTwo,accTwo=vec2(0,0)
    PlayerOne=0
    PlayerTwo=0
end
function touched(touch)
    -- If the touch is in any other state
    --  (such as BEGAN) we add it to our
    --
    touches[touch.id]=touch
end
-- This function gets called once every frame
function draw()
    -- This sets a dark background color
    background(40, 40, 50)
    
    -- This sets the line thickness
    strokeWidth(5)
    for i,v in pairs(touches) do
        if i~=PlayerTwo and v.state~=ENDED and v.x>WIDTH/2 and v.y<HEIGHT/2 then PlayerOne=i end
        if i~=PlayerOne and v.state~=ENDED and v.x<WIDTH/2 and v.y>HEIGHT/2 then PlayerTwo=i end
    end
    print(PlayerOne..", "..PlayerTwo)
    if touches[PlayerOne]~=nil and touches[PlayerOne].state~=ENDED then
        difOne=vec2(CurrentTouch.x,CurrentTouch.y)-vec2(3*WIDTH/4,200)
        rotatOne=-math.deg(math.atan2(difOne.x,difOne.y))
        --accOne=carOne:dist(vec2(CurrentTouch.x,CurrentTouch.y))
        --accOne=accOne:normalize()
        
    end
    if touches[PlayerTwo]~=nil and touches[PlayerTwo].state~=ENDED then
        difTwo=vec2(CurrentTouch.x,CurrentTouch.y)-vec2(WIDTH/4,HEIGHT-200)
        rotatTwo=-math.deg(math.atan2(difTwo.x,difTwo.y))
        --accOne=carOne:dist(vec2(CurrentTouch.x,CurrentTouch.y))
        --accOne=accOne:normalize()
        
    end
    
    -- Do your drawing here
    
    if touches[PlayerOne]~=nil and touches[PlayerOne].state~=ENDED then
        accOne=vec2(CurrentTouch.x,CurrentTouch.y)-vec2(3*WIDTH/4,200)
        accOne=accOne:normalize()
        else accOne=vec2(0,0)
    end
    if touches[PlayerTwo]~=nil and touches[PlayerTwo].state~=ENDED then
        accTwo=vec2(CurrentTouch.x,CurrentTouch.y)-vec2(WIDTH/4,HEIGHT-200)
        accTwo=accTwo:normalize()
        else accTwo=vec2(0,0)
    end
    
    velOne=velOne+accOne
    velTwo=velTwo+accTwo
    if velOne.x>6 then velOne.x=6 end
    if velOne.x<-6 then velOne.x=-6 end
    if velOne.y>6 then velOne.y=6 end
    if velOne.y<-6 then velOne.y=-6 end
    if touches[PlayerOne]~=nil and touches[PlayerOne].state==ENDED then
        if velOne.x>0 then velOne.x = velOne.x - 0.1 end
        if velOne.x<0 then velOne.x = velOne.x + 0.1 end
        if velOne.y>0 then velOne.y = velOne.y - 0.1 end
        if velOne.y<0 then velOne.y = velOne.y + 0.1 end
    end
    if velTwo.x>6 then velTwo.x=6 end
    if velTwo.x<-6 then velTwo.x=-6 end
    if velTwo.y>6 then velTwo.y=6 end
    if velTwo.y<-6 then velTwo.y=-6 end
    if touches[PlayerTwo]~=nil and touches[PlayerTwo].state==ENDED then
        if velTwo.x>0 then velTwo.x = velTwo.x - 0.1 end
        if velTwo.x<0 then velTwo.x = velTwo.x + 0.1 end
        if velTwo.y>0 then velTwo.y = velTwo.y - 0.1 end
        if velTwo.y<0 then velTwo.y = velTwo.y + 0.1 end
    end
    carOne=carOne+velOne
    carTwo=carTwo+velTwo
    pushMatrix()
    translate(carOne.x,carOne.y)
    rotate(rotatOne)
    sprite("Space Art:Part Gray Hull 4", 0,0,50,50)
    
    popMatrix()
    pushMatrix()
    translate(3*WIDTH/4,200)
    rotate(rotatOne)
    fill(0,0,0,0)
    stroke(255)
    strokeWidth(5)
    ellipse(0,0,100,100)
    line(0,0,45,0)
    line(0,0,-45,0)
    line(0,0,0,45)
    popMatrix()
    
    pushMatrix()
    translate(carTwo.x,carTwo.y)
    rotate(rotatTwo)
    sprite("Space Art:Part Red Hull 4", 0,0,50,50)
    
    popMatrix()
    pushMatrix()
    translate(WIDTH/4,HEIGHT-200)
    rotate(rotatTwo)
    fill(0,0,0,0)
    stroke(255)
    strokeWidth(5)
    ellipse(0,0,100,100)
    line(0,0,-45,0)
    line(0,0,45,0)
    line(0,0,0,45)
    popMatrix()
end

Thank you @Ignatz! I will implement that soon. Sorry to bump(if this is considered bumping) but I really don’t get a chance to reply because I’m busy with schoolwork and after-school clubs. I probably would have done what @Ignatz said but this started off as a one-player proof of concept that I later turned into a two player game. Thank all of you for your wonderful help! :smiley:

@TheSolderKing Here’s an example of using multiple joysticks. Maybe this will help you. The idea is to keep track of who has what id. You can have 5 joysticks going with this example.

EDIT: Actually you can have as many joysticks as you can get fingers on the screen. You just get 5 different sprites before they appear again.


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)
        ellipse(self.cx,self.cy,8) -- draw circle center
        noFill()
        stroke(255)
        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

The user and all related content has been deleted.

It’s a stick you push around for joy.

Do a google search for joystick. You’ll find more information there than we can ever tell you here.

@dave1707 thank you so much for your comment! I tried to keep track of the Touch ID, and that is what the “playerOne” and “playerTwo” variables are. They simply contain the Touch ID because the ID is the index in the table. For some reason, even when I have it printing the Touch ID, it still acts as if only one touch is on the screen. The print function prints two different Touch IDs. It is very strange. If anyone could explain to me why this happens, it would be very helpful. Thank you again dave1707 for the wonderful example.

@TheSolderKing I look over your code this evening while I’m watching the Bears and Jets football game.

Thank you @dave1707! I truly was not expecting a reply that promptly. Thank you for your help and your kindness.

@TheSolderKing I guess I don’t have to wait for the game. I took a closer look at your code and here’s what’s wrong. In draw(), in the “for” loop, you set PlayerOne andPlayerTwo to the id. Then after the “for” loop you check several “if touches” for the 2 players. When both players are touching the screen, you’re using the same CurrentTouch for both players. You need to use the correct touches .x and .y values for each corresponding player. I hope I explained that good enough.

@TheSolderKing - one little point.

velOne,accOne=vec2(0,0)

That line only sets velOne to a vec2, and accOne stays as nil. Perhaps what you need is

velOne,accOne=vec2(0,0),vec2(0,0)

@TheSolderKing Make these changes. I commented out the lines that used CurrentTouch and added a line to use touches[ ].x and .y .


    if touches[PlayerOne]~=nil and touches[PlayerOne].state~=ENDED then
        --difOne=vec2(CurrentTouch.x,CurrentTouch.y)-vec2(3*WIDTH/4,200)
        difOne=vec2(touches[PlayerOne].x,touches[PlayerOne].y)-vec2(3*WIDTH/4,200)
        rotatOne=-math.deg(math.atan2(difOne.x,difOne.y))
    end
    if touches[PlayerTwo]~=nil and touches[PlayerTwo].state~=ENDED then
        --difTwo=vec2(CurrentTouch.x,CurrentTouch.y)-vec2(WIDTH/4,HEIGHT-200)
        difTwo=vec2(touches[PlayerTwo].x,touches[PlayerTwo].y)-vec2(WIDTH/4,HEIGHT-200)
        rotatTwo=-math.deg(math.atan2(difTwo.x,difTwo.y))

    end
    if touches[PlayerOne]~=nil and touches[PlayerOne].state~=ENDED then
        --accOne=vec2(CurrentTouch.x,CurrentTouch.y)-vec2(3*WIDTH/4,200)
        accOne=vec2(touches[PlayerOne].x,touches[PlayerOne].y)-vec2(3*WIDTH/4,200)
        accOne=accOne:normalize()
        else accOne=vec2(0,0)
    end
    if touches[PlayerTwo]~=nil and touches[PlayerTwo].state~=ENDED then
        --accTwo=vec2(CurrentTouch.x,CurrentTouch.y)-vec2(WIDTH/4,HEIGHT-200)
        accTwo=vec2(touches[PlayerTwo].x,touches[PlayerTwo].y)-vec2(WIDTH/4,HEIGHT-200)
        accTwo=accTwo:normalize()
        else accTwo=vec2(0,0)
    end

Oh my gosh how could I have overlooked that? Thank you so much for your solution! :smiley:

@TheSolderKing - in the interests of avoiding code duplication (which can easily lead to errors, updating one but not both, etc), I would consider using a table for both players like so

P={} --table to hold all player properties
P.touches,P.dif,P.acc,P.rotat={},{},{},{}
P.pos={vec2(3*WIDTH/4,200),vec2(WIDTH/4,HEIGHT-200)}

then the touched code that dave changed simplifies to

for i=1,2 do
    if P[i].touches~=nil and P[i].touches.state~=ENDED then
        P[i].dif=vec2(P[i].touches.x,P[i].touches.y)-P[i].pos
        P[i].rotat=-math.deg(math.atan2(P[i].dif.x,P[i].dif.y))
        P[i].acc=(vec2(P[i].touches.x,P[i].touches.y)-P[i].pos):normalize()
    else P[i].acc=vec2(0,0)
    end
end

This not only makes your code much more compact, it keeps all your player properties together in one place, making it easier to modify them. If your players get more complex, it will also be easy to turn the player table P into a class.