Flash CS4로 '유니티로 만드는 게임 개발 총론' 2D 정점 기반의 우주 슈팅 게임 예제 구현하기 테스트.

우주선이 행성쪽으로 접근하며 총알을 발사하고 다시 출발점으로 돌아왔다가 다시 공격하는 행동의 반복, 총알과 행성 충돌시 폭파효과 무비클립 붙이기.
우주선 회전시 각도변화를 세분화시키는 것 이외의 기능은 모두 완료했다.
한데 공격 이후 돌아올 때 속도가 차츰 느려졌다가 다시 공격시 빠르고 일정한 속도로 이동하는, 의도치 않은 움직임을 보인다.

그나저나 이 작업을 해보면서 새삼 유니티의 능력에 놀라다. 액션스크립트 3.0에서의 아래처럼 제법 장황하고 긴 코드가 유니티에선 훨씬 간략하고 쉽게 처리된다. C나 자바 등에 비해 액션스크립트 3.0이 훨씬 간략하게 코딩할 수 있는데 유니티는 그보다 더 간략한 코딩이 가능한 듯 보인다.

15/7/14 화

화면에 'playerM', 'planetM'이란 이름의 주인공과 행성 무비클립(무비클립 내에는 'hit'이란 이름의 충돌체크용 원 무비클립을 만들어 두었다)을 만들어 두고, 'shotM'이란 익스포트명의 주인공 총알 무비클립, 'boomM'이란 이름의 폭파 애니 무비클립을 라이브러리에 만들어 두다.

var player = playerM;
var planet = planetM;

var preAng=0; // 주인공 이전 각도 저장용
var pSpeed=2; //주인공 이동속도
var pbSpeed=3; //주인공 총알 이동속도
var pVx, pVy; //주인공 이동속도 저장용
var pStartX, pStartY; //주인공 시작지점 저장용
var distance=0; //주인공과 행성 거리 저장용
var pState; //주인공 상태 저장용
var reloadTime=500; //주인공 총알 재장전 대기시간용(0.5초)
var lastShotTime=0; //마지막 샷 발사 시간 저장용

var bulletArr:Array = new Array();
var boomArr:Array = new Array();
//************************************************************
// 초기화 함수
//************************************************************
function init(){
	pStartX = player.x, pStartY = player.y;
	player.rotation = lookAtAB(player.x, planet.x, player.y, planet.y); 
	//주인공 행성쪽으로 회전
	
	stage.addEventListener(Event.ENTER_FRAME, update);
}
//************************************************************
// 메인 루프 함수
//************************************************************
function update(e:Event){
	distance = distanceAB(player.x, planet.x, player.y, planet.y); 
	//주인공과 행성 거리 구하기 함수 호출
	if(distance > 350){ //주인공과 행성 거리에따라 분기
		pState = "Attack";
	}else if(distance < 100){
		pState = "Retreat";
	}
	if(pState == "Attack"){
		pAttack();
	}else if(pState == "Retreat"){
		pRetreat();
	}
	pMove(); //주인공 움직임 처리
	pbMove(); //주인공 총알 움직임 처리
	eHitAniMove(); //폭파 애니 움직임 처리
}
//************************************************************
// 주인공 움직임 관련 함수
//************************************************************
function pAttack(){ //주인공 공격 처리
	pVx = -(player.x-planet.x)/distance*pSpeed; //주인공 이동속도 설정
	pVy = -(player.y-planet.y)/distance*pSpeed;
	player.rotation = lookAtAB(player.x, planet.x, player.y, planet.y); 
	//주인공 행성쪽으로 회전
	
	if(lastShotTime + reloadTime < getTimer()){ //총알 대기시간 지나면
		pShoot(player.rotation); //총알 발사 함수 호출
		lastShotTime = getTimer(); //마지막 총알 발사시간 갱신
	}
}
function pRetreat(){ //주인공 후퇴 처리
	pVx = -(player.x-pStartX)/distance*pSpeed;
	pVy = -(player.y-pStartY)/distance*pSpeed;
	player.rotation =lookAtAB(player.x, pStartX, player.y, pStartY); 
	//주인공 행성 시작점으로 회전
}
function pMove(){ //주인공 움직임 처리
	player.x += pVx;
	player.y += pVy;
}
//************************************************************
// 주인공 총알 관련 함수
//************************************************************
function pShoot(angle=0){ //주인공 총알(방향탄) 발사
	var b = new shotM();
	b.x = player.x, b.y = player.y; //탄 위치 초기화
	b.vx = 0, b.vy = 0; //탄 속도벡터 초기화
	b.life = 100;
	b.rotation = angle;
	
	angle = Math.PI/180 * angle; //도에서 라디안으로
	//탄 속도벡터 구하기
	b.vx = Math.cos(angle)*pbSpeed;
	b.vy = Math.sin(angle)*pbSpeed;
	
	stage.addChild(b); //탄 화면에 붙이기
	bulletArr.push(b); //탄 배열에 추가
}
function pbMove(){ //주인공 총알 움직임 처리
	bulletArr = bulletArr.filter(eraseNull);
	var pb;
	for(var i=0; i < bulletArr.length; ++i){
		pb = bulletArr[i];
		if(pb.life > 0){//탄의 여명 존재시
			pb.x += pb.vx; //기존 탄 위치 더하기 속도 벡터
			pb.y += pb.vy;
			pBulletCollisionCheck(pb, i);//탄과 적 충돌 체크 함수호출
			pb.life--; //탄 여명 출이기
		}else{ //탄 여명 부재시
			pbDestroy(pb, i); //탄 제거
			continue; //다음으로 넘어가기
		}
	}
}
function pBulletCollisionCheck(pb, id){ //탄과 적 충돌 체크
	if(pb.hitTestObject(planet.hit)){ //총알과 행성 충돌시
		eHitAniCreate(pb);//불꽃튀는 애니 처리 함수 호출
		pbDestroy(pb, id); //총알 제거 함수 호출
	}
}
function pbDestroy(pb, id){ //주인공 총탄 제거 처리
	arrDestroy(pb, id, bulletArr);
}
//************************************************************
// 폭파 애니 관련 함수
//************************************************************
function eHitAniCreate(pb){//폭파 애니 생성 함수
	var eh=new boomM();
	eh.x = pb.x, eh.y = pb.y;//위치설정
	eh.life = 60; //유지시간(2초)
	
	stage.addChild(eh); //화면에 붙이기
	boomArr.push(eh);//아이템 배열에 추가
	eh.play();//프레임 시작.
}
function eHitAniMove(){ //폭파 애니 움직임 처리
	boomArr = boomArr.filter(eraseNull);
	var eh;
	for(var i=0; i < boomArr.length; ++i){
		eh = boomArr[i];
		if(eh.life > 0){//여명 존재시
			eh.life--; //여명 출이기
		}else{ //
			eHitDestroy(eh, i); //폭파 애니 제거
			continue; //다음으로 넘어가기
		}
	}
}
function eHitDestroy(eh, id){ //폭파 애니 제거 처리
	arrDestroy(eh, id, boomArr);
}
//************************************************************
// 기타 도우미 함수들
//************************************************************
function distanceAB(aX, bX, aY, bY){ //두 점간 거리 구하기 
	return Math.sqrt((aX-bX)*(aX-bX) + (aY-bY)*(aY-bY));
}
function lookAtAB(aX, bX, aY, bY){ //b쪽으로 향하는 각도 반환
	var dx = bX-aX;
	var dy = bY-aY;
	var ang = Math.atan2(dy, dx);
	return ang * 180/Math.PI; //라디안에서 도로 변화해 반환
}
function eraseNull(element:*,index:uint,array:Array):Boolean{
	//배열 내부의 null 제거용 함수
	return (element != null);
}
function arrDestroy(item, id, arr:Array){ //배열내 해당요소 제거 처리
	try{
		stage.removeChild(item); //해당 요소 화면에서 제거
	}catch(er:Error){ trace("pBullet removeChild error"); }
	arr[id] = null; //해당요소 배열에서 비우기 위해 null 넣어두기
}

init();