基于MVC的纸牌游戏:如何基于非MonoBehaviour类创建对象?
实现思路与建议
1. 采用分层架构解耦逻辑与视图
将核心游戏逻辑与Unity视图层完全分离:
- 逻辑层:
Card类作为纯数据/逻辑类,只维护卡牌的核心属性(花色、点数、翻面状态、归属标识等),不调用任何Unity API,专注于游戏规则相关的逻辑处理。 - 视图层:创建继承
MonoBehaviour的CardView脚本,挂载在卡牌UI预制体上,负责接收逻辑层的数据并同步UI状态(切换正反面Sprite、调整位置/旋转等)。
2. 通过预制体实例化视图对象
- 先在Unity编辑器中制作卡牌UI预制体,包含显示用的
Image/SpriteRenderer、交互用的Collider等组件,并挂载CardView脚本。 - 当需要基于逻辑层的
Card数据生成场景对象时,用Object.Instantiate()实例化预制体,再通过CardView的绑定方法关联对应的Card实例,完成数据与视图的映射。
示例代码片段:
// 逻辑层纯数据Card类 public class Card { public enum Suit { Hearts, Diamonds, Clubs, Spades } public enum Rank { Ace, Two, ..., King } public Suit CardSuit { get; } public Rank CardRank { get; } public bool IsFaceUp { get; private set; } public Card(Suit suit, Rank rank) { CardSuit = suit; CardRank = rank; IsFaceUp = false; } public void Flip() => IsFaceUp = !IsFaceUp; } // 视图层CardView脚本 public class CardView : MonoBehaviour { [SerializeField] private Sprite faceSprite; [SerializeField] private Sprite backSprite; [SerializeField] private Image cardImage; private Card _logicCard; // 绑定逻辑层Card实例 public void BindToCard(Card logicCard) { _logicCard = logicCard; UpdateVisualState(); } // 同步UI状态 public void UpdateVisualState() { cardImage.sprite = _logicCard.IsFaceUp ? faceSprite : backSprite; // 可扩展:同步位置、缩放、层级等 } } // 控制器类负责实例化与绑定 public class DeckController : MonoBehaviour { [SerializeField] private CardView cardPrefab; [SerializeField] private Transform spawnRoot; private List<Card> _logicDeck = new List<Card>(); void Start() { InitLogicDeck(); SpawnCardViews(); } // 初始化逻辑层卡组 private void InitLogicDeck() { foreach (Card.Suit suit in Enum.GetValues(typeof(Card.Suit))) { foreach (Card.Rank rank in Enum.GetValues(typeof(Card.Rank))) { _logicDeck.Add(new Card(suit, rank)); } } } // 生成所有卡牌视图并绑定 private void SpawnCardViews() { float offsetX = 0.2f; int index = 0; foreach (var logicCard in _logicDeck) { CardView cardView = Instantiate(cardPrefab, spawnRoot.position + new Vector3(index * offsetX, 0, 0), Quaternion.identity); cardView.BindToCard(logicCard); index++; } } }
3. 用事件驱动实现状态自动同步
避免视图层轮询逻辑层数据,给Card类添加事件,当数据变化时触发事件,视图层监听事件并自动更新UI:
public class Card { public event Action OnStateChanged; public bool IsFaceUp { get; private set; } public void Flip() { IsFaceUp = !IsFaceUp; OnStateChanged?.Invoke(); } } // 在CardView中绑定事件 public void BindToCard(Card logicCard) { _logicCard = logicCard; // 先解绑避免重复注册 _logicCard.OnStateChanged -= UpdateVisualState; _logicCard.OnStateChanged += UpdateVisualState; UpdateVisualState(); } void OnDestroy() { if (_logicCard != null) { _logicCard.OnStateChanged -= UpdateVisualState; } }
4. 适配非UI场景的核心优势
由于逻辑层完全独立于Unity的视图组件,你可以直接在机器人逻辑模块等非Unity环境中实例化Card、Deck类,运行洗牌、发牌、规则判断等核心逻辑,无需依赖任何视图代码。当需要同步到UI时,再通过上述绑定机制更新视图即可。
额外优化建议
- 将卡组的洗牌、发牌等逻辑封装在非MonoBehaviour的
Deck类中,仅暴露必要接口给视图控制器调用。 - 逻辑层用抽象坐标(如
Vector2Int表示列/行)管理卡牌位置,视图层将抽象坐标转换为Unity世界空间坐标,进一步解耦位置逻辑。
内容的提问来源于stack exchange,提问作者Eduardo
相关产品推荐
相关产品推荐

