Making Tetris with p5.js - p5.js

I have some code so far:
function setup() {
createCanvas(500,550);
}
function draw() {
background(150);
o();
}
function block(x,y) {
rectMode(CENTER)
rect(x,y, cols, rows, 2)
}
function o() {
fill(255, 255,0)
block(width/2, rows);
block(width/2, rows* 2);
block(width/2 + cols, cols)
block(width/2 + cols, cols * 2)
}
And I'm wondering what to do next. I thought of creating drop function and this is what it would look like:
function drop() {
rows += rows;
cols += cols;
}
Then add this to the setup function:
frameRate(10);
So it moves slower, but that wouldn't work.
I don't know how to make the block go down without changing the values of cols and rows. My question is, how can I make the blocks move down, in a function(for instance, a function called drop)?
EDIT: The drop function wouldn't have worked because it would change the size, not the position.

For the block to move, it needs to have an x and a y position.
Currently, you just hardcoded the position.
block(width/2, rows);
Instead, you should do something like this
let x;
let y = rows;
function setup() {
createCanvas(500, 500);
x = width / 2; //you could not set x before now, because the program didn't yet know what the width was
Then, replace your o() function with this:
function o() {
fill(255, 255,0)
block(x, y);
block(x, y + cols);
block(x + cols, y);
block(x + cols, y + cols);
}
Finally, you can change the x and y position in your drop() function (don't forget to actually call it, too)
function drop() {
y += 10;
}

Related

Creating random pixeled lines in Proccesing

I'm trying to make a game and I'm stuck on random level design. Basically, I'm trying to create a line from one edge/corner to another edge/corner while having some randomness to it.
See below image 1 [link broken] and 2 for examples. I'm doing this in processing and every attempt I've tried hasn't yielded proper results. I can get them to populate randomly but not in a line or from edge to edge. I'm trying to do this on a 16 x 16 grid by the way. Any ideas or help would be greatly appreciated thanks!
Image 2:
Based on your description, the challenge is in having a connected line from top to bottom with a bit of randomness driving left/right direction.
There are multiple options.
Here's a basic idea that comes to mind:
pick a starting x position: left's say right down the middle
for each row from 0 to 15 (for 16 px level)
pick a random between 3 numbers:
if it's the 1st go left (x decrements)
if it's the 2nd go right (x increments)
if it's the 3rd: ignore: it means the line will go straight down for this iteration
Here's a basic sketch that illustrates this using PImage to visualise the data:
void setup(){
size(160, 160);
noSmooth();
int levelSize = 16;
PImage level = createImage(levelSize, levelSize, RGB);
level.loadPixels();
java.util.Arrays.fill(level.pixels, color(255));
int x = levelSize / 2;
for(int y = 0 ; y < levelSize; y++){
int randomDirection = (int)random(3);
if(randomDirection == 1) x--;
if(randomDirection == 2) x++;
// if randomDirection is 0 ignore as we don't change x -> just go down
// constrain to valid pixel
x = constrain(x, 0, levelSize - 1);
// render dot
level.pixels[x + y * levelSize] = color(0);
}
level.updatePixels();
// render result;
image(level, 0, 0, width, height);
fill(127);
text("click to reset", 10, 15);
}
// hacky reset
void draw(){}
void mousePressed(){
setup();
}
The logic is be pretty plain above, but free to replace random(3) with other options (perhaps throwing dice to determine direction or exploring other psuedo-random number generators (PRNGs) such as randomGaussian(), noise() (and related functions), etc.)
Here's a p5.js version of the above:
let levelSize = 16;
let numBlocks = levelSize * levelSize;
let level = new Array(numBlocks);
function setup() {
createCanvas(320, 320);
level.fill(0);
let x = floor(levelSize / 2);
for(let y = 0 ; y < levelSize; y++){
let randomDirection = floor(random(3));
if(randomDirection === 1) x--;
if(randomDirection === 2) x++;
// if randomDirection is 0 ignore as we don't change x -> just go down
// constrain to valid pixel
x = constrain(x, 0, levelSize - 1);
// render dot
level[x + y * levelSize] = 1;
}
// optional: print to console
// prettyPrintLevel(level, levelSize, numBlocks);
}
function draw() {
background(255);
// visualise
for(let i = 0 ; i < numBlocks; i++){
let x = i % levelSize;
let y = floor(i / levelSize);
fill(level[i] == 1 ? color(0) : color(255));
rect(x * 20, y * 20, 20, 20);
}
}
function prettyPrintLevel(level, levelSize, numBlocks){
for(let i = 0; i < numBlocks; i+= levelSize){
print(level.slice(i, i + levelSize));
}
}
function mousePressed(){
setup();
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.1/p5.min.js"></script>
The data is a structured a 1D array in both examples, however, if it makes it easier it could easily be a 2D array. At this stage of development, whatever is the simplest, most readable option is the way to go.

How to make this pattern to expand and shrink back

i have a task to make a pattern of circles and squares as described on photo, and i need to animate it so that all objects smoothly increase to four times the size and then shrink back to their original size and this is repeated. i tried but i cant understand problem
{
size(500,500);
background(#A5A3A3);
noFill();
rectMode(CENTER);
ellipseMode(CENTER);
}
void pattern(int a, int b)
{
boolean isShrinking = false;
for(int x = 0; x <= width; x += a){
for(int y = 0; y <= height; y += a){
stroke(#1B08FF);
ellipse(x,y,a,a);
stroke(#FF0000);
rect(x,y,a,a);
stroke(#0BFF00);
ellipse(x+25,y+25,a/2,a/2);
if (isShrinking){a -= b;}
else {a += b;}
if (a == 50 || a == 200){
isShrinking = !isShrinking ; }
}
}
}
void draw()
{
pattern(50,1);
}
this is what pattern need to look like
Great that you've posted your attempt.
From what you presented I can't understand the problem either. If this is an assignment, perhaps try to get more clarifications ?
If you comment you the isShrinking part of the code indeed you have an drawing similar to image you posted.
animate it so that all objects smoothly increase to four times the size and then shrink back to their original size and this is repeated
Does that simply mean scaling the whole pattern ?
If so, you can make use of the sine function (sin()) and the map() function to achieve that:
sin(), as the reference mentions, returns a value between -1 and 1 when you pass it an angle between 0 and 2 * PI (because in Processing trig. functions use radians not degrees for angles)
You can use frameCount divided by a fractional value to mimic an even increasing angle. (Even if you go around the circle multiple times (angle > 2 * PI), sin() will still return a value between -1 and 1)
map() takes a single value from one number range and maps it to another. (In your case from sin()'s result (-1,1) to the scale range (1,4)
Here's a tweaked version of your code with the above notes:
void setup()
{
size(500, 500, FX2D);
background(#A5A3A3);
noFill();
rectMode(CENTER);
ellipseMode(CENTER);
}
void pattern(int a)
{
for (int x = 0; x <= width; x += a) {
for (int y = 0; y <= height; y += a) {
stroke(#1B08FF);
ellipse(x, y, a, a);
stroke(#FF0000);
rect(x, y, a, a);
stroke(#0BFF00);
ellipse(x+25, y+25, a/2, a/2);
}
}
}
void draw()
{
// clear frame (previous drawings)
background(255);
// use the frame number as if it's an angle
float angleInRadians = frameCount * .01;
// map the sin of the frame based angle to the scale range
float sinAsScale = map(sin(angleInRadians), -1, 1, 1, 4);
// apply the scale
scale(sinAsScale);
// render the pattern (at current scale)
pattern(50);
}
(I've chosen the FX2D renderer because it's smoother in this case.
Additionally I advise in the future formatting the code. It makes it so much easier to read and it barely takes any effort (press Ctrl+T). On the long run you'll read code more than you'll write it, especially on large programs and heaving code that's easy to read will save you plenty of time and potentially headaches.)

Using radians and iterating over array of hex colour values

I have a number of hex values stored in an array. I am using the array index to increase the angle in radian and display a series of ellipses in a circle display a series of ellipses. Difficult to explain but I have a pen. The issue is that when I use a for loop I'm not sure how to use the index to colour the ellipses.
const colors = ['#b1ede8','#db9a78','#eed4ad','#a989b2']
function setup(){
createCanvas(windowWidth,windowHeight)
}
function draw(){
background(255,100,100)
translate(width/2,height/2)
noStroke();
prizes(colors,200)
}
function windowResized(){
resizeCanvas(windowWidth,windowHeight)
}
function prizes(data,radius){
for(i = 0 ; i < TWO_PI ; i+=TWO_PI/data.length)
{
let x = radius * cos(i);
let y = radius * sin(i);
i is now a floating value in radians and the fill code does not work.
fill(colors[i])
ellipse(x,y,20)
}
}
Thanks in advance
const colors = ['#b1ede8','#db9a78','#eed4ad','#a989b2']
function setup(){
createCanvas(windowWidth,windowHeight)
}
function draw(){
background(255,100,100)
translate(width/2,height/2)
noStroke();
prizes(colors,200)
}
function windowResized(){
resizeCanvas(windowWidth,windowHeight)
}
function prizes(data,radius){
var j = 0;
for(i = 0 ; i < TWO_PI ; i+=TWO_PI/data.length)
{
let x = radius * cos(i);
let y = radius * sin(i);
fill(data[j])
ellipse(x,y,20)
j++;
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.16/p5.js"></script>
I think i found the problem. You used i to get the color value. But You don't increment i by 1. So you will get invalide numbers. I made a new variable j to index the color. Is this the result You are looking for?

Hold noLoop() for certain amount of time

I'm attempting to create a very simple "whack-a-mole" type game, designed for students new to p5.js, and Processing in general.
Currently, I've created an array, and a random search within that array that randomly picks a square and makes it brown (a "mole", for now).
How do I make it so that after selecting a square, it stays there for a couple seconds, and then jumps to the next one, using basic p5?
I've managed to implement noLoop(), which can stop the search, but after a certain time I want it to resume.
Here's the code I have so far:
function setup() {
createCanvas(610,610)
}
function draw() {
var grid = []
for (var x = 0; x < 6; x += 1){
grid[x]=0;
for (var y = 0; y < 6; y += 1){
rand=round(random(360))
grid[x][y]=0
if (rand==0){
grid[x]=1
grid[y]=1
noLoop()
}
if (grid[x]==0 || grid[y]==0){
fill(76,153,0)
rect((x*100+10),(y*100+10),90,90)
}
if (grid[x]>0 && grid[y]>0){
fill(102,51,0)
rect((x*100+10),(y*100+10),90,90)
}
}
}
}
Instead of using noLoop(), you could keep looping at 60 frames per second, but then use the millis() function to keep track of the elapsed time.
Here's an example that shows a circle for 1 second whenever the user clicks:
var clickTime;
function mousePressed(){
clickTime = millis();
}
function draw() {
background(0);
if(millis() < clickTime + 1000){
ellipse(width/2, height/2, width/4, height/4);
}
}
Edit: Another approach is to use the % operator along with the frameCount variable in order to do something every X frames. This examples draws a circle in a random position every 60 frames:
function draw() {
if (frameCount % 60 == 0) {
background(0);
ellipse(random(width), random(height), width / 4, height / 4);
}
}

mousePressed in a loop

can anyone tell me how to use a mousePressed in a loop
when I click on each square it changes the color one at a time.
int WIDTH = 200;
int HEIGHT = 200;
int X = WIDTH /3;
int Y = HEIGHT / 4;
void setup()
{
size(200,200);
background(255);
strokeWeight(4);
stroke(2);
}
void draw()
{
for (int n = 0; n < 4; n++) {
for (int g = 0; g < 4; g++) {
if ((n + g + 1) % 2 == 0) {
}
fill(255);
rect(n * X, g * Y, (n + 1) * X, (g + 1) * Y);
}
}
}
void mousePressed() {}
Step 1: Store the state of your squares in some kind of data structure. You might use a 2D array of boolean values for this.
Step 2: Map the data structure to the positions of squares. If you have a 2D array, you might map index [i][j] to an x,y position of i*50, j*50. This is just an example, and the values you use depend on how large you want your squares to be.
Step 3: In the mousePressed() function, go the other way: given the mouseX, mouseY position of the cursor, map that back to an [i][j] index in your 2D array. Set the state of that index (for example, flip the boolean value at that index).
Step 4: In the draw() function, iterate over your 2D array and draw a square (using the same coordinate mapping from step 2) based on the value at that index.

Resources