Unity 실습
바닥을 벗어나지 못하는 물체 만들기
이동할 물체(Sphere)와, 범위를 설정해줄 바닥(Cube)를 만든다.
transform.position = new Vector3(
Mathf.Clamp(transform.position.x,
boxCollider.bounds.min.x,
boxCollider.bounds.max.x), 0,
Mathf.Clamp(
transform.position.z,
boxCollider.bounds.min.z,
boxCollider.bounds.max.z));
* Clamp : clamp(float value, float min, float max)// min와 max 사이의 값을 value가 지니게 함.
* Bound : bound 주로 객체의 경계를 나타내는데 사용
center : collider의 중심 위치
extents : colldier 크기의 절반, (중심부터 collider 경계까지의 거리)
min&max : 최소지점 꼭짓점과 최대지점 꼭짓점
size : 객체의 크기
참조 :
https://docs.unity3d.com/kr/560/ScriptReference/Mathf.Clamp.html
Mathf-Clamp - Unity 스크립팅 API
Clamps a value between a minimum float and maximum float value.
docs.unity3d.com
https://docs.unity3d.com/6000.0/Documentation/ScriptReference/Collider-bounds.html
Unity - Scripting API: Collider.bounds
Success! Thank you for helping us improve the quality of Unity Documentation. Although we cannot accept all submissions, we do read each suggested change from our users and will make updates where applicable. Close
docs.unity3d.com
그래서 코드가 의미하는 바는 , 위치를 할당할텐데 그 범위가 x는 boxcollider의 min부터 max 까지
y는 0(수평이동만 가능), z도 boxcollider의 min부터 max까지라는 코드이다.
위치에 따라 색이 달라지게 만들기
이제 객체의 색을 위치에 따라 다르게 조정해보자.
GetComponent<MeshRenderer>().
material.color = new Color(
transform.position.x /
boxCollider.bounds.size.x, 0
, 0,
transform.position.z /
boxCollider.bounds.size.z);
객체의 MeshRenderer 컴포넌트에서 color에 접근해 새로운 컬러를 할당해준다.
새로운 컬러는 Color (R, G, B) 값이 R: x의 월드 좌표를 박스 콜라이더의 bound.size로 나눠준다.
그럼 R와 B값만 조정하므로 다음과 같은 결과가 나온다.
참고 : bound size와 size의 차이가 궁금해서 한참 찾아봤다.
우리는BoxCollider.size를 조작하고, 조작한 값이 (부모 객체,최상위 객체 등의 변환 계산)을 해
BoxCollider.bounds.size 라는 값으로 출력되게 되고, 이 값은 읽기 전용이자 월드 좌표를따른다.
그러나 이 코드는 transform.position.x가 음수가 나올 수 있어 수정이 필요하다.
대포 만들고 발사하기
우선 몰입을 위해... 대포와, 발사될 지점인 firepoint를 생성한다.
그리고 생성될 대포알도 만들어준다. (prefab화 시켜줌)
2주차 때 배운대로, 키를 누르면 생성되고, 힘을 받아 방향대로 나가는 코드를 작성한다.
if (Input.GetKeyUp(KeyCode.Space))
{
GameObject caonnonBall = Instantiate(cannonBall,
firePoint.transform.position, transform.rotation);
caonnonBall.GetComponent<Rigidbody>().AddForce(firePoint.transform.forward * currentPower,ForceMode.Impulse);
caonnonBall.GetComponent<MeshRenderer>().material.color = Random.ColorHSV();
Destroy(caonnonBall, 2);
}
currentPower는 후의 UI 의 Slider와 연결되니 무시하고,
오타인걸 알지만 고치기 귀찮아서 놔둔 캐논볼을 생성하고 ,
그 생성한 캐논볼의 리지드바디 컴포넌트를 가져와 힘을 가해준다(방향에 주의)
if (Input.GetKey(KeyCode.A))
{
CannonRotate.transform.Rotate(Vector3.left,Time.deltaTime * 10);
}
if (Input.GetKey(KeyCode.D))
{
CannonRotate.transform.Rotate(Vector3.right,Time.deltaTime * 10);
}
}
기본 변수에 CannonRotate를 추가하고, 이를 A와 D키로 바꿀 수 있게 해 준다.
이는 GetAxisRaw로 코드를 줄여줄 수 있다.
UI로 파워 게이지 만들기
파워 게이지를 만들고 UI창에 표시되며, 이에 따라 다른 힘으로 발사되도록 할 것이다.
UI - Slider를 만들면 자동으로 Canvas와 slider 아래 다음 요소들이 생성된다.
Handle Slide Area는 지워주고 창을 환경에 맞게 조정한다. (anchor, 슬라이더색, 범위 )
참조 :
https://docs.unity3d.com/kr/560/Manual/UIBasicLayout.html
기본 레이아웃 - Unity 매뉴얼
이 섹션에서는 UI 요소를 서로 간 비교하거나 캔버스와 비교하여 배치하는 방법에 대해 설명합니다. GameObject -> UI -> Image 메뉴에서 이미지를 생성하고 섹션을 참고하여 직접 테스트해 볼 수 있습
docs.unity3d.com
그리고 대포 스크립트에 다음 변수들을 추가해준다
public Slider slider;
public float fillSpeed;
public float maxPoewr;
public float currentPower;
int n1 = 0;
- slider : slider에 연결할 변수
- fillSpeed : slider가 채워지는 속도
- maxPower : 발사될 대포알의 최대 파워
- currentPower : 발사될 대포알의 현재 파워
- n1 : 카운트를 위해 만든 변수
if (Input.GetKey(KeyCode.Space))
{
if (n1 < 1)
{
currentPower +=fillSpeed *Time.deltaTime;
}
else if ( n1 == 1)
{
currentPower -=fillSpeed *Time.deltaTime;
}
if (currentPower >= maxPoewr)
{
n1++;
}
if (currentPower <= 0) n1--;
currentPower = Mathf.Clamp(currentPower, 0, maxPoewr);
slider.value = currentPower / maxPoewr;
}
if (Input.GetKeyUp(KeyCode.Space))
{
// GameObject caonnonBall = Instantiate(cannonBall,
// firePoint.transform.position, transform.rotation);
// caonnonBall.GetComponent<Rigidbody>().AddForce(firePoint.transform.forward * currentPower,ForceMode.Impulse);
// caonnonBall.GetComponent<MeshRenderer>().material.color = Random.ColorHSV();
// Destroy(caonnonBall, 2);
currentPower = 0.0f;
slider.value = 0.0f;
}
다음과 같이 코드를 작성해 주면 된다.
파워 게이지가 Max가 되었을 때, 0이 되었을 때 n이 변화하게 해 주고
n에 따라서 게이지가 왔다 갔다 (0 >> maxPower >>> 0) >>) 를 반복할 수 있게 해 주었다.
그리고 if문 안에 쏘고 나서 게이지와 발사하는 힘을 초기화하는 코드를 넣어준다.
충돌 시 파편 만들기
파편으로 생성될 프리팹을 만들어준다.
대포알 프리팹에 발사체라는 의미의 스크립트를 만들어주고, 다음과 같은 코드를 작성한다.
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Random = UnityEngine.Random;
public class Projectile : MonoBehaviour
{
public GameObject piace;
public int MinPiaceCount = 3;
public int MaxPiaceCount = 8;
// Start is called before the first frame update
private void OnTriggerEnter(Collider other)
{
Vector3 hitDirection = GetComponent<Rigidbody>().velocity * -1;
int count = Random.Range(MinPiaceCount, MaxPiaceCount + 1);
for (int i = 0; i < count; ++i)
{
Vector3 randomDiretion = Random.insideUnitSphere;
Vector3 lastDiretion = Quaternion.LookRotation(randomDiretion)
* hitDirection;
GameObject instance = Instantiate(piace, transform.position,
Quaternion.LookRotation(lastDiretion));
instance.GetComponent<Rigidbody>().AddForce(lastDiretion, ForceMode.Impulse);
Destroy(this.gameObject);
}
}
}
piace는 임의로 이름붙인 파편이다.
최소, 최대 생성 개수를 정해줄 변수를 만들어준다.
OnTriggerEnter로 한 이유는 OnCollisionEnter로 했을 때 방향이 0이 되는 순간이 있기 때문이다.
OnTriggerEnter로 Collider가 닿는 순간의 velocity(방향과 크기를 갖는)에 -1를 곱해줘서 충돌 방향과
반대로 향하게 만든다. 이것만 하면 충돌 방향과 반대로 튀어나가는 파편을 볼 수 있다.
더 다이나믹하게 보이기 위해 랜덤적 요소(lastDirection)을 추가해줬다.
*주의 velocity는 속력(방향과 크기) 그래서 LookRotation()안에 넣어준 것 ?
Instantiate로 생성해주고, 이에 힘을 가해주었다. (방향은 랜덤)
그리고 게임 오브젝트(대포알)을 삭제해준다.
몬스터를 생성하고 맞추기
몬스터 변수, 일정 범위 내에 생성하기 위한 바닥 변수, 생성된 몬스터가 바라볼 방향을 표시할 player(대포) 변수를 만든다.
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Random = UnityEngine.Random;
public class MonsterSpawn : MonoBehaviour
{
public GameObject monsterPrefab;
public GameObject ground;
public GameObject player;
void Update()
{ Renderer cubeRenderer = ground.GetComponent<Renderer>();
Bounds bounds = cubeRenderer.bounds;
float randomX = Random.Range(bounds.min.x, bounds.max.x);
float randomZ = Random.Range(bounds.min.z, bounds.max.z);
Vector3 spawnPosition = new Vector3(randomX, -0.3f, randomZ);
if (Input.GetMouseButtonDown(0))
{
Vector3 directionToPlayer = player.transform.position - spawnPosition;
Quaternion rotationToPlayer = Quaternion.LookRotation(directionToPlayer);
Instantiate(monsterPrefab, spawnPosition, rotationToPlayer);
}
}
}
Update() 문안에는 크게 두 파트로 나뉜다, 생성될 범위를 설정하는 부분과
그 범위를 이용해 마우스 버튼을 누르면 플레이어를 바라보며 생성되게 하는 함수.
우선, 범위를 설정하는 함수는 바닥으로 설정할 변수에서 Renderer를 가져와 cubeRenderer에 할당하고
이를 바탕으로 경계(bounds)를 뽑는다.
이렇게 뽑아진 경계로 min와 max를 정해주고, 랜덤한 숫자로 나올 수 있게 처리한다.
이제 바라보는 방향을 표시할 차례이다.
방향 벡터는 플레이어의 위치에서 스폰 위치를 빼 주면 간단하게 표시된다.
2차원의 예시로 들어보면, 1번에서 2번을 바라보게 하고 싶다면, 2번에서 1번 좌표를 빼 주면 화살표와 같은 벡터가 나온다. 3차원도 마찬가지로 목적지에서 출발지를 빼 주면 방향 벡터가 나올 것이다.
그 방향 벡터를 Instantiate 함수에 넣어주면 코드가 완성된다.
재미있는 유니티 수업... 만지작 만지작 하면 하루가 다 간다.
알고리즘이나 자료구조 공부도 남는 시간에 조금씩 해 봐야겠다.
결국 생각하는 힘을 길러야 이런 것도 금방 만들고, 여러가지 기능(함수)들을 써 봐야 꺼내 쓸 수 있으니
열심히 기록하면서 해야지
'TIL' 카테고리의 다른 글
[멋쟁이사자처럼 부트캠프 TIL회고] Unity 게임개발 3기 25-26일차 (0) | 2024.12.15 |
---|---|
[멋쟁이사자처럼 부트캠프 TIL회고] Unity 게임 개발 24일차 (0) | 2024.12.14 |
[멋쟁이사자처럼 부트캠프 TIL회고] Unity 게임개발 3기 22일차 (0) | 2024.12.12 |
[멋쟁이사자처럼 부트캠프 TIL회고] Unity 게임개발 3기 21일차 (1) | 2024.12.10 |
[멋쟁이사자처럼 부트캠프 TIL회고] Unity 게임개발 3기 21일차 (3) | 2024.12.10 |