Quantize variables of type float

I have a work-in-progress version of 2-D Minecraft I am working on. Here is the code so far:

final float block_size = 8;
final float ground_level = 8;
final float sky_level = 256;
final float x_min = 0;
final float x_max = 256;

class Player {

  float x;
  float y;
  boolean facing;

  Player(float spawn_x, float spawn_y) {
    x = spawn_x;
    y = spawn_y;
  }

  void move() {
    if (keyPressed) {
      if (key == CODED) {
        switch(key) {
          case 'a':
            x--;
            facing = false;
            break;
          case 'd':
            x++;
            facing = true;
            break;
          case ' ':
            y--;
        }
      } else {
        switch(keyCode) {
          case LEFT:
            x--;
            facing = false;
            break;
          case RIGHT:
            x++;
            facing = true;
            break;
          case UP:
            y--;
        }
      }
    }
  }

  void physics() {
    if (y < ground_level) {
      y++;
    }
    x = constrain(x, x_min, x_max);
    y = constrain(y, ground_level, sky_level);
  }

  void place_block() {

  }

  void break_block() {

  }

}

class Block {

  Block(float x_, float y_) {

  }

  void display() {

  }

}

Player player = new Player(2, (x_max - x_min) / 2);

ArrayList<Block> blocks = new ArrayList<Block>();

I would like to know how to quantize the x and y coordinates of the blocks so that they appear at least slightly organized. Could you also give me other advice on this code? I am rather new to Processing, after all...

Tagged:

Answers

  • Also, here is the error list at the time of posting:Capture

  • We cannot read the errors in the image. Images get resized in the forum. It is better if you copy and paste the error here in the forum.

    Kf

  • edited March 2018

    Okay, here are the errors:

    1 The value of the local variable "block_size" is not used

    11 The value of the field Player.facing is not used

    18 The method move() from the type Player is never used locally

    50 The method physics() from the type Player is never used locally

    58 The method place_block() from the type Player is never used locally

    62 The method break_block() from the type Player is never used locally

    70 The constructor Block(float, float) is never used locally

    70 The value of the parameter x_ is not used

    70 The value of the parameter y_ is not used

    74 The method display() from the type Block is never used locally

    80 The value of the local variable "player" is not used

    80 The allocated object is never used

    82 The value of the local variable "blocks" is not used

    82 The allocated object is never used

    If you haven't guessed already, the numbers indicate which line the error occured in.

  • Those look like warnings rather than errors, and are all self explanatory. Line 1, for instance, you define a variable that you don't use. Either use it or delete it.

    I can't see anywhere in the code where you are creating blocks. How are you picking the positions?

  • edited April 2018

    I have not used the blocks yet, but in the constructorBlock(float x_, float y_) {I need them to be snapped to a grid of size block_size by block_size. A piece of code I tried for each variable was x = floor(x_ / block_size) * block_size; It turned out to be unreliable, so I need a better function to do this.

  • edited April 2018 Answer ✓

    I would like to know how to quantize the x and y coordinates of the blocks

    and

    need them to be snapped to a grid of size block_size by block_size

    Well, you could use round instead of floor. It really depends -- what do you mean by "unreliable"? Be careful of integer division.

    Here is one verbose expression of the logic of snapping (untested):

    offset = x_ % guideSpan;         // how far past the last snap line is it?
    if(offset < guideWidth/2){       // if the offset is less than half the width between lines
       x = x_ - offset;              // then the new location is the last snapline
    } else {
       x = x_ - offset + guideWidth; // otherwise the new location is the next snapline
    }
    

    This assumes a square snap distance in 2D. If it is rectangular, then you will want guideWidthX and guideWidthY.

  • edited April 2018

    I am working on a standalone sketch to test this in. You will have to revoke the title of untested code.

  • edited April 2018

    I've finished making the sketch, the code is here:

    float x_;
    float x;
    float offset;
    float snapSize;
    
    void setup() {
    
      size(200, 200);
    
      snapSize = 16;
    
      rectMode(CENTER);
    }
    
    void draw() {
    
      background(127);
    
      drawGrid();
    
      x_ = random(40, 164);
    
      offset = x_ % snapSize;
      if (offset < snapSize/2) {
        x = x_ - offset;
      } else {
        x = x_ - offset + snapSize;
      }
    
      x_ += snapSize / 2;
      x += snapSize / 2;
    
      rect(x_, 40, 16, 16);
    
      rect(x, 72, 16, 16);
    
      delay(100);
    }
    
    void drawGrid() {
    
      for (int i = 0; i < width; i += snapSize) {
        line(i, 0, i, height);
      }
      for (int i = 0; i < height; i += snapSize) {
        line(0, i, width, i);
      }
    }
    

    P.S. It worked perfectly, for as long as I tested it.

  • edited April 2018

    Now to implement it in my code, combined with the PeasyCam suggestion I got from another discussion. It should make a "good enough" game. However, there may be some difficulties, like limiting yaw and roll so that the game can't be flipped upside down

  • I've edited the code slightly so that it auto-tests, rather than having a human look at the pictorial representation.

    float x_;
    float x;
    float offset;
    float snapSize;
    int testNum;
    int testNumMax;
    
    void setup() {
    
      size(200, 200);
    
      snapSize = 16;
      testNumMax = 10000;
    
      rectMode(CENTER);
    }
    
    void draw() {
    
      testNum++;
    
      background(127);
    
      drawGrid();
    
      x_ = random(40, 164);
    
      offset = x_ % snapSize;
      if (offset < snapSize/2) {
        x = x_ - offset;
      } else {
        x = x_ - offset + snapSize;
      }
    
      if(testQuantize()) {
        println("Test", testNum, "successful (", (float)testNum/(testNumMax/100), "% Tested)");
      } else {
        println("Test", testNum, "failed");
        println("Cancelling test...");
        exit();
      }
    
      x_ += snapSize / 2;
      x += snapSize / 2;
    
      rect(x_, 40, 16, 16);
    
      rect(x, 72, 16, 16);
    
      if(testNum>=testNumMax) {
        println("Test process completed");
        exit();
      }
    
      //delay(100);
    }
    
    void drawGrid() {
    
      for (int i = 0; i < width; i += snapSize) {
        line(i, 0, i, height);
      }
      for (int i = 0; i < height; i += snapSize) {
        line(0, i, width, i);
      }
    }
    
    boolean testQuantize() {
    
      return ((x % snapSize) == 0);
    
    }
    

    I've left it to run for all 10,000 iterations, and it all worked!

  • Looks good!

    Here is an example of the x snap and xy snap behaviors wrapped in functions -- the xy one takes and returns a PVector instead of separate x and y arguments.

    float GUIDE = 100.0;
    
    void setup(){
      noLoop();
    }
    void draw() {
      for (int i=0; i < 500; i+=41) {
        println("   x:", i, "\nsnap:", snapToMark( i, GUIDE), '\n');
      }
      for (int i=0; i < 20; i++) {
        PVector pv = new PVector(random(1000),random(1000));
        PVector pvSnap = snapToXY(pv, GUIDE);
        println("  xy:", nf(pv.x,3,3), nf(pv.y,3,3), "\nsnap:", nf(pvSnap.x,3,3), nf(pvSnap.y,3,3), '\n');
      }
    }
    
    PVector snapToXY ( PVector pv, float guideWidth ) {
      return new PVector(snapToMark(pv.x, guideWidth), snapToMark(pv.y, guideWidth));
    }
    float snapToMark ( float x, float guideWidth ) {
      float offset = x % guideWidth;
      if (offset < guideWidth/2.0) {
        return x - offset;
      } else {
        return x - offset + guideWidth;
      }
    }
    
  • Thanks! I will now save this as a 2D test environment.

  • float snapToMark2 ( float x, float guideWidth ) {
      return round(x / guideWidth) * guideWidth;
    }
    
  • edited April 2018

    actually, whilst that is identical for all of jeremy's examples, the results might be different for -ve numbers because of the % you use.

    yes...

    float GUIDE = 100.0;
    
    void setup(){
      for (int i=0; i < 20; i++) {
        float r = random(-1000, 1000);
        println(r, snapToMark1(r, GUIDE), snapToMark2(r, GUIDE));
      }
    }
    
    float snapToMark1 ( float x, float guideWidth ) {
      float offset = x % guideWidth;
      if (offset < guideWidth/2.0) {
        return x - offset;
      } else {
        return x - offset + guideWidth;
      }
    }
    
    float snapToMark2 ( float x, float guideWidth ) {
      return round(x / guideWidth) * guideWidth;
    }
    

    ie:

    -397.40204 -300.0 -400.0
    -279.974 -200.0 -300.0
    -315.57867 -300.0 -300.0
    

    i wonder which is correct...

  • edited April 2018

    Good point. And avoiding that problem w/ negative numbers and modulo is a great example of why being concise (just round and scale) can be better than making code a slow multi-step demo -- more can go wrong.

    Worth noting that these operations could also be performed directly on PVector components.

Sign In or Register to comment.