проблема с отображением игрового поля
решил написать игру 2048 и получаю следующее при запуске:
[
сделал игру в виде нескольких файлов с использованием Avalonia файл MainWindow.axaml.cs
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Markup.Xaml;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
namespace Game
{
public partial class MainWindow : Window
{
private const int Size = 4;
private int[,] _field;
private int _score;
private Random _random;
private TextBlock? _scoreTextBlock;
public ObservableCollection<GameTile> GameTiles { get; set; }
public MainWindow()
{
InitializeComponent();
DataContext = this;
_random = new Random();
_field = new int[Size, Size];
_scoreTextBlock = this.FindControl<TextBlock>("ScoreTextBlock");
GameTiles = new ObservableCollection<GameTile>();
StartGame();
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
#pragma warning disable CS8622 // Допустимость значений NULL для ссылочных типов в типе параметра не соответствует целевому объекту делегирования (возможно, из-за атрибутов допустимости значений NULL).
this.KeyDown += OnKeyDown;
#pragma warning restore CS8622 // Допустимость значений NULL для ссылочных типов в типе параметра не соответствует целевому объекту делегирования (возможно, из-за атрибутов допустимости значений NULL).
}
private void StartGame()
{
_score = 0;
ClearField();
GameTiles.Clear();
for (int i = 0; i < Size; i++)
{
for (int j = 0; j < Size; j++)
{
GameTiles.Add(new GameTile { Value = _field[i, j] });
}
}
AddNewNumber();
AddNewNumber();
UpdateUI();
}
private void ClearField()
{
for (int i = 0; i < Size; i++)
for (int j = 0; j < Size; j++)
_field[i, j] = 0;
}
private void AddNewNumber()
{
List<(int x, int y)> emptyCells = new List<(int x, int y)>();
for (int i = 0; i < Size; i++)
{
for (int j = 0; j < Size; j++)
{
if (_field[i, j] == 0)
{
emptyCells.Add((i, j));
}
}
}
if (emptyCells.Count > 0)
{
var (x, y) = emptyCells[_random.Next(emptyCells.Count)];
_field[x, y] = _random.NextDouble() < 0.9 ? 2 : 4;
}
}
private bool CanMove()
{
for (int i = 0; i < Size; i++)
{
for (int j = 0; j < Size; j++)
{
if (_field[i, j] == 0) return true;
if (i < Size - 1 && _field[i, j] == _field[i + 1, j]) return true;
if (j < Size - 1 && _field[i, j] == _field[i, j + 1]) return true;
}
}
return false;
}
private void UpdateUI()
{
for (int i = 0; i < Size; i++)
{
for (int j = 0; j < Size; j++)
{
GameTiles[i * Size + j].Value = _field[i, j];
}
}
#pragma warning disable CS8602 // Разыменование вероятной пустой ссылки.
_scoreTextBlock.Text = $"Score: {_score}";
#pragma warning restore CS8602 // Разыменование вероятной пустой ссылки.
}
private void OnKeyDown(object sender, KeyEventArgs e)
{
switch (e.Key)
{
case Key.Left:
MoveLeft();
break;
case Key.Right:
MoveRight();
break;
case Key.Up:
MoveUp();
break;
case Key.Down:
MoveDown();
break;
}
if (CanMove())
{
AddNewNumber();
UpdateUI();
}
else
{
// Game Over Logic
}
}
private void MoveLeft()
{
bool needToAddNewNumber = false;
for (int i = 0; i < Size; i++)
{
for (int j = 1; j < Size; j++)
{
if (_field[i, j] == 0) continue;
int k = j;
while (k > 0 && _field[i, k - 1] == 0)
{
_field[i, k - 1] = _field[i, k];
_field[i, k] = 0;
k--;
needToAddNewNumber = true;
}
if (k > 0 && _field[i, k - 1] == _field[i, k])
{
_field[i, k - 1] *= 2;
_field[i, k] = 0;
_score += _field[i, k - 1];
needToAddNewNumber = true;
}
}
}
if (needToAddNewNumber) AddNewNumber();
}
private void MoveRight()
{
bool needToAddNewNumber = false;
for (int i = 0; i < Size; i++)
{
for (int j = Size - 2; j >= 0; j--)
{
if (_field[i, j] == 0) continue;
int k = j;
while (k < Size - 1 && _field[i, k + 1] == 0)
{
_field[i, k + 1] = _field[i, k];
_field[i, k] = 0;
k++;
needToAddNewNumber = true;
}
if (k < Size - 1 && _field[i, k + 1] == _field[i, k])
{
_field[i, k + 1] *= 2;
_field[i, k] = 0;
_score += _field[i, k + 1];
needToAddNewNumber = true;
}
}
}
if (needToAddNewNumber) AddNewNumber();
}
private void MoveUp()
{
bool needToAddNewNumber = false;
for (int j = 0; j < Size; j++)
{
for (int i = 1; i < Size; i++)
{
if (_field[i, j] == 0) continue;
int k = i;
while (k > 0 && _field[k - 1, j] == 0)
{
_field[k - 1, j] = _field[k, j];
_field[k, j] = 0;
k--;
needToAddNewNumber = true;
}
if (k > 0 && _field[k - 1, j] == _field[k, j])
{
_field[k - 1, j] *= 2;
_field[k, j] = 0;
_score += _field[k - 1, j];
needToAddNewNumber = true;
}
}
}
if (needToAddNewNumber) AddNewNumber();
}
private void MoveDown()
{
bool needToAddNewNumber = false;
for (int j = 0; j < Size; j++)
{
for (int i = Size - 2; i >= 0; i--)
{
if (_field[i, j] == 0) continue;
int k = i;
while (k < Size - 1 && _field[k + 1, j] == 0)
{
_field[k + 1, j] = _field[k, j];
_field[k, j] = 0;
k++;
needToAddNewNumber = true;
}
if (k < Size - 1 && _field[k + 1, j] == _field[k, j])
{
_field[k + 1, j] *= 2;
_field[k, j] = 0;
_score += _field[k + 1, j];
needToAddNewNumber = true;
}
}
}
if (needToAddNewNumber) AddNewNumber();
}
}
}
файл GameTiles.cs
using System.ComponentModel;
namespace Game
{
public class GameTile : INotifyPropertyChanged
{
private int _value;
public int Value
{
get => _value;
set
{
if (_value != value)
{
_value = value;
OnPropertyChanged(nameof(Value));
OnPropertyChanged(nameof(BackgroundColor));
}
}
}
public string BackgroundColor => Value switch
{
2 => "#eee4da",
4 => "#ede0c8",
8 => "#f2b179",
16 => "#f59563",
32 => "#f67c5f",
64 => "#f65e3b",
128 => "#edcf72",
256 => "#edcc61",
512 => "#edc850",
1024 => "#edc53f",
2048 => "#edc22e",
4096 => "#3c3a32",
8192 => "#3c3a33",
16384 => "#3c3a34",
32768 => "#3c3a35",
65536 => "#3c3a36",
131072 => "#3c3a37",
262144 => "#3c3a38",
524288 => "#3c3a39",
1048576 => "#3c3a3a",
2097152 => "#3c3a3b",
4194304 => "#3c3a3c",
8388608 => "#3c3a3d",
16777216 => "#3c3a3e",
33554432 => "#3c3a3f",
67108864 => "#3c3a40",
_ => "#808080", // Фон для значений выше 67108864 или для пустых плиток
};
public event PropertyChangedEventHandler? PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName) =>
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
и файл MainWindow.axaml
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Game"
x:Class="Game.MainWindow"
Title="2048 Game">
<Grid RowDefinitions="Auto, *" ColumnDefinitions="*">
<TextBlock x:Name="ScoreTextBlock"
Grid.Row="0"
HorizontalAlignment="Center"
Margin="10"
FontSize="20"/>
<ItemsControl x:Name="GameBoard"
Grid.Row="1"
ItemsSource="{Binding GameTiles}"
x:DataType="local:MainWindow">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Rows="4" Columns="4"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="local:GameTile">
<Border Background="{Binding BackgroundColor}" Margin="5">
<TextBlock Text="{Binding Value}"
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontSize="24"/>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</Window>
вопрос мой прост, знает может кто как решить проблему(исправление кода)?
Ответы (1 шт):
Автор решения: Cost
→ Ссылка
В данном случае проблема заключается в том, что инициализация свойства GameTiles происходит после вызова метода InitializeComponent. Привязка к этому свойству не произошла. Перенесите инициализацию до вызова InitializeComponent и всё заработает:
public MainWindow()
{
GameTiles = new ObservableCollection<GameTile>();
InitializeComponent();
DataContext = this;
_random = new Random();
_field = new int[Size, Size];
_scoreTextBlock = this.FindControl<TextBlock>("ScoreTextBlock");
StartGame();
}