본문 바로가기
Development/멋쟁이사자처럼 게임개발 부트캠프

[멋쟁이사자처럼 Unity 게임 부트캠프 4기] 14일차 - 1945Game (1)

by jjeondeuk1008 2025. 3. 19.
반응형

 

[ 목차 ]


     

    오늘은 유명한 게임 모작 실습을 진행할 것이다.

    드래곤 플라이트에 이어서 1945!!

     

    유명한 슈팅 게임인 만큼 소스를 활용해서 만들어 볼 것이다.

     

    이것만 잘 따라오면 누구나 간단한 게임을 만들 수 있을 것이다.

    물론 나역시도 ^.^...

     

    게임 개발 고수가 되기 위해 레츠고~

     

     


     

     

    1. 빌드 설정

     

     

    우린 보통 어떤 게임을 만들지부터 생각한다.

    모바일? PC?

     

    그에 따라 해상도가 달라질 것이다.

    이것을 초기에 설정해둘 수 있는데

     

    File - Build Profiles

     

     

     

    모바일하려면 Switch Platform으로 기존 빌드 세팅을 변경해도 됨

    이렇게 세팅해두면 좋은 점이 Game 뷰에서 화면 해상도 템플릿이 제공된다.

     

     

     


     

    2. 배경 추가

     

     

    드래곤 플라이트와 비슷하다.

    무한 배경을 만들 것이다.

     

    메테리얼을 생성하고,

     

    Shader

    Mobile - Particels - Alpha Blended

     

    particle Texture에 배경 이미지 삽입

     

     

     

    Quad을 생성해 만든 메테리얼을 Quad으로 넣어준다.

     

    이미지의 비율이 넓을 경우

    Quad의 비율을 늘려 맞춰준다.

     

     

     

     

    화질을 개선하기 위해 배경의 이미지 Max Size를 높은 걸로 선택해 apply 한다.

     

     

     

     

    추가적으로 Wrap Mode, Filter ModeRepeat, Point (no fillter)로 변경하면

    더욱 선명해진다.

     

     

     

     

    이제 무한배경 스크립트를 만들 것이다.

    Background 스크립트 생성

    using UnityEngine;
    
    public class Background : MonoBehaviour
    {
        public float scrollSpeed = 1.2f;
        Material myMaterial;
    
        void Start()
        {
            myMaterial = GetComponent<Renderer>().material;
        }
    
        void Update()
        {
            Vector2 newOffset = myMaterial.mainTextureOffset;
    
            newOffset.Set(0, newOffset.y + (scrollSpeed * Time.deltaTime));
    
            myMaterial.mainTextureOffset = newOffset;
        }
    }
    
    

     

     

     

     


     

    3. Player

     

     

    (1) Player 생성

     

     

    에셋이나 그림을 가져오면 여러 개의 이미지가 하나로 묶여있는 경우가 있을 것이다.

    이것을 나누어주는 방법부터 시작할 것이다.

     

    누끼가 안 되어 있다면 포토샵 혹은 여러 툴을 사용해 누끼를 없애고 시작하는 게 좋다.

     

     

     

     

    Sprite Mode는 Multiple

    나누어줄 Sprite를 선택하고 Open Sprite Editor를 클릭

     

     

     

    Sprite Editor가 켜지면 왼쪽 상단에 slice가 있다.

     

     

     

     

    Type의 Automatic은 컴퓨터가 스스로 자를 범위를 정한다는 것이다.

     

     

     

    동일하게 나눠주기 위해 Grid By Cell SIze 혹은

     

     

     

    Grid By Cell Count에서 C를 2로 늘려주는 방법이 있다.

    이 빨간색 라인이 나눌 범위를 지정하는 것이다.

     

     

     

    slice를 누르고 Apply를 클릭하면 이렇게 Player sprite 안에서 나누어진 것을 확인할 수 있다.

     

     

     

    (2) Player 움직이기

     

     

    이제 방향키로 움직일 스크립트를 작성할 것이다.

    Player 스크립트를 생성한다.

    using UnityEngine;
    
    public class Player : MonoBehaviour
    {
        //스피드
        public float moveSpeed = 5f;
    
        void Start()
        {
            
        }
    
        void Update()
        {
            //방향키에 따른 움직임
            float moveX = moveSpeed * Time.deltaTime * Input.GetAxis("Horizontal");
            float moveY = moveSpeed * Time.deltaTime * Input.GetAxis("Vertical");
    
            transform.Translate(moveX, moveY, 0);
        }
    }
    
    

     

     

     

    여기서 화면 밖으로 넘어가지 않는 2가지 방법이 있다.

     

    (1) 스크립트로 조정 (위의 방향키 이동도 포함)

    using UnityEngine;
    
    public class PlayerController : MonoBehaviour
    {
        public float speed = 5f;
        private Vector2 minBounds;
        private Vector2 maxBounds;
    
        void Start()
        {
            // 화면의 경계를 설정
            Camera cam = Camera.main;
            Vector3 bottomLeft = cam.ViewportToWorldPoint(new Vector3(0, 0, 0));
            Vector3 topRight = cam.ViewportToWorldPoint(new Vector3(1, 1, 0));
    
            minBounds = new Vector2(bottomLeft.x, bottomLeft.y);
            maxBounds = new Vector2(topRight.x, topRight.y);
        }
    
        void Update()
        {
            // 플레이어 이동
            float moveX = Input.GetAxis("Horizontal") * speed * Time.deltaTime;
            float moveY = Input.GetAxis("Vertical") * speed * Time.deltaTime;
    
            Vector3 newPosition = transform.position + new Vector3(moveX, moveY, 0);
    
            // 경계를 벗어나지 않도록 위치 제한
            newPosition.x = Mathf.Clamp(newPosition.x, minBounds.x, maxBounds.x);
            newPosition.y = Mathf.Clamp(newPosition.y, minBounds.y, maxBounds.y);
    
            transform.position = newPosition;
        }
    }
    

     

     

     

     

    (2) 벽 생성 및 콜라이더로 막기

     

     

    화면 넘어가는 것을 스크립트 만들지 않고, wall을 생성해 막는 방법도 있다. (지난 번과 동일: 드래곤 플라이트편 참고)

    상하좌우 벽을 화면 바깥 경계면에 붙인다.

     

     

     

     

    Box Collider 2D 생성

     

     

     

     

    Order in Layer 0에서 1로 변경

     

     

     

     

    wallGroup으로 묶어주는 게 편할 것이다.

     

     

     

     

    작업할 때 흰 벽이 거슬린다면, Inspector의 Sprite Renderer 체크 박스를 해제해 보이지 않게 한다.

     

     

     

     

     

    (3) Player 애니메이션

     

     

    우선 애니메이션을 구현할 때 정석의 방법과 간편한 방법이 있다.

    간편한 방법은 정석의 과정을 5분의 1로 스킵한 느낌이다.

     

    먼저 정석의 방법이다.

     

    Project에서 마우스 우클릭 - Create - Animation - Animator Controller를 생성후 이름을 지정한다.

     

     

     

     

    Window - Animation - Animation 클릭 후 생성

     

     

     

     

    Animation이 생성되면 이러한 창이 뜰 것이다.

    생성할 오브젝트를 Hierarchy를 클릭 후 Animaiton의 Create로 드래그한다.

     

     

     

     

     

    드래그 한 뒤에는 Animation 창이 이러할 것이다.

    여기에서 나눈 이미지를 ctrl 누른 상태로 클릭한 뒤에

    Add Property 쪽으로 드래그한다.

     

     

     

     

     

    이미지가 Animation에 붙는 것을 볼 수 있다.

    마름모 모양을 조절하면서 애니메이션 텀을 조절한다.

     

    이것이 정석의 방법이다.

     

     

     

     

    그렇다면 간편한 방법은?

     

    Player의 화살표를 열어보면 slice로 나눈 2개의 플레이어를

    ctrl를 누르면서 클릭해 두 가지를 동시에 선택한다.

     

    누른 이미지를 hierarchy에 드래그 한다.

     

     

     

     

    파일형식이 anim로 저장하는 창이 나온다.

    파일 이름을 정해 저장한다.

     

     

     

     

    이렇게 되면 Player Animation ClipAnimator Controller 두 가지가 생성된다.

     

     

     

     

    네모난 아이콘 (Animator Controller)를 더블 클릭하면 Animator 창이 나올 것이다.

     

     

     

     

    Player 오브젝트에 animator를 붙여주도록 한다. (Animator Controller)

     

     

     

     

    이게 끝이다!!! 정말 끝이다!! 간편한 방법이 이래서 많이 쓰이는 것 같다.

    꿀팁 최고!

     

     

     

     

     

     

    이제 이어서 애니메이션을 관리하는 것부터 다시 시작한다.

     

    그전에!

    현재 Hierarchy에 넣었는데 Scene에서 안 보일 수 있다.

    이건 뒤에 있다는 뜻인데,

     

    Inspector에서 Sprite Renderer - Order in Layer를 0에서 1로 변경하면 앞으로 보일 것이다.

     

     

     

     

    이젠 크기가 너무 작은 문제가 있을 것이다.

    그것을 해결하기 위해

    Pixels Per unit 100에서 32로 줄이기

     

    이렇게 하면 크기가 전보다 커질 것이고,

    Wrap Mode와 Filter Mode를 조절하면 좀 더 선명해질 수 있다.

     

     

     

     

     

    이제 플레이어가 왼쪽으로 갈 때의 애니메이션과 오른쪽으로 갈 때의 애니메이션을 추가할 것이다.

    이미지를 Player 오브젝트에 드래그 앤 드롭을 한다.

     

     

    그렇다면 각각의 Animator가 생성 되어있는 것을 알 수 있다.

     

     

     

     

    Animator 창에 left와 right가 생성된 것을 알 수 있다.

     

     

     

     

     

    Animator 창의 왼쪽 위에 Parameters 누른다.

    ‘+’ 버튼을 눌러 Bool을 선택해 left , right 이름으로 된 parameter를 생성한다.

    대소문자가 구문 되어야한다.

     

     

     

     

    생성된 모습

     

     

     

     

     

    Player를 선택하고 마우스 오른쪽 클릭 Make Transition 클릭

     

     

     

     

    화살표 모양의 선이 나타날 것인데 right에 연결한다.

     

     

     

     

    Player의 Inspector를 가면 Transitions의 ‘=’ 모양을 클릭한다.

    아래의 모습으로 보여질 것이다.

     

     

     

     

    Has Exit Time은 애니메이션 전환을 특정 시간에 발생시키는 것이다.

    도중에 다음 애니메이션으로 바뀌지 않고,

    정해진 시간만큼 반드시 애니메이션을 구현한 뒤에 변경해준다는 것이다.

     

    현재 적용하는 애니메이션은 그런 기능이 필요하지 않기 때문에

    Has Exit Time를 체크 해제한다.

     

    그리고 Conditions의 ‘+’ 버튼을 눌러 right / true로 변경한다.

    이것은 right가 true가 되면 Player_right 애니메이션을 실행한다는 뜻이다.

     

     

     

     

    반대로 Player_right에서 Make Transition를 선택해 다시 Player에게 향하는 화살표로 적용한다.

    아까와 같이 Has Exit Time을 해제하고,

     

    Conditions에서는 right가 실행되지 않았을 때 다시 기본 자세로 돌아가야 하기 때문에

    right / false 상태로 해둔다.

     

     

     

     

    이러한 방식으로 Player_left도 적용해준다.

     

     

     

     

    Player에 animator 스크립트를 추가할 것이다.

    using UnityEngine;
    
    public class PlayerController : MonoBehaviour
    {
        public float speed = 5f;
        private Vector2 minBounds;
        private Vector2 maxBounds;
    
        Animator ani; //애니메이터를 가져올 변수
    
        void Start()
        {
            ani = GetComponent<Animator>();
    
            // 화면의 경계를 설정
            Camera cam = Camera.main;
            Vector3 bottomLeft = cam.ViewportToWorldPoint(new Vector3(0, 0, 0));
            Vector3 topRight = cam.ViewportToWorldPoint(new Vector3(1, 1, 0));
    
            minBounds = new Vector2(bottomLeft.x, bottomLeft.y);
            maxBounds = new Vector2(topRight.x, topRight.y);
        }
    
        void Update()
        {
            // 플레이어 이동
            float moveX = Input.GetAxis("Horizontal") * speed * Time.deltaTime;
            float moveY = Input.GetAxis("Vertical") * speed * Time.deltaTime;
    
            //애니메이션 조건문
            // -1   0   1
            if (Input.GetAxis("Horizontal") <= -0.5f)
            {
                ani.SetBool("left", true);
            }
            else
                ani.SetBool("left", false);
    
            if (Input.GetAxis("Horizontal") >= 0.5f)
            {
                ani.SetBool("right", true);
            }
            else
                ani.SetBool("right", false);
    
            Vector3 newPosition = transform.position + new Vector3(moveX, moveY, 0);
    
            // 경계를 벗어나지 않도록 위치 제한
            newPosition.x = Mathf.Clamp(newPosition.x, minBounds.x, maxBounds.x);
            newPosition.y = Mathf.Clamp(newPosition.y, minBounds.y, maxBounds.y);
    
            transform.position = newPosition;
        }
    }
    

     

     

     

     

     

    위의 상태로 실행해보면

    Player_left와 Player_right가 애니메이션이 반복되는 느낌이 있을 것이다.

     

    이것은 Animation Clip이 반복되고 있다는 것인데,

    Clip의 Inspector의 Loop Time 체크박스를 해제한다.

    이러면 반복이 되지 않는다.

     

     

     

     

    up도 구현해줄 것이다. 위로 향할 때의 애니메이션을 적용하는 것이다.

    방법은 동일하다.

     

    Player_Up에서는 Loop Time 해제를 안 했다.

    이건 개인적인 설정에 따라 유동적으로 하면 될듯하다.

     

     

     

     

     

    이제 스크립트로 bool을 조절해줄 것이다.

    이 코드를 PlayerController에 추가한다.

    if (Input.GetAxis("Vertical") >= 0.1f)
    {
        ani.SetBool("up", true);
    }
    else
    {
        ani.SetBool("up", false);
    }
    

     

     

     

     

     


     

     

    4. Sound 추가 (BGM)

     

     

    Main Camera에 Audio Source를 추가해서 원하는 bgm을 넣는다.

     

     

     

     


     

    5. 적 추가

     

     

    플레이어와 동일하게 누끼를 따고 Sprite로 나눈다.

    애니메이션을 적용하고 싶다면 적용하고,

    지금은 애니메이션 없이 하나의 그림으로 적을 사용할 생각이다.

     

     

    Order in Layer를 1로 지정해주고,

    Monster를 Hierarchy에 추가하고 Box Collider 2D를 추가한다.

    Edit Collider를 눌러 범위를 조정해준다.

     

     

     

     

     

    뷰에서 몬스터의 크기가 매우 작을 시에는 Sprite Inspector에서

    Pixel Per Unit을 100에서 줄어들어야 커진다.

     

     

     

     

     


     

    6. Item 추가

     

     

     

    플레이어를 만들었던 했던 방식과 동일하다.

    나눠진 Strite PNG를 모두 선택해 Hierarchy에 드래그한다.

    (오브젝트로 드래그 하는 거 아님!!! Hierarchy 빈 곳에 !)

     

    그렇게 되면 파일 창이 열려서 Anim의 형식이 된 이름을 저장하게 되면

    Item의 Animator와 Animation Clip이 자동 생성된다.

     

     

     

    이제 Item 스크립트를 생성한다.

    using UnityEngine;
    
    public class Item : MonoBehaviour
    {
        public float ItemVelocity = 20f;
        Rigidbody2D rig = null;
    
        void Start()
        {
            rig = GetComponent<Rigidbody2D>();
            rig.AddForce(new Vector3(ItemVelocity, ItemVelocity, 0f));
        }
    
        void Update()
        {
            
        }
    }
    
    

     

     

     

    중력 0은 기본으로 해두고,

    Constraints - Freeze Rotation Z값 체크를 하면

    아이템이 z값으로 빙글빙글 돌아가는 걸 못하게 막는 것이다.

     

    스크립트의 Item Velocity(속도) 100으로 높여준다.

     

     

     

    이제 메테리얼을 만들 것이다.

    우리가 아는 메테리얼과 조금 다를 수 있으니 방심하지 말것

     

    Project 마우스 우클릭 - Create - 2D - Physics Material 2D

     

     

     

     

    이런 테니스 모양의 공이 있는 아이콘으로 메테리얼이 생기고, 이름을 지정해준다.

    Friction 0 / Bounciness 1 로 설정한다.

     

     

     

     

    이 Bounce를 적용하는 데에도

    여기에서도 2가지 방안이 있다.

     

     

    (1) 첫 번째 방안

     

    벽 4개의 Box Collider 2D - Material에 만들었던 Bounce 넣기

     

     

     

     

    (2) 두 번째 방안

     

    벽에 넣지 않고, 바운스가 될 Item 오브젝트의 rigidbody 2D - Material에 Bounce 넣기

     

     

     

    Item이 Monster를 통과하지 않게 is Trigger 체크하기

     

     

     

     

    하지만 여기에서 문제점이 발생할 수 있다.

    아이템이 여러 개일 때, 그들끼리 충돌하게 되면 복잡해지고 벽에 붙는 일이 발생한다.

     

    이럴 때를 위해 아이템끼리 충돌하지 않는 방법이 있다.

     

    Item의 Layer - Add Layer

     

     

    Layer 6에 새로 Item으로 추가한다.

    추가한 Item Layer를 Item 오브젝트에 적용한다.

     

     

     

    Edit - Project Settings - Physics - LayerCollsion Matrix

    여기에서 Item 체크를 해제한다. (Item과 Item이 충돌한다는 체크박스)

     

     

     


     

    오늘은 1945 게임을 구현해보는 첫 번째 실습날이었다.

    유니티는 역시 내가 모르는 엄청난 기능들이 많았다는 것을 다시 한 번 느끼게 되었다.

     

    아직 GPT는 못 따라 갈 정도의 활용법이다.

     

    꿀팁이 이리 많다니!

    오늘은 진짜 꿀팁 대방출 느낌이었다.

     

    이래서 강의 듣나봐요.. 듣길 정말 잘한듯 !

     

     

     

     

     


    목차