배움 __IL/TIL 1기

TIL : 31번째- 230110 [1-2-화]

Mo_bi!e 2023. 1. 10. 20:06

I. 게임만들기

1. 적기관련

 

(1)움직이기

<Enemy.js>

 update(){

        this.y += this.speed;

        // if(this.y == 700){
        //     this.y = 0;
        //     // this.x += 100;
          
        // }


    }
export default class Gamecanvas{ //생성자 만들기

    constructor(){
    //enemy
        this.enemies = [new Enemy(10,0),new Enemy(30,0),new Enemy(300,0),new Enemy(500,0),new Enemy(556,0)
                        ,new Enemy(800,10),new Enemy(700,20),new Enemy(60,0),new Enemy(300,30),new Enemy(700,0)];
}

update()함수에 적기의 y값을 조정해주어서 위에서 아래로 움직이게끔 한다.

 

composiotion 방식이다. Enemy 의 인스턴스가 처음부터 일체형으로 다 지정되어서 나온다.

이 경우 enemies 배열에 10개의 인스턴스를 만들어준다. (처음부터 다 지정해줌)

 

(2) onOutOfScreen : 적기 없어지기

1)

캐릭터 캔버스 밖에 나갔을 때 그냥 그대로 두면 메모리낭비

캔버스 밖에 나갔을 때 제거 하는 것이 필요함

 

스크린 밖에 가는 이벤트 발생시 특정함수 발생 시키기

 

적에게 스크린밖에 나간것을 자기가 감지할수 있게끔

영역 밖에 나간 것호출은 내가 아니라 캔버스가 하게한다.

 

인덱스 알때는 splice(), [https://mdlg.tistory.com/66}

인덱스 모를때는 스스로 찾아서 지우게, 불가능하다면 인덱스 알아내기

 

2)

<호출 전>

export default class Enemy{

   constructor(x = 0, y = 0){

        this.img = document.querySelector("#enemy");
        console.log(this.img);

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

        this.speed = 20;

        //이 변수에 함수의 참조값이 들어갔는지
        this.onOutofScreen = null;


        //48 64
        this.sw = 48;
        this.sh = 64;


    }

onOutofScreen 의 멤버변수를 설정해준다.

처음에는 함수 참조값을 넣지않고, null값을 넣어준다.

왜? ★??

 

 

<call back위한 함수 호출조건>

update(){

        this.y += this.speed;

        // if(this.y == 700){
        //     this.y = 0;
        //     // this.x += 100;
          
        // }
        
        if(this.y > 500)
                    //null이 아닐 때, 조건발생
            if(this.onOutofScreen != null)
                this.onOutofScreen(this);
                            //나를 보낸다.
            

    }

setTimeout 이 특정시간마다 함수가 호출되는 것처럼

y값이 500이상일 때 onOutofScreen 에 자신(인스턴스 : this) 을 호출한다

 

export default class Gamecanvas{ //생성자 만들기

    constructor(){
	//enemy
    this.enemies = [new Enemy(10,0),new Enemy(30,0),new Enemy(300,0),new Enemy(500,0),new Enemy(556,0)
                    ,new Enemy(800,10),new Enemy(700,20),new Enemy(60,0),new Enemy(300,30),new Enemy(700,0)];
                    

    for(let enemy of this.enemies){
        enemy.onOutofScreen = (en)=>{
        
            //this.enemies.splice(this.enemies.indexOf(en),1);
            
            //좀더 이해가 쉬운 방법
            let idx = this.enemies.indexOf(en);
        	this.enemies.splice(idx,1);
        };              
        
        //화살표 함수 없이 씀 (이 경우 this 조심)
    //    	enemy.onOutofScreen = function(en){
    //     let idx = this.enemies.indexOf(en);
    //     this.enemies.splice(idx,1);
    // }
    
    }

enemies 배열 각 인덱스 마다 값(개개 인스턴스들)들을 enemy에 반복하면서 대입한다

 

앞서 y가 500이상(back) [수신가능상태] 일 때 

개개 인스턴스(enemy)는 Enemy.js의 update()에서 자신을 인스턴스로 받은 인수(en)로 받는 형태의 함수를 호출(call)한다 [발신함]

 

3) 

이 경우 enemies 배열에서 indexOf메소드를 이용해서 en(인스턴스)의 배열 인덱스값(idx)을 알아낸다

알아낸 idx값으로 하나를 삭제한다.

 

그러나, 빈배열상태로 그 공간이 그대로 남아있게된다.

 

(3) 적기는 그때마다 만들어져야해

랜덤한 시간으로 나타나야한다.

즉 일정하지않고, 서있지않고 적극적으로 움직여야한다.

 

어떤것은 인근으로 어떤것은 안가게

 

1) 우선 Aggregation 방식으로 무작위로 적기 생성하자

 

방금까지 방식은 composition 방식이다.

enemies 라는 배열push로 인스턴스를 넣어주기

update(){ //boy 의 update 호출하는 함수

        this.boy.update(); //상태바뀌고

        for(let enemy of this.enemies)
            enemy.update();


        //애그리게이션
        {
           
            let min = Math.ceil(-50);
            let max = Math.floor(600);

            let rand = Math.floor(Math.random() * (max - min)) + min

            console.log(rand);

            let x = rand;   //-50 ~this.dom.width +50
            let y = -50;

            this.enemies.push(new Enemy(x,y));

        }

        
    }

난수값을 생성해주는데 최댓값 최솟값방식으로 적기가 생성되는 위치를 지정해준다.

MDN 랜덤

JS는 실수값이 기본적으로 나와야하는데, 값 자르는 과정을 거쳐야한다.

 

1.7을 반올림 하고싶으면 Math.round()를 쓰면된다 반올림하면 2가된다.

1.7을 자르고(내림) 싶으면 floor (바닥) /1.7보다 무조건 높은(올림) 값 2 원하면 ceil(천장)

 

아쉽지만 이 랜덤은 real random이 아니다

그리고 나오는 속도를 delay 하는것이 필요하다.

 

처음에 1초에 하나씩 나오게 하자

 

2) 1초에 하나씩 나오게

        this.enemyAppearDelay--;               
        //애그리게이션
        if(this.enemyAppearDelay == 0){
            
            
            // let max = this.dom.width - 50;
            // // console.log(min);
            
            // let min = 50;
            
            // let rand = Math.floor(Math.random() * (max - min)) + min
            
            // // console.log(rand);
            
            // let x = rand;   //-50 ~this.dom.width +50
            // let y = -50;
            
            // this.enemies.push(new Enemy(x,y));


            let max2 = 60; // 
            let min2 = 30; //0.5초
            let rand2 = Math.floor(Math.random() * (max2 - min2)) + min2
            console.log(rand2);

            this.enemyAppearDelay = rand2;
        }

 

또 문제가 또있다

아까 y가 500일때 적기가 사라지도록했는데 안없어진다.

 

얘는 왜냐하면 onoutOfscreen은 다 null이고, 함수 참조값을 받지 못했다

 

aggregation 방식은 upate할때 인스턴스가 만들어지는데,

인스턴스가 만들어진 update에 만들어지자마자 onoutOfscreen에 함수참조값넣어준다.

이렇게 하면 만들자 마자 바로 넣을 수 있다.

 

그러나 이렇게 하면 매번 onoutOfscreen에 함수만들어진다.

 

한번만 정의하자. 멤버함수로 만들어주자

3) onoutOfscreen멤버함수로 만들기

 

이러면 이제 화살표함수를 쓸 수가없어진다. 

update(){ //boy 의 update 호출하는 함수

        this.boy.update(); //상태바뀌고

        for(let enemy of this.enemies)
            enemy.update();
      
            

        this.enemyAppearDelay--;               
        //애그리게이션
        if(this.enemyAppearDelay == 0){
            
            
            let max = this.dom.width - 50;
            // console.log(min);
            
            let min = 50;
            
            let rand = Math.floor(Math.random() * (max - min)) + min
            
            // console.log(rand);
            
            let x = rand;   //-50 ~ this.dom.width ~ +50
            let y = -50;
            

            let enemy = new Enemy(x,y);
            //함수 호출해주기
            enemy.onOutofScreen = this.enemyOutofScreenHandler.bind(this);
            this.enemies.push(enemy);

            
            let max2 = 60; // 
            let min2 = 30; //0.5초
            let rand2 = Math.floor(Math.random() * (max2 - min2)) + min2
            console.log(rand2);

            this.enemyAppearDelay = rand2;
        }

        
    }
enemyOutofScreenHandler(en){
                
            let idx = this.enemies.indexOf(en);
            this.enemies.splice(idx,1);
    }

이렇게 멤버함수로 만들어서 할수있다

 

(-나의 경우 push를 없애서 작동되지않았다.)

 

 

4)충돌대해서 -> 죽었거나

 

(웹소켓을 하면은 같이 게임할 수있다.)

 

비행기 터지게 하려면 당사자간 거리가 어느정도인지

 

방법으로

1. boy가 업데이트 될때마다 적기를 다 훑고 지나가거나, 2. 적기들boy가 있는지 본다.

전자의 경우 한걸음마다 적기 10번 / 적기 각각이 10번 => 둘다 같음

 

적기만 검사하든 소년만 검사하든 하자

1. 소년만을 검사하기위해서 적기들의 상황파악을 해야한다

2. 적기 쉽게알수있게 하는 상황파악해야한다

 

---

 

충돌이란
R1 R2 두 중심거리가 크거나 같으면 충돌난 것으로 볼 수있다


중심간 거리(d)
두 점사이 거리 공식으로 구하기가 가능하다
부딪혔다고 하기위해서는 적기에게 다물어보아야한다.

아니면 원을 작게 할수도있다.

 

--

boy입장에서 적기를 알수있게끔해야한다

boy 가 canvas 참조하면은 서로 참조하게되버림
그래서 필요한 자원만 호출하는 방법이있다.

update에다가 enemy

싱글통 이것은 전역으로 있으면서 절대로 2개이상생성 될 수없으면서,

아무곳이나 접근할수있는 전역상태이어야한다.
우리가 공통으로 사용하는 객체집합을 문맥객체라고 한다

객체사이 공유하는 전역객체가 필요하다 이것이 더 바람직하게 이용이가능하다
얘가 캔버스 참조하기보다는 자료들을 공유하는 것을 모아두고 전역으로 할 수있다.


1. 보충

(1) 싱글톤 패턴

What (정의) : 전체 시스템에서 클래스에 하나의 인스턴스만 존재하는 패턴이다.

Why (존재이유)  : 고정된 메모리 영역이 생김,요청이 많은 곳에서 사용시 효율적으로 이용(메모리에 고정되서 바로 접근, 값 공유)하기 위해서

하나의 인스턴스는 다른 클래스의 인스턴스와 값을 공유를 용이하게 하기위해서

How (방법) : 일반객체의 경우 볼수 있고, 비공개 프로퍼티 메소드의 경우 클로저를 이용한다.

 

2. 회고 

1) splice() 가 순간 무엇인지 잊고있었다. 처음듣는 단어처럼 반응했는데, 역시 망각은 빠른것같다

 

2) callback 함수가 참 많이쓰이구나 싶다. 무섭다

 

3) onOutofScreen에 함수를 생성자에 바로 넣는것은 바람직하지 않는 것일까? 그래서 꼭 콜백을 써야할까?

 

생각해보면 enemy.js에서 this를 보내야지 특정인스턴스특정할수있어서 그럴수도있겠다 즉 목적은 인스턴스 특정하기

그리고 인스턴스를 만들고, 제거하는것은 결국 gameCanvas에서 종합적으로 통제한다.

 

어쩔 수 없긴하다.

만약에 생성자에 있었다면은 우선 500인지 여부에 대해서 update()로 매번 확인이 어렵다.

그리고 인스턴스 제거도 곤란하다.

 

4) 콜백함수 매개변수넣는 곳이 내 통념과 달라서 낯설다.

 

 

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

TIL : 33번째- 230112 [1-2-목]  (0) 2023.01.12
TIL : 32번째- 230111 [1-2-수]  (0) 2023.01.11
TIL : 30번째- 230109 [1-2-월]  (0) 2023.01.09
TIL : 29번째- 230106 [1-1-금]  (0) 2023.01.06
TIL : 28번째- 230105 [1-1-목]  (0) 2023.01.05