I have been stuck on this for hours and am unsure on what to do.
Here is my code:
var circles = [];
var circles2 = [];
function setup() {
createCanvas(500, 500);
//there's a "b" for every "a"
for (var a = 50; a < width - 300; a += 20) {
for (var b = 50; b < height - 300; b += 20) {
//add the circles to the array at x = a and y = b
circles.push(new Circle(a, b));
circles2.push(new Conn(a, b));
}
}
for (var a = 250; a < width - 50; a += 20) {
for (var b = 250; b < height - 50; b += 20) {
//add the circles to the array at x = a and y = b
}
}
console.log(circles.length);
}
function draw() {
background(50);
for (var b = 0; b < circles.length; b++) {
circles2[b].show();
circles[b].show();
//console.log("shown");
}
for (var b = 0; b < circles2.length; b++) {
//circles2[b].show();
//console.log("shown");
}
}
function Circle(x, y) {
this.x = x;
this.y = y;
this.show = function() {
fill(255);
noStroke();
ellipse(this.x, this.y, 10, 10);
//console.log("showing");
push();
fill(255);
noStroke();
translate(250, 250);
ellipse(this.x, this.y, 10, 10);
pop();
}
}
function Conn(x, y) {
this.x = x;
this.y = y;
this.show = function() {
noStroke();
let h = 0;
for (let i = 0; i < 251; i++) {
fill(h, 90, 120);
h = (h + 1) % 500;
noStroke();
push()
ellipse(this.x + i, this.y + i, 10, 10);
noStroke();
noLoop();
}
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>
It generates a grid of squares that is supposed to connect to a different grid of squares through gradient lines. However, only the bottom row and right most column of circles on the bottom right circle grid show up for some reason. How can I make it that all circles on the bottom right circle grid are in front of the gradient lines? I've tried push, pop, and everything else. I'm really confused as to why only some of the circles are showing up, but the others are stuck behind these gradients.
Unless you use p5.js in WEBGL mode then there is no object stacking order or z-index or z-buffer. Shapes that you draw always overlap whatever was drawn before them. So in order to make a shape appear on top of another you need to draw the shape underneath first, followed by the shape on top. I believe I was able to achieve this by rearranging your code a little:
var circles = [];
var connections = [];
function setup() {
createCanvas(500, 500);
//there's a "b" for every "a"
for (var a = 50; a < width - 300; a += 20) {
for (var b = 50; b < height - 300; b += 20) {
//add the circles to the array at x = a and y = b
circles.push(new Circle(a, b));
connections.push(new Conn(a, b));
}
}
for (var a = 250; a < width - 50; a += 20) {
for (var b = 250; b < height - 50; b += 20) {
//add the circles to the array at x = a and y = b
}
}
console.log(circles.length);
}
function draw() {
background(50);
// Show connections first
for (var b = 0; b < connections.length; b++) {
connections[b].show();
}
// Show circles second so that they appear on top of the connections
for (var b = 0; b < circles.length; b++) {
circles[b].show();
}
}
function Circle(x, y) {
this.x = x;
this.y = y;
this.show = function() {
fill(255);
noStroke();
ellipse(this.x, this.y, 10, 10);
//console.log("showing");
push();
fill(255);
noStroke();
translate(250, 250);
ellipse(this.x, this.y, 10, 10);
pop();
}
}
function Conn(x, y) {
this.x = x;
this.y = y;
this.show = function() {
noStroke();
let h = 0;
for (let i = 0; i < 251; i++) {
fill(h, 90, 120);
h = (h + 1) % 500;
noStroke();
push()
ellipse(this.x + i, this.y + i, 10, 10);
noStroke();
noLoop();
}
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>
Related
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>
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;
}
}
After a few hours of work and research (I just started learning p5js and javascript) I have about 50 lines of code that creates a grid of circles and begins to move them across the canvas. Before I get into my issue, I will share the code.
var circles = [];
function setup() {
createCanvas(500, 500);
for (var a = 50; a < width - 300; a += 20) {
for (var b = 50; b < height - 300; b += 20) {
circles.push(new Circle(a, b));
}
}
}
function draw() {
background(50);
for (var b = 0; b < circles.length; b++) {
circles[b].show();
}
}
function Circle(x, y) {
this.x = x;
this.y = y;
this.show = function() {
fill(255);
noStroke();
ellipse(this.x, this.y, 10, 10);
if (this.x < 51) {
this.x += 1
this.y += 1
}
if (this.x < 430) {
this.x += 1
this.y += 1
}
if (this.x > 430) {
this.x -= 1
this.y -= 1
}
if (this.x < 51) {
this.x += 1
this.y += 1
}
}
}
What I would like to do is move this grid of circles starting at (50,50) to the bottom right corner. Once it hits (width-50,height-50) I'd like the movement to reverse back to the starting point, and then back the other way. This code moves the circles to the bottom right corner successfully, them something goes wrong. The circles don't reverse their movement, rather, they get messed up. I thought the if statements would handle this but I must be missing something. I trouble shooted for about an hour and now I thought I'd ask SO. Thanks!
Add a moving direction to the object. Change the direction when the object goes out of bounds:
var circles = [];
function setup() {
createCanvas(500, 500);
for (var a = 50; a < width - 300; a += 20) {
for (var b = 50; b < height - 300; b += 20) {
circles.push(new Circle(a, b));
}
}
}
function draw() {
background(50);
for (var b = 0; b < circles.length; b++) {
circles[b].show();
}
}
function Circle(x, y) {
this.x = x;
this.y = y;
this.dx = 1;
this.dy = 1
this.show = function() {
fill(255);
noStroke();
ellipse(this.x, this.y, 10, 10);
this.x += this.dx
this.y += this.dy
if (this.x < 51 || this.y < 51) {
this.dx = 1
this.dy = 1
}
if (this.x > 430 || this.y > 430) {
this.dx = -1
this.dy = -1
}
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.3.1/p5.min.js"></script>
If you do not want to move the objects individually, you must use 1 direction of movement for all objects:
var circles = [];
function setup() {
createCanvas(500, 500);
for (var a = 50; a < width - 300; a += 20) {
for (var b = 50; b < height - 300; b += 20) {
circles.push(new Circle(a, b));
}
}
}
var dx = 1
var dy = 1
function draw() {
background(50);
mx = dx
my = dy
for (var b = 0; b < circles.length; b++) {
circles[b].show(mx, my);
}
}
function Circle(x, y) {
this.x = x;
this.y = y;
this.show = function(mx, my) {
fill(255);
noStroke();
ellipse(this.x, this.y, 10, 10);
this.x += mx
this.y += my
if (this.x < 51) {
dx = 1
dy = 1
}
if (this.x > 430) {
dx = -1
dy = -1
}
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.3.1/p5.min.js"></script>
A last issue i have in this code is that i am not sure how to create color change effect as 8 directional.
I can only map a mouseX to make it lerpColor horizontally or vertically .
But how do i make it work through moving both mouseX and mouseY?
I had it in shift_Color method within the class. I tried to state that within a certain dist(), lerpColor. But now it only showing black color rather than the changing color effect.
let cubes = [];
function setup() {
createCanvas(windowWidth, windowHeight, WEBGL);
backCol = color(243, 243, 243);
//background(backCol);
for (let i = 0; i < 10; i++) {
for (let j = 0; j < 10; j++) {
let xPos = map(i, 0, 9, 50, width - 50);
let yPos = map(j, 0, 9, 50, height - 50);
cubes.push(new Cubes(xPos, yPos));
}
}
}
function draw() {
background(backCol);
noFill();
for (let a = 0; a < cubes.length; a++) {
cubes[a].update();
}
}
class Cubes {
constructor(x, y) {
this.x = x;
this.y = y;
this.size = 30;
this.stroke = 70;
this.gap = 110
this.shift1 = color(96);
this.shift2 = color(244);
}
update() {
this.shape();
this.shift_Color();
}
shape() {
push();
stroke(this.stroke);
//fill(this.shift1);
this.shift_Color();
translate(this.x - width / 2, this.y - height / 2, 0);
this.magnetic()
box(this.size);
pop();
}
shift_Color() {
let distance = dist(mouseX, mouseY, this.x, this.y);
if (distance < this.gap) {
this.shift1 = color(96);
this.shift2 = color(244);
this.shiftX = map(mouseX - width/2,this.gap,distance,0,1.0);
this.change = lerpColor(this.shift1, this.shift2, this.shiftX);
fill(this.change);
} else {
fill(this.shift1);
}
}
magnetic() {
let distance = dist(mouseX, mouseY, this.x, this.y);
if (distance < this.gap) {
this.attract = atan2(mouseY - this.y, mouseX - this.x);
rotateX(this.attract);
rotateY(this.attract);
} else {
rotateX(millis() / 1000);
rotateY(millis() / 1000);
}
}
}
If I understood your question properly, there are two problems in your code.
The first is the fact that because you are trying to map the distance between mouse and the cube to number between 0 and 1, you should write lerpColor(this.shift2, this.shift1, this.shiftX) instead of lerpColor(this.shift1, this.shift2, this.shiftX), since this.shift2 is the lighter color and will be the inner color.
Another problem is when mapping the change variable, change should be calculated based on the distance between mouse and the cube (which is the distance variable), not mouseX or mouseY. Solution is to simply do map(distance, 0, this.gap, 0, 1);.
let cubes = [];
function setup() {
createCanvas(windowWidth, windowHeight, WEBGL);
backCol = color(243, 243, 243);
for (let i = 0; i < 10; i++) {
for (let j = 0; j < 10; j++) {
let xPos = map(i, 0, 9, 50, width - 50);
let yPos = map(j, 0, 9, 50, height - 50);
cubes.push(new Cubes(xPos, yPos));
}
}
}
function draw() {
background(backCol);
noFill();
for (let cube of cubes) {
cube.update();
}
}
class Cubes {
constructor(x, y) {
this.x = x;
this.y = y;
this.size = 30;
this.stroke = 70;
this.gap = 110
this.shift1 = color(96);
this.shift2 = color(244);
}
update() {
this.shape();
this.shift_Color();
}
shape() {
push();
stroke(this.stroke);
//fill(this.shift1);
this.shift_Color();
translate(this.x - width / 2, this.y - height / 2, 0);
this.magnetic()
box(this.size);
pop();
}
shift_Color() {
let distance = dist(mouseX, mouseY, this.x, this.y);
if (distance < this.gap) {
this.shiftX = map(distance, 0, this.gap, 0, 1);
// this.shiftX = map(mouseX - width/2,this.gap,distance,0,1.0);
this.change = lerpColor(this.shift2, this.shift1, this.shiftX);
// this.change = lerpColor(this.shift1, this.shift2, this.shiftX);
fill(this.change);
} else {
fill(this.shift1);
}
}
magnetic() {
let distance = dist(mouseX, mouseY, this.x, this.y);
if (distance < this.gap) {
this.attract = atan2(mouseY - this.y, mouseX - this.x);
rotateX(this.attract);
rotateY(this.attract);
} else {
rotateX(millis() / 1000);
rotateY(millis() / 1000);
}
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.0.0/p5.min.js"></script>
I also modified some of your code. Like the line
this.shift1 = color(96);
this.shift2 = color(244);
which is not needed currently since neither of these variable changes during execution.
I have JavaScript code for a memory game for Khan Academy and I have no idea how to make a tile change color when the mouse is over it. As a test I tried to draw a star on a tile when the mouse was over it in the "if (tiles[i].isUnderMouse(mouseX, mouseY))" in the mouseClicked function but of course that only worked when the mouse is clicked and because the tiles are in a draw function the star would be put behind the new set of tiles after the next click. I don't really even know where to start to do this. Can anyone help me?
//Card face down image variable
var fdImage = image(getImage("avatars/questionmark"), this.x, this.y, this.width, this.width);
var Tile = function(x, y, face) {
this.x = x;
this.y = y;
this.face = face;
this.width = 70;
};
Tile.prototype.drawFaceDown = function() {
fill(214, 247, 202);
strokeWeight(2);
rect(this.x, this.y, this.width, this.width, 10);
image(getImage("avatars/questionmark"), this.x, this.y, this.width, this.width);
this.isFaceUp = false;
};
Tile.prototype.drawFaceUp = function() {
fill(214, 247, 202);
strokeWeight(2);
rect(this.x, this.y, this.width, this.width, 10);
image(this.face, this.x, this.y, this.width, this.width);
this.isFaceUp = true;
};
Tile.prototype.isUnderMouse = function(x, y) {
if ( x >= this.x && x <= this.x + this.width &&
y >= this.y && y <= this.y + this.width ) {
}
return x >= this.x && x <= this.x + this.width &&
y >= this.y && y <= this.y + this.width;
};
// Global config
var NUM_COLS = 5;
var NUM_ROWS = 4;
// Declare an array of all possible faces
var faces = [
//saplings
getImage("avatars/leafers-seed"),
getImage("avatars/leafers-seedling"),
getImage("avatars/leafers-sapling"),
getImage("avatars/leafers-tree"),
getImage("avatars/leafers-ultimate"),
getImage("avatars/piceratops-seed"),
getImage("avatars/piceratops-seedling"),
getImage("avatars/piceratops-sapling"),
getImage("avatars/piceratops-tree"),
getImage("avatars/piceratops-ultimate"),
getImage("avatars/aqualine-seed"),
getImage("avatars/aqualine-seedling"),
getImage("avatars/aqualine-sapling"),
getImage("avatars/aqualine-tree"),
getImage("avatars/aqualine-ultimate"),
//figures
getImage("avatars/marcimus"),
getImage("avatars/mr-pants"),
getImage("avatars/mr-pink"),
getImage("avatars/old-spice-man"),
getImage("avatars/orange-juice-squid"),
getImage("avatars/purple-pi"),
getImage("avatars/spunky-sam"),
//robots
getImage("avatars/robot_female_1"),
getImage("avatars/robot_female_2"),
getImage("avatars/robot_female_3"),
getImage("avatars/robot_male_1"),
getImage("avatars/robot_male_2"),
getImage("avatars/robot_male_3"),
//important figures
getImage("creatures/Hopper-Happy"),
getImage("creatures/Hopper-Cool"),
getImage("creatures/Hopper-Jumping"),
getImage("creatures/OhNoes"),
getImage("creatures/BabyWinston"),
getImage("creatures/Winston"),
//rpg material
getImage("space/beetleship"),
getImage("space/healthheart"),
getImage("space/octopus"),
getImage("space/planet"),
getImage("space/rocketship"),
getImage("space/star"),
];
// Make an array which has 2 of each, then randomize it
var possibleFaces = faces.slice(0);
var selected = [];
for (var i = 0; i < (NUM_COLS * NUM_ROWS) / 2; i++) {
// Randomly pick one from the array of remaining faces
var randomInd = floor(random(possibleFaces.length));
var face = possibleFaces[randomInd];
// Push twice onto array
selected.push(face);
selected.push(face);
// Remove from array
possibleFaces.splice(randomInd, 1);
}
// Now we need to randomize the array
selected.sort(function() {
return 0.5 - Math.random();
});
// Create the tiles
var tiles = [];
for (var i = 0; i < NUM_COLS; i++) {
for (var j = 0; j < NUM_ROWS; j++) {
tiles.push(new Tile(i * 78 + 10, j * 78 + 40, selected.pop()));
}
}
background(255, 255, 255);
// Now draw them face up
for (var i = 0; i < tiles.length; i++) {
tiles[i].drawFaceDown();
}
var flippedTiles = [];
var delayStartFC = null;
var numTries = 0;
mouseClicked = function() {
for (var i = 0; i < tiles.length; i++) {
//
if (tiles[i].isUnderMouse(mouseX, mouseY)) {
//
if (flippedTiles.length < 2 && !tiles[i].isFaceUp) {
tiles[i].drawFaceUp();
flippedTiles.push(tiles[i]);
if (flippedTiles.length === 2) {
numTries++;
if (flippedTiles[0].face === flippedTiles[1].face) {
flippedTiles[0].isMatch = true;
flippedTiles[1].isMatch = true;
}
delayStartFC = frameCount;
loop();
}
}
}
}
var foundAllMatches = true;
for (var i = 0; i < tiles.length; i++) {
foundAllMatches = foundAllMatches && tiles[i].isMatch;
}
if (foundAllMatches) {
fill(0, 0, 0);
textSize(20);
text("You found them all in " + numTries + " tries!", 20, 375);
}
};
draw = function() {
if (delayStartFC && (frameCount - delayStartFC) > 30) {
for (var i = 0; i < tiles.length; i++) {
if (!tiles[i].isMatch) {
tiles[i].drawFaceDown();
}
}
flippedTiles = [];
delayStartFC = null;
noLoop();
}
};
In order to add a hover state to the tiles in this Khan Academy challenge, you must first add a new method to your Tile object
Tile.prototype.hoverState = function() {
fill(150, 247, 202);
strokeWeight(2);
rect(this.x, this.y, this.width, this.width, 10);
image(getImage("avatars/leaf-green"), this.x, this.y, this.width, this.width);
this.isFaceUp = false;
};
Afterwards you will need to use mouseMoved like this:
mouseMoved = function() {
for (var i = 0; i < tiles.length; i++) {
if (tiles[i].isUnderMouse(mouseX, mouseY) && !tiles[i].isFaceUp) {
tiles[i].hoverState();
} else if (tiles[i].isFaceUp) {
tiles[i].drawFaceUp();
} else {
tiles[i].drawFaceDown();
}
}
};