본문 바로가기
뒷북 정리 (국비 교육)/javascript

[javascript] Dragon Flight 만들기 (21.04.14 ~ 21.04.16)

by 규글 2021. 12. 11.

Dragon Flight 만들기 (21.04.14 ~ 21.04.16에 걸쳐 진행)

 

 

파일이 길어서 작성했던 필기를 기반으로 몇 가지만 기록하도록 한다.

        // context를 이용해서 그림이 그려지는 빈공간
        let canvas = document.querySelector("#myCanvas");
        // canvas에 그림이 그려지기위한 도구
        let context = canvas.getContext("2d");
        // 배경 이미지 loading
        let backImg = new Image();
        backImg.src = "images/backbg.png";
  1. canvas 위에 context로 그림을 그리는 방식으로 게임을 만든다.
    초당 몇 번씩 반복해서 그림을 그려주려고 한다.
  2. new의 의미는 heap 영역에 object를 생성하는 것이다. 그리고 변수에 heap 영역에 생성된 object의 reference value (참조값)를 담는 것이다. (ex - new Image(  ), new Audio(  ), new Data(  )...)
    이전에 만들었던 plane object와 array도 정석은 new를 통해서 만드는 것이었다. (해당 게시물에 내용 추가)
    let obj1={};
    let obj2=new Object();
    
    let arr1=[];
    let arr2=new Array();​
     이전에는 약식으로 단순히 중괄호만으로 object를, 대괄호만으로 array를 만들었으나 정석은 그 아래에 new 로 만드는 것이라고 했다. 중괄호와 대괄호는 편의를 위한 약식이라고 한다.

    object는 저장소(ex - .length)와 기능(ex - forEach(  ))로 이루어져 있다.
    이 두 가지 모두 만들 수 있다. (ex - obj.name="xxx" / obj.drive=function(  ){  })

    이렇게 new 로 만들어지는 것은 그냥 함수는 아니고 '생성자 함수'라고 한다. (나중에 배울 class의 개념이라고 했다.)
    'new' 라는 예약어로 미리 설계된 무언가를 사용하는 정도로 인지하고 있으면 된다고 했다.

    function Person(name, gender) {
      this.name = name;
      this.gender = gender;
    }
    Person.prototype.sayHello = function() {
      alert(this.name + ' said "hello"');
    };​

    (추가 search)
    생성자 함수의 이름은 대문자로 시작해야 한다. 소문자로 작성하게 된다면 새로이 객체를 생성하는 것이 아니라 그냥 일반적인 함수를 만드는 것이라고 한다.[각주:1]
    prototype이라는 것을 검색하다가 함께 발견하게 되었는데, 글자 그대로 객체의 prototype에 대한 정보를 담는다고 생각하면 될 것 같다. 객체를 만들게되면 해당 객체마다 메모리를 할당받을텐데, 동일한 동작에 대한 객체를 계속해서 만들게 된다고 생각하면 무의미한 메모리 할당이 될 것이다. 때문에 그런 동일한 내용을 prototype에 만든다면 해당 문제를 해결할 수 있다고 되어 있었다.[각주:2]
      
            setInterval(function(){
                // 만일 게임이 시작되지 않았다면
                if(!isStarted){
                    return;
                }
                count++;
                drawCanvas();
                dragonAni();
                backScroll();
                if(!isDragonDie)makeBullet();
                moveBullet();
                checkBullet();
                makeEnemy();
                moveEnemy();
                checkEnemy();
                checkCrash();
                checkDragon();
                makeMeteor();
                fallMeteor();
                checkMeteor();
                //makeUnseok();
                //moveUnseok();
                //checkUnseok();
            }, 10); // 1000분의 1초 단위​
  3.  setInterval(function(  ){  }, number) : number에는 숫자가 들어간다. 단위는 1000분의 1초. 0.001 초이다. loop처럼 반복해서 작업하는 것이기는 하나, for와 다르게 특정 주기로 반복하는 것이다.
    그리고 기능별로 쪼갠다. setInterval 자체에 함수의 내용을 모두 작성하면 너무 커지므로 함수는 따로 작성해준다.
    이 setInterval은 id 값을 return한다고 한다. 이것은 변수로 넣어서 확인이 가능하다. 이렇게 나오는 id값을 clearInterval(id) 함수에 넣어서 수행하게 한다면 setInterval이 취소된다고 한다.
  4. return : return을 통해 함수의 자리에 값을 뱉어낼 수도 있지만, 다른 시각으로 보면 함수를 강제로 끝내는 것이다.
  5.         /* 임시임
            그리다 보면 언젠가 로딩이 완료될 것.
            // 이미지 loading이 완료되면 실행할 함수 등록
            backImg.onload = function(){
                // context를 이용해서 image 그리기
                // .drawImage( 이미지, x, y, width, height);
                context.drawImage(backImg, 0, 0, 500, 800);
                // Dragon Image 그리기
                context.drawImage(unitImg, 250, 700, 100, 100);
            }
            */
     배경을 로딩하고 나서 이미지를 그리는 방법도 있다.
    하지만 함수를 이용해서 그린다.
  6. const ranNum = Math.floor(Math.random()*40)
    Math.random(  ) : 0와 1 사이의 랜덤한 숫자를 만들어준다.
    Math.floor(number) : 해당 number의 소수점 이하를 버린다.
  7.             function checkBullet(){
                    // 반복문 돌면서
                    for(let i=bullet.length-1; i>=0; i--){
                        // 미사일 object의 reference value를 하나씩 불러내서
                        let tmp=bullets[i];
                            if(tmp.isDelete == true){
                                bullets.splice(i,1);
                            }
                    }
                }
     




    이전의 for loop처럼 첫 index부터 돌리면 제거한 항목의 다음 내용에 대한 삭제 작업이 수행되지 않는다는 문제가 발생한다. 때문에 역순으로 for문을 돌리면 해당 내용을 제거하더라도, 다음 항목에 대한 작업을 정상적으로 수행할 수 있다.






  8.             // 미사일과 적기의 충돌을 검사하는 함수
                function checkCrash(){
                    for(let i=0; i<bullets.length; i++){
                        let b=bullets[i];
                        for(let j=0; j<enemyList.length; j++){
                            let e=enemyList[j];
                            // i 번째 미사일이 j번째 적기 영역에 있는지 여부
                            const isCrash = b.x > e.x-50 &&
                                            b.x < e.x+50 &&
                                            b.y > e.y-50 &&
                                            b.y < e.y+50;
                            if(isCrash == true){ // true 면 격추
                                // 1. 미사일 제거
                                //bullets.splice(i,1);
                                b.isDelete = true;
                                // 2. 적기 에너지 줄이기
                                e.energy -= b.damage;
    이중 for문 : for문 안에 다른 for문이 있는 것.
  9. const distance = Math.sqrt((e.x-unitX)**2 + (e.y-unitY)**2);
    Math.pow(a, b) : a의 b승 (a**b)
    Math.sqrt(number) : number**(0.5). root를 의미한다.
  10.                 // canvas 상에 점수 표기
                    context.fillText("Score : "+score, 20, 60);
                    context.font="50px 굴림";
                    context.fillStyle="red";
    글자는 text가 가지는 영역의 좌하단을 position의 기준으로 한다. 화면에서의 좌표계가 좌상단인 것과 다르다. 또한 canvas를 이용해서 만드는 것이기 때문에 css를 style 요소 안에서 작업하지 않는다. 주의해야할 점은, 이렇게 노출시키는 점수 text가 배경을 loading하는 것보다 늦으면 안된다는 것이다. 늦게된다면 배경 아래에 점수가 묻혀서 화면에 노출되지 않는다.
  11.                     context.save();
                        context.translate(unitX, unitY);
                        context.rotate(dragonAngle);
                        context.drawImage(unitImgs[dragonIndex], 0-dragonWidth/2, 0-dragonWidth/2, dragonWidth, dragonWidth);
                        context.restore();
     이 save()와 restore() 사이에서는 이 사이 친구들에 한하여 다른 좌표계를 사용할 수도 있다. 예를 들면 이 부분의 공간만 다르게 생각할 수 있는, 만화 원피스에서 등장하는 로우의 룸이라고 생각하면 될지도...
  12. 작업하면서 상당히 만은 if문을 사용했는데, 만약에 수행할 javascript가 한 줄이라면 굳이 중괄호 {  }로 묶지 않아도 된다고 했다. 예를 들면, if(조건) function( ); 처럼 간단히 작성할 수 있다면 굳이 묶지 않아도 된다고 한다.

dragon flight 끝!

댓글