상세 컨텐츠

본문 제목

유니티 자동 큐브타워 만들기 테스트중_V1

유니티/기능

by MJ_119 2024. 10. 2. 00:04

본문

 

 

 

보스가 큐브로 만들어진 브레스를 뿜고, 뿜은 브레스(큐브들)가 특정위치에 모이면서 뭉쳐지고 뭉쳐지면 큐브 탑이 생김.

 

- BossAttack.cs

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

public class BossAttack : MonoBehaviour
{
    public GameObject cubePrefab;  // 큐브 프리팹
    public Transform player;  // 플레이어
    public Transform mouth;  // 보스 몬스터의 입 위치
    public float force = 500f;  // 큐브 발사 힘
    public CubeManager cubeManager;  // CubeManager 참조

    void Start()
    {
        for (int i = 0; i < 10; i++)
        {
            // 큐브 생성
            GameObject cube = Instantiate(cubePrefab, mouth.position, Quaternion.identity);

            // 플레이어 방향으로 발사
            Vector3 direction = (player.position - mouth.position).normalized;
            cube.GetComponent<Rigidbody>().AddForce(direction * force);

            // CubeManager에 생성된 큐브 등록
            cubeManager.AddCube(cube);
        }
    }
}

 

 

- CubeManager.cs

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

public class CubeManager : MonoBehaviour
{
    [SerializeField] List<GameObject> cubes = new List<GameObject>();  // 동적 리스트 선언

    private bool isStacked = false;

    void Update()
    {
        //큐브가 모두 모였는지 확인(모두 목표 위치에 도착)
        if (!isStacked && AllCubesAreInPosition())
        {
            // 큐브를 부모-자식 계층으로 연결하여 스택 쌓기
            StackCubes();
            isStacked = true;
        }

        //Debug.Log("Cube : " + AllCubesAreInPosition());
    }

    public void AddCube(GameObject cube)
    {
        // cubes 리스트에 큐브 추가
        cubes.Add(cube);  // 큐브 추가
    }

    public bool AllCubesAreInPosition()
    {
        // 큐브들이 모두 목표 위치에 도착했는지 확인
        foreach (GameObject cube in cubes)
        {
            if (Vector3.Distance(cube.transform.position, cube.GetComponent<mergeTest>().targetPosition) > 2f)
                return false;
        }
        return true;
        
    }

    void StackCubes()
    {
        

        Destroy(cubes[0].GetComponent<Rigidbody>());
        // 큐브의 Y 높이를 구함 (기본적으로 큐브의 Y scale의 절반을 사용)
        float cubeHeight = cubes[0].transform.localScale.y;
        cubes[0].transform.rotation = Quaternion.Euler(0, 0, 0);
        for (int i = 1; i < cubes.Count; i++)
        {
            Destroy(cubes[i].GetComponent<Rigidbody>());
            cubes[i].transform.rotation = Quaternion.Euler(0, 0, 0);
            cubes[i].transform.position = new Vector3(cubes[i-1].transform.position.x, cubes[i - 1].transform.position.y + cubeHeight, cubes[i-1].transform.position.z);
            
        }



        // 첫 번째 큐브를 부모로 설정하고 그 위에 큐브를 차례대로 스택 쌓기
        for (int i = 1; i < cubes.Count; i++)  // 첫 번째 큐브는 기준이므로 i = 1부터 시작
        {
            cubes[i].transform.parent = cubes[i - 1].transform;  // 이전 큐브를 부모로 설정

            // 이전 큐브를 부모로 설정 (월드 좌표 유지)
            //cubes[i].transform.SetParent(cubes[i - 1].transform, false);
        }

        // 새로 생긴 큐브 탑에 NavMeshObstacle 추가하기. (지나다니지 못하게 하기 위함)
        AddNavMeshObstacle();


        // CubeStack 스크립트를 추가하여 추가적인 기능이 필요하면 처리
        //CubeStack stackScript = gameObject.AddComponent<CubeStack>();
        //stackScript.cubes = cubes;
        //stackScript.StackCubes();

        // 탑의 마지막 큐브에 IK 적용을 위한 TowerRigging 추가
        AddRiggingToTopCube();
    }



    private void AddNavMeshObstacle()
    {
        NavMeshObstacle obstacle = cubes[0].AddComponent<NavMeshObstacle>();
        obstacle.carving = true;  // NavMesh가 이 오브젝트 주변을 실시간으로 업데이트
        obstacle.size = new Vector3(1f, 10f, 1f);  // 탑의 크기에 맞춰 사이즈 설정
    }

    void AddRiggingToTopCube()
    {
        // 탑의 마지막 큐브에 TowerRigging 스크립트를 추가
        Transform headCube = cubes[cubes.Count - 1].transform;  // 마지막 큐브 선택
        TowerRigging rigging = headCube.gameObject.AddComponent<TowerRigging>();
        rigging.player = GameObject.FindGameObjectWithTag("Player").transform;  // 플레이어 타겟 설정
        rigging.headCube = headCube;  // 마지막 큐브를 머리로 설정
    }
}

 

- TowerRigging.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Animations.Rigging;

public class TowerRigging : MonoBehaviour
{
    public Transform player;  // 플레이어 타겟
    public Transform headCube;  // 탑의 머리 큐브 (마지막 큐브)

    void Start()
    {
        // Rig 설정
        Rig rig = headCube.gameObject.AddComponent<Rig>();

        // IK ChainIKConstraint 추가
        ChainIKConstraint ik = headCube.gameObject.AddComponent<ChainIKConstraint>();
        ik.data.target = player;  // 플레이어를 타겟으로 설정
    }
}

 

- mergeTest.cs

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

public class mergeTest : MonoBehaviour
{
    public Vector3 targetPosition;  // 탑의 일자 위치
    public float moveSpeed = 2f;  // 이동 속도
    GameObject cubeManager;
    mergeTest mergeTestV;

    private void Start()
    {
        cubeManager = GameObject.FindGameObjectWithTag("CubeManager");
        mergeTestV = GetComponent<mergeTest>();
    }
    void Update()
    {
        if( !cubeManager.GetComponent<CubeManager>().AllCubesAreInPosition() )
        // 큐브가 3초 후 이동을 시작
        StartCoroutine(MoveToTarget());

        mergeTestV.enabled = false;
    }

    IEnumerator MoveToTarget()
    {
        // 5초 기다림
        yield return new WaitForSeconds(3f);

        // 큐브를 목표 위치로 이동
        while (Vector3.Distance(transform.position, targetPosition) > 1f)
        {
            transform.position = Vector3.MoveTowards(transform.position, targetPosition, moveSpeed * Time.deltaTime);
            yield return null;
        }
    }
}

 

 

 

관련글 더보기