Phaser 사용법 2 - Scene1.js

2022. 2. 13. 11:12Technology[Front]

앞선 게시글에서 Phaser의 설정을 관리하는 config.js에서 scene에 사용하는 js파일로 입력해놓은 Scene1.js를 알아보겠습니다. 해당 js파일은 웹환경에서 Phaser 라이브러리를 사용하여 2D 게임맵을 구현한 js파일입니다.

 

(1) Scene1.js

class Scene1 extends Phaser.Scene {
    constructor() {
        super("Scene1");
        // 처음 실행 시 시작위치 x, y 초기화
        this.location_x = 1300;
        this.location_y = 500;
}

init(data) {
	// 추후 data를 포함하여 호출 시 해당 data의 값으로 시작위치 x, y 초기화
    if(Number.isInteger(data.x) && Number.isInteger(data.y)) {
        this.location_x = data.x;
        this.location_y = data.y;
    }
}

// 이미지 로딩
preload () 
{   
    //배경맵 이미지 로드
    this.load.image('map1', 'assets/Sample1.png');
    this.load.image('ground', 'assets/안보임0.png');
    //캐릭터, npc, 포탈 등 이미지 로드
    this.load.spritesheet('potal', 'assets/potal.png',{ frameWidth: 89 , frameHeight: 248  });
    this.load.spritesheet('dude1', 'assets/남자캐릭터 스탠드 왼쪽.png',{ frameWidth: 59, frameHeight: 69  });
    this.load.spritesheet('admin1', 'assets/궁수전직.png',{ frameWidth: 78, frameHeight:80});
	//음악 로드
    this.load.audio("music", "")
}

//맵 만들기
create (){
    //화면멈춤 설정
    this.pause = false;
    //캐릭터 초기 방향 설정
    this.facing = 'left';
    //카메라 바운드 설정
    this.cameras.main.setBounds(1010, -690, 5380, 10000);

	//맵 이미지 (가로위치,세로위치,url), 맵 바운드 설정
    this.add.image (3700, 50, 'map1');
    this.physics.world.setBounds( 1000, -5000, 5420 , 10000);

	//장애물 그룹 만들기
	this.platformsG = this.physics.add.staticGroup({
        collideWorldBounds: true
    });
    this.platformsB = this.physics.add.staticGroup({
        collideWorldBounds: true
    });
    this.platforms = this.physics.add.staticGroup({
        collideWorldBounds: false
    });

    //장애물 설정 후 그룹에 할당
    for(var j = 1000; j < 6500; j += 1250) {
        this.platformsG.create(j, 590, 'ground').setScale(10).refreshBody(); // 가장 밑바닥 땅 
    }
    this.platformsB.create(5412, 305, 'ground').setScale(1).refreshBody(); // Sample collider

    //캐릭터 설정
    this.player = this.physics.add.sprite(this.location_x, this.location_y, 'dude1');
    this.player.depth = 100; //캐릭터 레이어를 앞으로 설정
    this.player.setBounce(0); //땅에 닿았을때 다시 튀어오르는 정도
    this.player.setCollideWorldBounds(true); //맵 밖으로 안나가게 
    this.player.body.setGravityY(1000) //캐릭터 중력설정
    this.player.setScale(1,1); // 크기 설정
    this.physics.add.collider(this.player, this.platformsG); //ground블럭과 충돌여부 
    this.colliderB = this.physics.add.collider(this.player, this.platformsB); //collider블럭과 충돌여부
    //this.player.body.setCircle(30); //캐릭터 외곽 둥글게
    //왼쪽으로
	this.anims.create({
    key: 'left', //key값 설정 
    frames: this.anims.generateFrameNumbers('dude3', { start: 0, end: 3 }), //재생할 프레임 선택 
    frameRate: 5, //프레임 재생속도
    repeat: -1 //반복
	});
    
   	//포탈 설정 setImmovable() -> 충돌에도 움직이지 않음
    this.potal1 = this.physics.add.sprite(5034, -380,'potal').setImmovable(); 
    this.potal1.body.setGravityY(-300) //포탈 중력설정
    //포탈 움직임---------------
    this.anims.create({ 
    key: 'potal',
    frames: this.anims.generateFrameNumbers('potal', { start: 0, end: 7 }), //프레임 선택 
    frameRate: 13, //프레임 재생속도
    repeat: -1  //반복
    });
    this.potal1.anims.play('potal',true); //포탈 스프라이트 움직임 실행
    
    //npc 설정 setInteractive() -> 이벤트 설정 가능메서드 
    this.admin1 = this.physics.add.sprite(5060, 0, 'admin1').setInteractive(); // 운영자 -setInteractive() -> 이벤트 설정 가능메서드 
	this.admin1.body.setGravityY(-300) //운영자 중력설정
    this.physics.add.collider(this.admin1, this.platformsG); //ground블럭과 충돌여부 
    this.physics.add.collider(this.admin1, this.platformsB); //ground블럭과 충돌여부 
    this.admin1.setBounce(0); //땅에 닿았을때 다시 튀어오르는 정도
    this.admin1.setCollideWorldBounds(true); //맵 밖으로 안나가게 
     
    //운영자 움직임(gif로 움직임이 있을 때)--------------
    this.anims.create({ 
    key: 'admin1',
    frames: this.anims.generateFrameNumbers('admin1',{start:0,end:2}), //프레임 선택  
    frameRate: 5, //프레임 재생속도
    repeat: -1 //반복
     }
    );
    //운영자 움직임(jpg 등으로 움직임이 없을 때)--------------
   	//this.anims.create({ 
    //key: 'admin2',
    //frames: [ { key: 'admin2', frame: 0 } ], //재생할 프레임 선택
    // }
    //);
    //운영자 클릭시 대화 
    this.element1 = document.getElementById('input-box4'); // index.html에 있는 html태그 select
    //대화 켜기 (캐릭터 선택)
    this.admin1.on('pointerdown',()=>{
        this.pause = true; // 게임화면 멈춤
        if(this.element1 && this.element1.style.display === 'none') {
            this.element1.style.display = 'block'; // 숨겨놓은 대화창 block으로 화면출력
        } 
        })
        //끄는 버튼  (대화창 close 버튼)
        document.getElementById('btn4').addEventListener('click',()=>{ // index.html에 있는 html태그 select
          this.pause = false; // 게임화면 재생
          this.element1.style.display = 'none' // 화면출력된 대화창 none으로 숨김
        })
  	//대화 켜기 (팝업창 띄울 때)
    //this.admin6.on('pointerdown',()=>{
    //let width = 800;
    //let height = 600;
    //let top = (window.innerHeight - height) / 2 + screenY;
    //let left = (window.innerWidth - width) / 2 + screenX;
    //let spec = 'status=no, menubar=no, toolbar=no, resizable=no';
    //spec += ', width=' + width + ', height=' + height;
    //spec += ', top=' + top + ', left=' + left;
    //window.open('book.html', 'popup', spec); // book.html을 popup형식으로 화면띄움
    })  
    
    //아래점프시 충돌 설정 다시해줌
    this.timedEvent = this.time.addEvent({ delay: 500, callback: this.onEvent, callbackScope: this, loop: true });
    
    // 카메라 설정----------------------------------
    this.cameras.main.startFollow(this.player, true, 1, 1);//속도
    this.cameras.main.setZoom(1.7); // 줌 배율 
    this.cameras.main.setFollowOffset( 0, 120);
}


//반복문으로 움직임 구현 부분 ---------------------------------------------------------
update () {
	// 키보드 입력 변수 선언 및 초기화   createCursorKeys() 메서드엔 up down left light space shift 만 지정되어 있음 
    this.cursors = this.input.keyboard.createCursorKeys();
    this.space = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.SPACE); // alt 키 추가 
    this.ctrl = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.CTRL); 
    this.key_x = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.X); 
    this.key_w = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.W);
    
    var player = this.player;

	//player보다 아래에 있는 장애물은 통과불가(땅) & player보다 위에 있는 장애물은 통과가능(이동) 
    this.platforms.children.entries.forEach(element => {
        if(element.y < player.y + 30) {
            this.platformsB.remove(element);
            this.platforms.add(element);
        }
        else {
            this.platforms.remove(element);
            this.platformsB.add(element);
        }
    });
    this.platformsB.children.entries.forEach(element => {
        if(element.y < player.y + 30) {
            this.platformsB.remove(element);
            this.platforms.add(element);
        }
        else {
            this.platforms.remove(element);
            this.platformsB.add(element);
        }
    });

    //포탈에서 맵이동 구현(같은맵)-----------------
    if((this.player.x>=4670 && this.player.x <=4720 && this.player.y <= 427.5 && this.player.y >= 422.5  && this.player.body.touching.down)){ 
        if(this.cursors.up.isDown ){
            this.scene.start('Scene1', {x: 5034, y: -300}); //data를 함께 넘겨서 시작위치 설정
        }
    }
    //포탈에서 맵이동 구현(다른맵)-----------------
    if(this.player.x >= (this.potal3.x-40) && this.player.x <= (this.potal3.x+40) && this.player.y >=(this.potal3.y+30) && this.player.y <=(this.potal3.y+100) && this.player.body.touching.down){ 
        if(this.cursors.up.isDown ){
            this.scene.start('market');
        }
    }

	//키보드 & 방향키 조작 
    if (this.key_w.isDown) {
        //W키를 눌렀을 때 월드맵 팝업
        let width = 1000;
        let height = 600;
        let top = (window.innerHeight - height) / 2 + screenY;
        let left = (window.innerWidth - width) / 2 + screenX;
        let spec = 'status=no, menubar=no, toolbar=no, resizable=no';
        spec += ', width=' + width + ', height=' + height;
        spec += ', top=' + top + ', left=' + left;
        window.open('Worldmap.html', 'popup', spec);
    }
    else if (this.cursors.left.isDown) //왼쪽 (왼쪽방향키 누를시 실행)
        { if(this.pause)
            return;
            if(this.player.body.touching.down)
            this.player.anims.play('left', true); 
            this.player.setVelocityX(-250); //x축 속도 설정 
            this.facing ='left';// 캐릭터 방향 
        }
    else{ 
    	if(this.pause)
        	return;
        if(this.player.body.velocity.y < 0){
            this.colliderB.active = false; // 점프 시 장애물 무시
        }
        else{
            this.colliderB.active = true;
        }
        this.player.setVelocityX(0); //멈춤 (키보드 떼면 자동으로 실행)
            if(this.facing == 'left'){
                this.player.anims.play('stop',true);
            }else{
                this.player.anims.play('stopright',true);
        	}
        }
    }
}
onEvent =()=>
    {
    this.colliderB.active = true; // 혹시 장애물이 무시되어있었다면 true로 장애물 설정 복원
    }
}

위의 코드는 실제 프로젝트에서 일부 발췌한 코드로 실제 사용시 상황에 맞게 수정하여 사용하시면 됩니다. Phaser 라이브러리 사용 시 구현하는 땅, npc, 메인캐릭터, 장애물 충돌, 중력, 키보드 & 방향키 조작, 대화창 출력, 팝업창 띄우기, 맵 간 이동, 애니메이션 설정, 음악 설정, 이미지파일 적용, 맵 / 카메라 바운드 설정 등 대부분의 기능은 주석으로 설명하였으므로 위의 코드를 참고하여 Phaser 라이브러리를 사용하시면 됩니다.

 

이상으로 저번게시글에 걸쳐서 Phaser 라이브러리 사용법에 대해 알아보았습니다.