diff --git a/C++ProjectTemplate.wasm b/C++ProjectTemplate.wasm index ea78f01..85ce31f 100755 Binary files a/C++ProjectTemplate.wasm and b/C++ProjectTemplate.wasm differ diff --git a/main.cpp b/main.cpp index f6e4f00..46e1314 100644 --- a/main.cpp +++ b/main.cpp @@ -9,9 +9,16 @@ struct Ball{ vf2d pos={}; vf2d vel={}; vf2d acc={}; + vf2d originalPos={}; float radius=0; float mass=0; + float simTimeRemaining=0; +}; +struct Line{ + vf2d startPos={}; + vf2d endPos={}; + float radius=0; }; class MiniGolfPro : public olc::PixelGameEngine @@ -19,8 +26,11 @@ class MiniGolfPro : public olc::PixelGameEngine public: std::vectorballs; + std::vectorlines; Ball*selectedBall; + Line*selectedLine; std::vector>collidingPairs; + std::vectorfakeBalls; MiniGolfPro() { @@ -35,12 +45,26 @@ public: 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: bool OnUserCreate() override { for (int i=0;i<20;i++){ 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; } @@ -83,66 +107,113 @@ public: } Clear(BLACK); - for(Ball&b:balls){ - b.acc.x=-b.vel.x*0.8f; - b.acc.y=-b.vel.y*0.8f; - b.vel.x+=b.acc.x*fElapsedTime; - b.vel.y+=b.acc.y*fElapsedTime; - b.pos.x+=b.vel.x*fElapsedTime; - b.pos.y+=b.vel.y*fElapsedTime; - - if(b.pos.x<0){ - b.pos.x+=ScreenWidth(); - } - if(b.pos.y<0){ - b.pos.y+=ScreenHeight(); - } - if(b.pos.x>=ScreenWidth()){ - b.pos.x-=ScreenWidth(); - } - if(b.pos.y>=ScreenHeight()){ - b.pos.y-=ScreenHeight(); - } - if(fabs(b.vel.x*b.vel.x+b.vel.y*b.vel.y)<0.01){ - b.vel.x=0; - b.vel.y=0; + float stable=0.01f; + int simulationUpdates=4; + int maxSimulationSteps=15; + float simElapsedTime=fElapsedTime/(float)simulationUpdates; + + for(int i=0;i0){ + b.originalPos.x=b.pos.x; + b.originalPos.y=b.pos.y; + b.acc.x=-b.vel.x*0.8f; + b.acc.y=-b.vel.y*0.8f/*+100.f //Gravity constant*/; + b.vel.x+=b.acc.x*b.simTimeRemaining; + b.vel.y+=b.acc.y*b.simTimeRemaining; + b.pos.x+=b.vel.x*b.simTimeRemaining; + b.pos.y+=b.vel.y*b.simTimeRemaining; + + if(b.pos.x<0){ + b.pos.x+=ScreenWidth(); + } + if(b.pos.y<0){ + b.pos.y+=ScreenHeight(); + } + if(b.pos.x>=ScreenWidth()){ + b.pos.x-=ScreenWidth(); + } + if(b.pos.y>=ScreenHeight()){ + b.pos.y-=ScreenHeight(); + } + + if(fabs(b.vel.x*b.vel.x+b.vel.y*b.vel.y)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){ + if(&b!=&b2){ + if(DoCirclesOverlap(b.pos,b.radius,b2.pos,b2.radius)){ + collidingPairs.push_back({&b,&b2}); + float dist=sqrtf((b.pos.x-b2.pos.x)*(b.pos.x-b2.pos.x)+(b.pos.y-b2.pos.y)*(b.pos.y-b2.pos.y)); + float overlap=0.5f*(dist-b.radius-b2.radius); + b.pos.x-=overlap*(b.pos.x-b2.pos.x)/dist; + b.pos.y-=overlap*(b.pos.y-b2.pos.y)/dist; + b2.pos.x+=overlap*(b.pos.x-b2.pos.x)/dist; + b2.pos.y+=overlap*(b.pos.y-b2.pos.y)/dist; + } + } + } + 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&pair:collidingPairs){ + Ball*b1=pair.first; + Ball*b2=pair.second; + float dist=sqrtf((b1->pos.x-b2->pos.x)*(b1->pos.x-b2->pos.x)+(b1->pos.y-b2->pos.y)*(b1->pos.y-b2->pos.y)); + vf2d normal={(b2->pos.x-b1->pos.x)/dist,(b2->pos.y-b1->pos.y)/dist}; + vf2d tangent={-normal.y,normal.x}; + vf2d dpTangent={tangent.dot(b1->vel),tangent.dot(b2->vel)}; + vf2d dpNormal={normal.dot(b1->vel),normal.dot(b2->vel)}; + vf2d momentum={(dpNormal.x*(b1->mass-b2->mass)+2.f*b2->mass*dpNormal.y)/(b1->mass+b2->mass),(dpNormal.y*(b2->mass-b1->mass)+2.f*b1->mass*dpNormal.x)/(b1->mass+b2->mass)}; + b1->vel.x=tangent.x*dpTangent.x+normal.x*momentum.x; + b1->vel.y=tangent.y*dpTangent.x+normal.y*momentum.x; + b2->vel.x=tangent.x*dpTangent.y+normal.x*momentum.y; + b2->vel.y=tangent.y*dpTangent.y+normal.y*momentum.y; } - } - } - for(std::pair&pair:collidingPairs){ - Ball*b1=pair.first; - Ball*b2=pair.second; - float dist=sqrtf((b1->pos.x-b2->pos.x)*(b1->pos.x-b2->pos.x)+(b1->pos.y-b2->pos.y)*(b1->pos.y-b2->pos.y)); - vf2d normal={(b2->pos.x-b1->pos.x)/dist,(b2->pos.y-b1->pos.y)/dist}; - vf2d tangent={-normal.y,normal.x}; - vf2d dpTangent={tangent.dot(b1->vel),tangent.dot(b2->vel)}; - vf2d dpNormal={normal.dot(b1->vel),normal.dot(b2->vel)}; - vf2d momentum={(dpNormal.x*(b1->mass-b2->mass)+2.f*b2->mass*dpNormal.y)/(b1->mass+b2->mass),(dpNormal.y*(b2->mass-b1->mass)+2.f*b1->mass*dpNormal.x)/(b1->mass+b2->mass)}; - b1->vel.x=tangent.x*dpTangent.x+normal.x*momentum.x; - b1->vel.y=tangent.y*dpTangent.x+normal.y*momentum.x; - b2->vel.x=tangent.x*dpTangent.y+normal.x*momentum.y; - b2->vel.y=tangent.y*dpTangent.y+normal.y*momentum.y; + collidingPairs.clear(); + for(Ball*fb:fakeBalls){ + delete fb; + } + fakeBalls.clear(); + } } - collidingPairs.clear(); - for(Ball&b:balls){ if(selectedBall==&b){ FillCircle(b.pos,b.radius,YELLOW); @@ -150,6 +221,15 @@ public: 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; }