Notice
Recent Posts
Recent Comments
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
Today
Total
관리 메뉴

만재송

[COCOS2D-JS] chipmunk 물리엔진 정복(6) - body, shape 제거 본문

프로그래밍/COCOS2D-JS

[COCOS2D-JS] chipmunk 물리엔진 정복(6) - body, shape 제거

만재송 2018. 1. 21. 20:34

body, shape 제거


왜 제거하는 부분을 따로 다루지? 하는 생각도 했을 것이다. 그런데 무턱대고 지우다가 오류만 보는꼴을 볼것이다.


두 물체가 충돌했을 때 두 물체를 지우고 싶은 코드를 구현한다면 어떻게 해야할까? 이전장에 배운 CollisionHandler 로 처리하면 쉬울 것이다.


이전장에서 배우지않고 넘어간 부분이 있을 것이다. 아래코드를 보자.

var beginHandler = function(arbiter, space) {

return true;
};

모든 충돌 콜백은 2개의 파마리터 arbiter, space를 가진다. space는 딱봐도 맨처음에 선언한 Space 같은데 arbiter는 무엇일까?? arbiter에 대해서 설명해주겠다.


arbiter는 부딪친 두 물체의 shape 정보를 가지고 있다. 왜 body 정보는 없어?? 할지 모르는데 충돌은 shape가 관여한다고 했으니 shape 정보만 나오는게 당연한거다. arbiter를 통해 두 물체의 shape를 얻을 수 있는데 getA(), getB() 함수를 통해서 얻어올 수 있다. getA는 addCollisionHandler에서 첫번째 파라미터에 값을 넣은 타입의 shape를, getB는 두번째 타입의 shape를 가져온다. 


그럼 얻어온 두개의 shape를 통해서 sprite, shape, body를 지워보자.

var beginHandler = function(arbiter, space) {

var contactingShape = arbiter.getA();
var contactedShape = arbiter.getB();

space.removeShape(contactingShape);
space.removeBody(contactingShape.body);
contactingShape.sprite.removeFromParent();

space.removeShape(contactedShape);
space.removeBody(contactedShape.body);
contactedShape.sprite.removeFromParent();

return true;
};

지우는 방법은 이름 그대로 removeShape, Body 를 사용하면 된다. 충돌한 물체의 shape를 얻게 되면 space.removeShape() 를 통해서 지울 수 있고, space.removeBody() 를 통해서 body를 지울 수 있다. 이 때 body의 접근은 shape.body를 하면 해당 shape가 가지고 있는 body로 접근이 가능하다.


sprite는 어떻게 지울까? 안타깝게도 shape는 sprite정보를 가지고 있지 않다. sprite를 지울수 있는 2가지 방법이 있는데, 첫번째 방법은 spirte 객체를 프로퍼티에 달아서 GameScene 전체에 접근해서 지우는 방법이다. 두번째는 shape의 프로퍼티에 다는 방법이다. 필자는 두번째 방법을 선호한다.

shape.sprite = sprite;

 이제 완성한 코드를 실행해보자. 실행해보면 sprite, shape, body가 잘지워질 것 같았지만 안타깝게도 오류가 호출이 된다. 역시 바로 제거가 되었으면 필자가 이부분을 따로 설명할 이유도 없었을 것이다. 아래 오류를 한번 확인해보자.



직역해보면 cpSpaceStep 호출 중에 안전하게 add 하거나 remove를 사용할 수 없다. post-step 단계에서 실행해라. 라고 합니다. cpSpaceStep?? 아! 우리가 처음에 update에 실행했던 step함수! 즉, 위의 오류의 뜻은 step 함수를 실행하는 단계 => "Space 에 존재하는 물체들이 움직일때 add, remove 하지말고 그다음 단계에서 실행해라" 라는 뜻이다. 아니 우리가 어디서 step이 끝나는지를 알고 실행을 해야하나 싶지만 chipmunk는 우리를 위해 그런 코드를 구현해놓았다! 아래 코드를 보자.

var beginHandler = function(arbiter, space) {

var contactingShape = arbiter.getA();
var contactedShape = arbiter.getB();

space.addPostStepCallback(function () {
space.removeShape(contactingShape);
space.removeBody(contactingShape.body);
contactingShape.sprite.removeFromParent();
});

space.addPostStepCallback(function () {
space.removeShape(contactedShape);
space.removeBody(contactedShape.body);
contactedShape.sprite.removeFromParent();
});

return false;
};

addPostStepCallback 함수는 step이 끝나는 직후에 실행되는 함수이다. 이를통해서 두 물체가 충돌을 했고, sprite, shape, body 를 제거하고 싶을 때 step이 실행하고 있을때는 기다리다가 끝나는 즉시 PostStepCallback에 있는 함수를 실행하여 안전하게 제거를 할 수가 있다. 다시 코드를 실행시켜보자. 정상적으로 두 물체가 깨끗하게 제거되는 모습을 볼 수 있을것이다.


여기까지 잘 따라왔다면 chipmunk 의 기본적인 기능은 전부 사용할 수 있다. 배운 물리를 이용하여 코드를 훨씬 간단하고 멋있게 게임을 구현해보자!

var GameScene = cc.Scene.extend({

ctor: function () {
this._super();

this.initPhysics();
this.initDebugMode();
this.scheduleUpdate();
},

initPhysics: function () {
this.space = new cp.Space();
this.space.iterations = 10;
this.space.gravity = cp.v(0, -800);
this.space.damping = 1;
this.space.collisionSlop = 0.1;

this.addPhysicsCircle();
this.addPhysicsBox();
this.addWallsAndGround();
this.addCollisionHandler();
},

addWallsAndGround: function() {
var bottomWall = new cp.SegmentShape(this.space.staticBody,
cp.v(0, 0), cp.v(720, 0), 100);
this.space.addStaticShape(bottomWall);
},

addPhysicsCircle: function() {
var sprite = new cc.PhysicsSprite(res.orange); // PhysicsSprite 객체 생성

var body = new cp.Body(10, cp.momentForCircle(10, 0, 64, cp.v(0, 0)));
body.setPos(cp.v(360, 720));

var shape = new cp.CircleShape(body, 64, cp.v(0, 0));
shape.setCollisionType(2000);
shape.sprite = sprite;

this.space.addBody(body);
this.space.addShape(shape);

sprite.setBody(body); // Sprite에 body 설정
this.addChild(sprite);
},

addPhysicsBox: function() {
var sprite = new cc.PhysicsSprite(res.crate);

var body = new cp.Body(10, cp.momentForBox(10, 128, 128));
body.setPos(cp.v(360, 1000));

var shape = new cp.BoxShape(body, 128, 128);
shape.setCollisionType(1000);
shape.sprite = sprite;

this.space.addBody(body);
this.space.addShape(shape);

sprite.setBody(body);
this.addChild(sprite);
},

addCollisionHandler: function() {
var beginHandler = function(arbiter, space) {

var contactingShape = arbiter.getA();
var contactedShape = arbiter.getB();

space.addPostStepCallback(function () {
space.removeShape(contactingShape);
space.removeBody(contactingShape.body);
contactingShape.sprite.removeFromParent();
});

space.addPostStepCallback(function () {
space.removeShape(contactedShape);
space.removeBody(contactedShape.body);
contactedShape.sprite.removeFromParent();
});

return true;
};

var preSolveHandler = function(arbiter, space) {
return true;
};

var postSolveHandler = function(arbiter, space) {
};

var separateHandler = function(arbiter, space) {
};

this.space.addCollisionHandler(1000, 2000, beginHandler, preSolveHandler,
postSolveHandler, separateHandler);
},

initDebugMode: function() {
var phDebugNode = new cc.PhysicsDebugNode(this.space);
this.addChild(phDebugNode, 10);
},

update: function(dt) {
this.space.step(dt);
}
});




chipmunk 물리엔진 정복 시리즈



Comments