How to make a grid of moiré circles in p5.js? - javascript

I'm attempting to make a grid where every tile is filled with a single "moire-style" ellipse (a circle with circles inside).
function setup() {
createCanvas(500, 500);
ellipseMode(CENTER);
}
function draw() {
background(255);
noFill();
strokeWeight(3);
stroke(0);
let tilesX = 3;
let tilesY = tilesX;
let tileW = width / tilesX;
let tileH = height / tilesY;
for (let x = 0; x < tilesX; x++) {
for (let y = 0; y < tilesY; y++) {
moire(tilesX, tilesY, tileW);
}
}
function moire(x, y, size) {
for (var i = 1; i <= tileW; i = i + 8) {
ellipse(width / 2, height / 2, 2 * i, 2 * i);
translate(tilesX, tilesY);
}
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.5.0/p5.js"></script>
This is what I have in my p5.js sketch but the moire elements don't align to the tiles.

The following demo will create a grid of moire circles:
let _numRows = 3;
let _numCols = 3;
let _colGap = 30;
let _rowGap = 30;
function moire(x, y, size) {
for (var i = 1; i <= size; i = i + 8) {
ellipse(x, y, 2 * i, 2 * i);
translate(3, 3);
}
}
function setup() {
createCanvas(500, 500);
ellipseMode(CENTER);
}
function draw() {
background(255);
noFill();
strokeWeight(3);
stroke(0);
let _xOffset = width/5;
let _yOffset = height/5;
for (let j = 0; j < _numCols; j++) {
for (let k = 0; k < _numRows; k++) {
push();
moire(_xOffset + j * (100 + _colGap), _yOffset + k * (100 + _rowGap), 50);
pop();
}
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.5.0/p5.js"></script>

Related

How to change the rows or columns of a grid without messing up the content

I want to be able to implement more rows or columns to the grid depending on the format. (For example if i want to use the sketch on a horizontal 16x9 screen, there would have to be more rows than columns) Right now it only works if the format/canvas is square.
As soon as I change the number of tiles or the size of the canvas, the elements jump around.
Here is my sketch:
let colors = [
"#F7F7F7",
"#141414",
"#FB2576",
"#F48668",
"#67339E",
"#00A6A6",
"#78FFD6"
];
function drawSubdividedCircle(x, y, size, segments, layers) {
segments = random (1,13);
layers = random (1,13);
const r = 360 / segments;
for (let i = 0; i < segments; i++) {
for (let j = 0; j < layers; j++) {
fill(random(colors));
const s = map(j, 0, layers, size, 0);
arc(
x + size / 2,
y + size / 2,
s,
s,
radians(r * i),
radians(r * (i + 1)));
}
}
}
function setup() {
createCanvas(500, 500);
frameRate(2);
}
function draw() {
noStroke();
let tilesX = 5;
let tilesY = 5;
let tileW = width / tilesX;
let tileH = height / tilesY;
const tileSize = width / tilesX;
for (let x = 0; x < tilesX; x++) {
for (let y = 0; y < tilesY; y++) {
rect(x*tileW, y*tileH, tileW, tileH);
fill(random(colors));
push();
for (let x = 0; x < tilesX; x++) {
for (let y = 0; y < tilesY; y++) {
let r = random(1);
if (r < 0.5) {
ellipseMode(CORNER);
ellipse(x*tileW, y*tileH, tileW, tileH);
fill(random(colors));
} else {
ellipseMode(CENTER);
drawSubdividedCircle(x * tileSize, y * tileSize, tileSize);
fill(random(colors));
pop();
}
}
}
}
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.5.0/p5.js"></script>
I changed your code a little.. Removed two redundant for-loops, it is much faster now.
When you want to make your program responsive, you have to make a choice. Do you want the circles to scale when you change the resolution or maybe do you want the amount of rows/columns to change when the resolution changes? There are several possibilities, I made it now to keep the amount of tiles, and use the smaller value of the 'tileW' and 'tileH' to remain the circle shape.
let colors = [
"#F7F7F7",
"#141414",
"#FB2576",
"#F48668",
"#67339E",
"#00A6A6",
"#78FFD6"
];
var tilesX = 5;
var tilesY = 5;
var tileW;
var tileH;
var tileSize;
function drawSubdividedCircle(x, y, size, segments, layers)
{
segments = random (1,13);
layers = random (1,13);
const r = 360 / segments;
for (let i = 0; i < segments; i++)
{
for (let j = 0; j < layers; j++)
{
fill(random(colors));
const s = map(j, 0, layers, size, 0);
arc(
x + size / 2,
y + size / 2,
s,
s,
radians(r * i),
radians(r * (i + 1)));
}
}
}
function setup()
{
createCanvas(550, 500);
ellipseMode(CENTER);
//frameRate(2);
tileW = width / tilesX;
tileH = height / tilesY;
tileSize = min(tileW, tileH);
}
function draw()
{
background(0);
noStroke();
for (let x = 0; x < tilesX; x++)
{
for (let y = 0; y < tilesY; y++)
{
rect(x * tileSize, y * tileSize, tileSize, tileSize);
fill(random(colors));
let r = random(1);
if (r < 0.5)
{
ellipse((x - 0.5) * tileSize, (y - 0.5) * tileSize, tileSize, tileSize);
fill(random(colors));
}
else
{
drawSubdividedCircle(x * tileSize, y * tileSize, tileSize);
fill(random(colors));
}
}
}
}

How to make a grid of ellipses with subdivisions

I have created a circle with subdivisions (function CircleSubDivs) in p5.js and now want to generate a grid filled with those. Ideally the ellipse would also be disproportionate if the width and height of a tile is not the same, or if the amount of tiles were to be controlled by the mouse position the ellipse would move flexibly.
This was my inspiration
This is my code so far:
// let colors = [
// "#F48668 ",
// "#5D2E8C",
// "#F7F7F7"
// ];
function CircleSubDivs(x, y, size) {
let amount = 13;
let r = 360 / amount;
for (let j = 0; j < 10; j++) {
for (let i = 0; i < amount; i++) {
fill(random(255));
let s = map(j, 0, 8, width, 100);
arc(width / 2, height / 2, s, s, radians(r * i), radians(r * (i + 1)));
}
}
}
function setup() {
createCanvas(500, 500);
frameRate(1);
}
function draw() {
background("#0F0F0F");
noStroke();
let tilesX = 3;
let tilesY = 2;
let tileW = width / tilesX;
let tileH = height / tilesY;
for (let x = 0; x < tilesX; x++) {
for (let y = 0; y < tilesY; y++) {
CircleSubDivs(x * tileW, y * tileH, tileW, tileH);
}
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.5.0/p5.js"></script>
As you can see I have created a grid and tried to store my function for the ellipse with divisions in there, but it just shows me one single ellipse when I run it. I would really appreciate some help :)
Your parameters to your function are unused, so the function does the same thing every time.
You might try something like:
function drawSubdividedCircle(x, y, size, segments=13, layers=10) {
const r = 360 / segments;
for (let i = 0; i < segments; i++) {
for (let j = 0; j < layers; j++) {
fill(random(255));
const s = map(j, 0, layers, size, 0);
arc(
x + size / 2,
y + size / 2,
s,
s,
radians(r * i),
radians(r * (i + 1))
);
}
}
}
function setup() {
createCanvas(500, 500);
frameRate(1);
}
function draw() {
background("#0F0F0F");
noStroke();
const tilesX = 3;
const tilesY = 2;
const tileSize = width / tilesX;
for (let x = 0; x < tilesX; x++) {
for (let y = 0; y < tilesY; y++) {
drawSubdividedCircle(x * tileSize, y * tileSize, tileSize);
}
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.5.0/p5.js"></script>

Small issues with an interactive project in p5.js / javascript

I need help with an interactive project in p5.js.
Here are the things that are still missing:
the clock hands should rotate
when the puzzle is solved "won" should be displayed and the timer should stop (Here I have a code part in my program but it doesn´t work)
the "moves" don´t count up when you click somewhere - only at the specific field
at "Game Over" the picture and the clock should stop
Here is a picture of the puzzle: Slide Puzzle
I hope someone can help me. Thank you very much.
Here is the code:
let w = window.innerWidth/2;
let h = window.innerHeight/1.5;
let ground;
let plate = [];
let tiles = [];
let col = 4;
let row = 4;
let bubbles = [];
let timerValue = 160;
let moves = 0;
function setup() {
canvas = createCanvas(w, h);
ground = createGraphics(w, h);
w = width / col;
h = height / row;
textAlign(CENTER, CENTER);
setInterval(timeIt, 1000);
imag = loadImage('Mauszeiger.png');
for (let i = 0; i < col; i++) {
for (let j = 0; j < row; j++) {
let img = createImage(w, h);
let index = i + j * col;
plate.push(index);
let teil = new Tile(index, img);
tiles[index] = teil;
}
}
tiles.pop();
plate.pop();
plate.push(-1);
startViz();
simpleShuffle(plate);
}
function draw() {
background(100);
push();
scale(1, 0.9);
drawViz();
updateTiles();
for (let i = 0; i < col; i++) {
for (let j = 0; j < row; j++) {
let index = i + j * col;
let x = i * w;
let y = j * h;
let teileIndex = plate[index];
if (teileIndex > -1) {
let img = tiles[teileIndex].img;
image(img, x, y, w, h);
}
strokeWeight(5);
noFill();
rect(x, y, w, h);
}
}
pop();
if (isSolved()) {
console.log('SOLVED');
timerValue = 0;
text('Won', width/2, height/2);
}
if (timerValue < 10 || timerValue >= 10) {
textSize(15);
fill(255);
text(timerValue, width-30, height*0.95);
}
textSize(45);
if (timerValue == 0) {
text('Game Over', width/2, height/2);
draw = function(){}
}
textSize(15);
text('moves: ' + moves, width/2, height*0.95);
push();
noFill();
stroke(255);
ellipse(27, height*0.95, 40, 40);
imageMode(CENTER);
image(imag, 30, height*0.95, imag.width / 100, imag.height / 100);
pop();
}
function mousePressed() {
let i = floor(mouseX / w);
let j = floor(mouseY / h);
move(i, j, plate);
if (mousePressed) {
moves++;
}
}
function windowResized() {
w = window.innerWidth/2;
h = window.innerHeight/1.5;
resizeCanvas(w, h);
}
function timeIt() {
if (timerValue > 0) {
timerValue--;
}
}
function isSolved() {
for (let i = 0; i < plate.length - 1; i++) {
if (plate[i] !== tiles[i].index) {
return false;
}
}
return true;
}
function updateTiles() {
for (let i = 0; i < col; i++) {
for (let j = 0; j < row; j++) {
let x = j * w;
let y = i * h;
let index = i + j * col;
if (tiles[index]) tiles[index].img.copy(ground, x, y, w, h, 0, 0, w, h);
}
}
}
function swap(i, j, arr) {
let temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
function randomMove(arr) {
let r1 = floor(random(col));
let r2 = floor(random(row));
move(r1, r2, arr);
}
function simpleShuffle(arr) {
for (let i = 0; i < 1000; i++) {
randomMove(arr);
}
}
function move(i, j, arr) {
let blank = findBlank();
let blankCol = blank % col;
let blankRow = floor(blank / row);
if (isNeighbor(i, j, blankCol, blankRow)) {
swap(blank, i + j * col, arr);
}
}
function isNeighbor(i, j, x, y) {
if (i !== x && j !== y) {
return false;
}
if (abs(i - x) == 1 || abs(j - y) == 1) {
return true;
}
return false;
}
function findBlank() {
for (let i = 0; i < plate.length; i++) {
if (plate[i] == -1) return i;
}
}
function startViz() {
for (let i = 0; i < 5; i++) {
bubbles.push(new Bubble());
}
}
function drawViz() {
ground.background(30);
for (let b of bubbles) {
b.update();
b.show();
b.show1();
}
}
class Bubble {
constructor() {
this.r = random(50, 80);
this.x = random(this.r, width - this.r);
this.y = random(this.r, height - this.r);
this.vx = random(-1 * (w*0.005), 3 * (w*0.005));
this.vy = random(-1 * (w*0.005), 3 * (w*0.005));
this.color = color(random(255), random(255), random(255));
}
show() {
ground.noFill();
ground.stroke(255);
ground.fill(this.color);
ground.strokeWeight(3);
ground.circle(this.x, this.y, this.r * 2 * (w*0.005));
}
show1() {
ground.line(this.x, this.y, this.x + this.r / 2 * (w*0.005), this.y + this.r / 2 * (w*0.005));
ground.line(this.x, this.y, this.x - this.r / 2 * (w*0.005), this.y + this.r / 2 * (w*0.005));
}
update() {
this.x += this.vx;
this.y += this.vy;
if (this.x > width - this.r || this.x < this.r) {
this.vx *= -1;
}
if (this.y > height - this.r || this.y < this.r) {
this.vy *= -1;
}
}
}
class Tile {
constructor(i, img) {
this.index = i;
this.img = img;
}
}

Avoid crossing of geometries

I would like to work with this code:
let vertices = [];
function setup() {
createCanvas(windowWidth, windowHeight);
let numberOfVertices = random(3, 11); //pick the number of points
for (let i = 0; i < numberOfVertices; i++) {
vertices.push(createVector(random(width), random(height))); //add a point to the list of points
}
}
function draw() {
background(220);
fill(255, 0, 0);
noStroke();
beginShape();
for (let i = 0; i < vertices.length; i++) {
vertex(vertices[i].x, vertices[i].y);//place each vertex
}
endShape();
}
* {
margin: 0;
}
<script src="https://cdn.jsdelivr.net/npm/p5#1.3.1/lib/p5.js"></script>
Unfortunately, the geometries sometimes cross. How is it possible to avoid that?
Would be very thankful for help!
Calculate the center of the bounding box of the points and sort the points by the angle of the vector from the center to the point:
let ax = vertices.map(v => v.x);
let ay = vertices.map(v => v.y);
let cx = (Math.min(...ax) + Math.max(...ax)) / 2;
let cy = (Math.min(...ay) + Math.max(...ay)) / 2;
vertices.sort((a, b) => {
let v1 = p5.Vector.sub(a, createVector(cx, cy));
let v2 = p5.Vector.sub(b, createVector(cx, cy));
return Math.atan2(v1.y, v1.x) - Math.atan2(v2.y, v2.x);
});
In the following example, the lines that form the center point to the vertices are drawn to visualize the algorithm:
let vertices = [];
let cx, cy
function setup() {
createCanvas(windowWidth, windowHeight);
let numberOfVertices = random(3, 11); //pick the number of points
for (let i = 0; i < numberOfVertices; i++) {
vertices.push(createVector(random(width), random(height))); //add a point to the list of points
}
let ax = vertices.map(v => v.x);
let ay = vertices.map(v => v.y);
cx = (Math.min(...ax) + Math.max(...ax)) / 2;
cy = (Math.min(...ay) + Math.max(...ay)) / 2;
vertices.sort((a, b) => {
let v1 = p5.Vector.sub(a, createVector(cx, cy));
let v2 = p5.Vector.sub(b, createVector(cx, cy));
return Math.atan2(v1.y, v1.x) - Math.atan2(v2.y, v2.x);
});
}
function draw() {
background(220);
fill(255, 0, 0);
noStroke();
beginShape();
for (let i = 0; i < vertices.length; i++) {
vertex(vertices[i].x, vertices[i].y);//place each vertex
}
endShape();
stroke(255, 255, 255);
strokeWeight(3)
for (let i = 0; i < vertices.length; i++) {
line(cx, cy, vertices[i].x, vertices[i].y);
}
}
<script src="https://cdn.jsdelivr.net/npm/p5#1.3.1/lib/p5.js"></script>
Demo

Need help to draw a X for Tic Tac Toe in p5.js

I was following a tutorial on Youtube (The Coding Train) which was making a minesweeper game. I followed the video until I had make a X.
I want to make to lines that cross each other and form a big x like this:
The board with a X
The problem I have is that I do not know how to that with each cell.
I have a Cell class:
function Cell(x, y, w) {
this.x = x;
this.y = y;
this.w = w;
this.busy = true;
this.player = true;
this.computer = true;
}
Cell.prototype.show = function() {
stroke(0);
noFill();
rect(this.x, this.y, this.w, this.w);
if (true) {
line(0, 0, 100, 100);
line(0, 100, 100, 0);
}
}
And the main code is:
function make2DArray(cols, rows) {
var arr = new Array(cols);
for (var i = 0; i < arr.length; i++) {
arr[i] = new Array(rows);
}
return arr;
}
var grid;
var rows;
var cols;
var w = 100;
function setup() {
createCanvas(300, 300);
cols = floor(width/w);
rows = floor(width/w);
grid = make2DArray(cols, rows);
for (var i = 0; i < cols; i++) {
for (var j = 0; j < rows; j++) {
grid[i][j] = new Cell(i * w, j * w, w);
}
}
}
function draw() {
background(255);
for (var i = 0; i < cols; i++) {
for (var j = 0; j < rows; j++) {
grid[i][j].show();
}
}
}
I want to be able to call a X when a player clicks on a cell, and display it. The line needs to be in the Cell class in Show object.
The coordinate of the top left corner of each Cell is stored in the x and y properties. The width is stored in w.
So a cross over the entire Cell can be draw by:
line(this.x, this.y, this.x+this.w-1, this.y+this.w-1);
line(this.x, this.y+this.w-1, this.x+this.w-1, this.y);
To draw a cross in a Cell dependent on a click into the cell, you have to init the player property by false:
function Cell(x, y, w) {
.......
this.player = false;
}
Draw the cross it the Cell dependent on the player property:
Cell.prototype.show = function() {
stroke(0);
noFill();
rect(this.x, this.y, this.w-1, this.w-1);
if (this.player) {
line(this.x, this.y, this.x+this.w-1, this.y+this.w-1);
line(this.x, this.y+this.w-1, this.x+this.w-1, this.y);
}
}
Create a function which checks if a point is in the Cell and set the player property true, if the test succeeds:
Cell.prototype.testX = function(px, py) {
if (px >= this.x && px < this.x+this.w && py >= this.y && py < this.y+this.w ) {
this.player = true;
}
}
Add a mousePressed event, and call the test function testX for each Cell. if the mouse position is in a cell, then the player property of the Cell will become true and a cross will appear in the Cell at the next draw:
function mousePressed() {
if (mouseButton == LEFT) {
for (var i = 0; i < cols; i++) {
for (var j = 0; j < rows; j++) {
grid[i][j].testX(mouseX, mouseY);
}
}
}
}
function Cell(x, y, w) {
this.x = x;
this.y = y;
this.w = w;
this.busy = true;
this.computer = true;
this.player = false;
}
Cell.prototype.show = function() {
stroke(0);
noFill();
rect(this.x, this.y, this.w-1, this.w-1);
if (this.player) {
line(this.x, this.y, this.x+this.w-1, this.y+this.w-1);
line(this.x, this.y+this.w-1, this.x+this.w-1, this.y);
}
}
Cell.prototype.testX = function(px, py) {
if (px >= this.x && px < this.x+this.w && py >= this.y && py < this.y+this.w ) {
this.player = true;
}
}
function mousePressed() {
if (mouseButton == LEFT) {
for (var i = 0; i < cols; i++) {
for (var j = 0; j < rows; j++) {
grid[i][j].testX(mouseX, mouseY);
}
}
}
}
function make2DArray(cols, rows) {
var arr = new Array(cols);
for (var i = 0; i < arr.length; i++) {
arr[i] = new Array(rows);
}
return arr;
}
var grid;
var rows;
var cols;
var w = 100;
function setup() {
createCanvas(300, 300);
cols = floor(width/w);
rows = floor(width/w);
grid = make2DArray(cols, rows);
for (var i = 0; i < cols; i++) {
for (var j = 0; j < rows; j++) {
grid[i][j] = new Cell(i * w, j * w, w);
}
}
}
function draw() {
background(255);
for (var i = 0; i < cols; i++) {
for (var j = 0; j < rows; j++) {
grid[i][j].show();
}
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.6.1/p5.js"></script>

Categories

Resources