7 분 소요

아래 코드를 이용해 설명문 이미지 및 게임화면을 보여준다.

rythmking.jsp
...
<body>
	...	
	<div id='body-content'>	
		<div id="canvas-container" style="text-align:center">	
	 		<table style="border-right:hidden; border-left:hidden; border-top:hidden; 
	 		border-bottom:hidden; margin-left:auto; margin-right:auto;">	
				<tr>
					<td>
						<img src='shared/h_t_p/h_t_p_r.png', width="700" height="700">
					</td>
					<td>	
					    <canvas id='menu'  width='565' height='810' style='display: inline;'>
					       Canvas not supported
					    </canvas> 	 					
					</td>
				</tr>		    			    
			</table>	     		       		        
		</div>	
	</div>	
    <script id ="game" type="module" src='Menu17.js' ></script>	 
    ...
</body>
Menu17.js
var canvas = document.getElementById('menu'),
    context = canvas.getContext('2d', { willReadFrequently: true }),
    ...
    menu_image = new Image(),
    ...
    menu_image.src = 'shared/images/selecting_menu_1.png';
    menu_image.onload = function() 
    {
        showing_menu(true);
    }
    ...

selecting_menu_1.png이미지 사진

1

페이지에서 조작을 위한 버튼들을 만들어 준다.

Menu17.js
	...
	//cur_status값에 따른 상태 표시
	//0 => menu, 1=> playing, 2=> game over, 3=> result
	cur_status,
	...
	C_P_MODE,
	start_button = new Image(),
	challenge = new Image(),
	practice =  new Image(),
	up = new Image(),
	down = new Image(),
	...	
	start_button.src = 'shared/images/Start_button.png';
	challenge.src = 'shared/images/Challenge mode_button.png';
	practice.src = 'shared/images/Practice mode_button.png';
	up.src = 'shared/images/up.png';
	down.src = 'shared/images/down.png';
	...
	function showing_menu(begining)
	{			
		pic_path = pic_list[cur_num+(cur_page-1)*8];
		pic.src = pic_path;			
		context.drawImage(menu_image,0,0,565,810);	
		
		//맨처음 실행시
		if(begining)
		{
			start_button.onload = function() 
			{
				context.drawImage(start_button,270,700,240,100);				
			}
			challenge.onload = function() 
			{
				context.drawImage(challenge,10,690,240,50);
			}
			practice.onload = function() 
			{
				context.drawImage(practice,10,750,240,50);	
				context.drawImage(up,510,260,40,40);
				context.drawImage(down,510,640,40,40);				
				cur_status = 0;				
			}						
		}
		else
		{
			...							
		}
		
		//challenge, practice모드 중 선택된걸 노란색 테두리를 이용해 표시한다.
		context.save();
		context.strokeStyle = "yellow"
		context.lineWidth = 5;
		context.strokeRect(5,687,250,55);	
		context.restore();	
			
		context.save();
		context.strokeStyle = "black"
		context.lineWidth = 5;
		context.strokeRect(5,747,250,55);	
		context.restore();	

		//C_P_MODE가 0 => challnege 모드
		//C_P_MODE가 1 => practice 모드
		C_P_MODE = 0;		
		...	
	}
	...

2

Menu17.js
	...
	pic = new Image(),
	...
	cur_page = 1,
	cur_num = 0,
	...
	pic_list = ["shared/images/Beethoven Virus.png",
				"shared/images/Beethoven Virus.png",
				"shared/images/Fantaisie.png",
				"shared/images/Fantaisie.png",
				"shared/images/piano concerto1.png",
				"shared/images/piano concerto1.png",
				"shared/images/Swan:Black.png",
				"shared/images/Swan:Black.png",
				"shared/images/Swan:White.png",
				"shared/images/Swan:White.png",
				"shared/images/Flight_of_the bumblebee.png",
				"shared/images/Flight_of_the bumblebee.png",
				"shared/images/toccata and fuga.png",
				"shared/images/toccata and fuga.png",
				];
	...           
	function showing_menu(begining)
	{
		pic_path = pic_list[cur_num+(cur_page-1)*8];
		pic.src = pic_path;		
		...
		
		//곡에 해당하는 이미지를 보여준다.
		pic.onload = function() 
		{
			context.drawImage(pic,175,30,215,190);	
		}
		
		context.save();
		context.fillStyle = "white"
		context.font = "30px NotoKR";
		
		//현제 페이지의 곡 리스트를 보여준다.
		for(var i=0; i<8; i++)
		{
			if(song_list[i+(cur_page-1)*8] == undefined)
			{
				break;				
			}
			
			//선택된 곡은 배경은 하얗게, 글자는 검게 만들어 준다.
			if(i == cur_num)
			{				
				context.save();
				context.fillStyle = "white"	
				context.fillRect(30, (280+i*50), 465, 30);			
				context.fillStyle = "black"
				context.fillText(song_list[i+(cur_page-1)*8],35,(305+i*50));	
				context.restore();		
			}
			else
			{
				context.fillText(song_list[i+(cur_page-1)*8],35,(305+i*50));				
			}
		}	
		context.restore();			
    }
    ...

3

Challange Mode, Practice Mode버튼에 마우스를 가져가면 포인터가 손가락 모양으로 바뀌고, 버튼의 크기도 작게 표현해 준다.

Menu17.js
	...		
	//canvas안에서 마우스를 움직였을 때 이벤트들이 발생한다.
	canvas.addEventListener("mousemove" , function (e)
	{
		X_loc=e.offsetX;
		Y_loc=e.offsetY;	
		
		context.canvas.style.cursor = "auto";	
		
		/*
		이전 커서 위치에 따른 prev_button의 값
		challenge => prev_button = 0
		practice => prev_button = 1
		start => prev_button = 2
		up => prev_button = 3
		down => prev_button = 4
		retry = > prev_button = 5
		quit => prev_button = 6
		이전에 커서의 위치가 위의 7개 버튼에 없었던 경우
		prev_button값은 -1이다.	
		*/ 	
        
                //cur_status값에 따른 상태 표시
                //0=>menu, 1=>playying, 2=>gameover, 3=> result	         
		if(cur_status == 0)
		{
			if(10 <= X_loc 
			  && X_loc <=250)
			{
				//Challange Mode버튼에 커서 위치(아직 클릭전)
				if(690 <= Y_loc && Y_loc <= 740 )
				{	
					context.save();
					context.fillStyle = "black"
					context.fillRect(10,690,240,50);
					context.restore();		
					
					//커서 위치전보다 작게 Challange Mode버튼을 그려준다.
					context.drawImage(challenge,15,695,230,40);						
					context.canvas.style.cursor = "pointer";	
					prev_button = 0;											
				}
				
				//Practice Mode버튼에 커서 위치(아직 클릭전)
				else if(750 <= Y_loc && Y_loc <= 800 )
				{		
					context.save();
					context.fillStyle = "black"
					context.fillRect(10,750,240,50);
					context.restore();	
								
 					//커서 위치전보다 작게 Practice Mode버튼을 그려준다.
					context.drawImage(practice,15,755,230,40);											
					context.canvas.style.cursor = "pointer";	
					prev_button = 1;										
				}
								
			}	
			...
		}
		...
	}		

현재 마우스 커서가 Practice Mode버튼 위에 올려져 있는 상태다. 자세히 보면 Challenge Mode버튼보다, Practice Mode버튼이 작다느것을 알 수 있다.

4

아래 코드를 통해 Challange Mode, Practice Mode버튼을 클릭시 수행할 작업(노란색 테두리 위치 변경 및 클릭음 재생)들을 정의해준다.

Menu17.js
	...
	canvas.addEventListener('mousedown', function(e) 
	{
		X_loc=e.offsetX;
		Y_loc=e.offsetY;
               
		if(cur_status == 0)
		{
			
			//challeng, practice mode
			if(10 <= X_loc 
			  && X_loc <=250)
			{
				//challenge mode선택
				if(690 <= Y_loc && Y_loc <= 740)
				{	        
					context.save();
					context.strokeStyle = "yellow"
					context.lineWidth = 5;
					context.strokeRect(5,687,250,55);	
					context.restore();	
					
					context.save();
					context.strokeStyle = "black"
					context.lineWidth = 5;
					context.strokeRect(5,747,250,55);	
					context.restore();	
					
					context.save();
					context.fillStyle = "black"
					context.fillRect(10,690,240,50);
					context.restore();	
						
					if(prev_button == 0)
					{
						context.drawImage(challenge,15,695,230,40);							
					}	
					else
					{									
						context.drawImage(challenge,10,690,240,50);	
					}
										
					C_P_MODE = 0;		
					reacting_sound();													
				}
				
				//practice mode선택
				else if(750 <= Y_loc && Y_loc <= 800 )
				{
					context.save();
					context.strokeStyle = "black"
					context.lineWidth = 5;
					context.strokeRect(5,687,250,55);	
					context.restore();	
                                      
					context.save();
					context.strokeStyle = "yellow"
					context.lineWidth = 5;
					context.strokeRect(5,747,250,55);	
					context.restore();	
	
					context.save();
					context.fillStyle = "black"
					context.fillRect(10,750,240,50);
					context.restore();	
					
					if(prev_button == 1)
					{
						context.drawImage(practice,15,755,230,40);						
					}						
					else
					{													
						context.drawImage(practice,10,750,240,50);	
					}
										
					C_P_MODE = 1;	
					reacting_sound();							
								
				}
			}
		...
		}
	...
	}
	...
Menu17.js
	...
	click_sounds = [],
	...
	// 10개의 Audio객체를 배열에 담아둔다.
	// 버튼을 빠르게 연타할때 클릭소리를 내기위해선 여러개의 오디오 객체가 있어야 한다.
	for(let i = 0; i < 10; i++)
	{
	    var click_sound = new Audio();
	    click_sound.src = 'sound/click_audio.mp4';
	    click_sounds.push(click_sound);
		...
	}	
	...
	
	//Challange Mode, Practice Mode, Retry버튼 및 곡 제목 클릭시 소리 재생
	function reacting_sound()
	{
	    for(let i = 0; i < click_sounds.length; i++)
		{
	        if(click_sounds[i].paused)
			{ 
				//재생중이 아닌 Audio객체를 찾아서 1회만 재생한다.
	            click_sounds[i].play(); 
	            break;
	        }
	    }				
	}
	...	

5

다른 곡을 선택하고 싶다면 키보드의 상,하 버튼을 누르거나 원하는 곡에 마우스 커서를 가져다가 클릭하면 된다

Menu17.js
	...
	pic = new Image(),
	...
	cur_page = 1,
	cur_num = 0,
	...
	pic_list = ["shared/images/Beethoven Virus.png",
				"shared/images/Beethoven Virus.png",
				"shared/images/Fantaisie.png",
				"shared/images/Fantaisie.png",
				"shared/images/piano concerto1.png",
				"shared/images/piano concerto1.png",
				"shared/images/Swan:Black.png",
				"shared/images/Swan:Black.png",
				"shared/images/Swan:White.png",
				"shared/images/Swan:White.png",
				"shared/images/Flight_of_the bumblebee.png",
				"shared/images/Flight_of_the bumblebee.png",
				"shared/images/toccata and fuga.png",
				"shared/images/toccata and fuga.png",
				];
	...       
    
	//키눌림 감지
	window.addEventListener('keydown', function(e) 
	{
		if(cur_status == 0)
		{
			//Arrow Up		=> 38
			//Arrow Down	=> 40	
			if(e.key == 38 || e.keyCode == 38)
			{
				div = cur_num - 1;		
                
				//이전 페이지에서 마지막 곡 선택
				if(div == -1)
				{
					if(cur_page > 1)
					{
						cur_page = cur_page - 1;	
						cur_num = 7;
						shifting_sound();								
						page_move(cur_page, cur_num);				
					}									
				}	
				
				//현재 페이지에서 이전곡 선택
				else
				{
					reacting_sound();						
					selecting_song();							
				}				
			}	
		...
		}
		...
	}
	...
	canvas.addEventListener('mousedown', function(e) 
	{
		X_loc=e.offsetX;
		Y_loc=e.offsetY;
             
		if(cur_status == 0)
		{
			...
			//곡선택	
			if(280 <= Y_loc
			&& Y_loc<= 660)
			{
				if(25 <= X_loc 
			  	&& X_loc <=510)
				{
					div = Math.floor((Y_loc-280)/50);	
					reacting_sound();	//=>바로 위의 코드 보자										
					selecting_song();					
				}					
			}				
		...
		}
	...
	}
	
	...
	//Challange Mode, Practice Mode, Retry버튼 및 곡 제목 클릭시 소리 재생
	function reacting_sound()
	{
      for(let i = 0; i < click_sounds.length; i++)
      {
          if(click_sounds[i].paused)
          {
              click_sounds[i].play(); 
              break;
          }
      }			
	}	

	...

	//곡이 선택된 것을 나타내는 함수
	function selecting_song()
	{
		//한페이지 보여질 곡이 8개 이하인 경우를 위해 아래의 조건문을 이요한다.
		if(song_list[div+(cur_page-1)*8] != undefined)
		{				
			//이전에 선택된 곡의 배경을 검게, 글짜는 희게 표현한다.
			context.save();
			context.fillStyle = "black"	
			context.fillRect(30, (280+cur_num*50),465,30);			
			context.fillStyle = "white"
			context.font = "30px NotoKR";
			context.fillText(song_list[cur_num+(cur_page-1)*8],35,(305+cur_num*50));	
			context.restore();				
			
			//새로이 선택된 곡의 배경을 희게, 글짜는 검게 표현한다.	
			context.save();
			context.fillStyle = "white"	
			context.fillRect(30, (280+div*50), 465, 30);			
			context.fillStyle = "black"
			context.font = "30px NotoKR";
			context.fillText(song_list[div+(cur_page-1)*8],35,(305+div*50));	
			context.restore();		
			
			//현재 페이지에서의 순서를 갱신한다.
			cur_num = div;	
			
			pic_path = pic_list[cur_num+(cur_page-1)*8];
			pic.src = pic_path;
		
			pic.onload = function() 
			{
				context.drawImage(pic,175,30,215,190);	
			}													
		}				
	}	
	...

6

상하 화살표 클릭하면 다음페이지에 있는 곡들을 볼 수 있다. 이전에 버튼들과 마찬가지로, 마우스가 상하 화살표에 위치하면 버튼 크기가 작아지고, 커서가 손가락 모양으로 변한다.

Menu17.js
	...
	shift_sounds = [],
	...
	// 10개의 Audio객체를 배열에 담아둔다.
	// 버튼을 빠르게 연타할때 소리를 내기위해선 여러개의 오디오 객체가 있어야 한다.
	for(let i = 0; i < 10; i++)
	{
		...
	    var shift_sound = new Audio();
	    shift_sound.src = 'sound/shift_audio.mp4';
	    shift_sounds.push(shift_sound);
	}	
	...
	
	//song_list는 따로 정의해둔 값이다. 뒤에서 자세히 다룬다.
	max_page_n = Math.floor((song_list.length) / 8);
	if(song_list.length % 8 >0)
	{
		max_page_n +=1;		
	}
    	... 
   	
	//위,아랫방향 화살표 누를때 재생된다.
	function shifting_sound()
	{
    	for(let i = 0; i < shift_sounds.length; i++)
		{
     	 	if(shift_sounds[i].paused)
			{ 
				// 재생중이 아닌 Audio객체를 찾아서 1회만 재생한다.
	            shift_sounds[i].play(); 
	            break;
	        }
	    }				
	}
	...
	//현재 페이지에 해당하는 곡을 표시한다.
	function song_list_writer()
	{
		context.save();
		context.fillStyle = "white"
		context.font = "30px NotoKR";
		
		for(var i=0; i<8; i++)
		{
			if(song_list[i+(cur_page-1)*8] == undefined)
			{
				break;				
			}
			if(i == cur_num)
			{				
				context.save();
				context.fillStyle = "white"	
				context.fillRect(30, (280+i*50), 465, 30);			
				context.fillStyle = "black"
				context.fillText(song_list[i+(cur_page-1)*8],35,(305+i*50));	
				context.restore();		
			}
			else
			{
				context.fillText(song_list[i+(cur_page-1)*8],35,(305+i*50));				
			}
		}	
		context.restore();			
	}	    
    
	//페이지 이동시 실행된다.
	function page_move(c_p, c_n)
	{
		context.save();								
		context.fillStyle = "black";
		//25	250	  485	   430
		context.fillRect(30,260,465,410);	
		context.restore();		
									
		song_list_writer();		
				
		pic_path = pic_list[c_n+(c_p-1)*8];
		pic.src = pic_path;
	
		pic.onload = function() 
		{
			context.drawImage(pic,175,30,215,190);	
		}	
		
	}	    
	
	//캔버스에서 마우스 누르는것 감지
	canvas.addEventListener('mousedown', function(e) 
	{
		X_loc=e.offsetX;
		Y_loc=e.offsetY;	
			        
		if(cur_status == 0)
		{
			...			
			//화살표
			if(510 <= X_loc 
			  && X_loc <=550)
			{
				//윗방향 화살표
				if(260 <= Y_loc && Y_loc <= 300)
				{
					context.save();
					context.fillStyle = "black"
					context.fillRect(510,260,40,300);
					context.restore();		
					if(prev_button == 3)
					{
						context.drawImage(up,515,265,30,30);							
					}
					else
					{
						context.drawImage(up,510,260,40,40);						
					}	
						
					if(cur_page > 1)
					{
						cur_page = cur_page - 1;	
						cur_num = 0;
						shifting_sound();							
						page_move(cur_page, cur_num);										
					}					
				}
				
				//아랫방향 화살표
				else if(640 <= Y_loc && Y_loc <= 680)
				{	
					context.save();
					context.fillStyle = "black"
					context.fillRect(510, 640, 40,40);
					context.restore();	
					if(prev_button == 4)
					{
						context.drawImage(down,515,645,30,30);						
					}
					else
					{															
						context.drawImage(down,510,640,40,40);	
					}						
				
					if(cur_page < max_page_n)
					{
						cur_page = cur_page + 1;	
						cur_num = 0;
						shifting_sound();							
						page_move(cur_page, cur_num);						
					}						
				}						
			}
			...
		}
		...
	}
	
	////canvas안에서 마우스를 움직였을 때 이벤트들이 발생한다.
	canvas.addEventListener("mousemove" , function (e)
	{
		X_loc=e.offsetX;
		Y_loc=e.offsetY;	
		
		context.canvas.style.cursor = "auto";	
			
		/*
		이전 커서 위치에 따른 prev_button의 값
		challenge => prev_button = 0
		practice => prev_button = 1
		start => prev_button = 2
		up => prev_button = 3
		down => prev_button = 4
		retry = > prev_button = 5
		quit => prev_button = 6
		이전에 커서위 위치가 위의 7개 버튼에 없었던 경우
		prev_button값은 -1이다.	
		*/ 	
        
		...
		prev_button = -1;	
		
		//context.canvas.style.cursor = "pointer"; 
		//=> 마우스 커서를 화살표가 아닌 손가락 모양으로 바꾼다.	
		if(cur_status == 0)
		{				
			...			
			//화살표
			if(510 <= X_loc 
			  && X_loc <=550)
			{
				//윗방향 화살표
				if(260 <= Y_loc && Y_loc <= 300)
				{
					context.save();
					context.fillStyle = "black"
					context.fillRect(510,260,40,300);
					context.restore();										
					context.drawImage(up,515,265,30,30);		
									
					context.canvas.style.cursor = "pointer";	
					prev_button = 3;
				}
				
				//아랫방향 화살표
				else if(640 <= Y_loc && Y_loc <= 680)
				{	
					context.save();
					context.fillStyle = "black"
					context.fillRect(510,640,40,40);
					context.restore();										
					context.drawImage(down,515,645,30,30);	
										
					context.canvas.style.cursor = "pointer";	
					prev_button = 4;		
				}						
			}
			...
		}
		...
	});
	...	

7

댓글남기기