Split up simulation into time steps

Co-authored-by: sigonasr2 <sigonasr2@gmail.com>
master
parent c2214e1d33
commit f52788aa04
  1. BIN
      C++ProjectTemplate.wasm
  2. 94
      main.cpp

Binary file not shown.

@ -9,9 +9,16 @@ struct Ball{
vf2d pos={}; vf2d pos={};
vf2d vel={}; vf2d vel={};
vf2d acc={}; vf2d acc={};
vf2d originalPos={};
float radius=0; float radius=0;
float mass=0; float mass=0;
float simTimeRemaining=0;
};
struct Line{
vf2d startPos={};
vf2d endPos={};
float radius=0;
}; };
class MiniGolfPro : public olc::PixelGameEngine class MiniGolfPro : public olc::PixelGameEngine
@ -19,8 +26,11 @@ class MiniGolfPro : public olc::PixelGameEngine
public: public:
std::vector<Ball>balls; std::vector<Ball>balls;
std::vector<Line>lines;
Ball*selectedBall; Ball*selectedBall;
Line*selectedLine;
std::vector<std::pair<Ball*,Ball*>>collidingPairs; std::vector<std::pair<Ball*,Ball*>>collidingPairs;
std::vector<Ball*>fakeBalls;
MiniGolfPro() MiniGolfPro()
{ {
@ -35,12 +45,26 @@ public:
balls.emplace_back(b); balls.emplace_back(b);
} }
void AddLine(vf2d pos1,vf2d pos2,float r){
Line l;
l.startPos=pos1;
l.endPos=pos2;
l.radius=r;
lines.push_back(l);
}
public: public:
bool OnUserCreate() override bool OnUserCreate() override
{ {
for (int i=0;i<20;i++){ for (int i=0;i<20;i++){
AddBall({float(rand()%ScreenWidth()),float(rand()%ScreenHeight())},rand()%16+2); AddBall({float(rand()%ScreenWidth()),float(rand()%ScreenHeight())},rand()%16+2);
} }
AddLine({12,4},{64,4},5);
AddLine({76,4},{132,4},5);
AddLine({12,68},{64,68},5);
AddLine({76,68},{132,68},5);
AddLine({4,12},{4,60},5);
AddLine({140,12},{140,60},5);
return true; return true;
} }
@ -83,13 +107,27 @@ public:
} }
Clear(BLACK); Clear(BLACK);
float stable=0.01f;
int simulationUpdates=4;
int maxSimulationSteps=15;
float simElapsedTime=fElapsedTime/(float)simulationUpdates;
for(int i=0;i<simulationUpdates;i++){
for(Ball&b:balls){
b.simTimeRemaining=simElapsedTime;
}
for(int j=0;j<maxSimulationSteps;j++){
for(Ball&b:balls){ for(Ball&b:balls){
if(b.simTimeRemaining>0){
b.originalPos.x=b.pos.x;
b.originalPos.y=b.pos.y;
b.acc.x=-b.vel.x*0.8f; b.acc.x=-b.vel.x*0.8f;
b.acc.y=-b.vel.y*0.8f; b.acc.y=-b.vel.y*0.8f/*+100.f //Gravity constant*/;
b.vel.x+=b.acc.x*fElapsedTime; b.vel.x+=b.acc.x*b.simTimeRemaining;
b.vel.y+=b.acc.y*fElapsedTime; b.vel.y+=b.acc.y*b.simTimeRemaining;
b.pos.x+=b.vel.x*fElapsedTime; b.pos.x+=b.vel.x*b.simTimeRemaining;
b.pos.y+=b.vel.y*fElapsedTime; b.pos.y+=b.vel.y*b.simTimeRemaining;
if(b.pos.x<0){ if(b.pos.x<0){
b.pos.x+=ScreenWidth(); b.pos.x+=ScreenWidth();
@ -104,13 +142,35 @@ public:
b.pos.y-=ScreenHeight(); b.pos.y-=ScreenHeight();
} }
if(fabs(b.vel.x*b.vel.x+b.vel.y*b.vel.y)<0.01){ if(fabs(b.vel.x*b.vel.x+b.vel.y*b.vel.y)<stable){
b.vel.x=0; b.vel.x=0;
b.vel.y=0; b.vel.y=0;
} }
} }
}
for(Ball&b:balls){ for(Ball&b:balls){
float deltaTime=b.simTimeRemaining;
for(Line&l:lines){
vf2d line1={l.endPos.x-l.startPos.x,l.endPos.y-l.startPos.y};
vf2d line2={b.pos.x-l.startPos.x,b.pos.y-l.startPos.y};
float edgeLength=line1.x*line1.x+line1.y*line1.y;
float t=std::max(0.f,std::min(edgeLength,(line1.x*line2.x+line1.y*line2.y)))/edgeLength;
vf2d closestPoint={l.startPos.x+t*line1.x,l.startPos.y+t*line1.x};
float dist=sqrtf((b.pos.x-closestPoint.x)*(b.pos.x-closestPoint.x)+(b.pos.y-closestPoint.y)*(b.pos.y-closestPoint.y));
if(dist<=b.radius+l.radius){
Ball*fakeBall=new Ball();
fakeBall->radius=l.radius;
fakeBall->mass=b.mass*0.8f;
fakeBall->pos=closestPoint;
fakeBall->vel={-b.vel.x,-b.vel.y};
fakeBalls.push_back(fakeBall);
collidingPairs.push_back({&b,fakeBall});
float overlap=1.f*(dist-b.radius-fakeBall->radius);
b.pos.x-=overlap*(b.pos.x-fakeBall->pos.x)/dist;
b.pos.y-=overlap*(b.pos.y-fakeBall->pos.y)/dist;
}
}
for(Ball&b2:balls){ for(Ball&b2:balls){
if(&b!=&b2){ if(&b!=&b2){
if(DoCirclesOverlap(b.pos,b.radius,b2.pos,b2.radius)){ if(DoCirclesOverlap(b.pos,b.radius,b2.pos,b2.radius)){
@ -124,8 +184,13 @@ public:
} }
} }
} }
float intendedSpeed=sqrtf(b.vel.x+b.vel.y*b.vel.y);
float intendedDist=intendedSpeed*b.simTimeRemaining;
float actualDist=sqrtf((b.pos.x-b.originalPos.x)*(b.pos.x-b.originalPos.x)+(b.pos.y-b.originalPos.y)*(b.pos.y-b.originalPos.y));
float actualTime=actualDist/intendedSpeed;
b.simTimeRemaining=b.simTimeRemaining-actualTime;
} }
float efficiency=1;
for(std::pair<Ball*,Ball*>&pair:collidingPairs){ for(std::pair<Ball*,Ball*>&pair:collidingPairs){
Ball*b1=pair.first; Ball*b1=pair.first;
Ball*b2=pair.second; Ball*b2=pair.second;
@ -142,6 +207,12 @@ public:
} }
collidingPairs.clear(); collidingPairs.clear();
for(Ball*fb:fakeBalls){
delete fb;
}
fakeBalls.clear();
}
}
for(Ball&b:balls){ for(Ball&b:balls){
if(selectedBall==&b){ if(selectedBall==&b){
@ -150,6 +221,15 @@ public:
FillCircle(b.pos,b.radius); FillCircle(b.pos,b.radius);
} }
} }
for(Line&l:lines){
FillCircle(l.startPos,l.radius);
FillCircle(l.endPos,l.radius);
vf2d normal={-(l.endPos.y-l.startPos.y),l.endPos.x-l.startPos.x};
float dist=sqrt(normal.x*normal.x+normal.y*normal.y);
normal/=dist;
DrawLine(l.startPos.x+normal.x*l.radius,l.startPos.y+normal.y*l.radius,l.endPos.x+normal.x*l.radius,l.endPos.y+normal.y*l.radius);
DrawLine(l.startPos.x-normal.x*l.radius,l.startPos.y-normal.y*l.radius,l.endPos.x-normal.x*l.radius,l.endPos.y-normal.y*l.radius);
}
return true; return true;
} }

Loading…
Cancel
Save