从另一个Dll中以Monogame绘制对象

时间:2018-03-16 16:32:27

标签: c# design-patterns monogame

我正在使用.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);
    }
}

谢谢。

2 个答案:

答案 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);
            }
        }  
    }
}