- FCO 교불 푼다 와 ㅋㅋㅋㅋ [64]
- FCO 성능 향상 스탯 구간 찾았습니다 [87]
- 로아 현재 논란인 로아 스핵사건....gif [222]
- 걸그룹 itzy 유나 [5]
- 드라마 눈물의 여왕, 은성이 손에 붕대 궁금한 사람 없나?? [4]
Document Version : V1.3 - 2017.07.03 with cocos2d-x 3.15.1
Document Version : V1.2 - 2015.06.08 with cocos2d-x 3.6
Document Version : V1.1 - 2014.03.14 with cocos2d-x 3.0beta2
Document Version : V1.0 - 2013.07.10 with cocos2d-x 2.1.4
제 책인 "시작하세요! Cocos2d-x 3.0 프로그래밍" 내용을 3.15.1 버전에 맞게 수정하여 올리고 있습니다.
이 글은 네이버카페 "Cocos2d-x 사용자 모임"에 동시에 게재되고 있습니다.
개발환경 :
종류 | 설명 |
정적 바디 Static Body | 특정 위치에 고정되어 있는 바디입니다. 다른 강체와의 충돌에도 고정된 위치와 각도는 변하지 않습니다. (충돌에 따른 물리 연산을 하지 않습니다.) |
키네마틱 바디 Kinematic Body | 정적 바디와 같은 성격의 정적 객체이지만 속도와 방향을 지정해서 이동시킬 수 있습니다. (충돌에 따른 물리 연산을 하지 않습니다.) |
동적 바디 Dynamic Body | 중력의 힘을 받는 동적 객체로서 이동과 회전이 가능합니다. 다른 강체와 충돌하면 마찰력, 반발력에 의해 충돌 반응을 일으킵니다. (충돌에 따른 물리 연산을 하게 됩니다. ex: 튕김 현상 ) |
커맨드창을 열어 원하는 디렉터리로 이동한 후에, 다음과 같이 cocos 명령어를 이용하여 새로운 프로젝트를 생성합니다.
c:> cocos new Box2dEx03 -p com.study.box03 -l cpp ↵
Box2dEx02에서 한 것처럼 아래의 파일을 클래스 폴더에 추가합니다.
■ GLES-Render.h
■ GLES-Render.cpp
그러고 나서 다음의 디렉터리에서
{Cocos2d-x가 설치된 디렉터리} / tests / cpp-tests / Resources / Images
아래의 파일을 찾아 리소스 폴더에 추가합니다.
이제 헤더에서는 다음과 같이 색으로 표시된 부분이 Box2dEx02 코드에서 추가된 부분이므로 이 부분을 기존 코드에 추가하면 됩니다.
[ HelloWorldScene.h – 박스2D 바디의 종류 ]
#ifndef __HELLOWORLD_SCENE_H__
#define __HELLOWORLD_SCENE_H__
#if (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32)
#pragma execution_character_set("utf-8")
#endif
#include "cocos2d.h"
#include "Box2D/Box2D.h"
#include <GLES-Render.h>
#define PTM_RATIO 32
using namespace cocos2d;
class HelloWorld : public cocos2d::Scene
{
public:
static cocos2d::Scene* createScene();
virtual bool init();
CREATE_FUNC(HelloWorld);
Size winSize;
Texture2D* texture;
b2World* _world;
// For debugging
GLESDebugDraw* m_debugDraw;
cocos2d::CustomCommand _customCmd;
bool createBox2dWorld(bool debug);
void setBox2dWorld();
~HelloWorld();
virtual void draw(cocos2d::Renderer* renderer, const cocos2d::Mat4& transform,
uint32_t flags) override;
void onDraw(const cocos2d::Mat4& transform, uint32_t flags);
void onEnter();
void onExit();
void tick(float dt);
bool onTouchBegan(Touch* touch, Event* event);
void addNewSpriteAtPosition2(Vec2 location);
};
#endif // __HELLOWORLD_SCENE_H__
다음은 cpp의 전체 코드입니다.
[ HelloWorldScene.cpp – 박스2D 바디의 종류 ]
#include "HelloWorldScene.h"
Scene* HelloWorld::createScene()
{
return HelloWorld::create();
}
bool HelloWorld::init()
{
if ( !Scene::init() )
{
return false;
}
/////////////////////////////
// 윈도우 크기를 구한다.
winSize = Director::getInstance()->getWinSize();
// 이미지의 텍스쳐를 구한다.
texture = Director::getInstance()->getTextureCache()->addImage("blocks.png");
// 월드 생성
if (this->createBox2dWorld(true))
{
srand((int)time(nullptr));
this->setBox2dWorld();
this->schedule(schedule_selector(HelloWorld::tick));
}
return true;
}
bool HelloWorld::createBox2dWorld(bool debug)
{
… 생략 : Box2dEx02의 코드와 같음 …
}
void HelloWorld::setBox2dWorld()
{
// staticBody 스프라이트를 추가한다.
Sprite* pSprite1 = Sprite::createWithTexture(texture, Rect(0, 0, 64, 64));
pSprite1->setPosition(Vec2(winSize.width / 2, winSize.height / 2));
this->addChild(pSprite1);
// 바디데프 만들고 속성들을 지정한다.
b2BodyDef bodyDef1;
bodyDef1.type = b2_staticBody;
bodyDef1.position.Set(winSize.width / 2 / PTM_RATIO,
winSize.height / 2 / PTM_RATIO);
bodyDef1.userData = pSprite1;
b2Body* body1 = _world->CreateBody(&bodyDef1);
// 바디에 적용할 물리 속성용 바디의 모양을 만든다.
b2PolygonShape staticBox;
// 바디의 크기 지정 - 상자의 크기에서 가운데 위치를 지정한다.
staticBox.SetAsBox((pSprite1->getContentSize().width / 2) / PTM_RATIO,
(pSprite1->getContentSize().height / 2) / PTM_RATIO);
b2FixtureDef fixtureDef1;
fixtureDef1.shape = &staticBox;
fixtureDef1.density = 1.0f;
body1->CreateFixture(&fixtureDef1);
// kinematicBody 스프라이트를 추가한다.
Sprite* pSprite2 = Sprite::createWithTexture(texture, Rect(0, 0, 64, 32));
pSprite2->setPosition(Vec2(0, 100));
this->addChild(pSprite2);
// 바디데프 만들고 속성들을 지정한다.
b2BodyDef bodyDef2;
bodyDef2.type = b2_kinematicBody;
bodyDef2.position.Set(0, 100.0f / PTM_RATIO);
bodyDef2.linearVelocity = b2Vec2(1.0f, 0);
bodyDef2.userData = pSprite2;
b2Body* body2 = _world->CreateBody(&bodyDef2);
// 바디에 적용할 물리 속성용 바디의 모양을 만든다.
b2PolygonShape kinematicBox;
// 바디의 크기 지정 - 상자의 크기에서 가운데 위치를 지정한다.
kinematicBox.SetAsBox((pSprite2->getContentSize().width / 2) / PTM_RATIO,
(pSprite2->getContentSize().height / 2) / PTM_RATIO);
b2FixtureDef fixtureDef2;
fixtureDef2.shape = &kinematicBox;
fixtureDef2.density = 1.0f;
body2->CreateFixture(&fixtureDef2);
}
HelloWorld::~HelloWorld()
{
… 생략 : Box2dEx02의 코드와 같음 …
}
void HelloWorld::draw(Renderer *renderer, const Mat4 &transform, uint32_t flags)
{
… 생략 : Box2dEx02의 코드와 같음 …
}
void HelloWorld::onDraw(const Mat4 &transform, uint32_t flags)
{
… 생략 : Box2dEx02의 코드와 같음 …
}
void HelloWorld::onEnter()
{
… 생략 : Box2dEx02의 코드와 같음 …
}
void HelloWorld::onExit()
{
… 생략 : Box2dEx02의 코드와 같음 …
}
void HelloWorld::tick(float dt)
{
int velocityIterations = 8;
int positionIterations = 3;
// Step : 물리 세계를 시뮬레이션한다.
_world->Step(dt, velocityIterations, positionIterations);
// 만들어진 객체 만큼 루프를 돌리면서 바디에 붙인 스프라이트를 여기서 제어한다.
for (b2Body* b = _world->GetBodyList(); b; b = b->GetNext())
{
if (b->GetUserData() != nullptr) {
Sprite* spriteData = (Sprite *)b->GetUserData();
spriteData->setPosition(Vec2(b->GetPosition().x * PTM_RATIO,
b->GetPosition().y * PTM_RATIO));
spriteData->setRotation(-1 * CC_RADIANS_TO_DEGREES(b->GetAngle()));
}
// --------------------------------------------------------------------
// 키네마틱 바디 좌우로 이동시키기
if (b->GetType() == b2_kinematicBody) {
b2Vec2 v = b->GetPosition();
if (v.x*PTM_RATIO > winSize.width) {
// 왼쪽으로 이동
b->SetLinearVelocity(b2Vec2(-1.0f, 0));
}
else if (v.x < 0) {
// 오른쪽으로 이동
b->SetLinearVelocity(b2Vec2(1.0f, 0));
}
}
}
}
bool HelloWorld::onTouchBegan(Touch* touch, Event* event)
{
auto touchPoint = touch->getLocation();
// 터치된 지점에 새로운 물리 객체의 바디와 해당 스프라이트를 추가한다.
addNewSpriteAtPosition2(touchPoint);
return true;
}
void HelloWorld::addNewSpriteAtPosition2(Vec2 location)
{
int nNum = rand() % 3;
// 바디데프 만들고 속성들을 지정한다.
b2BodyDef bodyDef;
bodyDef.type = b2_dynamicBody;
bodyDef.position.Set(location.x / PTM_RATIO, location.y / PTM_RATIO);
bodyDef.userData = nullptr;
// 월드에 바디데프의 정보로 바디를 만든다.
b2Body* body = _world->CreateBody(&bodyDef);
// 바디에 적용할 물리 속성용 바디의 모양을 만든다.
if (nNum == 0) {
b2PolygonShape dynamicBox;
dynamicBox.SetAsBox(0.8f, 0.8f);
b2FixtureDef fixtureDef;
fixtureDef.shape = &dynamicBox;
fixtureDef.density = 1.0f;
fixtureDef.friction = 0.3f;
fixtureDef.restitution = 0.0f;
body->CreateFixture(&fixtureDef);
}
else if (nNum == 1) {
b2PolygonShape dynamicBox;
b2Vec2 tri[3];
tri[0].x = -.5;
tri[0].y = 0.0;
tri[1].x = .5;
tri[1].y = 0.0;
tri[2].x = 0;
tri[2].y = 1.0;
dynamicBox.Set(tri, 3);
b2FixtureDef fixtureDef;
fixtureDef.shape = &dynamicBox;
fixtureDef.density = 1.0f;
fixtureDef.friction = 0.3f;
fixtureDef.restitution = 1.0f;
body->CreateFixture(&fixtureDef);
}
else {
b2CircleShape dynamicCircle;
dynamicCircle.m_radius = 1.0;
b2FixtureDef fixtureDef;
fixtureDef.shape = &dynamicCircle;
fixtureDef.density = 1.0f;
fixtureDef.friction = 0.2f;
fixtureDef.restitution = 1.0f;
body->CreateFixture(&fixtureDef);
}
}
// 바디데프 만들고 속성들을 지정한다.
b2BodyDef bodyDef1;
bodyDef1.type = b2_staticBody;
bodyDef1.position.Set(winSize.width/2/PTM_RATIO, winSize.height/2/PTM_RATIO);
bodyDef1.userData = pSprite1;
b2Body* body1 = _world->CreateBody(&bodyDef1);
// 바디데프 만들고 속성들을 지정한다.
b2BodyDef bodyDef2;
bodyDef2.type = b2_kinematicBody;
bodyDef2.position.Set(0, 100.0f/PTM_RATIO);
bodyDef2.linearVelocity = b2Vec2(1.0f, 0);
bodyDef2.userData = pSprite2;
b2Body* body2 = _world->CreateBody(&bodyDef2);
// 바디데프 만들고 속성들을 지정한다.
b2BodyDef bodyDef;
bodyDef.type = b2_dynamicBody;
bodyDef.position.Set(location.x/PTM_RATIO, location.y/PTM_RATIO);
bodyDef.userData = NULL;
// 월드에 바디데프의 정보로 바디를 만든다.
b2Body* body = _world->CreateBody(&bodyDef);
정적 객체와 키네마틱 객체의 위치가 겹치면 어떻게 될까요?
궁금하면 위의 코드에서 키네마틱 바디가 생성되는 위치를 조금 위로 만들어서 테스트해 볼 수 있을 것입니다. 이처럼 물리 엔진을 사용할 때는 많은 값들을 조정해보고 실제로 눈으로 보면서 값의 변화에 따른 시뮬레이션의 결과가 어떻게 되는지 확인해 보는 작업이 중요합니다.
내폰젤무거워