게임엔진 제 15 강충돌처리 이대현교수 한국산업기술대학교게임공학과
학습목차 엔터티본구조의이해 콘솔입출력방법 본의위치좌표의획득 충돌오브젝트를이용한충돌처리기법 OgreOPCODE 를이용한충돌처리실습
본 (Bone) 뼈대애니메이션 (skeletal animation) 의기본구조. 위치와방향정보를가지고있는조인트. 본이여러개모여서 ( 트리구조 ) 하나의뼈대를이루게됨.
실습 ShowBones 닌자본구조의출력
콘솔입출력을위한설정 : cout, cin 을이용한입출력가능
PlayState.cpp bool PlayState::enter(void) { 중략 실습 Bone *bone; Skeleton::BoneIterator bi = ninjaentity->getskeleton()->getboneiterator(); while(bi.hasmoreelements()) { bone = bi.getnext(); std::cout << bone->getname() << ":" << bone->getposition(); if (bone->getparent()) { Bone* pb = static_cast <Bone*>(bone->getParent()); std::cout << "--->" << pb->getname() << std::endl; } else { std::cout << std::endl; } } 후략 }
실행결과
본구조의트리형태 머리 칼끝
본구조의출력 Bone *bone; Skeleton::BoneIterator bi = mninjaentity->getskeleton()->getboneiterator(); while(bi.hasmoreelements()) { bone = bi.getnext(); std::cout << bone->getname() << ":" << bone->getposition(); if (bone->getparent()) { Bone* pb = static_cast <Bone*>(bone->getParent()); std::cout << "--->" << pb->getname() << std::endl; } else { std::cout << std::endl; } }
실습 TipFish 칼끝의물고기
PlayState.cpp bool PlayState::enter(void) { 중략 실습 mfishentity = mscenemgr->createentity("fish#1", "fish.mesh"); mfishnode = mninjanode->createchildscenenode("fishnode"); mfishnode->attachobject(fishentity); mfishnode->scale(4,4,4); mswordtipbone = mninjaentity->getskeleton()->getbone("joint29"); 후략 } bool PlayState::frameStarted(GameManager* game, const FrameEvent& evt) { 중략 Vector3 pos = mswordtipbone->_getderivedposition(); mfishnode->setposition(pos); 후략 }
실행결과
bool PlayState::enter(void) { 중략 mfishentity = mscenemgr->createentity("fish#1", "fish.mesh"); mfishnode = mninjanode->createchildscenenode("fishnode"); mfishnode->attachobject(fishentity); mfishnode->scale(4,4,4); mswordtipbone = mninjaentity->getskeleton()->getbone("joint29"); 후략 } bool PlayState::frameStarted(GameManager* game, const FrameEvent& evt) { 중략 Vector3 pos = mswordtipbone->_getderivedposition(); mfishnode->setposition(pos); 후략 }
충돌오브젝트기반의충돌처리기법 충돌오브젝트 충돌을확인할부분을구, 또는육면체등으로표시한것. 충돌메쉬 (Collision Mesh), 바운딩박스 (bounding box) 충돌처리 충돌오브젝트간의충돌이일어나는지를확인 정확도는떨어지지만, 훨씬빠른시간내에충돌검사를할수있음. 격투대전게임에서가격에사용되는손또는발부분, 가격이가해지는머리, 복부, 배부분만을바운딩박스로적용.
OgreOPCODE OPCODE 공개물리엔진인 ODE 에포함된충돌검사라이브러리 OgreOPCODE OPCODE 라이브러리를 OGRE 용으로 wrapping 한라이브러리
OgreOpcode 설치 설치 OgreOpcodeSDK_vc80.zip 을 OgreSDK 폴더에압축풀기 bin/debug/ogreopcode_d.dll bin/debug/ogreopcode.dll include/ogreopcode/*.* lib/ogreopcode.lib, OgreOpcode_d.lib 프로젝트속성 : C++ 추가포함디렉토리및링커입력추가종속성설정
실습 CollisionTest 닌자의킥공격충돌처리
PlayState.cpp bool PlayState::enter(void) { 중략 실습 mtipnode = mninjanode->createchildscenenode("tipnode"); mheadnode = mninjanode2->createchildscenenode("headnode"); mswordtipbone = mninjaentity->getskeleton()->getbone("joint27"); mheadbone = mninjaentity2->getskeleton()->getbone("joint8"); new CollisionManager(mSceneMgr); CollisionManager::getSingletonPtr()->addCollClass("ninja"); CollisionManager::getSingletonPtr()->addCollType("ninja", "ninja", COLLTYPE_CONTACT); mcollidecontext = CollisionManager::getSingletonPtr()->getDefaultContext();
PlayState.cpp 실습 mtipcollshape = CollisionManager::getSingletonPtr()->createBoxCollisionShape("tip"); mtipcollshape->load(mtipnode, 5.0f, 5.0f, 5.0f); mtipcollobj = mcollidecontext->createobject("tip"); mtipcollobj->setcollclass("ninja"); mtipcollobj->setshape(mtipcollshape); mcollidecontext->addobject(mtipcollobj); mheadcollshape = CollisionManager::getSingletonPtr()->createBoxCollisionShape("head"); mheadcollshape->load(mheadnode, 25.0f, 25.0f, 25.0f); mheadcollobj = mcollidecontext->createobject("head"); mheadcollobj->setcollclass("ninja"); mheadcollobj->setshape(mheadcollshape); mcollidecontext->addobject(mheadcollobj); mcollidecontext->reset(); 후략
PlayState.cpp bool PlayState::frameStarted(GameManager* game, const FrameEvent& evt) { 중략 Vector3 pos = mswordtipbone->_getderivedposition(); mtipnode->setposition(pos); pos = mheadbone->_getderivedposition(); mheadnode->setposition(pos); 실습 CollisionManager::getSingletonPtr()->getDefaultContext()->collide(evt.timeSinceLastFrame); CollisionPair **collisionsreport; int numcollisions = mcollidecontext->getcollisions(mtipcollobj, collisionsreport); static int ccnt = 0; if (numcollisions) { CollisionObject *obj1 = collisionsreport[0]->this_object; CollisionObject *obj2 = collisionsreport[0]->other_object; std::cout << "Collision #" << ++ccnt << " between" << obj1->getname() << " and " << obj2->getname() << std::endl; mninjaentity2->getanimationstate("idle1")->setenabled(false); mninjaentity2->getanimationstate("death1")->settimeposition(0.0f); mninjaentity2->getanimationstate("death1")->setloop(false); mninjaentity2->getanimationstate("death1")->setenabled(true); } 후략
실행결과
OgreOPCODE 설정 // 충돌오브젝트위치를찾기위함. mswordtipbone = ninjaentity->getskeleton()->getbone("joint27"); mheadbone = ninjaentity2->getskeleton()->getbone("joint8"); // 충돌매니저의생성 new CollisionManager(mSceneMgr); // 충돌클래스의설정 CollisionManager::getSingletonPtr()->addCollClass("ninja"); // 충돌체크타입의설정 CollisionManager::getSingletonPtr()->addCollType("ninja", "ninja", COLLTYPE_CONTACT); // 충돌체크컨텍스트설정 충돌체크할오브젝트들의그룹 mcollidecontext = CollisionManager::getSingletonPtr()->getDefaultContext(); COLLTYPE_IGNORE: 충돌체크를하지않음. COLLTYPE_QUICK: 고속 sphere 대 sphere 체크를수행. COLLTYPE_CONTACT: 첫번째충돌체크만 report COLLTYPE_EXACT: 모든 contact을 report
충돌메쉬의생성및등록 // 충돌오브젝트의형태생성 mtipcollshape = CollisionManager::getSingletonPtr()->createBoxCollisionShape("tip"); mtipcollshape->load(mtipnode, 10.0f, 10.0f, 10.0f); // 충돌오브젝트의생성및등록 mtipcollobj = mcollidecontext->createobject("tip"); mtipcollobj->setcollclass("ninja"); mtipcollobj->setshape(mtipcollshape); mcollidecontext->addobject(mtipcollobj); // 상대편닌자의머리위치에충돌오브젝트생성 mheadcollshape = CollisionManager::getSingletonPtr()->createBoxCollisionShape("head"); mheadcollshape->load(mheadnode, 30.0f, 30.0f, 30.0f); mheadcollobj = mcollidecontext->createobject("head"); mheadcollobj->setcollclass("ninja"); mheadcollobj->setshape(mheadcollshape); mcollidecontext->addobject(mheadcollobj); // 충돌컨텍스트초기화 mcollidecontext->reset();
// 충돌오브젝트의위치계산 Vector3 pos = mswordtipbone->_getderivedposition(); mtipnode->setposition(pos); pos = mheadbone->_getderivedposition(); mheadnode->setposition(pos); // 충돌체크 CollisionManager::getSingletonPtr()->getDefaultContext()->collide(evt.timeSinceLastFrame); // 충돌체크결과해석 CollisionPair **collisionsreport; int numcollisions = mcollidecontext->getcollisions(mtipcollobj, collisionsreport); static int ccnt = 0; if (numcollisions) { CollisionObject *obj1 = collisionsreport[0]->this_object; CollisionObject *obj2 = collisionsreport[0]->other_object; ninjaentity2->getanimationstate("idle1")->setenabled(false); ninjaentity2->getanimationstate("death1")->settimeposition(0.0f); ninjaentity2->getanimationstate("death1")->setloop(false); ninjaentity2->getanimationstate("death1")->setenabled(true); }
COLLTYPE_CONTACT 의이해 직전프레임의충돌결과를이용함. 1번프레임 충돌! 2번프레임 실제로충돌검사를하기전에, 1번프레임의결과이용 충돌! 3번프레임 실제의충돌검사시행. 따라서, 현재의구조에서는한번공격에두번이상의충돌이검출될수있음.
정리 엔터티본구조 뼈대애니메이션 (skeletal animation) 의기본구조. 위치와방향정보를가지고있는조인트. 본의위치좌표의획득 _getderivedposition() OPCODE의충돌오브젝트를이용한충돌처리기법 충돌클래스설정 충돌오브젝트컨텍스트 ( 그룹 ) 설정 충돌오브젝트정의및충돌오브젝트그룹에등록 collide() 로충돌검사 getcollisions() 으로충돌결과획득
실습과제 #9 충돌처리추가 닌자의하단공격 ( M 키이 ) 이상대닌자의발부분에가해질때닌자가쓰러지도록구현.