🕹️
Flappy-Boo : 플래피 부
유령 캐릭터 Boo가 장애물을 피하며 날아가는 게임으로, space 키로 점프하고 장애물에 부딪히지 않고 오래 비행하는 것이 목표
📍 Kaplay 라이브러리 사용
Kaplay는
객체 관리,충돌 감지,애니메이션 처리등을 간단한 코드로 구현할 수 있는 게임 엔진으로, 반복적인 코드를 줄이고 빠르게 게임 로직을 구성할 수 있었다.
🎬 Kaplay 초기화 설정
js
1
k = kaplay({
width: 1300,
height: 750,
letterbox: true,
global: true,
canvas: canvas,
});kaplay(): 게임 엔진 초기화letterbox: 비율 유지global: 전역 접근 허용canvas: HTML 캔버스 지정
🎬 Scene 분리 — Start / Game
시작 화면과 실제 게임 화면을 Kaplay의
scene기능으로 분리
✔ 구현 방식
k.scene("name", callback)/k.go("name")로 전환 가능
js
1
// Start 씬
k.scene("start", async () => {
makeBackground(k);
const playBtn = k.add([
k.sprite("playBtn"),
k.scale(0.35),
k.area(),
k.anchor("center"),
k.pos(k.center().x + 20, k.center().y + 40),
]);
playBtn.onClick(goToGame);
});
// Main 씬
k.scene("main", async () => {
let score = 0;
makeBackground(k);
const player = makePlayer(k);
player.setControls();
player.onCollide("obstacle", async () => {
if (player.isDead) return;
player.isDead = true;
isGameStarted.value = false;
emit("open-game-over", score, currentTime.value);
reset();
});
k.onKeyPress("space", () => {
if (!isGameStarted.value) startGame();
else if (!player.isDead) player.jump(400);
});
});⚙️ 게임 요소 관리
1. 스프라이트/사운드 로드
js
1
k.loadSprite("boo", "/assets/images/game/flappy/Boo.png");
k.loadSound("jump", "/assets/images/game/flappy/jump.wav");
k.play("jump", { volume: 0.02 });2. 객체 추가
js
1
const player = k.add([
k.sprite("boo"),
k.pos(100, 100),
k.area(),
]);
k.setGravity(2500);3. 프레임 업데이트
js
1
k.onUpdate(() => {
if (isGameStarted.value) {
clouds.forEach((cloud) => {
cloud.move(cloud.speed, 0);
if (cloud.pos.x > canvas.width) {
cloud.pos.x = -cloud.width;
}
});
}
});4. 입력 처리
js
1
k.onKeyPress("space", () => {
if (!isGameStarted.value) startGame();
else if (!player.isDead) {
player.jump(400);
if (audioEnabled.value) k.play("jump", { volume: 0.02 });
}
});5. 점수 증가
js
1
k.loop(1, () => {
if (isGameStarted.value && !player.isDead) {
score += 50;
scoreLabel.updateScore(score);
}
});6. 충돌 감지
js
1
player.onCollide("obstacle", async () => {
if (player.isDead) return;
if (audioEnabled.value) k.play("hurt");
player.isDead = true;
player.disableControls();
isGameStarted.value = false;
obstaclesLayer.speed = 0;
map.speed = 0;
stop();
emit("open-game-over", score, currentTime.value);
reset();
});7. 카메라 설정
js
1
k.setCamScale(k.vec2(1.2));
player.onUpdate(() => {
if (isGameStarted.value && !player.isDead) {
k.setCamPos(player.pos.x + 100, 400);
}
});💡 화면 크기 대응
해상도가 다른 환경에서 캔버스 스케일 문제 발생
✔ 해결 방식
js
1
function setCanvasSize() {
const width = window.innerWidth;
const height = window.innerHeight;
game.setSize(width, height);
}
setCanvasSize();
window.addEventListener("resize", setCanvasSize);💡 장애물 무한 스크롤 구현
반복 생성 대신 2개의 장애물 스프라이트를 순환 사용
js
1
const obstaclesLayer = {
speed: -100,
parts: [
k.add([k.sprite("obstacles"), k.pos(0, 0), k.area(), k.scale(SCALE_FACTOR)]),
k.add([k.sprite("obstacles"), k.pos(IMAGE_WIDTH, 0), k.area(), k.scale(SCALE_FACTOR)]),
],
};
k.onUpdate(() => {
const currentTime = performance.now();
const deltaTime = (currentTime - lastUpdateTime) / 1000;
lastUpdateTime = currentTime;
if (isGameStarted.value) {
for (let i = 0; i < obstaclesLayer.parts.length; i++) {
const currentPart = obstaclesLayer.parts[i];
const nextPart = obstaclesLayer.parts[(i + 1) % obstaclesLayer.parts.length];
if (currentPart.pos.x < -IMAGE_WIDTH) {
currentPart.pos.x = nextPart.pos.x + IMAGE_WIDTH;
}
currentPart.move(obstaclesLayer.speed * deltaTime * 60, 0);
}
}
if (isGameStarted.value) obstaclesLayer.speed -= 5 * deltaTime;
});💡 난이도 조절
장애물 속도를 프레임마다 증가시키는 방식으로 난이도 상승 구현
js
1
if (isGameStarted.value) {
obstaclesLayer.speed -= 5 * deltaTime;
}💡 충돌 처리 및 게임 종료
플레이어가 장애물에 부딪힐 때
onCollide로 게임 오버 처리
js
1
player.onCollide("obstacle", async () => {
if (player.isDead) return;
if (audioEnabled.value) k.play("hurt");
player.isDead = true;
player.disableControls();
isGameStarted.value = false;
obstaclesLayer.speed = 0;
map.speed = 0;
stop();
emit("open-game-over", score, currentTime.value);
reset();
});🛠️ 개선 아이디어
- 드래그 앤 드랍 업로드
- Remove/Insert 시 애니메이션 추가
- 용량 및 파일 확장자 유효성 검사
- Multi 업로드 + Progress 표시
- 서버 업로드 큐 관리

