init
This commit is contained in:
132
Assets/TcgEngine/Scripts/GameClient/BSlot.cs
Normal file
132
Assets/TcgEngine/Scripts/GameClient/BSlot.cs
Normal file
@@ -0,0 +1,132 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace TcgEngine.Client
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for BoardSlot, BoardSlotPlayer and BoardSlotGroup
|
||||
/// </summary>
|
||||
|
||||
public class BSlot : MonoBehaviour
|
||||
{
|
||||
protected SpriteRenderer render;
|
||||
protected Collider collide;
|
||||
protected Bounds bounds;
|
||||
protected float start_alpha = 0f;
|
||||
protected float current_alpha = 0f;
|
||||
protected float target_alpha = 0f;
|
||||
|
||||
private static List<BSlot> slot_list = new List<BSlot>();
|
||||
|
||||
protected virtual void Awake()
|
||||
{
|
||||
slot_list.Add(this);
|
||||
render = GetComponent<SpriteRenderer>();
|
||||
collide = GetComponent<Collider>();
|
||||
start_alpha = render.color.a;
|
||||
render.color = new Color(render.color.r, render.color.g, render.color.b, 0f);
|
||||
bounds = collide.bounds;
|
||||
}
|
||||
|
||||
protected virtual void OnDestroy()
|
||||
{
|
||||
slot_list.Remove(this);
|
||||
}
|
||||
|
||||
protected virtual void Update()
|
||||
{
|
||||
current_alpha = Mathf.MoveTowards(current_alpha, target_alpha * start_alpha, 2f * Time.deltaTime);
|
||||
render.color = new Color(render.color.r, render.color.g, render.color.b, current_alpha);
|
||||
}
|
||||
|
||||
public virtual Slot GetSlot()
|
||||
{
|
||||
return Slot.None;
|
||||
}
|
||||
|
||||
public virtual Slot GetSlot(Vector3 wpos)
|
||||
{
|
||||
return GetSlot();
|
||||
}
|
||||
|
||||
public virtual Slot GetEmptySlot(Vector3 wpos)
|
||||
{
|
||||
return GetSlot();
|
||||
}
|
||||
|
||||
public virtual Card GetSlotCard(Vector3 wpos)
|
||||
{
|
||||
Game gdata = GameClient.Get().GetGameData();
|
||||
Slot slot = GetSlot(wpos);
|
||||
return gdata.GetSlotCard(slot);
|
||||
}
|
||||
|
||||
public virtual Vector3 GetPosition(Slot slot)
|
||||
{
|
||||
return transform.position;
|
||||
}
|
||||
|
||||
public virtual Player GetPlayer()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public virtual bool HasSlot(Slot slot)
|
||||
{
|
||||
Slot aslot = GetSlot();
|
||||
return aslot == slot;
|
||||
}
|
||||
|
||||
public virtual bool IsPlayer()
|
||||
{
|
||||
Slot slot = GetSlot();
|
||||
return slot.x == 0 && slot.y == 0;
|
||||
}
|
||||
|
||||
public virtual bool IsInside(Vector3 wpos)
|
||||
{
|
||||
return bounds.Contains(wpos);
|
||||
}
|
||||
|
||||
public static BSlot GetNearest(Vector3 pos)
|
||||
{
|
||||
BSlot nearest = null;
|
||||
float min_dist = 999f;
|
||||
foreach (BSlot slot in GetAll())
|
||||
{
|
||||
float dist = (slot.transform.position - pos).magnitude;
|
||||
if (slot.IsInside(pos) && dist < min_dist)
|
||||
{
|
||||
min_dist = dist;
|
||||
nearest = slot;
|
||||
}
|
||||
}
|
||||
return nearest;
|
||||
}
|
||||
|
||||
public static BSlot Get(Slot slot)
|
||||
{
|
||||
foreach (BSlot bslot in GetAll())
|
||||
{
|
||||
if (bslot.HasSlot(slot))
|
||||
return bslot;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static List<BSlot> GetAll()
|
||||
{
|
||||
return slot_list;
|
||||
}
|
||||
}
|
||||
|
||||
public enum BoardSlotType
|
||||
{
|
||||
Fixed = 0, //x,y,p = slot
|
||||
PlayerSelf = 5, //p = client player id
|
||||
PlayerOpponent = 7, //p = client's opponent player id
|
||||
FlipX = 10, //p=0, x=unchanged for first player, x=reversed for second player
|
||||
FlipY = 11, //p=0, y=unchanged for first player, y=reversed for second player
|
||||
}
|
||||
}
|
||||
11
Assets/TcgEngine/Scripts/GameClient/BSlot.cs.meta
Normal file
11
Assets/TcgEngine/Scripts/GameClient/BSlot.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f24fd6723cd31954591a68e4398ebe8a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
541
Assets/TcgEngine/Scripts/GameClient/BoardCard.cs
Normal file
541
Assets/TcgEngine/Scripts/GameClient/BoardCard.cs
Normal file
@@ -0,0 +1,541 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using TcgEngine.Client;
|
||||
using UnityEngine.Events;
|
||||
using TcgEngine.UI;
|
||||
using TcgEngine.FX;
|
||||
|
||||
namespace TcgEngine.Client
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the visual aspect of a card on the board.
|
||||
/// Will take the data from Card.cs and display it
|
||||
/// </summary>
|
||||
|
||||
public class BoardCard : MonoBehaviour
|
||||
{
|
||||
public SpriteRenderer card_sprite;
|
||||
public SpriteRenderer card_glow;
|
||||
public SpriteRenderer card_shadow;
|
||||
|
||||
public Image armor_icon;
|
||||
public Text armor;
|
||||
|
||||
public CanvasGroup status_group;
|
||||
public Text status_text;
|
||||
|
||||
public BoardCardEquip equipment;
|
||||
|
||||
public AbilityButton[] buttons;
|
||||
|
||||
public Color glow_ally;
|
||||
public Color glow_enemy;
|
||||
|
||||
public UnityAction onKill;
|
||||
|
||||
private CardUI card_ui;
|
||||
private BoardCardFX card_fx;
|
||||
private Canvas canvas;
|
||||
|
||||
private string card_uid = "";
|
||||
private bool destroyed = false;
|
||||
private bool focus = false;
|
||||
private float timer = 0f;
|
||||
private float status_alpha_target = 0f;
|
||||
private float delayed_damage_timer = 0f;
|
||||
private int prev_hp = 0;
|
||||
|
||||
private bool back_to_hand;
|
||||
private Vector3 back_to_hand_target;
|
||||
|
||||
private static List<BoardCard> card_list = new List<BoardCard>();
|
||||
|
||||
void Awake()
|
||||
{
|
||||
card_list.Add(this);
|
||||
card_ui = GetComponent<CardUI>();
|
||||
card_fx = GetComponent<BoardCardFX>();
|
||||
canvas = GetComponentInChildren<Canvas>();
|
||||
card_glow.color = new Color(card_glow.color.r, card_glow.color.g, card_glow.color.b, 0f);
|
||||
canvas.gameObject.SetActive(false);
|
||||
status_alpha_target = 0f;
|
||||
|
||||
if (equipment != null)
|
||||
equipment.Hide();
|
||||
|
||||
if (status_group != null)
|
||||
status_group.alpha = 0f;
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
card_list.Remove(this);
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
//Random slight rotation
|
||||
Vector3 board_rot = GameBoard.Get().GetAngles();
|
||||
transform.rotation = Quaternion.Euler(board_rot.x, board_rot.y, board_rot.z + Random.Range(-1f, 1f));
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
if (!GameClient.Get().IsReady())
|
||||
return;
|
||||
|
||||
delayed_damage_timer -= Time.deltaTime;
|
||||
timer += Time.deltaTime;
|
||||
if (timer > 0.15f && !destroyed && !canvas.gameObject.activeSelf)
|
||||
canvas.gameObject.SetActive(true);
|
||||
|
||||
PlayerControls controls = PlayerControls.Get();
|
||||
Game data = GameClient.Get().GetGameData();
|
||||
Player player = GameClient.Get().GetPlayer();
|
||||
Card card = data.GetCard(card_uid);
|
||||
|
||||
if (!destroyed)
|
||||
{
|
||||
card_ui.SetCard(card);
|
||||
card_ui.SetHP(prev_hp);
|
||||
}
|
||||
|
||||
//Save Previous HP
|
||||
if (!IsDamagedDelayed())
|
||||
prev_hp = card.GetHP();
|
||||
|
||||
bool selected = controls.GetSelected() == this;
|
||||
Vector3 targ_pos = GetTargetPos();
|
||||
float speed = 12f;
|
||||
|
||||
transform.position = Vector3.MoveTowards(transform.position, targ_pos, speed * Time.deltaTime);
|
||||
|
||||
float target_alpha = IsFocus() || selected ? 1f : 0f;
|
||||
if (destroyed || timer < 1f)
|
||||
target_alpha = 0f;
|
||||
if (equipment != null && equipment.IsFocus())
|
||||
target_alpha = 0f;
|
||||
|
||||
Color ccolor = player.player_id == card.player_id ? glow_ally : glow_enemy;
|
||||
float calpha = Mathf.MoveTowards(card_glow.color.a, target_alpha * ccolor.a, 4f * Time.deltaTime);
|
||||
card_glow.color = new Color(ccolor.r, ccolor.g, ccolor.b, calpha);
|
||||
card_shadow.enabled = !destroyed && timer > 0.4f;
|
||||
card_sprite.color = card.HasStatus(StatusType.Stealth) ? Color.gray : Color.white;
|
||||
card_ui.hp.color = (destroyed || card.damage > 0) ? Color.yellow : Color.white;
|
||||
|
||||
//armor
|
||||
int armor_val = card.GetStatusValue(StatusType.Armor);
|
||||
armor.text = armor_val.ToString();
|
||||
armor.enabled = armor_val > 0;
|
||||
armor_icon.enabled = armor_val > 0;
|
||||
|
||||
//Update card image
|
||||
Sprite sprite = card.CardData.GetBoardArt(card.VariantData);
|
||||
if (sprite != card_sprite.sprite)
|
||||
card_sprite.sprite = sprite;
|
||||
|
||||
//Update frame image
|
||||
Sprite frame = card.VariantData.frame_board;
|
||||
if (frame != null && card_ui.frame_image != null)
|
||||
card_ui.frame_image.sprite = frame;
|
||||
|
||||
//Equipment
|
||||
if (equipment != null)
|
||||
{
|
||||
Card equip = data.GetEquipCard(card.equipped_uid);
|
||||
equipment.SetEquip(equip);
|
||||
}
|
||||
|
||||
//Ability buttons
|
||||
foreach (AbilityButton button in buttons)
|
||||
button.Hide();
|
||||
|
||||
if (selected && card.player_id == player.player_id)
|
||||
{
|
||||
int index = 0;
|
||||
List<AbilityData> abilities = card.GetAbilities();
|
||||
foreach (AbilityData iability in abilities)
|
||||
{
|
||||
if (iability != null && iability.trigger == AbilityTrigger.Activate)
|
||||
{
|
||||
if (index < buttons.Length)
|
||||
{
|
||||
AbilityButton button = buttons[index];
|
||||
button.SetAbility(card, iability);
|
||||
button.SetInteractable(data.CanCastAbility(card, iability));
|
||||
}
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
Card equip = data.GetEquipCard(card.equipped_uid);
|
||||
if (equip != null)
|
||||
{
|
||||
List<AbilityData> equip_abilities = equip.GetAbilities();
|
||||
foreach (AbilityData iability in equip_abilities)
|
||||
{
|
||||
if (iability != null && iability.trigger == AbilityTrigger.Activate)
|
||||
{
|
||||
if (index < buttons.Length)
|
||||
{
|
||||
AbilityButton button = buttons[index];
|
||||
button.SetAbility(equip, iability);
|
||||
button.SetInteractable(data.CanCastAbility(equip, iability));
|
||||
}
|
||||
index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Status bar
|
||||
if (status_group != null)
|
||||
status_group.alpha = Mathf.MoveTowards(status_group.alpha, status_alpha_target, 5f * Time.deltaTime);
|
||||
}
|
||||
|
||||
private Vector3 GetTargetPos()
|
||||
{
|
||||
Game data = GameClient.Get().GetGameData();
|
||||
Card card = data.GetCard(card_uid);
|
||||
|
||||
if (destroyed && back_to_hand && timer > 0.5f)
|
||||
return back_to_hand_target;
|
||||
|
||||
BSlot slot = BSlot.Get(card.slot);
|
||||
if (slot != null)
|
||||
{
|
||||
Vector3 targ_pos = slot.GetPosition(card.slot);
|
||||
return targ_pos;
|
||||
}
|
||||
|
||||
return transform.position;
|
||||
}
|
||||
|
||||
public void SetCard(Card card)
|
||||
{
|
||||
this.card_uid = card.uid;
|
||||
|
||||
transform.position = GetTargetPos();
|
||||
prev_hp = card.GetHP();
|
||||
|
||||
CardData icard = CardData.Get(card.card_id);
|
||||
if (icard)
|
||||
{
|
||||
card_ui.SetCard(card);
|
||||
card_sprite.sprite = icard.GetBoardArt(card.VariantData);
|
||||
armor.enabled = false;
|
||||
armor_icon.enabled = false;
|
||||
status_alpha_target = 0f;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetOrder(int order)
|
||||
{
|
||||
card_sprite.sortingOrder = order;
|
||||
canvas.sortingOrder = order + 1;
|
||||
}
|
||||
|
||||
public void Destroy()
|
||||
{
|
||||
if (!destroyed)
|
||||
{
|
||||
Game data = GameClient.Get().GetGameData();
|
||||
Card card = data.GetCard(card_uid);
|
||||
Player player = data.GetPlayer(card.player_id);
|
||||
|
||||
destroyed = true;
|
||||
timer = 0f;
|
||||
status_alpha_target = 0f;
|
||||
card_glow.enabled = false;
|
||||
card_shadow.enabled = false;
|
||||
|
||||
SetOrder(card_sprite.sortingOrder - 2);
|
||||
Destroy(gameObject, 1.3f);
|
||||
|
||||
TimeTool.WaitFor(0.8f, () =>
|
||||
{
|
||||
canvas.gameObject.SetActive(false);
|
||||
});
|
||||
|
||||
GameBoard board = GameBoard.Get();
|
||||
if (player.HasCard(player.cards_hand, card) || player.HasCard(player.cards_deck, card))
|
||||
{
|
||||
back_to_hand = true;
|
||||
back_to_hand_target = player.player_id == GameClient.Get().GetPlayerID() ? -board.transform.up : board.transform.up;
|
||||
back_to_hand_target = back_to_hand_target * 10f;
|
||||
}
|
||||
|
||||
if (!back_to_hand)
|
||||
{
|
||||
card.hp = 0;
|
||||
card_ui.SetCard(card);
|
||||
}
|
||||
|
||||
if (onKill != null)
|
||||
onKill.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
//Offset the HP visuals by a value so the HP dont go down before end of animation (like a projectile)
|
||||
public void DelayDamage(int damage, float duration = 1f)
|
||||
{
|
||||
if (damage != 0)
|
||||
{
|
||||
delayed_damage_timer = duration;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsDamagedDelayed()
|
||||
{
|
||||
return delayed_damage_timer > 0f;
|
||||
}
|
||||
|
||||
private void ShowStatusBar()
|
||||
{
|
||||
Card card = GetCard();
|
||||
if (card != null && status_text != null && !destroyed)
|
||||
{
|
||||
string stxt = GetStatusText();
|
||||
string ttxt = GetTraitText();
|
||||
|
||||
if (stxt.Length > 0 && ttxt.Length > 0)
|
||||
status_text.text = ttxt + ", " + stxt;
|
||||
else
|
||||
status_text.text = ttxt + stxt;
|
||||
}
|
||||
|
||||
bool show_status = status_text != null && status_text.text.Length > 0;
|
||||
status_alpha_target = show_status ? 1f : 0f;
|
||||
}
|
||||
|
||||
public string GetStatusText()
|
||||
{
|
||||
Card card = GetCard();
|
||||
string txt = "";
|
||||
foreach (CardStatus astatus in card.GetAllStatus())
|
||||
{
|
||||
StatusData istats = StatusData.Get(astatus.type);
|
||||
if (istats != null && !string.IsNullOrEmpty(istats.title))
|
||||
{
|
||||
int ival = Mathf.Max(astatus.value, Mathf.CeilToInt(astatus.duration / 2f));
|
||||
string sval = ival > 1 ? " " + ival : "";
|
||||
txt += istats.GetTitle() + sval + ", ";
|
||||
}
|
||||
}
|
||||
if (txt.Length > 2)
|
||||
txt = txt.Substring(0, txt.Length - 2);
|
||||
return txt;
|
||||
}
|
||||
|
||||
public string GetTraitText()
|
||||
{
|
||||
Card card = GetCard();
|
||||
string txt = "";
|
||||
foreach (CardTrait atrait in card.GetAllTraits())
|
||||
{
|
||||
TraitData itrait = TraitData.Get(atrait.id);
|
||||
if (itrait != null && !string.IsNullOrEmpty(itrait.title))
|
||||
{
|
||||
int ival = atrait.value;
|
||||
string sval = ival > 1 ? " " + ival : "";
|
||||
txt += itrait.GetTitle() + sval + ", ";
|
||||
}
|
||||
}
|
||||
if (txt.Length > 2)
|
||||
txt = txt.Substring(0, txt.Length - 2);
|
||||
return txt;
|
||||
}
|
||||
|
||||
public bool IsDead()
|
||||
{
|
||||
return destroyed;
|
||||
}
|
||||
|
||||
public bool IsFocus()
|
||||
{
|
||||
return focus;
|
||||
}
|
||||
|
||||
public bool IsEquipFocus()
|
||||
{
|
||||
return equipment != null && equipment.IsFocus();
|
||||
}
|
||||
|
||||
public void OnMouseEnter()
|
||||
{
|
||||
if (GameUI.IsUIOpened())
|
||||
return;
|
||||
|
||||
if (GameTool.IsMobile())
|
||||
return;
|
||||
|
||||
focus = true;
|
||||
ShowStatusBar();
|
||||
}
|
||||
|
||||
public void OnMouseExit()
|
||||
{
|
||||
focus = false;
|
||||
status_alpha_target = 0f;
|
||||
}
|
||||
|
||||
public void OnMouseDown()
|
||||
{
|
||||
if (GameUI.IsOverUILayer("UI"))
|
||||
return;
|
||||
|
||||
PlayerControls.Get().SelectCard(this);
|
||||
|
||||
if (GameTool.IsMobile())
|
||||
{
|
||||
focus = true;
|
||||
ShowStatusBar();
|
||||
}
|
||||
}
|
||||
|
||||
public void OnMouseUp()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void OnMouseOver()
|
||||
{
|
||||
if (Input.GetMouseButtonDown(1))
|
||||
{
|
||||
PlayerControls.Get().SelectCardRight(this);
|
||||
}
|
||||
}
|
||||
|
||||
public string GetCardUID()
|
||||
{
|
||||
return card_uid;
|
||||
}
|
||||
|
||||
//Return main card (not equip)
|
||||
public Card GetCard()
|
||||
{
|
||||
Game data = GameClient.Get().GetGameData();
|
||||
Card card = data.GetCard(card_uid);
|
||||
return card;
|
||||
}
|
||||
|
||||
//Return equip card
|
||||
public Card GetEquipCard()
|
||||
{
|
||||
Game data = GameClient.Get().GetGameData();
|
||||
Card card = GetCard();
|
||||
Card equip = data?.GetEquipCard(card.equipped_uid);
|
||||
return equip;
|
||||
}
|
||||
|
||||
//Return either main or equip card based on which one is focused
|
||||
public Card GetFocusCard()
|
||||
{
|
||||
if (IsEquipFocus())
|
||||
return GetEquipCard();
|
||||
return GetCard();
|
||||
}
|
||||
|
||||
public CardData GetCardData()
|
||||
{
|
||||
Card card = GetCard();
|
||||
if (card != null)
|
||||
return CardData.Get(card.card_id);
|
||||
return null;
|
||||
}
|
||||
|
||||
public Slot GetSlot()
|
||||
{
|
||||
return GetCard().slot;
|
||||
}
|
||||
|
||||
public BoardCardFX GetCardFX()
|
||||
{
|
||||
return card_fx;
|
||||
}
|
||||
|
||||
public CardData CardData { get { return GetCardData(); } }
|
||||
|
||||
public static int GetNbCardsBoardPlayer(int player_id)
|
||||
{
|
||||
int nb = 0;
|
||||
foreach (BoardCard acard in card_list)
|
||||
{
|
||||
if (acard != null && acard.GetCard().player_id == player_id)
|
||||
nb++;
|
||||
}
|
||||
return nb;
|
||||
}
|
||||
|
||||
public static BoardCard GetNearestPlayer(Vector3 pos, int skip_player_id, BoardCard skip, float range = 2f)
|
||||
{
|
||||
BoardCard nearest = null;
|
||||
float min_dist = range;
|
||||
foreach (BoardCard card in card_list)
|
||||
{
|
||||
float dist = (card.transform.position - pos).magnitude;
|
||||
if (dist < min_dist && card != skip && skip_player_id != card.GetCard().player_id)
|
||||
{
|
||||
min_dist = dist;
|
||||
nearest = card;
|
||||
}
|
||||
}
|
||||
return nearest;
|
||||
}
|
||||
|
||||
public static BoardCard GetNearest(Vector3 pos, BoardCard skip, float range = 2f)
|
||||
{
|
||||
BoardCard nearest = null;
|
||||
float min_dist = range;
|
||||
foreach (BoardCard card in card_list)
|
||||
{
|
||||
float dist = (card.transform.position - pos).magnitude;
|
||||
if (dist < min_dist && card != skip)
|
||||
{
|
||||
min_dist = dist;
|
||||
nearest = card;
|
||||
}
|
||||
}
|
||||
return nearest;
|
||||
}
|
||||
|
||||
public static BoardCard GetFocus()
|
||||
{
|
||||
if (GameUI.IsOverUI())
|
||||
return null;
|
||||
|
||||
foreach (BoardCard card in card_list)
|
||||
{
|
||||
if (card.IsFocus() || card.IsEquipFocus())
|
||||
return card;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void UnfocusAll()
|
||||
{
|
||||
foreach (BoardCard card in card_list)
|
||||
{
|
||||
card.focus = false;
|
||||
card.status_alpha_target = 0f;
|
||||
}
|
||||
}
|
||||
|
||||
public static BoardCard Get(string uid)
|
||||
{
|
||||
foreach (BoardCard card in card_list)
|
||||
{
|
||||
if (card.card_uid == uid)
|
||||
return card;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static List<BoardCard> GetAll()
|
||||
{
|
||||
return card_list;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/TcgEngine/Scripts/GameClient/BoardCard.cs.meta
Normal file
11
Assets/TcgEngine/Scripts/GameClient/BoardCard.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0667b5470f3948f498f8dbd5e0af2433
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
105
Assets/TcgEngine/Scripts/GameClient/BoardCardEquip.cs
Normal file
105
Assets/TcgEngine/Scripts/GameClient/BoardCardEquip.cs
Normal file
@@ -0,0 +1,105 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
using UnityEngine.UI;
|
||||
using TcgEngine.UI;
|
||||
|
||||
namespace TcgEngine.Client
|
||||
{
|
||||
|
||||
public class BoardCardEquip : MonoBehaviour
|
||||
{
|
||||
public Image equip_sprite;
|
||||
public Image equip_glow;
|
||||
public Text equip_hp;
|
||||
|
||||
public Color glow_ally;
|
||||
public Color glow_enemy;
|
||||
|
||||
private Canvas canvas;
|
||||
private RectTransform rect;
|
||||
|
||||
private Card equip;
|
||||
private bool focus;
|
||||
private float target_alpha = 0f;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
canvas = GetComponentInParent<Canvas>();
|
||||
rect = GetComponent<RectTransform>();
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (equip != null)
|
||||
{
|
||||
target_alpha = focus ? 1f : 0f;
|
||||
focus = GameUI.IsOverRectTransform(canvas, rect);
|
||||
}
|
||||
else
|
||||
{
|
||||
target_alpha = 0f;
|
||||
focus = false;
|
||||
}
|
||||
|
||||
if (equip_glow != null)
|
||||
{
|
||||
int player_id = GameClient.Get().GetPlayerID();
|
||||
Color ccolor = player_id == equip.player_id ? glow_ally : glow_enemy;
|
||||
float calpha = Mathf.MoveTowards(equip_glow.color.a, target_alpha * ccolor.a, 4f * Time.deltaTime);
|
||||
equip_glow.color = new Color(ccolor.r, ccolor.g, ccolor.b, calpha);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetEquip(Card equip)
|
||||
{
|
||||
if (equip != null)
|
||||
{
|
||||
this.equip = equip;
|
||||
equip_sprite.sprite = equip.CardData.GetBoardArt(equip.VariantData);
|
||||
equip_hp.text = equip.GetHP().ToString();
|
||||
|
||||
if (!gameObject.activeSelf)
|
||||
gameObject.SetActive(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
Hide();
|
||||
}
|
||||
}
|
||||
|
||||
public void Hide()
|
||||
{
|
||||
this.equip = null;
|
||||
focus = false;
|
||||
if (gameObject.activeSelf)
|
||||
gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
public bool IsFocus()
|
||||
{
|
||||
return equip != null && focus;
|
||||
}
|
||||
|
||||
public Card GetCard()
|
||||
{
|
||||
return equip;
|
||||
}
|
||||
|
||||
public void OnPointerEnter(PointerEventData eventData)
|
||||
{
|
||||
focus = true;
|
||||
}
|
||||
|
||||
public void OnPointerExit(PointerEventData eventData)
|
||||
{
|
||||
focus = false;
|
||||
}
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
focus = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/TcgEngine/Scripts/GameClient/BoardCardEquip.cs.meta
Normal file
11
Assets/TcgEngine/Scripts/GameClient/BoardCardEquip.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 490b587793e30f64290ebc73ec4dc3bd
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
101
Assets/TcgEngine/Scripts/GameClient/BoardDeck.cs
Normal file
101
Assets/TcgEngine/Scripts/GameClient/BoardDeck.cs
Normal file
@@ -0,0 +1,101 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using TcgEngine.UI;
|
||||
|
||||
namespace TcgEngine.Client
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the visual deck on the board
|
||||
/// Will show number of cards in deck/discard when hovering
|
||||
/// </summary>
|
||||
|
||||
public class BoardDeck : MonoBehaviour
|
||||
{
|
||||
public bool opponent;
|
||||
public UIPanel hover_panel;
|
||||
public SpriteRenderer deck_render;
|
||||
public Text deck_value;
|
||||
public Text discard_value;
|
||||
|
||||
private bool hover = false;
|
||||
|
||||
void Start()
|
||||
{
|
||||
if (GameTool.IsMobile())
|
||||
{
|
||||
hover_panel?.SetVisible(true);
|
||||
}
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
Refresh();
|
||||
}
|
||||
|
||||
private void Refresh()
|
||||
{
|
||||
if (!GameClient.Get().IsReady())
|
||||
return;
|
||||
|
||||
Player player = opponent ? GameClient.Get().GetOpponentPlayer() : GameClient.Get().GetPlayer();
|
||||
if (player == null)
|
||||
return;
|
||||
|
||||
CardbackData cb = CardbackData.Get(player.cardback);
|
||||
if (deck_render != null && cb != null)
|
||||
deck_render.sprite = cb.deck;
|
||||
|
||||
if (deck_value != null)
|
||||
deck_value.text = player.cards_deck.Count.ToString();
|
||||
if (discard_value != null)
|
||||
discard_value.text = player.cards_discard.Count.ToString();
|
||||
}
|
||||
|
||||
public void ShowDeckCards()
|
||||
{
|
||||
Player player = GameClient.Get().GetPlayer();
|
||||
CardSelector.Get().Show(player.cards_deck, "DECK");
|
||||
}
|
||||
|
||||
public void ShowDiscardCards()
|
||||
{
|
||||
Player player = opponent ? GameClient.Get().GetOpponentPlayer() : GameClient.Get().GetPlayer();
|
||||
CardSelector.Get().Show(player.cards_discard, "DISCARD");
|
||||
}
|
||||
|
||||
private void ShowHover(bool hover)
|
||||
{
|
||||
if(!GameTool.IsMobile())
|
||||
hover_panel?.SetVisible(hover);
|
||||
}
|
||||
|
||||
private void OnMouseEnter()
|
||||
{
|
||||
hover = true;
|
||||
ShowHover(hover);
|
||||
Refresh();
|
||||
}
|
||||
|
||||
private void OnMouseExit()
|
||||
{
|
||||
hover = false;
|
||||
ShowHover(hover);
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
hover = false;
|
||||
ShowHover(hover);
|
||||
}
|
||||
|
||||
private void OnMouseOver()
|
||||
{
|
||||
if (!opponent && Input.GetMouseButtonDown(0))
|
||||
ShowDeckCards(); //Cannot see opponent deck
|
||||
else if(Input.GetMouseButtonDown(1))
|
||||
ShowDiscardCards(); //Cant see both player discard
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/TcgEngine/Scripts/GameClient/BoardDeck.cs.meta
Normal file
11
Assets/TcgEngine/Scripts/GameClient/BoardDeck.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 30b49cb9ea26dff4fb1c815bacdf2cbf
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
57
Assets/TcgEngine/Scripts/GameClient/BoardRef.cs
Normal file
57
Assets/TcgEngine/Scripts/GameClient/BoardRef.cs
Normal file
@@ -0,0 +1,57 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace TcgEngine.Client
|
||||
{
|
||||
|
||||
public enum BoardRefType
|
||||
{
|
||||
None = 0,
|
||||
PackCard = 4,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A reference to a position on the board,
|
||||
/// It is currently being used by the PackOpen board
|
||||
/// </summary>
|
||||
|
||||
public class BoardRef : MonoBehaviour
|
||||
{
|
||||
public BoardRefType type;
|
||||
public int index;
|
||||
public bool opponent;
|
||||
|
||||
private static List<BoardRef> ref_list = new List<BoardRef>();
|
||||
|
||||
void Awake()
|
||||
{
|
||||
ref_list.Add(this);
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
ref_list.Remove(this);
|
||||
}
|
||||
|
||||
public static BoardRef Get(BoardRefType type, bool opponent)
|
||||
{
|
||||
foreach (BoardRef bref in ref_list)
|
||||
{
|
||||
if (bref.type == type && bref.opponent == opponent)
|
||||
return bref;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static BoardRef Get(BoardRefType type, int index)
|
||||
{
|
||||
foreach (BoardRef bref in ref_list)
|
||||
{
|
||||
if (bref.type == type && bref.index == index)
|
||||
return bref;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/TcgEngine/Scripts/GameClient/BoardRef.cs.meta
Normal file
11
Assets/TcgEngine/Scripts/GameClient/BoardRef.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a77230af9aa79be4799f4927e744d232
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
142
Assets/TcgEngine/Scripts/GameClient/BoardSlot.cs
Normal file
142
Assets/TcgEngine/Scripts/GameClient/BoardSlot.cs
Normal file
@@ -0,0 +1,142 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using TcgEngine.Client;
|
||||
using TcgEngine.UI;
|
||||
|
||||
namespace TcgEngine.Client
|
||||
{
|
||||
/// <summary>
|
||||
/// Visual representation of a Slot.cs
|
||||
/// Will highlight when can be interacted with
|
||||
/// </summary>
|
||||
|
||||
public class BoardSlot : BSlot
|
||||
{
|
||||
public BoardSlotType type;
|
||||
public int x;
|
||||
public int y;
|
||||
|
||||
private static List<BoardSlot> slot_list = new List<BoardSlot>();
|
||||
|
||||
protected override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
slot_list.Add(this);
|
||||
}
|
||||
|
||||
protected override void OnDestroy()
|
||||
{
|
||||
base.OnDestroy();
|
||||
slot_list.Remove(this);
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
if (x < Slot.x_min || x > Slot.x_max || y < Slot.y_min || y > Slot.y_max)
|
||||
Debug.LogError("Board Slot X and Y value must be within the min and max set for those values, check Slot.cs script to change those min/max.");
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
if (!GameClient.Get().IsReady())
|
||||
return;
|
||||
|
||||
BoardCard bcard_selected = PlayerControls.Get().GetSelected();
|
||||
HandCard drag_card = HandCard.GetDrag();
|
||||
|
||||
Game gdata = GameClient.Get().GetGameData();
|
||||
Player player = GameClient.Get().GetPlayer();
|
||||
Slot slot = GetSlot();
|
||||
Card dcard = drag_card?.GetCard();
|
||||
Card slot_card = gdata.GetSlotCard(GetSlot());
|
||||
bool your_turn = GameClient.Get().IsYourTurn();
|
||||
collide.enabled = slot_card == null; //Disable collider when a card is here
|
||||
|
||||
//Find target opacity value
|
||||
target_alpha = 0f;
|
||||
if (your_turn && dcard != null && dcard.CardData.IsBoardCard() && gdata.CanPlayCard(dcard, slot))
|
||||
{
|
||||
target_alpha = 1f; //hightlight when dragging a character or artifact
|
||||
}
|
||||
|
||||
if (your_turn && dcard != null && dcard.CardData.IsRequireTarget() && gdata.CanPlayCard(dcard, slot))
|
||||
{
|
||||
target_alpha = 1f; //Highlight when dragin a spell with target
|
||||
}
|
||||
|
||||
if (gdata.selector == SelectorType.SelectTarget && player.player_id == gdata.selector_player_id)
|
||||
{
|
||||
Card caster = gdata.GetCard(gdata.selector_caster_uid);
|
||||
AbilityData ability = AbilityData.Get(gdata.selector_ability_id);
|
||||
if(ability != null && slot_card == null && ability.CanTarget(gdata, caster, slot))
|
||||
target_alpha = 1f; //Highlight when selecting a target and slot are valid
|
||||
if (ability != null && slot_card != null && ability.CanTarget(gdata, caster, slot_card))
|
||||
target_alpha = 1f; //Highlight when selecting a target and cards are valid
|
||||
}
|
||||
|
||||
Card select_card = bcard_selected?.GetCard();
|
||||
bool can_do_move = your_turn && select_card != null && slot_card == null && gdata.CanMoveCard(select_card, slot);
|
||||
bool can_do_attack = your_turn && select_card != null && slot_card != null && gdata.CanAttackTarget(select_card, slot_card);
|
||||
|
||||
if (can_do_attack || can_do_move)
|
||||
{
|
||||
target_alpha = 1f;
|
||||
}
|
||||
}
|
||||
|
||||
//Find the actual slot coordinates of this board slot
|
||||
public override Slot GetSlot()
|
||||
{
|
||||
int p = 0;
|
||||
|
||||
if (type == BoardSlotType.FlipX)
|
||||
{
|
||||
int pid = GameClient.Get().GetPlayerID();
|
||||
int px = x;
|
||||
if ((pid % 2) == 1)
|
||||
px = Slot.x_max - x + Slot.x_min; //Flip X coordinate if not the first player
|
||||
return new Slot(px, y, p);
|
||||
}
|
||||
|
||||
if (type == BoardSlotType.FlipY)
|
||||
{
|
||||
int pid = GameClient.Get().GetPlayerID();
|
||||
int py = y;
|
||||
if ((pid % 2) == 1)
|
||||
py = Slot.y_max - y + Slot.y_min; //Flip Y coordinate if not the first player
|
||||
return new Slot(x, py, p);
|
||||
}
|
||||
|
||||
if (type == BoardSlotType.PlayerSelf)
|
||||
p = GameClient.Get().GetPlayerID();
|
||||
if(type == BoardSlotType.PlayerOpponent)
|
||||
p = GameClient.Get().GetOpponentPlayerID();
|
||||
|
||||
return new Slot(x, y, p);
|
||||
}
|
||||
|
||||
//When clicking on the slot
|
||||
public void OnMouseDown()
|
||||
{
|
||||
if (GameUI.IsOverUI())
|
||||
return;
|
||||
|
||||
Game gdata = GameClient.Get().GetGameData();
|
||||
int player_id = GameClient.Get().GetPlayerID();
|
||||
|
||||
if (gdata.selector == SelectorType.SelectTarget && player_id == gdata.selector_player_id)
|
||||
{
|
||||
Slot slot = GetSlot();
|
||||
Card slot_card = gdata.GetSlotCard(slot);
|
||||
if (slot_card == null)
|
||||
{
|
||||
GameClient.Get().SelectSlot(slot);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
11
Assets/TcgEngine/Scripts/GameClient/BoardSlot.cs.meta
Normal file
11
Assets/TcgEngine/Scripts/GameClient/BoardSlot.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d054438193103c8408c5eedfc485482d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
278
Assets/TcgEngine/Scripts/GameClient/BoardSlotGroup.cs
Normal file
278
Assets/TcgEngine/Scripts/GameClient/BoardSlotGroup.cs
Normal file
@@ -0,0 +1,278 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using TcgEngine.Client;
|
||||
using TcgEngine.UI;
|
||||
|
||||
namespace TcgEngine.Client
|
||||
{
|
||||
/// <summary>
|
||||
/// Visual representation of a Slot.cs that position cards automatically
|
||||
/// </summary>
|
||||
|
||||
public class BoardSlotGroup : BSlot
|
||||
{
|
||||
public BoardSlotType type;
|
||||
public int min_x = 1;
|
||||
public int max_x = 5;
|
||||
public int y = 1;
|
||||
|
||||
public float spacing = 2.5f;
|
||||
public float reduce_delay = 1f;
|
||||
|
||||
private int nb_occupied = 0;
|
||||
|
||||
private List<GroupSlot> group_slots = new List<GroupSlot>();
|
||||
|
||||
protected override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
}
|
||||
|
||||
protected override void OnDestroy()
|
||||
{
|
||||
base.OnDestroy();
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
if (min_x < Slot.x_min || max_x > Slot.x_max || y < Slot.y_min || y > Slot.y_max)
|
||||
Debug.LogError("Board Slot X and Y value must be within the min and max set for those values, check Slot.cs script to change those min/max.");
|
||||
|
||||
GameClient.Get().onConnectGame += OnConnect;
|
||||
|
||||
nb_occupied = 0;
|
||||
collide.enabled = false;
|
||||
}
|
||||
|
||||
private void OnConnect()
|
||||
{
|
||||
foreach (Slot slot in Slot.GetAll())
|
||||
{
|
||||
if (IsInGroup(slot))
|
||||
{
|
||||
GroupSlot pos = new GroupSlot();
|
||||
pos.slot = slot;
|
||||
pos.pos = transform.position;
|
||||
group_slots.Add(pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
if (!GameClient.Get().IsReady())
|
||||
return;
|
||||
|
||||
Game gdata = GameClient.Get().GetGameData();
|
||||
HandCard drag_card = HandCard.GetDrag();
|
||||
bool your_turn = GameClient.Get().IsYourTurn();
|
||||
Card dcard = drag_card?.GetCard();
|
||||
|
||||
//Find target opacity value
|
||||
target_alpha = 0f;
|
||||
if (your_turn && dcard != null && dcard.CardData.IsBoardCard())
|
||||
{
|
||||
foreach (GroupSlot slot in group_slots)
|
||||
{
|
||||
if(gdata.CanPlayCard(dcard, slot.slot))
|
||||
target_alpha = 1f; //hightlight when dragging a character or artifact
|
||||
}
|
||||
}
|
||||
|
||||
UpdateOccupied();
|
||||
UpdatePositions();
|
||||
}
|
||||
|
||||
public void UpdateOccupied()
|
||||
{
|
||||
int count = 0;
|
||||
Game gdata = GameClient.Get().GetGameData();
|
||||
|
||||
foreach (GroupSlot slot in group_slots)
|
||||
{
|
||||
Card card = gdata.GetSlotCard(slot.slot);
|
||||
slot.timer += (card != null ? 1f : -1f) * Time.deltaTime / reduce_delay;
|
||||
slot.timer = Mathf.Clamp01(slot.timer);
|
||||
|
||||
if (slot.IsOccupied)
|
||||
count += 1;
|
||||
}
|
||||
|
||||
nb_occupied = count;
|
||||
}
|
||||
|
||||
public void UpdatePositions()
|
||||
{
|
||||
bool even = nb_occupied % 2 == 0;
|
||||
float offset = (nb_occupied / 2) * -spacing;
|
||||
if (even)
|
||||
offset += spacing * 0.5f;
|
||||
|
||||
int index = 0;
|
||||
foreach (GroupSlot slot in group_slots)
|
||||
{
|
||||
if (slot.IsOccupied)
|
||||
{
|
||||
slot.pos = transform.position + Vector3.right * (index * spacing + offset);
|
||||
index++;
|
||||
}
|
||||
else
|
||||
{
|
||||
slot.pos = transform.position + Vector3.right * (nb_occupied * spacing + offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsInGroup(Slot slot)
|
||||
{
|
||||
return IsInGroup(slot.x, slot.y, slot.p);
|
||||
}
|
||||
|
||||
public bool IsInGroup(int x, int y)
|
||||
{
|
||||
Slot min = GetSlotMin();
|
||||
Slot max = GetSlotMax();
|
||||
return x >= min.x && x <= max.x && y >= min.y && y <= max.y;
|
||||
}
|
||||
|
||||
public bool IsInGroup(int x, int y, int p)
|
||||
{
|
||||
Slot min = GetSlotMin();
|
||||
Slot max = GetSlotMax();
|
||||
return x >= min.x && x <= max.x && y >= min.y && y <= max.y && p >= min.p && p <= max.p;
|
||||
}
|
||||
|
||||
public Slot GetSlotMin()
|
||||
{
|
||||
return GetSlot(min_x, y);
|
||||
}
|
||||
|
||||
public Slot GetSlotMax()
|
||||
{
|
||||
return GetSlot(max_x, y);
|
||||
}
|
||||
|
||||
//Find the actual slot coordinates of this board slot
|
||||
public Slot GetSlot(int x, int y)
|
||||
{
|
||||
int p = 0;
|
||||
|
||||
if (type == BoardSlotType.FlipX)
|
||||
{
|
||||
int pid = GameClient.Get().GetPlayerID();
|
||||
int px = x;
|
||||
if ((pid % 2) == 1)
|
||||
px = Slot.x_max - x + Slot.x_min; //Flip X coordinate if not the first player
|
||||
return new Slot(px, y, p);
|
||||
}
|
||||
|
||||
if (type == BoardSlotType.FlipY)
|
||||
{
|
||||
int pid = GameClient.Get().GetPlayerID();
|
||||
int py = y;
|
||||
if ((pid % 2) == 1)
|
||||
py = Slot.y_max - y + Slot.y_min; //Flip Y coordinate if not the first player
|
||||
return new Slot(x, py, p);
|
||||
}
|
||||
|
||||
if (type == BoardSlotType.PlayerSelf)
|
||||
p = GameClient.Get().GetPlayerID();
|
||||
if(type == BoardSlotType.PlayerOpponent)
|
||||
p = GameClient.Get().GetOpponentPlayerID();
|
||||
|
||||
return new Slot(x, y, p);
|
||||
}
|
||||
|
||||
public override Slot GetSlot(Vector3 wpos)
|
||||
{
|
||||
GroupSlot nearest = null;
|
||||
float min_dist = 99f;
|
||||
|
||||
foreach (GroupSlot spos in group_slots)
|
||||
{
|
||||
float dist = (spos.pos - wpos).magnitude;
|
||||
if (dist < min_dist)
|
||||
{
|
||||
min_dist = dist;
|
||||
nearest = spos;
|
||||
}
|
||||
}
|
||||
|
||||
if (nearest != null)
|
||||
return nearest.slot;
|
||||
return Slot.None;
|
||||
}
|
||||
|
||||
public virtual Slot GetSlotOccupied(Vector3 wpos)
|
||||
{
|
||||
GroupSlot nearest = null;
|
||||
float min_dist = 99f;
|
||||
|
||||
foreach (GroupSlot spos in group_slots)
|
||||
{
|
||||
float dist = (spos.pos - wpos).magnitude;
|
||||
if (spos.IsOccupied && dist < min_dist)
|
||||
{
|
||||
min_dist = dist;
|
||||
nearest = spos;
|
||||
}
|
||||
}
|
||||
|
||||
if (nearest != null)
|
||||
return nearest.slot;
|
||||
return Slot.None;
|
||||
}
|
||||
|
||||
public override Card GetSlotCard(Vector3 wpos)
|
||||
{
|
||||
Game gdata = GameClient.Get().GetGameData();
|
||||
Slot slot = GetSlotOccupied(wpos);
|
||||
if (slot != Slot.None)
|
||||
return gdata.GetSlotCard(slot);
|
||||
return null;
|
||||
}
|
||||
|
||||
public override bool HasSlot(Slot slot)
|
||||
{
|
||||
foreach (GroupSlot spos in group_slots)
|
||||
{
|
||||
if (spos.slot == slot)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public override Vector3 GetPosition(Slot slot)
|
||||
{
|
||||
foreach (GroupSlot spos in group_slots)
|
||||
{
|
||||
if (spos.slot == slot)
|
||||
return spos.pos;
|
||||
}
|
||||
return transform.position;
|
||||
}
|
||||
|
||||
public override Slot GetEmptySlot(Vector3 wpos)
|
||||
{
|
||||
foreach (GroupSlot slot in group_slots)
|
||||
{
|
||||
if (!slot.IsOccupied)
|
||||
return slot.slot;
|
||||
}
|
||||
return Slot.None;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class GroupSlot
|
||||
{
|
||||
public Slot slot;
|
||||
public Vector3 pos;
|
||||
public float timer;
|
||||
|
||||
public bool IsOccupied { get { return timer > 0.01f; } }
|
||||
}
|
||||
}
|
||||
11
Assets/TcgEngine/Scripts/GameClient/BoardSlotGroup.cs.meta
Normal file
11
Assets/TcgEngine/Scripts/GameClient/BoardSlotGroup.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 81e500df2cf1ead4b997a8f5b582063d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
198
Assets/TcgEngine/Scripts/GameClient/BoardSlotPlayer.cs
Normal file
198
Assets/TcgEngine/Scripts/GameClient/BoardSlotPlayer.cs
Normal file
@@ -0,0 +1,198 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using TcgEngine.UI;
|
||||
using TcgEngine.FX;
|
||||
|
||||
namespace TcgEngine.Client
|
||||
{
|
||||
/// <summary>
|
||||
/// Visual zone that can be attacked by opponent's card to damage the player HP
|
||||
/// </summary>
|
||||
|
||||
public class BoardSlotPlayer : BSlot
|
||||
{
|
||||
public bool opponent;
|
||||
|
||||
public float range_x = 3f;
|
||||
public float range_y = 1f;
|
||||
|
||||
private static BoardSlotPlayer instance_self;
|
||||
private static BoardSlotPlayer instance_other;
|
||||
|
||||
private static List<BoardSlotPlayer> zone_list = new List<BoardSlotPlayer>();
|
||||
|
||||
protected override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
zone_list.Add(this);
|
||||
if (opponent)
|
||||
instance_other = this;
|
||||
else
|
||||
instance_self = this;
|
||||
}
|
||||
|
||||
protected override void OnDestroy()
|
||||
{
|
||||
base.OnDestroy();
|
||||
zone_list.Remove(this);
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
GameClient.Get().onPlayerDamaged += OnPlayerDamaged;
|
||||
GameClient.Get().onAbilityStart += OnAbilityStart;
|
||||
GameClient.Get().onAbilityTargetPlayer += OnAbilityEffect;
|
||||
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
if (!GameClient.Get().IsReady())
|
||||
return;
|
||||
|
||||
if (!opponent)
|
||||
return;
|
||||
|
||||
//int player_id = opponent ? GameClient.Get().GetOpponentPlayerID() : GameClient.Get().GetPlayerID();
|
||||
BoardCard bcard_selected = PlayerControls.Get().GetSelected();
|
||||
HandCard drag_card = HandCard.GetDrag();
|
||||
bool your_turn = GameClient.Get().IsYourTurn();
|
||||
|
||||
Game gdata = GameClient.Get().GetGameData();
|
||||
Player player = GameClient.Get().GetPlayer();
|
||||
Player oplayer = GameClient.Get().GetOpponentPlayer();
|
||||
|
||||
target_alpha = 0f;
|
||||
Card select_card = bcard_selected?.GetCard();
|
||||
if (select_card != null)
|
||||
{
|
||||
bool can_do_attack = gdata.IsPlayerActionTurn(player) && select_card.CanAttack();
|
||||
bool can_be_attacked = gdata.CanAttackTarget(select_card, oplayer);
|
||||
|
||||
if (can_do_attack && can_be_attacked)
|
||||
{
|
||||
target_alpha = 1f;
|
||||
}
|
||||
}
|
||||
|
||||
if (your_turn && drag_card != null && drag_card.CardData.IsRequireTargetSpell() && gdata.IsPlayTargetValid(drag_card.GetCard(), GetPlayer()))
|
||||
{
|
||||
target_alpha = 1f; //Highlight when dragin a spell with target
|
||||
}
|
||||
|
||||
if (gdata.selector == SelectorType.SelectTarget && player.player_id == gdata.selector_player_id)
|
||||
{
|
||||
Card caster = gdata.GetCard(gdata.selector_caster_uid);
|
||||
AbilityData ability = AbilityData.Get(gdata.selector_ability_id);
|
||||
if (ability != null && ability.AreTargetConditionsMet(gdata, caster, GetPlayer()))
|
||||
target_alpha = 1f; //Highlight when selecting a target and empty slots are valid
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void OnAbilityStart(AbilityData iability, Card caster)
|
||||
{
|
||||
if (iability != null && caster != null)
|
||||
{
|
||||
int player_id = opponent ? GameClient.Get().GetOpponentPlayerID() : GameClient.Get().GetPlayerID();
|
||||
if (caster.CardData.type == CardType.Spell && caster.player_id == player_id)
|
||||
{
|
||||
FXTool.DoFX(iability.caster_fx, transform.position);
|
||||
AudioTool.Get().PlaySFX("fx", iability.cast_audio);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnAbilityEffect(AbilityData iability, Card caster, Player target)
|
||||
{
|
||||
if (iability != null && caster != null && target != null)
|
||||
{
|
||||
int player_id = opponent ? GameClient.Get().GetOpponentPlayerID() : GameClient.Get().GetPlayerID();
|
||||
if (target.player_id == player_id)
|
||||
{
|
||||
FXTool.DoFX(iability.target_fx, transform.position);
|
||||
FXTool.DoProjectileFX(iability.projectile_fx, GetFXSource(caster), transform, iability.GetDamage());
|
||||
AudioTool.Get().PlaySFX("fx", iability.target_audio);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnPlayerDamaged(Player target, int damage)
|
||||
{
|
||||
if (GetPlayerID() == target.player_id && damage > 0)
|
||||
{
|
||||
DamageFX(transform, damage);
|
||||
}
|
||||
}
|
||||
|
||||
private void DamageFX(Transform target, int value, float delay = 0.5f)
|
||||
{
|
||||
TimeTool.WaitFor(delay, () =>
|
||||
{
|
||||
GameObject fx = FXTool.DoFX(AssetData.Get().damage_fx, target.position);
|
||||
fx.GetComponent<DamageFX>().SetValue(value);
|
||||
});
|
||||
}
|
||||
|
||||
private Transform GetFXSource(Card caster)
|
||||
{
|
||||
if (caster.CardData.IsBoardCard())
|
||||
{
|
||||
BoardCard bcard = BoardCard.Get(caster.uid);
|
||||
if (bcard != null)
|
||||
return bcard.transform;
|
||||
}
|
||||
else
|
||||
{
|
||||
BoardSlotPlayer slot = BoardSlotPlayer.Get(caster.player_id);
|
||||
if (slot != null)
|
||||
return slot.transform;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void OnMouseDown()
|
||||
{
|
||||
if (GameUI.IsUIOpened() || GameUI.IsOverUILayer("UI"))
|
||||
return;
|
||||
|
||||
Game gdata = GameClient.Get().GetGameData();
|
||||
int player_id = GameClient.Get().GetPlayerID();
|
||||
if (gdata.selector == SelectorType.SelectTarget && player_id == gdata.selector_player_id)
|
||||
{
|
||||
GameClient.Get().SelectPlayer(GetPlayer());
|
||||
}
|
||||
}
|
||||
|
||||
public int GetPlayerID()
|
||||
{
|
||||
return opponent ? GameClient.Get().GetOpponentPlayerID() : GameClient.Get().GetPlayerID();
|
||||
}
|
||||
|
||||
public override Player GetPlayer()
|
||||
{
|
||||
return opponent ? GameClient.Get().GetOpponentPlayer() : GameClient.Get().GetPlayer();
|
||||
}
|
||||
|
||||
public override Slot GetSlot()
|
||||
{
|
||||
return new Slot(GetPlayerID());
|
||||
}
|
||||
|
||||
public static BoardSlotPlayer Get(bool opponent)
|
||||
{
|
||||
if(opponent)
|
||||
return instance_other;
|
||||
return instance_self;
|
||||
}
|
||||
|
||||
public static BoardSlotPlayer Get(int player_id)
|
||||
{
|
||||
bool opponent = player_id != GameClient.Get().GetPlayerID();
|
||||
return Get(opponent);
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/TcgEngine/Scripts/GameClient/BoardSlotPlayer.cs.meta
Normal file
11
Assets/TcgEngine/Scripts/GameClient/BoardSlotPlayer.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4c1429011d3d53046b30acf29b7dbb24
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
165
Assets/TcgEngine/Scripts/GameClient/GameBoard.cs
Normal file
165
Assets/TcgEngine/Scripts/GameClient/GameBoard.cs
Normal file
@@ -0,0 +1,165 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using TcgEngine.Client;
|
||||
using UnityEngine.Events;
|
||||
using TcgEngine.UI;
|
||||
|
||||
namespace TcgEngine.Client
|
||||
{
|
||||
/// <summary>
|
||||
/// GameBoard takes care of spawning and despawning BoardCards, based on the refreshed data received from the server
|
||||
/// It also ends the game when the server sends a endgame
|
||||
/// </summary>
|
||||
|
||||
public class GameBoard : MonoBehaviour
|
||||
{
|
||||
public GameObject card_prefab;
|
||||
|
||||
public UnityAction<Card> onCardSpawned;
|
||||
public UnityAction<Card> onCardKilled;
|
||||
|
||||
private bool game_ended = false;
|
||||
|
||||
private static GameBoard _instance;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
_instance = this;
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
if (!GameClient.Get().IsReady())
|
||||
return;
|
||||
|
||||
Game data = GameClient.Get().GetGameData();
|
||||
|
||||
//--- Board cards --------
|
||||
|
||||
List<BoardCard> cards = BoardCard.GetAll();
|
||||
|
||||
//Add new cards
|
||||
foreach (Player p in data.players)
|
||||
{
|
||||
foreach (Card card in p.cards_board)
|
||||
{
|
||||
BoardCard bcard = BoardCard.Get(card.uid);
|
||||
if (card != null && bcard == null)
|
||||
{
|
||||
SpawnNewCard(card);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Remove cards
|
||||
for (int i = cards.Count - 1; i >= 0; i--)
|
||||
{
|
||||
BoardCard bcard = cards[i];
|
||||
if (bcard != null && HasBoardCard(bcard) &&!bcard.IsDamagedDelayed())
|
||||
{
|
||||
KillCard(bcard);
|
||||
}
|
||||
}
|
||||
|
||||
//--- End Game ----
|
||||
if (!game_ended && data.state == GameState.GameEnded)
|
||||
{
|
||||
game_ended = true;
|
||||
EndGame();
|
||||
}
|
||||
}
|
||||
|
||||
private void SpawnNewCard(Card card)
|
||||
{
|
||||
GameObject card_obj = Instantiate(card_prefab, Vector3.zero, Quaternion.identity);
|
||||
card_obj.SetActive(true);
|
||||
card_obj.GetComponent<BoardCard>().SetCard(card);
|
||||
onCardSpawned?.Invoke(card);
|
||||
}
|
||||
|
||||
private void KillCard(BoardCard card)
|
||||
{
|
||||
card.Destroy();
|
||||
onCardKilled?.Invoke(card.GetCard());
|
||||
}
|
||||
|
||||
private bool HasBoardCard(BoardCard bcard)
|
||||
{
|
||||
Game data = GameClient.Get().GetGameData();
|
||||
Card card = data.GetBoardCard(bcard.GetCardUID());
|
||||
return card == null && !bcard.IsDead();
|
||||
}
|
||||
|
||||
public void EndGame()
|
||||
{
|
||||
StartCoroutine(EndGameRun());
|
||||
}
|
||||
|
||||
private IEnumerator EndGameRun()
|
||||
{
|
||||
Game data = GameClient.Get().GetGameData();
|
||||
Player pwinner = data.GetPlayer(data.current_player);
|
||||
Player player = GameClient.Get().GetPlayer();
|
||||
bool win = pwinner != null && player.player_id == pwinner.player_id;
|
||||
bool tied = pwinner == null;
|
||||
|
||||
AudioTool.Get().FadeOutMusic("music");
|
||||
|
||||
yield return new WaitForSeconds(1f);
|
||||
|
||||
if (win)
|
||||
PlayerUI.Get(true).Kill();
|
||||
if (!win && !tied)
|
||||
PlayerUI.Get(false).Kill();
|
||||
|
||||
if (win && AssetData.Get().win_fx != null)
|
||||
Instantiate(AssetData.Get().win_fx, Vector3.zero, Quaternion.identity);
|
||||
else if (tied && AssetData.Get().tied_fx != null)
|
||||
Instantiate(AssetData.Get().tied_fx, Vector3.zero, Quaternion.identity);
|
||||
else if (tied && AssetData.Get().lose_fx != null)
|
||||
Instantiate(AssetData.Get().lose_fx, Vector3.zero, Quaternion.identity);
|
||||
|
||||
if (win)
|
||||
AudioTool.Get().PlaySFX("ending_sfx", AssetData.Get().win_audio);
|
||||
else
|
||||
AudioTool.Get().PlaySFX("ending_sfx", AssetData.Get().defeat_audio);
|
||||
|
||||
if (win)
|
||||
AudioTool.Get().PlayMusic("music", AssetData.Get().win_music, 0.4f, false);
|
||||
else
|
||||
AudioTool.Get().PlayMusic("music", AssetData.Get().defeat_music, 0.4f, false);
|
||||
|
||||
yield return new WaitForSeconds(2f);
|
||||
|
||||
|
||||
EndGamePanel.Get().ShowEnd(data.current_player);
|
||||
}
|
||||
|
||||
//Raycast mouse position to board position
|
||||
public Vector3 RaycastMouseBoard()
|
||||
{
|
||||
Ray ray = GameCamera.Get().MouseToRay(Input.mousePosition);
|
||||
Plane plane = new Plane(transform.forward, 0f);
|
||||
bool success = plane.Raycast(ray, out float dist);
|
||||
if (success)
|
||||
return ray.GetPoint(dist);
|
||||
return Vector3.zero;
|
||||
}
|
||||
|
||||
public Vector3 GetAngles()
|
||||
{
|
||||
return transform.rotation.eulerAngles;
|
||||
}
|
||||
|
||||
public static GameBoard Get()
|
||||
{
|
||||
return _instance;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/TcgEngine/Scripts/GameClient/GameBoard.cs.meta
Normal file
11
Assets/TcgEngine/Scripts/GameClient/GameBoard.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0af8ce7f0f0acf4408922e1c9fe6d764
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
81
Assets/TcgEngine/Scripts/GameClient/GameCamera.cs
Normal file
81
Assets/TcgEngine/Scripts/GameClient/GameCamera.cs
Normal file
@@ -0,0 +1,81 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace TcgEngine.Client
|
||||
{
|
||||
/// <summary>
|
||||
/// Game Camera has some useful features such as shake
|
||||
/// Or raycasting the mouse to a world/screen position
|
||||
/// </summary>
|
||||
|
||||
public class GameCamera : MonoBehaviour
|
||||
{
|
||||
private float shake_timer = 0f;
|
||||
private float shake_intensity = 1f;
|
||||
|
||||
private Camera cam;
|
||||
private Vector3 shake_vector = Vector3.zero;
|
||||
private Vector3 start_pos;
|
||||
|
||||
private static GameCamera instance;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
instance = this;
|
||||
start_pos = transform.position;
|
||||
cam = GetComponent<Camera>();
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
//Shake FX
|
||||
if (shake_timer > 0f)
|
||||
{
|
||||
shake_timer -= Time.deltaTime;
|
||||
shake_vector = new Vector3(Mathf.Cos(shake_timer * Mathf.PI * 16f) * 0.02f, Mathf.Sin(shake_timer * Mathf.PI * 12f) * 0.01f, 0f);
|
||||
transform.position = start_pos + shake_vector * shake_intensity;
|
||||
}
|
||||
else
|
||||
{
|
||||
transform.position = start_pos;
|
||||
}
|
||||
}
|
||||
|
||||
public void Shake(float intensity = 1f, float duration = 1f)
|
||||
{
|
||||
shake_intensity = intensity;
|
||||
shake_timer = duration;
|
||||
}
|
||||
|
||||
public Vector2 MouseToPercent(Vector3 mouse_pos)
|
||||
{
|
||||
float x = mouse_pos.x / Screen.width;
|
||||
float y = mouse_pos.y / Screen.height;
|
||||
return new Vector2(x, y);
|
||||
}
|
||||
|
||||
public Ray MouseToRay(Vector3 mouse_pos)
|
||||
{
|
||||
return cam.ScreenPointToRay(mouse_pos);
|
||||
}
|
||||
|
||||
public Vector3 MouseToWorld(Vector2 mouse_pos, float distance = 10f)
|
||||
{
|
||||
Vector3 wpos = cam.ScreenToWorldPoint(new Vector3(mouse_pos.x, mouse_pos.y, distance));
|
||||
return wpos;
|
||||
}
|
||||
|
||||
public static Camera GetCamera()
|
||||
{
|
||||
if (instance != null)
|
||||
return instance.cam;
|
||||
return null;
|
||||
}
|
||||
|
||||
public static GameCamera Get()
|
||||
{
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/TcgEngine/Scripts/GameClient/GameCamera.cs.meta
Normal file
11
Assets/TcgEngine/Scripts/GameClient/GameCamera.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3a9b8c2d7c7896346a760f2d221a1d59
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
747
Assets/TcgEngine/Scripts/GameClient/GameClient.cs
Normal file
747
Assets/TcgEngine/Scripts/GameClient/GameClient.cs
Normal file
@@ -0,0 +1,747 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
using Unity.Netcode;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace TcgEngine.Client
|
||||
{
|
||||
/// <summary>
|
||||
/// Main script for the client-side of the game, should be in game scene only
|
||||
/// Will connect to server, then connect to the game on that server (with uid) and then will send game settings
|
||||
/// During the game, will send all actions performed by the player and receive game refreshes
|
||||
/// </summary>
|
||||
|
||||
public class GameClient : MonoBehaviour
|
||||
{
|
||||
//--- These settings are set in the menu scene and when the game start will be sent to server
|
||||
|
||||
public static GameSettings game_settings = GameSettings.Default;
|
||||
public static PlayerSettings player_settings = PlayerSettings.Default;
|
||||
public static PlayerSettings ai_settings = PlayerSettings.DefaultAI;
|
||||
public static string observe_user = null; //Which user should it observe, null if not an obs
|
||||
|
||||
//-----
|
||||
|
||||
public UnityAction onConnectServer;
|
||||
public UnityAction onConnectGame;
|
||||
public UnityAction<int> onPlayerReady;
|
||||
|
||||
public UnityAction onGameStart;
|
||||
public UnityAction<int> onGameEnd; //winner player_id
|
||||
public UnityAction<int> onNewTurn; //current player_id
|
||||
|
||||
public UnityAction<Card, Slot> onCardPlayed;
|
||||
public UnityAction<Card, Slot> onCardMoved;
|
||||
public UnityAction<Slot> onCardSummoned;
|
||||
public UnityAction<Card> onCardTransformed;
|
||||
public UnityAction<Card> onCardDiscarded;
|
||||
public UnityAction<int> onCardDraw;
|
||||
public UnityAction<int> onValueRolled;
|
||||
|
||||
public UnityAction<AbilityData, Card> onAbilityStart;
|
||||
public UnityAction<AbilityData, Card, Card> onAbilityTargetCard; //Ability, Caster, Target
|
||||
public UnityAction<AbilityData, Card, Player> onAbilityTargetPlayer;
|
||||
public UnityAction<AbilityData, Card, Slot> onAbilityTargetSlot;
|
||||
public UnityAction<AbilityData, Card> onAbilityEnd;
|
||||
public UnityAction<Card, Card> onSecretTrigger; //Secret, Triggerer
|
||||
public UnityAction<Card, Card> onSecretResolve; //Secret, Triggerer
|
||||
|
||||
public UnityAction<Card, Card> onAttackStart; //Attacker, Defender
|
||||
public UnityAction<Card, Card> onAttackEnd; //Attacker, Defender
|
||||
public UnityAction<Card, Player> onAttackPlayerStart;
|
||||
public UnityAction<Card, Player> onAttackPlayerEnd;
|
||||
|
||||
public UnityAction<Card, int> onCardDamaged;
|
||||
public UnityAction<Player, int> onPlayerDamaged;
|
||||
public UnityAction<Card, int> onCardHealed;
|
||||
public UnityAction<Player, int> onPlayerHealed;
|
||||
|
||||
public UnityAction<int, string> onChatMsg; //player_id, msg
|
||||
public UnityAction< string> onServerMsg; //msg
|
||||
public UnityAction onRefreshAll;
|
||||
|
||||
private int player_id = 0; //Player playing on this device;
|
||||
private Game game_data;
|
||||
|
||||
private bool observe_mode = false;
|
||||
private int observe_player_id = 0;
|
||||
private float timer = 0f;
|
||||
|
||||
|
||||
private Dictionary<ushort, RefreshEvent> registered_commands = new Dictionary<ushort, RefreshEvent>();
|
||||
|
||||
private static GameClient instance;
|
||||
|
||||
protected virtual void Awake()
|
||||
{
|
||||
instance = this;
|
||||
Application.targetFrameRate = 120;
|
||||
}
|
||||
|
||||
protected virtual void Start()
|
||||
{
|
||||
RegisterRefresh(GameAction.Connected, OnConnectedToGame);
|
||||
RegisterRefresh(GameAction.PlayerReady, OnPlayerReady);
|
||||
RegisterRefresh(GameAction.GameStart, OnGameStart);
|
||||
RegisterRefresh(GameAction.GameEnd, OnGameEnd);
|
||||
RegisterRefresh(GameAction.NewTurn, OnNewTurn);
|
||||
RegisterRefresh(GameAction.CardPlayed, OnCardPlayed);
|
||||
RegisterRefresh(GameAction.CardMoved, OnCardMoved);
|
||||
RegisterRefresh(GameAction.CardSummoned, OnCardSummoned);
|
||||
RegisterRefresh(GameAction.CardTransformed, OnCardTransformed);
|
||||
RegisterRefresh(GameAction.CardDiscarded, OnCardDiscarded);
|
||||
RegisterRefresh(GameAction.CardDrawn, OnCardDraw);
|
||||
RegisterRefresh(GameAction.ValueRolled, OnValueRolled);
|
||||
|
||||
RegisterRefresh(GameAction.AttackStart, OnAttackStart);
|
||||
RegisterRefresh(GameAction.AttackEnd, OnAttackEnd);
|
||||
RegisterRefresh(GameAction.AttackPlayerStart, OnAttackPlayerStart);
|
||||
RegisterRefresh(GameAction.AttackPlayerEnd, OnAttackPlayerEnd);
|
||||
RegisterRefresh(GameAction.CardDamaged, OnCardDamaged);
|
||||
RegisterRefresh(GameAction.PlayerDamaged, OnPlayerDamaged);
|
||||
RegisterRefresh(GameAction.CardHealed, OnCardHealed);
|
||||
RegisterRefresh(GameAction.PlayerHealed, OnPlayerHealed);
|
||||
|
||||
RegisterRefresh(GameAction.AbilityTrigger, OnAbilityTrigger);
|
||||
RegisterRefresh(GameAction.AbilityTargetCard, OnAbilityTargetCard);
|
||||
RegisterRefresh(GameAction.AbilityTargetPlayer, OnAbilityTargetPlayer);
|
||||
RegisterRefresh(GameAction.AbilityTargetSlot, OnAbilityTargetSlot);
|
||||
RegisterRefresh(GameAction.AbilityEnd, OnAbilityAfter);
|
||||
|
||||
RegisterRefresh(GameAction.SecretTriggered, OnSecretTrigger);
|
||||
RegisterRefresh(GameAction.SecretResolved, OnSecretResolve);
|
||||
|
||||
RegisterRefresh(GameAction.ChatMessage, OnChat);
|
||||
RegisterRefresh(GameAction.ServerMessage, OnServerMsg);
|
||||
RegisterRefresh(GameAction.RefreshAll, OnRefreshAll);
|
||||
|
||||
TcgNetwork.Get().onConnect += OnConnectedServer;
|
||||
TcgNetwork.Get().Messaging.ListenMsg("refresh", OnReceiveRefresh);
|
||||
|
||||
ConnectToAPI();
|
||||
ConnectToServer();
|
||||
}
|
||||
|
||||
protected virtual void OnDestroy()
|
||||
{
|
||||
TcgNetwork.Get().onConnect -= OnConnectedServer;
|
||||
TcgNetwork.Get().Messaging.UnListenMsg("refresh");
|
||||
}
|
||||
|
||||
protected virtual void Update()
|
||||
{
|
||||
bool is_starting = game_data == null || game_data.state == GameState.Connecting;
|
||||
bool is_client = !game_settings.IsHost();
|
||||
bool is_connecting = TcgNetwork.Get().IsConnecting();
|
||||
bool is_connected = TcgNetwork.Get().IsConnected();
|
||||
|
||||
//Exit game scene if cannot connect after a while
|
||||
if (is_starting && is_client)
|
||||
{
|
||||
timer += Time.deltaTime;
|
||||
if (timer > 10f)
|
||||
{
|
||||
SceneNav.GoTo("Menu");
|
||||
}
|
||||
}
|
||||
|
||||
//Reconnect to server
|
||||
if (!is_starting && !is_connecting && is_client && !is_connected)
|
||||
{
|
||||
timer += Time.deltaTime;
|
||||
if (timer > 5f)
|
||||
{
|
||||
timer = 0f;
|
||||
ConnectToServer();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------
|
||||
|
||||
public virtual void ConnectToAPI()
|
||||
{
|
||||
//Should already be logged in from the menu
|
||||
//If not connected, start in test mode (this means game scene was launched directly from Unity)
|
||||
if (!Authenticator.Get().IsSignedIn())
|
||||
{
|
||||
Authenticator.Get().LoginTest("Player");
|
||||
|
||||
if (!player_settings.HasDeck())
|
||||
{
|
||||
player_settings.deck = new UserDeckData(GameplayData.Get().test_deck);
|
||||
}
|
||||
|
||||
if (!ai_settings.HasDeck())
|
||||
{
|
||||
ai_settings.deck = new UserDeckData(GameplayData.Get().test_deck_ai);
|
||||
ai_settings.ai_level = GameplayData.Get().ai_level;
|
||||
}
|
||||
}
|
||||
|
||||
//Set avatar, cardback based on your api data
|
||||
UserData udata = Authenticator.Get().UserData;
|
||||
if (udata != null)
|
||||
{
|
||||
player_settings.avatar = udata.GetAvatar();
|
||||
player_settings.cardback = udata.GetCardback();
|
||||
}
|
||||
}
|
||||
|
||||
public virtual async void ConnectToServer()
|
||||
{
|
||||
await TimeTool.Delay(100); //Wait for initialization to finish
|
||||
|
||||
if (TcgNetwork.Get().IsActive())
|
||||
return; // Already connected
|
||||
|
||||
if (game_settings.IsHost() && NetworkData.Get().solo_type == SoloType.Offline)
|
||||
{
|
||||
TcgNetwork.Get().StartHostOffline(); //WebGL dont support hosting a game, must join a dedicated server, in solo it starts a offline mode that doesn't use netcode at all
|
||||
}
|
||||
else if (game_settings.IsHost())
|
||||
{
|
||||
TcgNetwork.Get().StartHost(NetworkData.Get().port); //Host a game, either solo or for P2P, still using netcode in solo to have consistant behavior when testing solo vs multi
|
||||
}
|
||||
else
|
||||
{
|
||||
TcgNetwork.Get().StartClient(game_settings.GetUrl(), NetworkData.Get().port); //Join server
|
||||
}
|
||||
}
|
||||
|
||||
public virtual async void ConnectToGame(string uid)
|
||||
{
|
||||
await TimeTool.Delay(100); //Wait for initialization to finish
|
||||
|
||||
if (!TcgNetwork.Get().IsActive())
|
||||
return; //Not connected to server
|
||||
|
||||
Debug.Log("Connect to Game: " + uid);
|
||||
|
||||
MsgPlayerConnect nplayer = new MsgPlayerConnect();
|
||||
nplayer.user_id = Authenticator.Get().UserID;
|
||||
nplayer.username = Authenticator.Get().Username;
|
||||
nplayer.game_uid = uid;
|
||||
nplayer.nb_players = game_settings.nb_players;
|
||||
nplayer.observer = game_settings.game_type == GameType.Observer;
|
||||
|
||||
Messaging.SendObject("connect", ServerID, nplayer, NetworkDelivery.Reliable);
|
||||
}
|
||||
|
||||
public virtual void SendGameSettings()
|
||||
{
|
||||
if (game_settings.IsOffline())
|
||||
{
|
||||
//Solo mode, send both your settings and AI settings
|
||||
SendGameplaySettings(game_settings);
|
||||
SendPlayerSettingsAI(ai_settings);
|
||||
SendPlayerSettings(player_settings);
|
||||
}
|
||||
else
|
||||
{
|
||||
//Online mode, only send your own settings
|
||||
SendGameplaySettings(game_settings);
|
||||
SendPlayerSettings(player_settings);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void Disconnect()
|
||||
{
|
||||
TcgNetwork.Get().Disconnect();
|
||||
}
|
||||
|
||||
private void RegisterRefresh(ushort tag, UnityAction<SerializedData> callback)
|
||||
{
|
||||
RefreshEvent cmdevt = new RefreshEvent();
|
||||
cmdevt.tag = tag;
|
||||
cmdevt.callback = callback;
|
||||
registered_commands.Add(tag, cmdevt);
|
||||
}
|
||||
|
||||
public void OnReceiveRefresh(ulong client_id, FastBufferReader reader)
|
||||
{
|
||||
reader.ReadValueSafe(out ushort type);
|
||||
bool found = registered_commands.TryGetValue(type, out RefreshEvent command);
|
||||
if (found)
|
||||
{
|
||||
command.callback.Invoke(new SerializedData(reader));
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------
|
||||
|
||||
public void SendPlayerSettings(PlayerSettings psettings)
|
||||
{
|
||||
SendAction(GameAction.PlayerSettings, psettings, NetworkDelivery.ReliableFragmentedSequenced);
|
||||
}
|
||||
|
||||
public void SendPlayerSettingsAI(PlayerSettings psettings)
|
||||
{
|
||||
SendAction(GameAction.PlayerSettingsAI, psettings, NetworkDelivery.ReliableFragmentedSequenced);
|
||||
}
|
||||
|
||||
public void SendGameplaySettings(GameSettings settings)
|
||||
{
|
||||
SendAction(GameAction.GameSettings, settings, NetworkDelivery.ReliableFragmentedSequenced);
|
||||
}
|
||||
|
||||
public void PlayCard(Card card, Slot slot)
|
||||
{
|
||||
MsgPlayCard mdata = new MsgPlayCard();
|
||||
mdata.card_uid = card.uid;
|
||||
mdata.slot = slot;
|
||||
SendAction(GameAction.PlayCard, mdata);
|
||||
}
|
||||
|
||||
public void AttackTarget(Card card, Card target)
|
||||
{
|
||||
MsgAttack mdata = new MsgAttack();
|
||||
mdata.attacker_uid = card.uid;
|
||||
mdata.target_uid = target.uid;
|
||||
SendAction(GameAction.Attack, mdata);
|
||||
}
|
||||
|
||||
public void AttackPlayer(Card card, Player target)
|
||||
{
|
||||
MsgAttackPlayer mdata = new MsgAttackPlayer();
|
||||
mdata.attacker_uid = card.uid;
|
||||
mdata.target_id = target.player_id;
|
||||
SendAction(GameAction.AttackPlayer, mdata);
|
||||
}
|
||||
|
||||
public void Move(Card card, Slot slot)
|
||||
{
|
||||
MsgPlayCard mdata = new MsgPlayCard();
|
||||
mdata.card_uid = card.uid;
|
||||
mdata.slot = slot;
|
||||
SendAction(GameAction.Move, mdata);
|
||||
}
|
||||
|
||||
public void CastAbility(Card card, AbilityData ability)
|
||||
{
|
||||
MsgCastAbility mdata = new MsgCastAbility();
|
||||
mdata.caster_uid = card.uid;
|
||||
mdata.ability_id = ability.id;
|
||||
mdata.target_uid = "";
|
||||
SendAction(GameAction.CastAbility, mdata);
|
||||
}
|
||||
|
||||
public void SelectCard(Card card)
|
||||
{
|
||||
MsgCard mdata = new MsgCard();
|
||||
mdata.card_uid = card.uid;
|
||||
SendAction(GameAction.SelectCard, mdata);
|
||||
}
|
||||
|
||||
public void SelectPlayer(Player player)
|
||||
{
|
||||
MsgPlayer mdata = new MsgPlayer();
|
||||
mdata.player_id = player.player_id;
|
||||
SendAction(GameAction.SelectPlayer, mdata);
|
||||
}
|
||||
|
||||
public void SelectSlot(Slot slot)
|
||||
{
|
||||
SendAction(GameAction.SelectSlot, slot);
|
||||
}
|
||||
|
||||
public void SelectChoice(int c)
|
||||
{
|
||||
MsgInt choice = new MsgInt();
|
||||
choice.value = c;
|
||||
SendAction(GameAction.SelectChoice, choice);
|
||||
}
|
||||
|
||||
public void SelectCost(int c)
|
||||
{
|
||||
MsgInt choice = new MsgInt();
|
||||
choice.value = c;
|
||||
SendAction(GameAction.SelectCost, choice);
|
||||
}
|
||||
|
||||
public void Mulligan(string[] cards)
|
||||
{
|
||||
MsgMulligan mdata = new MsgMulligan();
|
||||
mdata.cards = cards;
|
||||
SendAction(GameAction.SelectMulligan, mdata);
|
||||
}
|
||||
|
||||
public void CancelSelection()
|
||||
{
|
||||
SendAction(GameAction.CancelSelect);
|
||||
}
|
||||
|
||||
public void SendChatMsg(string msg)
|
||||
{
|
||||
MsgChat chat = new MsgChat();
|
||||
chat.msg = msg;
|
||||
chat.player_id = player_id;
|
||||
SendAction(GameAction.ChatMessage, chat);
|
||||
}
|
||||
|
||||
public void EndTurn()
|
||||
{
|
||||
SendAction(GameAction.EndTurn);
|
||||
}
|
||||
|
||||
public void Resign()
|
||||
{
|
||||
SendAction(GameAction.Resign);
|
||||
}
|
||||
|
||||
public void SetObserverMode(int player_id)
|
||||
{
|
||||
observe_mode = true;
|
||||
observe_player_id = player_id;
|
||||
}
|
||||
|
||||
public void SetObserverMode(string username)
|
||||
{
|
||||
observe_player_id = 0; //Default value of observe_user not found
|
||||
|
||||
Game data = GetGameData();
|
||||
foreach (Player player in data.players)
|
||||
{
|
||||
if (player.username == username)
|
||||
{
|
||||
observe_player_id = player.player_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void SendAction<T>(ushort type, T data, NetworkDelivery delivery = NetworkDelivery.Reliable) where T : INetworkSerializable
|
||||
{
|
||||
FastBufferWriter writer = new FastBufferWriter(128, Unity.Collections.Allocator.Temp, TcgNetwork.MsgSizeMax);
|
||||
writer.WriteValueSafe(type);
|
||||
writer.WriteNetworkSerializable(data);
|
||||
Messaging.Send("action", ServerID, writer, delivery);
|
||||
writer.Dispose();
|
||||
}
|
||||
|
||||
public void SendAction(ushort type, int data)
|
||||
{
|
||||
FastBufferWriter writer = new FastBufferWriter(128, Unity.Collections.Allocator.Temp, TcgNetwork.MsgSizeMax);
|
||||
writer.WriteValueSafe(type);
|
||||
writer.WriteValueSafe(data);
|
||||
Messaging.Send("action", ServerID, writer, NetworkDelivery.Reliable);
|
||||
writer.Dispose();
|
||||
}
|
||||
|
||||
public void SendAction(ushort type)
|
||||
{
|
||||
FastBufferWriter writer = new FastBufferWriter(128, Unity.Collections.Allocator.Temp, TcgNetwork.MsgSizeMax);
|
||||
writer.WriteValueSafe(type);
|
||||
Messaging.Send("action", ServerID, writer, NetworkDelivery.Reliable);
|
||||
writer.Dispose();
|
||||
}
|
||||
|
||||
//--- Receive Refresh ----------------------
|
||||
|
||||
protected virtual void OnConnectedServer()
|
||||
{
|
||||
ConnectToGame(game_settings.game_uid);
|
||||
onConnectServer?.Invoke();
|
||||
}
|
||||
|
||||
protected virtual void OnConnectedToGame(SerializedData sdata)
|
||||
{
|
||||
MsgAfterConnected msg = sdata.Get<MsgAfterConnected>();
|
||||
player_id = msg.player_id;
|
||||
game_data = msg.game_data;
|
||||
observe_mode = player_id < 0; //Will usually return -1 if its an observer
|
||||
|
||||
if (observe_mode)
|
||||
SetObserverMode(observe_user);
|
||||
|
||||
if (onConnectGame != null)
|
||||
onConnectGame.Invoke();
|
||||
|
||||
SendGameSettings();
|
||||
}
|
||||
|
||||
protected virtual void OnPlayerReady(SerializedData sdata)
|
||||
{
|
||||
MsgInt msg = sdata.Get<MsgInt>();
|
||||
int pid = msg.value;
|
||||
|
||||
if (onPlayerReady != null)
|
||||
onPlayerReady.Invoke(pid);
|
||||
}
|
||||
|
||||
private void OnGameStart(SerializedData sdata)
|
||||
{
|
||||
onGameStart?.Invoke();
|
||||
}
|
||||
|
||||
private void OnGameEnd(SerializedData sdata)
|
||||
{
|
||||
MsgPlayer msg = sdata.Get<MsgPlayer>();
|
||||
onGameEnd?.Invoke(msg.player_id);
|
||||
}
|
||||
|
||||
private void OnNewTurn(SerializedData sdata)
|
||||
{
|
||||
MsgPlayer msg = sdata.Get<MsgPlayer>();
|
||||
onNewTurn?.Invoke(msg.player_id);
|
||||
}
|
||||
|
||||
private void OnCardPlayed(SerializedData sdata)
|
||||
{
|
||||
MsgPlayCard msg = sdata.Get<MsgPlayCard>();
|
||||
Card card = game_data.GetCard(msg.card_uid);
|
||||
onCardPlayed?.Invoke(card, msg.slot);
|
||||
}
|
||||
|
||||
private void OnCardSummoned(SerializedData sdata)
|
||||
{
|
||||
MsgPlayCard msg = sdata.Get<MsgPlayCard>();
|
||||
onCardSummoned?.Invoke(msg.slot);
|
||||
}
|
||||
|
||||
private void OnCardMoved(SerializedData sdata)
|
||||
{
|
||||
MsgPlayCard msg = sdata.Get<MsgPlayCard>();
|
||||
Card card = game_data.GetCard(msg.card_uid);
|
||||
onCardMoved?.Invoke(card, msg.slot);
|
||||
}
|
||||
|
||||
private void OnCardTransformed(SerializedData sdata)
|
||||
{
|
||||
MsgCard msg = sdata.Get<MsgCard>();
|
||||
Card card = game_data.GetCard(msg.card_uid);
|
||||
onCardTransformed?.Invoke(card);
|
||||
}
|
||||
|
||||
private void OnCardDiscarded(SerializedData sdata)
|
||||
{
|
||||
MsgCard msg = sdata.Get<MsgCard>();
|
||||
Card card = game_data.GetCard(msg.card_uid);
|
||||
onCardDiscarded?.Invoke(card);
|
||||
}
|
||||
|
||||
private void OnCardDraw(SerializedData sdata)
|
||||
{
|
||||
MsgInt msg = sdata.Get<MsgInt>();
|
||||
onCardDraw?.Invoke(msg.value);
|
||||
}
|
||||
|
||||
private void OnValueRolled(SerializedData sdata)
|
||||
{
|
||||
MsgInt msg = sdata.Get<MsgInt>();
|
||||
onValueRolled?.Invoke(msg.value);
|
||||
}
|
||||
|
||||
private void OnAttackStart(SerializedData sdata)
|
||||
{
|
||||
MsgAttack msg = sdata.Get<MsgAttack>();
|
||||
Card attacker = game_data.GetCard(msg.attacker_uid);
|
||||
Card target = game_data.GetCard(msg.target_uid);
|
||||
onAttackStart?.Invoke(attacker, target);
|
||||
}
|
||||
|
||||
private void OnAttackEnd(SerializedData sdata)
|
||||
{
|
||||
MsgAttack msg = sdata.Get<MsgAttack>();
|
||||
Card attacker = game_data.GetCard(msg.attacker_uid);
|
||||
Card target = game_data.GetCard(msg.target_uid);
|
||||
onAttackEnd?.Invoke(attacker, target);
|
||||
}
|
||||
|
||||
private void OnAttackPlayerStart(SerializedData sdata)
|
||||
{
|
||||
MsgAttackPlayer msg = sdata.Get<MsgAttackPlayer>();
|
||||
Card attacker = game_data.GetCard(msg.attacker_uid);
|
||||
Player target = game_data.GetPlayer(msg.target_id);
|
||||
onAttackPlayerStart?.Invoke(attacker, target);
|
||||
}
|
||||
|
||||
private void OnAttackPlayerEnd(SerializedData sdata)
|
||||
{
|
||||
MsgAttackPlayer msg = sdata.Get<MsgAttackPlayer>();
|
||||
Card attacker = game_data.GetCard(msg.attacker_uid);
|
||||
Player target = game_data.GetPlayer(msg.target_id);
|
||||
onAttackPlayerEnd?.Invoke(attacker, target);
|
||||
}
|
||||
|
||||
private void OnCardDamaged(SerializedData sdata)
|
||||
{
|
||||
MsgCardValue msg = sdata.Get<MsgCardValue>();
|
||||
Card card = game_data.GetCard(msg.card_uid);
|
||||
onCardDamaged?.Invoke(card, msg.value);
|
||||
}
|
||||
|
||||
private void OnPlayerDamaged(SerializedData sdata)
|
||||
{
|
||||
MsgPlayerValue msg = sdata.Get<MsgPlayerValue>();
|
||||
Player player = game_data.GetPlayer(msg.player_id);
|
||||
onPlayerDamaged?.Invoke(player, msg.value);
|
||||
}
|
||||
|
||||
private void OnCardHealed(SerializedData sdata)
|
||||
{
|
||||
MsgCardValue msg = sdata.Get<MsgCardValue>();
|
||||
Card card = game_data.GetCard(msg.card_uid);
|
||||
onCardHealed?.Invoke(card, msg.value);
|
||||
}
|
||||
|
||||
private void OnPlayerHealed(SerializedData sdata)
|
||||
{
|
||||
MsgPlayerValue msg = sdata.Get<MsgPlayerValue>();
|
||||
Player player = game_data.GetPlayer(msg.player_id);
|
||||
onPlayerHealed?.Invoke(player, msg.value);
|
||||
}
|
||||
|
||||
private void OnAbilityTrigger(SerializedData sdata)
|
||||
{
|
||||
MsgCastAbility msg = sdata.Get<MsgCastAbility>();
|
||||
AbilityData ability = AbilityData.Get(msg.ability_id);
|
||||
Card caster = game_data.GetCard(msg.caster_uid);
|
||||
onAbilityStart?.Invoke(ability, caster);
|
||||
}
|
||||
|
||||
private void OnAbilityTargetCard(SerializedData sdata)
|
||||
{
|
||||
MsgCastAbility msg = sdata.Get<MsgCastAbility>();
|
||||
AbilityData ability = AbilityData.Get(msg.ability_id);
|
||||
Card caster = game_data.GetCard(msg.caster_uid);
|
||||
Card target = game_data.GetCard(msg.target_uid);
|
||||
onAbilityTargetCard?.Invoke(ability, caster, target);
|
||||
}
|
||||
|
||||
private void OnAbilityTargetPlayer(SerializedData sdata)
|
||||
{
|
||||
MsgCastAbilityPlayer msg = sdata.Get<MsgCastAbilityPlayer>();
|
||||
AbilityData ability = AbilityData.Get(msg.ability_id);
|
||||
Card caster = game_data.GetCard(msg.caster_uid);
|
||||
Player target = game_data.GetPlayer(msg.target_id);
|
||||
onAbilityTargetPlayer?.Invoke(ability, caster, target);
|
||||
}
|
||||
|
||||
private void OnAbilityTargetSlot(SerializedData sdata)
|
||||
{
|
||||
MsgCastAbilitySlot msg = sdata.Get<MsgCastAbilitySlot>();
|
||||
AbilityData ability = AbilityData.Get(msg.ability_id);
|
||||
Card caster = game_data.GetCard(msg.caster_uid);
|
||||
onAbilityTargetSlot?.Invoke(ability, caster, msg.slot);
|
||||
}
|
||||
|
||||
private void OnAbilityAfter(SerializedData sdata)
|
||||
{
|
||||
MsgCastAbility msg = sdata.Get<MsgCastAbility>();
|
||||
AbilityData ability = AbilityData.Get(msg.ability_id);
|
||||
Card caster = game_data.GetCard(msg.caster_uid);
|
||||
onAbilityEnd?.Invoke(ability, caster);
|
||||
}
|
||||
|
||||
private void OnSecretTrigger(SerializedData sdata)
|
||||
{
|
||||
MsgSecret msg = sdata.Get<MsgSecret>();
|
||||
Card secret = game_data.GetCard(msg.secret_uid);
|
||||
Card triggerer = game_data.GetCard(msg.triggerer_uid);
|
||||
onSecretTrigger?.Invoke(secret, triggerer);
|
||||
}
|
||||
|
||||
private void OnSecretResolve(SerializedData sdata)
|
||||
{
|
||||
MsgSecret msg = sdata.Get<MsgSecret>();
|
||||
Card secret = game_data.GetCard(msg.secret_uid);
|
||||
Card triggerer = game_data.GetCard(msg.triggerer_uid);
|
||||
onSecretResolve?.Invoke(secret, triggerer);
|
||||
}
|
||||
|
||||
private void OnChat(SerializedData sdata)
|
||||
{
|
||||
MsgChat msg = sdata.Get<MsgChat>();
|
||||
onChatMsg?.Invoke(msg.player_id, msg.msg);
|
||||
}
|
||||
|
||||
private void OnServerMsg(SerializedData sdata)
|
||||
{
|
||||
string msg = sdata.GetString();
|
||||
onServerMsg?.Invoke(msg);
|
||||
}
|
||||
|
||||
private void OnRefreshAll(SerializedData sdata)
|
||||
{
|
||||
MsgRefreshAll msg = sdata.Get<MsgRefreshAll>();
|
||||
game_data = msg.game_data;
|
||||
onRefreshAll?.Invoke();
|
||||
}
|
||||
|
||||
//--------------------------
|
||||
|
||||
public virtual bool IsReady()
|
||||
{
|
||||
return game_data != null && TcgNetwork.Get().IsConnected();
|
||||
}
|
||||
|
||||
public Player GetPlayer()
|
||||
{
|
||||
Game gdata = GetGameData();
|
||||
return gdata.GetPlayer(GetPlayerID());
|
||||
}
|
||||
|
||||
public Player GetOpponentPlayer()
|
||||
{
|
||||
Game gdata = GetGameData();
|
||||
return gdata.GetPlayer(GetOpponentPlayerID());
|
||||
}
|
||||
|
||||
public int GetPlayerID()
|
||||
{
|
||||
if (observe_mode)
|
||||
return observe_player_id;
|
||||
return player_id;
|
||||
}
|
||||
|
||||
public int GetOpponentPlayerID()
|
||||
{
|
||||
return GetPlayerID() == 0 ? 1 : 0;
|
||||
}
|
||||
|
||||
public virtual bool IsYourTurn()
|
||||
{
|
||||
Game game_data = GetGameData();
|
||||
Player player = GetPlayer();
|
||||
return IsReady() && game_data.IsPlayerTurn(player);
|
||||
}
|
||||
|
||||
public bool IsObserveMode()
|
||||
{
|
||||
return observe_mode;
|
||||
}
|
||||
|
||||
public Game GetGameData()
|
||||
{
|
||||
return game_data;
|
||||
}
|
||||
|
||||
public bool HasEnded()
|
||||
{
|
||||
return game_data != null && game_data.HasEnded();
|
||||
}
|
||||
|
||||
private void OnApplicationQuit()
|
||||
{
|
||||
Resign(); //Auto Resign before closing the app. NOTE: doesn't seem to work since the msg dont have time to be sent before it closes
|
||||
}
|
||||
|
||||
public bool IsHost { get { return TcgNetwork.Get().IsHost; } }
|
||||
public ulong ServerID { get { return TcgNetwork.Get().ServerID; } }
|
||||
public NetworkMessaging Messaging { get { return TcgNetwork.Get().Messaging; } }
|
||||
|
||||
public static GameClient Get()
|
||||
{
|
||||
return instance;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class RefreshEvent
|
||||
{
|
||||
public ushort tag;
|
||||
public UnityAction<SerializedData> callback;
|
||||
}
|
||||
}
|
||||
11
Assets/TcgEngine/Scripts/GameClient/GameClient.cs.meta
Normal file
11
Assets/TcgEngine/Scripts/GameClient/GameClient.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0ad56e078bd4f1041bf0e76b3aa1b462
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
265
Assets/TcgEngine/Scripts/GameClient/GameClientMatchmaker.cs
Normal file
265
Assets/TcgEngine/Scripts/GameClient/GameClientMatchmaker.cs
Normal file
@@ -0,0 +1,265 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using Unity.Netcode;
|
||||
using UnityEngine.Events;
|
||||
using TcgEngine.UI;
|
||||
|
||||
namespace TcgEngine.Client
|
||||
{
|
||||
/// <summary>
|
||||
/// Main client script for the matchmaker
|
||||
/// Will send requests to server and receive a response when a matchmaking succeed or fail
|
||||
/// </summary>
|
||||
|
||||
public class GameClientMatchmaker : MonoBehaviour
|
||||
{
|
||||
public UnityAction<MatchmakingResult> onMatchmaking;
|
||||
public UnityAction<MatchmakingList> onMatchmakingList;
|
||||
public UnityAction<MatchList> onMatchList;
|
||||
|
||||
private bool matchmaking = false;
|
||||
private float timer = 0f;
|
||||
private float match_timer = 0f;
|
||||
private string matchmaking_group;
|
||||
private int matchmaking_players;
|
||||
private UnityAction<bool> connect_callback;
|
||||
|
||||
private static GameClientMatchmaker _instance;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
_instance = this;
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
TcgNetwork.Get().onConnect += OnConnect;
|
||||
TcgNetwork.Get().onDisconnect += OnDisconnect;
|
||||
Messaging.ListenMsg("matchmaking", ReceiveMatchmaking);
|
||||
Messaging.ListenMsg("matchmaking_list", ReceiveMatchmakingList);
|
||||
Messaging.ListenMsg("match_list", ReceiveMatchList);
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
Disconnect(); //Disconnect when switching scene
|
||||
|
||||
if (TcgNetwork.Get() != null)
|
||||
{
|
||||
TcgNetwork.Get().onConnect -= OnConnect;
|
||||
TcgNetwork.Get().onDisconnect -= OnDisconnect;
|
||||
Messaging.UnListenMsg("matchmaking");
|
||||
Messaging.UnListenMsg("matchmaking_list");
|
||||
Messaging.UnListenMsg("match_list");
|
||||
}
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
if (matchmaking)
|
||||
{
|
||||
timer += Time.deltaTime;
|
||||
match_timer += Time.deltaTime;
|
||||
|
||||
//Send periodic request
|
||||
if (IsConnected() && timer > 2f)
|
||||
{
|
||||
timer = 0f;
|
||||
SendMatchRequest(true, matchmaking_group, matchmaking_players);
|
||||
}
|
||||
|
||||
//Disconnected, stop
|
||||
if (!IsConnected() && !IsConnecting() && timer > 5f)
|
||||
{
|
||||
StopMatchmaking();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void StartMatchmaking(string group, int nb_players)
|
||||
{
|
||||
if (matchmaking)
|
||||
StopMatchmaking();
|
||||
|
||||
Debug.Log("Start Matchmaking!");
|
||||
matchmaking_group = group;
|
||||
matchmaking_players = nb_players;
|
||||
matchmaking = true;
|
||||
match_timer = 0f;
|
||||
timer = 0f;
|
||||
|
||||
Connect(NetworkData.Get().url, NetworkData.Get().port, (bool success) =>
|
||||
{
|
||||
if (success)
|
||||
{
|
||||
SendMatchRequest(false, group, nb_players);
|
||||
}
|
||||
else
|
||||
{
|
||||
StopMatchmaking();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void StopMatchmaking()
|
||||
{
|
||||
if (matchmaking)
|
||||
{
|
||||
Debug.Log("Stop Matchmaking!");
|
||||
onMatchmaking?.Invoke(null);
|
||||
matchmaking_group = "";
|
||||
matchmaking_players = 0;
|
||||
matchmaking = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void RefreshMatchmakingList()
|
||||
{
|
||||
Connect(NetworkData.Get().url, NetworkData.Get().port, (bool success) =>
|
||||
{
|
||||
if(success)
|
||||
SendMatchmakingListRequest();
|
||||
});
|
||||
}
|
||||
|
||||
public void RefreshMatchList(string username)
|
||||
{
|
||||
Connect(NetworkData.Get().url, NetworkData.Get().port, (bool success) =>
|
||||
{
|
||||
if (success)
|
||||
SendMatchListRequest(username);
|
||||
});
|
||||
}
|
||||
|
||||
public void Connect(string url, ushort port, UnityAction<bool> callback=null)
|
||||
{
|
||||
//Must be logged in to API to connect
|
||||
if(!Authenticator.Get().IsSignedIn())
|
||||
{
|
||||
callback?.Invoke(false);
|
||||
return;
|
||||
}
|
||||
|
||||
//Check if already connected
|
||||
if (IsConnected() || IsConnecting())
|
||||
{
|
||||
callback?.Invoke(IsConnected());
|
||||
return;
|
||||
}
|
||||
|
||||
connect_callback = callback;
|
||||
TcgNetwork.Get().StartClient(url, port);
|
||||
}
|
||||
|
||||
public void Disconnect()
|
||||
{
|
||||
TcgNetwork.Get()?.Disconnect();
|
||||
}
|
||||
|
||||
private void OnConnect()
|
||||
{
|
||||
Debug.Log("Connected to server!");
|
||||
connect_callback?.Invoke(true);
|
||||
connect_callback = null;
|
||||
}
|
||||
|
||||
private void OnDisconnect()
|
||||
{
|
||||
StopMatchmaking(); //Stop if currently running
|
||||
connect_callback?.Invoke(false);
|
||||
connect_callback = null;
|
||||
matchmaking = false;
|
||||
}
|
||||
|
||||
private void SendMatchRequest(bool refresh, string group, int nb_players)
|
||||
{
|
||||
MsgMatchmaking msg_match = new MsgMatchmaking();
|
||||
UserData udata = Authenticator.Get().GetUserData();
|
||||
msg_match.user_id = Authenticator.Get().GetUserId();
|
||||
msg_match.username = Authenticator.Get().GetUsername();
|
||||
msg_match.group = group;
|
||||
msg_match.players = nb_players;
|
||||
msg_match.elo = udata.elo;
|
||||
msg_match.time = match_timer;
|
||||
msg_match.refresh = refresh;
|
||||
Messaging.SendObject("matchmaking", ServerID, msg_match, NetworkDelivery.Reliable);
|
||||
}
|
||||
|
||||
private void SendMatchmakingListRequest()
|
||||
{
|
||||
MsgMatchmakingList msg_match = new MsgMatchmakingList();
|
||||
msg_match.username = ""; //Return all users
|
||||
Messaging.SendObject("matchmaking_list", ServerID, msg_match, NetworkDelivery.Reliable);
|
||||
}
|
||||
|
||||
private void SendMatchListRequest(string username)
|
||||
{
|
||||
MsgMatchmakingList msg_match = new MsgMatchmakingList();
|
||||
msg_match.username = username;
|
||||
Messaging.SendObject("match_list", ServerID, msg_match, NetworkDelivery.Reliable);
|
||||
}
|
||||
|
||||
private void ReceiveMatchmaking(ulong client_id, FastBufferReader reader)
|
||||
{
|
||||
reader.ReadNetworkSerializable(out MatchmakingResult msg);
|
||||
|
||||
if (IsConnected() && matchmaking && matchmaking_group == msg.group)
|
||||
{
|
||||
matchmaking = !msg.success; //Stop matchmaking if success
|
||||
onMatchmaking?.Invoke(msg);
|
||||
}
|
||||
}
|
||||
|
||||
private void ReceiveMatchmakingList(ulong client_id, FastBufferReader reader)
|
||||
{
|
||||
reader.ReadNetworkSerializable(out MatchmakingList list);
|
||||
onMatchmakingList?.Invoke(list);
|
||||
}
|
||||
|
||||
private void ReceiveMatchList(ulong client_id, FastBufferReader reader)
|
||||
{
|
||||
reader.ReadNetworkSerializable(out MatchList list);
|
||||
onMatchList?.Invoke(list);
|
||||
}
|
||||
|
||||
public bool IsMatchmaking()
|
||||
{
|
||||
return matchmaking;
|
||||
}
|
||||
|
||||
public string GetGroup()
|
||||
{
|
||||
return matchmaking_group;
|
||||
}
|
||||
|
||||
public int GetNbPlayers()
|
||||
{
|
||||
return matchmaking_players;
|
||||
}
|
||||
|
||||
public float GetTimer()
|
||||
{
|
||||
return match_timer;
|
||||
}
|
||||
|
||||
public bool IsConnected()
|
||||
{
|
||||
return TcgNetwork.Get().IsConnected();
|
||||
}
|
||||
|
||||
public bool IsConnecting()
|
||||
{
|
||||
return TcgNetwork.Get().IsConnecting();
|
||||
}
|
||||
|
||||
public ulong ServerID { get { return TcgNetwork.Get().ServerID; } }
|
||||
public NetworkMessaging Messaging { get { return TcgNetwork.Get().Messaging; } }
|
||||
|
||||
public static GameClientMatchmaker Get()
|
||||
{
|
||||
return _instance;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: edceb3bb736f47a4aab07ab20b0d947a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
298
Assets/TcgEngine/Scripts/GameClient/HandCard.cs
Normal file
298
Assets/TcgEngine/Scripts/GameClient/HandCard.cs
Normal file
@@ -0,0 +1,298 @@
|
||||
using TcgEngine.Client;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using TcgEngine.UI;
|
||||
|
||||
namespace TcgEngine.Client
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the visual aspect of a card in hand.
|
||||
/// Will take the data from Card.cs and display it
|
||||
/// </summary>
|
||||
|
||||
public class HandCard : MonoBehaviour
|
||||
{
|
||||
public Image card_glow;
|
||||
public float move_speed = 10f;
|
||||
public float move_rotate_speed = 4f;
|
||||
public float move_max_rotate = 10f;
|
||||
|
||||
[HideInInspector]
|
||||
public Vector2 deck_position;
|
||||
[HideInInspector]
|
||||
public float deck_angle;
|
||||
|
||||
private string card_uid = "";
|
||||
|
||||
private CardUI card_ui;
|
||||
private RectTransform hand_transform;
|
||||
private RectTransform card_transform;
|
||||
private Vector3 start_scale;
|
||||
private Vector3 current_rotate;
|
||||
private Vector3 target_rotate;
|
||||
private Vector3 prev_pos;
|
||||
|
||||
private bool destroyed = false;
|
||||
private float focus_timer = 0f;
|
||||
|
||||
private bool focus = false;
|
||||
private bool drag = false;
|
||||
private bool selected = false;
|
||||
|
||||
private static List<HandCard> card_list = new List<HandCard>();
|
||||
|
||||
void Awake()
|
||||
{
|
||||
card_list.Add(this);
|
||||
card_ui = GetComponent<CardUI>();
|
||||
card_transform = transform.GetComponent<RectTransform>();
|
||||
hand_transform = transform.parent.GetComponent<RectTransform>();
|
||||
start_scale = transform.localScale;
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
card_list.Remove(this);
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
if (!GameClient.Get().IsReady())
|
||||
return;
|
||||
|
||||
Card card = GetCard();
|
||||
Vector2 target_position = deck_position;
|
||||
Vector3 target_size = start_scale;
|
||||
|
||||
focus_timer += Time.deltaTime;
|
||||
|
||||
if (IsFocus())
|
||||
{
|
||||
target_position = deck_position + Vector2.up * 40f;
|
||||
}
|
||||
|
||||
if (IsDrag())
|
||||
{
|
||||
target_position = GetTargetPosition();
|
||||
target_size = start_scale * 0.75f;
|
||||
Vector3 dir = card_transform.position - prev_pos;
|
||||
Vector3 addrot = new Vector3(dir.y * 90f, -dir.x * 90f, 0f);
|
||||
target_rotate += addrot * move_rotate_speed * Time.deltaTime;
|
||||
target_rotate = new Vector3(Mathf.Clamp(target_rotate.x, -move_max_rotate, move_max_rotate), Mathf.Clamp(target_rotate.y, -move_max_rotate, move_max_rotate), 0f);
|
||||
current_rotate = Vector3.Lerp(current_rotate, target_rotate, move_rotate_speed * Time.deltaTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
target_rotate = new Vector3(0f, 0f, deck_angle);
|
||||
current_rotate = new Vector3(0f, 0f, deck_angle);
|
||||
}
|
||||
|
||||
card_transform.anchoredPosition = Vector2.Lerp(card_transform.anchoredPosition, target_position, Time.deltaTime * move_speed);
|
||||
card_transform.localRotation = Quaternion.Slerp(card_transform.localRotation, Quaternion.Euler(current_rotate), Time.deltaTime * move_speed);
|
||||
card_transform.localScale = Vector3.Lerp(card_transform.localScale, target_size, 5f * Time.deltaTime);
|
||||
|
||||
card_ui.SetCard(card);
|
||||
card_glow.enabled = IsFocus() || IsDrag();
|
||||
prev_pos = Vector3.Lerp(prev_pos, card_transform.position, 1f * Time.deltaTime);
|
||||
|
||||
//Unselect
|
||||
if (!drag && selected && Input.GetMouseButtonDown(0))
|
||||
selected = false;
|
||||
}
|
||||
|
||||
private Vector2 GetTargetPosition()
|
||||
{
|
||||
Card card = GetCard();
|
||||
RectTransformUtility.ScreenPointToLocalPointInRectangle(hand_transform, Input.mousePosition, Camera.main, out Vector2 tpos);
|
||||
if (card.CardData.IsRequireTarget())
|
||||
{
|
||||
tpos = deck_position + Vector2.up * 150f + Vector2.right * tpos.x / 10f;
|
||||
}
|
||||
return tpos;
|
||||
}
|
||||
|
||||
public void SetCard(Card card)
|
||||
{
|
||||
this.card_uid = card.uid;
|
||||
card_ui.SetCard(card);
|
||||
}
|
||||
|
||||
public void Kill()
|
||||
{
|
||||
if (!destroyed)
|
||||
{
|
||||
destroyed = true;
|
||||
Destroy(gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsFocus()
|
||||
{
|
||||
if (GameTool.IsMobile())
|
||||
return selected && !drag;
|
||||
return focus && !drag && focus_timer > 0f;
|
||||
}
|
||||
|
||||
public bool IsDrag()
|
||||
{
|
||||
return drag;
|
||||
}
|
||||
|
||||
public Card GetCard()
|
||||
{
|
||||
Game gdata = GameClient.Get().GetGameData();
|
||||
return gdata.GetCard(card_uid);
|
||||
}
|
||||
|
||||
public CardData GetCardData()
|
||||
{
|
||||
Card card = GetCard();
|
||||
if (card != null)
|
||||
return CardData.Get(card.card_id);
|
||||
return null;
|
||||
}
|
||||
|
||||
public string GetCardUID()
|
||||
{
|
||||
return card_uid;
|
||||
}
|
||||
|
||||
public void OnMouseEnterCard()
|
||||
{
|
||||
if (GameUI.IsUIOpened())
|
||||
return;
|
||||
|
||||
focus = true;
|
||||
}
|
||||
|
||||
public void OnMouseExitCard()
|
||||
{
|
||||
focus = false;
|
||||
focus_timer = -0.2f;
|
||||
}
|
||||
|
||||
public void OnMouseDownCard()
|
||||
{
|
||||
if (GameUI.IsOverUILayer("UI"))
|
||||
return;
|
||||
|
||||
UnselectAll();
|
||||
drag = true;
|
||||
selected = true;
|
||||
PlayerControls.Get().UnselectAll();
|
||||
AudioTool.Get().PlaySFX("hand_card", AssetData.Get().hand_card_click_audio);
|
||||
}
|
||||
|
||||
public void OnMouseUpCard()
|
||||
{
|
||||
Vector2 mpos = GameCamera.Get().MouseToPercent(Input.mousePosition);
|
||||
Vector3 board_pos = GameBoard.Get().RaycastMouseBoard();
|
||||
if (drag && mpos.y > 0.25f)
|
||||
TryPlayCard(board_pos);
|
||||
else if (!GameTool.IsMobile())
|
||||
HandCardArea.Get().SortCards();
|
||||
drag = false;
|
||||
}
|
||||
|
||||
public void TryPlayCard(Vector3 board_pos)
|
||||
{
|
||||
if (!GameClient.Get().IsYourTurn())
|
||||
{
|
||||
WarningText.ShowNotYourTurn();
|
||||
return;
|
||||
}
|
||||
|
||||
BSlot bslot = BSlot.GetNearest(board_pos);
|
||||
int player_id = GameClient.Get().GetPlayerID();
|
||||
Game gdata = GameClient.Get().GetGameData();
|
||||
Player player = gdata.GetPlayer(player_id);
|
||||
Card card = GetCard();
|
||||
|
||||
Slot slot = Slot.None;
|
||||
if (bslot != null)
|
||||
slot = bslot.GetEmptySlot(board_pos);
|
||||
if(bslot != null && card.CardData.IsRequireTarget())
|
||||
slot = bslot.GetSlot(board_pos);
|
||||
|
||||
if (!Tutorial.Get().CanDo(TutoEndTrigger.PlayCard, card))
|
||||
return;
|
||||
|
||||
Card slot_card = bslot?.GetSlotCard(board_pos);
|
||||
if (bslot != null && card.CardData.IsRequireTargetSpell() && slot_card != null && slot_card.HasStatus(StatusType.SpellImmunity))
|
||||
{
|
||||
WarningText.ShowSpellImmune();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!player.CanPayMana(card))
|
||||
{
|
||||
WarningText.ShowNoMana();
|
||||
return;
|
||||
}
|
||||
|
||||
if (gdata.CanPlayCard(card, slot, true))
|
||||
{
|
||||
PlayCard(slot);
|
||||
}
|
||||
}
|
||||
|
||||
public void PlayCard(Slot slot)
|
||||
{
|
||||
GameClient.Get().PlayCard(GetCard(), slot);
|
||||
HandCardArea.Get().DelayRefresh(GetCard());
|
||||
Destroy(gameObject);
|
||||
if (GameTool.IsMobile())
|
||||
BoardCard.UnfocusAll();
|
||||
}
|
||||
|
||||
public CardData CardData { get { return GetCardData(); } }
|
||||
|
||||
public static HandCard GetDrag()
|
||||
{
|
||||
foreach (HandCard card in card_list)
|
||||
{
|
||||
if (card.IsDrag())
|
||||
return card;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static HandCard GetFocus()
|
||||
{
|
||||
foreach (HandCard card in card_list)
|
||||
{
|
||||
if (card.IsFocus())
|
||||
return card;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static HandCard Get(string uid)
|
||||
{
|
||||
foreach (HandCard card in card_list)
|
||||
{
|
||||
if (card && card.GetCardUID() == uid)
|
||||
return card;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void UnselectAll()
|
||||
{
|
||||
foreach (HandCard card in card_list)
|
||||
card.selected = false;
|
||||
}
|
||||
|
||||
public static List<HandCard> GetAll()
|
||||
{
|
||||
return card_list;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/TcgEngine/Scripts/GameClient/HandCard.cs.meta
Normal file
11
Assets/TcgEngine/Scripts/GameClient/HandCard.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d2357af860d3cda49906d9a355df329e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
131
Assets/TcgEngine/Scripts/GameClient/HandCardArea.cs
Normal file
131
Assets/TcgEngine/Scripts/GameClient/HandCardArea.cs
Normal file
@@ -0,0 +1,131 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using TcgEngine.Client;
|
||||
using TcgEngine.UI;
|
||||
|
||||
namespace TcgEngine.Client
|
||||
{
|
||||
/// <summary>
|
||||
/// Area where all the hand cards are
|
||||
/// Will take card of spawning/despawning hand cards based on the refresh data received from server
|
||||
/// </summary>
|
||||
|
||||
public class HandCardArea : MonoBehaviour
|
||||
{
|
||||
public GameObject card_prefab;
|
||||
public RectTransform card_area;
|
||||
public float card_spacing = 100f;
|
||||
public float card_angle = 10f;
|
||||
public float card_offset_y = 10f;
|
||||
|
||||
private List<HandCard> cards = new List<HandCard>();
|
||||
|
||||
private bool is_dragging;
|
||||
|
||||
private string last_destroyed;
|
||||
private float last_destroyed_timer = 0f;
|
||||
|
||||
private static HandCardArea _instance;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
_instance = this;
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
if (!GameClient.Get().IsReady())
|
||||
return;
|
||||
|
||||
int player_id = GameClient.Get().GetPlayerID();
|
||||
Game data = GameClient.Get().GetGameData();
|
||||
Player player = data.GetPlayer(player_id);
|
||||
|
||||
last_destroyed_timer += Time.deltaTime;
|
||||
|
||||
//Add new cards
|
||||
foreach (Card card in player.cards_hand)
|
||||
{
|
||||
if (!HasCard(card.uid))
|
||||
SpawnNewCard(card);
|
||||
}
|
||||
|
||||
//Remove destroyed cards
|
||||
for (int i = cards.Count - 1; i >= 0; i--)
|
||||
{
|
||||
HandCard card = cards[i];
|
||||
if (card == null || player.GetHandCard(card.GetCard().uid) == null)
|
||||
{
|
||||
cards.RemoveAt(i);
|
||||
if(card != null)
|
||||
card.Kill();
|
||||
}
|
||||
}
|
||||
|
||||
//Set card index
|
||||
int index = 0;
|
||||
float count_half = cards.Count / 2f;
|
||||
foreach (HandCard card in cards)
|
||||
{
|
||||
card.deck_position = new Vector2((index - count_half) * card_spacing, (index - count_half) * (index - count_half) * -card_offset_y);
|
||||
card.deck_angle = (index - count_half) * -card_angle;
|
||||
index++;
|
||||
}
|
||||
|
||||
//Set target forcus
|
||||
HandCard drag_card = HandCard.GetDrag();
|
||||
is_dragging = drag_card != null;
|
||||
}
|
||||
|
||||
public void SpawnNewCard(Card card)
|
||||
{
|
||||
GameObject card_obj = Instantiate(card_prefab, card_area.transform);
|
||||
card_obj.GetComponent<HandCard>().SetCard(card);
|
||||
card_obj.GetComponent<RectTransform>().anchoredPosition = new Vector2(0f, -100f);
|
||||
cards.Add(card_obj.GetComponent<HandCard>());
|
||||
}
|
||||
|
||||
public void DelayRefresh(Card card)
|
||||
{
|
||||
last_destroyed_timer = 0f;
|
||||
last_destroyed = card.uid;
|
||||
}
|
||||
|
||||
public void SortCards()
|
||||
{
|
||||
cards.Sort(SortFunc);
|
||||
|
||||
int i = 0;
|
||||
foreach (HandCard acard in cards)
|
||||
{
|
||||
acard.transform.SetSiblingIndex(i);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
private int SortFunc(HandCard a, HandCard b)
|
||||
{
|
||||
return a.transform.position.x.CompareTo(b.transform.position.x);
|
||||
}
|
||||
|
||||
public bool HasCard(string card_uid)
|
||||
{
|
||||
HandCard card = HandCard.Get(card_uid);
|
||||
bool just_destroyed = card_uid == last_destroyed && last_destroyed_timer < 0.7f;
|
||||
return card != null || just_destroyed;
|
||||
}
|
||||
|
||||
public bool IsDragging()
|
||||
{
|
||||
return is_dragging;
|
||||
}
|
||||
|
||||
|
||||
public static HandCardArea Get()
|
||||
{
|
||||
return _instance;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/TcgEngine/Scripts/GameClient/HandCardArea.cs.meta
Normal file
11
Assets/TcgEngine/Scripts/GameClient/HandCardArea.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8fde1028e457564468c157e3c4b1bd3e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
46
Assets/TcgEngine/Scripts/GameClient/HandCardBack.cs
Normal file
46
Assets/TcgEngine/Scripts/GameClient/HandCardBack.cs
Normal file
@@ -0,0 +1,46 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace TcgEngine.Client
|
||||
{
|
||||
/// <summary>
|
||||
/// Same as HandCard, but simpler version for the opponent's cards
|
||||
/// </summary>
|
||||
|
||||
public class HandCardBack : MonoBehaviour
|
||||
{
|
||||
public Image card_sprite;
|
||||
|
||||
private RectTransform rect;
|
||||
|
||||
private static List<HandCardBack> card_list = new List<HandCardBack>();
|
||||
|
||||
void Awake()
|
||||
{
|
||||
card_list.Add(this);
|
||||
rect = GetComponent<RectTransform>();
|
||||
SetCardback(null);
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
card_list.Remove(this);
|
||||
}
|
||||
|
||||
public void SetCardback(CardbackData cb)
|
||||
{
|
||||
if (cb != null && cb.cardback != null)
|
||||
card_sprite.sprite = cb.cardback;
|
||||
}
|
||||
|
||||
public RectTransform GetRect()
|
||||
{
|
||||
if (rect == null)
|
||||
return GetComponent<RectTransform>();
|
||||
return rect;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
11
Assets/TcgEngine/Scripts/GameClient/HandCardBack.cs.meta
Normal file
11
Assets/TcgEngine/Scripts/GameClient/HandCardBack.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f2f4f7030abb7e74abf11024a293fde4
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
261
Assets/TcgEngine/Scripts/GameClient/HandPack.cs
Normal file
261
Assets/TcgEngine/Scripts/GameClient/HandPack.cs
Normal file
@@ -0,0 +1,261 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using TcgEngine.FX;
|
||||
using TcgEngine.Client;
|
||||
|
||||
namespace TcgEngine.Client
|
||||
{
|
||||
/// <summary>
|
||||
/// Visual representation of a booster pack in hand, for the OpenPack scene
|
||||
/// </summary>
|
||||
|
||||
public class HandPack : MonoBehaviour
|
||||
{
|
||||
public Image pack_sprite;
|
||||
public Image pack_glow;
|
||||
public Text pack_quantity;
|
||||
|
||||
public float move_speed = 10f;
|
||||
public float move_rotate_speed = 4f;
|
||||
public float move_max_rotate = 10f;
|
||||
|
||||
[HideInInspector]
|
||||
public Vector2 deck_position;
|
||||
[HideInInspector]
|
||||
public float deck_angle;
|
||||
|
||||
[Header("FX")]
|
||||
public GameObject pack_open_fx;
|
||||
public AudioClip pack_open_audio;
|
||||
|
||||
private string pack_tid = "";
|
||||
private int quantity = 0;
|
||||
|
||||
private RectTransform hand_transform;
|
||||
private RectTransform card_transform;
|
||||
private Vector3 start_scale;
|
||||
private float current_alpha = 0f;
|
||||
private Vector3 current_rotate;
|
||||
private Vector3 target_rotate;
|
||||
private Vector3 prev_pos;
|
||||
|
||||
private bool destroyed = false;
|
||||
private float focus_timer = 0f;
|
||||
|
||||
private bool focus = false;
|
||||
private bool drag = false;
|
||||
|
||||
private static List<HandPack> pack_list = new List<HandPack>();
|
||||
|
||||
void Awake()
|
||||
{
|
||||
pack_list.Add(this);
|
||||
card_transform = transform.GetComponent<RectTransform>();
|
||||
hand_transform = transform.parent.GetComponent<RectTransform>();
|
||||
start_scale = transform.localScale;
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
pack_list.Remove(this);
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
focus_timer += Time.deltaTime;
|
||||
|
||||
Vector2 target_position = deck_position;
|
||||
Vector3 target_size = start_scale;
|
||||
|
||||
float target_alpha = 1f;
|
||||
bool player_dragging = HandPackArea.Get().IsDragging();
|
||||
|
||||
if (focus && focus_timer > 0.5f)
|
||||
{
|
||||
target_position = deck_position + Vector2.up * 40f;
|
||||
}
|
||||
|
||||
if (drag)
|
||||
{
|
||||
target_position = GetTargetPosition();
|
||||
target_size = start_scale * 0.8f;
|
||||
Vector3 dir = card_transform.position - prev_pos;
|
||||
Vector3 addrot = new Vector3(dir.y * 90f, -dir.x * 90f, 0f);
|
||||
target_rotate += addrot * move_rotate_speed * Time.deltaTime;
|
||||
target_rotate = new Vector3(Mathf.Clamp(target_rotate.x, -move_max_rotate, move_max_rotate), Mathf.Clamp(target_rotate.y, -move_max_rotate, move_max_rotate), 0f);
|
||||
current_rotate = Vector3.Lerp(current_rotate, target_rotate, move_rotate_speed * Time.deltaTime);
|
||||
move_speed = 9f;
|
||||
target_alpha = 0.8f;
|
||||
}
|
||||
else
|
||||
{
|
||||
target_rotate = new Vector3(0f, 0f, deck_angle);
|
||||
current_rotate = new Vector3(0f, 0f, deck_angle);
|
||||
}
|
||||
|
||||
card_transform.anchoredPosition = Vector2.Lerp(card_transform.anchoredPosition, target_position, Time.deltaTime * move_speed);
|
||||
card_transform.rotation = Quaternion.Slerp(card_transform.rotation, Quaternion.Euler(current_rotate), Time.deltaTime * move_speed);
|
||||
card_transform.localScale = Vector3.Lerp(card_transform.localScale, target_size, 4f * Time.deltaTime);
|
||||
|
||||
pack_glow.enabled = (focus && !player_dragging) || drag;
|
||||
current_alpha = Mathf.MoveTowards(current_alpha, target_alpha, 2f * Time.deltaTime);
|
||||
pack_sprite.color = new Color(1f, 1f, 1f, current_alpha);
|
||||
pack_glow.color = new Color(pack_glow.color.r, pack_glow.color.g, pack_glow.color.b, current_alpha * 0.8f);
|
||||
pack_quantity.text = quantity.ToString();
|
||||
|
||||
prev_pos = Vector3.Lerp(prev_pos, card_transform.position, 1f * Time.deltaTime);
|
||||
}
|
||||
|
||||
private Vector2 GetTargetPosition()
|
||||
{
|
||||
RectTransformUtility.ScreenPointToLocalPointInRectangle(hand_transform, Input.mousePosition, Camera.main, out Vector2 tpos);
|
||||
return tpos;
|
||||
}
|
||||
|
||||
public void SetPack(UserCardData pack)
|
||||
{
|
||||
this.pack_tid = pack.tid;
|
||||
this.quantity = pack.quantity;
|
||||
|
||||
PackData ipack = PackData.Get(pack.tid);
|
||||
if (ipack)
|
||||
{
|
||||
pack_sprite.sprite = ipack.pack_img;
|
||||
}
|
||||
}
|
||||
|
||||
public void OpenPack()
|
||||
{
|
||||
FXTool.DoFX(pack_open_fx, transform.position);
|
||||
AudioTool.Get().PlaySFX("pack_open", pack_open_audio);
|
||||
Destroy(gameObject);
|
||||
OpenPackMenu.Get().OpenPack(pack_tid);
|
||||
}
|
||||
|
||||
public void Remove()
|
||||
{
|
||||
quantity--;
|
||||
if (quantity <= 0)
|
||||
Kill();
|
||||
}
|
||||
|
||||
public void Kill()
|
||||
{
|
||||
if (!destroyed)
|
||||
{
|
||||
destroyed = true;
|
||||
Destroy(gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsFocus()
|
||||
{
|
||||
return focus && !drag;
|
||||
}
|
||||
|
||||
public bool IsDrag()
|
||||
{
|
||||
return drag;
|
||||
}
|
||||
|
||||
public PackData GetPackData()
|
||||
{
|
||||
return PackData.Get(pack_tid);
|
||||
}
|
||||
|
||||
public string GetPackTid()
|
||||
{
|
||||
return pack_tid;
|
||||
}
|
||||
|
||||
public int GetPackQuantity()
|
||||
{
|
||||
UserData udata = Authenticator.Get().UserData;
|
||||
return udata.GetPackQuantity(pack_tid);
|
||||
}
|
||||
|
||||
public void OnMouseEnterCard()
|
||||
{
|
||||
if (HandPackArea.Get().IsLocked())
|
||||
return;
|
||||
|
||||
focus = true;
|
||||
}
|
||||
|
||||
public void OnMouseExitCard()
|
||||
{
|
||||
focus = false;
|
||||
focus_timer = 0f;
|
||||
}
|
||||
|
||||
public void OnMouseDownCard()
|
||||
{
|
||||
if (HandPackArea.Get().IsLocked())
|
||||
return;
|
||||
|
||||
drag = true;
|
||||
AudioTool.Get().PlaySFX("hand_card", AssetData.Get().hand_card_click_audio);
|
||||
}
|
||||
|
||||
public void OnMouseUpCard()
|
||||
{
|
||||
Vector3 world_pos = MouseToWorld(Input.mousePosition);
|
||||
if (drag && world_pos.y > -2.5f)
|
||||
OpenPack();
|
||||
else
|
||||
HandPackArea.Get().SortCards();
|
||||
drag = false;
|
||||
}
|
||||
|
||||
public Vector3 MouseToWorld(Vector3 mouse_pos)
|
||||
{
|
||||
Vector3 wpos = Camera.main.ScreenToWorldPoint(mouse_pos);
|
||||
wpos.z = 0f;
|
||||
return wpos;
|
||||
}
|
||||
|
||||
public PackData PackData { get { return GetPackData(); } }
|
||||
|
||||
public static HandPack GetDrag()
|
||||
{
|
||||
foreach (HandPack card in pack_list)
|
||||
{
|
||||
if (card.IsDrag())
|
||||
return card;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static HandPack GetFocus()
|
||||
{
|
||||
foreach (HandPack card in pack_list)
|
||||
{
|
||||
if (card.IsFocus())
|
||||
return card;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static HandPack Get(string uid)
|
||||
{
|
||||
foreach (HandPack card in pack_list)
|
||||
{
|
||||
if (card && card.GetPackTid() == uid)
|
||||
return card;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static List<HandPack> GetAll()
|
||||
{
|
||||
return pack_list;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/TcgEngine/Scripts/GameClient/HandPack.cs.meta
Normal file
11
Assets/TcgEngine/Scripts/GameClient/HandPack.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d4cb6ec85335c724eae85b838b0b3f89
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
172
Assets/TcgEngine/Scripts/GameClient/HandPackArea.cs
Normal file
172
Assets/TcgEngine/Scripts/GameClient/HandPackArea.cs
Normal file
@@ -0,0 +1,172 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using TcgEngine.Client;
|
||||
using TcgEngine.UI;
|
||||
|
||||
namespace TcgEngine.Client
|
||||
{
|
||||
/// <summary>
|
||||
/// Area of the hand of packs, will spawn/despawns visual packs based on what player has in the data
|
||||
/// </summary>
|
||||
|
||||
public class HandPackArea : MonoBehaviour
|
||||
{
|
||||
public RectTransform hand_area;
|
||||
public GameObject pack_template;
|
||||
public float card_spacing = 100f;
|
||||
public float card_angle = 10f;
|
||||
public float card_offset_y = 10f;
|
||||
|
||||
private List<HandPack> packs = new List<HandPack>();
|
||||
|
||||
private Vector3 start_pos;
|
||||
private bool is_dragging;
|
||||
private bool is_locked;
|
||||
private string last_destroyed;
|
||||
private float last_destroyed_timer = 0f;
|
||||
|
||||
private static HandPackArea _instance;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
_instance = this;
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
pack_template.SetActive(false);
|
||||
start_pos = hand_area.anchoredPosition;
|
||||
|
||||
if (Authenticator.Get().IsConnected())
|
||||
LoadPacks();
|
||||
else
|
||||
RefreshLogin();
|
||||
}
|
||||
|
||||
private async void RefreshLogin()
|
||||
{
|
||||
bool success = await Authenticator.Get().RefreshLogin();
|
||||
if (success)
|
||||
LoadPacks();
|
||||
else
|
||||
SceneNav.GoTo("LoginMenu");
|
||||
}
|
||||
|
||||
public async void LoadPacks()
|
||||
{
|
||||
UserData udata = await Authenticator.Get().LoadUserData();
|
||||
if (udata != null)
|
||||
{
|
||||
RefreshPacks();
|
||||
}
|
||||
}
|
||||
|
||||
public void RefreshPacks()
|
||||
{
|
||||
UserData udata = Authenticator.Get().UserData;
|
||||
|
||||
foreach (UserCardData pack in udata.packs)
|
||||
{
|
||||
PackData dpack = PackData.Get(pack.tid);
|
||||
if (dpack != null && !HasPack(pack.tid))
|
||||
SpawnNewPack(pack);
|
||||
}
|
||||
|
||||
//Remove removed cards
|
||||
for (int i = packs.Count - 1; i >= 0; i--)
|
||||
{
|
||||
HandPack pack = packs[i];
|
||||
if (pack == null || !udata.HasPack(pack.GetPackTid()))
|
||||
{
|
||||
packs.RemoveAt(i);
|
||||
if (pack)
|
||||
pack.Remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
last_destroyed_timer += Time.deltaTime;
|
||||
|
||||
//Position
|
||||
Vector3 tpos = is_locked ? (start_pos + Vector3.down * 200f) : start_pos;
|
||||
hand_area.anchoredPosition = Vector3.MoveTowards(hand_area.anchoredPosition, tpos, 200f * Time.deltaTime);
|
||||
|
||||
//Set card index
|
||||
int index = 0;
|
||||
float count_half = packs.Count / 2f;
|
||||
foreach (HandPack card in packs)
|
||||
{
|
||||
card.deck_position = new Vector2((index - count_half) * card_spacing, (index - count_half) * (index - count_half) * -card_offset_y);
|
||||
card.deck_angle = (index - count_half) * -card_angle;
|
||||
index++;
|
||||
}
|
||||
|
||||
//Set target forcus
|
||||
HandPack drag_pack = HandPack.GetDrag();
|
||||
is_dragging = drag_pack != null;
|
||||
}
|
||||
|
||||
public void SpawnNewPack(UserCardData pack)
|
||||
{
|
||||
GameObject card_obj = Instantiate(pack_template, hand_area.transform);
|
||||
card_obj.SetActive(true);
|
||||
card_obj.GetComponent<HandPack>().SetPack(pack);
|
||||
card_obj.GetComponent<RectTransform>().anchoredPosition = new Vector2(0f, -100f);
|
||||
packs.Add(card_obj.GetComponent<HandPack>());
|
||||
}
|
||||
|
||||
public void DelayRefresh(Card card)
|
||||
{
|
||||
last_destroyed_timer = 0f;
|
||||
last_destroyed = card.uid;
|
||||
}
|
||||
|
||||
public void Lock(bool locked)
|
||||
{
|
||||
is_locked = locked;
|
||||
}
|
||||
|
||||
public void SortCards()
|
||||
{
|
||||
packs.Sort(SortFunc);
|
||||
|
||||
int i = 0;
|
||||
foreach (HandPack acard in packs)
|
||||
{
|
||||
acard.transform.SetSiblingIndex(i);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
private int SortFunc(HandPack a, HandPack b)
|
||||
{
|
||||
return a.transform.position.x.CompareTo(b.transform.position.x);
|
||||
}
|
||||
|
||||
public bool HasPack(string pack_tid)
|
||||
{
|
||||
HandPack card = HandPack.Get(pack_tid);
|
||||
bool just_destroyed = pack_tid == last_destroyed && last_destroyed_timer < 0.5f;
|
||||
return card != null || just_destroyed;
|
||||
}
|
||||
|
||||
public bool IsDragging()
|
||||
{
|
||||
return is_dragging;
|
||||
}
|
||||
|
||||
public bool IsLocked()
|
||||
{
|
||||
return is_locked;
|
||||
}
|
||||
|
||||
public static HandPackArea Get()
|
||||
{
|
||||
return _instance;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/TcgEngine/Scripts/GameClient/HandPackArea.cs.meta
Normal file
11
Assets/TcgEngine/Scripts/GameClient/HandPackArea.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ca2948006648e4e4db48fa099d16fef5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
69
Assets/TcgEngine/Scripts/GameClient/OpponentHand.cs
Normal file
69
Assets/TcgEngine/Scripts/GameClient/OpponentHand.cs
Normal file
@@ -0,0 +1,69 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using TcgEngine.Client;
|
||||
|
||||
namespace TcgEngine.Client
|
||||
{
|
||||
/// <summary>
|
||||
/// Same as HandCardArea but for the opponents hand
|
||||
/// Simpler version with display only (no draging of card)
|
||||
/// </summary>
|
||||
|
||||
public class OpponentHand : MonoBehaviour
|
||||
{
|
||||
public GameObject card_prefab;
|
||||
public RectTransform card_area;
|
||||
public float card_spacing = 100f;
|
||||
public float card_angle = 10f;
|
||||
public float card_offset_y = 10f;
|
||||
|
||||
private List<HandCardBack> cards = new List<HandCardBack>();
|
||||
|
||||
void Start()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
if (!GameClient.Get().IsReady())
|
||||
return;
|
||||
|
||||
Game gdata = GameClient.Get().GetGameData();
|
||||
Player player = gdata.GetPlayer(GameClient.Get().GetOpponentPlayerID());
|
||||
|
||||
if (cards.Count < player.cards_hand.Count)
|
||||
{
|
||||
GameObject new_card = Instantiate(card_prefab, card_area);
|
||||
HandCardBack hand_card = new_card.GetComponent<HandCardBack>();
|
||||
CardbackData cbdata = CardbackData.Get(player.cardback);
|
||||
hand_card.SetCardback(cbdata);
|
||||
RectTransform card_rect = new_card.GetComponent<RectTransform>();
|
||||
card_rect.anchoredPosition = new Vector2(0f, 100f);
|
||||
cards.Add(hand_card);
|
||||
}
|
||||
|
||||
if (cards.Count > player.cards_hand.Count)
|
||||
{
|
||||
HandCardBack card = cards[cards.Count - 1];
|
||||
cards.RemoveAt(cards.Count - 1);
|
||||
Destroy(card.gameObject);
|
||||
}
|
||||
|
||||
int nb_cards = Mathf.Min(cards.Count, player.cards_hand.Count);
|
||||
|
||||
for (int i = 0; i < nb_cards; i++)
|
||||
{
|
||||
HandCardBack card = cards[i];
|
||||
RectTransform crect = card.GetRect();
|
||||
float half = nb_cards / 2f;
|
||||
Vector3 tpos = new Vector3((i - half) * card_spacing, (i - half) * (i - half) * card_offset_y);
|
||||
float tangle = (i - half) * card_angle;
|
||||
crect.anchoredPosition = Vector3.Lerp(crect.anchoredPosition, tpos, 4f * Time.deltaTime);
|
||||
card.transform.localRotation = Quaternion.Slerp(card.transform.localRotation, Quaternion.Euler(0f, 0f, tangle), 4f * Time.deltaTime);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/TcgEngine/Scripts/GameClient/OpponentHand.cs.meta
Normal file
11
Assets/TcgEngine/Scripts/GameClient/OpponentHand.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4ee08f17e9a14a14fa9ceb86cd38989a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
138
Assets/TcgEngine/Scripts/GameClient/PackCard.cs
Normal file
138
Assets/TcgEngine/Scripts/GameClient/PackCard.cs
Normal file
@@ -0,0 +1,138 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using TcgEngine.UI;
|
||||
using TcgEngine.FX;
|
||||
|
||||
namespace TcgEngine.Client
|
||||
{
|
||||
/// <summary>
|
||||
/// Visual representation of a card found in a pack (once opened)
|
||||
/// The card can be flipped by clicking on it
|
||||
/// </summary>
|
||||
|
||||
public class PackCard : MonoBehaviour
|
||||
{
|
||||
public float move_speed = 5f;
|
||||
public float flip_speed = 10f;
|
||||
|
||||
public SpriteRenderer cardback;
|
||||
public CardUI card_ui;
|
||||
|
||||
public GameObject new_card;
|
||||
|
||||
[Header("FX")]
|
||||
public GameObject card_flip_fx;
|
||||
public GameObject card_rare_flip_fx;
|
||||
public AudioClip card_flip_audio;
|
||||
public AudioClip card_rare_flip_audio;
|
||||
|
||||
private CardData icard;
|
||||
private VariantData variant;
|
||||
|
||||
private Vector3 target;
|
||||
private Quaternion rtarget;
|
||||
private bool revealed = false;
|
||||
private bool removed = false;
|
||||
private bool is_new = false;
|
||||
private float timer = 0f;
|
||||
|
||||
private static List<PackCard> card_list = new List<PackCard>();
|
||||
|
||||
void Awake()
|
||||
{
|
||||
card_list.Add(this);
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
card_list.Remove(this);
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
transform.position = Vector3.MoveTowards(transform.position, target, move_speed * Time.deltaTime);
|
||||
|
||||
if (revealed)
|
||||
{
|
||||
timer += Time.deltaTime;
|
||||
transform.rotation = Quaternion.Slerp(transform.rotation, rtarget, flip_speed * Time.deltaTime);
|
||||
}
|
||||
|
||||
if (removed && timer > 4f)
|
||||
Destroy(gameObject);
|
||||
}
|
||||
|
||||
public void SetCard(PackData pack, CardData card, VariantData variant)
|
||||
{
|
||||
this.icard = card;
|
||||
this.variant = variant;
|
||||
|
||||
if (cardback != null)
|
||||
cardback.sprite = pack.cardback_img;
|
||||
|
||||
card_ui.SetCard(card, variant);
|
||||
new_card?.SetActive(false);
|
||||
|
||||
UserData udata = Authenticator.Get().GetUserData();
|
||||
is_new = !udata.HasCard(icard.id, variant.id);
|
||||
}
|
||||
|
||||
public void SetTarget(Vector3 pos)
|
||||
{
|
||||
target = pos;
|
||||
rtarget = Quaternion.Euler(0f, 180f, 0f);
|
||||
transform.rotation = rtarget;
|
||||
}
|
||||
|
||||
public void Reveal()
|
||||
{
|
||||
if (revealed)
|
||||
return;
|
||||
|
||||
revealed = true;
|
||||
rtarget = Quaternion.Euler(0f, 0f, 0f);
|
||||
new_card?.SetActive(is_new);
|
||||
|
||||
if (icard != null && icard.rarity.rank >= 3)
|
||||
{
|
||||
FXTool.DoFX(card_rare_flip_fx, transform.position);
|
||||
AudioTool.Get().PlaySFX("pack_open", card_rare_flip_audio);
|
||||
}
|
||||
else
|
||||
{
|
||||
FXTool.DoFX(card_flip_fx, transform.position);
|
||||
AudioTool.Get().PlaySFX("pack_open", card_flip_audio);
|
||||
}
|
||||
}
|
||||
|
||||
public void Remove()
|
||||
{
|
||||
if (removed)
|
||||
return;
|
||||
|
||||
removed = true;
|
||||
timer = 0f;
|
||||
target = Vector3.up * 10f;
|
||||
}
|
||||
|
||||
public void OnMouseDown()
|
||||
{
|
||||
if (!GameUI.IsOverUILayer("UI"))
|
||||
{
|
||||
Reveal();
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsRevealed()
|
||||
{
|
||||
return revealed && timer > 0.5f;
|
||||
}
|
||||
|
||||
public static List<PackCard> GetAll()
|
||||
{
|
||||
return card_list;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/TcgEngine/Scripts/GameClient/PackCard.cs.meta
Normal file
11
Assets/TcgEngine/Scripts/GameClient/PackCard.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e17031c28aa430e4ab297ac6ff325bfa
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
12
Assets/TcgEngine/Scripts/GameClient/PlayerAttackZone.cs
Normal file
12
Assets/TcgEngine/Scripts/GameClient/PlayerAttackZone.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using TcgEngine.UI;
|
||||
|
||||
namespace TcgEngine.Client
|
||||
{
|
||||
public class PlayerAttackZone1 : MonoBehaviour
|
||||
{
|
||||
//Renamed to BoardSlotPlayer, kept file to override file in update
|
||||
}
|
||||
}
|
||||
11
Assets/TcgEngine/Scripts/GameClient/PlayerAttackZone.cs.meta
Normal file
11
Assets/TcgEngine/Scripts/GameClient/PlayerAttackZone.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9581722b67f7afa49a527eefff1a0084
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
137
Assets/TcgEngine/Scripts/GameClient/PlayerControls.cs
Normal file
137
Assets/TcgEngine/Scripts/GameClient/PlayerControls.cs
Normal file
@@ -0,0 +1,137 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using TcgEngine.Client;
|
||||
using UnityEngine.Events;
|
||||
using TcgEngine.UI;
|
||||
|
||||
namespace TcgEngine.Client
|
||||
{
|
||||
/// <summary>
|
||||
/// Script that contain main controls for clicking on cards, attacking, activating abilities
|
||||
/// Holds the currently selected card and will send action to GameClient on click release
|
||||
/// </summary>
|
||||
|
||||
public class PlayerControls : MonoBehaviour
|
||||
{
|
||||
private BoardCard selected_card = null;
|
||||
|
||||
private static PlayerControls instance;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
instance = this;
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
if (!GameClient.Get().IsReady())
|
||||
return;
|
||||
|
||||
if (Input.GetMouseButtonDown(1))
|
||||
UnselectAll();
|
||||
|
||||
if (selected_card != null)
|
||||
{
|
||||
if (Input.GetMouseButtonUp(0))
|
||||
{
|
||||
ReleaseClick();
|
||||
UnselectAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void SelectCard(BoardCard bcard)
|
||||
{
|
||||
Game gdata = GameClient.Get().GetGameData();
|
||||
Player player = GameClient.Get().GetPlayer();
|
||||
Card card = bcard.GetFocusCard();
|
||||
|
||||
if (gdata.IsPlayerSelectorTurn(player) && gdata.selector == SelectorType.SelectTarget)
|
||||
{
|
||||
if (!Tutorial.Get().CanDo(TutoEndTrigger.SelectTarget, card))
|
||||
return;
|
||||
|
||||
//Target selector, select this card
|
||||
GameClient.Get().SelectCard(card);
|
||||
}
|
||||
else if (gdata.IsPlayerActionTurn(player) && card.player_id == player.player_id)
|
||||
{
|
||||
//Start dragging card
|
||||
selected_card = bcard;
|
||||
}
|
||||
}
|
||||
|
||||
public void SelectCardRight(BoardCard card)
|
||||
{
|
||||
if (!Input.GetMouseButton(0))
|
||||
{
|
||||
//Nothing on right-click
|
||||
}
|
||||
}
|
||||
|
||||
private void ReleaseClick()
|
||||
{
|
||||
bool yourturn = GameClient.Get().IsYourTurn();
|
||||
|
||||
if (yourturn && selected_card != null)
|
||||
{
|
||||
Card card = selected_card.GetCard();
|
||||
Vector3 wpos = GameBoard.Get().RaycastMouseBoard();
|
||||
BSlot tslot = BSlot.GetNearest(wpos);
|
||||
Card target = tslot?.GetSlotCard(wpos);
|
||||
AbilityButton ability = AbilityButton.GetFocus(wpos, 1f);
|
||||
|
||||
if (ability != null && ability.IsInteractable())
|
||||
{
|
||||
if (!Tutorial.Get().CanDo(TutoEndTrigger.CastAbility, card))
|
||||
return;
|
||||
|
||||
GameClient.Get().CastAbility(card, ability.GetAbility());
|
||||
}
|
||||
else if (tslot is BoardSlotPlayer)
|
||||
{
|
||||
if (!Tutorial.Get().CanDo(TutoEndTrigger.AttackPlayer, card))
|
||||
return;
|
||||
|
||||
if (card.exhausted)
|
||||
WarningText.ShowExhausted();
|
||||
else
|
||||
GameClient.Get().AttackPlayer(card, tslot.GetPlayer());
|
||||
}
|
||||
else if (target != null && target.uid != card.uid && target.player_id != card.player_id)
|
||||
{
|
||||
if (!Tutorial.Get().CanDo(TutoEndTrigger.Attack, card) && !Tutorial.Get().CanDo(TutoEndTrigger.Attack, target))
|
||||
return;
|
||||
|
||||
if (card.exhausted)
|
||||
WarningText.ShowExhausted();
|
||||
else
|
||||
GameClient.Get().AttackTarget(card, target);
|
||||
}
|
||||
else if (tslot != null && tslot is BoardSlot)
|
||||
{
|
||||
if (!Tutorial.Get().CanDo(TutoEndTrigger.Move, tslot.GetSlot()))
|
||||
return;
|
||||
|
||||
GameClient.Get().Move(card, tslot.GetSlot());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void UnselectAll()
|
||||
{
|
||||
selected_card = null;
|
||||
}
|
||||
|
||||
public BoardCard GetSelected()
|
||||
{
|
||||
return selected_card;
|
||||
}
|
||||
|
||||
public static PlayerControls Get()
|
||||
{
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/TcgEngine/Scripts/GameClient/PlayerControls.cs.meta
Normal file
11
Assets/TcgEngine/Scripts/GameClient/PlayerControls.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9b1bad97b4da5664eb3a2254097ac000
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
93
Assets/TcgEngine/Scripts/GameClient/RewardManager.cs
Normal file
93
Assets/TcgEngine/Scripts/GameClient/RewardManager.cs
Normal file
@@ -0,0 +1,93 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
|
||||
namespace TcgEngine.Client
|
||||
{
|
||||
//Grants rewards for adventure solo mode
|
||||
|
||||
public class RewardManager : MonoBehaviour
|
||||
{
|
||||
private bool reward_gained = false;
|
||||
|
||||
private static RewardManager instance;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
instance = this;
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
GameClient.Get().onGameEnd += OnGameEnd;
|
||||
}
|
||||
|
||||
void OnGameEnd(int winner)
|
||||
{
|
||||
int player_id = GameClient.Get().GetPlayerID();
|
||||
if (GameClient.game_settings.game_type == GameType.Adventure && winner == player_id)
|
||||
{
|
||||
UserData udata = Authenticator.Get().UserData;
|
||||
LevelData level = LevelData.Get(GameClient.game_settings.level);
|
||||
if (level != null && !udata.HasReward(level.id) && !reward_gained)
|
||||
{
|
||||
if (Authenticator.Get().IsTest())
|
||||
GainRewardTest(level);
|
||||
if (Authenticator.Get().IsApi())
|
||||
GainRewardAPI(level);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async void GainRewardTest(LevelData level)
|
||||
{
|
||||
VariantData variant = VariantData.GetDefault();
|
||||
UserData udata = Authenticator.Get().UserData;
|
||||
udata.coins += level.reward_coins;
|
||||
udata.xp += level.reward_xp;
|
||||
udata.AddReward(level.id);
|
||||
|
||||
foreach (CardData card in level.reward_cards)
|
||||
{
|
||||
udata.AddCard(card.id, variant.id, 1);
|
||||
}
|
||||
|
||||
foreach (PackData pack in level.reward_packs)
|
||||
{
|
||||
udata.AddPack(pack.id, 1);
|
||||
}
|
||||
|
||||
reward_gained = true;
|
||||
await Authenticator.Get().SaveUserData();
|
||||
}
|
||||
|
||||
private async void GainRewardAPI(LevelData level)
|
||||
{
|
||||
bool success = await GainRewardAPI(level.id);
|
||||
reward_gained = success;
|
||||
}
|
||||
|
||||
public async Task<bool> GainRewardAPI(string reward_id)
|
||||
{
|
||||
RewardGainRequest req = new RewardGainRequest();
|
||||
req.reward = reward_id;
|
||||
|
||||
string url = ApiClient.ServerURL + "/users/rewards/gain/" + ApiClient.Get().UserID;
|
||||
string json = ApiTool.ToJson(req);
|
||||
WebResponse res = await ApiClient.Get().SendPostRequest(url, json);
|
||||
Debug.Log("Gain Reward: " + reward_id + " " + res.success);
|
||||
return res.success;
|
||||
}
|
||||
|
||||
public bool IsRewardGained()
|
||||
{
|
||||
return reward_gained;
|
||||
}
|
||||
|
||||
public static RewardManager Get()
|
||||
{
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/TcgEngine/Scripts/GameClient/RewardManager.cs.meta
Normal file
11
Assets/TcgEngine/Scripts/GameClient/RewardManager.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b096db1450456404a90d190fb5e7f3ee
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
43
Assets/TcgEngine/Scripts/GameClient/SceneSettings.cs
Normal file
43
Assets/TcgEngine/Scripts/GameClient/SceneSettings.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace TcgEngine.Client
|
||||
{
|
||||
/// <summary>
|
||||
/// Component added to a scene to add some generic sfx/music to the arena
|
||||
/// </summary>
|
||||
|
||||
public class SceneSettings : MonoBehaviour
|
||||
{
|
||||
public AudioClip start_audio;
|
||||
public AudioClip[] game_music;
|
||||
public AudioClip[] game_ambience;
|
||||
|
||||
private static SceneSettings instance;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
instance = this;
|
||||
}
|
||||
|
||||
void Start()
|
||||
{
|
||||
AudioTool.Get().PlaySFX("game_sfx", start_audio);
|
||||
if (game_music.Length > 0)
|
||||
AudioTool.Get().PlayMusic("music", game_music[Random.Range(0, game_music.Length)]);
|
||||
if (game_ambience.Length > 0)
|
||||
AudioTool.Get().PlaySFX("ambience", game_ambience[Random.Range(0, game_ambience.Length)], 0.5f, true);
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public static SceneSettings Get()
|
||||
{
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/TcgEngine/Scripts/GameClient/SceneSettings.cs.meta
Normal file
11
Assets/TcgEngine/Scripts/GameClient/SceneSettings.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c4bf35dcd0851ff49b983f15c2831e9f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
70
Assets/TcgEngine/Scripts/GameClient/TutoStep.cs
Normal file
70
Assets/TcgEngine/Scripts/GameClient/TutoStep.cs
Normal file
@@ -0,0 +1,70 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using TcgEngine.UI;
|
||||
|
||||
namespace TcgEngine.Client
|
||||
{
|
||||
/// <summary>
|
||||
/// TutoStep inside a group will all be triggered sequentially, game proceed to next step when end_trigger is met, or when another group is triggered
|
||||
/// </summary>
|
||||
|
||||
public class TutoStep : UIPanel
|
||||
{
|
||||
[Header("Tuto Step")]
|
||||
public TutoEndTrigger end_trigger;
|
||||
public CardData trigger_target;
|
||||
public bool forced; //Player MUST do the end_trigger action to proceed
|
||||
|
||||
private TutoStepGroup group;
|
||||
private int step;
|
||||
private TutoBox tuto_box;
|
||||
|
||||
private static List<TutoStep> steps = new List<TutoStep>();
|
||||
|
||||
protected override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
step = transform.GetSiblingIndex();
|
||||
group = GetComponentInParent<TutoStepGroup>();
|
||||
tuto_box = GetComponentInChildren<TutoBox>();
|
||||
steps.Add(this);
|
||||
}
|
||||
|
||||
protected override void Start()
|
||||
{
|
||||
base.Start();
|
||||
tuto_box.SetNextButton(end_trigger == TutoEndTrigger.Click);
|
||||
}
|
||||
|
||||
protected virtual void OnDestroy()
|
||||
{
|
||||
steps.Remove(this);
|
||||
}
|
||||
|
||||
public int GetStepIndex()
|
||||
{
|
||||
return step;
|
||||
}
|
||||
|
||||
public static TutoStep Get(TutoStepGroup group, int step)
|
||||
{
|
||||
foreach (TutoStep s in steps)
|
||||
{
|
||||
if (s.group == group && s.step == step)
|
||||
return s;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void HideAll()
|
||||
{
|
||||
foreach (TutoStep s in steps)
|
||||
{
|
||||
s.Hide();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
11
Assets/TcgEngine/Scripts/GameClient/TutoStep.cs.meta
Normal file
11
Assets/TcgEngine/Scripts/GameClient/TutoStep.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 58b5377c4c00f3e47bb3c3619c915d9f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
69
Assets/TcgEngine/Scripts/GameClient/TutoStepGroup.cs
Normal file
69
Assets/TcgEngine/Scripts/GameClient/TutoStepGroup.cs
Normal file
@@ -0,0 +1,69 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace TcgEngine.Client
|
||||
{
|
||||
/// <summary>
|
||||
/// TutoStep groups do NOT need to be triggered in order, group will be triggered on start_trigger condition
|
||||
/// and then all TutoStep inside group will be executed in order.
|
||||
/// </summary>
|
||||
|
||||
public class TutoStepGroup : MonoBehaviour
|
||||
{
|
||||
public int turn_min = 0;
|
||||
public int turn_max = 99;
|
||||
public TutoStartTrigger start_trigger;
|
||||
public CardData start_target;
|
||||
public bool forced; //Must finish all TutoStep inside group before triggering another group
|
||||
|
||||
private bool triggered = false;
|
||||
|
||||
private static List<TutoStepGroup> groups = new List<TutoStepGroup>();
|
||||
|
||||
protected virtual void Awake()
|
||||
{
|
||||
groups.Add(this);
|
||||
}
|
||||
|
||||
protected virtual void OnDestroy()
|
||||
{
|
||||
groups.Remove(this);
|
||||
}
|
||||
|
||||
public void SetTriggered()
|
||||
{
|
||||
triggered = true;
|
||||
}
|
||||
|
||||
public static TutoStepGroup Get(TutoStartTrigger trigger, int turn)
|
||||
{
|
||||
foreach (TutoStepGroup s in groups)
|
||||
{
|
||||
if (s.start_trigger == trigger && !s.triggered)
|
||||
{
|
||||
if(turn >= s.turn_min&& turn <= s.turn_max)
|
||||
return s;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static TutoStepGroup Get(TutoStartTrigger trigger, CardData target, int turn)
|
||||
{
|
||||
foreach (TutoStepGroup s in groups)
|
||||
{
|
||||
if (s.start_trigger == trigger && !s.triggered)
|
||||
{
|
||||
if (turn >= s.turn_min && turn <= s.turn_max)
|
||||
{
|
||||
if (s.start_target == null || s.start_target == target)
|
||||
return s;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
11
Assets/TcgEngine/Scripts/GameClient/TutoStepGroup.cs.meta
Normal file
11
Assets/TcgEngine/Scripts/GameClient/TutoStepGroup.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dc92c978bda7c8d43ada9d0487c31d1e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
295
Assets/TcgEngine/Scripts/GameClient/Tutorial.cs
Normal file
295
Assets/TcgEngine/Scripts/GameClient/Tutorial.cs
Normal file
@@ -0,0 +1,295 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace TcgEngine.Client
|
||||
{
|
||||
|
||||
public class Tutorial : MonoBehaviour
|
||||
{
|
||||
|
||||
private bool is_tuto = false;
|
||||
private TutoStepGroup current_group;
|
||||
private TutoStep current_step;
|
||||
private bool locked = false;
|
||||
|
||||
private static Tutorial instance;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
instance = this;
|
||||
}
|
||||
|
||||
void Start()
|
||||
{
|
||||
if (GameClient.game_settings.game_type == GameType.Adventure)
|
||||
{
|
||||
LevelData level = GameClient.game_settings.GetLevel();
|
||||
if (level.tuto_prefab != null)
|
||||
{
|
||||
is_tuto = true;
|
||||
|
||||
GameObject tuto_obj = Instantiate(level.tuto_prefab);
|
||||
tuto_obj.GetComponent<Canvas>().worldCamera = GameCamera.GetCamera();
|
||||
|
||||
GameClient.Get().onNewTurn += OnNewTurn;
|
||||
GameClient.Get().onCardPlayed += OnCardPlayed;
|
||||
GameClient.Get().onAttackStart += OnAttack;
|
||||
GameClient.Get().onAttackPlayerStart += OnAttackPlayer;
|
||||
GameClient.Get().onAbilityStart += OnCastAbility;
|
||||
GameClient.Get().onAbilityTargetCard += OnTargetCard;
|
||||
GameClient.Get().onAbilityTargetPlayer += OnTargetPlayer;
|
||||
}
|
||||
|
||||
HideAll();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnNewTurn(int player_id)
|
||||
{
|
||||
Game data = GameClient.Get().GetGameData();
|
||||
if (data == null)
|
||||
return;
|
||||
|
||||
EndGroup();
|
||||
|
||||
if (player_id != GameClient.Get().GetPlayerID())
|
||||
return;
|
||||
|
||||
TutoStepGroup group = TutoStepGroup.Get(TutoStartTrigger.StartTurn, data.turn_count);
|
||||
ShowGroup(group);
|
||||
}
|
||||
|
||||
private void OnCardPlayed(Card card, Slot slot)
|
||||
{
|
||||
Game data = GameClient.Get().GetGameData();
|
||||
if (card.player_id == GameClient.Get().GetPlayerID())
|
||||
{
|
||||
TriggerEndStep(TutoEndTrigger.PlayCard);
|
||||
TriggerStartGroup(TutoStartTrigger.PlayCard, card);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnAttack(Card card, Card target)
|
||||
{
|
||||
Game data = GameClient.Get().GetGameData();
|
||||
if (card.player_id == GameClient.Get().GetPlayerID())
|
||||
{
|
||||
TriggerEndStep(TutoEndTrigger.Attack, 2f);
|
||||
TriggerStartGroup(TutoStartTrigger.Attack, card);
|
||||
TriggerStartGroup(TutoStartTrigger.Attack, target);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnAttackPlayer(Card card, Player target)
|
||||
{
|
||||
Game data = GameClient.Get().GetGameData();
|
||||
if (card.player_id == GameClient.Get().GetPlayerID())
|
||||
{
|
||||
TriggerEndStep(TutoEndTrigger.AttackPlayer, 2f);
|
||||
TriggerStartGroup(TutoStartTrigger.Attack, card);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnCastAbility(AbilityData ability, Card card)
|
||||
{
|
||||
Game data = GameClient.Get().GetGameData();
|
||||
if (card.player_id == GameClient.Get().GetPlayerID())
|
||||
{
|
||||
TriggerEndStep(TutoEndTrigger.CastAbility);
|
||||
TriggerStartGroup(TutoStartTrigger.CastAbility, card);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnTargetCard(AbilityData ability, Card card, Card target)
|
||||
{
|
||||
Game data = GameClient.Get().GetGameData();
|
||||
if (card.player_id == GameClient.Get().GetPlayerID())
|
||||
{
|
||||
TriggerEndStep(TutoEndTrigger.SelectTarget);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnTargetPlayer(AbilityData ability, Card card, Player target)
|
||||
{
|
||||
Game data = GameClient.Get().GetGameData();
|
||||
if (card.player_id == GameClient.Get().GetPlayerID())
|
||||
{
|
||||
TriggerEndStep(TutoEndTrigger.SelectTarget);
|
||||
}
|
||||
}
|
||||
|
||||
public void TriggerEndStep(TutoEndTrigger trigger, float time = 1f)
|
||||
{
|
||||
if (current_step != null && current_step.end_trigger == trigger)
|
||||
{
|
||||
Hide();
|
||||
|
||||
TutoStepGroup group = current_group;
|
||||
locked = true;
|
||||
TimeTool.WaitFor(time, () =>
|
||||
{
|
||||
locked = false;
|
||||
if (group == current_group)
|
||||
{
|
||||
ShowNext();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public void TriggerStartGroup(TutoStartTrigger trigger, Card card)
|
||||
{
|
||||
if (current_group == null || !current_group.forced)
|
||||
{
|
||||
if (current_step == null || !current_step.forced)
|
||||
{
|
||||
CardData target = card != null ? card.CardData : null;
|
||||
ShowGroup(trigger, target);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ShowGroup(TutoStartTrigger trigger, CardData target)
|
||||
{
|
||||
Game data = GameClient.Get().GetGameData();
|
||||
TutoStepGroup group = TutoStepGroup.Get(trigger, target, data.turn_count);
|
||||
ShowGroup(group);
|
||||
}
|
||||
|
||||
public void ShowGroup(TutoStepGroup group)
|
||||
{
|
||||
if (group != null)
|
||||
{
|
||||
current_group = group;
|
||||
group.SetTriggered();
|
||||
TutoStep step = TutoStep.Get(group, 0);
|
||||
Show(step);
|
||||
}
|
||||
}
|
||||
|
||||
public void ShowNext()
|
||||
{
|
||||
if (current_group != null)
|
||||
{
|
||||
int index = GetNextIndex();
|
||||
TutoStep step = TutoStep.Get(current_group, index);
|
||||
if (step != null)
|
||||
Show(step);
|
||||
else
|
||||
EndGroup();
|
||||
}
|
||||
}
|
||||
|
||||
public void Show(TutoStep step)
|
||||
{
|
||||
HideAll();
|
||||
current_step = step;
|
||||
if (step != null)
|
||||
step.Show();
|
||||
}
|
||||
|
||||
public void EndGroup()
|
||||
{
|
||||
HideAll();
|
||||
current_group = null;
|
||||
current_step = null;
|
||||
}
|
||||
|
||||
public void Hide(TutoStep step)
|
||||
{
|
||||
if (step != null)
|
||||
step.Hide();
|
||||
}
|
||||
|
||||
public void Hide()
|
||||
{
|
||||
Hide(current_step);
|
||||
}
|
||||
|
||||
public bool CanDo(TutoEndTrigger trigger)
|
||||
{
|
||||
return CanDo(trigger, null);
|
||||
}
|
||||
|
||||
public bool CanDo(TutoEndTrigger trigger, Slot slot)
|
||||
{
|
||||
Game data = GameClient.Get().GetGameData();
|
||||
Card card = data.GetSlotCard(slot);
|
||||
return CanDo(trigger, card);
|
||||
}
|
||||
|
||||
public bool CanDo(TutoEndTrigger trigger, Card target)
|
||||
{
|
||||
if (!is_tuto)
|
||||
return true; //Not a tutorial
|
||||
|
||||
if (locked)
|
||||
return false;
|
||||
|
||||
if (current_step != null && current_step.forced)
|
||||
{
|
||||
if (trigger == TutoEndTrigger.CastAbility && current_step.end_trigger == TutoEndTrigger.SelectTarget)
|
||||
return true; //Dont get locked into select target if ability was canceled
|
||||
|
||||
if (current_step.end_trigger != trigger)
|
||||
return false; //Wrong trigger
|
||||
|
||||
CardData target_data = target != null ? target.CardData : null;
|
||||
if (current_step.trigger_target != null && current_step.trigger_target != target_data)
|
||||
return false; //Wrong target
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public int GetNextIndex()
|
||||
{
|
||||
if (current_step != null)
|
||||
return current_step.GetStepIndex() + 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
public bool IsTuto()
|
||||
{
|
||||
return is_tuto;
|
||||
}
|
||||
|
||||
public TutoEndTrigger GetEndTrigger()
|
||||
{
|
||||
if (current_step != null)
|
||||
return current_step.end_trigger;
|
||||
return TutoEndTrigger.Click;
|
||||
}
|
||||
|
||||
public void HideAll()
|
||||
{
|
||||
TutoStep.HideAll();
|
||||
}
|
||||
|
||||
public static Tutorial Get()
|
||||
{
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
||||
public enum TutoStartTrigger
|
||||
{
|
||||
StartTurn = 0,
|
||||
PlayCard = 10,
|
||||
Attack = 20,
|
||||
CastAbility = 30,
|
||||
}
|
||||
|
||||
public enum TutoEndTrigger
|
||||
{
|
||||
Click = 0,
|
||||
EndTurn = 5,
|
||||
PlayCard = 10,
|
||||
Move = 15,
|
||||
Attack = 20,
|
||||
AttackPlayer = 25,
|
||||
CastAbility = 30,
|
||||
SelectTarget = 35,
|
||||
}
|
||||
}
|
||||
11
Assets/TcgEngine/Scripts/GameClient/Tutorial.cs.meta
Normal file
11
Assets/TcgEngine/Scripts/GameClient/Tutorial.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b8660c53fc51f6b469daa03c25f99f99
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user