Flash CS4 + ActionScript 3.0로 만든 틈새탄 발사.

주인공기는 마우스를 따라다니게 하다.
타이머로 2초마다 적기에서 틈새탄을 발사하게 하다.
적탄은 화면을 나가면 제거되게 하다.

-----------------------------------------------------------------------------
Flash CS4로 '게임 매니악스 탄막게임 알고리즘' 중 6-4 틈새탄 예제 참고하여 만들기.

n-way탄의 변형.
n-way탄의 발사간격, 총알수, 총알간 각도와 속도를 조절하여 만들었다.
매번 발사할 때 마다 발사각도를 랜덤으로 바꿔 주는 방식으로 구현.
핵심은 매번 발사각도를 랜덤으로 바꿔 주는 것과 n-way탄 설정을 조절하는 것.
발사되는 총알의 각도를 발사 방향으로 바꿔주는 기능 추가.

15/6/18 목

* 한데 탄들의 속도와 간격이 균일하지 않고 미묘하게 들쭉날쭉하다.(특히 탄 간 간격이 아주 밀집되게 발사할 경우는 심하게 드러난다) 이건 액션스크립트의 한계인지, 정수와 소수간 변환시 날아가는 정확성 문제인지, 알고리즘 문제인지 잘 모르겠다.
* 그외 방향탄과 소용돌이탄도 코드상에 회색으로 남겨 두었다.

화면에 'playerM', 'enemyM'이란 이름의 주인공과 적 무비클립을 배치해 두고 'eBullet02M'이란 익스포트명의 적 총알 무비클립을 라이브러리에 만들어 두다.
var player = playerM; //화면상 플레이어 무비클립
var enemy = enemyM; //화면상 적 무비클립
var ebSpeed=2; //적탄 이동 속도
var ebTheta = -90;//적탄 발사 각도 초기화

var eBulletArr:Array=new Array();
var eBulletTimer:Timer=new Timer(2000); //적탄 발사 타이머(2초)

function init(){
	Mouse.hide(); //마우스 커서 감추기
	player.startDrag(true); //주인공 마우스 커서 따라다니게 하기
	
	stage.addEventListener(Event.ENTER_FRAME, loop);
	eBulletTimer.addEventListener(TimerEvent.TIMER, eBulletInit);
	eBulletTimer.start(); //적탄 발사 타이머 시작
}
function loop(e:Event){ //기본 루프
	eBulletMove(); //적탄 움직임 처리 함수 호출
}
function eBulletInit(e:TimerEvent){ //타이머 종료시
	//적탄 중심 탄환 속도벡터 구하기
	var vx0 = Math.cos(Math.PI/180 * ebTheta)*ebSpeed;
	var vy0 = Math.sin(Math.PI/180 * ebTheta)*ebSpeed;
	
	ebTheta=Math.random()*180+180;
	eBulletNwayInit(40, 8, vx0, vy0, [],[],[]); 
}
//function eBulletInit(e:TimerEvent){ //타이머 종료시
//	//ebDirectInit(90);
//	ebSpiralInit(0, 0.5, 2);
//	ebSpiralInit(90, 0.5, 2.5);
//	ebSpiralInit(180, 0.5, 3);
//	ebSpiralInit(270, 0.5, 1);
//}
function eBulletNwayInit(bulletNum, bbTheta, vx0, vy0, vxArr, vyArr, radArr){
//적 N-way탄 생성 및 초기화
//(탄환 수, 탄환 간 각도, 중심이되는 탄환속도(vx0,vy0),
//     		n-way탄의 속도 x,y 배열(vxArr,vyArr),탄방향각도 배열)
	//탄환 간 각도를 라디안으로 변환
	var radStep = Math.PI/180*bbTheta;
	//가장자리 탄환과 중심부분 탄환 간 각도 계산
	var rad = (-bulletNum/2+0.5)*radStep;
	var cosRad, sinRad;
	//bulletNum개의 탄환 속도 계산하기
	for(var i=0; i < bulletNum; i++, rad+=radStep){
		//(vx[i], vy[i]) 구하기
		//속도벡터 (vx0, vy0)를 rad만큼 회전시키기
		cosRad = Math.cos(rad);
		sinRad = Math.sin(rad);
		vxArr[i]=vx0*cosRad - vy0*sinRad;
		vyArr[i]=vx0*sinRad + vy0*cosRad;
		radArr[i] = Math.atan2(vyArr[i],vxArr[i]); //탄 방향용
	}
	for(var j=0; j < bulletNum; j++){//적탄 생성,속도부여,배열추가
		var eb = new eBullet02M();
		eb.x = enemy.x, eb.y = enemy.y; //적탄 위치 초기화
		eb.vx = 0, eb.vy = 0; //적탄 속도벡터 초기화
		eb.rotation = radArr[j]*180/ Math.PI;//라디안에서 도로
		//적탄 속도벡터 배열에서 적용하기
		eb.vx = vxArr[j];
		eb.vy = vyArr[j];
		
		stage.addChild(eb); //적탄 화면에 붙이기
		eBulletArr.push(eb); //적탄 배열에 추가
	}
}
//function ebDirectInit(angle=0, speed=2){ //적 방향탄 생성 및 초기화
//	//매개변수(각도, 이동속도)
//	var eb = new eBullet01M();
//	eb.x = enemy.x, eb.y = enemy.y; //적탄 위치 초기화
//	eb.vx = 0, eb.vy = 0; //적탄 속도벡터 초기화
//	
//	angle += Math.PI/180 * angle; //도에서 라디안으로
//	//적탄 속도벡터 구하기
//	eb.vx = Math.cos(angle)*speed;
//	eb.vy = Math.sin(angle)*speed;
//	
//	stage.addChild(eb); //적탄 화면에 붙이기
//	eBulletArr.push(eb); //적탄 배열에 추가
//}
//적 소용돌이탄 생성 및 초기화
//function ebSpiralInit(angle=0, angleRate=0.5, speed=2){ 
//매개변수(발사각도, 발사 각속도(+:시계방향, -:시계반대방향), 발사 속도)
//	var eb = new eBullet01M();
//	eb.x = enemy.x, eb.y = enemy.y; //적탄 위치 초기화
//	eb.vx = 0, eb.vy = 0; //적탄 속도벡터 초기화
//	
//	ebTheta += angleRate;
//	//적탄 속도벡터 구하기
//	eb.vx = Math.cos(ebTheta)*speed;
//	eb.vy = Math.sin(ebTheta)*speed;
//	
//	stage.addChild(eb); //적탄 화면에 붙이기
//	eBulletArr.push(eb); //적탄 배열에 추가
//}
function eBulletMove(){ //적 총탄 이동 처리
	//eBulletArr내 null값 요소 제거
	eBulletArr = eBulletArr.filter(eraseNull);
	for(var i=0; i < eBulletArr.length; ++i){
		var eb = eBulletArr[i];
		if(eb.x > -20 && eb.x < stage.stageWidth 
		   && eb.y > -20 && eb.y < stage.stageHeight){ 
			//적탄이 화면내 존재시
			eb.x += eb.vx; //기존 적탄 위치 더하기 속도 벡터
			eb.y += eb.vy;
		}else{ //적탄이 화면 밖으로 나갔을 경우
			try{
				stage.removeChild(eb); //적탄 화면에서 제거
			}catch(er:Error){ trace("removeChild error"); }
			eBulletArr[i] = null; //적탄 배열서 비우기 위해 null 넣기
			continue; //다음으로 넘어가기
		}
	}
}
function eraseNull(element:*,index:uint,array:Array):Boolean{
	//배열 내부의 null 제거용 함수
	return (element != null);
}

init();