코딩/1-JavaScript

E02_애니메이션 => 01단계_타이틀

tree0505 2025. 6. 13. 10:28
반응형
  • E02_애니메이션

  • 01단계_타이틀

  • 보통 인터넷 강의에서는 한페이지에 다 때려 박는다 ㅋ 알아볼 수도 없게. 
    • 한페이지에 다 넣으면 구조를 기능을 간소하게 할 수 밖에 없다. 

  • 애니메이션만 파악해도 머리가 개운해진다. 

  • 다른 페이지에서 함수를 실행하고 싶으면 해야한다.   
    • let ctx = ManagerGame.getInstance().getCtx();
  • export class ManagerImage
    • 페이지 않에서. 다른 페이지 함수를 실행하고 싶으니까. 
    • export를 해놓으면 다른 곳에서 import를 가능하다.
  • import는 다른 클래스를 사용하기 위해서.
  • export안에 클래스 안에 변수는 this.를 붙여서 사용한다.
  • 이제는 let을 안쓰고 this.를 쓴다.
  • let은 한번쓰고 버린다.   
  • let은 중괄호에서 사라지니까.
  • this는 사라지지 않는다.
  • class가 this 자신이다.
  • this는 클래스 안에서만 사용가능하다.
  • 한 페이지에서만 사용할 수 있는 변수다.
  • static instance = new ManagerGame();
        static getInstance() { return ManagerGame.instance; }
        //스태틱 처리 
        //getInstance => 스태틱 함수를 만든것 
            //원래 함수앞에는 
            //구조화 => 다른 페이지에서 가져오는거 
                // 가져올때. 함수를 만들때는 꼭 스태틱 new를 붙여야 하는데. 그게 힘드니까. 
            //구조화를 하기 위해서는 꼭 함수앞에는 스태틱을 붙여야 하는데. new를 하지 않기 위해서 getInstance()함수를 만든것 

  • 배열 넣는 방법 
  • let arr = [];
            arr.push(10);
            document.writeln(arr[0]);

            let arr2 = {};
            arr2["a"] = 10;
            document.writeln(arr2["a"]);

  • _index.html
  • <!DOCTYPE html>
    <html lang="ko">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>_index.html</title>
        <script src="_main.js" type="module"></script>
    </head>
    <body>
        <canvas id="myCanvas" width="1280" height="720"></canvas>
    </body>
    </html>

  • _main.js
  • 여기서 중요한것은 function draw()  이 함수를 계속 실행시키는 것 => setInterval(draw,20) 때문에 
    •     ManagerGame.getInstance().update();
          ManagerGame.getInstance().draw();
      • ManagerGame => 이 페이지 안에서
      • getInstance  => new 하기 싫고. 스태틱 붙이기 싫으니까. stactic 
      • update() 함수를 실행시켜라 
  • _index.html => 여기서 캔버스 태그를 만들었으니까.
    • 캔버스에서 그림 그리게 하는것 
  • ManagerGame.getInstance().start($canvas, ctx);
    • $canvas, ctx 이것을 쓸수 있게 넘겨준것 
  • import { ManagerGame } from "./managerGame.js";
    //메니저 게임을 임포트
    //페이지에 대한 임포트

    function draw() {
        ctx.clearRect(0, 0, $canvas.width, $canvas.height);
        //지우기

        ManagerGame.getInstance().update();
        //업데이트 //움직이고
        ManagerGame.getInstance().draw();
        //그리고
    }
    //윈도우도 위의 draw처럼 반복한다.
    //메인은 function draw() 이것만 계속 반복하는것

    //--------------------------------------------------------
    let $canvas = document.querySelector("#myCanvas");
    $canvas.style.border = "1px solid black"; //외각선
    let ctx = $canvas.getContext("2d");

    ManagerGame.getInstance().start($canvas, ctx);
    //ManagerGame => 여기에다가 $canvas, ctx를 넘겨준것
    //ManagerGame => 이 페이지에 대한 start함수를 실행하라.

    setInterval(draw, 20);

 


  • managerGame.js
  • static instance = new ManagerGame();
    • ManagerGame 클래스의 유일한 인스턴스를 정적으로(static) 하나만 만들어 둔 거예요.
    • 즉, 프로그램 전체에서 이 ManagerGame 객체 하나만 사용하도록 강제하려는 목적이에요
  • static getInstance() { return ManagerGame.instance; }
    • 이건 클래스 외부에서 new ManagerGame()으로 새로 만들지 못하게 하고,
    • 대신 이미 만들어져 있는 그 하나의 객체만 접근할 수 있도록 getInstance() 함수를 만든 거예요.
  • 🧠 왜 이렇게 쓰는가?
    • 💡 싱글턴 패턴의 목적
    • 어떤 클래스의 인스턴스를 하나만 유지하고 공유하려고 할 때 사용합니다.
    • 예: 게임 매니저, 설정값 관리자, 데이터베이스 연결 등
  • ManagerGame.getInstance().start(canvas, ctx);
    이런 식으로 외부에서 ManagerGame을 쓸 수 있어요.
    new를 직접 하지 않아도, 내부적으로 만들어둔 instance를 가져오니까요.
  • import { ManagerImage } from "./managerImage.js";
    import { ManagerScene } from "./managerScene.js";

    export class ManagerGame {
       
        static instance = new ManagerGame();
        static getInstance() { return ManagerGame.instance; }
        //스태틱 처리
        //getInstance => 스태틱 함수를 만든것
            //원래 함수앞에는
            //구조화 => 다른 페이지에서 가져오는거
                // 가져올때. 함수를 만들때는 꼭 스태틱 new를 붙여야 하는데. 그게 힘드니까.
            //구조화를 하기 위해서는 꼭 함수앞에는 스태틱을 붙여야 하는데. new를 하지 않기 위해서 getInstance()함수를 만든것

        start(canavs, ctx) { //canavs, ctx => 넘어옴
            // 메인에서 넘겨줌 => ManagerGame.getInstance().start($canvas, ctx);
            this.canavs = canavs;
            this.ctx = ctx;
            //위의 2개를 저장함
           
            ManagerImage.getInstance().start();
           // ManagerImage.instance.start();
            //ManagerImage => 매니저 이미지를 스타트를 했다.
            //ManagerImage => 이미지만 로딩하는 것
            //미리 이미지 로딩을 다 한것
            //그냥 처음에 모든 이미지를 모두 로딩
            ManagerScene.getInstance().start();
            //ManagerScene => 매니저 씬을 스타트 했다.
            //다 분리시켰다.
            //씬을 로딩

            ManagerScene.getInstance().changeScene("title");
            //타이틀 씬을 틀어줘

            // ManagerScene.getInstance().changeScene("lobby"); //로비
            // ManagerScene.getInstance().changeScene("select"); // 셀렉트


            //여기서 위의 3개가 화면전환을 하는것이다.
        }

        update() {
            ManagerScene.getInstance().update();
        }

        draw() {
            ManagerScene.getInstance().draw();
        }

        getCtx() {
            return this.ctx;
        }

    }

  • managerImage.js
    import { NodeImage } from "./nodeImage.js";

    export class ManagerImage { //이미지만 로딩함
       
        static instance = new ManagerImage();
        static getInstance() { return ManagerImage.instance; }
        //직접적으로 꺼내면 안되서. 꺼내는 함수를 만든것
       
        start() {
            this.imageList = {};
            this.setImageList();
        }

        setImageList() { //이미지만 다 가지고 있음
            this.setImage("타이틀_배경화면", 1280, 720, "../img/타이틀/타이틀_배경화면.png");
            this.setImage("타이틀_제목", 530, 240, "../img/타이틀/타이틀_제목.png");

            this.setImage("로비_배경화면", 1280, 720 , "../img/로비/로비_배경화면.jpg");

            this.setImage("셀렉트_배경화면", 1280, 720, "../img/셀렉트/셀렉트_배경화면.png");
        }

        setImage(imageName, width, height, imagePath) {
            //이미지를 만들어서 배열에 저장함 =>  this.imageList = {};
           this.imageList[imageName] = new NodeImage(width, height, imagePath);
        }

        getImage(imageName) { //이미지 꺼낼때.
            //직접적으로 꺼내는것을 하면 안되서. 함수로 만든것
            return this.imageList[imageName];
        }

    }

  • managerScene.js
  • import { SceneLobby } from "./sceneLobby.js";
    import { SceneSelect } from "./sceneSelect.js";
    import { SceneTitle } from "./sceneTitle.js";

    export class ManagerScene {
     
        static instance = new ManagerScene();
        static getInstance() { return ManagerScene.instance; }

        start() {
            this.sceneList = {}; //객체 가지고 있음
            this.curScene = null; //현제씬
            this.curSceneName = ""; //현제씬 이름

            this.setSceneList(); //씬 3개 함수 실행
            //3개를 로딩
        }

        setSceneList() { //씬 3개를 로딩 // 위의 임포트 해야됨
            this.sceneList["title"] = new SceneTitle();
            this.sceneList["lobby"] = new SceneLobby();
            this.sceneList["select"] = new SceneSelect();
        }

        changeScene(sceneName) {
            //타이틀을 틀라고 했다. / 지금 현재는 null이다. 즉  this.curScene = null; //현제씬
                                    // 위의 start()에서 null로 해놨다.
            if(this.curSceneName == sceneName) {
                return;
            }
            //현재 씬이 겹치면
            //이미 현재씬이랑 바꾸는 씬이랑 이름이 같으면 취소.

            this.curScene = this.sceneList[sceneName];
            //위의 if가 아니면 바뀌었다는거다.
            //sceneName => 이름을 꺼내가지고 curScene => 현재씬을 꺼내는것

            if(this.curScene != null) {
                //sceneName => 이름이 잘못될수도 있다. 그래서 curScene=> 이름이 있으면
                this.curSceneName = sceneName;
                //sceneName => 씬 이름 바꿔주고
                this.sceneList[sceneName].start();
                //그씬을 실행해라. / 현재씬을 틀어라
            }
        }
       
        update() {
            if(this.curScene != null) {
                this.curScene.update();
            }
        }

        draw() {
            if(this.curScene != null) {
                this.curScene.draw();
            }        
        }

    }

  • nodeImage.js
  • import { ManagerGame } from "./managerGame.js";

    export class NodeImage {
       
        constructor(width, height, imagePath) {
            this.image = new Image();
            this.image.width = width;
            this.image.height = height;
            this.image.src = imagePath;
        }

        nodeImageDraw(x, y) {
            let ctx = ManagerGame.getInstance().getCtx();
            //ManagerGame 페이지 않에 있는 .getCtx() 함수를 실행하고 싶으니까.
                //getInstance()를 쓴것
                    //new랑 스태틱 하기 싫으니가. 앞에 getInstance()쓴것
            ctx.drawImage(this.image, x, y, this.image.width, this.image.height);
        }

    }

  • sceneLobby.js
  • import { ManagerImage } from "./managerImage.js";

    export class SceneLobby {
       
        start() {
            this.imageBackground = ManagerImage.getInstance().getImage("로비_배경화면");

        }
       
        update() {}

        draw() {
            this.imageBackground.nodeImageDraw(0, 0);  
        }

    }

  • sceneSelect.js
  • import { ManagerImage } from "./managerImage.js";

    export class SceneSelect {
       
        start() {
            this.imageBackground = ManagerImage.getInstance().getImage("셀렉트_배경화면");
        }
       
        update() {

        }

        draw() {
            this.imageBackground.nodeImageDraw(0, 0);
        }

    }

  • sceneTitle.js
  • import { ManagerGame } from "./managerGame.js";
    import { ManagerImage } from "./managerImage.js";

    export class SceneTitle {
       
        start() {
            this.imageBackground = ManagerImage.getInstance().getImage("타이틀_배경화면");
            this.imageTitle = ManagerImage.getInstance().getImage("타이틀_제목");
        }

        update() {}

        draw() {
            this.imageBackground.nodeImageDraw(0, 0);
            this.imageTitle.nodeImageDraw(400, 30);
        }


    }

 

반응형

'코딩 > 1-JavaScript' 카테고리의 다른 글

E02_애니메이션 => 03단계_로비완성  (0) 2025.06.13
E02_애니메이션 => 02단계_페이지이동  (0) 2025.06.13
05_게임_오목  (0) 2025.06.12
04_캔버스충돌처리  (1) 2025.06.12
03_캔버스키보드  (2) 2025.06.12