
지난 시간에는 cocos2dx에서 어떻게 event들을 처리하는지 알아보았다.
이번시간에는 cocos2dx에서 어떻게 물리를 처리하는지에 대해 알아보도록 하겠다.
Scene Init
Physics를 쓰고 싶다면 먼저 Scene을 PhysicsWorld 로 초기화 해줘야 한다.
#pragma once
#define __HELLOWORLD_SCENE_H__
#include "cocos2d.h"
class HelloWorld : public cocos2d::Scene
{
public:
static cocos2d::Scene* createScene();
virtual bool init();
CREATE_FUNC(HelloWorld);
public:
cocos2d::PhysicsWorld* physicsWorld;
void SetUpPhysicsWorld(cocos2d::PhysicsWorld* _physicsWorld)
{
physicsWorld = _physicsWorld;
}
};
저렇게 Scene의 멤버에 PhysicsWorld를 만들어 주고 Create 할때 설정해 주면 된다.
Scene* HelloWorld::createScene()
{
auto scene = Scene::createWithPhysics();
scene->getPhysicsWorld()->setDebugDrawMask(PhysicsWorld::DEBUGDRAW_ALL);
auto layer = HelloWorld::create();
layer->SetUpPhysicsWorld(scene->getPhysicsWorld());
scene->addChild(layer);
return scene;
}
저기에 setDebugDrawMask는 Debug용으로 사용되는 함수이다.
저렇게 하면 Physics의 충돌 영역 및 충돌범위등을 알수 있다.
이렇게 설정을 Scene을 Physics용으로 바꿔주었다면 이제 본격적으로 Physics를 사용할수 있다!
Edge
auto edgeNode = Node::create();
auto edgeBody = PhysicsBody::createEdgeBox(visibleSize , PHYSICSBODY_MATERIAL_DEFAULT,3);
edgeNode->setPosition(Vec2(visibleSize.width / 2 + origin.x , visibleSize.height / 2 + origin.y));
edgeNode->setPhysicsBody(edgeBody);
addChild(edgeNode);
먼저 경계선을 만들어서 물체가 화면밖으로 튕겨 나가는걸 막아주어야 한다.
먼저 PhysicsBody를 만들어 주어야 한다.
Create할때 매개변수에 순선대로 크기,physicsMaterial,두께를 넣어줘야 한다.
여기서 처음 보는 게 PhysicsMaterial일 텐데, PhysicsMaterial은 물리 속성을 정의하는 구조체로,마찰력,탄성,밀도를 설정할 수 있다.이를 활용하면 물체가 얼마나 미끄러지는지, 얼마나 튕기는지 등을 조절할 수 있다.
cocos2dx에서 이미 정의된 PHYSICSBODY_MATERIAL_DEFAULT 도 있다.
const PhysicsMaterial PHYSICSBODY_MATERIAL_DEFAULT(0.1f, 0.5f, 0.5f);
다음과 같이 정의되어 있다.
다시 돌아가서 보면
저렇게 만든 physicsBody를 node에 설정해주면 된다.
Node에 적용시키기
auto sprite = Sprite::create("Character.png");
sprite->setPosition(Vec2(visibleSize.width /2 + origin.x , visibleSize.height/ 2 + origin.y));
auto spriteBody = PhysicsBody::createCircle(sprite->getContentSize().width / 2 , PhysicsMaterial(0,1,0));
sprite->setPhysicsBody(spriteBody);
먼저 Sprite를 Node를 하나 만들고 PhysicsBody를 만들어서 셋팅해주면 된다.
edge를 만들때와 똑같지만 PhysicsBody를 Create할때 edgeBox가 아닌 circle을 해주어야 한다.
AngularVelocity
spriteBody->setAngularVelocity(400);
spriteBody->setAngularDamping(1);
spriteBody->setAngularVelocityLimit(30);
setAngularVelocity는 회전 속도를 설정하는 함수다. 단위는 degree/s로, 400이면 1초에 400도 회전한다.
setAngularDamping은 회전 감속을 설정한다. 값이 클수록 빠르게 회전이 멈춘다.
setAngularVelocityLimit는 회전 속도의 최대치를 설정한다. 30으로 제한하면 아무리 힘을 줘도 30 degree/s 이상 회전하지 않는다.
Dynamic
spriteBody->setDynamic(false);
Dynamic을 false로 설정하면 해당 객체는 물리 엔진의 영향을 받지 않고 고정된 상태가 된다. 주로 배경이나 벽 같은 요소에 사용된다.
Velocity
spriteBody->setVelocity(Vec2(200, 0));
spriteBody->setLinearDamping(0);
setVelocity를 사용하면 객체의 속도를 설정할 수 있다. 위 코드는 x축 방향으로 초당 200 픽셀의 속도를 갖도록 한다.
setLinearDamping은 선형 감속 값을 설정한다. 값이 클수록 속도가 빨리 줄어든다. 0이면 감속이 없다.
Apply
spriteBody->applyForce(Vec2(-1200, 0));
spriteBody->applyTorque(4000);
spriteBody->applyImpulse(Vec2());
applyForce는 일정한 힘을 가하는 함수다. (-1200, 0)이면 왼쪽으로 지속적인 힘이 가해진다.
applyTorque는 회전력을 가하는 함수다. 4000이면 객체가 강하게 회전한다.
applyImpulse는 순간적인 힘(충격)을 가하는 함수다. applyForce와 다르게 단발성으로 작용한다.
Collision
spriteBody->setCollisionBitmask(1);
이렇게 유니티에서 layer를 설정해 주는 것처럼 Bitmask를 설정해줄수 있다.
auto contactListener = EventListenerPhysicsContact::create();
contactListener->onContactBegin = CC_CALLBACK_1(HelloWorld::OnTriggerEnter, this);
getEventDispatcher()->addEventListenerWithSceneGraphPriority(contactListener,this);
이렇게 EventListener를 만들어서 이벤트를 등록해주고 그걸 dispatcher에 등록해준다.
PhysicsEvent는 총4개가 존재한다.이해하기 쉽게 유니티의 함수들과 비교해보도록 하겠다.
| 이벤트 | cocos2dx | unity |
| 충돌 시작 | onContactBegin | OnCollisionEnter / OnTriggerEnter |
| 충돌 해결 전 | onContactPreSolve | 없음 |
| 충돌 해결 후 | onContactPostSolve | OnCollisionStay (완전히 동일하지 않음) |
| 충돌 종료 | onContactSeparate | OnCollisionExit / OnTriggerExit |
메서드의 호출 흐름을 예시를 통해 살펴보도록 하자.
충돌 시작 (onContactBegin): 공이 벽에 닿음.
충돌 해결 전 (onContactPreSolve): 공과 벽이 충돌했으니, 튕겨나가도록 속도를 변경하거나, 충돌을 무시하려면 충돌을 취소할 수 있음.
충돌 해결 후 (onContactPostSolve): 공이 벽에 충돌한 후 실제 물리적 변화가 적용되고 튕겨나가는지, 혹은 벽에 힘이 가해졌는지 등을 처리.
충돌 종료 (onContactSeparate): 공과 벽이 떨어지면서 충돌이 끝남.
이제 이런 이벤트들에만 메소드를 등록시키면 충돌 처리를 할수 있다.
다음은 내가 onContactBegin에 등록한 예시 함수이다.
bool HelloWorld::OnTriggerEnter(cocos2d::PhysicsContact& contact)
{
PhysicsBody* a = contact.getShapeA()->getBody();
PhysicsBody* b = contact.getShapeB()->getBody();
if (1 == a->getCollisionBitmask() && 2 == b->getCollisionBitmask() || 2 == a->getCollisionBitmask() && 1 == b->getCollisionBitmask())
{
CCLOG("Hi");
}
return true;
}
return이 true가 되면 충돌 처리가 되고 return false가 되면 두 물체는 충돌이 무시된다.
오늘은 cocos2dx의 Physics에 대해 알아보았다.
생각보다 내용이 유니티와 비슷해서 놀랐다.
다음시간 부터는 지금까지 배운걸 토대로 간단한 프로젝트를 만들고 그 과정을 공유해 보도록 하겠다!
'cocos2d-x' 카테고리의 다른 글
| [cocos2d-x]#9 JumpJump에 대해 알아보자. (0) | 2025.04.08 |
|---|---|
| [cocos2d-x]#7 Event들을 처리해보자. (5) | 2025.01.26 |
| [cocos2d-x]#6 다앙햔 Node들을 알아보자. (4) | 2025.01.22 |
| [cocos2d-x]#5 UI에 대해 알아보자2. (1) | 2025.01.15 |
| [cocos2d-x]#4 UI에 대해 알아보자. (2) | 2025.01.08 |