공부의 기록/프리스쿨 : 수업내용정리

프리스쿨 (3일/3일) : 토끼 슈팅 게임 만들기!

파티피플지선 2024. 11. 14. 17:08

오늘은 오후에 만들 게임을 위해 어제 마지막에 만들었던 이벤트 함수로 시작해서 여러가지 다양한 함수를 다루었다.

 

효과음, 음악을 재생하는 코드

 

 

■ 본격적으로 토끼 슈팅 게임 만들기 시작! (엉망진창이었다고 한다!)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>RabbitShoot.html</title>
    <style>
        canvas{
            border:1px solid green;
        }
    </style>
</head>
<body>
    <canvas width="800" height="500" id="myCanvas"></canvas>
    <script>
        let canvas=document.querySelector("#myCanvas");
        //canvas 요소에 그림을 그릴 수 있는 도구의 참조값얻어오기
        let context=canvas.getContext("2d");

        //스나이퍼 이미지 로딩하기
        var snipeImg=new Image();
        snipeImg.src="images/snipe.png";

        //스나이프 이미지의 초기 좌표
        let snipeX=400;
        let snipeY=250;

        //배경이미지 로딩
        let backImg= new Image();
        backImg.src="images/background.jpg";

        //효과음 로딩 
        let fireSound=new Audio("sounds/fire.wav");
        let screamSound=new Audio("sounds/birddie.mp3");

        // 총알 구멍 이미지 로딩
        let holeImg=new Image();
        holeImg.src="Images/hole.png";
    
        /*총알 구멍의 임시 좌표를 확인하여 조준경과 일치 시키기 위한 임시 좌표)
        let holeX=400;
        let holeY=250; */

        //총알 구멍의 정보를 누적시킬 배열 준비하기
        let holes = [];
    

        //토끼 이미지 2개를 로딩해서 배열에 담아두기
        let rabbitImg1=new Image();
        rabbitImg1.src="images/rabbit_1.png";
        let rabbitImg2=new Image();
        rabbitImg2.src="images/rabbit2.png";

        let rabbitImgs= [rabbitImg1, rabbitImg2];


        //파편 이미지를 저장할 배열
        let fragmentImgs = [];

        //토끼 파편 이미지
    	for(let i=0; i<5; i++){

            let tmp = new Image();
            tmp.src="images/r"+i+".png";
            fragmentImgs.push(tmp);
            

        }

        //토끼 파편 하나하나의 정보(object)를 저장할 배열
        let fragments=[];


        /*//토끼 파편이미지 로딩하기 위에 세줄짜리랑 같은거임
	    let r0=new Image();
	    let r1=new Image();
	    let r2=new Image();
	    let r3=new Image();
	    let r4=new Image();
	    r0.src="images/r0.png";
	    r1.src="images/r1.png";
	    r2.src="images/r2.png";
	    r3.src="images/r3.png";
	    r4.src="images/r4.png";

	    //배열에 이미지 객체의 참조값 저장하기
	    let fragmentImgs=[r0, r1, r2, r3, r4];
        */
        
        //토끼의 초기 좌표
        let rabbitX=400;
        let rabbitY=250;

        //토끼 이미지 인덱스를 담을 변수 선언하고 초기값 0 대입하기
        let rabbitIndex=0;

        //화면이 다시 그려지는 횟수를 카운트할 변수
        let count=0;
        let dead = 0;

        context.font="30px consolas";
        context.fillStyle = "yellow";

        //초당 100번 호출되는 함수 등록
        setInterval(function(){
            //4각형 영역을 설정해서 canvas를 지우기
            //context.clearRect(0,0,800,500); -> 이건 배경을 클리어하는 명령어인데 이 명령어를 지운거는 배경 이미지를 계속 주기적으로 연산하기 때문에
            //canvas의 정중앙에 테스트로 snipe 이미지를 그려보기(좌표 숫자 2개 크기 숫자 2개) 
            //context로 이미지 위치를 정할 때는 기준이 이미지의 좌 상단의 좌표라서 이미지의 폭과 높이의 반만큼 빼줘야 함
            
            //배경 이미지를 cavas 크기에 맞게 그리기
            context.drawImage(backImg, 0, 0, 800, 500);
            
            /*context.drawImage(holeImg, holeX-10, holeY-10, 20, 20) 총알 구멍 이미지 1개씩 만 그릴 때*/
            for(let i=0; i<holes.length; i++){
                //총알 구멍의 정보를 담고 있는 object를 불러온다.
                let tmp=holes[i];
                context.drawImage(holeImg, tmp.x-10, tmp.y-10, 20,20);
            };

        
            //토끼 파편 그리기
            for(let i=0; i<fragments.length; i++){
                //토끼 파편의 정보를 담고 있는 i번째 object를 불러온다.
                let tmp=fragments[i];
                context.drawImage(fragmentImgs[tmp.type], tmp.x-50, tmp.y-50, 100,100);

            }


            //토끼 파편 움직이기
            for(let i=0; i<fragments.length; i++){
                //토끼 파편의 정보를 담고 있는 i번째 object를 불러온다.
                let tmp=fragments[i];
                //speedX. speedY 값 만큼 x,y 좌표를 변경하기
                tmp.x = tmp.x + tmp.speedX;
                tmp.y = tmp.y+ tmp.speedY;


            }


            //반복문을 역순으로 돌면서 배열에서 제거할 파편 객체는 제거하기
            for(let i=fragments.length-1 ; i>=0; i--){
               
                //위에 줄은 i번째 파편 객체를 불러내서 
                let tmp = fragments[i];
                //제거할지 여부를 알아내서
                let isOut = tmp.x<-50 ||
                            tmp.y<-50 ||
                            tmp.y>550 ||
                            tmp.y>850;

                //만일 제거해야 한다면 제거한다.
                if(isOut){
                    //i번째 인덱스에 저장된 object를 fragments 배열에서 제거하기

                    fragments.splice(i,1);
                    
                } 

                

            };

            //토끼 이미지 그리기
            context.drawImage(rabbitImgs[rabbitIndex],rabbitX-50, rabbitY-50, 100,100);

            count++; // 1초에 100씩 증가, 화면을 1초에 100번 세니까 //초당 100번 실행

            //초당 10번만 실행 = 10의 배수에서만 실행
            if(count%10==0){


            //인덱스 증가 시키기
             rabbitIndex=rabbitIndex+1;
            //만일 존재하는 인덱스가 아니라면
            if(rabbitIndex==2){
                //다시 0번 인덱스로 변경한다.
                rabbitIndex=0;
            }
            
            /* 나의 시도는 망했다
            if(rabbitIndex=0){
                context.drawImage(rabbitImgs[rabbitIndex],rabbitX-50, rabbitY-50, 100,100);
                rabbitIndex=rabbitIndex+1;
            }else{rabbitIndex=1;
                context.drawImage(rabbitImgs[rabbitIndex],rabbitX-50, rabbitY-50, 100,100);
                rabbitIndex=0;
                }
            */
            

            }             
            if(count%100 == 0){
            //토끼를 랜덤한 위치로 이동시킨다
            rabbitX = Math.random()*800;
            rabbitY = Math.random()*500;
            };
        
            //점수 출력하기(글자는 좌하단에 X좌표가 자동 배정됨)
           
            context.fillText("Point:"+dead, 10,40);
              


            //아래 코드는 조준경 이미지를 나타내는 코드이기 때문에
            context.drawImage(snipeImg, snipeX-50, snipeY-50, 100, 100);
            //로딩 시점에서 좌표를 계산을 한 다음에 실행되어야 하는게 맞다

        }, 10);
    
      //매개변수 e는 이름을 아무렇게나 지어도 된다
        document.querySelector("#myCanvas").addEventListener("mousemove", function(e){
        snipeX= e.offsetX;
        snipeY= e.offsetY;

     });

        document.querySelector("#myCanvas").addEventListener("mousedown", function(e){
        //강제로 재생 위치를 처음으로 변경한 다음 
        fireSound.currentTime=0;
        //play를 하면 연속 재생이 가능하다
        fireSound.play();

        /* 총알 구멍 한개일 때 처음 좌표 열어 놓고
        holeX=e.offsetX;
        holeY=e.offsetY;이것도 열어 놔야 함*/
        //총알의 위치를 object에 담기
        let hole = {x:e.offsetX, y:e.offsetY};
        //object를 배열에 누적 시키다.
        holes.push(hole);


        //토끼가 총에 맞았는지 여부를 알아내서
        let isShooted = rabbitX-50<e.offsetX && 
                        rabbitX+50>e.offsetX && 
                        rabbitY-30<e.offsetY && 
                        rabbitY+50>e.offsetY;
            

        //만일 토끼가 맞았다면? 필요한 동작을 실행한다.
        if(isShooted){
            screamSound.currentTime=0;
            screamSound.play(); //비명지르기
            dead++;      //죽었을때 점수 올리기
            //토끼 파편 5개 만들어서 fragments 배열에 누적 시키기
            for (let i=0; i<5; i++){
                //빈 object를 만들어서
                let tmp = {};

                //토끼의 현재 좌표를 파편의 초기 좌표로 부여한다
                tmp.x=rabbitX;
                tmp.y=rabbitY;

                //파편의 속도를 random하게 부여한다(음수도 나올 수 있도록)
                tmp.speedX= Math.random()*10 -5;
                tmp.speedY= Math.random()*10 -5;
                //파편의 type을 부여
                tmp.type = i;
                //fragments 배열에 누적시키기
                fragments.push(tmp);
            }


        };



     });

    </script>
</body>
</html>