Как спроектировать слой View при разработке игры Snake с использованием MVVM в WPF? - PullRequest
0 голосов
/ 07 мая 2019

Я пытаюсь разработать игру со змеями в WPF, используя MVVM, https://github.com/Moore0/SnakeForWPF, у меня возникли проблемы при разработке слоя View

В слое View я использую ListBox в качестве контейнера, ItemSource привязывается к фоновому источнику данных, задает ItemsPanel ListBox для UniformGrid, задаю для DataTemplate Border для каждого квадрата и связываю строки и столбцы платы с UniformGrid. .Rows и UniformGrid.Columns.

<ListBox x:Name="lv"  
        IsEnabled="False" 
        HorizontalContentAlignment="Stretch" 
        VerticalContentAlignment="Stretch" 
        BorderThickness="0" 
        Padding="0"
        ItemContainerStyle="{StaticResource ListBoxForSnakePanelStyle}">
    <ListBox.ItemsSource>
        <!--Entity type design flaws, where multiple parameters must be passed in (but not important)...-->                               
        <MultiBinding Converter="{converters:ItemSourceConverter}">
            <Binding Path="SnakeNodes" />
            <Binding Path="LineX" />
            <Binding Path="LineY" />
            <Binding Path="FoodPoint" />
        </MultiBinding>
    </ListBox.ItemsSource>

    <ListBox.ItemTemplate>
        <DataTemplate>
            <Border Margin="1" Background="{Binding BlockType,Converter={converters:BlockBrushConverter}}">
            </Border>
        </DataTemplate>
    </ListBox.ItemTemplate>

    <ListBox.ItemsPanel>
        <ItemsPanelTemplate>
            <UniformGrid Rows="{Binding LineY}" Columns="{Binding LineX}" Background="{StaticResource BackgroundLightBrush}"/>
        </ItemsPanelTemplate>
    </ListBox.ItemsPanel>
</ListBox>

Я думаю, что это довольно неохотно. Есть ли лучший способ спроектировать слой View (который максимально ограничен XAML)

1 Ответ

2 голосов
/ 07 мая 2019

Вот очень быстрая реализация решения на основе Canvas, о котором я упоминал в комментариях. Конечно, для превращения этой игры в реально работоспособную игру потребуется больше работы, но, похоже, она прекрасно справляется с дисплеем.

GameVm содержит модель представления для текущей игры. Он отслеживает ширину и высоту доски, а также любые «сущности», которые в данный момент находятся в игре. Это включает в себя различные сегменты змеиной части, а также пищевые гранулы.

XAML - это, по сути, ItemsControl, привязанный к свойству Entities игры. Он выбирает визуальный элемент на основе шаблона, определяемого типом объекта. Я просто использовал текстовые символы, но вы можете легко заменить их на изображения. ItemsControl размещается внутри Canvas, а ContentPresenter каждого элемента оформляется так, чтобы позиционировать его на Canvas на основе свойств X и Y сущности.

Я бы, вероятно, подумал о том, чтобы изменить это, чтобы использовать индексы столбцов / строк, а не "пиксельные" координаты, с ValueConverter для преобразования их в пиксели для простоты.

Просмотр моделей:

class MainWindowVm
{
    public MainWindowVm()
    {
        Game = new GameVm(20, 20);
    }

    public GameVm Game { get; }
}

class GameVm : ViewModel
{
    public GameVm(int width, int height)
    {
        Width = width;
        Height = height;
        Entities = new ObservableCollection<GameEntity>();

        Entities.Add(new SnakeHead() { X = 20, Y = 20 });
        Entities.Add(new SnakeBody() { X = 30, Y = 20 });
        Entities.Add(new SnakeBody() { X = 40, Y = 20 });
        Entities.Add(new SnakeTail() { X = 40, Y = 30 });

        Entities.Add(new Food() { X = 0, Y = 0 });
        Entities.Add(new Food() { X = 60, Y = 20 });
        Entities.Add(new Food() { X = 50, Y = 50 });
        Entities.Add(new Food() { X = 10, Y = 80 });

    }

    public ObservableCollection<GameEntity> Entities { get; }

    private int _width;

    public int Width
    {
        get => _width;
        set => SetValue(ref _width, value);
    }

    private int _height;

    public int Height
    {
        get => _height;
        set => SetValue(ref _height, value);
    }
    }

abstract class GameEntity : ViewModel
{
    private int _x;

    public int X
    {
        get => _x;
        set => SetValue(ref _x, value);
    }

    private int _y;

    public int Y
    {
        get => _y;
        set => SetValue(ref _y, value);
    }
}

abstract class SnakeSegment : GameEntity { }

class SnakeBody : SnakeSegment { }

class SnakeHead : SnakeSegment { }

class SnakeTail : SnakeSegment { }

class Food : GameEntity { }

XAML:

<Window x:Class="Snake.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:Snake"
        mc:Ignorable="d"

        Title="MainWindow" Height="450" Width="800">
    <Window.DataContext>
        <local:MainWindowVm />
    </Window.DataContext>
    <ItemsControl ItemsSource="{Binding Path=Game.Entities}">
        <ItemsControl.Resources>
            <DataTemplate DataType="{x:Type local:SnakeHead}">
                <TextBlock Text="%" />
            </DataTemplate>
            <DataTemplate DataType="{x:Type local:SnakeBody}">
                <TextBlock Text="#" />
            </DataTemplate>
            <DataTemplate DataType="{x:Type local:SnakeTail}">
                <TextBlock Text="." />
            </DataTemplate>
            <DataTemplate DataType="{x:Type local:Food}">
                <TextBlock Text="O" />
            </DataTemplate>
        </ItemsControl.Resources>
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <Canvas />
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemContainerStyle>
            <Style TargetType="ContentPresenter">
                <Setter Property="Canvas.Top" Value="{Binding Path=X}" />
                <Setter Property="Canvas.Left" Value="{Binding Path=Y}" />
            </Style>
        </ItemsControl.ItemContainerStyle>
    </ItemsControl>
</Window>

Он производит следующий вывод: enter image description here

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...