JavaScript로 게임 만들기 - 9

Fantazindy·2022년 4월 12일
0

JSFightGame

목록 보기
9/12

달릴때의 이미지를 구성하기 위해 먼저 가만히 있을때와 달릴때의 상태를 구분해야 한다 이는 이후 만들 점프 등 다양한 동작에도 해당한다.

class Fighter extends Sprite {
  ...
    offset = { x: 0, y: 0 },
  }) {
    super({
      ...
    });

    ...
    this.sprites = sprites;

    for (const sprite in sprites) {
      sprites[sprite].image = new Image();
      sprites[sprite].image.src = sprites[sprite].imageSrc;
    }
    console.log(this.sprites);
  }
const player = new Fighter({
  ...
  sprites: {
    idle: {
      imageSrc: "./img/samuraiMack/Idle.png",
      framesMax: 8,
    },
    run: {
      imageSrc: "./img/samuraiMack/Run.png",
      framesMax: 8,
      image: new Image(),
    },
  },
});

동작을 구분할 sprites를 만들어주고 player에 sprite로 각 상태를 정해주어 clg로 출력해보았다.

Idle과 run 둘 다 잘 받아온다.
이제 a를 눌렀을 때 이미지를 run이미지로 바꿔주도록 하면

  //player movement
  if (keys.a.pressed && player.lastKey === "a") {
    player.velocity.x = -4;
    player.image = player.sprites.run.image;
  } else if (keys.d.pressed && player.lastKey === "d") {
    player.velocity.x = 4;
    player.image = player.sprites.run.image;
  }


달리는 애니메이션이 나온다.
그런데 키를 떼어도 계속 달리는 애니메이션만 나오는데

  //player movement
  player.image = player.sprites.idle.image;
  if (keys.a.pressed && player.lastKey === "a") {
  ...

기본 동작으로 Idle을 설정해주면 된다.

다음으로 점프 모션을 만들자 sprites에 jump를 추가하고

  sprites: {
    ...
    jump: {
      imageSrc: "./img/samuraiMack/Jump.png",
      framesMax: 2,
    },
  },

체공중일때만 점프모션이 나오도록 하기 위해 조건문으로 이미지를 바꿔주도록 하자

  //player movement
  ...
  if (player.velocity.y < 0) {
    player.image = player.sprites.jump.image;
    player.framesMax = player.sprites.jump.framesMax;
  }


갑자기 분신술을 하는데 framesMax의 값이 잘못 전달되고있어서 그렇다.

Fighter class에 switchSprite메소드를 만들어 각각의 frameMax를 관리하자.

코드를 입력하세요

    switch (sprite) {
      case "idle":
        if (this.image !== this.sprites.idle.image) {
          this.image = this.sprites.idle.image;
          this.framesMax = this.sprites.idle.framesMax;
        }
        break;
      case "run":
        if (this.image !== this.sprites.run.image) {
          this.image = this.sprites.run.image;
          this.framesMax = this.sprites.run.framesMax;
        }
        break;
      case "jump":
        if (this.image !== this.sprites.jump.image) {
          this.image = this.sprites.jump.image;
          this.framesMax = this.sprites.jump.framesMax;
        }
        break;

      default:
        break;
    }
  }
  //player movement
  player.switchSprite("idle");
  if (keys.a.pressed && player.lastKey === "a") {
    player.velocity.x = -4;
    player.switchSprite("run");
  } else if (keys.d.pressed && player.lastKey === "d") {
    player.velocity.x = 4;
    player.switchSprite("run");
  }
  if (player.velocity.y < 0) {
    player.switchSprite("jump");
  }


이전보다 낫긴 하지만 점프할때 사라지는 현상이 있다.
달리기는 8프레임인데 점프는 2프레임이라 그런데 각각의 case마다 framesCurrent를 초기화해주면 된다.

  switchSprite(sprite) {
    switch (sprite) {
      case "idle":
        if (this.image !== this.sprites.idle.image) {
          this.image = this.sprites.idle.image;
          this.framesMax = this.sprites.idle.framesMax;
          this.framesCurrent = 0;
        }
        break;
      case "run":
        if (this.image !== this.sprites.run.image) {
          this.image = this.sprites.run.image;
          this.framesMax = this.sprites.run.framesMax;
          this.framesCurrent = 0;
        }
        break;
      case "jump":
        if (this.image !== this.sprites.jump.image) {
          this.image = this.sprites.jump.image;
          this.framesMax = this.sprites.jump.framesMax;
          this.framesCurrent = 0;
        }
        break;

      default:
        break;
    }

좌우로 움직일때에도 모션이 이상한데

기본 동작인 player.switchSprite("idle")를 전역으로 두지 않고 else로 빼주면 해결된다.

  //player movement
  if (keys.a.pressed && player.lastKey === "a") {
    player.velocity.x = -4;
    player.switchSprite("run");
  } else if (keys.d.pressed && player.lastKey === "d") {
    player.velocity.x = 4;
    player.switchSprite("run");
  } else {
  player.switchSprite("idle");
  }
  if (player.velocity.y < 0) {
    player.switchSprite("jump");
  }


이제 떨어질때의 애니메이션을 적용하자 앞의 점프와 거의 유사한 과정이다.

  sprites: {
    ...
    fall: {
      imageSrc: "./img/samuraiMack/Fall.png",
      framesMax: 2,
    },
  },
});
switchSprite(sprite) {
    switch (sprite) {
      ...
      case "fall":
        if (this.image !== this.sprites.fall.image) {
          this.image = this.sprites.fall.image;
          this.framesMax = this.sprites.fall.framesMax;
          this.framesCurrent = 0;
        }
        break;

      default:
        break;
    }
  }
  //player movement
  ...
  if (player.velocity.y < 0) {
    player.switchSprite("jump");
  } else if (player.velocity.y > 0) {
    player.switchSprite("fall");
  }


이제 공격 모션을 적용시켜보자.
이것 역시 이전과 유사한데

  sprites: {
    ...
    attack1: {
      imageSrc: "./img/samuraiMack/Attack1.png",
      framesMax: 6,
    },
  },
switchSprite(sprite) {
    switch (sprite) {
      ...
      case "attack1":
        if (this.image !== this.sprites.attack1.image) {
          this.image = this.sprites.attack1.image;
          this.framesMax = this.sprites.attack1.framesMax;
          this.framesCurrent = 0;
        }
        break;

      default:
        break;
    }
  }

sprites와 case를 추가하고 이벤트 리스너를 보면 스페이스바를 누를때 attack 메소드를 호출하고 있다.

window.addEventListener("keydown", (event) => {
  //player key
  switch (event.key) {
    ...
    case " ":
      player.attack();
      break;

attack 메소드 내에서 switchSprite를 호출해주면

  attack() {
    this.switchSprite("attack1");
    this.isAttacking = true;
    setTimeout(() => {
      this.isAttacking = false;
    }, 100);
  }


뭔가 움찔움찔하기만 하고 공격하지 않는다.
아까 기본값으로 Idle을 설정해 주었기 때문에 attack이 실행되자마자 idle로 돌아가기 때문이다.
attack상태일 때는 이를 무시하도록 하면

  switchSprite(sprite) {
    if (this.image === this.sprites.attack1.image) return;
    switch (sprite) {
      ...


스페이스바를 누르지 않았는데도 계속 공격하는데 현재 동작중인 프레임을 공격 프레임의 -1만큼 일떄 라는 조건을 추가하면

  switchSprite(sprite) {
    if (
      this.image === this.sprites.attack1.image &&
      this.framesCurrent < this.sprites.attack1.framesMax - 1
    )
      return;

한번만 공격하고 다시 아래 switch문으로 넘어가면서 해결된다.

다음 포스팅에선 잠시 숨겨두었던 enemy를 다시 다뤄보자

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

0개의 댓글