목차
Unity 다뤄보기
GameObject 범위 제한
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MaterialColorChange : MonoBehaviour
{
public GameObject cube;
void Update()
{
BoxCollider boxCollider = cube.GetComponent<BoxCollider>();
//if (transform.position.x <= boxCollider.bounds.min.x ||
// transform.position.z <= boxCollider.bounds.min.z ||
// transform.position.x >= boxCollider.bounds.max.x ||
// transform.position.z >= boxCollider.bounds.max.z )
// Clamp에 이미 이 조건이 포함되어 있어서 삭제
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));
float scaleX = boxCollider.size.x * boxCollider.transform.localScale.x;
float scaleZ = boxCollider.size.z * boxCollider.transform.localScale.z;
//float scaleX = boxCollider.size.x * boxCollider.transform.lossyScale.x;
//float scaleZ = boxCollider.size.z * boxCollider.transform.lossyScale.z;
GetComponent<MeshRenderer>().material.color = new Color(
(transform.position.x + scaleX * 0.5f) /
scaleX, 0,
(transform.position.z + scaleZ * 0.5f) /
scaleZ);
}
}
※ Mathf.Clamp(position, min, max) : position을 min부터 max까지의 범위로 제한
※ lossyScale : 수정이 불가능한 WorldScale이라고 보면 된다.
※ 0.5f를 곱하는 이유 : 중간을 0.5로 설정하기 위해 --> 최소 0 최대 1이 된다.
※ boxCollider.size vs boxCollider.bounds.size
- boxCollider.size : Inspector로 적용한 Component의 로컬 크기
- boxCollider.bounds.size : Component의 Scale까지 고려된 월드 좌표계에서의 크기 --> Cube의 X Scale * boxCollider의 X size
대포 만들기
0. 땅 만들기
: Cube 생성 후, 적당히 크기 조절
1. 대포 모양 만들기
2. 빈 게임 오브젝트(FirePosition) 만들어서 포탄이 발사될 위치 잡기
: Rotation의 X를 -90으로 설정
3. 포탄 만들기
: Sphere 생성(CannonBall)
>> Material 추가 --> 다시 보니 Default랑 다른게 없더라..?
>> Rigidbody 추가
>> Prefab 하기
4. UI - Slider 생성
>> Anchor를 아래쪽으로 설정 후, 위치 조정
>> Handle Slide Area 삭제
>> Fill Area의 Left 0으로 설정, Fill Area - Fill 의 Width 0으로 설정 + 게이지 색 바꾸려면 Fill의 Color 수정
5. Cannon Script 생성 후 FirePosition에 넣고 코드 작성
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class Cannon : MonoBehaviour
{
public GameObject cannonBall;
public Slider slider;
public float maxPower;
public float currentPower;
public float fillSpeed;
void Update()
{
if (Input.GetKey(KeyCode.Space))
{
currentPower += fillSpeed * Time.deltaTime;
currentPower = Mathf.Clamp(currentPower, 0, maxPower);
slider.value = currentPower / maxPower;
}
if (Input.GetKeyUp(KeyCode.Space))
{
GameObject cannonBallInstance = Instantiate(cannonBall, transform.position, transform.rotation);
cannonBallInstance.GetComponent<Rigidbody>().AddForce(transform.forward * currentPower, ForceMode.Impulse);
currentPower = 0.0f;
slider.value = 0.0f;
}
}
}
6. CannonBall, Slider 각각 바인딩
※ 강사님은 Cannon Script를 최상위 Object에 넣고 아래 코드로 구동하시더라 --> 수정하려해도 수직으로 발사만 되더라
>> 나중에 원인을 찾아보자
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class Cannon : MonoBehaviour
{
public GameObject cannonBall;
public GameObject firePoint;
public Slider slider;
public float maxPower;
public float currentPower;
public float fillSpeed;
void Update()
{
if (Input.GetKey(KeyCode.Space))
{
currentPower += fillSpeed * Time.deltaTime;
currentPower = Mathf.Clamp(currentPower, 0, maxPower);
slider.value = currentPower / maxPower;
}
if (Input.GetKeyUp(KeyCode.Space))
{
GameObject cannonBallInstance = Instantiate(cannonBall,
firePoint.transform.position,
Quaternion.identity);
Vector3 forward = Quaternion.Euler(-90, 0, 0) * transform.forward;
cannonBallInstance.
GetComponent<Rigidbody>().
AddForce(forward* currentPower, ForceMode.Impulse);
currentPower = 0.0f;
slider.value = 0.0f;
}
}
}
└ 포탄이 땅에 닿으면 포탄이 사라지면서 파편이 튀도록 구현
1. Layer 추가
: Add Layer로 Ground, Projectile 생성
>> Cube는 Ground, CannonBall Prefab은 Projectile로 Layer 설정
2. 파편 만들기
: Cube 생성(Piece), Scale은 전부 0.5로 설정
>> Rigidbody 추가
3. Projectile Script 생성 후 CannonBall에 넣고 코드 작성
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Random = UnityEngine.Random;
public class Projectile : MonoBehaviour
{
public GameObject piece;
public int MinPieceCount = 3;
public int MaxPieceCount = 8;
private void OnTriggerEnter(Collider other)
{
Vector3 hitDirection = GetComponent<Rigidbody>().velocity * -1;
int count = Random.Range(MinPieceCount, MaxPieceCount + 1);
for (int i = 0; i < count; i++)
{
Vector3 randomDirection = Random.insideUnitSphere;
//Quaternion randomRotation = Random.rotation;
Vector3 lastDirection = Quaternion.LookRotation(randomDirection) * hitDirection;
GameObject instance = Instantiate(piece, transform.position, Quaternion.LookRotation(lastDirection));
instance.GetComponent<Rigidbody>().AddForce(lastDirection, ForceMode.Impulse);
Destroy(this.gameObject);
}
}
}
4. CannonBall Prefab에 추가 설정
>> Is Trigger 체크
>> Layer Overrides에서 Include Layers를 Ground로, Exclude Layers를 Default와 Projectile 설정
※ Exclude로 Projectile을 설정하면 공끼리 부딪혔을 때 깨지는 걸 방지
>> Projectile Script에 Piece 바인딩
※ 공의 속도가 너무 빠를 때, 공이 바닥을 통과하는 현상 방지하는 법
5. 파편이 3초 뒤에 사라지게 만들기
: Piece Script 생성 후 Piece에 넣고 코드 작성
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Piece : MonoBehaviour
{
IEnumerator Start()
{
yield return new WaitForSeconds(3.0f);
Destroy(this.gameObject);
}
}
└ 게이지가 꽉 차면 다시 줄어들도록 구현
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class Cannon : MonoBehaviour
{
public GameObject cannonBall;
public Slider slider;
public float maxPower;
public float currentPower;
public float fillSpeed;
public bool isMax = false;
void Update()
{
if (currentPower == maxPower)
isMax = true;
else if (currentPower < 0)
isMax = false;
if (Input.GetKey(KeyCode.Space))
{
if (!isMax)
{
currentPower += fillSpeed * Time.deltaTime;
currentPower = Mathf.Clamp(currentPower, 0, maxPower);
slider.value = currentPower / maxPower;
}
else if (isMax)
{
currentPower -= fillSpeed * Time.deltaTime;
slider.value = currentPower / maxPower;
}
}
if (Input.GetKeyUp(KeyCode.Space))
{
GameObject cannonBallInstance = Instantiate(cannonBall, transform.position, transform.rotation);
cannonBallInstance.GetComponent<Rigidbody>().AddForce(transform.forward * currentPower, ForceMode.Impulse);
currentPower = 0.0f;
slider.value = 0.0f;
}
}
}
└ 대포를 회전시키고 포신을 위아래로 움직이도록 구현
1. 대포 전체를 회전시키기 위해 최상위 Obejct로 CannonPivot 생성 후 대포를 구성하는 Object 전부 자식 Object로 넣기
2. 포신이 움직이면 포탄이 발사하는 지점도 같이 움직이도록 포신에 자식 Object로 FirePosition 넣기
3. 코드 작성
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class Cannon : MonoBehaviour
{
public GameObject cannonBall;
public GameObject capsule;
public GameObject cannonPivot;
public Slider slider;
public float maxPower;
public float currentPower;
public float fillSpeed;
public bool isMax = false;
public float rotateSpeed = 100f;
private float _capsuleZ;
void Update()
{
if (Input.GetKey(KeyCode.W))
{
capsule.transform.Rotate(Vector3.forward * (rotateSpeed * Time.deltaTime));
}
if (Input.GetKey(KeyCode.S))
{
capsule.transform.Rotate(Vector3.back * (rotateSpeed * Time.deltaTime));
}
if (Input.GetKey(KeyCode.A))
{
cannonPivot.transform.Rotate(Vector3.down * (rotateSpeed * Time.deltaTime));
}
if (Input.GetKey(KeyCode.D))
{
cannonPivot.transform.Rotate(Vector3.up * (rotateSpeed * Time.deltaTime));
}
if (currentPower == maxPower)
isMax = true;
else if (currentPower < 0)
isMax = false;
if (Input.GetKey(KeyCode.Space))
{
if (!isMax)
{
currentPower += fillSpeed * Time.deltaTime;
currentPower = Mathf.Clamp(currentPower, 0, maxPower);
slider.value = currentPower / maxPower;
}
else if (isMax)
{
currentPower -= fillSpeed * Time.deltaTime;
slider.value = currentPower / maxPower;
}
}
if (Input.GetKeyUp(KeyCode.Space))
{
GameObject cannonBallInstance = Instantiate(cannonBall, transform.position, transform.rotation);
cannonBallInstance.GetComponent<Rigidbody>().AddForce(transform.forward * currentPower, ForceMode.Impulse);
currentPower = 0.0f;
slider.value = 0.0f;
}
}
}
4. CannonPivot과 Capsule 각각 바인딩
└ 추가 보완점
1. W로 각도를 올릴 때 Z값을 최대 0까지, S로 각도를 내릴 때 Z값을 최대 -90까지만 움직이도록
2. 대포가 움직이게 구현
└ Quest
1. 사각 땅 안에 랜덤으로 몬스터 스폰, 캐논이 방향을 회전하면서 게이지를 조절해서 몬스터를 맞추면 몬스터가 죽고 그 자리에 파편이 남다가 3초 뒤 삭제되게 하기
2. 대포가 아니라 캐릭터가 공격 모션을 할 때 손에서 발사체가 나가게 하기 (상급자용)
'Development > C#' 카테고리의 다른 글
멋쟁이사자처럼부트캠프 Unity 게임 개발 3기 26일차 (0) | 2024.12.26 |
---|---|
[멋쟁이사자처럼 부트캠프 TIL 회고] Unity 게임 개발 3기 18일차 (0) | 2024.12.19 |
[멋쟁이사자처럼 부트캠프 TIL 회고] Unity 게임 개발 3기 16일차 (0) | 2024.12.11 |
[멋쟁이사자처럼 부트캠프 TIL 회고] Unity 게임 개발 3기 15일차 (2) | 2024.12.10 |
[멋쟁이사자처럼 부트캠프 TIL 회고] Unity 게임 개발 3기 14일차 (0) | 2024.12.07 |