(2-5) [JS] shooting game 만들기

씩씩한 조약돌·2023년 1월 20일
0

미니프로젝트🤹

목록 보기
10/21
post-thumbnail

참고 영상 : https://youtu.be/c-NcYoTshHw (코딩알려주는누나)

5일차 내용

점수 계산하기
1. 총알이 적군에 닿으면 총알과 우주선이 없어짐
2. 총알이미지가 적군이미지에 닿으면 점수+1
: 총알.y <= 적군y && (총알.x >= 적군.x && 총알.x <= 적군.width)
(총알의 y좌표가 적군의 y값보다 같거나 작아지면)
&& (총알의 x좌표가 적군의 x좌표보다 같거나 크고 && 총알의 x좌표가 적군의 width보다 같거나 작으면)

1. 총알이 적군에 닿았는지 확인

1-1. checkHit()함수 생성

  • Bullet()함수에 넣어주기
  • EnemyList 갯수만큼 반복
  • if(총알의 y값이 적군의 y값보다 크거나 같으면
    /총알의 x값이 적군의 x값보다 크거나 같고
    /총알의 x값이 적군의 width보다 작거나 같으면)
let bulletList = [];
function Bullet() {
  this.x = 0;
  this.y = 0;
  this.init = function () {
    this.x = spaceshipX + 20;
    this.y = spaceshipY;

    bulletList.push(this);
  };

  this.update = function () {
    this.y -= 7;
  };

  //총알이 적군과 닿으면 처리할 내용
  this.checkHit = function () {
    for (let i = 0; i < enemyList.length; i++) {
      if (
        this.y <= enemyList[i].y &&
        this.x >= enemyList[i].x &&
        this.x <= enemyList[i].x + 40
      ) {
       
      }//if
    }//for
  }; //checkHit()
}

1-1. 총알이 적군에 닿이면 점수증가

  • score++ : 점수증가
let score = 0;

let bulletList = [];
function Bullet() {
  this.x = 0;
  this.y = 0;
  this.init = function () {
    this.x = spaceshipX + 20;
    this.y = spaceshipY;

    bulletList.push(this);
  };

  this.update = function () {
    this.y -= 7;
  };

  //총알이 적군과 닿으면 처리할 내용
  this.checkHit = function () {
    for (let i = 0; i < enemyList.length; i++) {
      if (
        this.y <= enemyList[i].y &&
        this.x >= enemyList[i].x &&
        this.x <= enemyList[i].x + 40
      ) {
        //점수추가
        score++;
      }
    }
  };
}

1-2. 총알이 적군에 닿이면 총알의 상태를 false

  • this.init()this.alive = true; 추가 : 총알이 닿이면 false로 바꿈
let score = 0;

let bulletList = [];
function Bullet() {
  this.x = 0;
  this.y = 0;
  this.init = function () {
    this.x = spaceshipX + 20;
    this.y = spaceshipY;
    this.alive = true; // 적군과 닿이면 false

    bulletList.push(this);
  };

  this.update = function () {
    this.y -= 7;
  };

  //총알이 적군과 닿으면 처리할 내용
  this.checkHit = function () {
    for (let i = 0; i < enemyList.length; i++) {
      if (
        this.y <= enemyList[i].y &&
        this.x >= enemyList[i].x &&
        this.x <= enemyList[i].x + 40
      ) {
        //점수추가
        score++;
        // 적군과 닿으면 false로 바꿔줌
        this.alive = false;
      }
    }
  };
}

1-3. 총알이 적군에 닿이면 총알 이미지가 사라짐

  • render()함수 수정
  • bulletList 배열갯수만큼 반복문
  • if(bulletList[i].alive()가 true이면 이미지 렌더링하기
  • false이면 렌더링을 하지않음 (= 이미지가 안보임)
function render() {
  ctx.drawImage(backgroundImage, 0, 0, canvas.width, canvas.height);
  ctx.drawImage(mainImage, spaceshipX, spaceshipY, 64, 64);
  // ctx.fillText(`Score:${score}`, 20, 20);
  // ctx.fillStyle = "white";
  // ctx.font = "20px Arial";

  //bulletLIst[i].alive가 true일때만 총알이미지 보여주기
  for (let i = 0; i < bulletList.length; i++) {
    if (bulletList[i].alive) {
      ctx.drawImage(bulletImage, bulletList[i].x, bulletList[i].y, 25, 25);
    }
  }
  for (let i = 0; i < enemyList.length; i++) {
    ctx.drawImage(enemyImage, enemyList[i].x, enemyList[i].y, 40, 40);
  }
}

1-4. 총알이 적군에 닿이면 적군이 없어짐

  • splice() : 배열의 기존 요소를 삭제 또는 교체하거나 새 요소를 추가하여 배열의 내용을 변경 (원본 배열 자체를 수정)
  • enemyList.splice(i, 1); : i번째 요소 1개를 삭제
let bulletList = [];
function Bullet() {
  this.x = 0;
  this.y = 0;
  this.init = function () {
    this.x = spaceshipX + 20;
    this.y = spaceshipY;
    this.alive = true; // 적군과 닿이면 false

    bulletList.push(this);
  };

  this.update = function () {
    this.y -= 7;
  };

  //총알이 적군과 닿으면 처리할 내용
  this.checkHit = function () {
    for (let i = 0; i < enemyList.length; i++) {
      if (
        this.y <= enemyList[i].y &&
        this.x >= enemyList[i].x &&
        this.x <= enemyList[i].x + 40
      ) {
        //점수추가
        score++;
        // 적군과 닿으면 false로 바꿔줌
        this.alive = false;
        // 우주선 없애기
        enemyList.splice(i, 1);
      }
    }
  };
}

1-5. checkHit()함수 호출

  • update()함수 수정
  • 총알배열의 i요소를 update()y좌표 업데이트하면서 checkHit()적군과 닿으면 점수추가/alive=false/우주선삭제해줌
function update() {
  if (39 in keysDown) {
    spaceshipX += 5;
  } // right

  if (37 in keysDown) {
    spaceshipX -= 5;
  } //left

  if (spaceshipX <= 0) {
    spaceshipX = 0;
  }
  if (spaceshipX >= canvas.width - 64) {
    spaceshipX = canvas.width - 64;
  }

  // 총알의 y좌표 업데이트 하는 함수
  for (let i = 0; i < bulletList.length; i++) {
      bulletList[i].update();
      bulletList[i].checkHit();
  }


-> 총알 1개에 적군 2개가 사라짐

1-6. bulletList[i].alive=true일때만 update()되도록 수정

  • if (bulletList[i].alive)
function update() {
  if (39 in keysDown) {
    spaceshipX += 5;
  } // right

  if (37 in keysDown) {
    spaceshipX -= 5;
  } //left

  if (spaceshipX <= 0) {
    spaceshipX = 0;
  }
  if (spaceshipX >= canvas.width - 64) {
    spaceshipX = canvas.width - 64;
  }

  // 총알의 y좌표 업데이트 하는 함수
  for (let i = 0; i < bulletList.length; i++) {
    if (bulletList[i].alive) {
      bulletList[i].update();
      bulletList[i].checkHit();
    }
  }

  // 적군의 y좌표 업데이트 하는 함수
  for (let i = 0; i < enemyList.length; i++) {
    enemyList[i].update();
  }
}

2. 점수 계산하기

2-1. 점수판 생성

  • render()함수에 추가
  • fillText(넣어줄 텍스트, x좌표, y좌표)
  • fillStyle = 색깔
  • font
function render() {
  ctx.drawImage(backgroundImage, 0, 0, canvas.width, canvas.height);
  ctx.drawImage(mainImage, spaceshipX, spaceshipY, 64, 64);
  ctx.fillText(`Score:${score}`, 20, 20);
  ctx.fillStyle = "white";
  ctx.font = "20px Arial";

  //bulletLIst[i].alive가 true일때만 총알이미지 보여주기
  for (let i = 0; i < bulletList.length; i++) {
    if (bulletList[i].alive) {
      ctx.drawImage(bulletImage, bulletList[i].x, bulletList[i].y, 25, 25);
    }
  }
  for (let i = 0; i < enemyList.length; i++) {
    ctx.drawImage(enemyImage, enemyList[i].x, enemyList[i].y, 40, 40);
  }
}


전체 코드

// 1. Canvas 세팅
let canvas;
let ctx;

canvas = document.createElement("canvas");
ctx = canvas.getContext("2d");
canvas.width = 400;
canvas.height = 700;
document.body.appendChild(canvas);

// 2. image 가져오기
let backgroundImage, mainImage, bulletImage, enemyImage, gameOverImage;

let gameOver = false; // false는 게임진행중, true는 게임이 끝남 (우주선이 바닥에 닿으면 끝)
let score = 0;

//주인공 좌표
let spaceshipX = canvas.width / 2 - 32;
let spaceshipY = canvas.height - 64;

let bulletList = [];
function Bullet() {
  this.x = 0;
  this.y = 0;
  this.init = function () {
    this.x = spaceshipX + 20;
    this.y = spaceshipY;
    this.alive = true; // 적군과 닿이면 false

    bulletList.push(this);
  };

  this.update = function () {
    this.y -= 7;
  };

  //총알이 적군과 닿으면 처리할 내용
  this.checkHit = function () {
    for (let i = 0; i < enemyList.length; i++) {
      if (
        this.y <= enemyList[i].y &&
        this.x >= enemyList[i].x &&
        this.x <= enemyList[i].x + 40
      ) {
        //점수추가
        score++;
        // 적군과 닿으면 false로 바꿔줌
        this.alive = false;
        // 우주선 없애기
        enemyList.splice(i, 1);
      }
    }
  };
}

function generateRandomValue(min, max) {
  let randomNum = Math.floor(Math.random() * (max - min + 1)) + min;
  return randomNum;
}

let enemyList = [];
function Enemy() {
  this.x = 0;
  this.y = 0;
  this.init = function () {
    this.x = generateRandomValue(0, canvas.width - 48); //랜덤으로 시작
    this.y = 0; //최상단에서 시작

    enemyList.push(this);
  };
  //적군의 y좌표 변경
  this.update = function () {
    this.y += 3;

    if (this.y >= canvas.height - 40) {
      gameOver = true;
      //console.log("Game Over");
    }
  };
}

function loadImage() {
  backgroundImage = new Image();
  backgroundImage.src = "images/background.jpg";

  mainImage = new Image();
  mainImage.src = "images/main.png";

  bulletImage = new Image();
  bulletImage.src = "images/bullet.png";

  enemyImage = new Image();
  enemyImage.src = "images/enemy.png";

  gameOverImage = new Image();
  gameOverImage.src = "images/gameover.jpg";
}

//방향키 누르면
let keysDown = {};
function setupKeyboardListener() {
  document.addEventListener("keydown", function (event) {
    //console.log("무슨 키가 눌렸어?", event.keyCode);

    keysDown[event.keyCode] = true;
    //console.log("KeysDown =", keysDown);
  });

  document.addEventListener("keyup", function (event) {
    delete keysDown[event.keyCode];
    //console.log("버튼 클릭 후 = ", keysDown);

    if (event.keyCode == 32) {
      //32 : spacebar
      createBullet(); //총알 생성
    }
  });
}

function createBullet() {
  //console.log("총알 생성");
  let b = new Bullet(); // 총알 1개 생성
  b.init();
  console.log("총알 리스트 : ", bulletList);
}

function createEnemy() {
  const interval = setInterval(function () {
    let e = new Enemy();
    e.init();
  }, 1000);
}

// 우주선의 xy좌표가 바뀌고
function update() {
  if (39 in keysDown) {
    spaceshipX += 5;
  } // right

  if (37 in keysDown) {
    spaceshipX -= 5;
  } //left

  if (spaceshipX <= 0) {
    spaceshipX = 0;
  }
  if (spaceshipX >= canvas.width - 64) {
    spaceshipX = canvas.width - 64;
  }

  // 총알의 y좌표 업데이트 하는 함수
  for (let i = 0; i < bulletList.length; i++) {
    if (bulletList[i].alive) {
      bulletList[i].update();
      bulletList[i].checkHit();
    }
  }

  // 적군의 y좌표 업데이트 하는 함수
  for (let i = 0; i < enemyList.length; i++) {
    enemyList[i].update();
  }
}

function render() {
  ctx.drawImage(backgroundImage, 0, 0, canvas.width, canvas.height);
  ctx.drawImage(mainImage, spaceshipX, spaceshipY, 64, 64);
  ctx.fillText(`Score:${score}`, 20, 20);
  ctx.fillStyle = "white";
  ctx.font = "20px Arial";

  //bulletLIst[i].alive가 true일때만 총알이미지 보여주기
  for (let i = 0; i < bulletList.length; i++) {
    if (bulletList[i].alive) {
      ctx.drawImage(bulletImage, bulletList[i].x, bulletList[i].y, 25, 25);
    }
  }
  for (let i = 0; i < enemyList.length; i++) {
    ctx.drawImage(enemyImage, enemyList[i].x, enemyList[i].y, 40, 40);
  }
}

function main() {
  if (!gameOver) {
    update(); // 좌표값 업데이트
    render(); //그려주기
    requestAnimationFrame(main);
    //console.log("anmiation calls");
  } else {
    ctx.drawImage(gameOverImage, 10, 100, 380, 380);
  }
}

loadImage();
setupKeyboardListener();
createEnemy();
main();

5일차 후기

1. 코드 정리

  • checkHit() : 총알이미지가 적군이미지와 겹치면 / score++ / alive=false / enemyList.splice(i,1)
  • `bulletList[i].alive=true일때 / 이미지 렌더링 / y좌표업데이트 / checkHit()
  • 점수판생성

2. 지금까지 배운 배열, 반복문, 함수를 이용해서 실제로 작동시킬 수 있는 프로그램을 만들어 흥미로웠다.

3. 깃허브로 게임 배포 : https://apebstr.github.io/

4. 아래 내용 추가하기 !!! !


❗추가하기

  • 총알 y좌표 max값 설정(캔버스 밖에서 적군 잡지 않도록)
  • gameover 이미지 수정
  • 조작버튼 만들기 (키보드 또는 마우스로 할 수 있도록)
  • 닷홈 또는 깃허브로 사이트 배포
profile
씩씩하게 공부중 (22.11~)

0개의 댓글