Multiplayer Splitscreen Help

In my game, I’ve clipped my screen so you can only see one half of what’s happening on the screen. How do I make it so you can see a different screen on the other side?

Thank you :slight_smile:

@Creator27 - I think you need to provide us with a little more detail. For instance:

  1. Are both screens animated - like a two player game?
  2. Does one screen area hold controls or player details?
  3. Does one screen hold a map?

You may not need two clipped areas.

  1. The screens are supposed to be two separate cameras beside each other.

2.The cameras are both looking at two capsules that move left and right depending on where you are touching on the screen.

Here’s the code that I have done on my game so far just to give you a bit of context on what I’m dealing with here:

-- Test Shooter

function setup()
    -- Create a new craft scene
    scene = craft.scene()
    scene.physics.gravity = vec3(0, 1, 0)
    viewer.mode = FULLSCREEN
    

    -- Create a new entity
    local entity = scene:entity()
    body = entity:add(craft.rigidbody)
    entity.model = craft.model(asset.builtin.Primitives.Capsule)
    entity.material = craft.material(asset.builtin.Materials.Specular)
    entity.y = -1
    entity.z = 0
    entity.scale = vec3(1,1,1) / 8
    entity.eulerAngles = vec3(0, 180, 0)
    
    scene.camera.z = -4 
    
    
    
    local entity2 = scene:entity()
    body2 = entity2:add(craft.rigidbody)
    
    entity2.model = craft.model(asset.builtin.Primitives.Capsule)
    entity2.material = craft.material(asset.builtin.Materials.Specular)
    entity2.y = -1
    entity2.z = 0
    entity2.scale = vec3(1,1,1) / 8
    entity2.eulerAngles = vec3(0, 180, 0)
    
    
    if entity.y >= 700 then
        body:applyForce(vec3(0, -30, 0))
    end
end

function touched(touch)
    if touch.state == MOVING and touch.x < 500 then
        body:applyForce(vec3(1, 0, 0))
    end
    
    if touch.state == MOVING and touch.x < 500 then
        body:applyForce(vec3(1, 0, 0))
    end
end
    
function update(dt)
    -- Update the scene (physics, transforms etc)
    scene:update(dt)
end

-- Called automatically by codea 
function draw()
    update(DeltaTime)
    clip(0, 0, 540, 900)

    -- Draw the scene
    scene:draw()	
end

The easiest thing for me is this:

  1. Write two drawStuff functions that can draw the view for one player or the other, on the left side of the screen.
  2. In the one I want on the right, add a pushMatrix at the top, a popMatrix at the bottom.
  3. After the pushMatrix, put a call to translate, giving it the coordinate I want the second guy to draw at, typically WIDTH/2, 0

After that, the second guy should draw on the right side. Try it with a small example first to get the hang of it.

Good luck!

@Creator27 - just looking at your code. I was thinking of doing something similar with a plane in flight. So you could access views of the craft from 6 90degree angles. What I was thinking of doing was having just 1 view selectable by having 6 camera view definitions in Craft. That would allow 360° views around the ship.

I intended locking the camera position to the ship so you always see the ship as it was defined but the background rotates around you.

In Codea, some folks savor the experience of figuring out how to do everything from scratch, and some folks prefer to search out stuff other people have already done and try to build on top of it—I’m more of the second camp, myself, and if you are too, I suggest downloading @Steppers’s phenomenal WebRepo project and using it to get a project called “Shooter”.

It’s not fully finished, so it’s rough around the edges, and it’s made in 2D not in Craft, and for a beginner all that code might be a formidable challenge to dig through, but it’s a split-screen head-to-head shooter, with different weapons, power ups, teleportation portals, and a map editor.

If I were you I’d consider it a treasure trove of free code that would save me countless hours of re-inventing the wheel, and I’d rummage through the code, pull out everything I could use, and rejigger it to serve my own purposes.

WebRepo is here: https://codea.io/talk/discussion/11724/webrepo-1-3-easy-access-to-projects-from-the-codea-community/p2

You’ll need a GitHub account, but those are free too.

Hey there, before any of you guys commented on this, I was able to “partially” fix the split screen but with two problems.

The first problem, is that when I restart my game, one of the players is frozen on the spot until I touch the screen somewhere.

The second problem, is that at any given time, either the left screen, the right screen or even both screens can freeze instantaneously, and the only way to fix it is to reset the game.

Here’s the code that I have written so you can see if there might be any potential errors or bugs:

-- Test Shooter

function setup()
    -- Create a new craft scene
    scene = craft.scene()
    scene.physics.gravity = vec3(0, 1, 0)
    viewer.mode = FULLSCREEN
    clipScreen = false
    

    -- Create a new entity
    local entity = scene:entity()
    body = entity:add(craft.rigidbody)
    entity.model = craft.model(asset.builtin.Primitives.Capsule)
    entity.material = craft.material(asset.builtin.Materials.Specular)
    entity.material.map = readImage(asset.builtin.Blocks.Grass_Top)
    entity.y = -1
    entity.z = 0
    entity.scale = vec3(1,1,1) / 8
    entity.eulerAngles = vec3(0, 0, 0)
    
    scene.camera.z = -4 
    
    
    
    local entity2 = scene:entity()
    body2 = entity2:add(craft.rigidbody)
    
    entity2.model = craft.model(asset.builtin.Primitives.Capsule)
    entity2.material = craft.material(asset.builtin.Materials.Specular)
    entity2.y = -1
    entity2.z = 0
    entity2.scale = vec3(1,1,1) / 8
    entity2.eulerAngles = vec3(0, 180, 0)
    
    
    
    
    
    
    if entity.y >= 700 then
        body:applyForce(vec3(0, -30, 0))
    end
end

function touched(touch)
    if touch.state == MOVING and touch.x < 500 then
        body:applyForce(vec3(1, 0, 0))
    end
    
    if touch.state == MOVING and touch.x > 500 then
        body2:applyForce(vec3(-1, 0, 0))
    end
    
    if clipScreen == false then
        clipScreen = true
    end
    
    if touch.state == BEGAN and touch.x < 500 then
        body:applyForce(vec3(0, -60, 0))
    end
    
    if touch.state == BEGAN and touch.x > 500 then
        body2:applyForce(vec3(0, -60, 0))
    end
    
    if touch.tapCount == 4 then
        body:applyForce(vec3(0, -60, 0))
        body2:applyForce(vec3(0, -60, 0))
    end
end
    
function update(dt)
    -- Update the scene (physics, transforms etc)
    scene:update(dt)
end

-- Called automatically by codea 
function draw()
    update(DeltaTime)
    
    -- Buggy splitscreen :)
    if clipScreen == false then
        clip(0, 0, 540, 900)
        clip(540, 0, 540, 900)
    end
    

    -- Draw the scene
    scene:draw()
    
    -- Indicate the splitscreen point
    rect(535, 0, 10, 810)	
end

@Creator27 Whenever you post code, put ~~~ (3 tildes) on a line before and after your code so it formats correctly. I added them to your above code.

Thank you :slight_smile:

@RonJeffries, your method did not work. Is there some sort of alternative to your comment?

@Creator27 Take a look at the setContext() function.

You should be able to create new texture (framebuffer) for the splitscreens/viewports at the correctly divided resolution, use setContext prior to drawing and render to it from the corresponding players perspective.

Once you’ve drawn to the framebuffer you can then call setContext() again with no arguments before rendering the framebuffer to the screen to be visible to the user.

Rinse and repeat for each viewport.

local fb
local w = WIDTH * ContentScaleFactor
local h = (HEIGHT/2) * ContentScaleFactor

function setup()
    -- Create framebuffer image
    fb = image(w, h)
    
    -- Render defaults
    fill(255)
    spriteMode(CORNER)
end

function draw()
    -- Bind the framebuffer
    setContext(fb, true)
    background(255, 0, 0)
    
    -- Draw view 1 here
    ellipse(w/2, 3*h/4, 40, 60)
    
    -- Draw framebuffer to screen
    setContext()
    sprite(fb, 0, 0, WIDTH, HEIGHT/2)
    
    
    -- Bind the framebuffer
    setContext(fb, true)
    background(63, 0, 255)
    
    -- Draw view 2 here
    ellipse(w/4, h/2, 60, 40)
    
    -- Draw framebuffer to screen
    setContext()
    sprite(fb, 0, HEIGHT/2, WIDTH, HEIGHT/2)
end

Doing it this way you can probably avoid a lot of strange transformation awkwardness you’d get by doing it any other way as the rendering will be correctly mapped to the framebuffer image.

There’s a post here called “how to do split screen in 3D:” https://codea.io/talk/discussion/7798/how-to-do-split-screen-in-3d

ah, sorry, didn’t realize you were doing 3d. My scheme only works for simple 2D