유튜브(Youtube) Vagabond Developer(방랑개발자)님의 How to completely make 'Minecraft'(마인크래프트를 통째로 만드는 방법)을 따라하면서 유니티(Unity)를 알아가고 있습니다. 그 정리입니다.
https://www.youtube.com/watch?v=xNozfY_Iah8
04-땅표면 아래를 흙블럭과 돌블럭로 채우기
01-기본설정 및 평평한 땅 만들기에서 GrassBlock의 프리팹(Prefab)을 작성한 것과 동일한 방식으로 DirtBlock, StoneBlock의 프리팹(Prefab)을 작성
이미지를 준비해 텍스처작성 / 큐브(Cube)를 추가하고 머티리얼(Material)입히기 / 프리팹(Prefab) 작성
구글(Google) 이미지검색에서 dirt,stone를 아이콘사이즈로 검색해서 Dirt, Stone으로 저장, 팝업메뉴의 (Import New Asset...)로 임포트(Import)하거나 드래그해서 Textures폴더에 넣음
WorldGenerator스크립트(Script) 코딩
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class WorldGenerator : MonoBehaviour
{
public GameObject player; //플레이어 설정용
public int sizeX;
public int sizeZ;
public int groundHeight; //땅의 깊이
public float terDetail; //Mathf.PerlinNoise적용
public float terHeight; //Mathf.PerlinNoise적용
int seed; //Mathf.PerlinNoise적용
public GameObject[] blocks;
// Start is called before the first frame update
void Start()
{
seed = Random.Range(100000,999999);
GenerateTerrain();
}
// Update is called once per frame
void Update()
{
}
void GenerateTerrain()
{
for (int x = 0; x < sizeX; x++)
{
for (int z = 0; z < sizeZ; z++)
{
//maxY : 표면(GlassBlock)
int maxY = (int)(Mathf.PerlinNoise((x / 2 + seed) / terDetail, (z / 2 + seed) / terDetail) * terHeight);
maxY += groundHeight; // 표면(GlassBlock)을 땅의 깊이(groundHeight)만큼 올려줌
GameObject grass = Instantiate(blocks[0], new Vector3(x, maxY, z), Quaternion.identity) as GameObject;
grass.transform.SetParent(GameObject.FindGameObjectWithTag("Environment").transform,false);
for (int y = 0; y < maxY; y++) // 표면(GlassBlock)아래의 땅 생성
{
GameObject stone = Instantiate(blocks[1], new Vector3(x, y, z), Quaternion.identity) as GameObject;
stone.transform.SetParent(GameObject.FindGameObjectWithTag("Environment").transform, false);
}
if (x == (int)(sizeX / 2) && z == (int)(sizeZ / 2)) //표면(GlassBlock)의 정 중앙에 표시
{
Instantiate(player, new Vector3(x, maxY + 3, z), Quaternion.identity);
}
}
}
}
}
public int groundHeight;
땅 깊이
int y = (int)(Mathf.PerlinNoise((x / 2 + seed) / terDetail, (z / 2 + seed) / terDetail) * terHeight);
기존의 처리를 변경(땅 깊이(groundHeight)만큼 표면(GrassBlock)을 올려줌)
int maxY = (int)(Mathf.PerlinNoise((x / 2 + seed) / terDetail, (z / 2 + seed) / terDetail) * terHeight);
maxY += groundHeight;
GameObject grass = Instantiate(blocks[0], new Vector3(x, maxY, z), Quaternion.identity) as GameObject;
grass.transform.SetParent(GameObject.FindGameObjectWithTag("Environment").transform,false);
for (int y = 0; y < maxY; y++)
{
GameObject stone = Instantiate(blocks[1], new Vector3(x, y, z), Quaternion.identity) as GameObject;
stone.transform.SetParent(GameObject.FindGameObjectWithTag("Environment").transform, false);
}
표면(GrassBlock) 아래의 땅을 StoneBlock으로 채우기
if (x == (int)(sizeX / 2) && z == (int)(sizeZ / 2)) //표면(GlassBlock)의 정 중앙에 표시
{
Instantiate(player, new Vector3(x, maxY + 3, z), Quaternion.identity);
}
플레이어의 위치도 표면(GlassBlock)보다 조금 높은 위치로 조정
Environment오브젝트(Object)의 Blocks에 StoneBlock프리팹(Prefab)설정
GroundHeight설정
Blocks의 사이즈를 2로 변경
추가로 표시되는 Element 1에 StoneBlock프리팹(Prefab)을 설정(드래그 앤 드롭 또는 선택)
실행
표면(GrassBlock)과 땅밑이 깊이만큼 StoneBlock으로 잘 채워짐
WorldGenerator스크립트(Script) 코딩
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class WorldGenerator : MonoBehaviour
{
public GameObject player; //플레이어 설정용
public int sizeX;
public int sizeZ;
public int groundHeight; //땅의 깊이
public float terDetail; //Mathf.PerlinNoise적용
public float terHeight; //Mathf.PerlinNoise적용
int seed; //Mathf.PerlinNoise적용
public GameObject[] blocks;
// Start is called before the first frame update
void Start()
{
seed = Random.Range(100000,999999);
GenerateTerrain();
}
// Update is called once per frame
void Update()
{
}
void GenerateTerrain()
{
for (int x = 0; x < sizeX; x++)
{
for (int z = 0; z < sizeZ; z++)
{
//maxY : 표면(GlassBlock)
int maxY = (int)(Mathf.PerlinNoise((x / 2 + seed) / terDetail, (z / 2 + seed) / terDetail) * terHeight);
maxY += groundHeight; // 표면(GlassBlock)을 땅의 깊이(groundHeight)만큼 올려줌
GameObject grass = Instantiate(blocks[0], new Vector3(x, maxY, z), Quaternion.identity) as GameObject;
grass.transform.SetParent(GameObject.FindGameObjectWithTag("Environment").transform,false);
for (int y = 0; y < maxY; y++) // 표면(GlassBlock)아래의 땅 생성
{
int dirtLayers = Random.Range(1, 5); //흙(DirtBlock)의 깊이를 랜덤하게
if (y >= maxY - dirtLayers)
{
//흙(DirtBlock)
GameObject dirt = Instantiate(blocks[2], new Vector3(x, y, z), Quaternion.identity) as GameObject;
dirt.transform.SetParent(GameObject.FindGameObjectWithTag("Environment").transform, false);
}
else
{
//돌(StoneBlock)
GameObject stone = Instantiate(blocks[1], new Vector3(x, y, z), Quaternion.identity) as GameObject;
stone.transform.SetParent(GameObject.FindGameObjectWithTag("Environment").transform, false);
}
}
if (x == (int)(sizeX / 2) && z == (int)(sizeZ / 2)) //표면(GlassBlock)의 정 중앙에 표시
{
Instantiate(player, new Vector3(x, maxY + 3, z), Quaternion.identity);
}
}
}
}
}
int dirtLayers = Random.Range(1, 5);
흙(DirtBlock)의 깊이를 랜덤하게
GrassBlock
------------- maxY
DirtBlock
------------- ( maxY - dirtLayers )
StoneBlock
------------- 0
if (y >= maxY - dirtLayers)
{
GameObject dirt = Instantiate(blocks[2], new Vector3(x, y, z), Quaternion.identity) as GameObject;
dirt.transform.SetParent(GameObject.FindGameObjectWithTag("Environment").transform, false);
}
else
{
GameObject stone = Instantiate(blocks[1], new Vector3(x, y, z), Quaternion.identity) as GameObject;
stone.transform.SetParent(GameObject.FindGameObjectWithTag("Environment").transform, false);
}
Environment오브젝트(Object)의 Blocks에 DirtBlock프리팹(Prefab)설정
Blocks의 사이즈를 3로 변경
추가로 표시되는 Element 2에 DirtBlock프리팹(Prefab)을 설정(드래그 앤 드롭 또는 선택)
실행
표면(GrassBlock)과 땅밑이 깊이만큼 랜덤의 DirtBlock과 StoneBlock으로 잘 채워짐
05-블럭을 스크립트(Script)로 제어
BlockScript스크립트(Script)을 추가하고 코딩
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BlockScript : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
}
//마우스눌렀을때
private void OnMouseDown()
{
Destroy(this.gameObject);
}
}
private void OnMouseDown()
{
Destroy(this.gameObject);
}
OnMouseDown : 마우스 왼쪽 클릭만 작동
public static void Destroy (Object obj, float t= 0.0F) : 오브젝트(obj)를 t만큼의 딜레이후 삭제
this.gameObject: 자기 자신 (스크립트(Script)를 블럭에 설정할 예정이므로 클릭된 블럭의 의미)
참고) 마우스 왼쪽, 오른쪽, 중간버튼 클릭 체크
private void OnMouseOver()
{
if(Input.GetMouseButtonDown(0))
{
Debug.Log("Left");
}
if (Input.GetMouseButtonDown(1))
{
Debug.Log("RIGHT");
}
if (Input.GetMouseButtonDown(2))
{
Debug.Log("CENTER");
}
}
블럭프리팹(Prefab)에 BlockScript스크립트(Script)을 설정
프리팹(Prefab)폴더안의 각 블럭프리팹(Prefab)을 선택>>Inspector >> Add Component 후 BlockScript검색해서 추가
혹은 스크립트(Script)폴더의 BlockScript를 블럭프리팹(Prefab)으로 드래그 앤 드롭
실행
마우스를 클릭하면 화면의 정중앙의 블록이 잘 삭제됨
FPSController조정
발밑의 땅을 파도(삭제) FPSController의 크기가 커서 빠지지 않으므로 크기를 조정
FPSController선택>>Inspector >>Transform>>Scale 조정
x,y,z 1 -> 0.8
다음엔 정중앙을 직관적으로 표시하기위해 십자선(Crosshair)넣기를 진행
반응형