배움 __IL/TIL 1기

TIL : 32번째- 230111 [1-2-수]

Mo_bi!e 2023. 1. 11. 18:25

I. INTRO : 프로젝트관련

결과에 너무 목매달지 말자

아무거나 코드 들고오려고 하지말자

 

만든거 만큼만 발표하자

너무 크게하지말고 조금만 해서 조금씩만 더해가자!

그래야만 내가 만든것이 되고,

 

어제 콜백함수를 썻다. 이거는 객체지향의 모든개념에서 쓰인다.

특히 이벤트와 관련곳엣 쓰일 수있다

 

오늘은 창 전환과 충돌에 대해서 한다.

 

II. 게임만들기

1.  적기와의 충돌 체크

(1) 이론

boy만 검사하려면 적기만 쉽게 관리 할 수있어야한다

 

boy가 적기 이용하려고하지만, 적기는 canvas가 가지고있다.

그렇다면 boy가 canvas참조해야하나? 이상하다 loop가 만들어진다. (이미 canvas가 boy참조상태)

이것을 해소하기 위해서 그림을 다시 그려보자...

 

그렇다면...

canvas도 boy도 enemy도 아닌 어디서나 누구나 쉽게 접근할수있는 공동의 객체를 생각해보자

싱글톤패턴을 이용한다.

이러한 패턴은 객체지향을 알고 패턴을 알아야하는데, OOP경험모르고 이론경험하는것은 위험하다

(중국음식 안먹고 중국요리하기)

 

(2) 객체로 싱글톤 실습

<newlec.js>

export default{
    //1이라고 한이유는 전역객체로서 하나만 쓰여야한다
    x : 1
}

객체를 하나 선언해준다.

 

<app.js>

import Gamecanvas from './panel/game-canvas.js';
import newlec from './newlec.js';


window.addEventListener("load",function(){

    const gamecanvas = new Gamecanvas();
    gamecanvas.run();
    //스스로 다른것을 가져오는게 바로 안된다.
    //html에 요구해야한다

    newlec.x++;

    console.log("x : "+ newlec.x);
    //다른곳도 2나오는지 3이나오는지 알오보기

    
    // gamecanvas.pause();

});

newlec.x++

을 해서 x값이 전역객체로서 모든 공간에 공유가 되는지 확인이 필요하다

 

그 결과 새로만들어진게 아니라 다 같이 공유한다

import하면 누구나 쓸수있다.

 

이 공간에다가 적기들의 내용을 배열에 넣고 충돌하는지 여부를 확인할 것이다.

 

(3) 싱글톤 패턴 으로 적기 탐지기 만들어보기 : 클래스로 인스턴스 만들어서

클래스의 인스턴스로 만든다고 하더라도 x값은 여전히 공유된다

그렇다면 이제 본격적으로 적기탐지기를 만들어보자

 

1)

<newlec.js>

class Context{
    #enemies;

    constructor(){
        this.#enemies = null;
    }

    //get set 만들어주기
    //이렇게 하면 속성을 쓰는것처럼할 수있다.
    get enemies(){
        return this.#enemies;
    }

    set enemies(val){
        this.#enemies = val;
    }
}


export default new Context();

여기서 #enemies는 private 이기 때문에 get set이라는 속성을 이용한다.

 

가장아래 export 해준 것은 결국 new Context()로 만든 인스턴스이다.

이 객체만!! 이다. 이것이 싱글톤패턴의 시작이다.

 

 

2)

<game-cavns>

enemey 객체전역객체에 참조값 대입 (소스코드 가장 아래)

import newlec from '../newlec.js';
export default class Gamecanvas{ //생성자 만들기

    constructor(){

    this.dom = document.querySelector(".game-canvas");
    this.dom.focus();


     
    //이미 캔버스라서 dom으로 하자
    /**@type {CanvasRenderingContext2D};*/
    this.ctx = this.dom.getContext("2d");

    //boy
    this.boy = new Boy(100,100);
    this.boy.speed++;
    console.log("speed"+ this.boy.speed);
    
    
        //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)
            
            //비워두면 aggregation
        ];

    //bg
    this.bg = new Background(0,0);





    newlec.enemies = this.enemies;
    
    
    }

마지막 newlec.enemies 전역객체에다가 this.enemies의 참조값넣어준다.

전역객체에 this.enemies대입해준다.

 

이후 newlec.enemies를 <boy.js> 에서 import 함으로서 접근이 가능하다

그렇기때문에  <boy.js>가 <Enemy.js> 의 각종 값들을 받아줄수있다.

 

이렇게하는 이유는  <boy.js>가 <game-canvas>를 참조하게 돼서 상호 참조해버리는 불상사가 발생하기 때문이다

왜냐하면 원래 <game-canvas.js>가 <boy.js>이미 참조하고 있기 때문이다.

 

 

3)

폭파 뒤 적기와 소녀 모두 사라져야한다

스스로 다들 할 수있을까?

canvas가 하지않아도 

 

우선 console 로 그 여부를 알아보자

[첫번째]로 적기와 소년의 중앙값을 알아내야한다

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 = 5;

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


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

        // console.log(this.img.width);




    }


    //별도로 중앙값을 만들어준다

    get centerX(){
        return this.x + this.img.width/2;

    }

    get centerY(){
        return this.y + this.img.height/2;
    }

 

두번째로 적기 소년과의 거리(d)를 구해야한다

   update(){    

        // console.log(newlec.enemies.length);

        for(let enemy of newlec.enemies){
            
            //1번
            //적의 위치값
            let ex = enemy.x;
            let ey = enemy.y;

            //boy의 위치값
            let bx = this.x;
            let by = this.y;

            //두 점(위치값) 사이 거리구하기
            let w = bx - ex; 
            let h = by - ey;

            //두 점사이 거리
            let d = Math.sqrt(w*w + h*h);
            }
        }

 

세번째로 적기 소년 반지름의 거리를 구해야한다.

//2번
//두 개의 중앙값으로 반지름 합
let r1r2 = enemy.sw /2  + this.sw / 2;

 

네번째로 r1r2가 d보다 적을 때

if(d < r1r2){
    console.log("충돌발생");
}

 

종합

update(){    

    // console.log(newlec.enemies.length);

    for(let enemy of newlec.enemies){

        //1번
        //적의 위치값
        let ex = enemy.x;
        let ey = enemy.y;

        //boy의 위치값
        let bx = this.x;
        let by = this.y;

        //두 점(위치값) 사이 거리구하기
        let w = bx - ex; 
        let h = by - ey;

        //두 점사이 거리
        let d = Math.sqrt(w*w + h*h);

        //2번
        //두 개의 중앙값으로 반지름 합
        let r1r2 = enemy.sw /2  + this.sw / 2;

        //3번
        if(d < r1r2){
            console.log("충돌발생");
        }
    }

1번 / 2번 / 3번 과정을 거친다.

 

4)

이제 충돌하는 것에 대한 범위를 그림에다가 중심점을 기준으로 원을 표시해보자

그래서 어떤때 충돌되는지 판단이 필요하다. [공룡잡히기]

시각적으로 여부를 볼 수있다.

 

이거는 직접 해보자!

<Enemy.js>

draw(ctx){
    ctx.beginPath();
    ctx.arc(this.x, this.y, this.sw / 2, 0, 2 * Math.PI);
    ctx.stroke();
}

나의 경우 적기의 너비에 /2 를 하지않았다

실질적인 반지름을 반영하지않았다.

 

<boy.js>

draw(ctx){
	ctx.beginPath();
    ctx.arc(this.x, this.y,this.sw /2 , 0, 2 * Math.PI);
    ctx.stroke();
}

 

 

5)

충돌 하면 폭발할수도 있고 카운트다운할수도있고 그렇다

이 경우 explosion 을 html에 import 해주고 Enemy 생성자에 이미지를 불러온다.

이경우 특정이미지를 불러와서 그려준다.

 

이것을 직접 구현 시

특정부분 이미지 사이즈 떼오는 식을 잊었다.

export default class Enemy{

    constructor(x = 0, y = 0){

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

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

        // this.speed = 5;

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


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

        // // console.log(this.img.width);

        
        //폭파(e) 인덱스(i) x,y값
        this.eix = 0;
        this.eiy = 0;

        //이미지의 너비 높이
        this.esw = this.imgEplo.width / 4;
        this.esh = this.imgEplo.height / 5;

        

    }

 

draw(ctx){


    //x,y 자체로 두면 좌상단에 있다.
    //보정이 필요하다
    //그리기 보다 별도 중앙값 위에만들어주기

    // ctx.drawImage(this.img,
    //     this.x -this.img.width/2 
    //     ,this.y - this.img.height)
    //     //위가 이미지, 아래가 캔버스 위치두기

        //이거!
    this.esx = this.esw * this.eix;
    this.esy = this.esh * this.eiy;

    ctx.drawImage(this.imgEplo,
        this.esx, this.esy, this.esw, this.esh,
        (this.x - this.esw /2) ,( this.y - this.esh + 15  ), this.esw , this.esh)
        //위가 이미지, 아래가 캔버스 위치두기




    // ctx.beginPath();
    // ctx.arc(this.x, this.y, this.img.width/2, 0, 2 * Math.PI);
    // ctx.stroke();



}

 


1. 보충

 

 

2. 회고 

1) 싱글톤패턴의 경우 단순한 변수의 경우에는 var로 하면 그냥 전역으로 공유할수 있지 않나?
싶으면서도 ES6방식에서는 이것이 최선이지않을까? 왜냐하면 ES6에서 클래스를 이용하는 방식은 은닉성이 필요한데, var는 그런점에서 부합하지 못하기 때문이다.

 

2) 이미지 사이즈 떼오는 식이 아쉽다

 

3) drawimage에 대해서 각 인수에 대한 위치의 느낌을 또 잊은것 같아서 아쉽다.

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

TIL : 34번째- 230113 [1-2-금]  (0) 2023.01.13
TIL : 33번째- 230112 [1-2-목]  (0) 2023.01.12
TIL : 31번째- 230110 [1-2-화]  (0) 2023.01.10
TIL : 30번째- 230109 [1-2-월]  (0) 2023.01.09
TIL : 29번째- 230106 [1-1-금]  (0) 2023.01.06