ItemSO.cs 소스입니다
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[System.Serializable]
public class Item
{
public string name;
public int attack;
public int health;
public Sprite sprite;
public float percent;
}
[CreateAssetMenu(fileName = "ItemSO", menuName = "Scriptable Object/ItemSO")]
public class ItemSO : ScriptableObject
{
public Item[] items;
}
EndTurnBtn.cs 소스입니다
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class EndTurnBtn : MonoBehaviour
{
[SerializeField] Sprite active;
[SerializeField] Sprite inactive;
[SerializeField] Text btnText;
void Start()
{
Setup(false);
TurnManager.OnTurnStarted += Setup;
}
void OnDestroy()
{
TurnManager.OnTurnStarted -= Setup;
}
public void Setup(bool isActive)
{
GetComponent<Image>().sprite = isActive ? active : inactive;
GetComponent<Button>().interactable = isActive;
btnText.color = isActive ? new Color32(255, 195, 90, 255) : new Color32(55, 55, 55, 255);
}
}
NotificationPanel.cs 소스입니다
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;
using DG.Tweening;
public class NotificationPanel : MonoBehaviour
{
[SerializeField] TMP_Text notificationTMP;
public void Show(string message)
{
notificationTMP.text = message;
Sequence sequence = DOTween.Sequence()
.Append(transform.DOScale(Vector3.one, 0.3f).SetEase(Ease.InOutQuad))
.AppendInterval(0.9f)
.Append(transform.DOScale(Vector3.zero, 0.3f).SetEase(Ease.InOutQuad));
}
void Start() => ScaleZero();
[ContextMenu("ScaleOne")]
void ScaleOne() => transform.localScale = Vector3.one;
[ContextMenu("ScaleZero")]
public void ScaleZero() => transform.localScale = Vector3.zero;
}
ResultPanel.cs 소스입니다
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;
using DG.Tweening;
using UnityEngine.SceneManagement;
public class ResultPanel : MonoBehaviour
{
[SerializeField] TMP_Text resultTMP;
public void Show(string message)
{
resultTMP.text = message;
transform.DOScale(Vector3.one, 0.5f).SetEase(Ease.InOutQuad);
}
public void Restart()
{
SceneManager.LoadScene(0);
}
void Start() => ScaleZero();
[ContextMenu("ScaleOne")]
void ScaleOne() => transform.localScale = Vector3.one;
[ContextMenu("ScaleZero")]
public void ScaleZero() => transform.localScale = Vector3.zero;
}
TitlePanel.cs 소스입니다
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TitlePanel : MonoBehaviour
{
public void StartGameClick()
{
GameManager.Inst.StartGame();
Active(false);
}
public void Active(bool isActive)
{
gameObject.SetActive(isActive);
}
}
CameraEffect.cs 소스입니다
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CameraEffect : MonoBehaviour
{
[SerializeField] Material effectMat;
void OnRenderImage(RenderTexture _src, RenderTexture _dest)
{
if (effectMat == null)
return;
Graphics.Blit(_src, _dest, effectMat);
}
void OnDestroy()
{
SetGrayScale(false);
}
public void SetGrayScale(bool isGrayscale)
{
effectMat.SetFloat("_GrayscaleAmount", isGrayscale ? 1 : 0);
effectMat.SetFloat("_DarkAmount", isGrayscale ? 0.12f : 0);
}
}
Card.cs 소스입니다
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;
using DG.Tweening;
public class Card : MonoBehaviour
{
[SerializeField] SpriteRenderer card;
[SerializeField] SpriteRenderer character;
[SerializeField] TMP_Text nameTMP;
[SerializeField] TMP_Text attackTMP;
[SerializeField] TMP_Text healthTMP;
[SerializeField] Sprite cardFront;
[SerializeField] Sprite cardBack;
public Item item;
bool isFront;
public PRS originPRS;
public void Setup(Item item, bool isFront)
{
this.item = item;
this.isFront = isFront;
if (this.isFront)
{
character.sprite = this.item.sprite;
nameTMP.text = this.item.name;
attackTMP.text = this.item.attack.ToString();
healthTMP.text = this.item.health.ToString();
}
else
{
card.sprite = cardBack;
nameTMP.text = "";
attackTMP.text = "";
healthTMP.text = "";
}
}
void OnMouseOver()
{
if (isFront)
CardManager.Inst.CardMouseOver(this);
}
void OnMouseExit()
{
if (isFront)
CardManager.Inst.CardMouseExit(this);
}
void OnMouseDown()
{
if (isFront)
CardManager.Inst.CardMouseDown();
}
void OnMouseUp()
{
if (isFront)
CardManager.Inst.CardMouseUp();
}
public void MoveTransform(PRS prs, bool useDotween, float dotweenTime = 0)
{
if (useDotween)
{
transform.DOMove(prs.pos, dotweenTime);
transform.DORotateQuaternion(prs.rot, dotweenTime);
transform.DOScale(prs.scale, dotweenTime);
}
else
{
transform.position = prs.pos;
transform.rotation = prs.rot;
transform.localScale = prs.scale;
}
}
}
CardManager.cs 소스입니다
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Random = UnityEngine.Random;
using DG.Tweening;
public class CardManager : MonoBehaviour
{
public static CardManager Inst { get; private set; }
void Awake() => Inst = this;
[SerializeField] ItemSO itemSO;
[SerializeField] GameObject cardPrefab;
[SerializeField] List<Card> myCards;
[SerializeField] List<Card> otherCards;
[SerializeField] Transform cardSpawnPoint;
[SerializeField] Transform otherCardSpawnPoint;
[SerializeField] Transform myCardLeft;
[SerializeField] Transform myCardRight;
[SerializeField] Transform otherCardLeft;
[SerializeField] Transform otherCardRight;
[SerializeField] ECardState eCardState;
List<Item> itemBuffer;
Card selectCard;
bool isMyCardDrag;
bool onMyCardArea;
enum ECardState { Nothing, CanMouseOver, CanMouseDrag }
int myPutCount;
public Item PopItem()
{
if (itemBuffer.Count == 0)
SetupItemBuffer();
Item item = itemBuffer[0];
itemBuffer.RemoveAt(0);
return item;
}
void SetupItemBuffer()
{
itemBuffer = new List<Item>(100);
for (int i = 0; i < itemSO.items.Length; i++)
{
Item item = itemSO.items[i];
for (int j = 0; j < item.percent; j++)
itemBuffer.Add(item);
}
for (int i = 0; i < itemBuffer.Count; i++)
{
int rand = Random.Range(i, itemBuffer.Count);
Item temp = itemBuffer[i];
itemBuffer[i] = itemBuffer[rand];
itemBuffer[rand] = temp;
}
}
void Start()
{
SetupItemBuffer();
TurnManager.OnAddCard += AddCard;
TurnManager.OnTurnStarted += OnTurnStarted;
}
void OnDestroy()
{
TurnManager.OnAddCard -= AddCard;
TurnManager.OnTurnStarted -= OnTurnStarted;
}
void OnTurnStarted(bool myTurn)
{
if (myTurn)
myPutCount = 0;
}
void Update()
{
if (isMyCardDrag)
CardDrag();
DetectCardArea();
SetECardState();
}
void AddCard(bool isMine)
{
var cardObject = Instantiate(cardPrefab, cardSpawnPoint.position, Utils.QI);
var card = cardObject.GetComponent<Card>();
card.Setup(PopItem(), isMine);
(isMine ? myCards : otherCards).Add(card);
SetOriginOrder(isMine);
CardAlignment(isMine);
}
void SetOriginOrder(bool isMine)
{
int count = isMine ? myCards.Count : otherCards.Count;
for (int i = 0; i < count; i++)
{
var targetCard = isMine ? myCards[i] : otherCards[i];
targetCard?.GetComponent<Order>().SetOriginOrder(i);
}
}
void CardAlignment(bool isMine)
{
List<PRS> originCardPRSs = new List<PRS>();
if (isMine)
originCardPRSs = RoundAlignment(myCardLeft, myCardRight, myCards.Count, 0.5f, Vector3.one * 1.9f);
else
originCardPRSs = RoundAlignment(otherCardLeft, otherCardRight, otherCards.Count, -0.5f, Vector3.one * 1.9f);
var targetCards = isMine ? myCards : otherCards;
for (int i = 0; i < targetCards.Count; i++)
{
var targetCard = targetCards[i];
targetCard.originPRS = originCardPRSs[i];
targetCard.MoveTransform(targetCard.originPRS, true, 0.7f);
}
}
List<PRS> RoundAlignment(Transform leftTr, Transform rightTr, int objCount, float height, Vector3 scale)
{
float[] objLerps = new float[objCount];
List<PRS> results = new List<PRS>(objCount);
switch (objCount)
{
case 1: objLerps = new float[] { 0.5f }; break;
case 2: objLerps = new float[] { 0.27f, 0.73f }; break;
case 3: objLerps = new float[] { 0.1f, 0.5f, 0.9f }; break;
default:
float interval = 1f / (objCount - 1);
for (int i = 0; i < objCount; i++)
objLerps[i] = interval * i;
break;
}
for (int i = 0; i < objCount; i++)
{
var targetPos = Vector3.Lerp(leftTr.position, rightTr.position, objLerps[i]);
var targetRot = Utils.QI;
if (objCount >= 4)
{
float curve = Mathf.Sqrt(Mathf.Pow(height, 2) - Mathf.Pow(objLerps[i] - 0.5f, 2));
curve = height >= 0 ? curve : -curve;
targetPos.y += curve;
targetRot = Quaternion.Slerp(leftTr.rotation, rightTr.rotation, objLerps[i]);
}
results.Add(new PRS(targetPos, targetRot, scale));
}
return results;
}
public bool TryPutCard(bool isMine)
{
if (isMine && myPutCount >= 1)
return false;
if (!isMine && otherCards.Count <= 0)
return false;
Card card = isMine ? selectCard : otherCards[Random.Range(0, otherCards.Count)];
var spawnPos = isMine ? Utils.MousePos : otherCardSpawnPoint.position;
var targetCards = isMine ? myCards : otherCards;
if (EntityManager.Inst.SpawnEntity(isMine, card.item, spawnPos))
{
targetCards.Remove(card);
card.transform.DOKill();
DestroyImmediate(card.gameObject);
if (isMine)
{
selectCard = null;
myPutCount++;
}
CardAlignment(isMine);
return true;
}
else
{
targetCards.ForEach(x => x.GetComponent<Order>().SetMostFrontOrder(false));
CardAlignment(isMine);
return false;
}
}
#region MyCard
public void CardMouseOver(Card card)
{
if (eCardState == ECardState.Nothing)
return;
selectCard = card;
EnlargeCard(true, card);
}
public void CardMouseExit(Card card)
{
EnlargeCard(false, card);
}
public void CardMouseDown()
{
if (eCardState != ECardState.CanMouseDrag)
return;
isMyCardDrag = true;
}
public void CardMouseUp()
{
isMyCardDrag = false;
if (eCardState != ECardState.CanMouseDrag)
return;
if (onMyCardArea)
EntityManager.Inst.RemoveMyEmptyEntity();
else
TryPutCard(true);
}
void CardDrag()
{
if (eCardState != ECardState.CanMouseDrag)
return;
if (!onMyCardArea)
{
selectCard.MoveTransform(new PRS(Utils.MousePos, Utils.QI, selectCard.originPRS.scale), false);
EntityManager.Inst.InsertMyEmptyEntity(Utils.MousePos.x);
}
}
void DetectCardArea()
{
RaycastHit2D[] hits = Physics2D.RaycastAll(Utils.MousePos, Vector3.forward);
int layer = LayerMask.NameToLayer("MyCardArea");
onMyCardArea = Array.Exists(hits, x => x.collider.gameObject.layer == layer);
}
void EnlargeCard(bool isEnlarge, Card card)
{
if (isEnlarge)
{
Vector3 enlargePos = new Vector3(card.originPRS.pos.x, -4.8f, -10f);
card.MoveTransform(new PRS(enlargePos, Utils.QI, Vector3.one * 3.5f), false);
}
else
card.MoveTransform(card.originPRS, false);
card.GetComponent<Order>().SetMostFrontOrder(isEnlarge);
}
void SetECardState()
{
if (TurnManager.Inst.isLoading)
eCardState = ECardState.Nothing;
else if (!TurnManager.Inst.myTurn || myPutCount == 1 || EntityManager.Inst.IsFullMyEntities)
eCardState = ECardState.CanMouseOver;
else if (TurnManager.Inst.myTurn && myPutCount == 0)
eCardState = ECardState.CanMouseDrag;
}
#endregion
}
Damage.cs 소스입니다
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;
using DG.Tweening;
public class Damage : MonoBehaviour
{
[SerializeField] TMP_Text damageTMP;
Transform tr;
public void SetupTransform(Transform tr)
{
this.tr = tr;
}
void Update()
{
if (tr != null)
transform.position = tr.position;
}
public void Damaged(int damage)
{
if (damage <= 0)
return;
GetComponent<Order>().SetOrder(1000);
damageTMP.text = $"-{damage}";
Sequence sequence = DOTween.Sequence()
.Append(transform.DOScale(Vector3.one * 1.8f, 0.5f).SetEase(Ease.InOutBack))
.AppendInterval(1.2f)
.Append(transform.DOScale(Vector3.zero, 0.5f).SetEase(Ease.InOutBack))
.OnComplete(() => Destroy(gameObject));
}
}
Entity.cs 소스입니다
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;
using DG.Tweening;
public class Entity : MonoBehaviour
{
[SerializeField] Item item;
[SerializeField] SpriteRenderer entity;
[SerializeField] SpriteRenderer character;
[SerializeField] TMP_Text nameTMP;
[SerializeField] TMP_Text attackTMP;
[SerializeField] TMP_Text healthTMP;
[SerializeField] GameObject sleepParticle;
public int attack;
public int health;
public bool isMine;
public bool isDie;
public bool isBossOrEmpty;
public bool attackable;
public Vector3 originPos;
int liveCount;
void Start()
{
TurnManager.OnTurnStarted += OnTurnStarted;
}
void OnDestroy()
{
TurnManager.OnTurnStarted -= OnTurnStarted;
}
void OnTurnStarted(bool myTurn)
{
if (isBossOrEmpty)
return;
if (isMine == myTurn)
liveCount++;
sleepParticle.SetActive(liveCount < 1);
}
public void Setup(Item item)
{
attack = item.attack;
health = item.health;
this.item = item;
character.sprite = this.item.sprite;
nameTMP.text = this.item.name;
attackTMP.text = attack.ToString();
healthTMP.text = health.ToString();
}
void OnMouseDown()
{
if (isMine)
EntityManager.Inst.EntityMouseDown(this);
}
void OnMouseUp()
{
if (isMine)
EntityManager.Inst.EntityMouseUp();
}
void OnMouseDrag()
{
if (isMine)
EntityManager.Inst.EntityMouseDrag();
}
public bool Damaged(int damage)
{
health -= damage;
healthTMP.text = health.ToString();
if (health <= 0)
{
isDie = true;
return true;
}
return false;
}
public void MoveTransform(Vector3 pos, bool useDotween, float dotweenTime = 0)
{
if (useDotween)
transform.DOMove(pos, dotweenTime);
else
transform.position = pos;
}
}
EntityManager.cs 소스입니다
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using DG.Tweening;
public class EntityManager : MonoBehaviour
{
public static EntityManager Inst { get; private set; }
void Awake() => Inst = this;
[SerializeField] GameObject entityPrefab;
[SerializeField] GameObject damagePrefab;
[SerializeField] List<Entity> myEntities;
[SerializeField] List<Entity> otherEntities;
[SerializeField] GameObject TargetPicker;
[SerializeField] Entity myEmptyEntity;
[SerializeField] Entity myBossEntity;
[SerializeField] Entity otherBossEntity;
const int MAX_ENTITY_COUNT = 6;
public bool IsFullMyEntities => myEntities.Count >= MAX_ENTITY_COUNT && !ExistMyEmptyEntity;
bool IsFullOtherEntities => otherEntities.Count >= MAX_ENTITY_COUNT;
bool ExistTargetPickEntity => targetPickEntity != null;
bool ExistMyEmptyEntity => myEntities.Exists(x => x == myEmptyEntity);
int MyEmptyEntityIndex => myEntities.FindIndex(x => x == myEmptyEntity);
bool CanMouseInput => TurnManager.Inst.myTurn && !TurnManager.Inst.isLoading;
Entity selectEntity;
Entity targetPickEntity;
WaitForSeconds delay1 = new WaitForSeconds(1);
WaitForSeconds delay2 = new WaitForSeconds(2);
void Start()
{
TurnManager.OnTurnStarted += OnTurnStarted;
}
void OnDestroy()
{
TurnManager.OnTurnStarted -= OnTurnStarted;
}
void OnTurnStarted(bool myTurn)
{
AttackableReset(myTurn);
if (!myTurn)
StartCoroutine(AICo());
}
void Update()
{
ShowTargetPicker(ExistTargetPickEntity);
}
IEnumerator AICo()
{
CardManager.Inst.TryPutCard(false);
yield return delay1;
// attackable이 true인 모든 otherEntites를 가져와 순서를 섞는다
var attackers = new List<Entity>(otherEntities.FindAll(x => x.attackable == true));
for (int i = 0; i < attackers.Count; i++)
{
int rand = Random.Range(i, attackers.Count);
Entity temp = attackers[i];
attackers[i] = attackers[rand];
attackers[rand] = temp;
}
// 보스를 포함한 myEntities를 랜덤하게 시간차 공격한다
foreach (var attacker in attackers)
{
var defenders = new List<Entity>(myEntities);
defenders.Add(myBossEntity);
int rand = Random.Range(0, defenders.Count);
Attack(attacker, defenders[rand]);
if (TurnManager.Inst.isLoading)
yield break;
yield return delay2;
}
TurnManager.Inst.EndTurn();
}
void EntityAlignment(bool isMine)
{
float targetY = isMine ? -4.35f : 4.15f;
var targetEntities = isMine ? myEntities : otherEntities;
for (int i = 0; i < targetEntities.Count; i++)
{
float targetX = (targetEntities.Count - 1) * -3.4f + i * 6.8f;
var targetEntity = targetEntities[i];
targetEntity.originPos = new Vector3(targetX, targetY, 0);
targetEntity.MoveTransform(targetEntity.originPos, true, 0.5f);
targetEntity.GetComponent<Order>()?.SetOriginOrder(i);
}
}
public void InsertMyEmptyEntity(float xPos)
{
if (IsFullMyEntities)
return;
if (!ExistMyEmptyEntity)
myEntities.Add(myEmptyEntity);
Vector3 emptyEntityPos = myEmptyEntity.transform.position;
emptyEntityPos.x = xPos;
myEmptyEntity.transform.position = emptyEntityPos;
int _emptyEntityIndex = MyEmptyEntityIndex;
myEntities.Sort((entity1, entity2) => entity1.transform.position.x.CompareTo(entity2.transform.position.x));
if (MyEmptyEntityIndex != _emptyEntityIndex)
EntityAlignment(true);
}
public void RemoveMyEmptyEntity()
{
if (!ExistMyEmptyEntity)
return;
myEntities.RemoveAt(MyEmptyEntityIndex);
EntityAlignment(true);
}
public bool SpawnEntity(bool isMine, Item item, Vector3 spawnPos)
{
if (isMine)
{
if (IsFullMyEntities || !ExistMyEmptyEntity)
return false;
}
else
{
if (IsFullOtherEntities)
return false;
}
var entityObject = Instantiate(entityPrefab, spawnPos, Utils.QI);
var entity = entityObject.GetComponent<Entity>();
if (isMine)
myEntities[MyEmptyEntityIndex] = entity;
else
otherEntities.Insert(Random.Range(0, otherEntities.Count), entity);
entity.isMine = isMine;
entity.Setup(item);
EntityAlignment(isMine);
return true;
}
public void EntityMouseDown(Entity entity)
{
if (!CanMouseInput)
return;
selectEntity = entity;
}
public void EntityMouseUp()
{
if (!CanMouseInput)
return;
// selectEntity, targetPickEntity 둘다 존재하면 공격한다. 바로 null, null로 만든다.
if (selectEntity && targetPickEntity && selectEntity.attackable)
Attack(selectEntity, targetPickEntity);
selectEntity = null;
targetPickEntity = null;
}
public void EntityMouseDrag()
{
if (!CanMouseInput || selectEntity == null)
return;
// other 타겟엔티티 찾기
bool existTarget = false;
foreach (var hit in Physics2D.RaycastAll(Utils.MousePos, Vector3.forward))
{
Entity entity = hit.collider?.GetComponent<Entity>();
if (entity != null && !entity.isMine && selectEntity.attackable)
{
targetPickEntity = entity;
existTarget = true;
break;
}
}
if (!existTarget)
targetPickEntity = null;
}
void Attack(Entity attacker, Entity defender)
{
// _attacker가 _defender의 위치로 이동하다 원래 위치로 온다, 이때 order가 높다
attacker.attackable = false;
attacker.GetComponent<Order>().SetMostFrontOrder(true);
Sequence sequence = DOTween.Sequence()
.Append(attacker.transform.DOMove(defender.originPos, 0.4f)).SetEase(Ease.InSine)
.AppendCallback(() =>
{
attacker.Damaged(defender.attack);
defender.Damaged(attacker.attack);
SpawnDamage(defender.attack, attacker.transform);
SpawnDamage(attacker.attack, defender.transform);
})
.Append(attacker.transform.DOMove(attacker.originPos, 0.4f)).SetEase(Ease.OutSine)
.OnComplete(() => AttackCallback(attacker, defender));
}
void AttackCallback(params Entity[] entities)
{
// 죽을 사람 골라서 죽음 처리
entities[0].GetComponent<Order>().SetMostFrontOrder(false);
foreach (var entity in entities)
{
if (!entity.isDie || entity.isBossOrEmpty)
continue;
if (entity.isMine)
myEntities.Remove(entity);
else
otherEntities.Remove(entity);
Sequence sequence = DOTween.Sequence()
.Append(entity.transform.DOShakePosition(1.3f))
.Append(entity.transform.DOScale(Vector3.zero, 0.3f)).SetEase(Ease.OutCirc)
.OnComplete(() =>
{
EntityAlignment(entity.isMine);
Destroy(entity.gameObject);
});
}
StartCoroutine(CheckBossDie());
}
IEnumerator CheckBossDie()
{
yield return delay2;
if (myBossEntity.isDie)
StartCoroutine(GameManager.Inst.GameOver(false));
if (otherBossEntity.isDie)
StartCoroutine(GameManager.Inst.GameOver(true));
}
public void DamageBoss(bool isMine, int damage)
{
var targetBossEntity = isMine ? myBossEntity : otherBossEntity;
targetBossEntity.Damaged(damage);
StartCoroutine(CheckBossDie());
}
void ShowTargetPicker(bool isShow)
{
TargetPicker.SetActive(isShow);
if (ExistTargetPickEntity)
TargetPicker.transform.position = targetPickEntity.transform.position;
}
void SpawnDamage(int damage, Transform tr)
{
if (damage <= 0)
return;
var damageComponent = Instantiate(damagePrefab).GetComponent<Damage>();
damageComponent.SetupTransform(tr);
damageComponent.Damaged(damage);
}
public void AttackableReset(bool isMine)
{
var targetEntites = isMine ? myEntities : otherEntities;
targetEntites.ForEach(x => x.attackable = true);
}
}
GameManager.cs 소스입니다
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
// 치트, UI, 랭킹, 게임오버
public class GameManager : MonoBehaviour
{
public static GameManager Inst { get; private set; }
void Awake() => Inst = this;
[Multiline(10)]
[SerializeField] string cheatInfo;
[SerializeField] NotificationPanel notificationPanel;
[SerializeField] ResultPanel resultPanel;
[SerializeField] TitlePanel titlePanel;
[SerializeField] CameraEffect cameraEffect;
[SerializeField] GameObject endTurnBtn;
WaitForSeconds delay2 = new WaitForSeconds(2);
void Start()
{
UISetup();
}
void UISetup()
{
notificationPanel.ScaleZero();
resultPanel.ScaleZero();
titlePanel.Active(true);
cameraEffect.SetGrayScale(false);
}
void Update()
{
#if UNITY_EDITOR
InputCheatKey();
#endif
}
void InputCheatKey()
{
if (Input.GetKeyDown(KeyCode.Keypad1))
TurnManager.OnAddCard?.Invoke(true);
if (Input.GetKeyDown(KeyCode.Keypad2))
TurnManager.OnAddCard?.Invoke(false);
if (Input.GetKeyDown(KeyCode.Keypad3))
TurnManager.Inst.EndTurn();
if (Input.GetKeyDown(KeyCode.Keypad4))
CardManager.Inst.TryPutCard(false);
if (Input.GetKeyDown(KeyCode.Keypad5))
EntityManager.Inst.DamageBoss(true, 19);
if (Input.GetKeyDown(KeyCode.Keypad6))
EntityManager.Inst.DamageBoss(false, 19);
}
public void StartGame()
{
StartCoroutine(TurnManager.Inst.StartGameCo());
}
public void Notification(string message)
{
notificationPanel.Show(message);
}
public IEnumerator GameOver(bool isMyWin)
{
TurnManager.Inst.isLoading = true;
endTurnBtn.SetActive(false);
yield return delay2;
TurnManager.Inst.isLoading = true;
resultPanel.Show(isMyWin ? "승리" : "패배");
cameraEffect.SetGrayScale(true);
}
}
Order.cs 소스입니다
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Order : MonoBehaviour
{
[SerializeField] Renderer[] backRenderers;
[SerializeField] Renderer[] middleRenderers;
[SerializeField] string sortingLayerName;
int originOrder;
public void SetOriginOrder(int originOrder)
{
this.originOrder = originOrder;
SetOrder(originOrder);
}
public void SetMostFrontOrder(bool isMostFront)
{
SetOrder(isMostFront ? 100 : originOrder);
}
public void SetOrder(int order)
{
int mulOrder = order * 10;
foreach (var renderer in backRenderers)
{
renderer.sortingLayerName = sortingLayerName;
renderer.sortingOrder = mulOrder;
}
foreach (var renderer in middleRenderers)
{
renderer.sortingLayerName = sortingLayerName;
renderer.sortingOrder = mulOrder + 1;
}
}
}
TurnManager.cs 소스입니다
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using Random = UnityEngine.Random;
public class TurnManager : MonoBehaviour
{
public static TurnManager Inst { get; private set; }
void Awake() => Inst = this;
[Header("Develop")]
[SerializeField] [Tooltip("시작 턴 모드를 정합니다")] ETurnMode eTurnMode;
[SerializeField] [Tooltip("카드 배분이 매우 빨라집니다")] bool fastMode;
[SerializeField] [Tooltip("시작 카드 개수를 정합니다")] int startCardCount;
[Header("Properties")]
public bool isLoading; // 게임 끝나면 isLoading을 true로 하면 카드와 엔티티 클릭방지
public bool myTurn;
enum ETurnMode { Random, My, Other }
WaitForSeconds delay05 = new WaitForSeconds(0.5f);
WaitForSeconds delay07 = new WaitForSeconds(0.7f);
public static Action<bool> OnAddCard;
public static event Action<bool> OnTurnStarted;
void GameSetup()
{
if (fastMode)
delay05 = new WaitForSeconds(0.05f);
switch (eTurnMode)
{
case ETurnMode.Random:
myTurn = Random.Range(0, 2) == 0;
break;
case ETurnMode.My:
myTurn = true;
break;
case ETurnMode.Other:
myTurn = false;
break;
}
}
public IEnumerator StartGameCo()
{
GameSetup();
isLoading = true;
for (int i = 0; i < startCardCount; i++)
{
yield return delay05;
OnAddCard?.Invoke(false);
yield return delay05;
OnAddCard?.Invoke(true);
}
StartCoroutine(StartTurnCo());
}
IEnumerator StartTurnCo()
{
isLoading = true;
if (myTurn)
GameManager.Inst.Notification("나의 턴");
yield return delay07;
OnAddCard?.Invoke(myTurn);
yield return delay07;
isLoading = false;
OnTurnStarted?.Invoke(myTurn);
}
public void EndTurn()
{
myTurn = !myTurn;
StartCoroutine(StartTurnCo());
}
}
Utils.cs 소스입니다
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[System.Serializable]
public class PRS
{
public Vector3 pos;
public Quaternion rot;
public Vector3 scale;
public PRS(Vector3 pos, Quaternion rot, Vector3 scale)
{
this.pos = pos;
this.rot = rot;
this.scale = scale;
}
}
public class Utils
{
public static Quaternion QI => Quaternion.identity;
public static Vector3 MousePos
{
get
{
Vector3 result = Camera.main.ScreenToWorldPoint(Input.mousePosition);
result.z = -10;
return result;
}
}
}
GrayscaleShader.shader 소스입니다
Shader "Custom/GrayscaleShader"
{
Properties
{
_MainTex("Texture", 2D) = "white" {}
_GrayscaleAmount("Gray Scale Amount", Range(0, 1)) = 1.0
_DarkAmount("Dark Amount", Range(0, 1)) = 1.0
}
SubShader
{
// No culling or depth
Cull Off ZWrite Off ZTest Always
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
v2f vert(appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
return o;
}
sampler2D _MainTex;
float _GrayscaleAmount;
float _DarkAmount;
fixed4 frag(v2f i) : SV_Target
{
fixed4 col = tex2D(_MainTex, i.uv);
col.rgb = lerp(col.rgb, dot(col.rgb, float3(0.3, 0.59, 0.11)), _GrayscaleAmount);
col.rgb -= _DarkAmount;
return col;
}
ENDCG
}
}
}