Processing - Move circle with cursor position - processing

I made a simple drawing program to draw lines and increase/decrase the thickness of the line:
float strokeWeight = 2;
void setup() {
size(640, 360);
noSmooth();
fill(126);
background(255);
strokeWeight(strokeWeight);
}
void draw() {
background(0);
ellipse(mouseX, mouseY, strokeWeight/2, strokeWeight/2);
background(255);
if (mousePressed) {
stroke(0);
line(mouseX, mouseY, pmouseX, pmouseY);
}
if (keyPressed) {
if (key == '+') {
strokeWeight = strokeWeight + 0.5;
}
if (key == '-') {
strokeWeight = strokeWeight - 0.5;
}
if (strokeWeight >= 0.5) {
strokeWeight(strokeWeight);
}
}
}
Now I want to move a circle with my cursor that indicates the current thickness of the line. I tried something like this:
ellipse(mouseX, mouseY, strokeWeight/2, strokeWeight/2)
But this way it draws ellipses over and over again. Is there a way to "erase" the circle made before?

I am not 100% sure that I've understood your question, but you probably want to use PGrahics, on one you keep the lines, on the other you draw the circle.
float strokeWeight = 2;
PGraphics canvas;
PGraphics thickness_circle;
void setup() {
size(640, 360);
canvas = createGraphics(width, height);
thickness_circle = createGraphics(width, height);
thickness_circle.beginDraw();
thickness_circle.noFill();
thickness_circle.strokeWeight(1);
thickness_circle.stroke(255, 0, 0);
thickness_circle.endDraw();
}
void draw() {
background(255);
if (keyPressed) {
if (key == '+') {
strokeWeight += 0.5;
}
if (key == '-') {
strokeWeight -= 0.5;
}
strokeWeight = strokeWeight >= 0.5 ? strokeWeight : 0.5;
}
if (mousePressed) {
canvas.beginDraw();
canvas.strokeWeight(strokeWeight);
canvas.line(mouseX, mouseY, pmouseX, pmouseY);
canvas.endDraw();
}
image(canvas, 0, 0);
thickness_circle.beginDraw();
thickness_circle.clear();
thickness_circle.ellipse(mouseX, mouseY, strokeWeight, strokeWeight);
thickness_circle.endDraw();
image(thickness_circle, 0, 0);
}

Related

How to draw a circle and then when keyPressed, draw another circle etc

I am learning how to code in Processing 4.
I am trying to make a code where when keyPressed() is clicked, one circle is drawn then when the button is pressed again, the first circle remains and then a second circle is drawn but with extent increased by 10, then the key pressed for a final time (3) and the third circle is drawn with the extent increased by 3 then it stops producing more circles.
This is the code I have so far but I am confused on how to approach it. Right now, the first circle just increases in size and it doesn't draw a second one. How do I draw 3 circles, one once keyPressed()?
int sizeIncrease = 10;
int initialSize = 70;
void setup() {
size(500, 500);
}
void draw() {
background(0);
stroke(255,0,0);
strokeWeight(25);
fill(255);
pushMatrix();
translate(20, 50);
circle(width/2, height/2, initialSize);
popMatrix();
}
void keyPressed() {
initialSize += sizeIncrease;
}
Add a variable count. Increment the variable when a key is pressed and draw the circles in a for-loop:
int sizeIncrease = 10;
int initialSize = 70;
int count = 1;
void setup() {
size(500, 500);
}
void draw() {
background(0);
noFill();
stroke(255);
pushMatrix();
translate(20, 50);
for (int i = 0; i < count; i++) {
circle(width/2, height/2, initialSize + i*sizeIncrease);
}
popMatrix();
}
void keyPressed() {
count ++;
}
int sizeIncrease = 10;
int initialSize = 70;
int count = 1;
void setup() {
size(500, 500);
}
void draw() {
background(0);
noFill();
stroke(255);
pushMatrix();
translate(20, 50);
for (int i = 0; i < count; i++)
{
circle(width/2, height/2, initialSize + i*sizeIncrease);
**if(i == 1)
{
sizeIncrease = 3;
}**
}
popMatrix();
}
void keyPressed() {
count ++;
}

How to use custom shapes in a repeating loop pattern?

I already made a custom shape (myFunction), and I also made patterns using simpler shapes. I want to know how to replace those simple shapes with my custom shape while maintaining the pattern drawn on processing...
You're already calling functions such as noFill(), noStroke(), etc.
It's the same for your function: call it by simply using it's name and () (because it has no arguments): myFunction();
Let's say you want to draw it in pattern 1, you could do something like:
if (pattern==1) {
for (int x=50; x<width; x+=100) {
for (int y=20; y<height; y+=100) {
myFunction();
}
}
}
You will need to pay attention to rendering though.
Running the above will not display anything you call in noFill() in myFunction() and also noStroke() in draw(), right after background(): you won't be able to see a shape with no fill and no stroke :)
One suggestion is to add a stroke:
void myFunction() {
noFill();
stroke(255);
ellipse(300, 300, 200, 400);
ellipse(300, 300, 400, 200);
translate(300, 300);
rotate(radians(130));
ellipse(0, 0, 200, 400);
translate(0, 0);
rotate(radians(0));
ellipse(0, 0, 400, 200);
}
Of course feel free to experiment and make this look nicer.
Here's a modified version of your sketch that uses a few key presses to change the pattern type and shape type at runtime:
int pattern = 1;
// 0 = pluseEllipseCluser, 1 = blobs, 2= myFunction spirograph circles
int shape = 0;
void setup() {
size(600, 600);
println("press 1,2 to change pattern");
println("press p/b/c to change shapes");
}
void draw() {
background(30);
noStroke();
if (pattern==1) {
for (int x=50; x<width; x+=100) {
for (int y=20; y<height; y+=100) {
drawSelectedShapes(x, y);
}
}
}
if (pattern==2) {
float rando = random(10, 90);
for (float x= rando; x >= 0; x-=random(2.5)) {
for (float y= rando; y >= 0; y-=random(2.5)) {
drawSelectedShapes(x, y);
}
}
}
}
void drawSelectedShapes(float x, float y){
if(shape == 0){
plusEllipseCluser(x, y);
}
if(shape == 1){
blobs();
}
if(shape == 2){
myFunction();
}
}
void plusEllipseCluser(float x, float y){
fill(random(255), random(255), random(255), random(255));
ellipse(x, y+30, 50, 20); //plus ellipse cluster
ellipse(x, y+30, 20, 50);
}
void blobs(){
noStroke();
fill(random(250), random(120), random(100));
ellipse(random(width), random(height), 20, 50);
noFill();
stroke(random(255));
ellipse(random(width), random(height), 50, 20);
}
void myFunction() {
noFill();
stroke(255);
ellipse(300, 300, 200, 400);
ellipse(300, 300, 400, 200);
translate(300, 300);
rotate(radians(130));
ellipse(0, 0, 200, 400);
translate(0, 0);
rotate(radians(0));
ellipse(0, 0, 400, 200);
}
void keyPressed(){
if(key == '1') {
pattern = 1;
}
if(key == '2') {
pattern = 2;
}
if(key == 'p'){
shape = 0;
}
if(key == 'b'){
shape = 1;
}
if(key == 'c'){
shape = 2;
}
}
Notice that the example above also calls plusEllipseCluser() passing two arguments: it's a basic example of defining and calling a function that takes two arguments. Of course you've already called functions with arguments before (e.g. random(min,max), ellipse(x,y,w,h), etc.)
Have fun with shapes and patterns.

How can I make this rectangle slow down?

The rectangle is moving and when I click it needs to be moving at 0.1 instead of 3. I don't know how to code the mousePressed part so that it stays at 0.1 the whole time.
float stripeX = 0;
void setup() {
size(500, 300);
}
void draw() {
background(255);
fill(10, 10, 100);
rect(stripeX, 90, 150, 250);
stripeX = stripeX + 3;
stripeX = stripeX % width;
}
void mousePressed() {
stripeX = stripeX - 2.9;
}
You could just use the mousePressed variable along with an if statement inside the draw() function:
float stripeX = 0;
void setup() {
size(500, 300);
}
void draw() {
background(255);
fill(10, 10, 100);
rect(stripeX, 90, 150, 250);
if(mousePressed){
stripeX = stripeX + .1;
}
else{
stripeX = stripeX + 3;
}
stripeX = stripeX % width;
}
The best way in Your case is to use mouseReleased() method:
float stripeX, deltaX;
void setup() {
size(500, 300);
stripeX = 0f; // init values here, in setup()
deltaX = 3f;
}
void draw() {
background(255);
fill(10, 10, 100);
rect(stripeX, 90, 150, 250);
stripeX += deltaX;
stripeX = stripeX % width;
}
void mousePressed(){
deltaX = 0.1;
}
void mouseReleased(){
deltaX = 3f;
}
This is all a bit dicey. How often is draw() called? On every frame? Generally it's a bad idea to adjust things in a draw function, it should just draw.
To hack it somewhat
float stripeX = 0;
float deltaX = 3.0;
void draw()
{
//omitted some code
stripeX += deltaX;
}
void mousePressed()
{
if(deltaX > 0.1)
deltaX = 0.1;
else
deltaX = 3.0; // let a second press put it back to 3.0
}
However you probably want to put it back to 3.0 on mouse up. You haven't
given enough information to know how to intercept that event.

Making particles move around the object smoother

i was able to make particles go around the ellipse I created which was my previous question. Now I have another one, flow of the particles are not as smooth as i want, there is this diagonal looking shape they follow and when you move the mouse (the ellipse) you can see my lines of my "force" variable. Again I want particles to move like water floating around a rock in a river.
Link for the previous question I asked about same project
int NUM_PARTICLES = 9000;
ParticleSystem p;
Rock r;
void setup()
{
smooth();
size(700,700,P2D);
p = new ParticleSystem();
r = new Rock();
}
void draw()
{
background(0);
p.update();
p.render();
r.rock();
}
float speed = 2;
float rad = 100;
class Particle
{
PVector position, velocity;
float initialPosY;
Particle()
{
position = new PVector(random(width), random(height));
initialPosY = position.y;
velocity = new PVector();
}
void update()
{
velocity.x = speed;
velocity.y = 0;
float d = dist (position.x, position.y, mouseX, mouseY);
if (d < rad) {
float force = map(d, 0, rad, speed, 0);
if (position.x < mouseX) {
if (position.y < mouseY) {
velocity.y = -force;
} else {
velocity.y = force;
}
} else {
if (position.y < mouseY) {
velocity.y = force;
} else {
velocity.y = -force;
}
}
position.add(velocity);
} else {
position = new PVector(position.x+speed, initialPosY);
}
if (position.x<0)position.x+=width;
if (position.x>width)position.x-=width;
if (position.y<0)position.y+=height;
if (position.y>height)position.y-=height;
}
void render()
{
stroke(255, 255, 255, 80);
point(position.x, position.y);
}
}
class ParticleSystem
{
Particle[] particles;
ParticleSystem()
{
particles = new Particle[NUM_PARTICLES];
for (int i = 0; i < NUM_PARTICLES; i++)
{
particles[i]= new Particle();
}
}
void update()
{
for (int i = 0; i < NUM_PARTICLES; i++)
{
particles[i].update();
}
}
void render()
{
for (int i = 0; i < NUM_PARTICLES; i++)
{
particles[i].render();
}
}
}
class Rock{
void rock()
{
noFill();
stroke(255);
strokeWeight(4);
ellipse(mouseX,mouseY,50,50);
}
}
It'll be a lot easier if you try to narrow your problem down to a smaller MCVE, like I did in the answer to your first question:
PVector position;
PVector speed;
void setup() {
size(500, 500);
position = new PVector(250, 0);
speed = new PVector(0, 1);
}
void draw() {
background(0);
if (dist(position.x, position.y, mouseX, mouseY) < 100) {
fill(255, 0, 0);
if (position.x < mouseX) {
position.x--;
} else {
position.x++;
}
} else {
fill(0, 255, 0);
}
ellipse(mouseX, mouseY, 100, 100);
fill(0, 0, 255);
ellipse(position.x, position.y, 20, 20);
position.add(speed);
if (position.y > height) {
position.y = 0;
}
if (position.x < 0) {
position.x = width;
} else if (position.x > width) {
position.x = 0;
}
}
Now that we have that, we can talk about how we might improve it.
Right now, our logic for having the particles avoid our obstacle is here:
if (dist(position.x, position.y, mouseX, mouseY) < 100) {
if (position.x < mouseX) {
position.x--;
} else {
position.x++;
}
}
Notice that we're always moving the particle by 1 pixel, which is why it looks blocky. What we need to do is smooth our transition out by moving the pixel only a little bit at first, and then moving it more as it gets closer to the obstacle.
You might user the lerp() or map() function for this, but for this simple example, we can simply use the dist() function.
Here is a super simple approach you might take:
float distance = dist(position.x, position.y, mouseX, mouseY);
if (position.x < mouseX) {
position.x -= 1000/(distance*distance);
} else {
position.x += 1000/(distance*distance);
}
Notice that by squaring the distance, I'm setting up a polynomical interpolation. In other words, the particle moves faster the closer it gets to the center of the boundary.
Again, you're going to have to play with this to get the exact effect you're looking for, but the basic idea is there: what you're looking for is an interpolation (how fast the particle moves) that scales with the distance from the boundary. You can use squaring to exaggerate the effect.
You could also use basic trig to make the particle follow a circular path.

Stop background from refreshing?

I am trying to get my gif to do something similar to this gif.
I have been able to get the line to draw, and the 'planets' to orbit, but can't figure out how to keep the line connecting the two circles, like the gif does.
Here's the basic code:
int x = 500;
int y = 500;
int radius = y/2;
int cX = x/2;
int cY = y/2;
String text1;
int lg_xBall;
int lg_yBall;
int sm_xBall;
int sm_yBall;
void setup() {
size(x, y);
smooth();
colorMode(RGB);
}
void draw() {
background(0);
stroke(255);
float t = millis()/1000.0f;
drawSmBallOrbit(100);
drawLgBallOrbit(100);
moveSmBall(t);
moveLgBall(t);
sun();
// showMouse();
connectingLines();
}
void drawCircle() { // This will draw a simple circle
stroke(1);
// x1=a+r*cos t, y1=b+r*sin t
ellipse(x/2, y/2, x/2, y/2);
}
void drawLines() { // This will draw lines from the center of the circle.
stroke(1);
line(x/2, y/2, radius/2, radius); // line from 6 to center
line(x/2, y/2, x/2, y/4); // line from 12 to center
for (int i = 0; i <= 5; i+=2.5) {
float x1 = x/2+radius/2*cos(i);
float y1 = y/2+radius/2*sin(i);
line(x/2, y/2, x1, y1);
}
}
void moveSmBall(float ky) { // This will create, and move, a small 'planet'
pushStyle();
stroke(100);
sm_xBall = (int)(cX+radius*cos(ky));
sm_yBall = (int)(cY+radius*sin(ky));
fill(190, 0, 0);
// background(0);
ellipse(sm_xBall, sm_yBall, 10, 10);
popStyle();
}
void drawSmBallOrbit(float opacity) {
pushStyle();
stroke(255, opacity);
strokeWeight(1);
noFill();
ellipse(x/2, y/2, cX+radius, cY+radius);
popStyle();
}
void moveLgBall(float kx) {
kx = kx/.7;
pushStyle();
lg_xBall = (int)(cX+radius*cos(kx)*.6);
lg_yBall = (int)(cY+radius*sin(kx)*.6);
fill(0, 0, 230);
ellipse(lg_xBall, lg_yBall, 30, 30);
popStyle();
}
void drawLgBallOrbit(float opacity) {
pushStyle();
stroke(255, opacity);
strokeWeight(1);
noFill();
ellipse(x/2, y/2, (cX+radius)*.6, (cY+radius)*.6);
popStyle();
}
void sun() {
pushStyle();
fill(250, 250, 0);
ellipse(cX, cY, 40, 40);
popStyle();
}
void connectingLines() {
line(sm_xBall, sm_yBall, lg_xBall, lg_yBall);
}
void showMouse() {
text("X: " + mouseX, x/2, y/2-30);
text("Y: " + mouseY, x/2, y/2-50);
}
Thanks for any help/advice!
The problem is that you're calling background() during every frame, which will clear away anything you've already drawn.
So you either need to stop calling background(), or you need to redraw the old lines every frame.
If you simply move the call to background() out of your draw() function and into your setup() function, you're about 50% there already:
void setup() {
size(x, y);
smooth();
colorMode(RGB);
background(0);
}
void draw() {
// background(0);
stroke(255);
float t = millis()/1000.0f;
drawSmBallOrbit(100);
drawLgBallOrbit(100);
moveSmBall(t);
moveLgBall(t);
sun();
// showMouse();
connectingLines();
}
However, the original animation does not show the previous positions of the ellipses. So you need to clear away the previous frame by calling the background() function, and then redraw previous line positions. You'd do that by having an ArrayList that holds those previous positions.
Here's a simple example that uses an ArrayList to redraw anywhere the mouse has been:
ArrayList<PVector> points = new ArrayList<PVector>();
void setup() {
size(500, 500);
}
void draw() {
background(0);
stroke(255);
points.add(new PVector(mouseX, mouseY));
for(PVector p : points){
ellipse(p.x, p.y, 10, 10);
}
}
You would need to do something very similar, but you'd have to keep track of two points at a time instead of one, since you're tracking two ellipses and not just the mouse position.

Resources