How to fix this Solar System model on processing? - processing

I am trying to build a solar system model (only with the Earth, the Sun and the Moon) on Processing (version 3.4), using the Java Mode. I am new to processing and I have only used Java in this context (hence, I am also new to Java).
I have something which is partially working:
That's my code. First tab:
Planet sun;
void setup() {
size(900, 1200);
sun = new Planet(100, 10, 0);
sun.spawnMoons(1,2);
}
void draw() {
background(0);
translate(750, 900/2);
sun.show();
sun.orbit();
}
Second tab:
class Planet {
float radius;
float distance;
Planet[] planets;
float angle;
float orbitspeed;
Planet(float r, float d, float o) {
radius = r;
distance = 400;
angle = PI;
orbitspeed = o;
}
void orbit() {
angle = angle + orbitspeed;
if (planets != null) {
for (int i = 0; i < planets.length; i++) {
planets[i].orbit();
}
}
}
void spawnMoons(int total, int level) {
planets = new Planet[total];
for (int i = 0; i < planets.length; i++) {
float r = radius/(level*2);
float d = distance/(level*4);
float o = 0.01;
planets[i] = new Planet(r, d/(level*8), o);
if (level < 3) {
int num = 2;
planets[i].spawnMoons(num, level+1);
}
}
}
void show() {
pushMatrix();
fill(255, 100);
rotate(angle);
translate(distance, 0);
ellipse(0, 0, radius*2, radius*2);
if (planets != null) {
for (int i = 0; i < planets.length; i++) {
planets[i].show();
}
}
popMatrix();
}
}
However, my "Moon" is too far from my "Earth". I am trying to fix it, but I can't. Considering the way I built it, if I change the value on 11st line (second tab), it won't solve the problem:
distance = 10;
Considering the way I built it, the distance between the Earth and the Sun it is the same as the distance between the Earth and its moon.
I was able to make the radius of each object proportional to each other. Nonetheless, I am failing to do the same with the distance between them. The line bellow was supposed to keep the proportionality on distance but it fails:
float d = distance/(level*4);
How do I fix this?
Thanks.

This is the error:
Planet(float r, float d, float o) {
radius = r;
distance = 400; //<== here
angle = PI;
orbitspeed = o;
}
In the constructor the distance for each new planet is set at 400, so the logic in spawnMoons() does nothing.
If you apply the changes below, it will work as you want and you can start tweaking ;)
//in setup()
sun = new Planet(100, 400, 0);
//in the planet constructor
distance = d;
//in spawnMoons()
float d = distance/level;
planets[i] = new Planet(r, d, o);

Related

Ununderstandable Processing behavior [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I just can't understand this trivial script's behavior in Processing.
For a ParticleSystem of size 1, it works. As soon as the size is over 1, the Particles go crazy. Why?
Sketch to run :
float dt = 1;
ParticleSystem ps;
void setup(){
size(700,700);
// PARTICLE SYSTEM
PVector origin = new PVector(width/2, height/2);
ps = new ParticleSystem(12, origin); // Change the number here to see the weird behavior !
}
void draw(){
background(255);
// PARTICLE SYSTEM
ps.run();
}
Particle Class :
class Particle {
private PVector pos;
private PVector prevPos;
private PVector vel;
private PVector force;
private float m = 10;
private float r = 60;
private boolean dead = false;
Particle(PVector pos, PVector vel) {
this.prevPos = pos;
this.vel = vel;
this.force = new PVector(0, 0);
this.pos = new PVector();
this.pos.x = pos.x + vel.x * dt + 0.5 * force.x / m * sq(dt);
this.pos.y = pos.y + vel.y * dt + 0.5 * force.y / m * sq(dt);
}
void display() {
color c = color(0);
fill(c);
ellipse(this.pos.x, this.pos.y, this.r * 2, this.r * 2);
}
void run() {
this.update();
this.display();
}
void update() {
this.moveVerlet();
}
void moveVerlet() {
PVector tempPos = new PVector(this.pos.x, this.pos.y);
this.pos.x = this.pos.x * 2 - this.prevPos.x + sq(dt) * this.force.x / this.m;
this.pos.y = this.pos.y * 2 - this.prevPos.y + sq(dt) * this.force.y / this.m;
this.prevPos.set(tempPos);
}
}
Particle System Class :
class ParticleSystem {
private ArrayList<Particle> particles;
private PVector origin;
ParticleSystem(int nb, PVector origin) {
this.origin = origin;
this.particles = new ArrayList<Particle>(nb);
for (int i = 0 ; i < nb ; i++) {
float k = 0.5;
float vx = random(-k, k);
float vy = random(-k, k);
this.particles.add(new Particle(origin, new PVector(vx, vy)));
}
}
void checkBoundaries() {
for (int i = this.particles.size() - 1 ; i >= 0 ; i--) {
if (this.particles.get(i).pos.x - this.particles.get(i).r <= 0
|| this.particles.get(i).pos.x + this.particles.get(i).r >= width) {
this.particles.get(i).prevPos.x = this.particles.get(i).pos.x + this.particles.get(i).pos.x
- this.particles.get(i).prevPos.x;
}
else if (this.particles.get(i).pos.y - this.particles.get(i).r <= 0
|| this.particles.get(i).pos.y + this.particles.get(i).r >= height) {
this.particles.get(i).prevPos.y = this.particles.get(i).pos.y + this.particles.get(i).pos.y
- this.particles.get(i).prevPos.y;
}
}
}
void run() {
checkBoundaries();
for (Particle p : this.particles) {
p.run();
}
}
}
Notice that you pass the origin into the ParticleSystem constructor. You then pass that into the Particle constructor, and the Particle class stores that in the prevPos variable, which it uses for updating the position of each Particle.
So you've got multiple instances of Particle sharing the same prevPos variable. Uh oh!
The problem is that the Particle class also modifies that prevPos variable. So now you've got multiple instances of Particle all modifying that same prevPos variable, which you then use to update the position, and you start accumulating errors.
The solution is to just copy the origin PVector before passing it into each Particle constructor. Luckily PVector has a copy() function that does exactly that:
this.particles.add(new Particle(origin.copy(), new PVector(vx, vy)));
More info can be found in the reference.

How to return value from a class, derived from an array in Processing

I'm new to Processing. I want to learn how to graph some modelling I am doing so I'm using gwoptics to do it. They have an example called RollingGraph. This basically plots out whatever you want along a time dependent scrolling x axis.
The problem is that I don't quite understand how I get it to plot what I want.
I have an array, let's say which plots ellipses randomly on a canvas and these rotate randomly every frame. How can I get the Rolling Graph to plot the sum of all the rotations, which could be circle.rot?
So far I have the best MCVE I could get:
import org.gwoptics.graphics.graph2D.Graph2D;
import org.gwoptics.graphics.graph2D.traces.ILine2DEquation;
import org.gwoptics.graphics.graph2D.traces.RollingLine2DTrace;
class eq implements ILine2DEquation{
public double computePoint(double x,int pos) {
return mouseX; //////HOW DO I GET THIS TO RETURN THE SUM OF circle.rot??????
}
}
class eq2 implements ILine2DEquation{
public double computePoint(double x,int pos) {
return mouseY;
}
}
class eq3 implements ILine2DEquation{
public double computePoint(double x,int pos) {
if(mousePressed)
return 400;
else
return 0;
}
}
RollingLine2DTrace roll,roll2,roll3;
Graph2D g;
class Circle{
public float x1;
public float y1;
public float x2;
public float y2;
public color cB;
public float rot;
public float authority;
public float fert = 1;
public float r = x1; //radius
public Circle(float x1, float y1, float x2, float y2, color tempcB, float rot, float authority, float fert){
this.x1 = x1;
this.y1 = y1;
this.x2 = x2;
this.y2 = y2;
this.cB = tempcB;
this.authority = random(255);
this.fert = random(1);
this.rot= random(360);
}
}
public ArrayList<Circle> circles = new ArrayList<Circle>();
void setup(){
size(1000, 1000);
frameRate(6);
rectMode(CENTER);
ellipseMode(CENTER);
int sec = second();
roll = new RollingLine2DTrace(new eq() ,100,0.01f);
roll.setTraceColour(0, 255, 0);
roll2 = new RollingLine2DTrace(new eq2(),100,0.01f);
roll2.setTraceColour(255, 0, 0);
roll3 = new RollingLine2DTrace(new eq3(),100,0.05f);
roll3.setTraceColour(255, 255, 255);
g = new Graph2D(this, 400, 200, false);
g.setYAxisMax(600);
g.addTrace(roll);
g.addTrace(roll2);
g.addTrace(roll3);
g.position.y = 50;
g.position.x = 100;
g.setYAxisTickSpacing(100);
g.setXAxisMax(5f);
smooth();
background(204);
noStroke();
fill(255, 204,100);
for(int i = 1; i < 48; i++){
float r = random(100,height-200);
float s = random(100,width-200);
float t = 20;
float u = 20;
circles.add(new Circle(r,s,t,u,color(100,14,14),random(360),color(100,14,14),random(10)));
}
}
void draw() {
background(204);
g.draw();
for(Circle circle : circles){
pushMatrix();
translate(circle.x1, circle.y1);
rotate(random(360));
translate(-circle.x1, -circle.y1);
fill(circle.authority);
strokeWeight(0);
stroke(100,0,0);
rect(circle.x1, circle.y1, 24, 36,0, 0, 12, 18);
popMatrix();
}
}
If I understand your question, all you have to do is iterate over the instances and calculate the total.
First, you're going to need a data structure that holds all of your instances. You've said you're using an array, so it sounds like you've go that covered. You have to make sure that this array is in scope for the next step, so this probably means declaring it at the sketch level (not inside a function or class).
Secondly, you're going to need a for loop that iterates over the instances in the data structure. You can use a variable to add up the total. Something like this:
float total = 0;
for(Circle c : yourCircleArray){
total += c.rot;
}
You might put that into a function so that you can call it whenever you want.
Edit: Looking at your code more closely, you actually have an ArrayList, not an array. It looks like it's already initialized at the sketch level, so all you need to do is this:
public double computePoint() {
float total = 0;
for(Circle c : circles){
total += c.rot;
}
return total;
}
If you can't get that working, try creating an MCVE by eliminating your dependencies on whatever library you're importing at the top of your sketch. Remember that an MCVE is supposed to narrow it down to one specific problem (how to get a total from an array), not do your whole end goal.

How to make a sliding member in Processing with particle systems

I am simulating particle system in Processing. Based on Daniel Shiffman’s Nature of Code book, I did a spring and then I started experimenting with sliders to do one that has longer or shorter length based on a slider.
Now, I am trying to make one that slides by the slider, the two particles move to the same direction of the two particles.
I did it with the PVector add, finding the new position and drawing the node, but it doesn’t work when I have multiple members and one is affected by the others.
I need to apply a force to do this: see applyForce() function.
void update(float distance) {
PVector force = PVector.sub(b.location, a.location);
float d = force.mag();
float x = d - distance;
//direction of the force
force.normalize();
force.mult(-1 * k* x/mass);
//apply to one node
b.applyForce(force);
force.mult(-1);
//apply opposite to the other node
a.applyForce(force);
}
//Newton's law: F = M * A
void applyForce(PVector force) {
PVector f = force.get();
f.div(mass);
acceleration.add(f);
}
Check the diagram below:
(a) is what I want to have, (b) is how it's doing it now.
In the first example the length is the same and the members slides (both particles).
In the second the length is bigger and does not slide
Please let me know if you know how to apply a force that slides the member.
Thank you
If I understood correctly, you're trying to do a few things:
change the spring's length
translate the spring's endpoints in the spring's direction
control the above parameters using sliders
The first part is trivial since the Spring object has a len property.
The second involves a bit of vector math:
the direction of a line is the subtraction of it's two end points
a vector can be scaled easily to any length by normalising it first (reducing it so it's length is equal to 1.0) and then multiplying by a scalar value.
A vector can be translated by simply adding another vector to itself
Here is a commented sketch implementing the points above:
//sliders to control spring rest length and translation
Slider rlength = new Slider("rest length", 5, 5, 200, 20, 50, 250, 100, false);
Slider translate = new Slider("translate", 5, 30, 200, 20, -10, 10, 0, false);
Spring spring = new Spring(new Bob(75,350),new Bob(350,75),(int)rlength.value);
void setup(){
size(400,400);
spring.k = 0.01;//tweak elasticity
}
void draw(){
// update
//update sliders
rlength.update(mouseX,mouseY,mousePressed);
translate.update(mouseX,mouseY,mousePressed);
//update spring
spring.a.update();
spring.b.update();
spring.update();
//make both points draggable
spring.a.drag(mouseX, mouseY);
spring.b.drag(mouseX, mouseY);
//draw
background(255);
rlength.draw();
translate.draw();
spring.display();
}
//handle mouse events for spring points dragging
void mousePressed() {
spring.a.clicked(mouseX, mouseY);
spring.b.clicked(mouseX, mouseY);
}
void mouseReleased() {
spring.a.stopDragging();
spring.b.stopDragging();
}
//handle slider events
void onSliderUpdate(Slider s){
if(s == rlength) spring.len = rlength.value;
if(s == translate){
//compute the direction of the spring by subtracting the two points
PVector direction = PVector.sub(spring.a.location,spring.b.location);
//normalize the vector -> it will not have a length/magnitude of 1.0, but will still point in the line direction
direction.normalize();
//scale or multiply the normalized vector to the translation amount
direction.mult(translate.value);
//finally, add the result to each spring point, essentially offsetting/translating
spring.a.location.add(direction);
spring.b.location.add(direction);
}
}
//Slider
class GUIElement{
float w,h,x,y;//width, height and position
color bg = color(200);//background colour
color fg = color(0);//foreground colour
String label;
GUIElement(String label,float x,float y,float w,float h){
this.x = x;
this.y = y;
this.w = w;
this.h = h;
this.label = label;
}
void update(int mx,int my,boolean md){}
void draw(){}
}
class Slider extends GUIElement{
float min,max,value,pvalue;//slider values: minimum, maximum and current
float cx,pw = 20;//current slider picker position, picker width
boolean updating,liveDrag = true,isInt = false;
//label to display on slider, it's position(x,y), size(w,h) and values(min, max and default/current)
Slider(String label,float x,float y,float w,float h,float min,float max,float value,boolean isInt){
super(label,x,y,w,h);
this.min = min;
this.max = max;
this.value = value;
this.isInt = isInt;
cx = map(value,min,max,x,x+w);
}
void update(int mx,int my,boolean md){
if(md){
if((mx >= x && mx <= (x+w)) &&
(my >= y && my <= (y+h))){
cx = mx;
value = map(cx,x,x+w,min,max);
updating = true;
if(liveDrag){
boolean updated = (isInt ? ((int)value != (int)pvalue) : (value != pvalue));
if(updated){
pvalue = value;
onSliderUpdate(this);
}
}
}else updating = false;
}else{
if(updating){
updating = false;
onSliderUpdate(this);
}
}
}
void draw(){
pushStyle();
noStroke();
fill(bg);
rect(x,y,w,h);
fill(fg,64);
rect(x,y,cx-x,h);//this displays a rect that stretches based on the value
fill(0);
text(label+": "+(isInt ? (int)value : value),x+pw,y+h*.75);
popStyle();
}
String toString(){
return label + ":" + value;
}
}
// The Nature of Code
// Daniel Shiffman
// http://natureofcode.com
// Bob class, just like our regular Mover (location, velocity, acceleration, mass)
class Bob {
PVector location;
PVector velocity;
PVector acceleration;
float mass = 12;
// Arbitrary damping to simulate friction / drag
float damping = 0.95;
// For mouse interaction
PVector dragOffset;
boolean dragging = false;
// Constructor
Bob(float x, float y) {
location = new PVector(x,y);
velocity = new PVector();
acceleration = new PVector();
dragOffset = new PVector();
}
// Standard Euler integration
void update() {
velocity.add(acceleration);
velocity.mult(damping);
location.add(velocity);
acceleration.mult(0);
}
// Newton's law: F = M * A
void applyForce(PVector force) {
PVector f = force.get();
f.div(mass);
acceleration.add(f);
}
// Draw the bob
void display() {
stroke(0);
strokeWeight(2);
fill(175);
if (dragging) {
fill(50);
}
ellipse(location.x,location.y,mass*2,mass*2);
}
// The methods below are for mouse interaction
// This checks to see if we clicked on the mover
void clicked(int mx, int my) {
float d = dist(mx,my,location.x,location.y);
if (d < mass) {
dragging = true;
dragOffset.x = location.x-mx;
dragOffset.y = location.y-my;
}
}
void stopDragging() {
dragging = false;
}
void drag(int mx, int my) {
if (dragging) {
location.x = mx + dragOffset.x;
location.y = my + dragOffset.y;
}
}
}
// Nature of Code 2011
// Daniel Shiffman
// Chapter 3: Oscillation
// Class to describe an anchor point that can connect to "Bob" objects via a spring
// Thank you: http://www.myphysicslab.com/spring2d.html
class Spring {
// Location
PVector anchor;
// Rest length and spring constant
float len;
float k = 0.2;
Bob a;
Bob b;
// Constructor
Spring(Bob a_, Bob b_, int l) {
a = a_;
b = b_;
len = l;
}
// Calculate spring force
void update() {
// Vector pointing from anchor to bob location
PVector force = PVector.sub(a.location, b.location);
// What is distance
float d = force.mag();
// Stretch is difference between current distance and rest length
float stretch = d - len;
// Calculate force according to Hooke's Law
// F = k * stretch
force.normalize();
force.mult(-1 * k * stretch);
a.applyForce(force);
force.mult(-1);
b.applyForce(force);
}
void display() {
strokeWeight(3);
stroke(0);
line(a.location.x, a.location.y, b.location.x, b.location.y);
ellipse(a.location.x, a.location.y,10,10);
ellipse(b.location.x, b.location.y,10,10);
}
}

Array index out of bounds exception: 100

//----------------------------------------------\\
float x = 300;
float y = 300;
float direction = 0;
float increment = 1;
float speed = 5;
boolean toggle = true; // - For spaceship reversal
float wormX = random(0, 600); // - For wormHole v
float wormY = random(0, 600);
float wormGrowth = 0;
boolean growthSwitch = true; // - for wormHole ^
float[] starXpos = new float[100]; //starsRandom
float[] starYpos = new float[100]; //starsRandom
float d = dist(x, y, wormX, wormY);
int score = 0;
//----------------------------------------------\\
//----------------------------------------------\\ Setup
void setup (){
size (600, 600);
starsP1();
}
//----------------------------------------------\\ Draw
void draw (){
background (0);
spaceShip();
starsP2();
wormHole ();
score();
warpInitial();
blackHoleAt(100, 40);
blackHoleAt(400, 500);
}
//----------------------------------------------\\
//----------------------------------------------\\ starsRandom
void starsP1(){
int i = 0;
while (i < 100){
starXpos[i] = random(0, width);
starYpos[i] = random(0, height);
i = i + 1;
}
}
void starsP2(){
stroke(255);
strokeWeight(5);
int i = 0;
while (i < 100){
point(starXpos[i], starYpos[i]);
i = i + 1;
}
if (key == 'w'){
starYpos[i] = starYpos[i] + 1;
}
}
I'm trying to create a form of parallax for the stars in my code. When the user presses w,a,s,d the array of stars should correspond to the direction. I don't understand how this should work as I keep getting this error.
Try formatting your code to better see what's going on:
void starsP2(){
stroke(255);
strokeWeight(5);
int i = 0;
while (i < 100){
point(starXpos[i], starYpos[i]);
i = i + 1;
}
if (key == 'w'){
starYpos[i] = starYpos[i] + 1;
}
}
Your while loop executes until i == 100. Then after the while loop exits, you use that i variable again. Since i is 100, and your starYpos array only has up to index 99, you get an error.
The fix is to either move that if statement to inside the while loop, or to refactor your code so i doesn't go outside the bounds of the array.

Basic pool game issue

Im trying to create a basic pool game where one ball hits another and causes that second ball to continue in the same direction at the same speed and move the same amount of distance that the first ball moved. I've so far gotten everything to work except having that second ball continue on. Would anyone be able to help me make this work? I think my problem lies in click == 4 section of the code, but I don't understand how to fix it/add on to it.
Ball cue, billiard;
boolean fired = false;
String msg;
int click;
int steps = 20;
int difx, dify;
Boolean move = false;
void setup(){
msg = "";
size(600,300);
click = 0;
cue = new Ball(30, #FFFFFF);
billiard = new Ball(30, #000000);
}
void draw(){
background(#009900);
if(click == 0){
cue.xpos = mouseX;
cue.ypos = mouseY;
billiard.xpos = -15;
billiard.ypos = -15;
msg = "please place the cue ball";
}else if(click == 1){
billiard.xpos = mouseX;
billiard.ypos = mouseY;
msg = "click again to place billiard ball";
}else if(click ==2){
difx = cue.xpos-billiard.xpos;
dify = cue.ypos-billiard.ypos;
}else if(click == 3){
float cdistance = dist(cue.xpos,cue.ypos,billiard.xpos,billiard.ypos);
if(cdistance>billiard.ballDiam/2){
move = true;
cue.xpos-=difx/steps;
cue.ypos-=dify/steps;
msg = "You got it! Push c on your keyboard to restart";
}else{
move = false;
cue.visible = true;
click = 4;
}
}else if(click == 4){
float cdistance = dist(cue.xpos,cue.ypos,billiard.xpos,billiard.ypos);
if(cdistance<billiard.ballDiam){
if (dist(cue.xpos, cue.ypos, billiard.xpos, billiard.ypos) < sqrt(sq(difx)+sq(dify))) {
move = true;
billiard.xpos-=difx/steps;
billiard.ypos-=difx/steps;
}
}
}
cue.update();
billiard.update();
textSize(20);
text(msg,0,height-5);
}
void mouseClicked(){
if(!move){
click++;
}
}
class Ball{
int xpos, ypos;
int ballDiam;
color myColor;
boolean visible = true;
Ball(int tempdiam,color tempColor){
ballDiam=tempdiam;
myColor=tempColor;
}
void update(){
if(visible){
fill(myColor);
ellipse(xpos,ypos,ballDiam,ballDiam);
}
}
}
Your first stop should be the examples that come with Processing, specifically the CircleCollision example inside the Motion section. That example includes all of the logic for bouncing balls off of one another using more-or-less realistic physics.
/**
* Circle Collision with Swapping Velocities
* by Ira Greenberg.
*
* Based on Keith Peter's Solution in
* Foundation Actionscript Animation: Making Things Move!
*/
Ball[] balls = {
new Ball(100, 400, 20),
new Ball(700, 400, 80)
};
void setup() {
size(640, 360);
}
void draw() {
background(51);
for (Ball b : balls) {
b.update();
b.display();
b.checkBoundaryCollision();
}
balls[0].checkCollision(balls[1]);
}
class Ball {
PVector position;
PVector velocity;
float r, m;
Ball(float x, float y, float r_) {
position = new PVector(x, y);
velocity = PVector.random2D();
velocity.mult(3);
r = r_;
m = r*.1;
}
void update() {
position.add(velocity);
}
void checkBoundaryCollision() {
if (position.x > width-r) {
position.x = width-r;
velocity.x *= -1;
}
else if (position.x < r) {
position.x = r;
velocity.x *= -1;
}
else if (position.y > height-r) {
position.y = height-r;
velocity.y *= -1;
}
else if (position.y < r) {
position.y = r;
velocity.y *= -1;
}
}
void checkCollision(Ball other) {
// get distances between the balls components
PVector bVect = PVector.sub(other.position, position);
// calculate magnitude of the vector separating the balls
float bVectMag = bVect.mag();
if (bVectMag < r + other.r) {
// get angle of bVect
float theta = bVect.heading();
// precalculate trig values
float sine = sin(theta);
float cosine = cos(theta);
/* bTemp will hold rotated ball positions. You
just need to worry about bTemp[1] position*/
PVector[] bTemp = {
new PVector(), new PVector()
};
/* this ball's position is relative to the other
so you can use the vector between them (bVect) as the
reference point in the rotation expressions.
bTemp[0].position.x and bTemp[0].position.y will initialize
automatically to 0.0, which is what you want
since b[1] will rotate around b[0] */
bTemp[1].x = cosine * bVect.x + sine * bVect.y;
bTemp[1].y = cosine * bVect.y - sine * bVect.x;
// rotate Temporary velocities
PVector[] vTemp = {
new PVector(), new PVector()
};
vTemp[0].x = cosine * velocity.x + sine * velocity.y;
vTemp[0].y = cosine * velocity.y - sine * velocity.x;
vTemp[1].x = cosine * other.velocity.x + sine * other.velocity.y;
vTemp[1].y = cosine * other.velocity.y - sine * other.velocity.x;
/* Now that velocities are rotated, you can use 1D
conservation of momentum equations to calculate
the final velocity along the x-axis. */
PVector[] vFinal = {
new PVector(), new PVector()
};
// final rotated velocity for b[0]
vFinal[0].x = ((m - other.m) * vTemp[0].x + 2 * other.m * vTemp[1].x) / (m + other.m);
vFinal[0].y = vTemp[0].y;
// final rotated velocity for b[0]
vFinal[1].x = ((other.m - m) * vTemp[1].x + 2 * m * vTemp[0].x) / (m + other.m);
vFinal[1].y = vTemp[1].y;
// hack to avoid clumping
bTemp[0].x += vFinal[0].x;
bTemp[1].x += vFinal[1].x;
/* Rotate ball positions and velocities back
Reverse signs in trig expressions to rotate
in the opposite direction */
// rotate balls
PVector[] bFinal = {
new PVector(), new PVector()
};
bFinal[0].x = cosine * bTemp[0].x - sine * bTemp[0].y;
bFinal[0].y = cosine * bTemp[0].y + sine * bTemp[0].x;
bFinal[1].x = cosine * bTemp[1].x - sine * bTemp[1].y;
bFinal[1].y = cosine * bTemp[1].y + sine * bTemp[1].x;
// update balls to screen position
other.position.x = position.x + bFinal[1].x;
other.position.y = position.y + bFinal[1].y;
position.add(bFinal[0]);
// update velocities
velocity.x = cosine * vFinal[0].x - sine * vFinal[0].y;
velocity.y = cosine * vFinal[0].y + sine * vFinal[0].x;
other.velocity.x = cosine * vFinal[1].x - sine * vFinal[1].y;
other.velocity.y = cosine * vFinal[1].y + sine * vFinal[1].x;
}
}
void display() {
noStroke();
fill(204);
ellipse(position.x, position.y, r*2, r*2);
}
}
Here's your solution (but you have to re-design your program too):
Ball cue, billiard;
boolean fired = false;
String msg;
int click;
int steps = 20;
int difx, dify;
Boolean move = false;
Boolean continueMoving;
void setup() {
msg = "";
size(600, 300);
click = 0;
cue = new Ball(30, #FFFFFF);
billiard = new Ball(30, #000000);
continueMoving = false;
}
void draw() {
background(#009900);
if (click == 0) {
cue.xpos = mouseX;
cue.ypos = mouseY;
billiard.xpos = -15;
billiard.ypos = -15;
msg = "please place the cue ball";
}
else if (click == 1) {
billiard.xpos = mouseX;
billiard.ypos = mouseY;
msg = "click again to place billiard ball";
}
else if (click ==2) {
difx = cue.xpos-billiard.xpos;
dify = cue.ypos-billiard.ypos;
}
else if (click == 3) {
float cdistance = dist(cue.xpos, cue.ypos, billiard.xpos, billiard.ypos);
if (cdistance>billiard.ballDiam/2) {
move = true;
cue.xpos-=difx/steps;
cue.ypos-=dify/steps;
msg = "You got it! Push c on your keyboard to restart";
}
else {
move = false;
cue.visible = true;
click = 4;
}
}
else if (click == 4)
{
float cdistance = dist(cue.xpos, cue.ypos, billiard.xpos, billiard.ypos);
if (cdistance<billiard.ballDiam)
{
if (dist(cue.xpos, cue.ypos, billiard.xpos, billiard.ypos) < sqrt(sq(difx)+sq(dify))) {
move = true;
continueMoving = true;
billiard.xpos-=difx/steps;
billiard.ypos-=dify/steps;
//print(click);
}
}
}
if (continueMoving)
{
billiard.xpos-=difx/steps;
billiard.ypos-=dify/steps;
}
cue.update();
billiard.update();
textSize(20);
text(msg, 0, height-5);
print(click);
}//draw
void mouseClicked() {
if (!move) {
click++;
}
}
class Ball
{
int xpos, ypos;
int ballDiam;
color myColor;
boolean visible = true;
Ball(int tempdiam, color tempColor) {
ballDiam=tempdiam;
myColor=tempColor;
}
void update() {
if (visible) {
fill(myColor);
ellipse(xpos, ypos, ballDiam, ballDiam);
}
}
}//Ball class
First, instead of using if else statements, use switch. Second, don't put all your code in the draw function. You can put your switch statements there, but shift the code within the conditions to some functions outside the draw function. Google for how other people have created snooker/billiards games, and you'll get to know other different types of logic. Mostly, they will be using a for or while loop to keep the game going. And that loop will be the same as your draw function.
If you're new to StackOverflow, you can click the arrow button pointing up on this page to give me a few points for this answer, and click the tick mark to mark this as the accepted answer.

Resources