Visual Border in Top-Down-2D-Game is weirdly misplaced

I’m making a 2D survival game, with a top-down perspective. I don’t want the world to be infinite, so i made the map a square, with the sides being 200.000 pixels long. The script for moving the player works fine (so the player can’t move in the x or y axis beyond (-)100.000), but for some weird reason, the visual border is WAY off, even though the map square is placed 100.000 pixels from the map center, and has 200.000 pixels in side length.

here is the code. the framerate is set to 6000 for testing purposes, the player moves 100 times faster than normal, which is useful for getting to the border quickly. it is at 60 normally. there is also a mini map which i didn’t include here. (i disabled some code that’s associated with rocks that get placed on the map, these work fine)

int camx = 0;
int camy = 0;

void setup() {
  surface.setTitle("ScrollingTest");
  frameRate(6000);
  size(1920, 1080);
  background(0);
  //spawnRock(50);
}

void draw() {
  background(0);
  fill(#329032);
  strokeWeight(10);
  stroke(#CB212C);
  rect(-100000-camx, -100000-camy, 200000, 200000); //THIS is the line that draws the map square!
  //executeRock();
  drawPlayer();
  inputPlayer();
  drawUI();
}

void drawPlayer() {
  fill(50);
  strokeWeight(1);
  stroke(0);
  rect(width/2, height/2, 100, 100);
}

void inputPlayer() {
  if (keyPressed == true) {
    if (key == 'w') {
      if (camy > -100000) {
        camy = camy-10;
      }
    }
  }
  if (keyPressed == true) {
    if (key == 'a') {
      if (camx > -100000) {
        camx = camx-10;
      }
    }
  }
  if (keyPressed == true) {
    if (key == 's') {
      if (camy < 100000) {
        camy = camy+10;
      }
    }
  }
  if (keyPressed == true) {
    if (key == 'd') {
      if (camx < 100000) {
        camx = camx+10;
      }
    }
  }
}

void drawUI() {
  drawMap();
  fill(255);
  textSize(20);
  text("X: " + camx + "     Y: " + (0-camy), 50, 800);
}

Hi! What do you mean by “way off” ? I tested with increment/decrement of 1000 instead of 10 because I’m not patient enough :slight_smile: what I see is if I go to left/top, I cannot reach the border and if I go to right/bottom edges I exceed the edge.

You draw the border rect at -100000-camx, -100000-camy and player at width/2, height/2. it is problematic because in fact rect by default uses the first two arguments for the top left instead of the center. There are two things to suggest: 1) use rectMode(CENTER) so you can select the center position of the rect and 2) use translate and push/popMatrix.

For the latter, I would say you draw the map at 0, 0 independent of camx and camy. The player should be at camx and camy and not the “center” of the screen. Then, before drawing these objects, use translate(width/2, height/2) and translate(-camx, -camy) so that the player end up being in the center of the screen. It may look not straightforward but it helps a lot to simplify when you add more objects and also when you want to zoom in/out for example.

Thanks for the advice, @micuat. Changing to rectMode(CENTER) results in the same problem…

For the latter: What exactly does translate() do? And where to put it? As soon as i threw one of these into the code, the whole thing broke (minimap, coordinates and objects didn’t appear, and the screen stopped scrolling).
This is where i put translate(width/2, height/2)

void drawPlayer() {
  fill(50);
  strokeWeight(1);
  stroke(0);
translate(width/2, height/2);
  rect(camx, camy 100, 100);
}

I’m still not very familiar with coding, could you please explain what translate() does and what i did wrong by putting it there?

I appreciate the help :slight_smile:

Hello Braunstein,

When you don’t know what a function is doing, the first thing to do is to go see the reference.

For the translate function here it is.

Now to explain briefly, it pretty much does what the name implies, translate stuff you draw on the screen by the specify amount.

Take the following example:

void setup() {
  size(300, 300);
  background(20);
  
  // Red ellipse
  translate(100, 100);
  fill(255, 0, 0);
  ellipse(0, 0, 20, 20);
  
  // Blue ellipse
  translate(50, 50);
  fill(0, 0, 255);
  ellipse(0, 0, 20, 20);
}

It simply draws a red ellipse, followed by a blue one. As you can see they are both drawn at coordinates (0, 0) (so the top left corner) but if you run the program this is what you see:

image

The reason is because we are using the translate function. It basically moves the canvas your are drawing into inside the window. The first translate(100, 100); move the canvas 100 pixels to the right and 100 to the bottom. So the (0, 0) coordinate of the canvas is now at position (100, 100) of the window. That’s why when we draw the red ellipse a (0, 0) it appears where it does in the window.

The second time we call translate(50, 50); it moves the canvas again, this is cumulative. So now the coordinate (0, 0) of the canvas is at position (100 + 50, 100 + 50) of the window.

Another thing to now when using the translate function is the pushMatrix() and popMatrix() functions. They allow you to save and restore transformations. So if you want to translate something without affecting the rest of it, you can enclose your transformation between those 2 functions.

The previous example slightly modified:

void setup() {
  size(300, 300);
  background(20);
  
  // Red ellipse
  pushMatrix();
  translate(100, 100);
  fill(255, 0, 0);
  ellipse(0, 0, 20, 20);
  popMatrix();
  
  // Blue ellipse
  translate(50, 50);
  fill(0, 0, 255);
  ellipse(0, 0, 20, 20);
}

image

You can see how now the blue ellipse is at position (50, 50) of the window.

And as I said, to know more:
https://processing.org/reference/popMatrix_.html
https://processing.org/reference/pushMatrix_.html