Moving an objects while others stay static in a click controlled sketch - processing

So I'm trying to build an animation that I can step through with mouse clicks. Adding individual objects click by click is easy. Sequence I want is as follows:
One object(a) drawn initially.
First mouse click adds an object(b).
Second mouse click adds an object(c).
Third mouse click, object(c) should move across the screen and disappear.
I'm having a problem on the last part of the sequence. I can't figure out how to make the object move and still maintain the static part of the sketch. The normal way of doing movement is to change the coordinates of the object with each loop through the draw() function, and use the background to cover up the previous objects. Can't do that in this case because I need object(a) and object(b) to be persistent.
Code below. Thanks for your help!
var count = 0;
function setup() {
createCanvas(200, 200);
a = new Object1(20, 40);
b = new Object1(20, 85);
c = new Object1(20, 130);
}
function draw() {
background(200);
a.display();
if (count == 1) {
b.display();
}
if (count == 2) {
b.display();
c.display();
}
if (count == 3) { //this is where I have a problem
}
if (count > 3) {
count = 0;
}
}
function Object1(ix, iy, itext) {
this.x = ix;
this.y = iy;
this.text = itext;
this.display = function() {
fill(160);
rect(this.x, this.y, 40, 40);
}
}
function mousePressed() {
count++;
}

Generally how you'd do this is by drawing the static part of your scene to an off-screen buffer, which you can create using the createGraphics() function. From the reference:
var pg;
function setup() {
createCanvas(100, 100);
pg = createGraphics(100, 100);
}
function draw() {
background(200);
pg.background(100);
pg.noStroke();
pg.ellipse(pg.width/2, pg.height/2, 50, 50);
image(pg, 50, 50);
image(pg, 0, 0, 50, 50);
}
You'd draw the static part to the buffer, then draw the buffer to the screen, then draw the dynamic stuff on top of it each frame.
This has been discussed before, so I'd recommend doing a search for stuff like "processing pgraphics" and "p5.js buffer" to find a bunch more information.

Related

Not able to copy paste a section of image in P5.js

I have been working on a project in which I have to select an area of image and then use CTRL+C and CTRL+V to copy and paste the selected area. I have tried creating a buffer using createGraphics() but did not work. I have also tried getting pixels one by one and creating image but that is not working either. Can somebody help? Below is my code.
if (this.isCtrlPressed == true && p5.key == 'v') {
let img = p5.createImage(this.dw, this.dh);
p5.draw = () => {
img.loadPixels();
for (let i = 0; i < parseInt(this.sw); i++) {
for (let j = 0; j < parseInt(this.sh); j++) {
img.set(i, j, p5.get(i, j));
}
}
img.updatePixels();
p5.stroke(255);
p5.image(img, 10, 10);
p5.noFill();
p5.rect(p5.mouseX, p5.mouseY, 10, 10);
return;
}
You're not too far off.
Bare in mind that you can also call get() with width, height arguments, not just the first two (x, y): this will make it easy to copy a section of the image.
The p5.Graphics you get using createGraphics() is handy indeed.
Remember to store the selection rectangle properties (x, y, width, height) to copy the image in the first place.
Here's a very rough sketch based on the CreateImage p5.js example:
/*
* #name Create Image
* #description The createImage() function provides a fresh buffer of pixels to
* play with. This example creates an image gradient.
*/
let img; // Declare variable 'img'.
// copy/paste selection rectangle
let selection = {x:0, y:0, w:0, h:0};
// p5.Image from main image using selection
let clipboard;
// where to paste the clipboard p5.Image
let pasteBuffer;
function setup() {
createCanvas(720, 400);
img = createImage(230, 230);
img.loadPixels();
for (let x = 0; x < img.width; x++) {
for (let y = 0; y < img.height; y++) {
let a = map(y, 0, img.height, 255, 0);
img.set(x, y, [0, 153, 204, a]);
}
}
img.updatePixels();
// selection drawing style
noFill();
stroke(255);
// setup buffer to paste into
pasteBuffer = createGraphics(width, height);
}
function draw() {
background(0);
// render original image
image(img, 0, 0);
// render pasted graphics
image(pasteBuffer, 0, 0);
// render selection rectangle
rect(selection.x, selection.y, selection.w, selection.h);
}
function mousePressed(){
// store selection start
selection.x = mouseX;
selection.y = mouseY;
}
function mouseDragged(){
// update selection dimension as the difference between the current mouse coordinates and the previous ones (selection x, y)
selection.w = mouseX - selection.x;
selection.h = mouseY - selection.y;
}
function keyPressed(keyEvent){
if (key == 'c') {
console.log("copy image", selection);
// use get() to "clone" a subsection of the main image
clipboard = img.get(selection.x, selection.y, selection.w, selection.h);
}
if (key == 'v') {
console.log("paste image");
if(clipboard){
// simply render the clipboard image
pasteBuffer.image(clipboard, mouseX, mouseY);
}
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.2/p5.min.js"></script>
Note the above isn't perfect (e.g. you need to use abs() to handle making selections from right to left, not just left to right), but hopefully it illustrates the usage of a selection rectangle, copying pixels and "pasting"/rendering them into a buffer.
Speaking of copying pixels, an alternative option could be using a p5.Image (using createImage() instead of createGraphics()) and copy() (instead of buffer.image()) (and you'd use the selection rectangle properties to know from where to where to paste pixels).

How do I make a object move towards the mouse in p5.js?

I'm making a zombie game in p5js, does anyone have any recommendations on to make a shape or object move towards the mouse(this will be used to make the gun)? and if anyone knows how to make more enemies spawn more often each round that would be nice to!:)
Sorry if the solution is super simple, I still kinda new!
code:
let dogmode;
let round;
let zombie, player;
let x, y;
let health, speed, damage, playerhealth;
function setup() {
dogmode=false;
createCanvas(400,400);
round = 1;
bullet ={
damage:20
};
//Player and zombie parameters
zombie = {
pos: createVector(500, 200),
//increase by 100 each round until round 9
health: 150,
speed: 1,
};
player = {
pos: createVector(200, 200),
//default
health: 100,
};
fill(0);
}
function draw() {
if( dogmode===true){
player.health=player.health+100;
}
background(220);
stroke(0);
line(player.pos.x,player.pos.y,mouseX,mouseY);
fill('gray')
ellipse(mouseX,mouseY,10,10);
push();
//player
fill("green");
ellipse(player.pos.x, player.pos.y, 20, 20);
//HUD or something
fill("black");
text("" + player.health, 10, 10);
//zombie(s)
fill("gray");
rect(zombie.pos.x, zombie.pos.y, 20, 20);
//Damage system
if (p5.Vector.sub(player.pos, zombie.pos).mag() <= 30) {
player.health = player.health - 1;
}
//Health detection
if (player.health <= 0) {
background(0);
textSize(20);
text("You died \n Round " + round, 165, 200);
}
if (keyIsDown(87)) {
player.pos.y -= 2;
}
if (keyIsDown(83)) {
player.pos.y += 2;
}
if (keyIsDown(65)) {
player.pos.x -= 2;
}
if (keyIsDown(68)) {
player.pos.x += 2;
}
zombie.pos.add(p5.Vector.sub(player.pos, zombie.pos).limit(zombie.speed))
pop();
//Create bullet
if(mouseIsPressed ){
fill('yellow')
ellipse(mouseX,mouseY,5,5);
//Shoots bullet
}
}
In order to fire a bullet you need to:
Determine the direction of motion at the time the bullet is fired.
Save that vector so that the direction remains constant for the life of the bullet.
Update the position of the bullet each frame after it is fired.
Determining the direction of motion is simple vector arithmetic if you have two vectors, A and B, and subtract A - B you will get a vector representing the offset from B to A (i.e. pointing in the direction of A from B):
It is important to save this direction vector, because as the player, mouse, and bullet move the result of this computation will continually change; and bullets don't usually change direction once fired.
const BULLET_SPEED = 5;
let player;
let bullet;
function setup() {
createCanvas(windowWidth, windowHeight);
bullet = {
damage: 20,
};
player = {
pos: createVector(width / 2, height / 2),
//default
health: 100,
};
}
function draw() {
background(220);
stroke(0);
// By taking the difference between the vector pointing to the mouse and the
// vector pointing to the player we get a vector from the player to the mouse.
let mouseDir = createVector(mouseX, mouseY).sub(player.pos);
// Limit the length to display an indicator of the bullet direction
mouseDir.setMag(30);
// Because we want to draw a line to the point mouseDir offset away from
// player, we'll need to add mouseDir and player pos. Do so using the static
// function so that we don't modify either one.
let dirOffset = p5.Vector.add(player.pos, mouseDir);
// direction indicator
line(player.pos.x, player.pos.y, dirOffset.x, dirOffset.y);
fill("gray");
ellipse(dirOffset.x, dirOffset.y, 10, 10);
//player
fill("green");
ellipse(player.pos.x, player.pos.y, 20, 20);
if (keyIsDown(87)) {
player.pos.y -= 2;
}
if (keyIsDown(83)) {
player.pos.y += 2;
}
if (keyIsDown(65)) {
player.pos.x -= 2;
}
if (keyIsDown(68)) {
player.pos.x += 2;
}
//Create bullet
if (mouseIsPressed) {
// Notice there can be only one bullet on the screen at a time, but there's
// no reason you couldn't create multiple bullets and add them to an array.
// However, if you did, you might want to create bullets in a mouseClicked()
// function instead of in draw() lets you create too many bullets at a time.
bullet.firing = true;
// Save the direction of the mouse;
bullet.dir = mouseDir;
// Adjust the bullet speed
bullet.dir.setMag(BULLET_SPEED);
// Position the bullet at/near the player
bullet.initialPos = dirOffset;
// Make a copy so that initialPos stays fixed when pos gets updated
bullet.pos = bullet.initialPos.copy();
//Shoots bullet
}
if (bullet.firing) {
fill('yellow');
ellipse(bullet.pos.x, bullet.pos.y, 5, 5);
// move the bullet
bullet.pos.add(bullet.dir);
if (bullet.pos.dist(bullet.initialPos) > 500) {
bullet.firing = false;
}
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>

How do I create a line that recedes as you draw more in p5.js?

Currently working on a site that features some line drawing while hovering. How can I make the line recede naturally as you draw more? Right now I've figured out how to draw a continual line.
var canvas;
var button;
function windowResized() {
console.log('resized');
resizeCanvas(windowWidth, windowHeight);
}
function setup () {
canvas = createCanvas(windowWidth, windowHeight);
canvas.position(0,0);
canvas.style('z-index', '-1')
background(175);
// button = createButton("Start Your Walk");
}
function draw () {
strokeWeight(4);
console.log('button')
line(pmouseX, pmouseY, mouseX, mouseY)
}
You may store the values of your mouse position in an array and then draw the points of the array in order. When the array is updated, if it is full, you will have to erase the last point of the array, move all the points one position backwards and add the new point. The following would be an example code. I recomend you to consult this page for documentation and also the p5 reference.
var mousePositions = [];
function setup() {
createCanvas(400, 400);
}
function draw() {
background(220);
v = createVector(mouseX, mouseY);
mousePositions.push(v);
noFill();
beginShape();
for(var i = 0; i < mousePositions.length; i++){
vertex(mousePositions[i].x, mousePositions[i].y);
}
endShape();
if(mousePositions.length > 25){
mousePositions.shift();
}
}

How do I save a p5.js canvas as a very large PNG?

I know how to save the canvas using p5.js. However I want to save the canvas as a very large png (for example 8000x8000) so that I can use it in Photoshop and scale down the image to the appropriate size. Is there a simple way of doing this besides creating a new canvas behind the scenes that is too large for the browser window?
You could use the createGraphics() function to create an off-screen buffer. Then you can draw it to the screen using the image() function, or you can call its save() function to store it as a file. Here's an example:
let pg;
function setup() {
createCanvas(400, 400);
pg = createGraphics(4000, 4000);
pg.background(32);
}
function draw() {
pg.ellipse(random(pg.width), random(pg.height), 100, 100);
image(pg, 0, 0, width, height);
}
function mousePressed(){
pg.save("pg.png");
}
Draw everything into a pGraphics object.
Normally you draw this "output" just as an image to the canvas.
But if you want to export a high-res version of it, you scale it up first.
let scaleOutput = 1;
let output;
let canvas;
// setup
function setup() {
// other stuff...
output = createGraphics(1000, 640);
canvas = createCanvas(1000, 640);
}
// the draw loop
function draw() {
// Clear Canvas
background(255);
output.clear();
// Set scale
output.push();
output.scale(scaleOutput);
// Draw to your output here...
output.pop();
// Show on canvas
image(output, 0, 0);
}
// Scale up graphics before exporting
function exportHighRes() {
// HighRes Export
scaleOutput = 5;
output = createGraphics(scaleOutput * 1000, scaleOutput * 640);
draw();
save(output, "filename", 'png');
// Reset Default
scaleOutput = 1;
output = createGraphics(1000, 640);
draw();
}
// Export when key is pressed
function keyReleased() {
if (key == 'e' || key == 'E') exportHighRes();
}

Re-sizing screen not the expected size

int displayX, displayY;
final int screenX=200, screenY=200; // display size
void setup() {
background(255);
displayX=displayWidth;
displayY=displayHeight;
size(screenX, screenY);
}
void mouseClicked() {
if (width==screenX) {
frame.setSize(displayX, displayY);
setSize(displayX, displayY);
println(width +" "+height);
} else {
frame.setSize(screenX, screenY);
setSize(screenX, screenY);
println(width +" "+height);
}
}
void draw() {
fill(33, 33, 33);
rect(0, 0, screenX, screenY);
fill(77, 77, 77);
rect(0, 0, screenX-20, screenY-20);
}
full code
press b to start beta - left mouse click change the size
I want a small size on startup (screenX).
After a click it grows to the display size.
After another click it gets the small size again.
But after changing the size the sizes aren't correct.
I see that on the border. I've everywhere a border around my "star". But this is only on top and left correct.
I also tested it with a lineal.
Processing 2.2.1
Windows 7
Step one is to check out the Processing reference.
From the size() documentation:
The size() function can only be used once inside a sketch, and it cannot be used for resizing.
So, you can't use the size() function the way you're trying to use it. Instead, you can access the frame variable directly:
frame.setSize(200, 200);
You might toggle the frame's size like this:
boolean big = false;
void setup(){
size(200, 200);
}
void mouseClicked(){
if(big){
frame.setSize(200, 200); //set the window size
big = false;
}
else{
frame.setSize(400, 400); //set the window size
big = true;
}
}
void draw(){
background(0);
ellipse(mouseX, mouseY, 10, 10);
}
However, if you run that program, you might notice something like this:
The window has increased size, but the actual canvas where things get drawn hasn't. So you get a gray area, and mouse events aren't detected correctly. To fix that problem, you have to set the size of the canvas as well, by calling the setSize() function:
boolean big = false;
void setup(){
size(200, 200);
}
void mouseClicked(){
if(big){
frame.setSize(200, 200); //set the window size
setSize(200, 200); //set the canvas size
big = false;
}
else{
frame.setSize(400, 400); //set the window size
setSize(400, 400); //set the canvas size
big = true;
}
}
void draw(){
background(0);
ellipse(mouseX, mouseY, 10, 10);
}

Resources