본문 바로가기

html5 캔버스『시간,상태,동작구현』

by Recstasy 2020. 2. 14.

html5 canvas게임제작에서 초기 canvas DOM설정과 마우스 이벤트까지 마쳤다면, 본격적으로 시간, 상태 변화를 구현해야한다. 게임설계의 핵심은 다음 3가지 요소에 있다.


1] 시간 

2] 상태 

3] 동작 


게임세계는 현실과 같은 또다른 현실이다. 게임개발자는 창조주다. 게임 세상을 위해 시간을 만들어야하고, 시간에 따라 변하는 상태를 설계하고, 동작을 설정한다. 어떠한 게임도 '시간', '상태', '동작'을 벗어날 수 없다. 게임은 영상처럼 일방향적이지 않기 때문에 사용자의 입력을 받고 반응을 해야한다. 이를 위해 게임 전체를 관할하는 '절대 시간'이 존재하고, 각 개체들마다 자신만의 시간이 필요하다. 즉, 게임 속의 개체들은 능동적이다. 


1 refresh()메서드 || 시간

refresh()메서드는 현실 시간을 받는 활동을 반복함으로써 게임 시간 생성한다. init()메서드에서는 아래와 같이 Date.now()를 통해 게임이 시작되는 시간(단위.밀리초)을 저장한다.    


init(){

   this.lastTime = Date.now();

   this.score = 0;

   

   this.spawn();

   this.refresh();

   ....중략....

}


refresh()메서드는 다시 현재시간을 받고, init()메서드에서 받은 시간과의 '차이'를 update()메서드에 전달한다. 


refresh(){

   const now = Date.now();

   const delta = ( now - this.lastTime ) / 1000.0;

   const game = this;   


   this.update(delta);

   this.render();

   this.lastTime = now;


   requestAnimationFrame(function(){

          game.refresh();

   })

}


refresh()메서드에서 생성된 delta값은 게임 세계의 시간으로 사용된다. 가령, delta값이 게임 내의 특정 캐릭터에 적용되면 해당 캐릭터만의 시간이 된다. 게임 개발자는 해당 시간을 조절해서 특정 오브젝트의 상태변화를 만들어낸다. 이렇게 만들어진 시간은 게임 내 오브젝트들의 움직임(거리값)과 각종 물리값에 모두 적용할 수 있다. 



2 spawn()메서드 || 상태

상태변화는 게임의 난이도를 조절하고, 재미를 자아내는 핵심적인 요소다. 사용자의 입력에 따라 상태변화가 발생하지 않는다면 해당 게임은 죽은 것이나 다름없다. 상태변화 코드는 최근 인공지능과 빅데이터 덕분에 게임이 아닌 어플에서도 그 중요도가 높아졌다. 


현재 프로젝트에서는 꽃의 상태가 "생성", "유지", "삭제" 이 3가지로 변한다. 이를 위해 spawn()메서드에서 Sprite 인스턴스 객체를 생성하고, states(상태)값을 [{객체},{객체},....]형태로 입력한다.


...중략


spawn(){

   this.spawnLife = 0;

   const option = {

       context : this.context,

       img : this.spriteImg

         ...(중략)

       states : [{mode:'spawn',duration:0.4},{mode:'static',duration:1.0},{mode:'die',duration:0.5}]

   }

   const sprite = new Sprite(option);

   this.sprites.push(sprite);

}


배열 내부에 객체를 삽입하는 방식으로 상태를 작성하면, 시간에 따라 배열의 index값을 올려주는 것만으로 sprite인스턴스 객체의 state.mode가 변한다. 이제 sprite클래스의 내부는 update(delta)의 delta값을 통해 꽃의 상태를 변화시킬 수 있다.


class Sprite{

    constructor(opt){

  this.context = opt.context;

  this.img = opt.img;

  this.kill = false;

  this.state = 0;

  ...(중략)

    }


    get state(){

        let result;

         if(this.stateIndex < this.states.length) result = this.states[this.stateIndex]

        return result

    }


    set state(index){

        this.stateTime = 0;

        this.stateIndex = index;

    }


    update(dt){

       const state = this.state;

       this.stateTime += dt;

       const stDelta = this.stateTime / state.duration;

       if(stDelta > 1){

           this.state = this.stateIndex + 1;

       } 

    }

}


sprite클래스를 통해 sprite인스턴스 객체를 생성할 때 가장 먼저 해야할 일은 state값을 0으로 설정하는 것이다. 위의 코드에서는 get, set구문을 통해 stateTime과 stateIndex를 '0'으로 초기화하고 있다. 


update(dt)메서드에서는 Game클래스의 delta(시간)를 stateTime에 더해줌으로써 sprite자체의 시간을 생성한다.(stDelta) 이렇게 생성된 stDelta값은 states의 duration의 나눗셈을 통해 항상 '1'로 수렴한다. 만일 stDelta값이 1을 넘기게되면 stateIndex값에 1이 더해지고, state가 다시 실행(set)되면서 stateTime은 0으로 리셋되고, stateIndex값은 '1'만큼 올라간다.


stateIndex값이 증가한다는 의미는 states.mode의 배열 index가 증가함을 뜻하고, get state()에서 해당 값이 반환된다. 하지만 위의 코드에서는 상태변화가 '동작변화'를 의미하지 않는다. 그래서 아래와 같이 update()메서드에 상태변화와 관련된 기능을 추가한다.



3 spawn()메서드 || 동작

...(중략)


update(dt){


    ...(중략)

 

  switch(state.mode){

     case 'spawn' :

          this.opacity = stDelta;

          this.scale = stDelta;

          break;


     case 'static' :

          this.opacity = 1.0;

          this.scale = 1.0;

          break;


     case 'die' :

          this.opacity = 1,0 - stDelta;

          this.scale = 1.0 + stDelta;

          if(this.opacity < 0){

              this.opacity = 0;

          }

          break;

     }

}


위와같이 switch문을 통해 opacity와 scale을 변화시킴으로써 상태변화를 그래픽적으로 표현할 수 있다. render()메서드에서 this.canvas.globalAlpha값에 this.opacity값을 넣게되면 꽃의 투명도가 'spawn', 'static', 'die' 상태에 따라 동작이 변하게된다.


만일 '꽃'을 '움직이는 캐릭터'로 바꿔주면 시간에 따라 반복적으로 움직이는 이미지를 생성할 수도 있다. 


//구현




댓글

최신글 전체

이미지
제목
글쓴이
등록일