feat(): 大量更新

This commit is contained in:
2025-10-15 21:31:13 +08:00
parent 546f08c53a
commit 668bfe12eb
178 changed files with 11318 additions and 446 deletions

View File

@@ -1,7 +0,0 @@
fileFormatVersion: 2
guid: ec826b79cbc40da479bcc7969404880e
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,10 +0,0 @@
using UnityEngine;
using Share;
namespace Card
{
public class CardContext
{
public ICharacter Player;
public ICharacter Target;
}
}

View File

@@ -1,33 +0,0 @@
using UnityEngine;
namespace Card
{
public static class EffectHandler
{
public static void Execute(EffectData effect, CardContext context)
{
switch (effect.type)
{
case EffectType.Damage:
context.Target.TakeDamage(effect.value);
break;
case EffectType.Heal:
context.Target.Heal(effect.value);
break;
case EffectType.DrawCard:
context.Player.Draw(effect.value);
break;
case EffectType.AddBuff:
//TODO:context.Target.AddBuff(effect.value);
break;
default:
Debug.LogWarning($"未知效果类型: {effect.type}");
break;
}
}
}
}

View File

@@ -2,7 +2,6 @@
"name": "Core",
"rootNamespace": "",
"references": [
"GUID:9e4105fe56ff4b1789a1683a3c08d507",
"GUID:75469ad4d38634e559750d17036d5f7c"
],
"includePlatforms": [],

View File

@@ -1,8 +0,0 @@
fileFormatVersion: 2
guid: 656856e514875b444af5c8db9035beea
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: f02de2f72561440b862be76a712a53a6
timeCreated: 1760448092

View File

@@ -0,0 +1,16 @@
using UnityEngine;
namespace Core
{
public interface IInputManager
{
public Vector2 Move { get; }
public Vector2 Look { get; }
public bool JumpPressed { get; }
public bool PausePressed { get; }
public bool InteractPressed { get; }
public void SetCursorState(bool visible, CursorLockMode lockMode);
public void SetInputForLook(bool enabled);
public void SetInputForMove(bool enabled);
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: b077e0f59a474f5a981770fae92ed42f
timeCreated: 1760447509

View File

@@ -25,6 +25,13 @@ namespace Core
private Dictionary<UILayer, Transform> layerRoots = new Dictionary<UILayer, Transform>();
private Dictionary<string, UIBase> openedUIs = new Dictionary<string, UIBase>();
private IInputManager inputManager;
public void RegisterInputManager(IInputManager inputMgr)
{
inputManager = inputMgr;
}
public void RegisterLayer(UILayer layer, Transform root)
{
@@ -122,18 +129,19 @@ namespace Core
private void UpdateCursorState()
{
if(inputManager == null) return;
bool shouldLockCursor = !IsHasNonBackgroundUIActive; //&& !isInMainMenu; // 仅在没有非Background UI且不在主菜单时锁定鼠标
if (shouldLockCursor)
{
InputManager.Instance.SetCursorState(false, CursorLockMode.Locked);
inputManager.SetCursorState(false, CursorLockMode.Locked);
}
else
{
InputManager.Instance.SetCursorState(true, CursorLockMode.None);
inputManager.SetCursorState(true, CursorLockMode.None);
}
InputManager.Instance.SetInputForLook(shouldLockCursor);
InputManager.Instance.SetInputForMove(shouldLockCursor);
inputManager.SetInputForLook(shouldLockCursor);
inputManager.SetInputForMove(shouldLockCursor);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 6da45fd756c6481b8c0cffce4915e971
timeCreated: 1760444989

View File

@@ -1,6 +1,6 @@
using UnityEngine;
namespace Card
namespace Gameplay
{
public class Card
{

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 37e71088bd934b78aa07c7a76b7e5d07
timeCreated: 1760422523

View File

@@ -0,0 +1,48 @@
using System;
using UnityEngine;
namespace Gameplay
{
public class CardBook
{
public CardBookData Data;
public CardSlot[] Slots;
public CardSlot[] Spares;
public CardBook(CardBookData data)
{
Data = data;
Slots = new CardSlot[Data.SlotCount];
Spares = new CardSlot[Data.SpareCount];
for (int i = 0; i < Slots.Length; i++)
{
Slots[i] = new CardSlot();
}
for (int i = 0; i < Spares.Length; i++)
{
Spares[i] = new CardSlot();
}
}
// Get all cards in the card book,and not Spares
public Card[] GetCards()
{
var cards = new Card[Slots.Length + Spares.Length];
for (int i = 0; i < Slots.Length; i++)
{
cards[i] = Slots[i].StoredCard;
}
return cards;
}
public Card[] GetSpareCards()
{
var cards = new Card[Spares.Length + Spares.Length];
for (int i = 0; i < Spares.Length; i++)
{
cards[i] = Spares[i].StoredCard;
}
return cards;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 4bb8bfb17c6a4eaa88954871942ee72d
timeCreated: 1760422530

View File

@@ -0,0 +1,12 @@
using UnityEngine;
namespace Gameplay
{
[CreateAssetMenu(fileName = "CardBookData", menuName = "ScriptableObject/CardBookData", order = 1)]
public class CardBookData : ScriptableObject
{
public int SlotCount;
public int SpareCount;
public int MaxLoopCount;
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 54f1f8ff48b84542962110e7a9851917
timeCreated: 1760422573

View File

@@ -0,0 +1,12 @@
using UnityEngine;
namespace Gameplay
{
// 卡牌书的显示相关脚本
public class CardBookViewer : MonoBehaviour
{
[SerializeField] private Transform LeftHandPoint;
private CardBook CardBook;
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 68803a8f56734f22a3025f8028fc027f
timeCreated: 1760431288

View File

@@ -0,0 +1,23 @@
namespace Gameplay
{
public class CardSlot
{
public Card StoredCard;
public bool IsEmpty => StoredCard == null;
public int ActiveTimes = 0;
public void StoreCard(Card card)
{
StoredCard = card;
ActiveTimes = 0;
}
public Card RemoveCard()
{
var card = StoredCard;
StoredCard = null;
ActiveTimes = 0;
return card;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: e5f566603b3f4286965da48bb49c018a
timeCreated: 1760422548

View File

@@ -2,11 +2,12 @@ using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace Card
namespace Gameplay
{
[CreateAssetMenu(fileName = "NewCard", menuName = "Card/CardData")]
[CreateAssetMenu(fileName = "CardData", menuName = "ScriptableObject/CardData")]
public class CardData : ScriptableObject
{
public int CardID;
public string CardName;
public string CardDescription;
public Texture CardTexture;

View File

@@ -0,0 +1,16 @@
using UnityEngine;
using Share;
namespace Gameplay
{
public class CardContext
{
public ICharacter Owner;
public ICharacter Enemy;
public CardContext(ICharacter owner,ICharacter enemy)
{
Owner = owner;
Enemy = enemy;
}
}
}

View File

@@ -1,6 +1,6 @@
using UnityEngine;
namespace Card
namespace Gameplay
{
[System.Serializable]
public class EffectData
@@ -22,7 +22,5 @@ namespace Card
{
Damage,
Heal,
DrawCard,
AddBuff,
}
}

View File

@@ -0,0 +1,24 @@
using UnityEngine;
namespace Gameplay
{
public static class EffectHandler
{
public static void Execute(EffectData effect, CardContext context)
{
switch (effect.type)
{
case EffectType.Damage:
context.Enemy.TakeDamage(effect.value);
break;
case EffectType.Heal:
context.Enemy.Heal(effect.value);
break;
default:
Debug.Log($"未知效果类型: {effect.type}");
break;
}
}
}
}

View File

@@ -0,0 +1,21 @@
using UnityEngine;
namespace Gameplay
{
// 从Resources文件夹加载卡牌数据的静态类
public static class CardLoader
{
public static CardData GetCardDataByID(int cardID)
{
CardData[] allCards = Resources.LoadAll<CardData>("Configs/Card");
foreach (var card in allCards)
{
if (card.CardID == cardID)
{
return card;
}
}
Debug.LogError($"Card with ID {cardID} not found!");
return null;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 447cd4a06d4a497cb301f68b51a4121a
timeCreated: 1760518833

View File

@@ -1,8 +1,7 @@
using UnityEngine;
using Card;
using UnityEngine.UI;
namespace Card
namespace Gameplay
{
public class CardViewer : MonoBehaviour
{

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 649c2c30ae8a4f64ae00e35a3bf67479
timeCreated: 1760496426

View File

@@ -0,0 +1,176 @@
using System;
using System.Collections;
using Core;
using Gameplay.Enemy;
using Gameplay.Player;
using Share;
using UnityEngine;
namespace Gameplay
{
/// <summary>
/// 战斗流程管理器(回合制、循环抽牌)
/// 使用方法:在场景中挂载一个空物体并配置 player 与 enemy 的 Combatant 引用。
/// 该管理器通过事件回调让 UI 或其它系统接入“双方牌都打空时”的选择(继续/逃跑)。
/// </summary>
public class CombatFlowManager : MonoSingleton<CombatFlowManager>
{
[Header("Participants")]
public PlayerController player;
public EnemyController enemy;
[Header("Flow Settings")]
[Tooltip("玩家是否先手true=玩家先出一张)")]
public bool playerStarts = true;
[Tooltip("每出一张牌后的间隔(秒)")]
public float turnDelay = 0.8f;
// Events
public event Action OnCombatStarted;
public event Action<ICharacter, Card> OnCardPlayed;
public event Action<ICharacter> OnCombatEnded; // 参数为胜利方null 表示平局或逃跑)
public event Action OnBothEmpty; // 当双方都没有卡可以出时触发UI 需要通过 ContinueAfterBothEmpty 或 EscapeFromCombat 响应
// internal state
private Coroutine runningRoutine;
private bool waitingForDecision = false;
private bool decisionContinue = false;
private bool decisionEscape = false;
/// <summary>
/// 启动战斗流程(也可以在 Inspector 中提前绑定 player/enemy然后只调用 StartCombat()
/// </summary>
public void StartCombat(PlayerController playerController = null, EnemyController enemyController = null)
{
if (playerController != null) player = playerController;
if (enemyController != null) enemy = enemyController;
if (player == null || enemy == null)
{
Debug.LogError("CombatFlowManager: player 或 enemy 未设置。");
return;
}
// 初始化双方状态
player.StartCombat();
enemy.StartCombat();
player.InitializeDeckCycle();
enemy.InitializeDeckCycle();
runningRoutine = StartCoroutine(CombatRoutine());
OnCombatStarted?.Invoke();
}
public void StopCombat()
{
if (runningRoutine != null) StopCoroutine(runningRoutine);
runningRoutine = null;
}
private IEnumerator CombatRoutine()
{
ICharacter current = playerStarts ? player : enemy;
while (true)
{
// 结束检查
if (player.IsDead || enemy.IsDead)
{
ICharacter winner = player.IsDead ? enemy : player;
OnCombatEnded?.Invoke(winner);
runningRoutine = null;
yield break;
}
bool playerHas = player.HasCardsLeft();
bool enemyHas = enemy.HasCardsLeft();
if (!playerHas && !enemyHas)
{
// 双方都打空,等待玩家选择(由 UI 调用 ContinueAfterBothEmpty 或 EscapeFromCombat
waitingForDecision = true;
decisionContinue = false;
decisionEscape = false;
OnBothEmpty?.Invoke();
// 等待选择
while (waitingForDecision)
yield return null;
if (decisionEscape)
{
// 玩家选择逃跑 -> 结束战斗,胜者设为 null或按需要设成敌人/玩家)
OnCombatEnded?.Invoke(null);
runningRoutine = null;
yield break;
}
if (decisionContinue)
{
// 重新从卡册读取(重置抽牌队列),保持生命与其它状态不变
player.InitializeDeckCycle();
enemy.InitializeDeckCycle();
// 继续循环(当前先手不变)
yield return null;
continue;
}
}
// 当前回合:如果当前方没有牌则跳过(空过)
if (current.HasCardsLeft())
{
var card = current.GetNextCard();
ICharacter target;
if (current is PlayerController)
{
target = enemy;
}
else
{
target = player;
}
// 触发卡牌效果(当前仅支持直接伤害)
if (card != null)
{
card.PlayCard(new CardContext(current, target));
OnCardPlayed?.Invoke(current, card);
}
// 检查死亡(将在下一循环顶部处理)
yield return new WaitForSeconds(turnDelay);
}
else
{
// 跳过一轮,不延迟太久
yield return new WaitForSeconds(0.1f);
}
// 切换行动方
current = (current == player) ? enemy : player;
}
}
/// <summary>
/// 当双方都打空时UI 调用此方法选择继续下一轮(重新从卡册读取卡牌)
/// </summary>
public void ContinueAfterBothEmpty()
{
if (!waitingForDecision) return;
decisionContinue = true;
waitingForDecision = false;
}
/// <summary>
/// 当双方都打空时UI 调用此方法选择逃跑
/// </summary>
public void EscapeFromCombat()
{
if (!waitingForDecision) return;
decisionEscape = true;
waitingForDecision = false;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 3e8e663fe8d349bea29b9887d29db187
timeCreated: 1760496426

View File

@@ -0,0 +1,49 @@
using System;
using UnityEngine;
using Gameplay;
using Share;
using Gameplay.Enemy;
using Gameplay.Player;
namespace Gameplay.Combat
{
[RequireComponent(typeof(Collider))]
public class CombatTrigger : MonoBehaviour
{
//[Tooltip("战斗管理器引用(场景中单例/对象)")]
private CombatFlowManager combatManager;
[Tooltip("触发时指定的玩家 Combatant可为空manager 使用已配置的)")]
public PlayerController player;
[Tooltip("触发时指定的敌人 Combatant可为空manager 使用已配置的)")]
public EnemyController enemy;
[Tooltip("被触发后是否自动禁用触发器,避免重复触发")]
public bool disableAfterTrigger = true;
private void Start()
{
combatManager = CombatFlowManager.Instance;
}
private void Reset()
{
// Collider 需要 isTrigger
var col = GetComponent<Collider>();
col.isTrigger = true;
}
private void OnTriggerEnter(Collider other)
{
// 简单检测:玩家层或带有 "Player" 标签的物体
if (combatManager == null) return;
if (other.CompareTag("Player") || other.gameObject.layer == LayerMask.NameToLayer("Player"))
{
combatManager.StartCombat(player, enemy);
if (disableAfterTrigger) gameObject.SetActive(false);
}
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 2d9265c2645847c2b5197ed2ba181c98
timeCreated: 1760496463

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 3b712b2fa4f743408e56868a21312535
timeCreated: 1760495486

View File

@@ -0,0 +1,77 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Share;
using UnityEngine;
namespace Gameplay.Enemy
{
public class EnemyController : MonoBehaviour, ICharacter
{
[SerializeField] private string enemyName;
[SerializeField] private int maxHealth = 100;
public int MaxHealth => maxHealth;
public int CurrentHealth { get; set; }
[SerializeField] private CardBookData cardBookData;
private CardBook myCardBook;
private List<Card> cards;
private int currentCardIndex = 0;
public bool IsFlight { get; private set; }
public bool IsDead { get; private set; }
private void Awake()
{
CurrentHealth = MaxHealth;
myCardBook = new CardBook(cardBookData);
cards = new List<Card>();
}
public void TakeDamage(int damage)
{
CurrentHealth -= damage;
}
public void Heal(int heal)
{
CurrentHealth += heal;
if (CurrentHealth > MaxHealth)
{
CurrentHealth = MaxHealth;
}
}
public void StartCombat()
{
Debug.Log($"{name} Enemy Start Combat");
IsFlight = false;
}
public void EndFlight()
{
Debug.Log($"{name} Enemy End Flight");
IsFlight = true;
}
public bool HasCardsLeft()
{
return currentCardIndex < cards.Count;
}
public Card GetNextCard()
{
if (!HasCardsLeft())
{
return null;
}
return cards[currentCardIndex++];
}
public void InitializeDeckCycle()
{
cards = myCardBook.GetCards().ToList();
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: b5a587a681ae48d6b3a5dcd5a723fd5a
timeCreated: 1760512105

View File

@@ -1,9 +1,10 @@
{
"name": "Card",
"name": "Gameplay",
"rootNamespace": "",
"references": [
"GUID:fd0e97c21c15497f9406b8ee23c1f67e",
"GUID:9e4105fe56ff4b1789a1683a3c08d507"
"GUID:75469ad4d38634e559750d17036d5f7c",
"GUID:f51ebe6a0ceec4240a699833d6309b23"
],
"includePlatforms": [],
"excludePlatforms": [],

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: ceb6a2c14699464ca35be17af198f904
timeCreated: 1760445049

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 1c652418c7ff4cb9be7aa23ec423c5f9
timeCreated: 1760447326

View File

@@ -1,16 +1,19 @@
using System;
using UnityEngine;
using UnityEngine.InputSystem;
using Core;
namespace Core
namespace Input
{
public class InputManager : MonoSingleton<InputManager>
public class InputManager : MonoSingleton<InputManager>, IInputManager
{
private PlayerInputActions _input; // 自动生成的输入类
// 当前输入值
public Vector2 Move { get; private set; }
public Vector2 Look { get; private set; }
public bool JumpPressed { get; private set; }
public bool PausePressed { get; private set; }
public bool InteractPressed { get; private set; }
private void Awake()
{
@@ -27,11 +30,15 @@ namespace Core
_input.Player.Look.performed += ctx => Look = ctx.ReadValue<Vector2>();
_input.Player.Look.canceled += ctx => Look = Vector2.zero;
//
// _input.Player.Jump.performed += ctx => JumpPressed = true;
// _input.Player.Jump.canceled += ctx => JumpPressed = false;
//
_input.Player.Jump.performed += ctx => JumpPressed = true;
_input.Player.Jump.canceled += ctx => JumpPressed = false;
// _input.Player.Pause.performed += ctx => PausePressed = true;
// _input.Player.Pause.canceled += ctx => PausePressed = false;
_input.Player.Interact.performed += ctx => InteractPressed = true;
_input.Player.Interact.canceled += ctx => InteractPressed = false;
}
private void OnDisable()
@@ -39,6 +46,11 @@ namespace Core
_input.Disable();
}
private void Start()
{
UIManager.Instance.RegisterInputManager(this);
}
private void Update()
{
// 在此更新一次性触发的输入,例如“按下瞬间触发”

View File

@@ -15,7 +15,7 @@ using System.Collections.Generic;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Utilities;
namespace Core
namespace Input
{
public partial class @PlayerInputActions: IInputActionCollection2, IDisposable
{
@@ -31,12 +31,12 @@ namespace Core
""actions"": [
{
""name"": ""Move"",
""type"": ""Button"",
""type"": ""Value"",
""id"": ""cba876cd-5594-42ac-a4b0-2f2ed0f0e120"",
""expectedControlType"": """",
""expectedControlType"": ""Vector2"",
""processors"": """",
""interactions"": """",
""initialStateCheck"": false
""initialStateCheck"": true
},
{
""name"": ""Look"",
@@ -46,28 +46,123 @@ namespace Core
""processors"": """",
""interactions"": """",
""initialStateCheck"": true
},
{
""name"": ""Jump"",
""type"": ""Button"",
""id"": ""850284f0-b2d8-412c-9970-c1a7256e29de"",
""expectedControlType"": """",
""processors"": """",
""interactions"": """",
""initialStateCheck"": false
},
{
""name"": ""Interact"",
""type"": ""Button"",
""id"": ""b405cb77-699f-4558-831a-c6c12a5c0300"",
""expectedControlType"": """",
""processors"": """",
""interactions"": """",
""initialStateCheck"": false
}
],
""bindings"": [
{
""name"": """",
""id"": ""dab4d8f6-9492-4327-8944-76f09907ba54"",
""id"": ""d7c34f0b-b18e-4498-8d3e-1bdec4cb355d"",
""path"": ""<Mouse>/delta"",
""interactions"": """",
""processors"": """",
""groups"": """",
""action"": ""Look"",
""isComposite"": false,
""isPartOfComposite"": false
},
{
""name"": ""2D Vector"",
""id"": ""132c4a80-d02d-43c4-bf7b-8e0ff43a44de"",
""path"": ""2DVector"",
""interactions"": """",
""processors"": """",
""groups"": """",
""action"": ""Move"",
""isComposite"": true,
""isPartOfComposite"": false
},
{
""name"": ""up"",
""id"": ""a4d4ec38-2560-46b0-b57b-d9ea0f35d701"",
""path"": ""<Keyboard>/w"",
""interactions"": """",
""processors"": """",
""groups"": """",
""action"": ""Move"",
""isComposite"": false,
""isPartOfComposite"": true
},
{
""name"": ""down"",
""id"": ""f1c59ea2-0648-4f49-8cfb-d566be529303"",
""path"": ""<Keyboard>/s"",
""interactions"": """",
""processors"": """",
""groups"": """",
""action"": ""Move"",
""isComposite"": false,
""isPartOfComposite"": true
},
{
""name"": ""left"",
""id"": ""529b3ae4-cbf4-412c-a783-5bf62c57de72"",
""path"": ""<Keyboard>/a"",
""interactions"": """",
""processors"": """",
""groups"": """",
""action"": ""Move"",
""isComposite"": false,
""isPartOfComposite"": true
},
{
""name"": ""right"",
""id"": ""57ddd6bd-cbf7-4cfb-98d3-5b4458a21562"",
""path"": ""<Keyboard>/d"",
""interactions"": """",
""processors"": """",
""groups"": """",
""action"": ""Move"",
""isComposite"": false,
""isPartOfComposite"": true
},
{
""name"": """",
""id"": ""b6a61d59-edf3-4759-8791-8967ffa1e187"",
""path"": ""<Keyboard>/space"",
""interactions"": """",
""processors"": """",
""groups"": """",
""action"": ""Jump"",
""isComposite"": false,
""isPartOfComposite"": false
},
{
""name"": """",
""id"": ""d7c34f0b-b18e-4498-8d3e-1bdec4cb355d"",
""path"": ""<Mouse>/position"",
""id"": ""c7bb1d3e-20de-4ff9-96fc-bfc70ca54e20"",
""path"": ""<Keyboard>/f"",
""interactions"": """",
""processors"": """",
""groups"": """",
""action"": ""Look"",
""action"": ""Interact"",
""isComposite"": false,
""isPartOfComposite"": false
},
{
""name"": """",
""id"": ""ab4a9194-7003-42f9-a13b-f6edf0427a6e"",
""path"": ""<Mouse>/leftButton"",
""interactions"": """",
""processors"": """",
""groups"": """",
""action"": ""Interact"",
""isComposite"": false,
""isPartOfComposite"": false
}
@@ -80,6 +175,8 @@ namespace Core
m_Player = asset.FindActionMap("Player", throwIfNotFound: true);
m_Player_Move = m_Player.FindAction("Move", throwIfNotFound: true);
m_Player_Look = m_Player.FindAction("Look", throwIfNotFound: true);
m_Player_Jump = m_Player.FindAction("Jump", throwIfNotFound: true);
m_Player_Interact = m_Player.FindAction("Interact", throwIfNotFound: true);
}
~@PlayerInputActions()
@@ -148,12 +245,16 @@ namespace Core
private List<IPlayerActions> m_PlayerActionsCallbackInterfaces = new List<IPlayerActions>();
private readonly InputAction m_Player_Move;
private readonly InputAction m_Player_Look;
private readonly InputAction m_Player_Jump;
private readonly InputAction m_Player_Interact;
public struct PlayerActions
{
private @PlayerInputActions m_Wrapper;
public PlayerActions(@PlayerInputActions wrapper) { m_Wrapper = wrapper; }
public InputAction @Move => m_Wrapper.m_Player_Move;
public InputAction @Look => m_Wrapper.m_Player_Look;
public InputAction @Jump => m_Wrapper.m_Player_Jump;
public InputAction @Interact => m_Wrapper.m_Player_Interact;
public InputActionMap Get() { return m_Wrapper.m_Player; }
public void Enable() { Get().Enable(); }
public void Disable() { Get().Disable(); }
@@ -169,6 +270,12 @@ namespace Core
@Look.started += instance.OnLook;
@Look.performed += instance.OnLook;
@Look.canceled += instance.OnLook;
@Jump.started += instance.OnJump;
@Jump.performed += instance.OnJump;
@Jump.canceled += instance.OnJump;
@Interact.started += instance.OnInteract;
@Interact.performed += instance.OnInteract;
@Interact.canceled += instance.OnInteract;
}
private void UnregisterCallbacks(IPlayerActions instance)
@@ -179,6 +286,12 @@ namespace Core
@Look.started -= instance.OnLook;
@Look.performed -= instance.OnLook;
@Look.canceled -= instance.OnLook;
@Jump.started -= instance.OnJump;
@Jump.performed -= instance.OnJump;
@Jump.canceled -= instance.OnJump;
@Interact.started -= instance.OnInteract;
@Interact.performed -= instance.OnInteract;
@Interact.canceled -= instance.OnInteract;
}
public void RemoveCallbacks(IPlayerActions instance)
@@ -200,6 +313,8 @@ namespace Core
{
void OnMove(InputAction.CallbackContext context);
void OnLook(InputAction.CallbackContext context);
void OnJump(InputAction.CallbackContext context);
void OnInteract(InputAction.CallbackContext context);
}
}
}

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: ff05c86378543b94488d735aea6436d1
guid: 3112886b43bfe4d40bf728a52f00436c
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 6407e403d6f34e658b36489eb9954344
timeCreated: 1760445405

View File

@@ -0,0 +1,28 @@
using System;
using UnityEngine;
using Gameplay;
using System.Collections.Generic;
namespace Share
{
/// <summary>
/// 角色接口可受伤害、治疗和添加Buff、发生战斗
/// 拥有卡牌书
/// </summary>
public interface ICharacter
{
// public int MaxHealth { get; }
// public int CurrentHealth { get; }
// public CardBook CardBook { get; }
// public List<Card> Cards { get; }
public bool IsFlight { get; }
public bool IsDead { get; }
public void TakeDamage(int damage);
public void Heal(int heal);
public void StartCombat();
public void EndFlight();
public bool HasCardsLeft();
public Card GetNextCard();
public void InitializeDeckCycle();
}
}

View File

@@ -0,0 +1,9 @@
using UnityEngine;
namespace Share
{
public interface IInteractable
{
string GetInteractPrompt(); // 返回提示文字例如“按E打开门”
void Interact(GameObject interactor); // 当玩家交互时触发
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 3bb60830b6e14df78b72c49d9250fa75
timeCreated: 1760444920

View File

@@ -0,0 +1,10 @@
using UnityEngine;
using Share;
namespace Map
{
public class FlightTrigger : MonoBehaviour
{
[SerializeField] public ICharacter Player;
[SerializeField] public ICharacter Enemy;
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 5e697dc78ed84a3ab2e921a57c17be95
timeCreated: 1760495479

View File

@@ -0,0 +1,20 @@
using UnityEngine;
using System;
namespace Map
{
public class MapFlag : MonoBehaviour
{
public string FlagName;
public Vector3 Position;
public MapFlag ParentFlag;
public MapFlag LeftFlag;
public MapFlag RightFlag;
public event Action<MapFlag> OnPlayerEnter;
private void OnTriggerEnter(Collider other)
{
OnPlayerEnter?.Invoke(this);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 2c3ea88c92cc4d0bb6098983903be7fb
timeCreated: 1760444130

View File

@@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Core;
using UnityEngine;
namespace Map
{
public class MapFlagManager : MonoSingleton<MapFlagManager>
{
public MapFlag StartFlag;
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: f13be1e244e84e3b93b0b3a4c054cb46
timeCreated: 1760424376

View File

@@ -1,13 +1,13 @@
using Core;
using UnityEngine;
using Input;
namespace Player
namespace Gameplay.Player
{
/// <summary>
/// 玩家第一人称相机控制器
/// 挂到相机或相机父物体playerBody 指向角色的根 Transform用于左右旋转
/// </summary>
/// TODO:使用InputManager替换掉Input.GetAxis
public class PlayerCameraController : MonoBehaviour
{
[Header("References")]

View File

@@ -0,0 +1,9 @@
using UnityEngine;
namespace Gameplay.Player
{
public class PlayerConfig : MonoBehaviour
{
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 6ff9e093e80541dc93d1186499dbfd79
timeCreated: 1760498762

View File

@@ -0,0 +1,92 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Gameplay;
using Share;
using UnityEngine;
using Core;
namespace Gameplay.Player
{
public class PlayerController : MonoBehaviour, ICharacter
{
public int MaxHealth { get; set; } = 100;
public int CurrentHealth { get; private set; }
[SerializeField] private CardBookData cardBookData;
public CardBook MyCardBook { get; private set; }
public List<Card> Cards { get; private set; }
private int currentCardIndex = 0;
public bool IsFlight { get; private set; }
public bool IsDead { get; private set; }
private PlayerMoveController playerMoveController;
private PlayerCameraController playerCameraController;
private void Awake()
{
playerMoveController = GetComponent<PlayerMoveController>();
playerCameraController = GetComponent<PlayerCameraController>();
CurrentHealth = MaxHealth;
MyCardBook = new CardBook(cardBookData);
Cards = new List<Card>();
UIViewerControllerLocator.Instance.Register(this);
}
private void Start()
{
}
public void TakeDamage(int damage)
{
CurrentHealth -= damage;
}
public void Heal(int heal)
{
CurrentHealth += heal;
if (CurrentHealth > MaxHealth)
{
CurrentHealth = MaxHealth;
}
}
public void StartCombat()
{
Debug.Log("Player StartCombat");
IsFlight = true;
playerMoveController.SetSpeed(0.5f);
}
public void EndFlight()
{
Debug.Log("Player EndFlight");
IsFlight = false;
playerMoveController.ResetSpeed();
}
public bool HasCardsLeft()
{
return currentCardIndex < Cards.Count;
}
public Card GetNextCard()
{
if (!HasCardsLeft())
{
return null;
}
return Cards[currentCardIndex++];
}
public void InitializeDeckCycle()
{
Cards = MyCardBook.GetCards().ToList();
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: d7071907d14f433789ea37a8367b584a
timeCreated: 1760495717

View File

@@ -0,0 +1,58 @@
using UnityEngine;
using Share;
using System;
using Input;
namespace Gameplay.Player
{
public class PlayerInteractorController : MonoBehaviour
{
[SerializeField] private float interactRange = 15f;
[SerializeField] private LayerMask interactableLayer;
[SerializeField] private Camera playerCamera;
private IInteractable currentTarget;
void Start()
{
playerCamera = GameObject.FindWithTag("MainCamera").GetComponent<Camera>();
}
void Update()
{
DetectInteractable();
if (currentTarget != null && InputManager.Instance.InteractPressed)
{
currentTarget.Interact(this.gameObject);
}
}
void DetectInteractable()
{
Ray ray = new Ray(playerCamera.transform.position, playerCamera.transform.forward);
if (Physics.Raycast(ray, out RaycastHit hit, interactRange, interactableLayer))
{
currentTarget = hit.collider.GetComponent<IInteractable>();
if (currentTarget != null)
{
// 这里可以显示交互提示UI例如 “E - 开门”
Debug.Log(currentTarget.GetInteractPrompt());
}
}
else
{
currentTarget = null;
}
}
void OnDrawGizmos()
{
if (playerCamera == null) return;
Gizmos.color = Color.green;
Vector3 origin = playerCamera.transform.position;
Vector3 direction = playerCamera.transform.forward * interactRange;
Gizmos.DrawLine(origin, origin + direction);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: dc03712b5c254b8380471356f3bac151
timeCreated: 1760516273

View File

@@ -0,0 +1,89 @@
using System;
using Core;
using Input;
using Map;
using UnityEngine;
namespace Gameplay.Player
{
public class PlayerMoveController : MonoBehaviour
{
[Header("Movement Settings")]
[Tooltip("移动速度(米/秒)")]
public float speed = 5f;
[Tooltip("跳跃高度(米)")]
public float jumpHeight = 2f;
[Tooltip("重力加速度(米/秒²)")]
public float gravity = -9.81f;
[Header("Ground Check")]
[Tooltip("检测地面的位置(通常为角色脚下)")]
public Transform groundCheck;
[Tooltip("地面检测半径")]
public float groundDistance = 0.4f;
[Tooltip("地面层LayerMask")]
public LayerMask groundMask;
private float initSpeed;
private CharacterController characterController;
private Vector3 velocity;
private bool isGrounded;
private IInputManager inputManager;
private void Awake()
{
characterController = GetComponent<CharacterController>();
if (characterController == null)
Debug.LogError("PlayerMoveController 需要 CharacterController 组件!");
initSpeed = speed;
}
private void Start()
{
inputManager = InputManager.Instance;
}
private void Update()
{
// 地面检测
if (groundCheck != null)
isGrounded = Physics.CheckSphere(groundCheck.position, groundDistance, groundMask);
else
isGrounded = characterController.isGrounded;
if (isGrounded && velocity.y < 0)
velocity.y = -2f; // 保持贴地
Vector2 inputMove = inputManager.Move;
// 获取输入
float x = inputMove.x;
float z = inputMove.y;
// 按玩家朝向移动
Vector3 move = transform.right * x + transform.forward * z;
characterController.Move(move * speed * Time.deltaTime);
// 跳跃
if (isGrounded && inputManager.JumpPressed)
{
velocity.y = Mathf.Sqrt(jumpHeight * -2f * gravity);
}
// 重力
velocity.y += gravity * Time.deltaTime;
characterController.Move(velocity * Time.deltaTime);
}
public void SetSpeed(float newSpeed)
{
speed = newSpeed;
}
public void ResetSpeed()
{
speed = initSpeed;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 14c86d6b22344680a9eba4de056d3b53
timeCreated: 1760424128

View File

@@ -1,3 +0,0 @@
{
"name": "Map"
}

View File

@@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: ccba5c55d09a415a94ff4a5e6375019a
timeCreated: 1760362986

View File

@@ -1,3 +0,0 @@
{
"name": "Player"
}

View File

@@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: f9c4db94c16f41feaa2a3b1ea6785a04
timeCreated: 1760362801

View File

@@ -1,9 +0,0 @@
using UnityEngine;
namespace Player
{
public class PlayerMoveController : MonoBehaviour
{
}
}

View File

@@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 6025e0f3c5664b9c8c01a994fb1e0620
timeCreated: 1760362812

View File

@@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 05474807e682482694deb13b21e1bdfb
timeCreated: 1760361359

View File

@@ -1,15 +0,0 @@
using UnityEngine;
namespace Share
{
/// <summary>
/// 角色接口可受伤害、治疗和添加Buff
/// </summary>
public interface ICharacter
{
public void TakeDamage(int damage);
public void Heal(int heal);
public void AddBuff(string buffName, int duration);
public void Draw(int count);
}
}

View File

@@ -1,3 +0,0 @@
{
"name": "Share"
}

View File

@@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 9e4105fe56ff4b1789a1683a3c08d507
timeCreated: 1760361379

View File

@@ -0,0 +1,32 @@
using System;
using Core;
using Gameplay.Player;
using UnityEngine;
using UnityEngine.UI;
namespace UI
{
public class PlayerHpViewer : UIBase
{
private PlayerController _playerController;
public Text hpText;
private void Start()
{
UIViewerControllerLocator.Instance.TryGetWait<PlayerController>(OnGet);
}
private void Update()
{
if (_playerController != null)
{
hpText.text = "HP: " + _playerController.CurrentHealth;
}
}
private void OnGet(PlayerController playerController)
{
_playerController = playerController;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: a450025fc367419faaf7481787bfac88
timeCreated: 1760514338

View File

@@ -2,9 +2,8 @@
"name": "UI",
"rootNamespace": "",
"references": [
"GUID:ec826b79cbc40da479bcc7969404880e",
"GUID:fd0e97c21c15497f9406b8ee23c1f67e",
"GUID:9e4105fe56ff4b1789a1683a3c08d507"
"GUID:ceb6a2c14699464ca35be17af198f904"
],
"includePlatforms": [],
"excludePlatforms": [],