JavaScript로 게임 만들기 - 9

Fantazindy·2022년 4월 12일
0

JSFightGame

목록 보기
10/12

이번 포스팅에선 enemy를 구성해보자 player와 기본적으로 같은 구조이므로 player에서 썼던 것들을 그대로 가져오자.

const enemy = new Fighter({
  position: {
    x: 400,
    y: 100,
  },
  velocity: {
    x: 0,
    y: 0,
  },
  color: "red",
  offset: {
    x: 50,
    y: 0,
  },
  imageSrc: "./img/kenji/Idle.png",
  framesMax: 4,
  scale: 2.5,
  offset: {
    x: 215,
    y: 157,
  },
  sprites: {
    idle: {
      imageSrc: "./img/kenji/Idle.png",
      framesMax: 4,
    },
    run: {
      imageSrc: "./img/kenji/Run.png",
      framesMax: 8,
    },
    jump: {
      imageSrc: "./img/kenji/Jump.png",
      framesMax: 2,
    },
    fall: {
      imageSrc: "./img/kenji/Fall.png",
      framesMax: 2,
    },
    attack1: {
      imageSrc: "./img/kenji/Attack1.png",
      framesMax: 4,
    },
  },
});
...
function animate() {
  window.requestAnimationFrame(animate);
  ...
  enemy.update();

각각의 파일명과 framesMax만 맞게 수정해 주고 주석처리를 풀어주면

땅에 좀 가라앉아 있으니 position을 좀 수정해주고 player와 동일하게 animate메소드 부분을 수정해주면 된다.

  //enemy movement
  if (keys.ArrowLeft.pressed && enemy.lastKey === "ArrowLeft") {
    enemy.velocity.x = -4;
    enemy.switchSprite("run");
  } else if (keys.ArrowRight.pressed && enemy.lastKey === "ArrowRight") {
    enemy.velocity.x = 4;
    enemy.switchSprite("run");
  } else {
    enemy.switchSprite("idle");
  }

  //jump
  if (enemy.velocity.y < 0) {
    enemy.switchSprite("jump");
  } else if (enemy.velocity.y > 0) {
    enemy.switchSprite("fall");
  }


그런데 캐릭터의 공격이 동작하지 않는데 확인을 위해 attackBox를 다시 표시해보자.

  update() {
    ...
    c.fillRect(
      this.attackBox.position.x,
      this.attackBox.position.y,
      this.attackBox.width,
      this.attackBox.height
    );


아니나 다를까 이상한 위치에 있었다.
Fighter 클래스에서 attackBox를 다시 잡아주자고

class Fighter extends Sprite {
  constructor({
    ...
    attackBox = { offset: {}, width: undefined, height: undefined },
  }) {
    ...
    this.attackBox = {
      position: {
        x: this.position.x,
        y: this.position.y,
      },
      offset: attackBox.offset,
      width: attackBox.width,
      height: attackBox.height,
    };

player와 enemy에 값을 넣어주고 refresh해가면서 값을 조정하자

const player = new Fighter({
  ...
  attackBox: {
    offset: {
      x: -80,
      y: 0,
    },
    width: 178,
    height: 150,
  },
});

y값이 조정이 안되었는데 update메소드에 y offset 적용을 안했었다 적용해주자.

update() {
    this.draw();
    this.animateFrames();

    //attack box
    this.attackBox.position.x = this.position.x - this.attackBox.offset.x;
    this.attackBox.position.y = this.position.y - this.attackBox.offset.y;


합리적인 공격범위가 완성되었다.
그런데 공격해보면 키를 누르자마자 그러니까 공격모션이 닿지도 않았는데 체력이 닳는다.
공격프레임 중간에 체력이 닳도록 하자

  //detect collision
  if (
    rectangularCollision({ rectangle1: player, rectangle2: enemy }) &&
    player.isAttacking && player.framesCurrent === 4
  ) {
    player.isAttacking = false;
    enemy.health -= 20;
    document.querySelector("#enemyHealth").style.width = enemy.health + "%";
    console.log("player attack");
  }

플레이어의 공격중 현재 프레임이 4프레임 일때 충돌이 일어나도록 하면 된다.
그런데 이 경우 데미지가 아예 들어가지 않는데 프레임이 도는 시간이 attack메소드에 setTimeout한 시간보다 길기때문에 공격판정이 일어나기 전에 isAttacking이 false가 되기 때문이다.

  attack() {
    this.switchSprite("attack1");
    this.isAttacking = true;
  }

타임아웃을 지우면 또 문제가 생기는데 허공에 공격을 한 뒤 attackBox가 닿으면 또 데미지가 들어간다.
플레이어가 공격을 맞추지 못했을 때의 경우도 잡아주자.

  //if player misses
  if (player.isAttacking && player.framesCurrent === 4) {
    player.isAttacking = false;
  }

위 과정을 enemy쪽에도 동일하게 해주면

판정이 모션에 잘 맞는다.

이제 참고차 그려둔 attackBox를 지워주면 된다.

다음 포스팅에선 피격시 애니메이션을 추가해보자.

profile
풀스택 개발자를 목표로 성장중입니다!

0개의 댓글