using Snake.Model; using Snake.Persistance; namespace view { public partial class Form1 : Form { Graphics graphics; int line_width = 2; SnakeLevel? CurrentLevel; SnakeLevelLoader level_loader; public Form1() { InitializeComponent(); graphics = Canvas.CreateGraphics(); level_loader = new SnakeLevelLoader(Path.Combine(Directory.GetCurrentDirectory(), "levels.json")); } private void Form1_KeyDown(object sender, KeyEventArgs e) { if (CurrentLevel == null) return; switch (e.KeyCode) { case Keys.Up: CurrentLevel.SnakeHeadDirection = SnakeLevel.SnakeDirection.Up; break; case Keys.Down: CurrentLevel.SnakeHeadDirection = SnakeLevel.SnakeDirection.Down; break; case Keys.Left: CurrentLevel.SnakeHeadDirection = SnakeLevel.SnakeDirection.Left; break; case Keys.Right: CurrentLevel.SnakeHeadDirection = SnakeLevel.SnakeDirection.Right; break; case Keys.Escape: if(CurrentLevel.State == SnakeLevel.GameState.Running) CurrentLevel.Pause(); break; } } private void Draw(SnakeLevel level) { var canvas_size = Math.Min(Canvas.Width, Canvas.Height); graphics = Canvas.CreateGraphics(); graphics.Clear(Color.White); double cell_size = (double)(canvas_size - (level.Size + 1) * line_width) / level.Size; // vertical lines for (int i = 0; i <= level.Size; i++) { int x = (int)(i * (cell_size + line_width)); graphics.FillRectangle(Brushes.Black, x, 0, line_width, canvas_size); } // horizontal lines for (int i = 0; i <= level.Size; i++) { int y = (int)(i * (cell_size + line_width)); graphics.FillRectangle(Brushes.Black, 0, y, canvas_size, line_width); } // Ssnake foreach (var pos in level.Snake) { int x = (int)(cell_size * pos.X + line_width * (pos.X + 1)); int y = (int)(cell_size * pos.Y + line_width * (pos.Y + 1)); graphics.FillRectangle(Brushes.Green, x, y, (int)cell_size, (int)cell_size); } // snake head int snake_head_x = (int)(cell_size * level.SnakeHead.X + line_width * (level.SnakeHead.X + 1)); int snake_head_y = (int)(cell_size * level.SnakeHead.Y + line_width * (level.SnakeHead.Y + 1)); graphics.FillRectangle(Brushes.Red, snake_head_x, snake_head_y, (int)cell_size, (int)cell_size); switch (level.SnakeHeadDirection) { case SnakeLevel.SnakeDirection.Up: graphics.DrawLine(Pens.Black, snake_head_x + (int)cell_size / 2, snake_head_y, snake_head_x + (int)cell_size / 2, snake_head_y + (int)cell_size); graphics.DrawLine(Pens.Black, snake_head_x + (int)cell_size / 2, snake_head_y, snake_head_x, snake_head_y + (int)cell_size / 2); graphics.DrawLine(Pens.Black, snake_head_x + (int)cell_size / 2, snake_head_y, snake_head_x + (int)cell_size, snake_head_y + (int)cell_size / 2); break; case SnakeLevel.SnakeDirection.Down: graphics.DrawLine(Pens.Black, snake_head_x + (int)cell_size / 2, snake_head_y, snake_head_x + (int)cell_size / 2, snake_head_y + (int)cell_size); graphics.DrawLine(Pens.Black, snake_head_x + (int)cell_size / 2, snake_head_y + (int)cell_size, snake_head_x, snake_head_y + (int)cell_size / 2); graphics.DrawLine(Pens.Black, snake_head_x + (int)cell_size / 2, snake_head_y + (int)cell_size, snake_head_x + (int)cell_size, snake_head_y + (int)cell_size / 2); break; case SnakeLevel.SnakeDirection.Left: graphics.DrawLine(Pens.Black, snake_head_x, snake_head_y + (int)cell_size / 2, snake_head_x + (int)cell_size, snake_head_y + (int)cell_size / 2); graphics.DrawLine(Pens.Black, snake_head_x, snake_head_y + (int)(cell_size / 2), snake_head_x + (int)(cell_size / 2), snake_head_y); graphics.DrawLine(Pens.Black, snake_head_x, snake_head_y + (int)(cell_size / 2), snake_head_x + (int)(cell_size / 2), snake_head_y + (int)cell_size); break; case SnakeLevel.SnakeDirection.Right: graphics.DrawLine(Pens.Black, snake_head_x, snake_head_y + (int)cell_size / 2, snake_head_x + (int)cell_size, snake_head_y + (int)cell_size / 2); graphics.DrawLine(Pens.Black, snake_head_x + (int)cell_size, snake_head_y + (int)(cell_size / 2), snake_head_x + (int)(cell_size / 2), snake_head_y); graphics.DrawLine(Pens.Black, snake_head_x + (int)cell_size, snake_head_y + (int)(cell_size / 2), snake_head_x + (int)(cell_size / 2), snake_head_y + (int)cell_size); break; } // obstacles foreach (var pos in level.Obstacles) { int x = (int)(cell_size * pos.X + line_width * (pos.X + 1)); int y = (int)(cell_size * pos.Y + line_width * (pos.Y + 1)); graphics.FillRectangle(Brushes.Black, x, y, (int)cell_size, (int)cell_size); } //eggs foreach (var pos in level.Eggs) { int x = (int)(cell_size * pos.X + line_width * (pos.X + 1)); int y = (int)(cell_size * pos.Y + line_width * (pos.Y + 1)); graphics.FillRectangle(Brushes.Pink, x, y, (int)cell_size, (int)cell_size); } } private void btnStart_Click(object sender, EventArgs e) { if (CurrentLevel is null || CurrentLevel.State == SnakeLevel.GameState.Dead) { var MapChooser = new MapChooser(this.level_loader); MapChooser.ShowDialog(); if (MapChooser.SelectedLevel != null) { CurrentLevel = level_loader.LoadLevel(MapChooser.SelectedLevel); CurrentLevel.GameStateUpdate += CurrentLevel_GameStateUpdate; CurrentLevel.GameUpdate += CurrentLevel_GameUpdate; } else { CurrentLevel = null; } } if (CurrentLevel != null) { CurrentLevel.Start(); this.Focus(); } } private void CurrentLevel_GameUpdate(object? sender, EventArgs e) { this.Invoke(() => { if (CurrentLevel != null) { Draw(CurrentLevel); txtScore.Text = CurrentLevel.Score.ToString(); } }); } private void CurrentLevel_GameStateUpdate(object? sender, SnakeLevel.GameState e) { this.Invoke(() => { if (CurrentLevel == null) return; switch (e) { case SnakeLevel.GameState.Running: btnStart.Visible = false; Draw(CurrentLevel); break; case SnakeLevel.GameState.Paused: btnStart.Visible = true; break; case SnakeLevel.GameState.Dead: btnStart.Visible = true; MessageBox.Show($"Skill issue.\nScore: {CurrentLevel.Score}", "Snake", MessageBoxButtons.OK, MessageBoxIcon.Information); break; } }); } private void Form1_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e) { if(CurrentLevel?.State is SnakeLevel.GameState.Running) { e.IsInputKey = true; } } } }