Collision detection - LearnOpenGL

文章推薦指數: 80 %
投票人數:10人

Because the ball is a circle-like object, an AABB is probably not the best choice for the ball's collision shape. The collision code thinks the ball is a ... Ifyou'rerunningAdBlock,pleaseconsiderwhitelistingthissiteifyou'dliketosupportLearnOpenGL;andnoworries,Iwon'tbemadifyoudon't:) IntroductionGettingstartedOpenGLCreatingawindowHelloWindowHelloTriangleShadersTexturesTransformationsCoordinateSystemsCameraReviewLightingColorsBasicLightingMaterialsLightingmapsLightcastersMultiplelightsReviewModelLoadingAssimpMeshModelAdvancedOpenGLDepthtestingStenciltestingBlendingFacecullingFramebuffersCubemapsAdvancedDataAdvancedGLSLGeometryShaderInstancingAntiAliasingAdvancedLightingAdvancedLightingGammaCorrectionShadowsShadowMappingPointShadowsNormalMappingParallaxMappingHDRBloomDeferredShadingSSAOPBRTheoryLightingIBLDiffuseirradianceSpecularIBLInPracticeDebuggingTextRendering2DGameBreakoutSettingupRenderingSpritesLevelsCollisionsBallCollisiondetectionCollisionresolutionParticlesPostprocessingPowerupsAudioRendertextFinalthoughtsGuestArticlesHowtopublish2020OITIntroductionWeightedBlendedSkeletalAnimation2021CSMSceneSceneGraphFrustumCullingTessellationHeightmapTessellationDSA2022ComputeShadersIntroductionPhys.BasedBloomCoderepositoryTranslationsAbout BTC 1CLGKgmBSuYJ1nnvDGAepVTKNNDpUjfpRa ETH/ERC20 0x1de59bd9e52521a46309474f8372531533bd7c43 Collisiondetection In-Practice/2D-Game/Collisions/Collision-detection Whentryingtodetermineifacollisionoccursbetweentwoobjects,wegenerallydonotusethevertexdataoftheobjectsthemselvessincetheseobjectsoftenhavecomplicatedshapes;thisinturnmakesthecollisiondetectioncomplicated.Forthisreason,itisacommonpracticetousemoresimpleshapes(thatusuallyhaveanicemathematicaldefinition)forcollisiondetectionthatweoverlayontopoftheoriginalobject.Wethencheckforcollisionsbasedonthesesimpleshapes;thismakesthecodeeasierandsavesalotofperformance.Afewexamplesofsuchcollisionshapesarecircles,spheres,rectangles,andboxes;thesearealotsimplertoworkwithcomparedtoarbitrarymesheswithhundredsoftriangles. Whilethesimpleshapesdogiveuseasierandmoreefficientcollisiondetectionalgorithms,theyshareacommondisadvantageinthattheseshapesusuallydonotfullysurroundtheobject.Theeffectisthatacollisionmaybedetectedthatdidn'treallycollidewiththeactualobject;oneshouldalwayskeepinmindthattheseshapesarejustapproximationsoftherealshapes. AABB-AABBcollisions AABBstandsforaxis-alignedboundingbox,arectangularcollisionshapealignedtothebaseaxesofthescene,whichin2Dalignstothexandyaxis.Beingaxis-alignedmeanstherectangularboxhasnorotationanditsedgesareparalleltothebaseaxesofthescene(e.g.leftandrightedgeareparalleltotheyaxis).Thefactthattheseboxesarealwaysalignedtotheaxesofthescenemakescalculationseasier.HerewesurroundtheballobjectwithanAABB: AlmostalltheobjectsinBreakoutarerectangularbasedobjects,soitmakesperfectsensetouseaxisalignedboundingboxesfordetectingcollisions.Thisisexactlywhatwe'regoingtodo. Axisalignedboundingboxescanbedefinedinseveralways.OneofthemistodefineanAABBbyatop-leftandabottom-rightposition.TheGameObjectclassthatwedefinedalreadycontainsatop-leftposition(itsPositionvector),andwecaneasilycalculateitsbottom-rightpositionbyaddingitssizetothetop-leftpositionvector(Position+Size).Effectively,eachGameObjectcontainsanAABBthatwecanuseforcollisions. Sohowdowecheckforcollisions?Acollisionoccurswhentwocollisionshapesentereachother'sregionse.g.theshapethatdeterminesthefirstobjectisinsomewayinsidetheshapeofthesecondobject.ForAABBsthisisquiteeasytodetermineduetothefactthatthey'realignedtothescene'saxes:wecheckforeachaxisifthetwoobject'edgesonthataxisoverlap.Sowecheckifthehorizontaledgesoverlap,andiftheverticaledgesoverlapofbothobjects.Ifboththehorizontalandverticaledgesoverlapwehaveacollision. Translatingthisconcepttocodeisrelativelystraightforward.Wecheckforoverlaponbothaxesandifso,returnacollision: boolCheckCollision(GameObject&one,GameObject&two)//AABB-AABBcollision { //collisionx-axis? boolcollisionX=one.Position.x+one.Size.x>=two.Position.x&& two.Position.x+two.Size.x>=one.Position.x; //collisiony-axis? boolcollisionY=one.Position.y+one.Size.y>=two.Position.y&& two.Position.y+two.Size.y>=one.Position.y; //collisiononlyifonbothaxes returncollisionX&&collisionY; } Wecheckiftherightsideofthefirstobjectisgreaterthantheleftsideofthesecondobjectandifthesecondobject'srightsideisgreaterthanthefirstobject'sleftside;similarlyfortheverticalaxis.Ifyouhavetroublevisualizingthis,trytodrawtheedges/rectanglesonpaperanddeterminethisforyourself. TokeepthecollisioncodeabitmoreorganizedweaddanextrafunctiontotheGameclass: classGame { public: [...] voidDoCollisions(); }; WithinDoCollisions,wecheckforcollisionsbetweentheballobjectandeachbrickofthelevel.Ifwedetectacollision,wesetthebrick'sDestroyedpropertytotrue,whichinstantlystopsthelevelfromrenderingthisbrick: voidGame::DoCollisions() { for(GameObject&box:this->Levels[this->Level].Bricks) { if(!box.Destroyed) { if(CheckCollision(*Ball,box)) { if(!box.IsSolid) box.Destroyed=true; } } } } Thenwealsoneedtoupdatethegame'sUpdatefunction: voidGame::Update(floatdt) { //updateobjects Ball->Move(dt,this->Width); //checkforcollisions this->DoCollisions(); } Ifwerunthecodenow,theballshoulddetectcollisionswitheachofthebricksandifthebrickisnotsolid,thebrickisdestroyed.Ifyourunthegamenowit'lllooksomethinglikethis: Whilethecollisiondetectiondoeswork,it'snotveryprecisesincetheball'srectangularcollisionshapecollideswithmostofthebrickswithouttheballdirectlytouchingthem.Let'sseeifwecanfigureoutamoreprecisecollisiondetectiontechnique. AABB-Circlecollisiondetection Becausetheballisacircle-likeobject,anAABBisprobablynotthebestchoicefortheball'scollisionshape.Thecollisioncodethinkstheballisarectangularbox,sotheballoftencollideswithabrickeventhoughtheballspriteitselfisn'tyettouchingthebrick. ItmakesmuchmoresensetorepresenttheballwithacirclecollisionshapeinsteadofanAABB.ForthisreasonweincludedaRadiusvariablewithintheballobject.Todefineacirclecollisionshape,allweneedisapositionvectorandaradius. ThisdoesmeanwehavetoupdatethedetectionalgorithmsinceitcurrentlyonlyworksbetweentwoAABBs.Detectingcollisionsbetweenacircleandarectangleisabitmorecomplicated,butthetrickisasfollows:wefindthepointontheAABBthatisclosesttothecircle,andifthedistancefromthecircletothispointislessthanitsradius,wehaveacollision. Thedifficultpartisgettingthisclosestpoint\(\color{red}{\bar{P}}\)ontheAABB.ThefollowingimageshowshowwecancalculatethispointforanyarbitraryAABBandcircle: Wefirstneedtogetthedifferencevectorbetweentheball'scenter\(\color{blue}{\bar{C}}\)andtheAABB'scenter\(\color{green}{\bar{B}}\)toobtain\(\color{purple}{\bar{D}}\).Whatwethenneedtodoisclampthisvector\(\color{purple}{\bar{D}}\)totheAABB'shalf-extents\(\color{orange}{{w}}\)and\(\color{teal}{\bar{h}}\)andadditto\(\color{green}{\bar{B}}\).Thehalf-extentsofarectanglearethedistancesbetweentherectangle'scenteranditsedges:itssizedividedbytwo.ThisreturnsapositionvectorthatisalwayslocatedsomewhereattheedgeoftheAABB(unlessthecircle'scenterisinsidetheAABB). Aclampoperationclampsavaluetoavaluewithinagivenrange.Thisisoftenexpressedas: floatclamp(floatvalue,floatmin,floatmax){ returnstd::max(min,std::min(max,value)); } Forexample,avalueof42.0fisclampedto6.0fwitharangeof3.0fto6.0f,andavalueof4.20fwouldbeclampedto4.20f. Clampinga2Dvectormeansweclampbothitsxanditsycomponentwithinthegivenrange. Thisclampedvector\(\color{red}{\bar{P}}\)isthentheclosestpointfromtheAABBtothecircle.Whatwethenneedtodoiscalculateanewdifferencevector\(\color{purple}{\bar{D'}}\)thatisthedifferencebetweenthecircle'scenter\(\color{blue}{\bar{C}}\)andthevector\(\color{red}{\bar{P}}\). Nowthatwehavethevector\(\color{purple}{\bar{D'}}\),wecancompareitslengthtotheradiusofthecircle.Ifthelengthof\(\color{purple}{\bar{D'}}\)islessthanthecircle'sradius,wehaveacollision. Thisisallexpressedincodeasfollows: boolCheckCollision(BallObject&one,GameObject&two)//AABB-Circlecollision { //getcenterpointcirclefirst glm::vec2center(one.Position+one.Radius); //calculateAABBinfo(center,half-extents) glm::vec2aabb_half_extents(two.Size.x/2.0f,two.Size.y/2.0f); glm::vec2aabb_center( two.Position.x+aabb_half_extents.x, two.Position.y+aabb_half_extents.y ); //getdifferencevectorbetweenbothcenters glm::vec2difference=center-aabb_center; glm::vec2clamped=glm::clamp(difference,-aabb_half_extents,aabb_half_extents); //addclampedvaluetoAABB_centerandwegetthevalueofboxclosesttocircle glm::vec2closest=aabb_center+clamped; //retrievevectorbetweencentercircleandclosestpointAABBandcheckiflength<=radius difference=closest-center; returnglm::length(difference)



請為這篇文章評分?