배움 __IL/TIL 1기

TIL : 29번째- 230106 [1-1-금]

Mo_bi!e 2023. 1. 6. 19:04

I. 게임 쓰레드 이해하기

무한 loop에 빠져있다.

흐름이 하나 면다른 것을 못한다를 의미한다.

 

즉 흐름이 하나가 아니라는 것을 의미한다.

스레드로 흐름을 별개로 만들어주어야한다.

 

하나는 무한 + 하나는 사용자의 입출력담당 위해 무한

 

mainTread(보조흐름이지만, 추가한): uiThread

초당 60번돌리기위한 흐름 : gameThread

 

두개가 동시에 동작한다. 항상 있다고 해야한다.

만들 때 메인쓰레드인지, 게임쓰레드인지 파악을해야한다

둘간에 소통은 상태변수로 소통한다.

 

흐름에 직접 꽂아넣기가 불가능한데,

위에(상태변수)에다가 값을 넣어준다.

흐름은 상태변수 바뀐것을 적용한다.

(즉 바로 적용은아니다)

파이터라는 상태변수로 가능하다.

60번돌면서 쟤를 확인하면서 바꾸는 것이다.

 

 

II. 동작시키기

1. 목적지에서 멈추기

목적지에 도착하면 멈추게끔 해야하는데,,, 

(1) 전투기를 멈추게 하기 : 목적지에 도착했을 때는 벡터를 0으로 만든다.

계속 누적은 하는데 소수점이라서 미세하게 값이 달라서 멈추지를못하는데,,,

 

(2) 소수점이 잘리면서 미세하게 벗어나는 목적지 : 먼거리를 이동할 때의 위치를 잡아주는 보정기술이 필요

누적된 값이 다르다.

업데이트는 중에 보정을 해주면된다.

 

예컨데 1/10 정도올때마다,,, 보정해준다.

목표점과의 비교? / 범위값으로 비교? / 거리로 비교?

 

draw(ctx){

        var img = new Image();
        img.src = "./image/boy.png";

        img.onload = function(){

            ctx.drawImage(img,
                this.sx,this.sy,this.sw,this.sh,
                this.x,this.y,105,148.24)

        }.bind(this);

    }

    update(){
        //여기서 점진적으로 그리기 위한 용도
        // 즉 점진적 좌표변경

        //호출될때마다 단위벡터 더해주기
        this.x += this.vx;
        this.y += this.vy;

    }

이런 함수(draw / update)는 내가 하는게 아니라 영사기에서 돌아가듯이 내(사용자)가 호출하는것이 아니다.

 

 

(3) 실습

update(){
    //여기서 점진적으로 그리기 위한 용도
    // 즉 점진적 좌표변경


    //목표 도달 시 0으로 해주는것
    // 이 경우 목적지를 크기를 늘려줘서 멈추게끔해서
    //벡터 영으로 만들어준다.

        //x축
    if((this.x > -20 + this.dx && this.x < 20 + this.dx) 
        //y축
    || (this.y > -20 + this.dy && this.y < 20 + this.dy ))
    {
        console.log("qq")
        this.vx = 0;
        this.vy = 0;

    }

    //호출될때마다 단위벡터 더해주기
    this.x += this.vx;
    this.y += this.vy;

}

dx 값을 기준으로 +20/ -20 등으로 범위를 지정해준다.

 

 

2. 위치 보정하기

draw(ctx){

    var img = new Image();
    img.src = "./image/boy.png";

    img.onload = function(){

         ctx.drawImage(img,
            this.sx, this.sy, this.sw, this.sh,
            this.x - this.sw /2 , this.y - this.sh +15 , this.sw , this.sh)
		  //위가 이미지, 아래가 캔버스 위치두기
     }.bind(this);
}

drawImage에서 아래쪽 x,y 값은 보정을 해주어야한다.

 

canvas에 그려지는 x,y은 좌측상단을 기준으로 들고온다.

이를 고쳐서 x,y에 있는것보다

x는 좀더 좌측으로 해서 몸 가운데로 ( - this.sw /2 )

y는 좀더 아래로 하기위해서 몸 가운데로 (- this.sh /2)

한다

 

다만 캐릭터 특성상 다리 아래를 기준으로 하는것이 바람직하기 때문에,

+15를 해준다.

 

3. 이미지 깜빡거리기 막아주기

draw(ctx){

    // console.log(this); 
    // console.log("10------------구분----------");

    var img = new Image();
    img.src = "./image/boy.png";

    img.onload = function(){
        // console.log(this); 
        // console.log("11------------구분----------");

        ctx.drawImage(img,
            this.sx, this.sy, this.sw, this.sh,
            this.x - this.sw /2 , this.y - this.sh +15 , this.sw , this.sh)

    }.bind(this);

}

위와같이 이미지를 draw()메소드로 매번 불러오는건 낭비이다. (왜냐하면 gameThread는 초당 60번실행)

생성자에서 만들어서하기

 

 

이미지 마다 각자하기보다, 같이쓰고, 미리 로드하자 (html에서!)

<body>
    <!-- <img src="./img/boy.png" alt=""> -->

    <img src="./image/boy.png " id = "boy" style="display: none;">
    <img src="./image/map.png " id = "bg" style="display: none;">

    <canvas class="game-canvas" width="700" height="700"></canvas>
</body>
class Boy{
 	constructor(x , y){
		//이미지 그리기 위한 변수들
        //여기서 한번만 들고오기
        this.img = document.querySelector("#boy");
        }
        
 draw(ctx){

// var img = new Image();
// img.src = "./image/boy.png";

// img.onload = function(){

//     ctx.drawImage(img,
//         this.sx, this.sy, this.sw, this.sh,
//         this.x - this.sw /2 , this.y - this.sh +15 , this.sw , this.sh)

// }.bind(this);

    ctx.drawImage(this.img,
        this.sx, this.sy, this.sw, this.sh,
        (this.x - this.sw /2) ,( this.y - this.sh +25 ), this.sw , this.sh)
        //위가 이미지, 아래가 캔버스 위치두기

}
}

1)

// var img = new Image();
// img.src = "./image/boy.png";
// img.onload = function(){}

 

이 부분을 HTML에서 갈음할 수있다.

onload는 필요가 없을수 있는것이 이미 html에서 불러왔고

불러온 이미지를 생성자를 이용해서 인스턴스로 만들어주면 충분하다.

 

4. 배경이미지 넣어주기

1) Background 클래스 정의하기

class Background{

    constructor(x,y){

        this.x = 0;
        this.y = 0;

        this.img = document.querySelector("#bg");
        
    }
    
    draw(ctx){
        ctx.drawImage(this.img, this.x ,this.y);
    }

    update(){

    }

}

 

<html> 에 background.js import해주고,  이미지도 해준다.

 

<Gamecanvas 생성자>에 Background 인스턴스 만들어주고 , draw 메소드에 그려주어야한다.

draw(){ //boy의 draw를 호출하는 함수
        this.bg.draw(this.ctx);
        this.boy.draw(this.ctx); //다시그리고

    }

순서를 중요시하자

배경이 늦게 그려져 캐릭터가 잡아먹혀버린다.

 

 

5. 다리움직여주기

이미지를 계속 바꿔주기는 업데이트에서 이미지를 지속 전환시켜주면된다.

이 경우에 이미지를 배열처럼 들고왔기 때문에 ix값을 조절해준다.

다만 결국 drawImage에 대입하는 sx이 최종적으로 필요하기 때문에 sx관련식도 함께 선언해주어야한다.

(여러번 선언하는게 문제임)

 

update(){

    //다리 바꿔주기

    if(this.ix == 0 ){
        this.ix = 2 ;
    }
    else 
        this.ix = 0 ;

    this.sx = this.sw * this.ix;

    //목표 도달 시 0으로 해주는것
    // 이 경우 목적지를 크기를 늘려줘서 멈추게끔해서
    //벡터 영으로 만들어준다.

        //x축
    if((this.x > -1 + this.dx && this.x < 1 + this.dx) 
        //y축
    || (this.y > -1 + this.dy && this.y < 1 + this.dy ))
    {
        console.log("qq")
        this.vx = 0;
        this.vy = 0;

        //제자리에서 도착하면 서있기
        this.ix = 1 ;
        this.sx = this.sw * this.ix;
    }

    //호출될때마다 단위벡터 더해주기
    this.x += this.vx;
    this.y += this.vy;

}

목적지 도착시 특정자세로 고정되게끔 하기위해서, 조건문(목적지)에도 동작에 대해서 명령을 넣어준다.  

 

0 , 2로 자세 만들어주기

        //두개 값만 바꿔주는 거면 삼항연산자 권함
        this.ix = this.ix==2? 0:2;

 

6. 다리 천천히 움직여주자

update는 계속하되, 생성자에 this.walkDelay 를 선언해준다. 

update(){

    this.walkDelay--;

	if(this.walkDelay == 0){

        this.ix = this.ix==2? 0:2;
        this.sx = this.sw * this.ix;
        this.walkDelay = 30;

    }
    
}

나의 경우 또다른 반복문 block 을 만들어서 실행하려고했다

하지만 block 안에서 인덱스(i)가 반복 후 자세가 바뀌는 것이여서 차이가 없었다.

 

그러나 update전체에서 인덱스(walkDelay)를 설정해주면 update의 진행과 연동해서 다리를 천천히 움직이게끔 가능하다.

 

 

7. 도착하면 멈춰주자

나의 경우 목적지 도착했을 때(도착조건)를 기준으로 0으로 생각했다.

그러나 최초 시작시에는 제자리 걸음을 하고있는 문제가있다.

 

update()에 별도로 벡터값이 0일 때 멈추게끔 하면된다.

if(this.vx == 0 && this.vy == 0){
    //제자리에서 도착하면 서있기
    this.ix = 1 ;
    this.sx = this.sw * this.ix;
}

 

8. 반복되는 식 해결

this.sx = this.sw * this.ix;
this.sy = this.sh * this.iy;

이 식은 draw()

왜냐하면 어차피 그려줄때 반복되고, 이식하나면 변경된 ix,iy를 반영하기 수월하다.

 

9. 키보드로 입력

key-up / key-down

 

1) ★콘솔에 안먹힐수 있다.

tabindex = 0 방식으로 해결한다.

<input tabindex="0">
<img>
<div tabindex = "0">
    test
</div>
<input tabindex= "0">
<input tabindex= "0">

이런 경우에 div 는 원래 <Tap>이 적용되지않는다.

그러나 div에 tapindex 를 넣어주면 가능하고, 이는 곳 키보드 입력을 받을 수 있는 상태를 의미한다,

 

 

2) 한편 원래 키보드 입력은 우선순위를 가지고있지않다.

윈도우는 하나만 활성화되어있는데, 그거만 키를 받을수있고 나머지는 받지못한다. (창이 밝은)

class Gamecanvas{ //생성자 만들기
	this.dom.focus();
    }

이거를 하면된다.

본 함수의 검증방법은 새로고침하고 캔버스에 아무런 마우스클릭(창 밝은상태)하지 않아도, 키보드 입력되는 경우를 확인하는 것이다.

 

야매 같지만 어쩔수없이 이렇게 해야한다.

창을 움직이거나 배치시킬때 이용을한다.

 

 

10. 마무리하며

1. 어떤키를눌렀는지

2. 키값이 어떤모양인지

3. 적용 시 어떤제어형식으로 해야할지

 

고민해보자!


1. 보충

moveTo(dx,dy){

        //목적지에서 현재위치를 빼서
        //가로세로 를 지정한다
        let w = dx - this.x;
        let h = dy - this.y;

        //구해진 가로세로로 거리로
        // 총 거리를 구한다
        let d = Math.sqrt(w * w + h * h);

        //x,y 좌표 벡터값을 구한다.
        this. vx = w / d;
        this. vy = h / d;

        // this.x = x;
        // this.y = y;
        // 이렇게 하면안됨 왜냐하면 바로 순간이동하게된다.


        //이게 없어서...
        this.dx = dx;
        this.dy = dy;

    }

dx,dy를 이렇게 한 효과가 이해가 안된다.

 

 

 

 

2. 회고 

1) 우리가 보편적으로 게임할때 배우는 행동하나하나에 디테일한 설정을 넣어주고, 다양한 문제에 봉착했을 때 조금씩해결하는것이 즐겁다.

 

2) 모든 사소한설정한 저마다 이유와 논리가 있다. 그리고 이러한 논리는 내가 생각한대로, 의도한대로 디테일하게 접근할수 있어서 흥미가 있다.

 

3) 신기한것은 내컴퓨터의 경우 별도의 tableindex를 하지않아도 내꺼에는 왜 키보드가 입력되는 것일까?

'배움 __IL > TIL 1기' 카테고리의 다른 글

TIL : 31번째- 230110 [1-2-화]  (0) 2023.01.10
TIL : 30번째- 230109 [1-2-월]  (0) 2023.01.09
TIL : 28번째- 230105 [1-1-목]  (0) 2023.01.05
TIL : 27번째- 230104 [1-1-수]  (0) 2023.01.04
TIL : 26번째- 230103 [1-1-화]  (0) 2023.01.03