[ 플레이 캐릭터 선택 ] --> 캐릭터를 선택하는 로직과 UI 구현
- Canvas\GameStart안에서 Create Empty(Charactor Group)
- Pos Y = -40
- Width = 101 | Height = 101 - Charactor Group에 Add Component
- Grid Layout Group - Cell Size X = 50 | Y = 50
- Spacing X = 1 | Y = 1
- Button Start를 Charactor Group에 자식 오브젝트로 넣기(드래그&드랍)
- Button Start 이름을 Charactor 0로 변경
- Charactor 0에 UI\Image 추가
- Source Image를 Player 0의 Stand 0 sprite로 변경
- Set Native Size 클릭
- Pos Y = 8
- 이름을 Icon으로 변경 - Text(Legacy) 이름을 Text Name으로 변경
- Text = 벼농부
- Font Size = 8
- 앵커 선택 후 Shift + Alt 누른 후 양옆 꽉 채운 가운데 앵커로 설정
- Left = 2 | Right = 2
- Pos Y = -8 - Text Name을 Ctrl + D로 복사(Text Adv)
- Pos Y = -16
- Foont Size = 5
- Text = 이동속도 10% 증가 - Charactor 0의 Color를 캐릭터 색상과 비슷하게 변경(하늘~파랑)
- Text Name, Adv의 Outline 색상을 Charactor 0 의 색상보다 살짝 어둡게 변경
- Charactor 0를 Ctrl + D로 복사(Charactor 1)
- Source Image를 Player 1의 Stand 0 sprite로 변경
- Charactor 0의 Color를 캐릭터 색상과 비슷하게 변경(분홍)
- Text Name, Adv의 Outline 색상을 Charactor 1의 색상보다 살짝 어둡게 변경
- Text Name의 Text = 보리농부 - 기존의 GameManager 스크립트에 코드 추가
ㅡ아래는 완성된 코드ㅡ
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class GameManager : MonoBehaviour
{
public static GameManager instance;
[Header("# Game Conrol")]
public bool isLive;
public float gameTime;
public float maxGameTime = 2 * 10f;
[Header("# Player Info")]
public int playerId;
public float hp;
public float maxHp = 100;
public int level;
public int kill;
public int exp;
public int[] nextExp = { 3, 5, 10, 100, 150, 210, 280, 360, 450, 600 };
[Header("# Game Object")]
public PoolManager pool;
public Player player;
public LevelUp uiLevelUp;
public Result uiResult;
public GameObject enemyCleaner;
private void Awake()
{
instance = this;
}
public void GameStart(int id)
{
playerId = id; // 플레이어 id 값 적용
hp = maxHp;
player.gameObject.SetActive(true); // 버튼을 눌러 게임을 시작했을 때, 활성화
uiLevelUp.Select(playerId % 2); // 플레이어 id 별로 다른 기본무기 지금
Resume();
}
public void GameOver()
{
StartCoroutine(GameOverRoutine());
}
IEnumerator GameOverRoutine()
{
isLive = false;
yield return new WaitForSeconds(0.5f);
uiResult.gameObject.SetActive(true);
uiResult.Lose();
Stop();
}
public void GameRetry()
{
SceneManager.LoadScene(0);
}
void Update()
{
if(!isLive)
{
return;
}
gameTime += Time.deltaTime;
if (gameTime > maxGameTime){
gameTime = maxGameTime;
GameVictory();
}
}
public void GetExp()
{
if (!isLive)
{
return;
}
exp++;
if (exp == nextExp[Mathf.Min(level, nextExp.Length-1)])
{
level++;
exp = 0;
uiLevelUp.Show();
}
}
public void Stop()
{
isLive = false;
Time.timeScale = 0;
}
public void Resume()
{
isLive = true;
Time.timeScale = 1;
}
public void GameVictory()
{
StartCoroutine(GameVictoryRoutine());
}
IEnumerator GameVictoryRoutine()
{
isLive = false;
enemyCleaner.SetActive(true);
yield return new WaitForSeconds(0.5f);
uiResult.gameObject.SetActive(true);
uiResult.Win();
Stop();
}
}
- Player 오브젝트 비활성화
- Undead Survivor\Animations에 farmer 2,3의 애니메이션도 추가로 만들기(2D 셀 애니메이션 제작 참고)
- 기존의 Player 스크립트에 코드 추가
ㅡ아래는 완성된 코드ㅡ
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Player : MonoBehaviour
{
public Vector2 inputVec;
public float speed;
public Scanner scanner;
public Hand[] hands;
public RuntimeAnimatorController[] animCon; // 애니메이션 컨트롤러 배열 변수
Rigidbody2D rigid;
SpriteRenderer spriter;
Animator anim;
void Awake()
{
rigid = GetComponent<Rigidbody2D>();
spriter = GetComponent<SpriteRenderer>();
anim = GetComponent<Animator>();
scanner = GetComponent<Scanner>();
hands = GetComponentsInChildren<Hand>(true);
}
private void OnEnable()
{
speed *= Character.Speed;
anim.runtimeAnimatorController = animCon[GameManager.instance.playerId]; // 애니메이션 변경
}
void Update()
{
if (!GameManager.instance.isLive)
return;
inputVec.x = Input.GetAxisRaw("Horizontal");
inputVec.y = Input.GetAxisRaw("Vertical");
}
private void FixedUpdate()
{
if (!GameManager.instance.isLive)
return;
Vector2 nextVec = inputVec.normalized*speed* Time.fixedDeltaTime;
rigid.MovePosition(rigid.position + nextVec);
}
private void LateUpdate()
{
if (!GameManager.instance.isLive)
return;
anim.SetFloat("Speed", inputVec.magnitude);
if (inputVec.x != 0)
{
spriter.flipX = inputVec.x < 0;
}
}
private void OnCollisionStay2D(Collision2D collision)
{
if (!GameManager.instance.isLive)
return;
GameManager.instance.hp -= Time.deltaTime * 10;
if (GameManager.instance.hp < 0)
{
for(int index=2; index<transform.childCount; index++)
{
transform.GetChild(index).gameObject.SetActive(false);
}
anim.SetTrigger("Dead");
GameManager.instance.GameOver();
}
}
}
- Player의 Anim Con에 ACPlayer 0,1,2,3 오브젝트 초기화
- Charactor 0의 On Click ()에 GameManager.GameStart 함수 재연결
- Charactor 번호에 맞게 0-->0 | 1-->1 - Charactor 1\Text Adv의 Text = 연사속도 10% 증가
- C# 스크립트 생성(Character)
ㅡ아래는 완성된 코드ㅡ
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Character : MonoBehaviour
{
// 함수가 아닌 속성을 작성
public static float Speed
{
get { return GameManager.instance.playerId == 0 ? 1.1f : 1f; } // 캐릭터 0
}
public static float WeaponSpeed
{
get { return GameManager.instance.playerId == 1 ? 1.1f : 1f; } // 캐릭터 1
}
public static float WeaponRate
{
get { return GameManager.instance.playerId == 1 ? 0.9f : 1f; } // 캐릭터 1
}
public static float Damage
{
get { return GameManager.instance.playerId == 2 ? 1.2f : 1f; } // 캐릭터 2
}
public static int Count
{
get { return GameManager.instance.playerId == 3 ? 1 : 0; } // 캐릭터 3
}
}
- 기존의 Gear 스크립트에 코드 추가
ㅡ아래는 완성된 코드ㅡ
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Gear : MonoBehaviour
{
public ItemData.ItemType type;
public float rate;
public void Init(ItemData data)
{
// Basic set
name = "Gear " + data.itemId;
transform.parent = GameManager.instance.player.transform;
transform.localPosition = Vector3.zero;
// Property set
type = data.itemType;
rate = data.damages[0];
ApplyGear();
}
public void LevelUp(float rate)
{
this.rate = rate;
ApplyGear();
}
void ApplyGear()
{
switch (type)
{
case ItemData.ItemType.Glove:
RateUp();
break;
case ItemData.ItemType.Shoe:
SpeedUp();
break;
}
}
private void RateUp()
{
Weapon[] weapons = transform.parent.GetComponentsInChildren<Weapon>();
foreach(Weapon weapon in weapons)
{
switch (weapon.id)
{
case 0: // 캐릭터마다 다르게 적용
float speed = 150 * Character.WeaponSpeed;
weapon.speed = speed + (speed * rate);
break;
default: // 캐릭터마다 다르게 적용
speed = 0.5f * Character.WeaponRate;
weapon.speed = speed * (1f - rate);
break;
}
}
}
void SpeedUp()
{
float speed = 3 * Character.Speed; // 캐릭터에 따라 다른 스피드
GameManager.instance.player.speed = speed + speed * rate;
}
}
- 기존의 Weapon 스크립트에 코드 추가
ㅡ아래는 완성된 코드ㅡ
using System.Collections;
using System.Collections.Generic;
using System.Runtime.ConstrainedExecution;
using UnityEngine;
public class Weapon : MonoBehaviour
{
public int id;
public int prefabId;
public float damage;
public int count;
public float speed;
float timer;
Player player;
void Awake(){
player = GameManager.instance.player;
}
void Update(){
if (!GameManager.instance.isLive)
return;
switch (id){
case 0:
transform.Rotate(Vector3.back * speed * Time.deltaTime);
break;
default:
timer += Time.deltaTime;
if(timer > speed){
timer = 0f;
Fire();
}
break;
}
// .. Test Code ..
if (Input.GetButtonDown("Jump")){
LevelUp(10, 1);
}
}
public void LevelUp(float damage, int count)
{
this.damage += damage * Character.Damage; // 레벨업 수치 조정
this.count += count; // 레벨업 수치 조정
if(id == 0){
Batch();
}
player.BroadcastMessage("ApplyGear",SendMessageOptions.DontRequireReceiver);
}
public void Init(ItemData data)
{
// Basic Set
name = "Weapon " + data.itemId;
transform.parent = player.transform;
transform.localPosition = Vector3.zero;
// Property Set
id = data.itemId;
damage = data.baseDamage * Character.Damage;
count = data.baseCount + Character.Count;
for(int index=0; index<GameManager.instance.pool.prefabs.Length; index++){
if (data.projectile == GameManager.instance.pool.prefabs[index]){
prefabId = index;
break;
}
}
switch(id){
case 0:
speed = 150 * Character.WeaponSpeed; // 캐릭터마다 다른 무기 회전 속도
Batch();
break;
default:
speed = 0.5f * Character.WeaponRate; // 캐릭터마다 다른 무기 발사 속도
break;
}
// Hand Set
Hand hand = player.hands[(int)data.itemType];
hand.spriter.sprite = data.hand;
hand.gameObject.SetActive(true);
player.BroadcastMessage("ApplyGear", SendMessageOptions.DontRequireReceiver);
}
void Batch(){
for(int index=0; index < count; index++) {
Transform bullet;
if(index < transform.childCount){
bullet = transform.GetChild(index);
}
else{
bullet = GameManager.instance.pool.Get(prefabId).transform;
bullet.parent = transform;
}
bullet.localPosition = Vector3.zero;
bullet.localRotation = Quaternion.identity;
Vector3 rotVec = Vector3.forward * 350 * index / count;
bullet.Rotate(rotVec);
bullet.Translate(bullet.up * 1.5f, Space.World);
bullet.GetComponent<Bullet>().Init(damage, -1, Vector3.zero); // -1 is Infinity Per.
}
}
void Fire()
{
if (!player.scanner.nearestTarget){
return;
}
Vector3 targetPos = player.scanner.nearestTarget.position;
Vector3 dir = targetPos - transform.position;
dir = dir.normalized;
Transform bullet = GameManager.instance.pool.Get(prefabId).transform;
bullet.position = transform.position;
bullet.rotation = Quaternion.FromToRotation(Vector3.up, dir);
bullet.GetComponent<Bullet>().Init(damage, count, dir);
}
}
ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ
★Slow and Steady★
'Unity 공부 > Unity_2D' 카테고리의 다른 글
| [Day 15] 오디오 시스템 구축 (0) | 2023.07.25 |
|---|---|
| [Day 14] 캐릭터 해금 시스템 (0) | 2023.07.24 |
| [Day 12] 게임 시작과 종료 구현 (0) | 2023.07.18 |
| [Day 11] 레벨업 시스템 (0) | 2023.07.17 |
| [Day 10] 무기 장착 표현 (0) | 2023.07.16 |