Flash CS4 + ActionScript 3.0으로 게임 수학/물리 구현 공부 계속.

2-3: 맵칩을 조합한 맵 배경 스크롤.

키보드의 상하좌우 키로 맵칩들의 조합인 배경을 스크롤 하기.
맵칩은 무비클립에 프레임별로 다른 모양을 넣어두어 gotoAndStop()을 이용해 번호에따라 변형 가능하게 해 두고 배열로 맵 구조를 구성한 뒤 맵칩 무비클립들을 생성해 맵칩 무비클립들의 덩어리인 전체 맵을 생성, 화면에 붙이고 mapAll 스프라이트에 담아 한꺼번에 움직이도록 처리.(음냐... 말로 설명하려니 너무 복잡하군)

14/12/8 월

소스(라이브러리에 미리 'blockM'이란 Export 명의 맵칩 무비클립을 만들어두었다.):

var maps:Array = [3,1,2,1,1,1,1,1,2,2,1,1,1,1,1,
		  1,1,1,2,2,1,1,1,1,1,1,2,1,1,1,
		  2,1,1,1,2,1,1,1,1,1,1,1,1,1,1,
		  2,1,1,1,2,1,1,1,1,2,1,2,1,1,2,
		  1,1,1,1,2,1,1,1,1,1,1,2,1,1,1,
		  1,1,1,1,1,1,1,1,2,1,1,2,1,1,1,
		  1,1,1,1,1,1,1,1,2,2,1,1,1,1,2,
		  1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,
		  1,1,2,1,1,1,1,1,2,2,1,1,1,1,1,
		  1,1,2,1,1,1,1,1,2,2,1,1,1,2,1,
		  1,1,1,1,1,1,1,1,1,1,1,1,1,2,4,
		  ]; //배경 블럭 형태 담을 배열
var maps2:Array=new Array(); //배경 블럭 무비 담을 배열
var mapAll = new Sprite(); //배경 블럭 무비 담을 컨테이너

var cVel:int = 10; //1회 이동 거리
var up=false,down=false,left=false,right=false;
var rightEnd = stage.stageWidth;
var downEnd = stage.stageHeight;
	
function init(){
	addChildAt(mapAll,0);
	mapSetting(maps); //맵 만들어 화면에 붙이기
	
	stage.addEventListener(Event.ENTER_FRAME,loop);
	stage.addEventListener(KeyboardEvent.KEY_DOWN,keyOn);
	stage.addEventListener(KeyboardEvent.KEY_UP,keyUps);
}
function mapSetting(map){//배경 블럭 처리
	for(var i = 0; i < map.length; i++){
		var form = map[i];
		blockArrange(blockM, form, i);
	}
}
function blockArrange(mov, frameNumber, intervalX){ //배경 블럭 생성
	var b = new mov();
	mapAll.addChild(b);
	b.gotoAndStop(frameNumber); //번호로 종류 변경
	b.num = frameNumber;
	b.x = (0 + intervalX * 50)%750;
	b.y = (0 + Math.floor(intervalX / 15) * 50);
	maps2.push(b);
}
function keyOn(e:KeyboardEvent){
   switch(e.keyCode){
      case Keyboard.LEFT: left=true; break;//왼쪽 화살표
      case Keyboard.RIGHT: right=true; break;//오른쪽 화살표
	  case Keyboard.UP: up=true; break;//윗쪽 화살표
	  case Keyboard.DOWN: down=true; break;//아랫쪽 화살표
      default: break;
   }
}
function keyUps(e:KeyboardEvent){
   switch(e.keyCode){
      case Keyboard.LEFT: left=false; break;//왼쪽 화살표
      case Keyboard.RIGHT: right=false; break;//오른쪽 화살표
	  case Keyboard.UP: up=false; break;//윗쪽 화살표
	  case Keyboard.DOWN: down=false; break;//아랫쪽 화살표
      default: break;
   }
}
function loop(e:Event){
	if(left){ 
		mapAll.x += cVel;
		if(mapAll.x > 0) mapAll.x = 0; //화면 이탈 방지
	}
	if(right){ 
		mapAll.x -= cVel;
		if(mapAll.x < rightEnd - mapAll.width) mapAll.x = rightEnd - mapAll.width;
	}
	if(up){ 
		mapAll.y += cVel;
		if(mapAll.y > 0) mapAll.y = 0;
	}
	if(down){ 
		mapAll.y -= cVel;
		if(mapAll.y < downEnd - mapAll.height) mapAll.y = downEnd - mapAll.height;
	}
}
init();

 


2-4: Sin을 이용해 흔들리는 배경 스크롤.

맵칩으로 구성된 맵을 삼각함수 Sin을 이용해 시간에따라 출렁이게 하고 키보드로 스크롤 가능하게 하기.

y = A * sin(2 * PI * x / lamda)에서 A는 진폭, lamda는 파장을 뜻한다.
시간을 포함한 사인파 공식은
y = A * sin(2 * PI * ((t / T)-(x / lamda))
t는 시간, T는 주기를 뜻한다.

아래 코드 중 sinMoveOri(), sinMove() 함수는 같은 일(맵 속 맵칩들 흔들기)을 하는 함수인데 sinMove()의 경우 약간의 최적화를 한 것. 삼각함수를 듬뿍 사용해서 CPU를 꽤 많이 사용하는지라... 맵 x축 첫 무비클립만 sin을 이용해 구하고 나머지 옆의 14개의 무비클립들은 구해진 값을 단순히 더하는 형태로 하는 간단한 최적화.

소스(라이브러리에 미리 'blockM'이란 Export 명의 맵칩 무비클립과 'ballMov'란 Export명의 볼 무비클립을 만들어두었다.):

var maps:Array = [3,1,2,1,1,1,1,1,2,2,1,1,1,1,1,
		  1,1,1,2,2,1,1,1,1,1,1,2,1,1,1,
		  2,1,1,1,2,1,1,1,1,1,1,1,1,1,1,
		  2,1,1,1,2,1,1,1,1,2,1,2,1,1,2,
		  1,1,1,1,2,1,1,1,1,1,1,2,1,1,1,
		  1,1,1,1,1,1,1,1,2,1,1,2,1,1,1,
		  1,1,1,1,1,1,1,1,2,2,1,1,1,1,2,
		  1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,
		  1,1,2,1,1,1,1,1,2,2,1,1,1,1,1,
		  1,1,2,1,1,1,1,1,2,2,1,1,1,2,1,
		  1,1,1,1,1,1,1,1,1,1,1,1,1,2,4,
		  ]; //배경 블럭 형태 담을 배열
var maps2:Array=new Array(); //배경 블럭 무비 담을 배열
var mapAll = new Sprite(); //배경 블럭 무비 담을 컨테이너
var ballArr:Array = new Array(); //볼들 담을 배열
var cVel:int = 10; //1회 이동 거리
var up=false,down=false,left=false,right=false;
var rightEnd = stage.stageWidth;
var downEnd = stage.stageHeight;
var fTime = 0;
	
function init(){
	addChildAt(mapAll,0);
	mapSetting(maps); //맵 만들어 화면에 붙이기
	ballArrCreate(); //수직으로 늘어선 볼들 생성
	ballSinMove()//수직으로 늘어선 볼들 흔들기
	sinMove(); //맵 Sin에 따라 흔들기
	
	stage.addEventListener(Event.ENTER_FRAME,loop);
	stage.addEventListener(KeyboardEvent.KEY_DOWN,keyOn);
	stage.addEventListener(KeyboardEvent.KEY_UP,keyUps);
}
function ballArrCreate(){
	for(var i=0; i < 8; i++){
		var m = new ballMov();
		addChild(m);
		m.x = rightEnd/2;
		m.y = (0 + i)*50;
		ballArr.push(m);
	}
}
function ballSinMove(){
	for(var i=0; i < ballArr.length; i++){
		ballArr[i].x=(80*Math.sin(2*Math.PI*(fTime/60-ballArr[i].y/400)))+rightEnd/2;
		ballArr[i].y=(0 + i)*50;
	}
}
function mapSetting(map){//배경 블럭 처리
	for(var i = 0; i < map.length; i++){
		var form = map[i];
		blockArrange(blockM, form, i);
	}
}
function blockArrange(mov, frameNumber, intervalX){ //배경 블럭 생성
	var b = new mov();
	mapAll.addChild(b);
	b.gotoAndStop(frameNumber);
	b.num = frameNumber;
	b.x = (0 + intervalX * 50)%750;
	b.y = (0 + Math.floor(intervalX / 15) * 50);
	maps2.push(b);
}
function sinMove(){
	var fSin=0;
	for(var i=0; i < maps2.length; i++){
		maps2[i].x = (0 + i * 50)%750;
		maps2[i].y = (0 + Math.floor(i / 15) * 50);
		if(i%15 == 0){
			fSin=50*Math.sin(2*Math.PI*(fTime/60-maps2[i].y/400));
		}
		maps2[i].x += fSin;
	}
}
function sinMoveOri(){
	var fSin=0;
	for(var i=0; i < maps2.length; i++){
		maps2[i].x = (0 + i * 50)%750;
		maps2[i].y = (0 + Math.floor(i / 15) * 50);
		maps2[i].x += 50*Math.sin(2*Math.PI*(fTime/60-maps2[i].y/400));
	}
}
function keyOn(e:KeyboardEvent){
   switch(e.keyCode){
      case Keyboard.LEFT: left=true; break;//왼쪽 화살표
      case Keyboard.RIGHT: right=true; break;//오른쪽 화살표
	  case Keyboard.UP: up=true; break;//윗쪽 화살표
	  case Keyboard.DOWN: down=true; break;//아랫쪽 화살표
      default: break;
   }
}
function keyUps(e:KeyboardEvent){
   switch(e.keyCode){
      case Keyboard.LEFT: left=false; break;//왼쪽 화살표
      case Keyboard.RIGHT: right=false; break;//오른쪽 화살표
	  case Keyboard.UP: up=false; break;//윗쪽 화살표
	  case Keyboard.DOWN: down=false; break;//아랫쪽 화살표
      default: break;
   }
}
function loop(e:Event){
	if(left){ 
		mapAll.x += cVel;
		if(mapAll.x > 0) mapAll.x = 0;
	}
	if(right){ 
		mapAll.x -= cVel;
		if(mapAll.x < rightEnd - mapAll.width) mapAll.x = rightEnd - mapAll.width;
	}
	if(up){ 
		mapAll.y += cVel;
		if(mapAll.y > 0) mapAll.y = 0;
	}
	if(down){ 
		mapAll.y -= cVel;
		if(mapAll.y < downEnd - mapAll.height) mapAll.y = downEnd - mapAll.height;
	}
	fTime++; //시간증가
	ballSinMove(); //볼들 흔들기
	sinMove(); //맵 흔들기
}
init();