[SKKU DT] 4일차 -아이템 먹는 미니 게임 완성(스크립트, UI), 개발방법론 조금

2023. 11. 2. 18:19SKKU DT

728x90
반응형

<평면 위에 캐릭터 돌아다니면서 아이템 먹으면 점수 올라가는 게임>

 

캐릭터 움직이기 위한 Inpuit Manager 먼저 확인 (기본 18개, 추가 가능)

 

 


 

 

플레이어 움직이게 하는 스크립트 작성 (+플레이어에 스크립트 컴포넌트 추가)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerControl : MonoBehaviour
{
    public float speed = 5f;

    void Start()
    {
        
    }
    void Update()
    {
        float horizontal = Input.GetAxis("Horizontal");
        float vertical = Input.GetAxis("Vertical");

        //콘솔 창 디버그 로그 확인
        Debug.Log("h: " + horizontal);
        Debug.Log("v: " +  vertical);

        //거리 = 속도 * 시간
        horizontal = horizontal * speed * Time.deltaTime;
        vertical = vertical * speed * Time.deltaTime;

        //이동
        transform.Translate(horizontal * Vector3.right);
        transform.Translate(vertical * Vector3.forward);
    }
}

 

 

 


 

 

카메라가 플레이어를 따라다니게 하기 (카메라에 스크립트 컴포넌트 추가)

(***플레이어와 카메라 사이의 거리를 구한 다음 플레이어가 움직일 때 거리를 계속해서 업데이트)

(거리 d = 카메라의 위치 c - 플레이어의 위치 p,   카메라의 위치 c = 플레이어의 위치 p + 거리 d)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CameraControl : MonoBehaviour
{
    public GameObject player;
    Vector3 distance;  //카메라와 플레이어 사이의 거리 변수


    void Start()
    {
        distance = transform.position - player.transform.position;
    }

    void Update()
    {
        transform.position = player.transform.position + distance;
    }
}

 

**카메라가 버벅거리는 현상 발생 -> 플레이어와 카메라의 Update가 순서가 정해져있지 않기 때문.

 

-> FixedUpdate, Update, LateUpdate의 차이로 해결 가능.

LateUpdate : Update가 끝난 후 프레임당 한 번 호출. 주로 3인칭 카메라에 사용된다.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CameraControl : MonoBehaviour
{
    public GameObject player;
    Vector3 distance;  //카메라와 플레이어 사이의 거리 변수


    void Start()
    {
        distance = transform.position - player.transform.position;
    }

    void LateUpdate()
    {
        transform.position = player.transform.position + distance;
    }
}

 

 


 

 

플레이어 회전 막기 -Rigid Body -Rotation constraints

 

 


 

 

아이템 만들기, 먹어서 없애기 - CallBack 이벤트 함수(On으로 시작하는) 필요 (OnCollisionEnter는 Trigger 아닐 때 충돌 감지 / OnTriggerEnter는 Trigger 감지)

방법 1. Hierarchy 창엔 있지만 비활성화 시키기(v)

방법 2. Hierarchy 창에서도 아예 삭제하기

 

Prefab 사용

그냥 복제와 Prefab 사용의 차이: 프리팹 내부로 들어가서 메테리얼 변경하면 다른 프리팹까지 같이 바뀐다.

 

Item 프리팹에 Tag 달기(item인 것만 먹기 위해서)

private void OnTriggerEnter(Collider other)
{
    if (other.gameObject.CompareTag("item"))
    {
        Debug.Log("트리거 감지");
        other.gameObject.SetActive(false);
    }
}

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.VFX;

public class PlayerControl : MonoBehaviour
{
    public float speed = 5f;
    
    void Start()
    {
        
    }
    void Update()
    {
        float horizontal = Input.GetAxis("Horizontal");
        float vertical = Input.GetAxis("Vertical");

        //콘솔 창 디버그 로그 확인
        //Debug.Log("h: " + horizontal);
        //Debug.Log("v: " +  vertical);

        //거리 = 속도 * 시간
        horizontal = horizontal * speed * Time.deltaTime;
        vertical = vertical * speed * Time.deltaTime;

        //이동
        transform.Translate(horizontal * Vector3.right);
        transform.Translate(vertical * Vector3.forward);
    }

    private void OnCollisionEnter(Collision collision)  //괄호 안은 Argument
    {
        Debug.Log("충돌 감지");
    }

    private void OnTriggerEnter(Collider other)
    {
        if (other.gameObject.CompareTag("Item"))
        {
            Debug.Log("트리거 감지");
            other.gameObject.SetActive(false);
        }
    }
}

 

 


 

 

점수 올리기

-int count; 추가해서 트리거 감지되면 로그 창에 +10점 씩 추가 되는 걸로.

private void OnTriggerEnter(Collider other)
{
    if (other.gameObject.CompareTag("Item"))
    {
        other.gameObject.SetActive(false);  //아이템 비활성화
        count += 10;
        print("Score: " + count);
    }
}

 

 


 

 

UI -점수 표시, 게임 재시작 등 메뉴

Screen Space -Overlay: 무조건 스크린에서만 2차원으로 고정되어 있다고 생각하면 됨. 독립적으로 움직인다.

Screen Space -Camera: 카메라의 Fov를 따라간다. 게임 뷰 위에 캔버스가 올려져 있는 듯.

 

 

이미지와 텍스트 생성 후 PlayerControl 스크립트 수정

using TMPro; 추가

TextPro에서 텍스트를 가져오기

public TextMeshProUGUI scoreText;

 

새 함수 만들기 void SetCount()

void SetCount()
{
    scoreText.text = "Score: " + score.ToString(); //ToString()으로 문자열로 바꾸기
}

 

만든 함수를 void Start();에 추가

void Start()
{
    score = 0;
    SetCount();
}

 

OnTriggerEnter 함수 안에 추가

private void OnTriggerEnter(Collider other)
{
    if (other.gameObject.CompareTag("Item"))
    {
        //Debug.Log("트리거 감지");
        other.gameObject.SetActive(false);  //아이템 비활성화
        score += 10;
        Destroy(other.gameObject);
        SetCount();
    }
}

 

ScoreText 추가

 

 

전체 PlayerControl 스크립트

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;

public class PlayerControl : MonoBehaviour
{
    public float speed = 5f;
    int score;
    public TextMeshProUGUI scoreText;

    void Start()
    {
        score = 0;
        SetCount();
    }
    void Update()
    {
        float horizontal = Input.GetAxis("Horizontal");
        float vertical = Input.GetAxis("Vertical");

        //콘솔 창 디버그 로그 확인
        //Debug.Log("h: " + horizontal);
        //Debug.Log("v: " +  vertical);

        //거리 = 속도 * 시간
        horizontal = horizontal * speed * Time.deltaTime;
        vertical = vertical * speed * Time.deltaTime;

        //이동
        transform.Translate(horizontal * Vector3.right);
        transform.Translate(vertical * Vector3.forward);
    }

    private void OnCollisionEnter(Collision collision)  //괄호 안은 Argument
    {
        Debug.Log("충돌 감지");
    }

    private void OnTriggerEnter(Collider other)
    {
        if (other.gameObject.CompareTag("Item"))
        {
            //Debug.Log("트리거 감지");
            other.gameObject.SetActive(false);  //아이템 비활성화
            score += 10;
            SetCount();
        }
    }

    void SetCount()
    {
        scoreText.text = "Score: " + score.ToString(); //ToString()으로 문자열로 바꾸기
    }
}

 

 


 

 

일정 점수 이상이면 Game Clear 텍스트 활성화

텍스트 생성 후

GameObject public 변수 생성

public GameObject clearText;

 

Start 함수에서 초기에 비활성화

void Start()
{
    score = 0;
    SetCount();
    clearText.SetActive(false);
}

 

SetCount() 함수에서 다 먹으면 true로 변경

void SetCount()
{
    scoreText.text = "Score: " + score.ToString(); //ToString()으로 문자열로 바꾸기
    if(score >= 200) //점수가 일정 이상이면
    {
        clearText.SetActive(true); //Game Clear 텍스트 활성화
    }
}

 

 


 

 

메뉴 패널 만들기

패널 추가

GameClear 텍스트는 패널의 자식으로 넣는다.

패널의 자식으로 버튼 2개 생성.

 

ClearText 부분에 Panel 전체 드래그해서 한번에 뜨게 한다.

 

GameManager 스크립트 생성

 

GameManager 스크립트에 using UnityEngine.SceneManagement; 추가

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;

public class GameManager : MonoBehaviour
{
    public void RestartGame()  //버튼에서 불러올 것이기 때문에 public 붙인다. 버튼에 연결이 되는 함수
    {
        //활성화 되어있는 씬을 다시 불러온다
        SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
        Time.timeScale = 1.0f;  //일시정지 해제
    }

    public void QuitGame()
    {
        Application.Quit();  //실행 말고 빌드에서만 작동함
    }

    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        
    }
}

 

버튼에 함수 매핑

 

 


 

 

아이템 랜덤 생성 PlayerControl Script 최

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;

public class PlayerControl : MonoBehaviour
{
    //필드 선언 스피드, 스코어, UI텍스트
    public float speed = 5.0f;
    int score;
    public TextMeshProUGUI scoreText;
    public GameObject clearText;

    //랜덤 생성을 위한 변수 선언 스폰타임, 스폰스피드, float 타임, 복제를 위한 item
    float spawntime = 3;
    float spawnSpeed;
    public float time = 0;
    public GameObject item;

    void Start()
    {
        score = 0;  //스코어 초기확
        SetCount();  //SetCount 함수 실행
        clearText.SetActive(false);  //GameClear 텍스트 비활성화
    }
    void Update()
    {
        float horizontal = Input.GetAxis("Horizontal");
        float vertical = Input.GetAxis("Vertical");

        //콘솔 창 디버그 로그 확인
        //Debug.Log("h: " + horizontal);
        //Debug.Log("v: " +  vertical);

        //거리 = 속도 * 시간 -> 변수에 대입
        horizontal = horizontal * speed * Time.deltaTime;
        vertical = vertical * speed * Time.deltaTime;

        //이동
        transform.Translate(horizontal * Vector3.right);    
        transform.Translate(vertical * Vector3.forward);

        //이동 제한
        float nowX = transform.position.x;
        float nowZ = transform.position.z;

        if(nowX < -10)
        {
            nowX = -10;
        }
        if (nowX > 10)
        {
            nowX = 10;
        }
        if (nowZ < -10)
        {
            nowZ = -10;
        }
        if (nowZ > 10)
        {
            nowZ = 10;
        }
        transform.position = new Vector3(nowX, 0.5f, nowZ);
        
        //랜덤 출현
        spawnSpeed = Random.Range(1.0f, 5.0f);
        time += Time.deltaTime * spawnSpeed;
        if(time > spawntime)
        {
            time = 0;
            Instantiate(item, new Vector3(Random.Range(-9.0f, 9.0f), 0.25f, Random.Range(-9.0f, 9.0f)), Quaternion.identity);
            item.gameObject.SetActive(true);
        }
    }

    private void OnCollisionEnter(Collision collision)  //괄호 안은 Argument
    {
        if (collision.gameObject.CompareTag("Obstacle"))
        {
            Debug.Log("충돌 감지");
            MeshRenderer mesh = collision.gameObject.GetComponent<MeshRenderer>();
            mesh.material.color = Color.red;
        }
    }

    private void OnCollisionExit(Collision collision)
    {
        if (collision.gameObject.CompareTag("Obstacle"))
        {
            MeshRenderer mesh = collision.gameObject.GetComponent<MeshRenderer>();
            mesh.material.color = Color.green;
        }
    }

    private void OnTriggerEnter(Collider other)
    {
        if (other.gameObject.CompareTag("Item"))
        {
            //Debug.Log("트리거 감지");
            other.gameObject.SetActive(false);  //아이템 비활성화
            score += 10;
            Destroy(other.gameObject);
            SetCount();
        }
    }

    void SetCount()
    {
        scoreText.text = "Score: " + score.ToString(); //ToString()으로 문자열로 바꾸기
        if(score >= 100) //점수가 일정 이상이면
        {
            clearText.SetActive(true); //Game Clear 텍스트 활성화
            Time.timeScale = 0;  //팝업이 뜨면서 게임 일시정지
        }
    }
}

 

 


 

 

완성

 

 


개발 방법론

병렬 형태 개선된 개발 방식

기획자가 아트, 프로그래머에게 각각 의견 전달 가능.

 

기획/프로그래밍/디자인

 

프로그램 

  • 클라이언트
    -엔진 개발, 툴 개발, UI개발
  • 서버
    -네트워크(firebase, photon), DB, 보안
728x90
반응형