ArrayList<PVector> pointss;
PVector fp;
for (Hand hand : leap.getHands()) {
for (Finger finger : hand.getFingers()) {
fp = finger.getPosition();
}
}
In the project I'm working on, I need to replace the mouseX variable with the X variable generated by the leap motion for hand tracking. It tracks the hand with [X, Y, Z] but since I need to save the variable that holds this data as a PVector I am not sure how to get the X variable out of it.
Any help is greatly appreciated.
If you have a PVector instance, you can simply reference its x field.
PVector p = new PVector(100, 200, 300);
println(p.x); //prints 100
More info can be found in the reference.
Related
EDIT I changed my code to the one below but it still clips through the terrain sometimes. It also likes to bounce on corners where it should slide off.
I tried implementing my own collision for a little game I am making. This is the code for my ball class.
class Ball {
//config
float gforce = 1;
float friction = 0.8;
float elasticity = 0.5;
//vars
PVector position;
PVector velocity = new PVector(0, 0);
Ball(PVector p) {position = p;}
void render(){fill(255, 255, 0); noStroke(); circle(position.x, height-position.y, 16);}
PVector bounce(PVector v, PVector n){ //calculate velocity after bounce
PVector u = PVector.mult(n,v.dot(n)/n.dot(n));
PVector w = PVector.sub(v, u);
return PVector.sub(PVector.mult(w, friction), PVector.mult(u, elasticity));
}
Boolean intersect(PVector c, PVector p1, PVector p2, float r){
if (c.dist(p1)<=r || c.dist(p2)<=r){return true;}
float len = p1.dist(p2);
float dot = ( ((c.x-p1.x)*(p2.x-p1.x)) + ((c.y-p1.y)*(p2.y-p1.y)) )/(len*len);
PVector closest = PVector.add(p1, PVector.mult(PVector.sub(p2, p1), dot));
float d1 = closest.dist(p1);
float d2 = closest.dist(p2);
if (d1+d2>=len-0.1 && d1+d2<=len+0.1){if(closest.dist(c)<=r){return true;}}
return false;
}
Boolean intersect(PVector p1, PVector p2, PVector p3, PVector p4){ //if the line p1p2 intersects line p3p4
float uA = ((p4.x-p3.x)*(p1.y-p3.y) - (p4.y-p3.y)*(p1.x-p3.x))/((p4.y-p3.y)*(p2.x-p1.x) - (p4.x-p3.x)*(p2.y-p1.y));
float uB = ((p2.x-p1.x)*(p1.y-p3.y) - (p2.y-p1.y)*(p1.x-p3.x))/((p4.y-p3.y)*(p2.x-p1.x) - (p4.x-p3.x)*(p2.y-p1.y));
if (uA>=0 && uA<=1 && uB>=0 && uB<=1){return true;}else{return false;}
}
void moveBall(){
//if the ball is stationary
if(velocity.mag()==0 || velocity.mag()==1 || velocity.mag()==2){
PVector v = new PVector(min(280, max(-280, mX-mouseX)), min(280, max(-280, mouseY-mY))).div(28);
int n = int(max(abs(v.x), abs(v.y)));
v.normalize().mult(25);
//render arrow
if(mX!=0 && mousePressed){
strokeWeight(5); stroke(#75D5FD); line(mX, mY, mouseX, mouseY);
for (int i=0; i<n+1; i++){
noStroke(); fill(510*(float)i/12, 510*(1-(float)i/12), 0, 55+200*(1-(float)i/12)); circle(mX+(v.x*i), mY-(v.y*i), 15);
}
}
if(mX==0 && mouseP){mX=mouseX; mY=mouseY; mouseP=false;}
if(mX!=0 && mouseR){b.velocity = new PVector(min(280, max(-280, mX-mouseX)), min(280, max(-280, mouseY-mY))).div(8); mX=0; mouseR=false;} //apply velocity
}else {
//if the ball is still, do not allow additional movement
if(mX!=0 && mousePressed){stroke(200); line(mX, mY, mouseX, mouseY);}
if(mX==0 && mouseP){mX=mouseX; mY=mouseY; mouseP=false;}
if(mX!=0 && mouseR){mX=0; mouseR=false;}
}
}
void collision(){
//test collision with terrain
for (int i=1; i<l.points.length; i++){
PVector centerout = PVector.div(velocity, velocity.mag()).mult(8);
strokeWeight(5); stroke(255,0,0); line(position.x, height-position.y, position.x+centerout.x+velocity.x, height-position.y-centerout.y-velocity.y);
if(intersect(position, l.points[i-1], l.points[i], 7) || intersect(position, PVector.add(position,velocity,centerout), l.points[i-1], l.points[i])){
velocity = bounce(velocity, l.normals[i-1]);
}
}
}
void move() {
moveBall();
collision();
position.add(velocity);
if(velocity.y>-10){velocity.y-=gforce;}
if(velocity.mag()<0.5){velocity.x=0; velocity.y=0;}
}
}
There is another object, l (which is the terrain), and it stores the array points[] which contains all the coordinates for the terrain. There is a line connecting each point and the ball detects if its velocity vector intersects that line, or if the ball itself intersects that line.
When i drag and release my mouse, it changes the velocity to whatever vector the mouse was dragged in. It then detects for a collision and it changes the velocity based on its current velocity and the normal of the terrain. However, when it does that, it flies in the opposite direction and flings itself through the floor.
How can I fix my code so that the collision and bouncing works as expected? Additionally it will be nice if the velocity eventually became 0 after bouncing a while.
Oh and usually the y position goes up the further you go down but I changed it so that the y position goes down the further you go down. SO at the very bottom, the y position is 0 instead of the height of the canvas.
Regarding your current problem, I actually have 2 different suggestions I decided to offer only the first one after consideration, as the second one can throw you into recursive madness, but I'm willing to expand on it if needed. I cannot really test them or offer you real code without a working example, though, so I'll stay on pseudocode level.
Solution 1: easy and robust
This one is pretty straightforward: save the pre-bounce vector. When the ball actually bounce, if the rebound has clipping, forget about it and inverse the initial vector. Since the ball came from this exact direction, you can be pretty damn sure that it can go back that way.
The algo would go like this:
if ValidateMove(CurrentVector):
Move(CurrentVector)
else:
NewVector = CalculateNewVector
if ValidateMove(NewVector):
Move(NewVector)
else:
Move(CurrentVector.Invert)
There's a possible problematic edge case, though. If another object is in movement, it may block the ball's inverted path. Honestly, I wouldn't care about the chance that this happens unless your game is specifically prone to this.
Hope this'll help!
Wondering if someone could help me, I am new to processing and programming in general.
I have created a random walker that walks a point around a 3D space. Please see code below.
Now I would like to be able to rotate the view of this walker as it is drawn, so I can view it from different angles. I have tried using PeasyCam to achieve this, but when I use the mouse to rotate the camera, it only affects the location of the new points, and not the previously plotted ones.
If anyone could let me know what I'm doing wrong that would be really helpful! Thanks, here is my code:
import peasy.*;
PeasyCam camera;
void setup() {
size(500,500,P3D);
background(0);
camera = new PeasyCam(this, 0, 0, 0, 50);
}
void draw() {
walker();
}
float x = 0;
float y = 0;
float z = 0;
void walker() {
pushMatrix();
stroke(255);
strokeWeight(5);
point(x,y,z);
x = x + random(-2.5,2.5);
y = y + random(-2.5,2.5);
z = z + random(-2.5,2.5);
popMatrix();
}
If you want your previous points to be affected by the rotation, then you need to redraw them.
You could do this by storing all of the points in a data structure like an array or ArrayList. Then you'd iterate over the points and redraw them every frame.
I want to make a background with changing color on each point of the window depending on the distance of that point from the center of the window in Processing. All I need is a variable to designate x and y coordinates of the screen. How can I do that?
Now, I tried to define such a variable in Processing but failed to do so. But, I've written this code with built-in variables mouseX and mouseY. This is the code I've written:
void setup(){
size(640,360);
frameRate(144);
}
void draw(){
int x=0;
int y=0;
x=x+1;
y=y+1;
float d=dist(width/2,height/2, mouseX,mouseY);
float maxd=dist(width/2,height/2, width,height);
float colour=map(d,0,maxd,0,255);
stroke(50,20,30);
strokeWeight(2);
for(x=0; x<width; x=x+20){
for(y=0; y<height; y=y+20){
rect(x,y,20,20);
fill(colour);
}
}
}
and it works perfectly as I expected. Now, all I need is some variables (like mathematical variables which change the values within some defined range) to specify the coordinates of each point on the screen. Any hint is appreciated.
You're already doing most of what you've described with this nested for loop:
for(x=0; x<width; x=x+20){
for(y=0; y<height; y=y+20){
This nested for loop creates x and y variables that iterate over every point in the frame.
From here, you could use those variables to calculate a color. Here's a simplified example:
for(x=0; x<width; x=x+20){
for(y=0; y<height; y=y+20){
fill(x, y, 0);
rect(x, y, 20, 20);
}
}
This code now uses the x and y variables directly in the calculation of the fill color.
From here, you could add logic that calculates a color based on the distance between 0,0 and x,y. You already have most of that logic as well, but you need to move it to be inside this nested for loop.
Shameless self-promotion: here is a tutorial on for loops, and here are some examples that use for loops, including examples that draw a different color at each point.
I've used an expression to emit particles on the death of a first particle object and it works really well. What I want to do now is use the second set of emitted particles to drive joint rotation, again using expressions.
So, the sum total of what I have now is:
if (volumeAxis_nParticle1_nerveImpulseShape.age >= volumeAxis_nParticle1_nerveImpulseShape.lifespanPP)
//if particle age is >= lifespan
{
vector $pos = volumeAxis_nParticle1_nerveImpulseShape.position;
//determines where the particles are when they die
float $emitNum = 3;
//determines how many particles will be emitted upon particle death ie 3
for ($i = 0; $i < $emitNum; $i ++)
// for variable $i, start at 0 and if $i <emitNum then add 1 to it and execute the following commands, but if $i =3, then quit
{
vector $randVel = <<rand(-0.5,0.5), -1, rand(-0.5,0.5)>>;
//determines the direction of the emitted particles in x, y, z
emit -o emitOnDeath_nParticle1_acetylCholine //emit the second particle object
-position ($pos.x) ($pos.y) ($pos.z) //where first particle object dies
-at velocity //now determine velocity
–vv ($randVel.x) ($randVel.y) ($randVel.z); //vector values (vv) for random velocity x, y or z
};
};
The next set of expressions I have is:
if (emitOnDeath_nParticle1_acetylCholineShape.age < emitOnDeath_nParticle1_acetylCholineShape.lifespanPP)
longMuscleController22.rotateY = 0;
else if (emitOnDeath_nParticle1_acetylCholineShape.age >= emitOnDeath_nParticle1_acetylCholineShape.lifespanPP)
longMuscleController22.rotateY = -0.1;
This second expression does rotate the joint, but for greater control, what I really need is another command to quickly return the joint rotation to 0 again, ie relax quickly after a contraction. At the moment, the rotation only returns to 0 when the first expression starts again. I was thinking maybe another else if line, something to the effect that when the particle count =0 (ie once all the particles have died off when lifespanPP is exceeded), that rotate y = 0 again?
I tried this instead, using particle count:
int $numPar = `particle -ct emitOnDeath_nParticle1_acetylCholineShape`;
if($numPar == 0)
longMuscleController22.rotateY = 0;
else if($numPar > 0)
longMuscleController22.rotateY = -0.1;
Maya says the syntax is correct, but it throws up all sorts of errors once it executes and doesn't move the joint. I'd really appreciate any advice please on how to use the second set of particles to control joint rotation, if you have any?
Thank you in advance for all your help and best wishes,
Maja
This morning I felt like writing a useless program and I ended up with this extremely minimal astronomic simulator in processing. MCVE version of code attached at the end of the post.
Then I added some planets, sit back and got ready to enjoy watching some planets orbiting around each other. However there turned out to be a problem.
The problem is, two originally static planets that getting too close to each other tend to fling each other to super ultra high speed and they will both disappear out of the screen forever. This is obviously against principle of momentum. Planets don't do this. I start to doubt there is something wrong with my Newton's Law implementation. But some other times the planets work just fine, provided that they keep a 'safe' distance.
If you wanna look into this problem, I have carefully included two setups for you. The first one, adds two planets and is beautifully stable. (You can do this by commenting out every line that has 'Three' in it.) You can test the second one by just input the default code. This one is where planets go crazy.
This issue seems like a mystery that origins from some computer science domain I have never explored(I am a noob though). For the sake of my hair, I would greatly appreciate it if someone could explain.
Start of code:
PVector planetOneLocation = new PVector(300, 200);
PVector planetOneSpeed = new PVector(0, -.1);
float planetOneMass = 1;
PVector planetTwoLocation = new PVector(100, 200);
PVector planetTwoSpeed = new PVector(0, .1);
float planetTwoMass = 1;
PVector planetThreeLocation = new PVector(200, 200);
PVector planetThreeSpeed = new PVector(0, 0);
float planetThreeMass = 10;
float g = 5;
void setup() {
size(500, 500);
}
void draw() {
updatePlanetOne();
updatePlanetTwo();
updatePlanetThree();
planetOneLocation.add(planetOneSpeed);
planetTwoLocation.add(planetTwoSpeed);
planetThreeLocation.add(planetThreeSpeed);
background(0);
ellipse(planetOneLocation.x, planetOneLocation.y, 10*planetOneMass, 10*planetOneMass);
ellipse(planetTwoLocation.x, planetTwoLocation.y, 10*planetTwoMass, 10*planetTwoMass);
ellipse(planetThreeLocation.x, planetThreeLocation.y, 10*planetThreeMass, 10*planetThreeMass);
}
void updatePlanetOne() {
PVector accDir = PVector.sub(planetTwoLocation, planetOneLocation);
float a = g * planetTwoMass / (accDir.mag() * accDir.mag());
accDir.normalize();
PVector acceleration = accDir.mult(a);
planetOneSpeed.add(acceleration);
accDir = PVector.sub(planetThreeLocation, planetOneLocation);
a = g * planetThreeMass / (accDir.mag() * accDir.mag());
accDir.normalize();
acceleration = accDir.mult(a);
planetOneSpeed.add(acceleration);
}
void updatePlanetTwo() {
PVector accDir = PVector.sub(planetOneLocation, planetTwoLocation);
float a = g * planetOneMass / (accDir.mag() * accDir.mag());
accDir.normalize();
PVector acceleration = accDir.mult(a);
planetTwoSpeed.add(acceleration);
accDir = PVector.sub(planetThreeLocation, planetTwoLocation);
a = g * planetThreeMass / (accDir.mag() * accDir.mag());
accDir.normalize();
acceleration = accDir.mult(a);
planetTwoSpeed.add(acceleration);
}
void updatePlanetThree() {
PVector accDir = PVector.sub(planetOneLocation, planetThreeLocation);
float a = g * planetOneMass / (accDir.mag() * accDir.mag());
accDir.normalize();
PVector acceleration = accDir.mult(a);
planetThreeSpeed.add(acceleration);
accDir = PVector.sub(planetTwoLocation, planetThreeLocation);
a = g * planetTwoMass / (accDir.mag() * accDir.mag());
accDir.normalize();
acceleration = accDir.mult(a);
planetThreeSpeed.add(acceleration);
}
Update: After some effort I change float variables to double. But my planets are stilling bouncing out of the screen. I think besides the double/float problem, actually there is some issues with the resolution. I didn't define any time step, and that also contribute to inaccurate behaviour especially when speed is high.
Update 2: Setting up time-step helps a lot. Some setups that went crazy without a time-step now works fine. But as long as there is the possibility that the center of two planets will be extremely close, there will be chances that the system go wild again. To solve this, a better integrator is needed.
Updata 3: In respond to #kevin-workman I ported his beautiful code here to replace the original project code. The same third planet in original post is added and the corresponding Newton math is updated. Contradictory to his tests, it looks even if mv.add(p.speed.mult(p.mass)); is commented out, the third planet still go crazy(Now since I have changed the demonstration code to a minimal version, there is no such line anymore). I think the error introduced by mult()do contribute, but concretely the unstable integrator also plays a major role.
This problem has nothing to do with float vs double accuracy. Float has more than enough accuracy for this, and in fact Processing uses float for everything by default, so any double values you try to use will just get lost anyway.
All of your problems are caused by this line:
for (Planet p: planets) {
mv.add(p.speed.mult(p.mass));
}
Particularly this bit:
p.speed.mult(p.mass)
This line multiplies each planet's speed by its mass.
You might be thinking that p.speed.mult(p.mass) will leave the original p.speed PVector unchanged, but this isn't the case. PVector is not immutable, so calling the mult() function changes the underlying PVector instance.
Your first two planets have a mass of 1, so this line doesn't really affect them. But your third planet has a mass of 10, which means you're multiplying its speed by 10 every single frame.
You can test this by simply changing the mass of one of your original planets to 10 or even 2, or by changing the mass of the third planet to 1.
So, to fix your main problem, just get rid of this line, or change it so that it doesn't modify the p.speed PVector.
More info can be found in the Processing reference for PVector#mult():
Multiplies a vector by a scalar. The version of the method that uses a
float acts directly on the vector upon which it is called (as in the
first example above). The versions that receive both a PVector and a
float as arguments are static methods, and each returns a new PVector
that is the result of the multiplication operation.
Basically, you could change that line to this:
PVector.mult(p.speed, p.mass)
That will leave p.speed unchanged and return a copy with the multiplied value.
Taking a step back, you're going to have another issue because your planets can get arbitrarily close to each other. In other words, their distance can approach (or equal) zero. This doesn't happen in real life, and if it does, you can bet things are going to go crazy. So you're going to have crazy "gravity assists" if things get too close. You might consider limiting their distances.
If you have further questions, it'll be easier to help you if you work from this MCVE instead of posting your whole project:
PVector planetOneLocation = new PVector(300, 200);
PVector planetOneSpeed = new PVector(0, -.1);
float planetOneMass = 1;
PVector planetTwoLocation = new PVector(100, 200);
PVector planetTwoSpeed = new PVector(0, .1);
float planetTwoMass = 10;
float g = 5;
void setup() {
size(500, 500);
}
void draw() {
updatePlanetOne();
updatePlanetTwo();
planetOneLocation.add(planetOneSpeed);
planetTwoLocation.add(planetTwoSpeed);
background(0);
ellipse(planetOneLocation.x, planetOneLocation.y, 10*planetOneMass, 10*planetOneMass);
ellipse(planetTwoLocation.x, planetTwoLocation.y, 10*planetTwoMass, 10*planetTwoMass);
}
void updatePlanetOne() {
PVector accDir = PVector.sub(planetTwoLocation, planetOneLocation);
float a = g * planetOneMass / (accDir.mag() * accDir.mag());
accDir.normalize();
PVector acceleration = accDir.mult(a);
planetOneSpeed.add(acceleration);
}
void updatePlanetTwo() {
PVector accDir = PVector.sub(planetOneLocation, planetTwoLocation);
float a = g * planetTwoMass / (accDir.mag() * accDir.mag());
accDir.normalize();
PVector acceleration = accDir.mult(a);
planetTwoSpeed.add(acceleration);
}
The problem is in the integrating part.
The one used is an Euler Integrator and it's not very accurate. Verlet integration is normally used for physics simulation.
Quoting Ilmari Karonen's Answer, verlet can be implemented as:
acceleration = force(time, position) / mass;
time += timestep;
position += timestep * (velocity + timestep * acceleration / 2);
newAcceleration = force(time, position) / mass;
velocity += timestep * (acceleration + newAcceleration) / 2;