How to draw circles in a pyramid shape using p5js and matterjs

193 Views Asked by At

I am trying to draw multiple circles in pyramid shape like this: balls in pyramid shape

I have made this 'Balls' class:

class Balls {
  constructor(x, y, radius, color, ballCount) {
    this.x = x;
    this.y = y;
    this.radius = radius;
    this.color = color;

    this.balls = [];

    this.ballCount = ballCount;

    this.option = { restitution: 1, friction: 0.01, label: "ball" };
  }

  setupBalls() {
    for (var i = 0; i < this.ballCount; i++) {
      var ball = Bodies.circle(this.x, this.y , this.radius, this.option);
      this.balls.push(ball);
      World.add(engine.world, [this.balls[i]]);
    }
  }

  
  drawBalls() {
    fill(this.color);
    noStroke();
    for(var i = 0; i<this.balls.length; i++){
        drawVertices(this.balls[i].vertices);
    }
  }
}

'setupBalls()' method is called in 'function setup()' and 'drawBalls()' is called in 'function draw()' of p5.js like this:

function setup() {
    createCanvas(1200, 600);

    //create engine
    engine = Engine.create();
    //set world gravity to 0
    engine.world.gravity.y = 0;


    //balls
    balls = new Balls(width / 2 + 100, 250, 8, color(200, 0, 0), 15);
    balls.setupBalls();


}

 function draw() {

    background(125);
    Engine.update(engine);

    //balls
    balls.drawBalls();
}

<script src="https://cdnjs.cloudflare.com/ajax/libs/matter-js/0.19.0/matter.min.js"></script>
<script 
src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.6.0/p5.min.js"> 
</script>

I tried playing around with the x and y position using nested for loops but i just cant get the pyramid shape that i wanted.

class Balls {
  constructor(x, y, radius, color, ballCount) {
    this.x = x;
    this.y = y;
    this.radius = radius;
    this.color = color;

    this.balls = [];

    this.ballCount = ballCount;

    this.option = {
      restitution: 1,
      friction: 0.01,
      label: "ball"
    };
  }

  setupBalls() {
    for (var i = 0; i < this.ballCount; i++) {
      var ball = Bodies.circle(this.x, this.y, this.radius, this.option);
      this.balls.push(ball);
      World.add(engine.world, [this.balls[i]]);
    }
  }


  drawBalls() {
    fill(this.color);
    noStroke();
    for (var i = 0; i < this.balls.length; i++) {
      drawVertices(this.balls[i].vertices);
    }
  }
}

//module aliases
var Engine = Matter.Engine;
var World = Matter.World;
var Bodies = Matter.Bodies;
var Body = Matter.Body;

function setup() {
  createCanvas(1200, 600);

  //create engine
  engine = Engine.create();
  //set world gravity to 0
  engine.world.gravity.y = 0;


  //balls
  balls = new Balls(width / 2 + 100, 250, 8, color(200, 0, 0), 15);
  balls.setupBalls();


}

function draw() {

  background(125);
  Engine.update(engine);

  //balls
  balls.drawBalls();
}

<script src="https://cdnjs.cloudflare.com/ajax/libs/matter-js/0.19.0/matter.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.6.0/p5.min.js"></script>

1

There are 1 best solutions below

2
On BEST ANSWER

I'm not familiar with matter.js but the following code uses nested for loops to create a triangle shape using circles to simulate a pool ball rack configuration:

let numBalls = [1, 2, 3, 4, 5]; // Per column
let ballsMax = 5;
let lenDisparity = 0;
let counter = 0;

// Build by column
function circleGrid(l, t, diameter, hgap, vgap) {
  var x;
  var y; 
  for (let j = 0; j < numBalls.length; j++) {
  for (let k = 0; k < numBalls[counter]; k++) {   
      x = l + j*vgap;
      y = t + k*hgap;
      lenDisparity = ballsMax - numBalls[counter];
      if (lenDisparity > 0) {
        y += lenDisparity*hgap/2;
      }    
      fill(random(255),random(255),random(255));
      circle(x,y,diameter);
    }
    counter++;
  }
}

function setup() {
  createCanvas(400, 400);
  circleGrid(60,60,28,30,30);
}

function draw() {
}

CircleGridByColAndRow

The following source code demonstrates the differences of building the grid by column vs. building by row:

let numBalls = [1, 2, 3, 4, 5]; 
let ballsMax = 5;
let lenDisparity = 0;

function circleGridByCol(l, t, diameter, hgap, vgap) {
  var x;
  var y; 
  counter = 0;
  for (let j = 0; j < numBalls.length; j++) {
  for (let k = 0; k < numBalls[counter]; k++) {   
      x = l + j*vgap;
      y = t + k*hgap;
      lenDisparity = ballsMax - numBalls[counter];
      if (lenDisparity > 0) {
        y += lenDisparity*hgap/2;
      }    
      fill(random(255),random(255),random(255));
      circle(x,y,diameter);
    }
    counter++;
  }
}

function circleGridByRow(l, t, diameter, hgap, vgap) {
  var x;
  var y; 
  counter = 0;
  for (let k = 0; k < numBalls.length; k++) {
  for (let j = 0; j < numBalls[counter]; j++) {   
      x = l + j*vgap;
      y = t + k*hgap;
      lenDisparity = ballsMax - numBalls[counter];
      if (lenDisparity > 0) {
        x += lenDisparity*vgap/2;
      }    
      fill(random(255),random(255),random(255));
      circle(x,y,diameter);
    }
    counter++;
  }
}

function setup() {
  createCanvas(600, 250);
  circleGridByCol(60,60,28,30,30);
  circleGridByRow(250,60,28,30,30);
}

function draw() {
}