我正在使用.NET Standard和Monogame创建一个纸牌游戏。我在dll中创建并测试了游戏的核心(PlayingCards.Common.Dll)。
我现在需要添加一个GUI层,并且遇到设计问题。
例如,我的卡类位于PlayingCards.Common.Dll中。 GUI需要使用此播放器卡,但添加纹理,位置和可能的更新。
我知道我可以使用装饰器模式并创建一个持有卡的GuiCard和GUI所需的额外功能但是当我的经销商类向用户交付卡时(因为这是在核心中完成的)他们只会收到一张卡而不是一张GuiCard。
玩家类还包含手,其中包含x个卡,因此在绘制Gui时我需要以某种方式为所有玩家绘制所有牌....
感兴趣的课程:
public class Card
{
...
public Card(Suit suit, Value value)
{
Suit = suit;
Value = value;
...
}
}
public class Dealer
{
private readonly Deck _deck = new Deck();
...
private Card DealCard() => _deck.Draw();
}
//This is in GUI.DLL
public class CardEntity
{
...
private readonly Position _position;
private readonly Card _card = new Card(Suit.Spades, Value.King);
public CardEntity(GraphicsDevice graphicsDevice, Card card)
{
_position = new Position();
...
}
public void Draw(SpriteBatch spriteBatch)
{
var topLeftOfSprite = new Vector2(_position.X, _position.Y);
var sourceRectangle = new Rectangle
{
X = XPosOnSpriteSheet,
Y = YPosOnSpriteSheet,
Height = CardTextureHeight,
Width = CardTextureWidth - Offset
};
spriteBatch.Draw(_cardsSheetTexture, topLeftOfSprite, sourceRectangle, XnaColor.White);
}
}
谢谢。
答案 0 :(得分:1)
设计问题有很多可能的答案。如果你想要一个好的答案,可能值得refining your question更具体。
然而,我确实发现了一件可以清楚回答的事情。
我知道我可以使用装饰器模式并创建一个持有卡的GuiCard和GUI所需的额外功能但是当我的经销商类向用户交付卡时(因为这是在核心中完成的)他们只会收到一张卡而不是一张GuiCard。
装饰器模式中缺少的东西来自基类。在大多数示例中,他们使用抽象基类或接口。
因此,在您的特定情况下,类应该看起来更像这样:
public abstract class Card
{
public Card(Suit suit, Value value)
{
Suit = suit;
Value = value;
}
public abstract Suit Suit { get; }
public abstract Value Value { get; }
}
public class CardEntity : Card
{
private readonly Position _position;
private readonly Card _card;
public CardEntity(GraphicsDevice graphicsDevice, Card card)
{
_position = new Position();
_card = card;
}
public Suit Suit => _card.Suit;
public Value Value => _card.Value;
public void Draw(SpriteBatch spriteBatch)
{
var topLeftOfSprite = new Vector2(_position.X, _position.Y);
var sourceRectangle = new Rectangle
{
X = XPosOnSpriteSheet,
Y = YPosOnSpriteSheet,
Height = CardTextureHeight,
Width = CardTextureWidth - Offset
};
spriteBatch.Draw(_cardsSheetTexture, topLeftOfSprite, sourceRectangle, XnaColor.White);
}
}
请记住,这将通过使用装饰器模式解决问题,但它仍然可能不是正确的设计选择。装饰器模式带来了开销,最终迫使您实现更多的代码。
如果您正在寻找可能有用的更多设计模式,我会在一段时间后阅读一本名为Game Programming Patterns的好书。作者甚至免费提供web version:)
答案 1 :(得分:0)
在本周末阅读并测试了多种设计模式后,我使用了访客模式。
我的卡和手实施 IVisitable 和接受方法。
我的访问者然后访问所有卡片,并拥有绘制卡片的所有逻辑。这意味着我可以完全分离任何对象和可绘制组件的关注点,并且非常可靠。这将在未来分离更新逻辑,因为我将简单地创建一个新的UpdateVisitor。
以下访客代码,如果有人有兴趣:
using System.Collections.Generic;
...
namespace ...
{
public class CardDrawingVisitor : Visitor
{
private readonly SpriteBatch _spriteBatch;
private readonly PngHandler _cardPng;
private readonly Stack<Card> _result = new Stack<Card>();
public CardDrawingVisitor(GraphicsDevice graphicsDevice, SpriteBatch spriteBatch)
{
_spriteBatch = spriteBatch;
_cardPng = new PngHandler(graphicsDevice, "cards");
}
public override void Visit(Card card)
{
_result.Push(card);
}
public void Draw()
{
var cardNumber = 0;
foreach (var card in _result)
{
_cardPng.Draw(_spriteBatch, card, cardNumber++, 0);
}
}
}
}