how to clear old text on p5js canvas - p5.js

var j=0;
function keyPressed() {
word[j] =key;
j++;
if(keyCode == BACKSPACE){
shorten(word);
shorten(word);
arrayCopy(word, contents);
}
else{
contents=key;
}
}
function draw(){
text(contents, pos_x, pos_y, 300, 300);
pos_x = pos_x + textWidth(contents);
}
when i am using backspace key,i use shorten() to remove the last element of array.how to put this new text on the canvas,without calling clear() and background().

You've already outlined both of your options.
Option 1: Every frame, call the background() function to clear out old frames, and then draw everything again.
Option 2: Draw the stuff you never want to clear to an off-screen buffer using the createGraphics() function. Then every frame, clear out old frames, draw the off-screen buffer to the screen, then draw the "dynamic" content on top of that.
You're going to have to try both approaches and be more specific about exactly what "performance" you're afraid of. But in general, the above two approaches are exactly how you'd deal with this problem.

Related

p5js only drawing what's needed

I'm looking for a way to limit what gets done in the draw loop.
I have a system where when I click, it add's a rect.
This rect then starts spawning circles that move.
since the rect does not change location, it isn't ideal to redraw it in every frame.
Is there a way to put the rects on a different layer of sorts, or is there another mechanism that I can use to limit the rect-drawing without impeding the circle-drawing?
I've tried with createGraphic to make a background with the rects, but I can't make the 'foreground' where the circles reside to be transparant.
Curious about this I tried myself. My idea was simply grabbing the canvas and interacting with it regardless of p5.js.
My result was that the draw... in this case ctx.fillRect did not render on screen.
However the fillStyle was changed.
Canvas is surprisingly efficient as well as WebGL and can handle the performance usually... unless you are rendering hundreds(mobile) to thousands(laptop/desktop) of objects.
I would have liked to have a better outcome but I think it was worthwhile posting what I had tried and my outcome nonetheless.
//P5 Setup
function setup(){
createCanvas(1500, 750);
background('rgba(0, 0, 0, 0.3)');
stroke(255);
fill(255)
doNonP5Drawing();
}
//Render
function draw(){
background(0);
frame();
}
function doNonP5Drawing(){
let canvas = document.querySelector('canvas'),
ctx = canvas.getContext('2d');
ctx.fillStyle="red";
ctx.fillRect(canvas.innerWidth/2 - 100,canvas.innerHeight/2 - 100,200,200);
}

Running background in P5

Im trying to make a side-scroller game and I got stuck on the running background part. I've looked for solutions and I've discovered some , but they were using javascript not the p5 library.
I started from the tutorials found on The Coding Train , and looked over all the examples and references on their site.
Although I could avoid this by using something else, just for the sake of it being here in case someone gets stuck on the same issue, could anyone offer a solution to this in p5? Disclaimer: Im a total noob p5.js.
later edit : By running background i mean moving Background image in a loop from left to right
Honestly, from the discussion we had in the comments, it sounds like you're overthinking it.
The general approach to animation (that tutorial is for Processing, but the principles apply to P5.js as well) is as follows:
Step 1: Create a set of variables that represent the state of your scene.
Step 2: Use those variables to draw your scene every frame.
Step 3: Change those variables over time to make your scene move.
You already know what to do: load an image that contains your background, then draw that image, and move it a little bit each frame.
You've said you want to call the background() function instead of the image() function, which doesn't make a ton of sense. The background() function is not any more efficient than the image() function. In fact, the background() function just calls the image() function for you!
From the P5.js source:
p5.prototype.background = function() {
if (arguments[0] instanceof p5.Image) {
this.image(arguments[0], 0, 0, this.width, this.height);
} else {
this._renderer.background.apply(this._renderer, arguments);
}
return this;
};
P5.js simply checks whether the argument is an image, and if so, calls the image() function for you. So it doesn't really make sense to say that using the image() function is "less efficient" than using the background() function.
Taking a step back, you should really avoid thinking about these kinds of micro-optimizations until you A: understand the problem and B: actually have a problem. Don't make assumptions about "efficiency" until you've actually measured your code for performance.
Anyway, back to your question. You also said that you're loading the image twice, which you shouldn't have to do. You can just load the image once (make sure you do that in the setup() function and not the draw() function, and then draw that image twice:
var img;
function preload() {
img = loadImage("image.jpg");
}
function setup() {
image(img, 0, 0);
image(img, 100, 100);
}
And since you can draw two images, you'd then just draw them next to each other. Here's an example using colored rectangles to show the approach more clearly:
var offsetX = 0;
function setup() {
createCanvas(200, 200);
}
function draw() {
background(0);
fill(0, 255, 0);
rect(offsetX, 0, width, height);
fill(0, 0, 255);
rect(offsetX + width, 0, width, height);
offsetX--;
if(offsetX <= -width){
offsetX = 0;
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.14/p5.js"></script>
There are other ways to do it, like creating an image that contains the wrapping itself. But the general approach is pretty much the same.
If you're still stuck, please try to break your problem down into smaller pieces like I've done here. For example, notice that I created a simple sketch that deals with images, and another simple sketch that deals with moving rectangles. Then if you get stuck, please post a MCVE in a new question post and we'll go from there. Good luck.
Maybe it is a late answer.. but you can make the environment 3D and then move the camera.
Docs: https://p5js.org/reference/#/p5/camera
Example:
function setup() {
createCanvas(windowWidth - 200, windowHeight - 200, WEBGL);
background(175);
frameRate(30);
}
function draw() {
background(175);
//move the camera Xaxis when mouse is moved
let camX = map(mouseX, 0, width, 0,width);
camera(camX, 0, (height/2.0) / tan(PI*30.0 / 180.0), camX, 0, 0, 0, 1, 0);
normalMaterial();
noStroke();
ambientLight(251,45,43);
box(100, 100, 50);
ang += 0.3;
rotateY(ang * 0.03);
}
Keep calm and Happy Coding!

How can I clear the canvas using one click in processing?

I was trying to make a very simple game but I'm having trouble with mouse events. I want to only click once and the whole canvas will be cleared but what happen is it keeps on coming back to its original canvas if I'm not clicking anymore.
if((mouseX >= 100) && (mouseX <= 235) &&
(mouseY >= 490) && (mouseY <= 540) &&
(mousePressed))
{
clear ();
slide1 ();
}
This is the second tab:
void slide1()
{
clear ();
background (30);`enter code here`
slide1 = loadImage ("slide1.jpg");
image (slide1,100,0,400,300);
}
Without seeing a complete, working example, it is difficult to tell for certain. However, it seems likely that you have confused clear() and background(). The easiest way to wipe the screen is by calling background() -- for example at the beginning of every draw() frame.
From the Processing reference:
clear(): "Clears the pixels within a buffer. This function only works on PGraphics objects"
background(): "This function is typically used within draw() to clear the display window at the beginning of each frame, but it can be used inside setup() to set the background on the first frame of animation or if the backgound need only be set once."
e.g. (based on your code):
PImage slide1;
void setup(){
size(512,512);
slide1 = loadImage ("https://processing.org/img/processing3-logo.png");
}
void draw(){
background (30); // clear screen every frame
if(mousePressed) { // show image whenever mouse is down
image (slide1,0,0);
}
}
This always clears the canvas.
Alternately, if you only want to wipe the canvas on a click, don't call background each draw -- instead, call background only on mousePressed. However, in your case (showing an image) it looks like you might also want to wipe again on mouseReleased (so that the image disappears). You may wish to use the built-in mousePressed() and mouseReleased() Processing functions for this and call background in each one.
I don't think this is what you actually want, but: the actual answer to the title question ("How can I clear the canvas using one click in processing?") is:
void draw(){
line(mouseX,mouseY,pmouseX,pmouseY);
}
void mouseClicked(){
background(192);
}

In Processing, how can I save part of the window as an image?

I am using Processing under Fedora 20, and I want to display an image of the extending tracks of objects moving across part of the screen, with each object displayed at its current position at the end of the track. To avoid having to record all the co-ordinates of the tracks, I usesave("image.png"); to save the tracks so far, then draw the objects. In the next frame I use img = loadImage("image.png"); to restore the tracks made so far, without the objects, which would still be in their previous positions.. I extend the tracks to their new positions, then usesave("image.png"); to save the extended tracks, still without the objects, ready for the next loop round. Then I draw the objects in their new positions at the end of their extended tracks. In this way successive loops show the objects advancing, with their previous positions as tracks behind them.
This has worked well in tests where the image is the whole frame, but now I need to put that display in a corner of the whole frame, and leave the rest unchanged. I expect that createImage(...) will be the answer, but I cannot find any details of how to to so.
A similar question asked here has this recommendation: "The PImage class contains a save() function that exports to file. The API should be your first stop for questions like this." Of course I've looked at that API, but I don't think it helps here, unless I have to create the image to save pixel by pixel, in which case I would expect it to slow things down a lot.
So my question is: in Processing can I save and restore just part of the frame as an image, without affecting the rest of the frame?
I have continued to research this. It seems strange to me that I can find oodles of sketch references, tutorials, and examples, that save and load the entire frame, but no easy way of saving and restoring just part of the frame as an image. I could probably do it using Pimage but that appears to require an awful lot of image. in front of everything to be drawn there.
I have got round it with a kludge: I created a mask image (see this Processing reference) the size of the whole frame. The mask is defined as grey areas representing opacity, so that white, zero opacity (0), is transparent and black, fully opaque (255) completely conceals the background image, thus:
{ size (1280,800);
background(0); // whole frame is transparent..
fill(255); // ..and..
rect(680,0,600,600); // ..smaller image area is now opaque
save("[path to sketch]/mask01.jpg");
}
void draw(){}
Then in my main code I use:
PImage img, mimg;
img = loadImage("image4.png"); // The image I want to see ..
// .. including the rest of the frame which would obscure previous work
mimg = loadImage("mask01.jpg"); // create the mask
//apply the mask, allowing previous work to show though
img.mask(mimg);
// display the masked image
image(img, 0, 0);
I will accept this as an answer if no better suggestion is made.
void setup(){
size(640, 480);
background(0);
noStroke();
fill(255);
rect(40, 150, 200, 100);
}
void draw(){
}
void mousePressed(){
PImage img =get(40, 150, 200, 100);
img.save("test.jpg");
}
Old news, but here's an answer: you can use the pixel array and math.
Let's say that this is your viewport:
You can use loadPixels(); to fill the pixels[] array with the current content of the viewport, then fish the pixels you want from this array.
In the given example, here's a way to filter the unwanted pixels:
void exportImage() {
// creating the image to the "desired size"
PImage img = createImage(600, 900, RGB);
loadPixels();
int index = 0;
for(int i=0; i<pixels.length; i++) {
// filtering the unwanted first 200 pixels on every row
// remember that the pixels[] array is 1 dimensional, so some math are unavoidable. For this simple example I use the modulo operator.
if (i % width >= 200) { // "magic numbers" are bad, remember. This is only a simplification.
img.pixels[index] = pixels[i];
index++;
}
}
img.updatePixels();
img.save("test.png");
}
It may be too late to help you, but maybe someone else will need this. Either way, have fun!

Need to draw arrows and circles on canvas without clearing the whole canvas

I'm trying to draw arrows and circles on a canvas, currently the whole canvas is cleared on mousemove and mousedown or whenever the draw function is called, I am not able to draw multiple arrows and circles. Is there any other to accomplish this task?
heres a fiddle: http://jsfiddle.net/V7MRL/
Stack two canvases on top of each over, and draw the temporary arrows/circle on the one on top, and do the final draw on the canvas below.
This way you can clear the top canvas with no issue, and your draws 'accumulate' in the lower canvas.
http://jsfiddle.net/V7MRL/5/ (updated)
I changed your draw function so it takes a 'final' flag that states wether the draw is final.
For a final draw, lower canvas is used, for an temporary draw, upper canvas is cleared then used.
function draw(final) {
var ctx = final ? context : tempContext ;
if (final == false) ctx.clearRect(0, 0, canvas.width, canvas.height);
Edit : for the issue #markE mentionned, i just handled mouseout event to cancel the draw if one is ongoing :
function mouseOut(eve) {
if ( mouseIsDown ) {
mouseIsDown = 0;
cancelTempDraw();
}
}
with :
function cancelTempDraw() {
tempContext.clearRect(0, 0, canvas.width, canvas.height);
}
Rq that your undo logic is not working as of now. I changed it a bit so that in draw, if the draw is final, i save the final canvas prior to drawing the latest figure to quickly have a 1-step undo. i just created a third temp canvas to/from which you copy.
Rq also that you cannot store one canvas for each stroke, or the memory will soon explode. Store the figures + their coordinates in an array if you want a full undo... or just allow 1-step undo for now.
i updated the jsfiddle link.

Resources