본 콘텐츠의 이미지 및 내용은 AI로 생성되었습니다.
본 콘텐츠의 이미지 및 내용을 무단으로 복제, 배포, 수정하여 사용할 경우 저작권법에 의해 법적 제재를 받을 수 있습니다.
이미지 로딩 중...
AI Generated
2025. 12. 3. · 18 Views
Phaser 충돌 감지와 처리 완벽 가이드
게임 개발의 핵심인 충돌 감지와 처리를 Phaser 프레임워크로 배워봅니다. collider와 overlap의 차이부터 타일맵 충돌까지, 실무에서 바로 쓸 수 있는 기법을 익힙니다.
목차
1. collider vs overlap
김개발 씨는 첫 번째 플랫폼 게임을 만들고 있었습니다. 플레이어가 적과 부딪히면 데미지를 받고, 코인에 닿으면 점수가 올라가는 간단한 게임이었죠.
그런데 이상한 일이 벌어졌습니다. 코인에 닿으면 플레이어가 코인에 막혀서 더 이상 앞으로 나아가지 못하는 것이었습니다.
collider와 overlap은 Phaser에서 충돌을 감지하는 두 가지 방법입니다. collider는 물리적 충돌을 처리하여 두 객체가 서로 밀어내는 반면, overlap은 겹침만 감지하고 물리적 반응은 일으키지 않습니다.
마치 collider는 벽에 부딪히는 것이고, overlap은 센서를 통과하는 것과 같습니다.
다음 코드를 살펴봅시다.
// collider: 물리적 충돌 - 플레이어가 바닥에 서 있을 수 있음
this.physics.add.collider(player, platforms);
// collider: 적과 충돌하면 서로 밀어냄
this.physics.add.collider(player, enemy, this.onHitEnemy, null, this);
// overlap: 겹침만 감지 - 코인을 통과하며 수집
this.physics.add.overlap(player, coins, this.collectCoin, null, this);
// collectCoin 함수: 코인 수집 처리
collectCoin(player, coin) {
coin.disableBody(true, true); // 코인 비활성화 및 숨김
this.score += 10;
}
김개발 씨는 입사 3개월 차 주니어 게임 개발자입니다. 오늘도 열심히 플랫폼 게임을 만들던 중, 이상한 버그를 발견했습니다.
코인에 닿으면 점수는 올라가는데, 플레이어가 코인에 막혀서 앞으로 나아가지 못하는 것이었습니다. 선배 개발자 박시니어 씨가 다가와 코드를 살펴봅니다.
"아, 여기가 문제네요. collider와 overlap의 차이를 이해하지 못해서 생긴 실수예요." 그렇다면 이 둘의 차이는 정확히 무엇일까요?
쉽게 비유하자면, collider는 마치 실제 벽에 부딪히는 것과 같습니다. 여러분이 벽을 향해 걸어가면 벽에 막혀서 더 이상 앞으로 나아갈 수 없죠.
두 물체가 서로를 밀어내는 물리적인 반응이 일어납니다. 반면 overlap은 마트 입구의 자동문 센서를 지나가는 것과 같습니다.
센서는 여러분이 지나갔다는 것을 감지하지만, 여러분의 움직임을 막지는 않습니다. 그냥 통과하면서 문이 열리는 것이죠.
게임에서 이 차이는 매우 중요합니다. 플레이어가 바닥 위에 서 있으려면 바닥과의 물리적 충돌이 필요합니다.
그래야 중력에 의해 바닥을 뚫고 떨어지지 않죠. 하지만 코인을 수집할 때는 플레이어가 코인을 그냥 통과하면서 점수만 올라가면 됩니다.
위의 코드를 살펴보겠습니다. 첫 번째 줄에서 this.physics.add.collider(player, platforms)는 플레이어와 플랫폼 사이에 물리적 충돌을 설정합니다.
이렇게 해야 플레이어가 플랫폼 위에 서 있을 수 있습니다. 세 번째 줄의 this.physics.add.overlap(player, coins, ...)는 플레이어와 코인 사이에 겹침 감지를 설정합니다.
플레이어가 코인과 겹치면 collectCoin 함수가 호출되지만, 물리적으로 밀어내지는 않습니다. 실제 게임 개발에서 이 구분은 필수적입니다.
슈퍼 마리오를 떠올려 보세요. 마리오는 땅과 블록에 collider로 충돌하여 위에 서거나 막히고, 코인과 버섯에는 overlap으로 겹쳐서 아이템을 획득합니다.
주의할 점은 두 경우 모두 콜백 함수를 연결할 수 있다는 것입니다. collider도 충돌 시 특정 함수를 실행할 수 있습니다.
차이는 물리적 반응의 유무입니다. 다시 김개발 씨의 이야기로 돌아가 봅시다.
박시니어 씨의 설명을 들은 김개발 씨는 collider를 overlap으로 바꿨고, 코인 수집이 자연스럽게 작동하기 시작했습니다. "아, 그래서 그랬군요!"
실전 팁
💡 - 플레이어가 통과해야 하는 아이템은 overlap, 막혀야 하는 장애물은 collider를 사용하세요
- 둘 다 콜백 함수를 받을 수 있으니, 상황에 맞게 선택하세요
2. 그룹 간 충돌
김개발 씨의 게임에는 이제 적이 10마리, 코인이 30개, 총알이 수십 개씩 날아다닙니다. 모든 객체에 일일이 충돌을 설정하다 보니 코드가 수백 줄이 넘어갔습니다.
박시니어 씨가 지나가다 코드를 보고 한숨을 쉬었습니다. "이거 그룹으로 처리하면 한 줄이면 되는데..."
**그룹(Group)**은 같은 종류의 게임 객체를 묶어서 관리하는 컨테이너입니다. 그룹을 사용하면 여러 객체에 대한 충돌 처리를 한 번에 설정할 수 있습니다.
마치 학교에서 학생 한 명 한 명에게 공지하는 대신, 반 전체에 방송하는 것과 같습니다.
다음 코드를 살펴봅시다.
// 적 그룹 생성
this.enemies = this.physics.add.group();
// 적 여러 마리 추가
for (let i = 0; i < 10; i++) {
let enemy = this.enemies.create(100 + i * 50, 300, 'enemy');
enemy.setBounce(0.5);
}
// 코인 그룹 생성
this.coins = this.physics.add.group({
key: 'coin',
repeat: 29, // 30개 생성
setXY: { x: 12, y: 0, stepX: 70 }
});
// 그룹 간 충돌 설정 - 한 줄로 모든 충돌 처리
this.physics.add.collider(this.player, this.enemies, this.hitEnemy, null, this);
this.physics.add.overlap(this.player, this.coins, this.collectCoin, null, this);
김개발 씨는 이제 꽤 복잡한 게임을 만들고 있었습니다. 적 10마리, 코인 30개, 총알 수십 개가 화면을 가득 채웠죠.
문제는 이 모든 객체에 충돌을 설정하는 코드였습니다. 처음에 김개발 씨는 이렇게 작성했습니다.
collider(player, enemy1), collider(player, enemy2), collider(player, enemy3)... 적 하나하나에 대해 충돌 코드를 작성하다 보니 코드가 끝없이 늘어났습니다.
박시니어 씨가 지나가다 코드를 보고 말했습니다. "김개발 씨, 그룹이라는 개념을 아시나요?" 그룹은 마치 폴더와 같습니다.
파일을 하나하나 관리하는 대신 폴더에 넣어서 한 번에 관리하듯이, 게임 객체도 그룹에 넣어서 한 번에 다룰 수 있습니다. Phaser에서 그룹을 만드는 방법은 간단합니다.
this.physics.add.group()을 호출하면 물리 엔진이 적용된 그룹이 생성됩니다. 이 그룹에 create() 메서드로 객체를 추가하거나, 생성 시 옵션으로 여러 객체를 한꺼번에 만들 수 있습니다.
위 코드에서 repeat: 29는 첫 번째 객체 외에 29개를 더 만들라는 의미입니다. 즉, 총 30개의 코인이 생성됩니다.
setXY로 시작 위치와 간격을 지정하면 자동으로 배치됩니다. 가장 강력한 부분은 충돌 설정입니다.
this.physics.add.collider(this.player, this.enemies, ...)라고 한 줄만 작성하면, 플레이어와 enemies 그룹 안의 모든 적 사이에 충돌이 설정됩니다. 10마리든 100마리든 상관없이 한 줄입니다.
성능 면에서도 그룹은 탁월합니다. Phaser는 그룹 단위로 충돌 검사를 최적화하기 때문에, 개별 객체를 일일이 검사하는 것보다 훨씬 빠릅니다.
실무에서는 거의 모든 게임이 그룹을 사용합니다. 슈팅 게임의 총알, RPG의 몬스터, 퍼즐 게임의 블록 등 같은 종류의 객체는 반드시 그룹으로 관리해야 합니다.
주의할 점은 그룹에서 객체를 제거할 때입니다. destroy()로 객체를 완전히 삭제하거나, disableBody(true, true)로 비활성화할 수 있는데, 재사용이 필요하면 후자가 더 효율적입니다.
김개발 씨는 수백 줄의 코드를 몇 줄로 줄이고 감탄했습니다. "그룹이 이렇게 편한 거였군요!"
실전 팁
💡 - 같은 종류의 객체는 항상 그룹으로 관리하세요
group.getChildren()으로 그룹 내 모든 객체에 접근할 수 있습니다
3. 충돌 콜백 함수
김개발 씨의 게임에서 플레이어가 적과 충돌하면 그냥 멈춰버렸습니다. 충돌은 감지되는데, 그 다음에 무슨 일이 일어나야 하는지 아무것도 정의하지 않았기 때문입니다.
"충돌했을 때 뭔가 일어나게 하려면 어떻게 해야 하죠?"
충돌 콜백 함수는 충돌이 발생했을 때 자동으로 호출되는 함수입니다. 이 함수는 충돌한 두 객체를 매개변수로 받아, 원하는 로직을 실행할 수 있습니다.
마치 초인종이 울리면 자동으로 현관문을 확인하러 가는 것처럼, 충돌이 감지되면 지정한 함수가 실행됩니다.
다음 코드를 살펴봅시다.
// 충돌 설정 시 콜백 함수 연결
this.physics.add.collider(
player,
enemies,
this.handleCollision, // 충돌 시 호출할 함수
this.shouldCollide, // 충돌 여부를 결정하는 함수 (선택)
this // 콜백 함수의 this 컨텍스트
);
// 충돌 처리 콜백 함수
handleCollision(player, enemy) {
// 충돌한 두 객체가 매개변수로 전달됨
player.health -= enemy.damage;
// 넉백 효과 적용
let knockbackX = player.x < enemy.x ? -200 : 200;
player.setVelocityX(knockbackX);
// 무적 시간 설정
player.setTint(0xff0000);
this.time.delayedCall(1000, () => player.clearTint());
}
김개발 씨는 충돌 감지까지는 성공했습니다. 하지만 플레이어가 적과 부딪히면 그냥 서로 밀어내기만 할 뿐, 아무 일도 일어나지 않았습니다.
게임에서는 체력이 깎이고, 효과음이 나고, 플레이어가 튕겨 나가야 하는데 말이죠. 박시니어 씨가 설명했습니다.
"충돌 감지는 언제 충돌했는지를 알려주는 것이고, 충돌했을 때 무슨 일이 일어나는지는 콜백 함수에서 정의해야 해요." 콜백 함수는 특정 이벤트가 발생했을 때 자동으로 호출되는 함수입니다. 충돌 콜백의 경우, Phaser가 충돌을 감지하면 우리가 지정한 함수를 대신 호출해 줍니다.
collider()나 overlap() 함수의 세 번째 매개변수가 바로 이 콜백 함수입니다. 위 코드에서 this.handleCollision이 그것입니다.
콜백 함수는 충돌한 두 객체를 매개변수로 받습니다. 첫 번째 매개변수는 collider()에서 첫 번째로 지정한 객체(player), 두 번째 매개변수는 두 번째로 지정한 객체(enemy)입니다.
이 순서는 항상 일정합니다. 네 번째 매개변수인 this.shouldCollide는 프로세스 콜백이라고 합니다.
이 함수가 false를 반환하면 충돌 자체가 무시됩니다. 예를 들어 플레이어가 무적 상태일 때 충돌을 무시하고 싶다면 여기서 처리합니다.
다섯 번째 매개변수는 콜백 함수 내에서 this가 가리킬 대상입니다. 보통 현재 씬(this)을 전달합니다.
이렇게 해야 콜백 함수 내에서 this.score나 this.time 같은 씬의 속성에 접근할 수 있습니다. 실제 게임에서 충돌 콜백은 다양하게 활용됩니다.
체력 감소, 점수 증가, 효과음 재생, 파티클 효과, 넉백, 무적 시간 설정 등 게임의 재미를 만드는 거의 모든 요소가 여기서 처리됩니다. 코드에서 setTint(0xff0000)은 객체를 빨간색으로 물들이는 효과입니다.
피격 시 빨갛게 변했다가 1초 후에 원래대로 돌아오는 전형적인 패턴입니다. 김개발 씨는 콜백 함수를 추가하자 게임이 살아났다고 느꼈습니다.
"충돌이 일어났을 때 진짜 게임처럼 반응하네요!"
실전 팁
💡 - 콜백 함수의 매개변수 순서는 collider 설정 시 객체를 넣은 순서와 같습니다
- 프로세스 콜백을 활용하면 무적 시간이나 조건부 충돌을 쉽게 구현할 수 있습니다
4. 충돌 영역 설정
김개발 씨가 만든 캐릭터는 조금 통통한 모습이었습니다. 그런데 게임을 테스트해 보니 캐릭터의 머리 위 빈 공간에 적이 닿아도 데미지를 받았습니다.
이미지는 네모인데 캐릭터는 동그랗다 보니 생긴 문제였습니다. "히트박스를 캐릭터 모양에 맞게 조절할 수 없을까요?"
**충돌 영역(히트박스)**은 실제로 충돌 판정이 일어나는 범위를 정의합니다. 기본적으로 스프라이트의 전체 크기가 충돌 영역이 되지만, setSize()와 setOffset()을 사용하여 원하는 크기와 위치로 조절할 수 있습니다.
마치 축구에서 골대 안에 공이 들어가야만 골인 것처럼, 히트박스 안에 닿아야만 충돌로 인정됩니다.
다음 코드를 살펴봅시다.
// 기본 충돌 영역 (스프라이트 전체)
let player = this.physics.add.sprite(100, 300, 'player');
// 충돌 영역 크기 조절 (가로 20, 세로 40)
player.body.setSize(20, 40);
// 충돌 영역 위치 조절 (스프라이트 내에서의 오프셋)
player.body.setOffset(6, 8);
// 원형 충돌 영역 사용 (공, 코인 등에 적합)
let ball = this.physics.add.sprite(200, 200, 'ball');
ball.body.setCircle(16); // 반지름 16픽셀의 원
// 원형 충돌 영역의 오프셋 조절
ball.body.setCircle(16, 4, 4); // 반지름, x오프셋, y오프셋
김개발 씨의 캐릭터는 귀여운 동그란 슬라임이었습니다. 그런데 스프라이트 이미지는 32x32 픽셀의 정사각형이고, 슬라임의 실제 몸체는 그 안의 일부분만 차지했습니다.
네 귀퉁이에는 투명한 빈 공간이 있었죠. 문제는 Phaser가 기본적으로 스프라이트 전체 크기를 충돌 영역으로 사용한다는 것입니다.
그래서 빈 공간에 적이 닿아도 충돌로 판정되었습니다. 플레이어 입장에서는 분명히 피했는데 맞은 것처럼 느껴지니 억울할 수밖에 없습니다.
박시니어 씨가 해결책을 알려주었습니다. "히트박스를 조절하면 돼요.
실제 캐릭터 모양에 맞게 충돌 영역을 설정하는 거죠." body.setSize(width, height)는 충돌 영역의 크기를 설정합니다. 32x32 스프라이트에서 실제 캐릭터가 20x24 크기라면, setSize(20, 24)로 줄여주면 됩니다.
하지만 크기만 줄이면 히트박스가 스프라이트의 왼쪽 상단에 붙어버립니다. 캐릭터가 중앙에 있다면 히트박스도 중앙에 와야 합니다.
이때 body.setOffset(x, y)을 사용합니다. 스프라이트 내에서 히트박스의 위치를 조절하는 것입니다.
동그란 캐릭터나 공 같은 객체는 setCircle()이 더 적합합니다. 사각형 히트박스는 원형 객체의 모서리 부분에서 어색한 충돌이 발생할 수 있기 때문입니다.
원형 히트박스를 사용하면 훨씬 자연스러운 충돌 판정이 가능합니다. 개발할 때 히트박스를 눈으로 확인하고 싶다면, Phaser의 디버그 모드를 활용할 수 있습니다.
this.physics.world.createDebugGraphic()를 호출하면 모든 히트박스가 화면에 표시됩니다. 실무에서 히트박스 조절은 게임의 게임 필에 큰 영향을 미칩니다.
액션 게임에서 히트박스가 실제 모습보다 약간 작으면 플레이어가 "아슬아슬하게 피했다"는 쾌감을 느낍니다. 반대로 너무 크면 억울한 피격이 많아져 스트레스를 받습니다.
많은 인기 게임들이 플레이어의 히트박스는 작게, 적의 히트박스는 크게 설정하여 플레이어에게 유리한 판정을 주는 기법을 사용합니다. 이것이 바로 관대한 히트박스 디자인입니다.
김개발 씨는 히트박스를 조절하자 게임이 훨씬 공정하게 느껴졌습니다. "이제 진짜 피하면 안 맞네요!"
실전 팁
💡 - 디버그 모드로 히트박스를 시각적으로 확인하며 조절하세요
- 플레이어에게 관대한 히트박스를 적용하면 게임이 더 재미있어집니다
5. 충돌 필터링
김개발 씨의 게임이 복잡해지면서 새로운 문제가 생겼습니다. 아군 총알이 아군 캐릭터에게도 데미지를 주고, 적끼리도 서로 부딪혀서 밀어내고 있었습니다.
"특정 객체끼리만 충돌하게 하고 싶은데, 방법이 없을까요?"
충돌 필터링은 어떤 객체가 어떤 객체와 충돌할지를 세밀하게 제어하는 기능입니다. 프로세스 콜백을 사용하거나, Arcade Physics의 콜리전 카테고리를 활용할 수 있습니다.
마치 VIP 파티에서 초대받은 사람만 입장할 수 있는 것처럼, 특정 조건을 만족하는 객체만 충돌하도록 필터링할 수 있습니다.
다음 코드를 살펴봅시다.
// 프로세스 콜백을 사용한 충돌 필터링
this.physics.add.collider(
bullets,
characters,
this.onBulletHit,
this.canCollide, // 충돌 여부 결정 함수
this
);
// 같은 팀끼리는 충돌하지 않도록 필터링
canCollide(bullet, character) {
// 같은 팀이면 충돌하지 않음
if (bullet.team === character.team) {
return false;
}
// 캐릭터가 무적 상태면 충돌하지 않음
if (character.isInvincible) {
return false;
}
return true; // 그 외에는 충돌
}
// 무적 상태 설정 예시
setInvincible(character, duration) {
character.isInvincible = true;
this.time.delayedCall(duration, () => {
character.isInvincible = false;
});
}
김개발 씨의 게임은 이제 제법 복잡해졌습니다. 플레이어 팀과 적 팀이 있고, 양쪽 다 총알을 발사합니다.
그런데 플레이어의 총알이 플레이어에게도 맞고, 적의 총알이 적에게도 맞는 혼란스러운 상황이 벌어졌습니다. 모든 총알과 모든 캐릭터 사이에 충돌을 설정해 놓았기 때문입니다.
하지만 게임 규칙상 아군의 총알은 아군에게 맞으면 안 됩니다. 박시니어 씨가 프로세스 콜백을 소개해 주었습니다.
"충돌이 일어나기 전에 한 번 더 검사하는 거예요. 조건에 맞지 않으면 충돌 자체를 무시할 수 있어요." collider()의 네 번째 매개변수가 바로 프로세스 콜백입니다.
이 함수가 false를 반환하면 두 객체가 겹쳐 있어도 충돌로 처리하지 않습니다. 물리적 반응도 없고, 충돌 콜백도 호출되지 않습니다.
위 코드에서 canCollide 함수는 총알과 캐릭터가 같은 팀인지 확인합니다. 같은 팀이면 false를 반환하여 충돌을 무시합니다.
또한 캐릭터가 무적 상태일 때도 충돌을 무시합니다. 이 패턴은 매우 유용합니다.
무적 시간, 팀 구분, 특정 조건에서만 활성화되는 트랩 등 다양한 게임 메카닉을 구현할 수 있습니다. 프로세스 콜백은 충돌 콜백보다 먼저 호출된다는 점을 기억하세요.
프로세스 콜백이 false를 반환하면 충돌 콜백은 아예 호출되지 않습니다. 따라서 성능상 이점도 있습니다.
실무에서는 객체에 team, faction, layer 같은 속성을 추가하여 충돌 그룹을 논리적으로 구분합니다. Phaser 3의 Arcade Physics는 Matter.js처럼 복잡한 콜리전 카테고리를 지원하지 않지만, 프로세스 콜백으로 충분히 대체할 수 있습니다.
더 복잡한 충돌 규칙이 필요하다면 Matter.js 물리 엔진을 고려해 볼 수 있습니다. Matter.js는 콜리전 필터를 네이티브로 지원하여, 비트마스크로 충돌 그룹을 정의할 수 있습니다.
김개발 씨는 팀 속성을 추가하고 프로세스 콜백을 설정하자, 아군끼리는 총알이 그냥 통과하게 되었습니다. "이제 진짜 팀 게임 같아요!"
실전 팁
💡 - 프로세스 콜백에서 복잡한 로직은 피하고, 단순한 조건 검사만 하세요
- 객체에 team, layer 같은 속성을 추가하면 필터링이 쉬워집니다
6. 타일맵 충돌
김개발 씨는 이제 본격적인 플랫폼 게임을 만들고 싶었습니다. 레벨 에디터로 멋진 맵을 만들었는데, 문제는 이 타일맵과 캐릭터 사이의 충돌이었습니다.
수백 개의 타일 하나하나에 충돌을 설정하는 건 불가능해 보였습니다.
타일맵 충돌은 Tiled 같은 맵 에디터로 만든 레벨에서 특정 타일과의 충돌을 설정하는 기능입니다. setCollisionByProperty()나 setCollisionByExclusion()을 사용하면 수백 개의 타일에 대한 충돌을 몇 줄의 코드로 설정할 수 있습니다.
마치 지도에서 파란색은 물, 초록색은 땅이라고 규칙을 정해두면 자동으로 구분되는 것과 같습니다.
다음 코드를 살펴봅시다.
// 타일맵과 타일셋 로드
const map = this.make.tilemap({ key: 'level1' });
const tileset = map.addTilesetImage('platformTiles', 'tiles');
const groundLayer = map.createLayer('Ground', tileset);
// 방법 1: 타일 속성으로 충돌 설정 (Tiled에서 collides 속성 부여)
groundLayer.setCollisionByProperty({ collides: true });
// 방법 2: 특정 타일 인덱스 제외하고 모두 충돌 (빈 타일 = -1)
groundLayer.setCollisionByExclusion([-1]);
// 방법 3: 특정 타일 인덱스 범위에 충돌 설정
groundLayer.setCollision([1, 2, 3, 4, 5]); // 1~5번 타일만 충돌
groundLayer.setCollisionBetween(1, 10); // 1~10번 타일 충돌
// 타일맵 레이어와 플레이어 충돌 설정
this.physics.add.collider(player, groundLayer);
김개발 씨는 Tiled라는 맵 에디터를 배웠습니다. 드래그 앤 드롭으로 타일을 배치하니 멋진 게임 레벨이 만들어졌습니다.
하지만 이 맵을 Phaser로 가져와서 충돌을 설정하려니 막막했습니다. 맵에는 수백 개의 타일이 있었습니다.
바닥 타일, 벽 타일, 장식 타일, 배경 타일... 이 모든 타일에 일일이 충돌을 설정하는 것은 불가능해 보였습니다.
박시니어 씨가 웃으며 말했습니다. "타일맵 충돌은 아주 쉬워요.
Phaser가 다 해주거든요." 가장 깔끔한 방법은 Tiled에서 타일에 커스텀 속성을 부여하는 것입니다. 타일셋 에디터에서 바닥, 벽 타일에 collides: true 속성을 추가합니다.
그리고 Phaser에서 setCollisionByProperty({ collides: true })를 호출하면 해당 속성을 가진 모든 타일에 자동으로 충돌이 설정됩니다. 또 다른 방법은 setCollisionByExclusion()입니다.
매개변수로 전달한 타일 인덱스를 제외한 모든 타일에 충돌을 설정합니다. 빈 타일의 인덱스가 -1이므로, setCollisionByExclusion([-1])은 빈 공간을 제외한 모든 타일에 충돌을 설정하는 간단한 방법입니다.
특정 타일만 선택적으로 충돌시키고 싶다면 setCollision([1, 2, 3])처럼 타일 인덱스 배열을 전달하거나, setCollisionBetween(1, 10)처럼 범위를 지정할 수 있습니다. 타일맵 레이어와 캐릭터의 충돌은 일반 충돌과 동일하게 physics.add.collider()로 설정합니다.
첫 번째 매개변수에 캐릭터, 두 번째에 타일맵 레이어를 넣으면 됩니다. 실무에서는 여러 레이어를 사용합니다.
배경 레이어(충돌 없음), 바닥 레이어(충돌 있음), 장식 레이어(충돌 없음) 등으로 구분하면 관리가 쉽습니다. 각 레이어별로 충돌 여부를 다르게 설정할 수 있기 때문입니다.
주의할 점은 타일맵은 **정적(static)**이라는 것입니다. 타일맵의 물리 body는 움직이지 않으므로, 캐릭터가 타일맵을 밀어낼 수는 없습니다.
이것이 바닥이나 벽으로 적합한 이유입니다. 디버그 모드를 켜면 어떤 타일에 충돌이 설정되었는지 시각적으로 확인할 수 있습니다.
충돌 타일은 색상으로 표시되어 레벨 디자인 시 매우 유용합니다. 김개발 씨는 단 두 줄의 코드로 전체 레벨의 충돌을 설정하고 감탄했습니다.
"수백 개 타일을 한 번에 처리하다니!"
실전 팁
💡 - Tiled에서 타일에 collides 속성을 미리 부여해두면 관리가 편합니다
- 레이어를 논리적으로 분리하여 충돌 여부를 레이어 단위로 관리하세요
이상으로 학습을 마칩니다. 위 내용을 직접 코드로 작성해보면서 익혀보세요!
댓글 (0)
함께 보면 좋은 카드 뉴스
서비스 메시 완벽 가이드
마이크로서비스 간 통신을 안전하고 효율적으로 관리하는 서비스 메시의 핵심 개념부터 실전 도입까지, 초급 개발자를 위한 완벽한 입문서입니다. Istio와 Linkerd 비교, 사이드카 패턴, 실무 적용 노하우를 담았습니다.
EFK 스택 로깅 완벽 가이드
마이크로서비스 환경에서 로그를 효과적으로 수집하고 분석하는 EFK 스택(Elasticsearch, Fluentd, Kibana)의 핵심 개념과 실전 활용법을 초급 개발자도 쉽게 이해할 수 있도록 정리한 가이드입니다.
Grafana 대시보드 완벽 가이드
실시간 모니터링의 핵심, Grafana 대시보드를 처음부터 끝까지 배워봅니다. Prometheus 연동부터 알람 설정까지, 초급 개발자도 쉽게 따라할 수 있는 실전 가이드입니다.
분산 추적 완벽 가이드
마이크로서비스 환경에서 요청의 전체 흐름을 추적하는 분산 추적 시스템의 핵심 개념을 배웁니다. Trace, Span, Trace ID 전파, 샘플링 전략까지 실무에 필요한 모든 것을 다룹니다.
CloudFront CDN 완벽 가이드
AWS CloudFront를 활용한 콘텐츠 배포 최적화 방법을 실무 관점에서 다룹니다. 배포 생성부터 캐시 설정, HTTPS 적용까지 단계별로 알아봅니다.