diff --git a/TestTetris/GridTest.cs b/TestTetris/GridTest.cs index f494d0d..48f0926 100644 --- a/TestTetris/GridTest.cs +++ b/TestTetris/GridTest.cs @@ -133,14 +133,16 @@ public class GridTest { [Test] public void LineFull() { Console.Out.WriteLine(g.ToString()); - Assert.False(g.LineFull()); + Assert.AreEqual(-1, g.LineFull()); + + int line = random.Next(g.MinGrid.Y, g.MaxGrid.Y); for (int x = 0; x < ig.GetLength(0); x++) - ig[x, ig.GetLength(1) - 1] = Color.Aqua; + ig[x, line] = Color.Aqua; Console.Out.WriteLine("=========="); Console.Out.WriteLine(g.ToString()); - Assert.True(g.LineFull()); + Assert.AreEqual(line, g.LineFull()); } [Test] @@ -150,16 +152,17 @@ public class GridTest { ig[x, y] = Color.FromArgb(random.Next(256), random.Next(256), random.Next(256)); } + int line = random.Next(g.MinGrid.Y, g.MaxGrid.Y); for (int x = 0; x < ig.GetLength(0); x++) - ig[x, ig.GetLength(1) - 1] = Color.Aqua; + ig[x, line] = Color.Aqua; Color[,] olg_grid = (Color[,])ig.Clone(); Console.Out.WriteLine(g.ToString()); - g.ClearLine(); + g.ClearLine(line); Console.Out.WriteLine("=========="); Console.Out.WriteLine(g.ToString()); for (uint x = 0; x < ig.GetLength(0); x++) - for (uint y = 1; y < ig.GetLength(1); y++) { + for (uint y = 1; y <= line; y++) { Assert.AreEqual(olg_grid[x, y-1], ig[x,y]); } diff --git a/Tetris/Models/Game.cs b/Tetris/Models/Game.cs index 2a1483f..4411e88 100644 --- a/Tetris/Models/Game.cs +++ b/Tetris/Models/Game.cs @@ -61,12 +61,16 @@ public class Game : INotifyPropertyChanged { return _grid.MinGrid.Y == _currentTetrominoe.Coordinates.Y; } - public bool LineFull() { - return _grid.LineFull(); - } - - public void ClearLine() { - _grid.ClearLine(); + public void ClearLine() + { + int line = _grid.LineFull(); + + while (line != -1) + { + _grid.ClearLine(line); + Score += Grid.CGrid.GetLength(0); + line = _grid.LineFull(); + } } public void PrintTetrominoe() { diff --git a/Tetris/Models/Grid.cs b/Tetris/Models/Grid.cs index 6547716..7d57eab 100644 --- a/Tetris/Models/Grid.cs +++ b/Tetris/Models/Grid.cs @@ -38,18 +38,32 @@ public class Grid { return true; } - public bool LineFull() { - return Enumerable.Range(0, _grid.GetLength(0)).Select(x => _grid[x, MaxGrid.Y]).All(x => x != Color.Empty); + public int LineFull() + { + for (int y = MaxGrid.Y; y > 0; y--) + { + bool full = true; + for (int x = 0; x <= MaxGrid.X; x++) + if (_grid[x, y] == Color.Empty) + { + full = false; + break; + } + if (full) + return y; + } + + return -1; } - public void ClearLine() { - for (int x = 0; x <= MaxGrid.X; x++) - for (int y = MaxGrid.Y; y > 0; y--) { + public void ClearLine(int line) { + for (int x = MinGrid.X; x <= MaxGrid.X; x++) + for (int y = line; y > MinGrid.Y; y--) { _grid[x, y] = _grid[x, y - 1]; } for (int x = 0; x <= MaxGrid.X; x++) - _grid[x,0] = Color.Empty; + _grid[x,MinGrid.Y] = Color.Empty; } public void PrintTetrominoe(Tetrominoe t) { diff --git a/Tetris/Views/GameWindow.xaml b/Tetris/Views/GameWindow.xaml index 135dfac..80015c7 100644 --- a/Tetris/Views/GameWindow.xaml +++ b/Tetris/Views/GameWindow.xaml @@ -6,6 +6,7 @@ mc:Ignorable="d" Title="GameWindow" Width="{Binding Width}" Height="{Binding Height}" KeyDown="UIElement_OnKeyDown"> + \ No newline at end of file diff --git a/Tetris/Views/GameWindow.xaml.cs b/Tetris/Views/GameWindow.xaml.cs index 15494fb..561455f 100644 --- a/Tetris/Views/GameWindow.xaml.cs +++ b/Tetris/Views/GameWindow.xaml.cs @@ -6,13 +6,11 @@ namespace Tetris.Views; public partial class GameWindow { - private static readonly GameViewModel GameViewModel = new(); - public GameWindow() { AttachConsole(-1); InitializeComponent(); - DataContext = GameViewModel; + DataContext = new GameViewModel(); } [DllImport("kernel32.dll")] diff --git a/Tetris/ViewsModels/GameViewModel.cs b/Tetris/ViewsModels/GameViewModel.cs index 215374d..0d64eaf 100644 --- a/Tetris/ViewsModels/GameViewModel.cs +++ b/Tetris/ViewsModels/GameViewModel.cs @@ -2,11 +2,13 @@ using System; using System.ComponentModel; +using System.Windows.Controls; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Threading; using Tetris.Models; using Color = System.Drawing.Color; +using Grid = Tetris.Models.Grid; namespace Tetris.ViewsModels; @@ -14,7 +16,12 @@ public class GameViewModel : INotifyPropertyChanged { public event PropertyChangedEventHandler? PropertyChanged; - public static readonly Game Game = new("...", new Grid(new Color[20, 40])); + protected virtual void OnPropertyChanged(string propertyName) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + + public static readonly Game Game = new("...", new Grid(new Color[15, 30])); private const int RendererHertz = 5; private const int GameRendererHertz = (1 / RendererHertz) * 1000; @@ -22,6 +29,10 @@ public class GameViewModel : INotifyPropertyChanged private readonly int _width = (Game.Grid.MaxGrid.X + 1) * Multiplier; private readonly int _height = (Game.Grid.MaxGrid.Y + 1) * Multiplier; private readonly WriteableBitmap _writeableBitmap; + private readonly int _colorLine = 0xFFFFFF; + private bool _isPaused; + private uint _countDown; + private string _scoreText = ""; public GameViewModel() { @@ -37,7 +48,7 @@ public class GameViewModel : INotifyPropertyChanged var dispatcherUpdateTimer = new DispatcherTimer { - Interval = new TimeSpan(0, 0, 0, 0, 100) + Interval = new TimeSpan(0, 0, 0, 0, 200) }; dispatcherUpdateTimer.Tick += Update; @@ -45,23 +56,38 @@ public class GameViewModel : INotifyPropertyChanged } public ImageSource Source => _writeableBitmap; - public ImageSource RightSource => _writeableBitmap; + + public string ScoreText + { + get => _scoreText; + set + { + _scoreText = value; + OnPropertyChanged("ScoreText"); + } + } private void Render(object? sender, EventArgs eventArgs) { _writeableBitmap.Lock(); _writeableBitmap.Clear(Colors.Black); + ScoreText = "Score: " + Game.Score; var colorGrid = Game.Grid.CGrid; for (var x = 0; x < Game.Grid.MaxGrid.X + 1; x++) { + var startX = x * Multiplier; + var endX = startX + Multiplier; + for (var y = 0; y < Game.Grid.MaxGrid.Y + 1; y++) { - if (colorGrid[x, y] == Color.Empty) continue; - - var startX = x * Multiplier; var startY = y * Multiplier; - _writeableBitmap.FillRectangle(startX, startY, startX + Multiplier, startY + Multiplier, colorGrid[x, y].ToArgb()); + var endY = startY + Multiplier; + + _writeableBitmap.DrawLine(startX, startY, endX, startY, _colorLine); + _writeableBitmap.DrawLine(startX, startY, startX, endY, _colorLine); + if (colorGrid[x, y] == Color.Empty) continue; + _writeableBitmap.FillRectangle(startX, startY, endX, endY, colorGrid[x, y].ToArgb()); } } @@ -81,23 +107,35 @@ public class GameViewModel : INotifyPropertyChanged _writeableBitmap.FillRectangle(startX, startY, startX + Multiplier, startY + Multiplier, color.ToArgb()); } } - + _writeableBitmap.Unlock(); } private void Update(object? sender, EventArgs eventArgs) { + if (_isPaused) + { + return; + } + Game.CurrentTetrominoe?.GoDown(); - + if (Game.HitBottom()) { - Game.PrintTetrominoe(); + if (_countDown >= 3) + { + Game.PrintTetrominoe(); + _countDown = 0; + } + else + _countDown++; } + + Game.ClearLine(); - if (Game.LineFull()) + if (Game.HitTop()) { - Game.ClearLine(); - // TODO: Add score + _isPaused = true; } } } \ No newline at end of file