<코딩 알려주는 누나>의 슈팅게임 프로젝트를 따라하면서 만들면서 배운 것들을 하나씩 리뷰해보는 시간을 스스로에게 가져보도록 하자.
내가 이 프로젝트를 따라하면서 느꼈던 것은 두가지다
1. 함수를 잘쓰자!
2. 게임은 이런 식으로 만들어지는 구나...
하는것이 었다.
브라우저에 이런 것들을 그리고 올리는 것들도 신기하지만 내가 가장 신기했던 것은 움직이는 것을 구현하는 것과 적이 랜덤으로 내려오게 하는 것. 그리고 미사일을 발사하는 것. 그리고 미사일을 발사하면 적이 없어지는 것.그냥 게임의 가장 중요한 부분이 젤 궁금했다고 하자.
그래서 그것을 어떻게 구현했는지를 여기서 한 번 정리하고 넘어가도록 해볼 것이다.
1. 움직이는 것을 구현.
일단 이 게임프로젝트에서 가장 중요한 것은 main -> render -> update가 계속해서 돌아 간다는 것이다.
function main() {
if (!gameover) {
update();
render();
requestAnimationFrame(main);
} else {
ctx.drawImage(finish, 400, 200, 300, 300);
}
}
loadImg();
main();
이런 식으로 말이다.
그러면 왼쪽 오른쪽 움직이는 것을 어떻게 구현할까??
왼쪽 키보드를 누르면 왼쪽으로 가고 오른쪽 키보드를 누르면 오른쪽으로 가게끔 하는 건 일단
왼쪽 키보드를 누를때 움직이려는 대상의 X값을 -(마이너스) 하면 될 것이고 오른쪽 키보드를 누를 때 X값을 +(플러스) 하면 될 것이다.
function update() {
if ('ArrowRight' in keyDowns) {
if (rocketX == canvas.width - 60) {
return;
}
rocketX += 5;
}
if ('ArrowLeft' in keyDowns) {
if (rocketX == 0) {
return;
}
rocketX -= 5;
}
}
이런식으로 말이다. 그러면 이제 이 update 함수가 위의 main 함수에서 계속 호출이 되기 때문에 움직이는 것처럼 보일 것이다.
2. 총알을 발사 구현.
움직이는 것을 구현 했으니 총알 발사도 알아보자. 일단 총알 발사는 spacebar를 누르면 나간다고 설정해야 한다. 그러면 EventListener를 통해서 key가 눌러졌을 때 동작을 하도록 해야 겠다.
let keyDowns = {};
function setupKeyBoardListener() {
document.addEventListener('keydown', event => {
keyDowns[event.key] = true;
});
document.addEventListener('keyup', event => {
delete keyDowns[event.key];
if (event.key === ' ') {
console.log('spacebar 입력');
createBullet();
}
});
}
여기서 keyDowns 객체를 만들어서 keydown을 할 때 값을 추가하고 keyup이 일어날 때 삭제해주는 코드가 있는데 이렇게 해주지 않으면 물체가 계속 오른쪽으로 가거나 왼쪽으로 가기 때문에 이런 설정을 해준 것이다.
keyup에서 spacebar를 눌렀을 때 createBullet 함수가 호출되게 한 것은 만약 keydown에서 호출하면 createBullet이 계속 연속적으로 호출 되서 총알이 마치 한 줄 처럼 나가기 때문에 keyup에서 설정해 줬다.
let bulletList = [];
function createBullet() {
let b = new Bullet();
console.log(bulletList);
b.init();
}
function Bullet() {
this.x = 0;
this.y = 0;
this.init = () => {
this.x = rocketX + 20;
this.y = rocketY - 20;
};
this.alive = true;
bulletList.push(this);
this.update = () => {
this.y -= 7;
};
this.checkhit = () => {
for (let i = 0; i < enemyList.length; i++) {
if (this.y <= enemyList[i].y && this.x >= enemyList[i].x && this.x <= enemyList[i].x + 64) {
score++;
this.alive = false;
enemyList.splice(i, 1);
}
}
};
}
이제 Bullet에 대해서 보면 일단 Bullet 함수는 클래스처럼 보인다. 그래서 이 안에서 bullet의 좌표들과 처음 생성될 때의 위치 그리고 this.update를 통해서 Bullet의 이동까지 할 수 있게 했다. 이제 이 Bullet 함수를 구현만 하면 된다.
createBullet에서 이를 구현해서 update 함수에서 구현 하기만 하면 끝
function update() {
if ('ArrowRight' in keyDowns) {
if (rocketX == canvas.width - 60) {
return;
}
rocketX += 5;
}
if ('ArrowLeft' in keyDowns) {
if (rocketX == 0) {
return;
}
rocketX -= 5;
}
for (let i = 0; i < bulletList.length; i++) {
if (bulletList[i].alive) {
bulletList[i].update();
bulletList[i].checkhit();
}
}
}
3. 적 출현 구현
적을 구현 하는 것은 Bullet 총알을 구현 하는 것과 비슷하다. 초기 위치를 잡아주고 나타나게 하고 생성해서 계속해서 자동적으로 update를 통해서 y값에 변화를 주면 된다. 하지만 여기서 좀 다르게 생각해야 할 것이 있다.
일단
1) 적 출현 즉 적의 위치가 랜덤하게 나타난다는 것이다.
2) 적이 이제 맨 밑에 즉 우주선이 있는 위치까지 오면 게임이 끝나야 한다는 것.
let enemyList = [];
let gameover = false;
function Enemy() {
this.x = 0;
this.y = 0;
this.init = () => {
this.x = randomEnemyPosition(0, canvas.width - 64);
this.y = 0;
};
this.update = () => {
this.y += 2;
if (this.y >= canvas.height - 64) {
gameover = true;
}
};
enemyList.push(this);
}
function randomEnemyPosition(min, max) {
let position = Math.floor(Math.random() * (max - min) + min);
return position;
}
function createEnemy() {
let interval = setInterval(() => {
let enemy = new Enemy();
enemy.init();
}, 1000);
}
Enemy( ) 함수를 만들어서 적의 위치 값을 잡아준다. 여기서 randomEnemyPosition( ) 함수를 통해서 Enemy의 출현 위치를 랜덤하게 잡아준다. gameover 라는 변수를 만들어서 Enemy의 y값이 화면의 y값보다 클 시 true가 되게 끔해서 game을 끝내도록 한다.
createEnemy( ) 함수를 통해서 적을 생성해 주는데 여기서 이게 계속해서 생성되어야 하기 때문에 setInterval( ) 함수를 이용해준다. setInterval( ) 함수는 지정한 시간 마다 해당 함수를 계속해서 호출해 주는 함수이다. 여기서 1초마다 계속해서 Enemy함수를 계속 해출 해주도록 했다.
function update() {
if ('ArrowRight' in keyDowns) {
if (rocketX == canvas.width - 60) {
return;
}
rocketX += 5;
}
if ('ArrowLeft' in keyDowns) {
if (rocketX == 0) {
return;
}
rocketX -= 5;
}
for (let i = 0; i < bulletList.length; i++) {
if (bulletList[i].alive) {
bulletList[i].update();
bulletList[i].checkhit();
}
}
for (let i = 0; i < enemyList.length; i++) {
enemyList[i].update();
}
}
이제 업데이트에 enemyList에 있는 것을 불러내기만 하면 계속해서 적이 보이게 된다.
4. 총알에 닿으면 적이 없어지는 것 구현.
이건 위에 Bullet을 만드는 코드에 보면 checkhit라는 함수를 만들어놨었다.
let bulletList = [];
function createBullet() {
let b = new Bullet();
console.log(bulletList);
b.init();
}
function Bullet() {
this.x = 0;
this.y = 0;
this.init = () => {
this.x = rocketX + 20;
this.y = rocketY - 20;
};
this.alive = true;
bulletList.push(this);
this.update = () => {
this.y -= 7;
};
this.checkhit = () => {
for (let i = 0; i < enemyList.length; i++) {
if (this.y <= enemyList[i].y && this.x >= enemyList[i].x && this.x <= enemyList[i].x + 64) {
score++;
this.alive = false;
enemyList.splice(i, 1);
}
}
};
}
여기서 checkhit 함수가 이제 총알과 적이 닿으면 없어지도록 만든 함수이다. 이걸 이제 update문에서 불러서 계속 check하게끔 불러내면 된다.
따라해보면서 참 신기하고 재밌었다.
기초적으로 게임이 어떻게 만들어지는 가를 조금 배울 수 있었고 자바스크립트의 기초, 그리고 좌표에 대한 이해 등을 배울수 있는 아주 좋은 시간들이었다.
아래의 영상으로 가서 한 번 보고 따라해 보는 것이 정말 좋은 것 같다!!
https://www.youtube.com/watch?v=TJmvuyt6tT8
'Javascript' 카테고리의 다른 글
Array.includes에 대하여 (0) | 2025.02.09 |
---|---|
스프레드 연산자(...) Javascript (0) | 2023.12.24 |
Array.sort를 쓸 때 주의사항(Javascript) (0) | 2023.10.26 |
모든 제이쿼리 코드를 자바스크립트로 바꿀 순 없나??? (0) | 2022.12.28 |