# Minecraft-Like Clone Lagging too much

**URL:** <https://discourse.processing.org/t/minecraft-like-clone-lagging-too-much/43083>\
**Category:** Coding Questions\
**Created:** [October 28, 2023, 2:24pm UTC](https://discourse.processing.org/t/minecraft-like-clone-lagging-too-much/43083 "2023-10-28T14:24:53Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![Noodlybanan](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/noodlybanan/32/18897_2.png) [@Noodlybanan](https://discourse.processing.org/u/Noodlybanan)\
**Post date:** [October 28, 2023, 2:24pm UTC](https://discourse.processing.org/t/minecraft-like-clone-lagging-too-much/43083/1 "2023-10-28T14:24:53Z")

</div>

Hi! I am programming a Minecraft Like Clone in processing to learn more about the language. I have an RTX3050 but rendering 6800 triangles is only running at 20FPS. It would be helpfull if someone could explain me why it’s lagging and how i could fix that! -Libby

```auto
PVector camPos;
PVector camLookAt;
float camYaw;
float camPitch;
float camSpeed = 15;
float sensitivity = 0.005;

PImage[] imgs = new PImage[32];

byte[][][] data = new byte[128][128][128];

PVector raycastDirection; // Direction of the ray
float raycastLength = 500; // Length of the ray

import java.awt.Robot;
import java.awt.AWTException;
import java.awt.event.InputEvent;

Robot robot;

void setup() {
  size(1080, 720, P3D);
  surface.setLocation(100, 100);
  frameRate(500);
  textureMode(NORMAL);
  windowTitle("Camera Test");
  camPos = new PVector(0, 0, 0);
  camLookAt = new PVector(0, 0, -1);
  camYaw = 0;
  camPitch = 0;

  try {
    robot = new Robot();
  }
  catch (AWTException e) {
    e.printStackTrace();
  }

  //try {
  // imgs[0] = loadImage("graeess.png");
  // imgs[1] = loadImage("gerass-side.png");
  // imgs[2] = loadImage("diert.png");
  //}
  //catch (Exception e) {
    PGraphics img1 = createGraphics(16, 16);
    PGraphics img2 = createGraphics(16, 16);
    PGraphics img3 = createGraphics(16, 16);

    img1.beginDraw();
    img1.background(#3BCE34);
    img1.endDraw();
    img2.beginDraw();
    img2.background(#287125);
    img2.endDraw();
    img3.beginDraw();
    img3.background(#6F341D);
    img3.endDraw();
    
    imgs[0] = img1;
    imgs[1] = img2;
    imgs[2] = img3;
  //}

  ((PGraphicsOpenGL)g).textureSampling(3);

  noiseDetail(2);

  int size = 128;
  float detail = 0.092;
  for (int i = 0; i < size; i++) {
    for (int j = 0; j < size; j++) {
      for (int k = 0; k < size; k++) {
        push();
        translate(100*i, k*100, 100*j);
        if (noise(i*detail, 0, j*detail)*100 < k*15) {
          scale(50);
          data[i][j][k] = 1;
        }
        pop();
      }
    }
  }
}

void draw() {
  //PVector p = getPosition(null);
  //camYaw += (mouseX - width/2)*sensitivity;
  //camPitch += (mouseY - height/2)*sensitivity;
  //robot.mouseMove(round(p.x+width/2), round(p.y+height/2));
  if (mousePressed && mouseButton == CENTER) {
    camYaw -= (pmouseX-mouseX)*sensitivity;
    camPitch -= (pmouseY-mouseY)*sensitivity;
  }

  windowTitle("("+round(frameRate)+") Camera Test "+this);
  background(25);
  //directionalLight(153, 153, 153, .5, 0, -1);
  //ambientLight(255, 255, 255);
  //ambient(255, 255, 128);

  camera(camPos.x, camPos.y, camPos.z, camLookAt.x, camLookAt.y, camLookAt.z, 0, 1, 0);

  int polyCount = 0;
  int size = 32;
  float detail = 0.092;
  for (int i = 0; i < size; i++) {
    for (int j = 0; j < size; j++) {
      for (int k = 0; k < size; k++) {
        push();
        translate(100*i, k*100, 100*j);
        scale(50);
        if (data[i][j][k] == 1 && isNotSurrounded(i, j, k)) {
          boolean showTopFace = true;
          boolean showBottomFace = true;
          boolean showXpositiveFace = true;
          boolean showXnegativeFace = true;
          boolean showYpositiveFace = true;
          boolean showYnegativeFace = true;
          if (k < size-1) showTopFace = data[i][j][k+1] == 0;
          if (k > 1) showBottomFace = data[i][j][k-1] == 0;
          if (i < size-1) showYpositiveFace = data[i+1][j][k] == 0;
          if (i > 1) showYnegativeFace = data[i-1][j][k] == 0;
          if (j < size-1) showXpositiveFace = data[i][j+1][k] == 0;
          if (j > 1) showXnegativeFace = data[i][j-1][k] == 0;
          if (showXpositiveFace) polyCount+=2;
          if (showYpositiveFace) polyCount+=2;
          if (showXnegativeFace) polyCount+=2;
          if (showYnegativeFace) polyCount+=2;
          if (showTopFace) polyCount+=2;
          if (showBottomFace) polyCount+=2;

          texturedCube(imgs[0], imgs[1], imgs[2], showXpositiveFace, showXnegativeFace, showYpositiveFace, showYnegativeFace, showTopFace, showBottomFace);
        } else {
          //box(10);
        }
        pop();
      }
    }
  }

  //Block Breaking

  //try {

  // PVector raycastDirection = camLookAt.copy().sub(camPos); // Calculate ray direction
  // PVector rayOrigin = camPos.copy();

  // float stepSize = 0.025; // Adjust this step size as needed
  // float maxDistance = 700; // Set your desired raycast length

  // for (float d = 0; d < maxDistance; d += stepSize) {
  // int i = round(rayOrigin.x / 100);
  // int j = round(rayOrigin.z / 100);
  // int k = round(rayOrigin.y / 100);

  // if (i >= 0 && i < data.length && j >= 0 && j < data[0].length && k >= 0 && k < data[0][0].length) {
  // if (data[i][j][k] == 1) {
  // if (mousePressed && mouseButton == LEFT) data[i][j][k] = 0;
  // translate(100*i, 100*k, 100*j);
  // noFill();
  // stroke(0);
  // box(101);
  // scale(25);
  // break;
  // }
  // }

  // rayOrigin.add(raycastDirection.normalize().mult(stepSize));
  // }
  //}
  //catch (Exception e) {
  //}

  // Calculate the camera's direction
  float camX = cos(camYaw) * cos(camPitch);
  float camY = sin(camPitch);
  float camZ = sin(camYaw) * cos(camPitch);
  camLookAt = new PVector(camX, camY, camZ);

  // Update the camera position
  if (keyPressed) {
    if (key == 'w') {
      camPos.add(camLookAt.mult(camSpeed));
    }
    if (key == 's') {
      camPos.sub(camLookAt.mult(camSpeed));
    }
    if (key == 'a') {
      PVector right = camLookAt.cross(new PVector(0, 1, 0));
      right.normalize();
      camPos.sub(right.mult(camSpeed));
    }
    if (key == 'd') {
      PVector right = camLookAt.cross(new PVector(0, 1, 0));
      right.normalize();
      camPos.add(right.mult(camSpeed));
    }
  }

  // Rotate the camera using the mouse
  //if (mousePressed) {
  //camHeading += (mouseX - pmouseX) * sensitivity;
  //camPitch += (mouseY - pmouseY) * sensitivity;
  // }

  // Constrain the pitch to prevent camera flipping
  camPitch = constrain(camPitch, -HALF_PI + 0.1, HALF_PI - 0.1);

  //camYaw+=0.1;

  // Move the camera's "lookAt" point
  camLookAt.add(camPos);

  camera();
  noLights();

  noStroke();
  fill(255);
  rect(width/2-15, height/2-1, 30, 2);
  rect(width/2-1, height/2-15, 2, 30);

  text(frameRate+"\n"+polyCount, 100, 100);
}

boolean isNotSurrounded(int i, int j, int k) {
  try {
    if (!(data[i][j][k-1] == 1 && data[i][j][k+1] == 1 && data[i][j-1][k] == 1 && data[i][j+1][k] == 1 && data[i-1][j][k] == 1 && data[i+1][j][k] == 1)) {
      return true;
    } else {
      return false;
    }
  }
  catch (Exception e) {
    return true;
  }
}

void keyPressed() {
  // Use key presses to control camera movement
  if (key == ' ') {
    int playerBlockX = int(camPos.x / 100);
    int playerBlockY = int(camPos.y / 100);
    int playerBlockZ = int(camPos.z / 100);

    if (playerBlockX >= 0 && playerBlockX < 32 &&
      playerBlockY >= 0 && playerBlockY < 32 &&
      playerBlockZ >= 0 && playerBlockZ < 32) {
      data[playerBlockX][playerBlockY][playerBlockZ] = 0; // Set the block at player's position to 0
    }
  }
}

void texturedCube(PImage texture1, PImage texture2, PImage texture3, boolean a, boolean b, boolean c, boolean d, boolean e, boolean f) {
  //noStroke();
  if (a) {
    beginShape(QUADS);
    texture(texture2);
    vertex(-1, -1, 1, 0, 0);
    vertex( 1, -1, 1, 1, 0);
    vertex( 1, 1, 1, 1, 1);
    vertex(-1, 1, 1, 0, 1);
    endShape();
  }
  if (b) {
    beginShape(QUADS);
    texture(texture2);
    vertex( 1, -1, -1, 0, 0);
    vertex(-1, -1, -1, 1, 0);
    vertex(-1, 1, -1, 1, 1);
    vertex( 1, 1, -1, 0, 1);
    endShape();
  }
  if (c) {
    beginShape(QUADS);
    texture(texture2);
    vertex( 1, -1, 1, 0, 0);
    vertex( 1, -1, -1, 1, 0);
    vertex( 1, 1, -1, 1, 1);
    vertex( 1, 1, 1, 0, 1);
    endShape();
  }
  if (d) {
    beginShape(QUADS);
    texture(texture2);
    vertex(-1, -1, -1, 0, 0);
    vertex(-1, -1, 1, 1, 0);
    vertex(-1, 1, 1, 1, 1);
    vertex(-1, 1, -1, 0, 1);
    endShape();
  }
  if (e) {
    beginShape(QUADS);
    texture(texture3);
    vertex(-1, 1, 1, 0, 0);
    vertex( 1, 1, 1, 1, 0);
    vertex( 1, 1, -1, 1, 1);
    vertex(-1, 1, -1, 0, 1);
    endShape();
  }
  if (f) {
    beginShape(QUADS);
    texture(texture1);
    vertex(-1, -1, -1, 0, 0);
    vertex( 1, -1, -1, 1, 0);
    vertex( 1, -1, 1, 1, 1);
    vertex(-1, -1, 1, 0, 1);
    endShape();
  }
}

```

---

<div class="post-metadata">

**Author:** ![micuat](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/micuat/32/19407_2.png) [@micuat](https://discourse.processing.org/u/micuat)\
**Post date:** [October 28, 2023, 3:36pm UTC](https://discourse.processing.org/t/minecraft-like-clone-lagging-too-much/43083/2 "2023-10-28T15:36:10Z")

</div>

The problem may be that you are using so-called immediate mode for rendering - caculating the geometry in CPU and send it to GPU every frame even though it is not changing. In game engines (for example, Unity), usually they use retained mode to store the geometry in GPU and call it every frame so it runs much faster. You can use createShape to achieve it in Processing (with a bit more code), and there is a tutorial [here](https://processing.org/tutorials/pshape). As you are already using begin/endShape, it won’t be too hard to adapt it.

---

<div class="post-metadata">

**Author:** ![glv](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/glv/32/18785_2.png) [@glv](https://discourse.processing.org/u/glv)\
**Post date:** [October 28, 2023, 5:43pm UTC](https://discourse.processing.org/t/minecraft-like-clone-lagging-too-much/43083/3 "2023-10-28T17:43:25Z")

</div>

Hello @Noodlybanan,

The first thing I did was start comment out lines to see what slowed things down.

Commenting this changed the frame rate from 16 to 18 fps:

`texturedCube(imgs[0], imgs[1], imgs[2], showXpositiveFace, showXnegativeFace, showYpositiveFace, showYnegativeFace, showTopFace, showBottomFace);`

I explored further and it was your i_sNotSurrounded(i, j, k)_ that slowed things down.

```auto
if (!(data[i][j][k-1] == 1 && data[i][j][k+1] == 1 && data[i][j-1][k] == 1 && data[i][j+1][k] == 1 && data[i-1][j][k] == 1 && data[i+1][j][k] == 1)) 

```

was giving this exception:

```auto
ArrayIndexOutOfBoundsException: Index -1 out of bounds for length 128

```

I replaced the try\catch with this and was getting a solid 60 fps:

```auto
boolean isNotSurrounded(int i, int j, int k) 
  {
  boolean test = false;
  if(i>0 && j>0 && k>0) 
    {
    if (!(data[i][j][k-1] == 1 && data[i][j][k+1] == 1 && data[i][j-1][k] == 1 && data[i][j+1][k] == 1 && data[i-1][j][k] == 1 && data[i+1][j][k] == 1)) 
      test = true;
    else
      test = false;
    }
  return test;  
  } 

```

I did not scrutinize code further than this and there may be more room for improvement.

`:)`

---

<div class="post-metadata">

**Author:** ![Noodlybanan](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/noodlybanan/32/18897_2.png) [@Noodlybanan](https://discourse.processing.org/u/Noodlybanan)\
**Post date:** [October 29, 2023, 12:31am UTC](https://discourse.processing.org/t/minecraft-like-clone-lagging-too-much/43083/4 "2023-10-29T00:31:59Z")

</div>

Thanks! This was an improvment in performance 🙂

---

<div class="post-metadata">

**Author:** ![Noodlybanan](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/noodlybanan/32/18897_2.png) [@Noodlybanan](https://discourse.processing.org/u/Noodlybanan)\
**Post date:** [October 29, 2023, 12:45am UTC](https://discourse.processing.org/t/minecraft-like-clone-lagging-too-much/43083/5 "2023-10-29T00:45:44Z")

</div>

Hi! I tried this option, and this is my code, it definitly is a performance improvment! Thank you \<3

> **Mesh Builder + Cube Generator**
>
> ```auto
> void buildMeshChunk() {
> chunktest = createShape(GROUP);
> polyCount = 0;
> int size = 16;
> for (int i = 0; i < size; i++) {
> for (int j = 0; j < size; j++) {
> for (int k = 0; k < size; k++) {
> if (data[i][j][k] != 0 && isNotSurrounded(i, j, k)) {
> boolean showTopFace = true;
> boolean showBottomFace = true;
> boolean showXpositiveFace = false;
> boolean showXnegativeFace = false;
> boolean showYpositiveFace = false;
> boolean showYnegativeFace = false;
> 
> if (k < size - 1) showTopFace = data[i][j][k + 1] == 0;
> if (k > 1) showBottomFace = data[i][j][k - 1] == 0;
> if (i < size - 1) showYpositiveFace = data[i + 1][j][k] == 0;
> if (i > 1) showYnegativeFace = data[i - 1][j][k] == 0;
> if (j < size - 1) showXpositiveFace = data[i][j + 1][k] == 0;
> if (j > 1) showXnegativeFace = data[i][j - 1][k] == 0;
>           
> if (showXpositiveFace) polyCount += 2;
> if (showYpositiveFace) polyCount += 2;
> if (showXnegativeFace) polyCount += 2;
> if (showYnegativeFace) polyCount += 2;
> if (showTopFace) polyCount += 2;
> if (showBottomFace) polyCount += 2;
> 
> if (data[i][j][k] == 1) {
> chunktest.addChild(texturedCube(imgs[0], imgs[1], imgs[2], i*2, k*2,j*2, showXpositiveFace, showXnegativeFace, showYpositiveFace, showYnegativeFace, showTopFace, showBottomFace));
> }
> if (data[i][j][k] == 2) {
> chunktest.addChild(texturedCube(imgs[2], imgs[2], imgs[2], i*2, k*2, j*2, showXpositiveFace, showXnegativeFace, showYpositiveFace, showYnegativeFace, showTopFace, showBottomFace));
> }
> }
> }
> }
> }
> }
> 
> ```
> 
> &
> 
> ```auto
> PShape texturedCube(PImage texture1, PImage texture2, PImage texture3, int x, int y, int z, boolean a, boolean b, boolean c, boolean d, boolean e, boolean f) {
> PShape cube = createShape(GROUP);
> if (a) {
> PShape face = createShape();
> face.beginShape(QUADS);
> face.translate(x, y, z);
> face.texture(texture2);
> face.vertex(-1, -1, 1, 0, 0);
> face.vertex(1, -1, 1, 1, 0);
> face.vertex(1, 1, 1, 1, 1);
> face.vertex(-1, 1, 1, 0, 1);
> face.endShape();
> cube.addChild(face);
> }
> if (b) {
> PShape face = createShape();
> face.beginShape(QUADS);
> face.translate(x, y, z);
> face.texture(texture2);
> face.vertex(1, -1, -1, 0, 0);
> face.vertex(-1, -1, -1, 1, 0);
> face.vertex(-1, 1, -1, 1, 1);
> face.vertex(1, 1, -1, 0, 1);
> face.endShape();
> cube.addChild(face);
> }
> if (c) {
> PShape face = createShape();
> face.beginShape(QUADS);
> face.translate(x, y, z);
> face.texture(texture2);
> face.vertex(1, -1, 1, 0, 0);
> face.vertex(1, -1, -1, 1, 0);
> face.vertex(1, 1, -1, 1, 1);
> face.vertex(1, 1, 1, 0, 1);
> face.endShape();
> cube.addChild(face);
> }
> if (d) {
> PShape face = createShape();
> face.beginShape(QUADS);
> face.translate(x, y, z);
> face.texture(texture2);
> face.vertex(-1, -1, -1, 0, 0);
> face.vertex(-1, -1, 1, 1, 0);
> face.vertex(-1, 1, 1, 1, 1);
> face.vertex(-1, 1, -1, 0, 1);
> face.endShape();
> cube.addChild(face);
> }
> if (e) {
> PShape face = createShape();
> face.beginShape(QUADS);
> face.translate(x, y, z);
> face.texture(texture3);
> face.vertex(-1, 1, 1, 0, 0);
> face.vertex(1, 1, 1, 1, 0);
> face.vertex(1, 1, -1, 1, 1);
> face.vertex(-1, 1, -1, 0, 1);
> face.endShape();
> cube.addChild(face);
> }
> if (f) {
> PShape face = createShape();
> face.beginShape(QUADS);
> face.translate(x, y, z);
> face.texture(texture1);
> face.vertex(-1, -1, -1, 0, 0);
> face.vertex(1, -1, -1, 1, 0);
> face.vertex(1, -1, 1, 1, 1);
> face.vertex(-1, -1, 1, 0, 1);
> face.endShape();
> cube.addChild(face);
> }
> return cube;
> }
> 
> ```

However, i still have performance problems. Is there a way to fix this, because i saw [this post](https://forum.processing.org/two/discussion/26119/how-to-stop-edge-artifacts-when-using-a-spritesheet-textureatlas.html) and i wonder how they made their game so efficient!  
-Libby
