티스토리 뷰

흥미/phaser

#12 움직이는 Player 1

RadderNepa 2023. 5. 16. 01:46

● 도입

- 하나의 class(=scene)에서 함수가 실행되는 순서

- init은 constructor function을 의미한다.  /  마지막인 update function은 계속 반복해서 실행된다.

- 바로 이 update function에 사용자가 키보드를 눌렀을 때 player가 움직이도록 코드를 작성할 것이다.


● 움직이는 player 만들기

- PlayingScene.js에 update function을 만들어 캐릭터 움직임 관련 내용을 작성했다.

import Phaser from "phaser";
import Player from "../characters/Player";
import { setBackground } from "../utils/backgroundManager";

export default class PlayingScene extends Phaser.Scene {
    constructor() {
        super("playGame");
    }

    create() {
        // 사용할 sound들을 추가해놓는 부분
        // load function : 어떤 scene에서든 전역적으로 asset을 사용할 수 있도록 load (LoadingScene.js 참고)
        // add function  : 해당 scene에서 asset을 사용할 수 있도록 scene의 멤버 변수로 추가할 때 사용
        // cf) this.xxxx 에서 xxxx 자리에 적힌 것들이 멤버 변수들이다.
        this.sound.pauseOnBlur  = false;
        this.m_beamSound        = this.sound.add("audio_beam");
        this.m_scratchSound     = this.sound.add("audio_scratch");
        this.m_hitMobSound      = this.sound.add("audio_hitMob");
        this.m_growlSound       = this.sound.add("audio_growl");
        this.m_explosionSound   = this.sound.add("audio_explosion");
        this.m_expUpSound       = this.sound.add("audio_expUp");
        this.m_hurtSound        = this.sound.add("audio_hurt");
        this.m_nextLevelSound   = this.sound.add("audio_nextLevel");
        this.m_gameOverSound    = this.sound.add("audio_gameOver");
        this.m_gameClearSound   = this.sound.add("audio_gameClear");
        this.m_pauseInSound     = this.sound.add("audio_pauseIn");
        this.m_pauseOutSound    = this.sound.add("audio_pauseOut");

        // player를 m_player라는 멤버 변수로 추가
        // new Player(this) --> (Player class의 인스턴스 생성, 자기 자신(PlayingScene)을 scene으로 전달)
        this.m_player = new Player(this); // characters/Player.js

        // PlayingScene의 background 설정
        // 여기서 "background1"은 LoadingScene에서 load한 asset이다. --> this.load.image("background1", bgImg1);
        setBackground(this, "background1"); // backgroundManager.js의 함수

        // m_cursorKeys = 사용자 키보드 입력값을 받을 수 있는 변수
        // 입력값 = (up, down, left, right, space, shift)
        // ex) m_cursorKeys.left.isDown = 사용자가 왼쪽 방향키를 눌렀는지 여부
        this.m_cursorKeys = this.input.keyboard.createCursorKeys();
    }

    // 키보드 이벤트는 매 frame 마다 탐지를 해야하기 때문에 update function을 만들었다.
    update() {
        // movePlayerManager = 직접 만든 함수(phaser 내장 함수 아님)
        this.movePlayerManager(); // 매 순간 movePlayerManager function이 실행되는 것이다.
    }

    movePlayerManager() {
        if (this.m_cursorKeys.left.isDown
            || this.m_cursorKeys.right.isDown
            || this.m_cursorKeys.up.isDown
            || this.m_cursorKeys.down.isDown) {
                // 방향키가 눌리면 애니메이션 재생
                if (!this.m_player.m_moving) { // player가 움직이면 true / 멈춰있으면 false
                    // "player_anim"는 LoadingScene.js의 create function에 있다.
                    // 방향키에 손을 떼서 멈추기 직전까지 계속해서 아래 코드가 실행된다.(한 번 play 되면 계속해서 play 된다.)
                    this.m_player.play("player_anim"); // player_anim를 play 할 것이다.(재생할 것이다.)
                }
                this.m_player.m_moving = true;
        } else {
            // 방향키를 떼면 애니메이션 정지
            if (this.m_player.m_moving) {
                // "player_idle"는 LoadingScene.js의 create function에 있다.
                this.m_player.play("player_idle");
            }
            this.m_player.m_moving = false;
        }

        // vector 변수를 사용해 움직임 관리
        // x좌표와 y좌표가 '얼만큼 이동했는지'가 아니라 '어디로 이동하고 있는지를 관리하는 변수'이다.
        // (어디로 이동하고 있는지 = 어느 방향을 향하고 있는지)
        // 이것을 이용해 방향에 따른 캐릭터의 모습을 실시간으로 변경해줄 것이다.
        let vector = [0, 0]; // [x좌표 방향, y좌표 방향]

        // vector[0]은 (-1, 0, 1) 중 하나의 값만 갖는다.
        if(this.m_cursorKeys.left.isDown) {
            vector[0] += -1;
            // 이 값이 계속 누적돼서 -1, -2, -3, -4 ... 이렇게 되는게 아니다.
            // update function이 실행될때마다 movePlayerManager function도 실행되므로
            // vector 변수도 계속해서 [0, 0]으로 초기화 된다.
            // 따라서 사용자가 왼쪽 방향키를 누를 때마다 (vector[0] = -1)로 계속해서 값이 변경되는 것이지
            // -1 값이 누적되는게 아니다.
        } else if(this.m_cursorKeys.right.isDown) {
            vector[0] += 1;
        }

        // vector[1]도 (-1, 0, 1) 중 하나의 값만 갖는다.
        if(this.m_cursorKeys.up.isDown) {
            vector[1] += -1;
        } else if(this.m_cursorKeys.down.isDown) {
            vector[1] += 1;
        }

        // vector 변수를 player class의 move method의 parameter로 넘긴다.
        this.m_player.move(vector);
    }
}

- Player.js에 move function을 만들어 캐릭터 움직임 관련 내용을 작성했다.

import Phaser from "phaser";
import Config from "../Config";

// Player가 Arcade 물리엔진의 영향을 받도록 extends
export default class Player extends Phaser.Physics.Arcade.Sprite {
    // 어느 scene에 Player가 나올지 정해줘야 하므로 argument로 scene을 받는다.
    // 참고로 scene의 constructor는 parameter가 없다.
    constructor(scene) {
        // 화면의 가운데에 player를 추가
        // 마지막 "player" string이 identifier(식별자)이다. by LoadingScene.js
        super(scene, Config.width / 2, Config.height / 2, "player");

        // scene.add.existing : scene에 오브젝트 추가
        scene.add.existing(this);

        // scene.physics.add.existing : scene의 물리엔진에 오브젝트를 추가
        scene.physics.add.existing(this);

        // scale 프로퍼티를 조절해 크기 조절(디폴트: 1)
        this.scale = 2;

        // depth를 조절해 어떤 오브젝트가 앞에 오고 뒤에 올지 설정
        // CSS의 z-index와 비슷한 개념(디폴트: 0)
        this.setDepth(20); // 10단위로 조절하는게 좋다.

        // 해당 오브젝트가 물리적으로 어느정도의 면적을 차지할 지 설정하는 함수(디폴트는 이미지 사이즈)
        // 하지만 디폴트는 추후 몹을 추가했을 때 잘 부딪히는 느낌이 드므로 원본 이미지보다 약간 작게 설정
        this.setBodySize(28, 32);

        // 걷기 애니메이션 재생 여부를 위한 멤버 변수
        this.m_moving = false;
    }

    // player가 움직이도록 하는 함수
    move(vector) {
        console.log(vector);
        // player의
        // x좌표 = vector[0] * Player.PLAYER_SPEED 만큼,
        // y좌표 = vector[1] * Player.PLAYER_SPEED 만큼 움직인다.
        let PLAYER_SPEED = 10;

        console.log(this.x);
        this.x += vector[0] * PLAYER_SPEED; // player의 x좌표 위치 변경
        this.y += vector[1] * PLAYER_SPEED; // player의 y좌표 위치 변경
        // PLAYER_SPEED에서 SPEED 라는 단어 자체는 큰 의미가 없다.
        // 그저 방향키를 누를 때 (x좌표, y좌표)를 한 번에 얼만큼 이동하는지 결정하는 값이다.
        // 당연히 PLAYER_SPEED의 값이 클 수록 한 번에 변화되는 위치 값이 크므로 그만큼 SPEED가 빨라보이는 것이다.(그래서 변수 이름이 SPEED)

        // 캐릭터 이미지 원본은 왼쪽을 바라보고 있다.
        // flipX 프로퍼티는 boolean 값을 받아 x축 방향으로 뒤집혀있을지 아닐지를 설정한다.
        // player가 왼쪽으로 이동할 때는 flipX = false,
        // player가 오른쪽쪽으로 이동할 때는 flipX = true로 설정해 적절한 방향으로 캐릭터의 모습을 변경한다.
        if(vector[0] === -1) this.flipX = false;
        else if(vector[0] === 1) this.flipX = true;
    }
}

 

cf) createCursorKeys function API docs

https://newdocs.phaser.io/docs/3.55.2/Phaser.Types.Input.Keyboard.CursorKeys

 

Phaser.Types.Input.Keyboard.CursorKeys - Phaser 3 API Documentation (beta)

 

newdocs.phaser.io

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
글 보관함