We are about to switch to a new forum software. Until then we have removed the registration on this forum.
I am working on a project and need to do 2 things.
I have a number of objects that can be dropped from the user via mouse click and the movements of the ball with gravity will create a sort of "art" I have used the gravity mechanism from this tutorial on Processing: https://processing.org/examples/arraylistclass.html
I currently have a ball object that drops from where the mouse is clicked to the ground, bouncing several times with gravity like in real life before disappearing after a while.
The 2things I need to do are:
1) create a colored line/curve that fixed to the center of the ball and basically marks the path of the ball as it bounces up/down/left/right. this line should stay permanently on the screen while the ball disappears
2) have the ball bounce left or right. currently the ball only bounces up and down. I want the ball, after it first hits the ground to continue bouncing up and down while also moving left or right before coming to a stop
Help is appreciated.
Code below:
`ArrayList<Shape> shapes;
void setup() {
size(2000, 1000);
noStroke();
shapes = new ArrayList<Shape>();
background(255);
}
void draw() {
//For objects to disappear after some time
//background(255);
//For a "stream" of shapes
//if (mousePressed) {
// shapes.add(new Ball(mouseX, mouseY, random(5, 40)));
//}
for (int i = shapes.size()-1; i >= 0; i--) {
Shape ball = shapes.get(i);
ball.move();
ball.display();
if (ball.finished()) {
shapes.remove(i);
}
}
}
//For single shapes
void mousePressed() {
shapes.add(new Ball(mouseX, mouseY, random(5, 40)));
}
//----------------------------------------------------------------
//Shape Superclass
class Shape {
float xPos;
float yPos;
float speed;
float gravity;
float size;
float life;
Shape(float xPos, float yPos, float size) {
this.xPos = xPos;
this.yPos = yPos;
this.size = size;
speed = 0;
gravity = 0.6;
life = 255;
}
void move() {
speed = speed + gravity;
yPos = yPos + speed;
if (yPos > height) {
// Dampening
speed = speed * -0.8;
yPos = height;
}
}
boolean finished() {
life--;
if (life < 0) {
return true;
} else {
return false;
}
}
void display() {
fill(255);
}
}
//----------------------------------------------------------------
//Ball Class
class Ball extends Shape {
Ball(float xPos, float yPos, float size) {
super(xPos, yPos, size);
}
void display() {
fill(random(0, 255));
ellipse(xPos, yPos, size, size);
}
}
//----------------------------------------------------------------
// Rectangle Class
class Rectangle extends Shape {
Rectangle(float xPos, float yPos, float size) {
super(xPos, yPos, size);
}
void display() {
fill(random(0, 255));
rect(xPos, yPos, random(size-20, size+20), random(size-10, size+10));
}
}
//----------------------------------------------------------------
// Square Class
class Square extends Shape {
Square(float xPos, float yPos, float size) {
super(xPos, yPos, size);
}
void display() {
fill(random(0, 255));
rect(xPos, yPos, size, size);
}
}
//----------------------------------------------------------------
// Letters Class
class Letters extends Shape {
PFont f;
float angle;
char letter;
Letters(float xPos, float yPos, float size) {
super(xPos, yPos, size);
f = createFont("Arial",size+30,true);
letter = (char) int(random(65, 90));
}
void display() {
fill(random(0, 255));
textFont(f);
//translate(xPos,xPos);
//rotate(angle);
textAlign(CENTER);
text(letter, xPos , yPos);
//angle += 0.05;
}
}`
Answers
Edit post, highlight code, press ctrl-o
Ok, my code is formatted. Sorry it is my first post. Can someone help?
You could either use an ArrayList of fixed points to trace the ball's movement, or use PGraphics (https://processing.org/tutorials/rendering/) . Also, you could have the shapes randomly choose a direction when they hit the ground.
Re: "2) have the ball bounce left or right."
The simplest way is to extend the
.move()
behavior of yourShape
class. If I understand right, you want it to fall straight, but to drift left or right at random on each bounce -- like a rubber high-bounce ball.Add the three lines marked * into your class
Shape
class:Now, as @BleuBox suggested, each time a shape strike the ground (your if statement), it will be assigned a new drift in a random left/right direction.
One simple way to add path-drawing to your Shapes is:
move
is called, write down each new position in the list of pointsNow when you call shape.path() from draw it renders a curved bouncing line.
Here is the new
Shape
class, with path related changes marked //// + :Then call it from draw:
Thanks for all your help! It works great! But is there a way to make the path stay even after the shape disappears?
I guess you could make Path a separate class object and pass in the ball's X and Y to it.
@Archlefirth -- you are correct -- you can make the Path a separate class object.
Another easy approach is to just leave the path in each ball, but never remove balls, just change what you draw.
Only
.move
and.display
balls that aren't.finished
. Show the.path
for all balls, even ones that you aren't displaying because they are finished.Below I reorganized your draw loop, putting move and display inside the conditional and dropping the remove.
This is easier to see working if you uncomment
background(255);
That makes more sense than a separate class.
However, not removing might cause the program to lag since every ball created still exists.
I'll try implementing a seperate class and comparing that to the modified loop
Thanks for your help!
Yes, you should definitely coordinate a separate Path class if you plan to do many different things with those paths. Try it out. Just note that, as things stand, separate paths won't reduce your number of objects.
If you want thousands or millions of paths, then you might want to draw each path then onto a PImage or PGraphics and render it with image(). Then you only have one object (the image layer you are drawing the paths on) and you can remove balls whenever you want without needing the path data for rendering.
How would you add everything to a PGraphic while removing all the balls and adding all the paths?
Think of a PGraphics object as like a separate transparent sheet that you draw on.
https://processing.org/reference/PGraphics.html
See the example. So you create an PGraphics pgPaths object for drawing your paths, and instead of drawing your paths onto the main sketch canvas with line(...) you instead draw your paths onto that object with pgPaths.line(...). In your draw loop, display your pgPaths as an image with
image(pgPaths,0,0);
Depending on whether your paths image is drawn before or after your balls (behind or in front of) you may need to make sure that it is a transparent layer so it doesn't hide the balls completely.
Putting image inside the loop caused the program to become even more slow, I think for the same principle you mentioned earlier about adding more objects.
So I put the image as well as the begin/endDraw() outside the loop and that solved the lag issue.
However, the path color does not match the color of the shape that draws it. I have a color slider (worked perfectly before pgGraphics) that the user can slide over. The color of the path is always the initial value of the slider.
I used pg.push/pop Style in the path drawing method but to no avail
I'm not sure why your sketch has serious performance problems -- there is a lot going on in it, and it is also rendering to a large screen area (twice).
However, the purpose of the PGraphics for paths is to eliminate keeping a large
ArrayList<PVector> path;
list that is being built up in every Shape object, and, more importantly, to simplify the Shape.path draw routine so that you can avoid looping through the entire list for every object every time you draw each shape.So, if you have 10 objects that have been on the screen for 40 path segments each, then draw() will have to draw 400 segments every single time the draw loop runs (e.g. 60 fps). Instead, if you eliminate
ArrayList<PVector> path
and instead only keep your previous positions in each objectfloat xPosLast; float yPosLast;
then you are only drawing 10 segments (one per object) each draw, and you aren't constantly growing arrays. The drawn line segments accumulate as pixel data on the PGraphics surface rather than being constantly recomputed, and they are shown with each image() call at the end of draw.Still, the number one thing that affects performance on my machine regardless of other factors is your sketch size being 2200, 1000. But I can get choppiness for even simple bouncing balls at that size.
You can test this by displaying frameRate, for example adding
println(frameRate);
to the end of your draw loop and watching the console. For example, on my machine at 500,500 I'm able to create as many shapes and paths as I want and the sketch stays at between 58-61 fps. At 2100,1000 I start at around 40fps and the sketch dives to ~5fps as I add shapes.Thanks for the input. Changing the window did really help as did changing button size.
But I still have the problem where path will only use the initial Color Value and not the shape's color.
I tried using push/pop style but to no avail
I fixed everything. All I had to do was change the color mode of the pgGraphics object.
With a smaller window size and pgGraphics, the preformace is much much better now.
Glad to hear it! So it sounds like
pgPaths.colorMode(HSB);
fixed your last problem?