diff --git a/Views/GameWindow.xaml b/Views/GameWindow.xaml index 66e917f..4014365 100644 --- a/Views/GameWindow.xaml +++ b/Views/GameWindow.xaml @@ -4,8 +4,8 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" mc:Ignorable="d" - Title="GameWindow" Height="450" Width="800"> - - + Title="GameWindow" Width="{Binding Width}" Height="{Binding Height}" KeyDown="UIElement_OnKeyDown"> + + \ No newline at end of file diff --git a/Views/GameWindow.xaml.cs b/Views/GameWindow.xaml.cs index 2d3ddcf..dda3d64 100644 --- a/Views/GameWindow.xaml.cs +++ b/Views/GameWindow.xaml.cs @@ -1,18 +1,49 @@ -using System.Runtime.InteropServices; +using System; +using System.Runtime.InteropServices; using System.Windows; +using System.Windows.Input; using Tetris.ViewsModels; namespace Tetris.Views; public partial class GameWindow : Window { + private static readonly GameViewModel GameViewModel = new(); + public GameWindow() { AttachConsole(-1); InitializeComponent(); - new GameModel((int)Width, (int)Height, ImageControl); + DataContext = GameViewModel; } [DllImport("kernel32.dll")] private static extern bool AttachConsole(int dwProcessId); + + private void UIElement_OnKeyDown(object sender, KeyEventArgs e) + { + // If key is space + if (e.Key == Key.Space) + { + GameViewModel.Game.CurrentTetrominoe?.RotateRight(); + } + + // If key is down + else if (e.Key == Key.Down) + { + GameViewModel.Game.CurrentTetrominoe?.GoDown(); + } + + // If key is left + else if (e.Key == Key.Left) + { + GameViewModel.Game.CurrentTetrominoe?.GoLeft(); + } + + // If key is right + else if (e.Key == Key.Right) + { + GameViewModel.Game.CurrentTetrominoe?.GoRight(); + } + } } \ No newline at end of file diff --git a/ViewsModels/GameModel.cs b/ViewsModels/GameModel.cs deleted file mode 100644 index 6e8771e..0000000 --- a/ViewsModels/GameModel.cs +++ /dev/null @@ -1,49 +0,0 @@ -using System; -using System.Windows.Controls; -using System.Windows.Media; -using System.Windows.Media.Imaging; -using System.Windows.Threading; - -namespace Tetris.ViewsModels; - -public class GameModel -{ - private const int RendererHertz = 5; - private const int GameRendererHertz = (1 / RendererHertz) * 1000; - private readonly WriteableBitmap _writeableBitmap; - - public GameModel(int width, int height, Image image) - { - _writeableBitmap = BitmapFactory.New(width, height); - image.Source = _writeableBitmap; - - var dispatcherRenderTimer = new DispatcherTimer - { - Interval = new TimeSpan(0, 0, 0, 0, GameRendererHertz) - }; - - dispatcherRenderTimer.Tick += Render; - dispatcherRenderTimer.Start(); - - var dispatcherUpdateTimer = new DispatcherTimer - { - Interval = new TimeSpan(0, 0, 0, 0, 25) - }; - - dispatcherUpdateTimer.Tick += Update; - dispatcherUpdateTimer.Start(); - } - - private void Render(object? sender, EventArgs eventArgs) - { - _writeableBitmap.Lock(); - _writeableBitmap.Clear(Colors.Black); - - _writeableBitmap.Unlock(); - } - - private void Update(object? sender, EventArgs eventArgs) - { - - } -} \ No newline at end of file diff --git a/ViewsModels/GameViewModel.cs b/ViewsModels/GameViewModel.cs new file mode 100644 index 0000000..4d5aac4 --- /dev/null +++ b/ViewsModels/GameViewModel.cs @@ -0,0 +1,96 @@ + + +using System; +using System.ComponentModel; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Threading; +using Tetris.Models; +using Color = System.Drawing.Color; + +namespace Tetris.ViewsModels; + +public class GameViewModel : INotifyPropertyChanged +{ + public event PropertyChangedEventHandler? PropertyChanged; + + public static readonly Game Game = new("...", new Grid(new Color[20, 40])); + + private const int RendererHertz = 5; + private const int GameRendererHertz = (1 / RendererHertz) * 1000; + private const int Multiplier = 10; + private readonly int _width = (Game.Grid.MaxGrid.X + 1) * Multiplier; + private readonly int _height = (Game.Grid.MaxGrid.Y + 1) * Multiplier; + private readonly WriteableBitmap _writeableBitmap; + + public GameViewModel() + { + _writeableBitmap = BitmapFactory.New(_width, _height); + + var dispatcherRenderTimer = new DispatcherTimer + { + Interval = new TimeSpan(0, 0, 0, 0, GameRendererHertz) + }; + + dispatcherRenderTimer.Tick += Render; + dispatcherRenderTimer.Start(); + + var dispatcherUpdateTimer = new DispatcherTimer + { + Interval = new TimeSpan(0, 0, 0, 0, 100) + }; + + dispatcherUpdateTimer.Tick += Update; + dispatcherUpdateTimer.Start(); + } + + public ImageSource Source => _writeableBitmap; + + private void Render(object? sender, EventArgs eventArgs) + { + _writeableBitmap.Lock(); + _writeableBitmap.Clear(Colors.Black); + + var colorGrid = Game.Grid.CGrid; + for (var x = 0; x < Game.Grid.MaxGrid.X + 1; x++) + { + 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 tetrominoeWidth = Game.CurrentTetrominoe?.Shape.GetLength(0); + var tetrominoeHeight = Game.CurrentTetrominoe?.Shape.GetLength(1); + + for (int x = 0; x < tetrominoeWidth; x++) + { + for (int y = 0; y < tetrominoeHeight; y++) + { + var currentPiece = Game.CurrentTetrominoe!; + if (currentPiece.Shape[x, y] == false) continue; + var color = currentPiece.Color; + + var startX = (currentPiece.Coordinates.X + x) * Multiplier; + var startY = (currentPiece.Coordinates.Y + y) * Multiplier; + _writeableBitmap.FillRectangle(startX, startY, startX + Multiplier, startY + Multiplier, color.ToArgb()); + } + } + + _writeableBitmap.Unlock(); + } + + private void Update(object? sender, EventArgs eventArgs) + { + Game.CurrentTetrominoe?.GoDown(); + + if (Game.HitBottom()) + { + Game.PrintTetrominoe(); + } + } +} \ No newline at end of file