javascriptp5.js

Player movement with split screen viewports using p5


I am trying to make a program where there are two different screens that are centered on different players. I am using createGraphics() to try and achieve this. They render, but the screens aren't centered on them. I tried using translate() but it doesn't center the screen on them.

Also, the players don't seem to be rendering correctly. One of them is supposed to be white with a black outline, and the other is supposed to be black with a white outline, but it only seems to render like that on the first one.

let p1Pos;
let p2Pos;
let buffer1;
let buffer2;
let speed = 0.1;



function setup() {
    createCanvas(windowWidth, windowHeight);
    background(100);
    p1Pos = createVector(0, 0);
    p2Pos = createVector(0, 0);
    buffer1 = createGraphics(width, height / 2);
    buffer2 = createGraphics(width, height / 2);
}

function draw() {
    background(200);
    strokeWeight(4);
    line(0, height / 2, width, height / 2);
    controller();
    drawBuf1();
    drawBuf2();
    image(buffer1, 0, 0);
    image(buffer2, 0, height/2);
}


function controller() {
    // P1
    if (keyIsDown(87)) p1Pos.add(0, -speed);
    if (keyIsDown(83)) p1Pos.add(0, speed);
    if (keyIsDown(65)) p1Pos.add(-speed);
    if (keyIsDown(68)) p1Pos.add(speed);
    // P2
    if (keyIsDown(38)) p2Pos.add(0, -speed);
    if (keyIsDown(40)) p2Pos.add(0, speed);
    if (keyIsDown(37)) p2Pos.add(-speed);
    if (keyIsDown(39)) p2Pos.add(speed);
}



function drawBuf1() { // Draw first buffer
    buffer1.translate(p1Pos.x, p1Pos.y);
    buffer1.background(100);
    buffer1.strokeWeight(2);
    buffer1.fill('#FFFFFF');
    buffer1.stroke('#0000000');
    buffer1.circle(0, 0, 40);
    buffer1.fill('#0000000');
    buffer1.stroke('#FFFFFF');
    buffer1.circle(p2Pos.x, p2Pos.y, 40);
}

function drawBuf2() {
    buffer2.translate(p2Pos.x, p2Pos.y);
    buffer2.background(100);
    buffer2.strokeWeight(2);
    buffer2.fill('#000000');
    buffer2.stroke('#FFFFFF0');
    buffer2.circle(0, 0, 40);
    buffer2.fill('#FFFFFF0');
    buffer2.stroke('#000000');
    buffer2.circle(p1Pos.x, p1Pos.y, 40);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.11.0/p5.js"></script>


Solution

  • For starters, your colors are invalid. There should be 6 digits in the hexadecimal number, not 7.

    As for the main issue, take a look at HTML5 Canvas camera/viewport - how to actually do it?. This shows the following generalized formula:

    function update() {
    
      // Assign the viewport to follow a target for this frame
      var viewportX = canvas.width / 2 - target.x;
      var viewportY = canvas.height / 2 - target.y;
    
      // Draw each entity, including the target, relative to the viewport
      ctx.fillRect(
        entity.x + viewportX, 
        entity.y + viewportY,
        entity.size,
        entity.size
      );
    }
    

    Since you only have 2 objects, you can skip the viewport for starters and move players relative to each other, with the "current player" as always as w / 2, h / 2 to pin them to the center of the screen:

    let p1Pos;
    let p2Pos;
    let buffer1;
    let buffer2;
    let speed = 1;
    
    function setup() {
      createCanvas(windowWidth, windowHeight);
      background(100);
      p1Pos = createVector(40, 0);
      p2Pos = createVector(-40, 0);
      buffer1 = createGraphics(width, height / 2);
      buffer2 = createGraphics(width, height / 2);
    }
    
    function draw() {
      background(200);
      strokeWeight(4);
      line(0, height / 2, width, height / 2);
      handleInput();
      drawBuf1();
      drawBuf2();
      image(buffer1, 0, 0);
      image(buffer2, 0, height / 2);
    }
    
    function handleInput() {
      // P1
      if (keyIsDown(87)) p1Pos.add(0, -speed);
      if (keyIsDown(83)) p1Pos.add(0, speed);
      if (keyIsDown(65)) p1Pos.add(-speed);
      if (keyIsDown(68)) p1Pos.add(speed);
      // P2
      if (keyIsDown(38)) p2Pos.add(0, -speed);
      if (keyIsDown(40)) p2Pos.add(0, speed);
      if (keyIsDown(37)) p2Pos.add(-speed);
      if (keyIsDown(39)) p2Pos.add(speed);
    }
    
    function drawBuf1() {
      buffer1.background(100);
      buffer1.strokeWeight(2);
      buffer1.fill("#FFFFFF");
      buffer1.stroke("#000000");
      buffer1.circle(width / 2, height / 4, 40);
      buffer1.fill("#000000");
      buffer1.stroke("#FFFFFF");
      buffer1.circle(
        width / 2 - p1Pos.x + p2Pos.x,
        height / 4 - p1Pos.y + p2Pos.y,
        40
      );
    }
    
    function drawBuf2() {
      buffer2.background(100);
      buffer2.strokeWeight(2);
      buffer2.fill("#000000");
      buffer2.stroke("#FFFFFF");
      buffer2.circle(width / 2, height / 4, 40);
      buffer2.fill("#FFFFFF");
      buffer2.stroke("#000000");
      buffer2.circle(
        width / 2 - p2Pos.x + p1Pos.x,
        height / 4 - p2Pos.y + p1Pos.y,
        40
      );
    }
    
    // prevent scrolling
    window.addEventListener("keydown", e => {
      if ([37, 38, 39, 40].includes(e.keyCode)) {
        e.preventDefault();
      }
    });
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.11.0/p5.js"></script>

    If this appears strange, cover up the other player's viewport and it'll look more natural (when I move, it moves away from or towards the other player on my screen; when the other player moves, they move closer or towards me). Adding stationary objects and implementing full viewports will make the illusion convincing.