This commit is contained in:
yaoyanwei
2025-08-04 16:45:48 +08:00
parent 565aa16389
commit 2f2a601227
2296 changed files with 522745 additions and 93 deletions

View File

@@ -0,0 +1,42 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TcgEngine.Client;
namespace TcgEngine.FX
{
/// <summary>
/// The crosshair target that appears when targeting with a spell
/// </summary>
public class AimTargetFX : MonoBehaviour
{
public GameObject fx;
void Start()
{
}
void Update()
{
bool visible = false;
HandCard hcard = HandCard.GetDrag();
if (hcard != null)
{
Card caster = hcard.GetCard();
if (caster.CardData.IsRequireTarget())
visible = true;
}
if (fx.activeSelf != visible)
fx.SetActive(visible);
if (visible)
{
Vector3 dest = GameBoard.Get().RaycastMouseBoard();
transform.position = dest;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5234e6a711e0d54478e776bc62fcb94f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,132 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
namespace TcgEngine.FX
{
/// <summary>
/// Useful tool to define animation sequences
/// </summary>
public class AnimFX : MonoBehaviour
{
private GameObject target;
private float timer = 0f;
private Vector3 start_pos;
private Vector3 current_pos;
private AnimAction current = null;
private Queue<AnimAction> sequence = new Queue<AnimAction>();
void Start()
{
}
void Update()
{
if (target == null)
return;
if (current == null && sequence.Count > 0)
{
current = sequence.Dequeue();
start_pos = target.transform.position;
current_pos = target.transform.position;
timer = 0f;
}
if (current != null)
{
if (timer < current.duration)
{
timer += Time.deltaTime;
if (current.type == AnimActionType.Move)
{
float dist = (current.target_pos - start_pos).magnitude;
float speed = dist / Mathf.Max(current.duration, 0.01f);
current_pos = Vector3.MoveTowards(current_pos, current.target_pos, speed * Time.deltaTime);
transform.position = current_pos;
}
if (current.type == AnimActionType.Size)
{
float dist = Mathf.Abs(transform.localScale.y - current.value);
float speed = dist / Mathf.Max(current.duration, 0.01f);
transform.localScale = Vector3.MoveTowards(transform.localScale, current.value * Vector3.one, speed * Time.deltaTime);
}
}
else
{
current.callback?.Invoke();
current = null;
}
}
}
public void MoveTo(Vector3 pos, float duration)
{
AnimAction action = new AnimAction();
action.type = AnimActionType.Move;
action.duration = duration;
action.target_pos = pos;
sequence.Enqueue(action);
}
public void ScaleTo(float value, float duration)
{
AnimAction action = new AnimAction();
action.type = AnimActionType.Size;
action.duration = duration;
action.value = value;
sequence.Enqueue(action);
}
public void Callback(float duration, UnityAction callback)
{
AnimAction action = new AnimAction();
action.type = AnimActionType.None;
action.duration = duration;
action.callback = callback;
sequence.Enqueue(action);
}
public void Clear()
{
target = null;
timer = 0f;
sequence.Clear();
}
public static AnimFX Create(GameObject target)
{
AnimFX anim = target.GetComponent<AnimFX>();
if (anim == null)
anim = target.AddComponent<AnimFX>();
anim.Clear();
anim.target = target;
return anim;
}
}
public enum AnimActionType
{
None = 0,
Move = 5,
Size = 10,
}
public class AnimAction
{
public AnimActionType type;
public Vector3 target_pos;
public float value = 0f;
public float duration = 1f;
public UnityAction callback = null;
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 20c9606959e055c4fad673809048ddce
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,116 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
namespace TcgEngine.FX
{
/// <summary>
/// Useful tool to define animation sequences on materials
/// </summary>
public class AnimMatFX : MonoBehaviour
{
private Material target;
private float timer = 0f;
private float start_val;
private float current_val;
private AnimMatAction current = null;
private Queue<AnimMatAction> sequence = new Queue<AnimMatAction>();
void Start()
{
}
void Update()
{
if (target == null)
return;
if (current == null && sequence.Count > 0)
{
current = sequence.Dequeue();
start_val = target.GetFloat(current.target_name);
current_val = start_val;
timer = 0f;
}
if (current != null)
{
if (timer < current.duration)
{
timer += Time.deltaTime;
if (current.type == AnimMatActionType.Float)
{
float dist = Mathf.Abs(current.target_value - start_val);
float speed = dist / Mathf.Max(current.duration, 0.01f);
current_val = Mathf.MoveTowards(current_val, current.target_value, speed * Time.deltaTime);
target.SetFloat(current.target_name, current_val);
}
}
else
{
current.callback?.Invoke();
current = null;
}
}
}
public void SetFloat(string name, float value, float duration)
{
AnimMatAction action = new AnimMatAction();
action.type = AnimMatActionType.Float;
action.duration = duration;
action.target_name = name;
action.target_value = value;
sequence.Enqueue(action);
}
public void Callback(float duration, UnityAction callback)
{
AnimMatAction action = new AnimMatAction();
action.type = AnimMatActionType.None;
action.duration = duration;
action.callback = callback;
sequence.Enqueue(action);
}
public void Clear()
{
target = null;
timer = 0f;
sequence.Clear();
}
public static AnimMatFX Create(GameObject obj, Material target)
{
AnimMatFX anim = obj.GetComponent<AnimMatFX>();
if (anim == null)
anim = obj.AddComponent<AnimMatFX>();
anim.Clear();
anim.target = target;
return anim;
}
}
public enum AnimMatActionType
{
None = 0,
Float = 5,
}
public class AnimMatAction
{
public AnimMatActionType type;
public string target_name;
public float target_value;
public float duration = 1f;
public UnityAction callback = null;
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 354b0d285edd22d45843f7aca7f4ac25
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,392 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using TcgEngine.Client;
using UnityEngine.Events;
using TcgEngine;
namespace TcgEngine.FX
{
/// <summary>
/// All FX/anims related to a card on the board
/// </summary>
public class BoardCardFX : MonoBehaviour
{
public Material kill_mat;
public string kill_mat_fade = "noise_fade";
private BoardCard bcard;
private ParticleSystem exhausted_fx = null;
private Dictionary<StatusType, GameObject> status_fx_list = new Dictionary<StatusType, GameObject>();
void Awake()
{
bcard = GetComponent<BoardCard>();
bcard.onKill += OnKill;
}
void Start()
{
GameClient client = GameClient.Get();
client.onCardMoved += OnMove;
client.onCardPlayed += OnPlayed;
client.onCardDamaged += OnCardDamaged;
client.onAttackStart += OnAttack;
client.onAttackPlayerStart += OnAttackPlayer;
client.onAbilityStart += OnAbilityStart;
client.onAbilityTargetCard += OnAbilityEffect;
client.onAbilityEnd += OnAbilityAfter;
OnSpawn();
}
private void OnDestroy()
{
GameClient client = GameClient.Get();
client.onCardMoved -= OnMove;
client.onCardPlayed -= OnPlayed;
client.onCardDamaged -= OnCardDamaged;
client.onAttackStart -= OnAttack;
client.onAttackPlayerStart -= OnAttackPlayer;
client.onAbilityStart -= OnAbilityStart;
client.onAbilityTargetCard -= OnAbilityEffect;
client.onAbilityEnd -= OnAbilityAfter;
}
void Update()
{
if (!GameClient.Get().IsReady())
return;
Card card = bcard.GetCard();
//Status FX
List<CardStatus> status_all = card.GetAllStatus();
foreach (CardStatus status in status_all)
{
StatusData istatus = StatusData.Get(status.type);
if (istatus != null && !status_fx_list.ContainsKey(status.type) && istatus.status_fx != null)
{
GameObject fx = Instantiate(istatus.status_fx, transform);
fx.transform.localPosition = Vector3.zero;
status_fx_list[istatus.effect] = fx;
}
}
//Remove status FX
List<StatusType> remove_list = new List<StatusType>();
foreach (KeyValuePair<StatusType, GameObject> pair in status_fx_list)
{
if (!card.HasStatus(pair.Key))
{
remove_list.Add(pair.Key);
Destroy(pair.Value);
}
}
foreach (StatusType status in remove_list)
status_fx_list.Remove(status);
//Exhausted add/remove
if (exhausted_fx != null && !exhausted_fx.isPlaying && card.exhausted)
exhausted_fx.Play();
if (exhausted_fx != null && exhausted_fx.isPlaying && !card.exhausted)
exhausted_fx.Stop();
}
private void OnSpawn()
{
CardData icard = bcard.GetCardData();
//Spawn Audio
AudioClip audio = icard?.spawn_audio != null ? icard.spawn_audio : AssetData.Get().card_spawn_audio;
AudioTool.Get().PlaySFX("card_spawn", audio);
//Spawn FX
GameObject spawn_fx = icard.spawn_fx != null ? icard.spawn_fx : AssetData.Get().card_spawn_fx;
FXTool.DoFX(spawn_fx, transform.position);
//Spawn dissolve fx
if (GameTool.IsURP())
{
SpriteRenderer render = bcard.card_sprite;
render.material = kill_mat;
FadeSetVal(bcard.card_sprite, 0f);
FadeKill(bcard.card_sprite, 1f, 0.5f);
}
//Exhausted fx
if (AssetData.Get().card_exhausted_fx != null)
{
GameObject efx = Instantiate(AssetData.Get().card_exhausted_fx, transform);
efx.transform.localPosition = Vector3.zero;
exhausted_fx = efx.GetComponent<ParticleSystem>();
}
//Idle status
TimeTool.WaitFor(1f, () =>
{
if (icard.idle_fx != null)
{
GameObject fx = Instantiate(icard.idle_fx, transform);
fx.transform.localPosition = Vector3.zero;
}
});
}
private void OnKill()
{
StartCoroutine(KillRoutine());
}
private IEnumerator KillRoutine()
{
yield return new WaitForSeconds(0.5f);
CardData icard = bcard.GetCardData();
//Death FX
GameObject death_fx = icard.death_fx != null ? icard.death_fx : AssetData.Get().card_destroy_fx;
FXTool.DoFX(death_fx, transform.position);
//Death audio
AudioClip audio = icard?.death_audio != null ? icard.death_audio : AssetData.Get().card_destroy_audio;
AudioTool.Get().PlaySFX("card_spawn", audio);
//Death dissolve fx
if (GameTool.IsURP())
{
FadeKill(bcard.card_sprite, 0f, 0.5f);
}
}
private void FadeSetVal(SpriteRenderer render, float val)
{
render.material = kill_mat;
render.material.SetFloat(kill_mat_fade, val);
}
private void FadeKill(SpriteRenderer render, float val, float duration)
{
AnimMatFX anim = AnimMatFX.Create(render.gameObject, render.material);
anim.SetFloat(kill_mat_fade, val, duration);
}
private void OnMove(Card card, Slot slot)
{
AudioTool.Get().PlaySFX("card_move", AssetData.Get().card_move_audio);
}
private void OnPlayed(Card card, Slot slot)
{
//Playing equipment
Card ecard = bcard?.GetEquipCard();
if (ecard != null && card.uid == ecard.uid && transform != null)
{
FXTool.DoFX(ecard.CardData.spawn_fx, transform.position);
AudioTool.Get().PlaySFX("card_spawn", ecard.CardData.spawn_audio);
}
}
private void OnCardDamaged(Card target, int damage)
{
Card card = bcard.GetCard();
if (card.uid == target.uid && damage > 0)
{
DamageFX(bcard.transform, damage);
}
}
private void OnAttack(Card attacker, Card target)
{
Card card = bcard.GetCard();
CardData icard = bcard.GetCardData();
if (attacker == null || target == null)
return;
if (card.uid == attacker.uid)
{
BoardCard btarget = BoardCard.Get(target.uid);
if (btarget != null)
{
//Card charge into target
ChargeInto(btarget);
//Attack FX and Audio
GameObject fx = icard.attack_fx != null ? icard.attack_fx : AssetData.Get().card_attack_fx;
FXTool.DoSnapFX(fx, transform);
AudioClip audio = icard?.attack_audio != null ? icard.attack_audio : AssetData.Get().card_attack_audio;
AudioTool.Get().PlaySFX("card_attack", audio);
//Equip FX
Card ecard = bcard.GetEquipCard();
if (ecard != null)
{
FXTool.DoFX(ecard.CardData.attack_fx, transform.position);
AudioTool.Get().PlaySFX("card_attack_equip", ecard.CardData.attack_audio);
}
}
}
}
private void OnAttackPlayer(Card attacker, Player player)
{
if (attacker == null || player == null)
return;
Card card = bcard.GetCard();
if (card.uid == attacker.uid)
{
bool is_other = player.player_id != GameClient.Get().GetPlayerID();
CardData icard = bcard.GetCardData();
BoardSlotPlayer zone = BoardSlotPlayer.Get(is_other);
ChargeIntoPlayer(zone);
AudioClip audio = icard?.attack_audio != null ? icard.attack_audio : AssetData.Get().card_attack_audio;
AudioTool.Get().PlaySFX("card_attack", audio);
//Equip FX
Card ecard = bcard.GetEquipCard();
if (ecard != null)
{
FXTool.DoFX(ecard.CardData.attack_fx, transform.position);
AudioTool.Get().PlaySFX("card_attack_equip", ecard.CardData.attack_audio);
}
}
}
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 void ChargeInto(BoardCard target)
{
if (target != null)
{
ChargeInto(target.gameObject);
CardData icard = target.GetCardData();
TimeTool.WaitFor(0.25f, () =>
{
//Damage fx and audio
GameObject prefab = icard.damage_fx ? icard.damage_fx : AssetData.Get().card_damage_fx;
AudioClip audio = icard.damage_audio ? icard.damage_audio : AssetData.Get().card_damage_audio;
FXTool.DoFX(prefab, target.transform.position);
AudioTool.Get().PlaySFX("card_hit", audio);
});
}
}
private void ChargeIntoPlayer(BoardSlotPlayer target)
{
if (target != null)
{
ChargeInto(target.gameObject);
TimeTool.WaitFor(0.25f, () =>
{
//Damage fx and audio
FXTool.DoFX(AssetData.Get().player_damage_fx, target.transform.position);
AudioClip audio = AssetData.Get().player_damage_audio;
AudioTool.Get().PlaySFX("card_hit", audio);
});
}
}
private void ChargeInto(GameObject target)
{
if (target != null)
{
int current_order = bcard.card_sprite.sortingOrder;
Vector3 dir = target.transform.position - transform.position;
Vector3 target_pos = target.transform.position - dir.normalized * 1f;
Vector3 current_pos = transform.position;
bcard.SetOrder(current_order + 10);
AnimFX anim = AnimFX.Create(gameObject);
anim.MoveTo(current_pos - dir.normalized * 0.5f, 0.3f);
anim.MoveTo(target.transform.position, 0.1f);
anim.MoveTo(current_pos, 0.3f);
anim.Callback(0f, () =>
{
if (bcard != null)
bcard.SetOrder(current_order);
});
}
}
private void OnAbilityStart(AbilityData iability, Card caster)
{
if (iability != null && caster != null)
{
if (caster.uid == bcard.GetCardUID())
{
FXTool.DoSnapFX(iability.caster_fx, bcard.transform);
AudioTool.Get().PlaySFX("ability", iability.cast_audio);
}
}
}
private void OnAbilityAfter(AbilityData iability, Card caster)
{
if (iability != null && caster != null)
{
if (caster.uid == bcard.GetCardUID())
{
}
}
}
private void OnAbilityEffect(AbilityData iability, Card caster, Card target)
{
if (iability != null && caster != null && target != null)
{
if (target.uid == bcard.GetCardUID())
{
FXTool.DoSnapFX(iability.target_fx, bcard.transform);
FXTool.DoProjectileFX(iability.projectile_fx, GetFXSource(caster), bcard.transform, iability.GetDamage());
AudioTool.Get().PlaySFX("ability_effect", iability.target_audio);
}
if (caster.uid == bcard.GetCardUID())
{
if (iability.charge_target && caster.CardData.IsBoardCard())
{
BoardCard btarget = BoardCard.Get(target.uid);
ChargeInto(btarget);
}
}
}
}
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;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9e76d90c36735e34db869f5b43cf6118
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,39 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using TcgEngine.UI;
namespace TcgEngine.FX
{
/// <summary>
/// Text number FX that appear when a card receives damage
/// </summary>
public class DamageFX : MonoBehaviour
{
public Text text_value;
void Start()
{
}
void Update()
{
}
public void SetValue(int value)
{
if (text_value != null)
text_value.text = value.ToString();
}
public void SetValue(string value)
{
if (text_value != null)
text_value.text = value;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5888f4bc12bcff04d946a0b498d22820
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,81 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace TcgEngine.FX
{
/// <summary>
/// Dice roll FX, coded for 6 faces only
/// </summary>
public class DiceRollFX : MonoBehaviour
{
public int value;
[Header("Anim")]
public Transform dice;
public float roll_speed = 20f;
public float roll_duration = 1f;
public AudioClip start_audio;
public AudioClip end_audio;
private Vector3[] dir;
private bool ended = false;
private float timer = 0f;
private float x = 0f;
private float y = 0f;
private float z = 0f;
void Start()
{
//Direction of each face
dir = new Vector3[6];
dir[0] = Vector3.forward; //one
dir[1] = Vector3.up; //two
dir[2] = Vector3.right; //three
dir[3] = Vector3.left; //four
dir[4] = Vector3.down; //five
dir[5] = Vector3.back; //six
AudioTool.Get().PlaySFX("dice", start_audio);
}
void Update()
{
timer += Time.deltaTime;
if (!ended)
{
if (timer < roll_duration)
{
x += 5f * Time.deltaTime;
y += 7f * Time.deltaTime;
dice.Rotate(x * roll_speed, y * roll_speed, z * roll_speed, Space.Self);
}
else
{
ended = true;
timer = 0f;
AudioTool.Get().PlaySFX("dice", end_audio);
}
}
if (ended)
{
if (value >= 1 && value <= dir.Length)
{
Vector3 target = dir[value - 1];
Vector3 up = target.y > target.z ? Vector3.back : Vector3.up;
Quaternion trot = Quaternion.LookRotation(target, up);
dice.localRotation = Quaternion.Slerp(dice.localRotation, trot, roll_speed * Time.deltaTime);
}
if (timer > 1f)
{
Destroy(gameObject);
}
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: baa33d0efb908fe4dafe4ffe7d71f3d6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,58 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TcgEngine.Client;
namespace TcgEngine.FX
{
/// <summary>
/// Rotate FX to face camera
/// </summary>
public class FaceFX : MonoBehaviour
{
public FaceType type;
void Start()
{
Vector3 up = GameBoard.Get().transform.up;
if (type == FaceType.FaceCamera)
{
GameCamera cam = GameCamera.Get();
if (cam != null)
{
Vector3 forward = cam.transform.forward;
transform.rotation = Quaternion.LookRotation(forward, up);
}
}
if (type == FaceType.FaceCameraCenter)
{
GameCamera cam = GameCamera.Get();
if (cam != null)
{
Vector3 forward = transform.position - cam.transform.position;
transform.rotation = Quaternion.LookRotation(forward.normalized, up);
}
}
if (type == FaceType.FaceBoard)
{
GameBoard board = GameBoard.Get();
if (board != null)
{
Vector3 forward = board.transform.forward;
transform.rotation = Quaternion.LookRotation(forward, up);
}
}
}
}
public enum FaceType
{
FaceCamera = 0, //Set same rotation as camera rotation
FaceCameraCenter = 5, //Face camera world position
FaceBoard = 10 //Set same rotation as to board rotation
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 16351a71b037e2041a072ebc119b4675
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,86 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TcgEngine.Client;
using TcgEngine.UI;
namespace TcgEngine.FX
{
/// <summary>
/// FX that are not related to any card/player, and appear in the middle of the board
/// Usually when big abilities are played
/// </summary>
public class GameBoardFX : MonoBehaviour
{
void Start()
{
GameClient client = GameClient.Get();
client.onNewTurn += OnNewTurn;
client.onCardPlayed += OnPlayCard;
client.onAbilityStart += OnAbility;
client.onSecretTrigger += OnSecret;
client.onValueRolled += OnRoll;
}
void OnNewTurn(int player_id)
{
AudioTool.Get().PlaySFX("turn", AssetData.Get().new_turn_audio);
FXTool.DoFX(AssetData.Get().new_turn_fx, Vector3.zero);
}
void OnPlayCard(Card card, Slot slot)
{
int player_id = GameClient.Get().GetPlayerID();
if (card != null)
{
CardData icard = CardData.Get(card.card_id);
if (icard.type == CardType.Spell)
{
GameObject prefab = player_id == card.player_id ? AssetData.Get().play_card_fx : AssetData.Get().play_card_other_fx;
GameObject obj = FXTool.DoFX(prefab, Vector3.zero);
CardUI ui = obj.GetComponentInChildren<CardUI>();
ui.SetCard(icard, card.VariantData);
AudioClip spawn_audio = icard.spawn_audio != null ? icard.spawn_audio : AssetData.Get().card_spawn_audio;
AudioTool.Get().PlaySFX("card_spell", spawn_audio);
}
if (icard.type == CardType.Secret)
{
GameObject sprefab = player_id == card.player_id ? AssetData.Get().play_secret_fx : AssetData.Get().play_secret_other_fx;
FXTool.DoFX(sprefab, Vector3.zero);
AudioClip spawn_audio = icard.spawn_audio != null ? icard.spawn_audio : AssetData.Get().card_spawn_audio;
AudioTool.Get().PlaySFX("card_spell", spawn_audio);
}
}
}
private void OnAbility(AbilityData iability, Card caster)
{
if (iability != null)
{
FXTool.DoFX(iability.board_fx, Vector3.zero);
}
}
private void OnSecret(Card secret, Card triggerer)
{
CardData icard = CardData.Get(secret.card_id);
if (icard?.attack_audio != null)
AudioTool.Get().PlaySFX("card_secret", icard.attack_audio);
}
private void OnRoll(int value)
{
GameObject fx = FXTool.DoFX(AssetData.Get().dice_roll_fx, Vector3.zero);
DiceRollFX dice = fx?.GetComponent<DiceRollFX>();
if (dice != null)
{
dice.value = value;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 15640e40e1c85894bad699794f9ef581
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,38 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace TcgEngine.FX
{
/// <summary>
/// FX that appear when hovering a target
/// </summary>
public class HoverFX : MonoBehaviour
{
public GameObject fx;
private bool hover = false;
void Start()
{
}
void Update()
{
if (hover != fx.activeSelf)
fx.SetActive(hover);
}
public void PointerEnter()
{
hover = true;
}
public void PointerExit()
{
hover = false;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 44c3816681df6ac448c1e32f1e9aa34f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,30 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace TcgEngine.FX
{
/// <summary>
/// FX that follows the mouse
/// </summary>
public class MouseFX : MonoBehaviour
{
public float speed = 20f;
void Start()
{
}
// Update is called once per frame
void Update()
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
Plane plane = new Plane(Vector3.forward, 0f);
plane.Raycast(ray, out float dist);
Vector3 tpos = ray.GetPoint(dist);
transform.position = Vector3.Lerp(transform.position, tpos, speed * Time.deltaTime);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 92080fb3b9f31f64e8c0ce65ad64238e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,117 @@
using TcgEngine.Client;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TcgEngine;
namespace TcgEngine.FX
{
/// <summary>
/// Line FX that appear when dragin a board card to attack
/// </summary>
public class MouseLineFX : MonoBehaviour
{
public GameObject dot_template;
public float dot_spacing = 0.2f;
private List<GameObject> dot_list = new List<GameObject>();
private List<Vector3> points = new List<Vector3>();
void Start()
{
dot_template.SetActive(false);
}
void Update()
{
if (!GameClient.Get().IsReady())
return;
RefreshLine();
RefreshRender();
}
private void RefreshLine()
{
points.Clear();
Game gdata = GameClient.Get().GetGameData();
PlayerControls controls = PlayerControls.Get();
BoardCard bcard = controls.GetSelected();
bool visible = false;
Vector3 source = Vector3.zero;
if (bcard != null)
{
source = bcard.transform.position;
visible = true;
}
HandCard drag = HandCard.GetDrag();
if (drag != null)
{
source = drag.transform.position;
visible = drag.GetCardData().IsRequireTarget();
}
if (gdata.selector == SelectorType.SelectTarget && gdata.selector_player_id == GameClient.Get().GetPlayerID())
{
BoardCard caster = BoardCard.Get(gdata.selector_caster_uid);
if (caster != null)
{
source = caster.transform.position;
visible = true;
}
}
if (visible)
{
Vector3 dest = GameBoard.Get().RaycastMouseBoard();
Vector3 dir = (dest - source).normalized;
float dist = (dest - source).magnitude;
float value = 0f;
while (value < dist)
{
Vector3 pos = source + dir * value;
points.Add(pos);
value += dot_spacing;
}
}
}
private void RefreshRender()
{
while (dot_list.Count < points.Count)
{
AddDot();
}
int index = 0;
foreach (GameObject dot in dot_list)
{
bool active = false;
if (index < points.Count)
{
Vector3 pos = points[index];
dot.transform.position = pos;
active = true;
}
if (dot.activeSelf != active)
dot.SetActive(active);
index++;
}
}
public void AddDot()
{
GameObject dot = Instantiate(dot_template, transform);
dot.SetActive(true);
dot_list.Add(dot);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: bdc0cc16f70b4474ea08d8070d6093b8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,104 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TcgEngine.Client;
using TcgEngine.UI;
namespace TcgEngine.FX
{
public class Projectile : MonoBehaviour
{
public float speed = 10f;
public float duration = 4f;
public GameObject explode_fx;
public AudioClip explode_audio;
[HideInInspector]
public int damage; //Damage dealth by projectile, to delay HP display by this amount
private Transform source;
private Transform target;
private Vector3 source_offset;
private Vector3 target_offset;
private float timer = 0f;
public void DelayDamage()
{
BoardCard tcard = target?.GetComponent<BoardCard>();
if (tcard != null)
{
//Delay visual HP so that the HP dont change before projectile hit
tcard.DelayDamage(damage, 8f / speed);
}
BoardSlotPlayer pslot = target?.GetComponent<BoardSlotPlayer>();
if (pslot != null)
{
PlayerUI player_ui = PlayerUI.Get(pslot.GetPlayerID() != GameClient.Get().GetPlayerID());
player_ui.DelayDamage(damage, 8f / speed);
}
}
void Update()
{
timer += Time.deltaTime;
if (source == null || target == null)
{
Destroy(gameObject);
return;
}
if (timer > duration)
{
Destroy(gameObject);
return;
}
Vector3 spos = transform.position;
Vector3 tpos = target.position + target_offset;
Vector3 dir = (tpos - spos);
transform.position += dir.normalized * Mathf.Min(dir.magnitude, 1f) * speed * Time.deltaTime;
transform.rotation = GetFXRotation(dir.normalized);
if (dir.magnitude < 0.2f)
{
FXTool.DoFX(explode_fx, target.position);
AudioTool.Get().PlaySFX("fx", explode_audio);
Destroy(gameObject);
}
}
public void SetSource(Transform source)
{
this.source = source;
transform.position = source.position;
}
public void SetSource(Transform source, Vector3 offset)
{
this.source = source;
source_offset = offset;
transform.position = source.position + source_offset;
}
public void SetTarget(Transform target)
{
this.target = target;
}
public void SetTarget(Transform target, Vector3 offset)
{
this.target = target;
target_offset = offset;
}
private static Quaternion GetFXRotation(Vector3 dir)
{
GameBoard board = GameBoard.Get();
Vector3 facing = board != null ? board.transform.forward : Vector3.forward;
return Quaternion.LookRotation(facing, dir);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9e923cc09c1e58341a5895218219b363
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,32 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace TcgEngine.FX
{
/// <summary>
/// FX that snap to another object (target), and follows it
/// </summary>
public class SnapFX : MonoBehaviour
{
public Transform target;
public Vector3 offset = Vector3.zero;
void Start()
{
}
void Update()
{
if (target == null)
{
Destroy(gameObject);
return;
}
transform.position = target.position + offset;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8867c8a76ca24ac4186efd9cd1e7cb1c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: