화면과 같이 유니티 엔진으로 무한 점프 게임을 만들어 보겠습니다
제작게임 해보기 : Google Play
Game 씬 화면을 16:9 맞춤니다
Scene 폴더를 만들고 씬을 생성하여 이름을 MainGame이라 합니다
Texture 폴더를 만들고 그림 리소스를 드래그 하여 폴더 안에 넣습니다
Audio폴더를 만들고 드래그 하여 사운드 리소스를 넣습니다
MainCamera를 선택하여 그림과 같이 맞춤니다
Sky 텍스쳐를 선택하고 그림과 같이 속성을 바꿈니다
Hierarchy에 Quad를 생성 하여 이름을 Sky라 합니다
Materials폴더를 만들고 Material를 생성하여 Sky라 이름을 붙힙니다
Hierarchy에 Sky를 선택하고 만든 Material을 드래그 하여 붙히고 Shader -> Unlit -> Texture
를 선택합니다
Select창에 sky Texture를 붙힙니다
Sky 오브젝트를 MainCamera자식으로 이동 합니다
그리고 그림과 같이 스케일과 포지션을 바꿉니다
Scripts폴더를 생성하고 SkyCtrl 스크립트를 생성하여 넣습니다
SkyCtrl 스크립트 작성
Sky를 배경으로 하여 배경 스크롤 하는 오브젝트를 짭니다
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SkyCtrl : MonoBehaviour {
float speed = 0.03f;
//------------------------------
// 화면 스크롤
//------------------------------
void Update()
{
float ofsX = speed * Time.time;
transform.GetComponent<Renderer>().material.mainTextureOffset = new Vector2(ofsX, 0);
}
}
SkyCtrl 스크립트를 Sky 오브젝트에 드래그하여 붙힙니다
배경이 좌로 스크롤 되는 것을 확인합니다
Jump_tile 텍스쳐를 선택하여 그림과 같이 속성을 바꿉니다
Jump_tile 텍스쳐를 선택하여 Hierarchy창에 드래그하여 놓고 이름을 Tile 로 바꿉니다
Tile 오브젝트를 선택하여 Tag를 Tile을 생성하여 선택하고 Layer를 Tile를 만들어 선택합니다
TilCtrl 스크립트를 만들어 저장합니다
TilCtrl 스크립트 작성
그림과 같이 Camera 시선에 좌표를 만들어 화면에 벗어나면 삭제되는 스크립트를 작성합니다
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TilCtrl : MonoBehaviour {
//-------------------
// 화면 아래를 벗어나면 제거
void Update()
{
// 월드 좌표를 스크린 좌표로 변환
Vector3 view = Camera.main.WorldToScreenPoint(transform.position);
if (view.y < -50)
{
Destroy(gameObject);
}
}
}
Tile오브젝트에 Tile스크립틀 붙힙니다
Tile 오브젝트를 Prefabs폴더에 드래그하여 프리팹을 만듭니다
tile Sorting Layers tile 을 만들고 선택합니다 Sorting Layer는 아래로 선택할수록 텍스쳐가 위로 보이는 기능입니다
Hierarchy 창에 Tile 오브젝트를 하나더 만들어서 포지션을 조금 높게 설정하여 저장합니다
rabbit_jump2 텍스쳐를 선택하여 드래그하여 Hierarchy창에 올리고 이름을 Player라 합니다
Sorting Layer를 Player를 만들어 선택합니다
MainCamera를 선택하여 빈 오브젝트를 만들고 이름을 spPoint 라고 하고 포지션을 그림과 같이 합니다
Player를 선택하고 그림과 같이 자식으로 오브젝트를 만들어 StartPos 와 EndPos 이름을 붙힙니다
그림과 같이 오브젝트포지션을 Player 발끝에 EndPos 를 놓고 바로 위에 StartPos를 놓습니다
Player를 선택하고 Audio Source를 붙힙니다
PlayerCtrl스크립트를 만들고 PlayerCtrl 스크립트를 작성합니다
PlayerCtrl 스크립트 작성
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class PlayerCtrl : MonoBehaviour {
public Transform tile;
public Transform startPos;
public Transform endPos;
public AudioClip sndJump; // 효과음 및 배경음악
public AudioClip sndGift;
public AudioClip sndBird;
public AudioClip sndStage;
public AudioClip sndOver;
Transform spPoint;
Transform newTile;
float maxY = 0;
int speedSide = 10; // 좌우 이동 속도
int speedJump = 16; // 점프 속도
int gravity = 25; // 추락 속도
Vector3 moveDir = Vector3.zero;
bool isDead = false;
Animator anim;
public Button retryGame;
void Start()
{
anim = GetComponent<Animator>();
// 모바일 단말기 설정
Screen.orientation = ScreenOrientation.LandscapeRight;
Screen.sleepTimeout = SleepTimeout.NeverSleep;
spPoint = GameObject.Find("spPoint").transform;
// Tile 만들기
newTile = Instantiate(tile, spPoint.position, spPoint.rotation) as Transform;
//Cursor.visible = false; // 커서 감추기
retryGame.gameObject.SetActive(false);
}
//-------------------
// 게임 루프
//-------------------
void Update()
{
if (isDead) return;
JumpPlayer(); // Player 점프
MovePlayer(); // Player 이동
MoveCamera(); // 카메라 이동
}
//-------------------
// Player 점프
//-------------------
void JumpPlayer()
{
RaycastHit2D hit;
hit = Physics2D.Linecast(startPos.position, endPos.position, 1 << LayerMask.NameToLayer("Tile"));
if (hit)
{
moveDir.y = speedJump;
AudioSource.PlayClipAtPoint(sndJump, transform.position);
}
}
//-------------------
// Player 이동
//-------------------
void MovePlayer()
{
Vector3 view = Camera.main.WorldToScreenPoint(transform.position);
if (view.y < -50)
{ // 화면 아래를 벗어나면
isDead = true; // 게임 오버
GameOver();
return;
}
moveDir.x = 0; // Player의 좌우 이동 방향
// Mobile 처리
if (Application.platform == RuntimePlatform.Android ||
Application.platform == RuntimePlatform.IPhonePlayer)
{
// 중력 가속도 센서 읽기
float x = Input.acceleration.x;
// 왼쪽으로 기울였나?
if (x < -0.2f && view.x > 35)
{
moveDir.x = 2 * x * speedSide;
}
if (x > 0.2f && view.x < Screen.width - 35)
{
moveDir.x = 2 * x * speedSide;
}
}
else
{ // Keyboard 읽기
float key = Input.GetAxis("Horizontal");
if ((key < 0 && view.x > 35) ||
(key > 0 && view.x < Screen.width - 35))
{
moveDir.x = key * speedSide;
}
}
// 매 프레임마다 점프 속도 감소
moveDir.y -= gravity * Time.deltaTime;
transform.Translate(moveDir * Time.smoothDeltaTime);
//애니메이션 설정
if (moveDir.y > 0)
{
anim.Play("PlayerJump");
}
else
{
anim.Play("PlayerIdle");
}
}
void MoveCamera()
{
// Player 최대 높이 구하기
if (transform.position.y > maxY)
{
maxY = transform.position.y;
// 카메라 위치 이동
Camera.main.transform.position = new Vector3(0, maxY - 2.5f, -10);
// score = (int)maxY * 1000;
}
// 가장 최근의 Tile과 spPoint와의 거리 구하기
if (spPoint.position.y - newTile.position.y >= 4)
{
float x = Random.Range(-10f, 10f) * 0.5f;
Vector3 pos = new Vector3(x, spPoint.position.y, 0.3f);
newTile = Instantiate(tile, pos, Quaternion.identity) as Transform;
// 나뭇가지의 회전방향 설정
int mx = (Random.Range(0, 2) == 0) ? -1 : 1;
int my = (Random.Range(0, 2) == 0) ? -1 : 1;
newTile.GetComponent<SpriteRenderer>().material.mainTextureScale = new Vector2(mx, my);
}
}
//게임 오버 설정
void GameOver()
{
retryGame.gameObject.SetActive(true);
if (GetComponent<AudioSource>().clip != sndOver)
{
GetComponent<AudioSource>().clip = sndOver;
GetComponent<AudioSource>().loop = false;
GetComponent<AudioSource>().Play();
}
}
// 재시작
public void RetryGame()
{
Application.LoadLevel("MainGame");
}
}
Player를 선택하고 Animation을 만든다
Create New Clip 으로 들어가 PlayerIdle 만들고 저장하고 그림과 같이 rabbit_jump2 텍스쳐를 드래그하여 애니메이션을 만든다
Create New Clip 으로 들어가 PlayerJump 이름을 만들고 저장하고 그림과 같이 rabbit_jump 텍스쳐를 드래그하여 애니메이션을 만든다
Main Camera 자식으로 한 Canvas 를 만들어
Button 을 만듭니다
Canvas 의 설정을 그림과 같이 합니다
Button 밑에 있는 Text 도 그림과 같이 속성을 합니다
버튼 크기를 적당히 그림과 같이 배치하고 크기를 조절합니다
Player 오브젝트에 PlayerCtrl스크립트를 연결하고 그림과 같이 오브젝트들을 연결합니다
Tile은 프리팹으로 연결합니다
게임을 실행합니다
영상과 같이 캐릭터가 올라가면 됩니다
bird 스프라이트 하나를 드래그 하여 Hierarchy 창에 올리고 이름을 Bird하 합니다
만든 Bird 오브젝트에 Animation 을 열고 BirdFly 애니메이션 이름을 만들고 bird_107*92*0 ~ 5 스프라이트를 드래그 하여 Animation창에 올려 놓습니다
Bird 오브젝트를 선택하여 Tag를 Bird 를 만들어 선택하고 Sorting Layer를 bird 를 만들어 선택합니다
그리고 Box Coillder2D를 붙힙니다
BirdCtrl 스크립트를 만들어 붙힙니다
BirdCtrl 스크립트 작성
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class BirdCtrl : MonoBehaviour {
public Transform txtScore; // 프리팹
int speed; // 이동 속도
bool isDrop = false; // Use this for initialization
Animator anim;
private void Awake()
{
anim = transform.GetComponent<Animator>();
}
void Update()
{
speed = Random.Range(3, 7);
float amtMove = speed * Time.smoothDeltaTime;
if (!isDrop)
{
AnimateBird();
transform.Translate(Vector3.right * amtMove);
}
else
{ // 아래로 이동
transform.Translate(Vector3.down * amtMove, Space.World);
}
// 화면을 벗어난 오브젝트 제거
Vector3 view = Camera.main.WorldToScreenPoint(transform.position);
if (view.y < -50 || view.x > Screen.width + 50)
{
Destroy(gameObject);
}
}
void AnimateBird()
{
anim.Play("BirdFly");
}
void DropBird()
{
isDrop = true;
// 참새 회전
transform.eulerAngles = new Vector3(0, 0, 180);
// 감점 표시
Transform obj = Instantiate(txtScore) as Transform;
obj.GetComponent<Text>().text = "<color=red><size=22>-1000</size></color>";
// World 좌표를 Viewport 좌표로 변환
var pos = Camera.main.WorldToViewportPoint(transform.position);
obj.position = transform.position;
}
// Update is called once per frame
}
스크립트를 작성하고 Bird 프리팹을 만들어 저장합니다 Hierachy 창에 Bird는 삭제합니다
Canvas 자식으로 Text 를 만들고 이름을 TextCtrl이라 하고속성을 그림과 같이 합니다
TextCtrl 스크립트를 만들고 TextCtrl 오브젝트에 붙힙니다
TextCtrl 오브젝트를 Canvas 자식에서 빼냅니다
TextCtrl 오브젝트의 Scale을 변경 하지마시고 TextCtrl 오브젝트를 프리팹을 만들고 Hierarchy창에 있는 TextCtrl을 삭제합니다
Bird 오브젝트를 선택하고 TextCtrl 프리팹을 txtScore에 붙힙니다
gift1 스트라이트를 선택 드래그 하여 Item1오브젝트를 만듭니다
Item1오브젝트를 선택하여 Tag를 Item1 정하고 Sorting Layer를 Item을 만들어 선택합니다
그리고 BoxCoillder2D를 붙힙니다
ItemCtrl 스크립트 작성
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class ItemCtrl : MonoBehaviour {
public Transform txtScore; // 프리팹
//-------------------
// 화면을 벗어난 Gift 제거
//-------------------
void Update()
{
// World 좌표를 Screen 좌표로 변환
Vector3 view = Camera.main.WorldToScreenPoint(transform.position);
if (view.y < -50)
{
Destroy(gameObject);
}
}
//-------------------
// 점수 표시 - 외부 호출
//-------------------
void DisplayScore(int n)
{
// 점수 표시용 UIText 만들기
Transform obj = Instantiate(txtScore, transform.position, Quaternion.identity) as Transform;
obj.GetComponent<Text>().text = "+" + n * 500;
// World 좌표를 Viewport 좌표로 변환
var pos = Camera.main.WorldToViewportPoint(transform.position);
// obj.position = pos;
// Gift 제거
Destroy(gameObject);
}
}
작성한 스크립트를 Item1에 붙히고 TextCtrl 프리팹을 연결합니다
Item2를 만들어 그림과 같이 합니다
Item3를 만들어 그림과 같이 합니다
Canvas에 Text 3개를 만들어 이름을 그림과 같이 하고 속성을 그림과 같이 합니다
Scene 창에 그림과 같이 대략 적절한 크기와 위치 색깔로 맞춤니다
PlayerCtrl 스크립트를 그립과 같이 수정합니다
PlayerCtrl 스크립트 수정
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class PlayerCtrl : MonoBehaviour
{
public Text tScore; //점수,높이 ,아이템갯수
public Text tHeight;
public Text tItem;
public Transform tile; // 프리팹
public Transform[] item;
public Transform bird;
public Transform startPos;
public Transform endPos;
public AudioClip sndJump; // 효과음 및 배경음악
public AudioClip sndGift;
public AudioClip sndBird;
public AudioClip sndStage;
public AudioClip sndOver;
Transform spPoint;
Transform newTile;
float maxY = 0;
int giftCnt = 0; // 획득한 선물 수
int score = 0; // 득점
int speedSide = 10; // 좌우 이동 속도
int speedJump = 16; // 점프 속도
int gravity = 25; // 추락 속도
Vector3 moveDir = Vector3.zero;
bool isDead = false;
Animator anim;
public Button retryGame;
void Start()
{
anim = GetComponent<Animator>();
// 모바일 단말기 설정
Screen.orientation = ScreenOrientation.LandscapeRight;
Screen.sleepTimeout = SleepTimeout.NeverSleep;
spPoint = GameObject.Find("spPoint").transform;
// Tile 만들기
newTile = Instantiate(tile, spPoint.position, spPoint.rotation) as Transform;
//Cursor.visible = false; // 커서 감추기
retryGame.gameObject.SetActive(false);
}
//-------------------
// 게임 루프
//-------------------
void Update()
{
if (isDead) return;
JumpPlayer(); // Player 점프
MovePlayer(); // Player 이동
MoveCamera(); // 카메라 이동
MakeItem();
UIText();
}
//-------------------
// Player 점프
//-------------------
void JumpPlayer()
{
RaycastHit2D hit;
hit = Physics2D.Linecast(startPos.position, endPos.position, 1 << LayerMask.NameToLayer("Tile"));
if (hit)
{
moveDir.y = speedJump;
AudioSource.PlayClipAtPoint(sndJump, transform.position);
}
}
//-------------------
// Player 이동
//-------------------
void MovePlayer()
{
Vector3 view = Camera.main.WorldToScreenPoint(transform.position);
if (view.y < -50)
{ // 화면 아래를 벗어나면
isDead = true; // 게임 오버
GameOver();
return;
}
moveDir.x = 0; // Player의 좌우 이동 방향
// Mobile 처리
if (Application.platform == RuntimePlatform.Android ||
Application.platform == RuntimePlatform.IPhonePlayer)
{
// 중력 가속도 센서 읽기
float x = Input.acceleration.x;
// 왼쪽으로 기울였나?
if (x < -0.2f && view.x > 35)
{
moveDir.x = 2 * x * speedSide;
}
if (x > 0.2f && view.x < Screen.width - 35)
{
moveDir.x = 2 * x * speedSide;
}
}
else
{ // Keyboard 읽기
float key = Input.GetAxis("Horizontal");
if ((key < 0 && view.x > 35) ||
(key > 0 && view.x < Screen.width - 35))
{
moveDir.x = key * speedSide;
}
}
// 매 프레임마다 점프 속도 감소
moveDir.y -= gravity * Time.deltaTime;
transform.Translate(moveDir * Time.smoothDeltaTime);
//애니메이션 설정
if (moveDir.y > 0)
{
anim.Play("PlayerJump");
}
else
{
anim.Play("PlayerIdle");
}
}
void MoveCamera()
{
// Player 최대 높이 구하기
if (transform.position.y > maxY)
{
maxY = transform.position.y;
// 카메라 위치 이동
Camera.main.transform.position = new Vector3(0, maxY - 2.5f, -10);
// score = (int)maxY * 1000;
}
// 가장 최근의 Tile과 spPoint와의 거리 구하기
if (spPoint.position.y - newTile.position.y >= 4)
{
float x = Random.Range(-10f, 10f) * 0.5f;
Vector3 pos = new Vector3(x, spPoint.position.y, 0.3f);
newTile = Instantiate(tile, pos, Quaternion.identity) as Transform;
// 나뭇가지의 회전방향 설정
int mx = (Random.Range(0, 2) == 0) ? -1 : 1;
int my = (Random.Range(0, 2) == 0) ? -1 : 1;
newTile.GetComponent<SpriteRenderer>().material.mainTextureScale = new Vector2(mx, my);
}
}
void MakeItem()
{
if (Random.Range(1, 1000) < 990) return;
// 오브젝트 표시 위치
Vector3 pos = Vector3.zero;
pos.y = maxY + Random.Range(4, 5.5f);
if (Random.Range(0, 100) < 50)
{
// 참새 만들기
pos.x = -12f;
Instantiate(bird, pos, Quaternion.identity);
}
else
{
for (int i = 1; i < item.Length; i++)
{
// 화면의 선물 수를 5개 이내로 제한
int n1 = GameObject.FindGameObjectsWithTag("Item1").Length;
int n2 = GameObject.FindGameObjectsWithTag("Item2").Length;
int n3 = GameObject.FindGameObjectsWithTag("Item3").Length;
if (n1 + n2 + n3 >= 5) return;
// Item 만들기
pos.x = Random.Range(-5f, 5f);
int n = Random.Range(0, 3);
Transform obj = Instantiate(item[n], pos, Quaternion.identity) as Transform;
}
}
}
void OnTriggerEnter2D(Collider2D coll)
{
switch (coll.transform.tag)
{
case "Item1":
AudioSource.PlayClipAtPoint(sndGift, transform.position);
// 득점 처리
score += 500;
giftCnt++;
// 선물 제거
coll.transform.SendMessage("DisplayScore", 1);
break;
case "Item2":
AudioSource.PlayClipAtPoint(sndGift, transform.position);
// 득점 처리
score += 1000;
giftCnt++;
// 선물 제거
coll.transform.SendMessage("DisplayScore", 2);
break;
case "Item3":
AudioSource.PlayClipAtPoint(sndGift, transform.position);
// 득점 처리
score += 1500;
giftCnt++;
// 선물 제거
coll.transform.SendMessage("DisplayScore", 3);
break;
case "Bird":
if (coll.transform.eulerAngles.z != 0) return;
AudioSource.PlayClipAtPoint(sndBird, transform.position);
score -= 1000;
// 참새 추락 처리
coll.transform.SendMessage("DropBird", SendMessageOptions.DontRequireReceiver);
break;
}
}
void UIText()
{
tScore.text = "Score :" + score;
tHeight.text = "Height :" + (int)maxY;
tItem.text = "Gift :" + giftCnt;
}
//게임 오버 설정
void GameOver()
{
retryGame.gameObject.SetActive(true);
if (GetComponent<AudioSource>().clip != sndOver)
{
GetComponent<AudioSource>().clip = sndOver;
GetComponent<AudioSource>().loop = false;
GetComponent<AudioSource>().Play();
}
}
// 재시작
public void RetryGame()
{
Application.LoadLevel("MainGame");
}
}
수정한 PlayerCtrl 스크립트에 그림과 같이 리소스를 연결합니다
제작게임 해보기 Google Play
게임을 실행하여 동영상과 같이 실행되는지 확인합니다