Форум программистов, компьютерный форум, киберфорум
Наши страницы
8Observer8
Войти
Регистрация
Восстановить пароль
Рейтинг: 5.00. Голосов: 1.

How to write a prototype of the Snake Game using C#, WinForms, GDI+

Запись от 8Observer8 размещена 05.02.2019 в 00:28
Обновил(-а) 8Observer8 10.02.2019 в 22:35

Let's make a very simple classic snake game. For example, if we have a snake head with 10x10 pixels then we will move our snake by a step with 10 pixels using timer.

Note. I take ideas from this tutorial: Python Snake Game

We can set a game field size like this:

C#
1
2
// Set a game field size
ClientSize = new Size(200, 200);
Let's create a method for drawing of a rectangle:

C#
1
2
3
4
5
6
7
8
private void DrawRect(int x, int y, Color color, int size = 10)
{
    Graphics g = CreateGraphics();
    SolidBrush brush = new SolidBrush(color);
    g.FillRectangle(brush, new Rectangle(x, y, size, size));
    brush.Dispose();
    g.Dispose();
}
Each game must have a game loop that will be called by timer. I created the GameLoop method that just prints "Hello, World!" to the debug console every 500 ms:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public Form1()
{
    InitializeComponent();
 
    // Set a game field size
    ClientSize = new Size(200, 200);
 
    // Create a timer for the GameLoop method
    var timer = new Timer();
    timer.Tick += GameLoop;
    timer.Interval = 500;
    timer.Start();
}
 
private void GameLoop(object sender, System.EventArgs e)
{
    System.Console.WriteLine("Hello, World!");
}
For a while our GameLoop will have only two called methods Update() and Draw(). The Update() method will have updates for snake cell coordinates and etc. The Draw() method will have only draw methods for game entities.

For example:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
private void GameLoop(object sender, System.EventArgs e)
{
    Update();
    Draw();
}
 
private void Update()
{
    Console.WriteLine("Game entities coords was updated");
}
 
private void Draw()
{
    DrawFood();
    DrawSnake();
}
 
private void DrawSnake()
{
    Console.WriteLine("Snake was drawn");
}
 
private void DrawFood()
{
    Console.WriteLine("Food was drawn");
}
List data structure is ideal for keeping snake cells coordinates:

C#
1
2
3
4
5
// Snake list of (x, y) positions
private List<Point> _snake = new List<Point>()
{
    new Point(10, 10)
};
Point (10, 10) - it is position of the head.

It is better to move a general Draw() method call to Form1_Paint() and add Invalidate() call to GameLoop:

C#
1
2
3
4
5
6
7
8
9
10
private void Form1_Paint(object sender, PaintEventArgs e)
{
    Draw();
}
 
private void GameLoop(object sender, System.EventArgs e)
{
    Update();
    Invalidate();
}
Method for drawing the snake:

C#
1
2
3
4
5
6
7
private void DrawSnake()
{
    foreach (var cell in _snake)
    {
        DrawRect(cell.X, cell.Y, Color.Green);
    }
}
For moving the snake we need to create the "snakeDir" variable:

C#
1
2
// Snake movement direction
private Point _snakeDir = new Point(10, 0);
The snake moving is very simple. Please, read comments:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
private void Update()
{
    // Calc a new position of the head
    Point newHeadPosition = new Point(
        _snake[0].X + _snakeDir.X,
        _snake[0].Y + _snakeDir.Y
    );
 
    // Insert new position in the beginning of the snake list
    _snake.Insert(0, newHeadPosition);
 
    // Remove the last element
    _snake.RemoveAt(_snake.Count - 1);
}
Название: SnakeWinforms_HeadOnly.gif
Просмотров: 301

Размер: 11.4 Кб

I will explain eating food later. But you can read comments in the code.

This is the result:

Название: SnakeWinForms_EatingFood.gif
Просмотров: 294

Размер: 31.1 Кб

Note. I got ideas from this tutorial: Python Snake Game

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
 
namespace Snake
{
    public partial class Form1 : Form
    {
        // Snake list of (x, y) positions
        private List<Point> _snake = new List<Point>()
        {
            new Point(10, 10)
        };
 
        // Snake movement direction
        private Point _snakeDir = new Point(10, 0);
 
        // Food
        private Point _food = new Point();
 
        // Random generator
        private Random _rnd = new Random();
 
        // Game field size
        private int _fieldWidth = 200;
        private int _fieldHeight = 200;
 
        // Snake step
        private int _snakeStep = 10;
 
        public Form1()
        {
            InitializeComponent();
 
            // Centers the form on the current screen
            CenterToScreen();
 
            // Set a game field size
            ClientSize = new Size(_fieldWidth, _fieldHeight);
 
            // Generate an initial random position for the food
            GenerateFood();
 
            // Create a timer for the GameLoop method
            var timer = new Timer();
            timer.Tick += GameLoop;
            timer.Interval = 200;
            timer.Start();
        }
 
        private void Form1_Paint(object sender, PaintEventArgs e)
        {
            Draw();
        }
 
        private void GameLoop(object sender, System.EventArgs e)
        {
            Update();
            Invalidate();
        }
 
        private void Update()
        {
            // Calc a new position of the head
            Point newHeadPosition = new Point(
                _snake[0].X + _snakeDir.X,
                _snake[0].Y + _snakeDir.Y
            );
 
            // Insert new position in the beginning of the snake list
            _snake.Insert(0, newHeadPosition);
 
            // Remove the last element
            _snake.RemoveAt(_snake.Count - 1);
 
            // Check collision with the food
            if (_snake[0].X == _food.X &&
                _snake[0].Y == _food.Y)
            {
                // Add new element in the snake
                _snake.Add(new Point(_food.X, _food.Y));
 
                // Generate a new food position
                GenerateFood();
            }
        }
 
        private void Draw()
        {
            DrawFood();
            DrawSnake();
        }
 
        private void DrawSnake()
        {
            foreach (var cell in _snake)
            {
                DrawRect(cell.X, cell.Y, Color.Green);
            }
        }
 
        private void DrawFood()
        {
            DrawRect(_food.X, _food.Y, Color.OrangeRed);
        }
 
        private void DrawRect(int x, int y, Color color, int size = 10)
        {
            Graphics g = CreateGraphics();
            SolidBrush brush = new SolidBrush(color);
            g.FillRectangle(brush, new Rectangle(x, y, size, size));
            brush.Dispose();
            g.Dispose();
        }
 
        private void GenerateFood()
        {
            _food.X = 10 * _rnd.Next(0, _fieldWidth / 10 - 1);
            _food.Y = 10 * _rnd.Next(0, _fieldHeight / 10 - 1);
        }
 
        private void Form1_KeyPress(object sender, KeyPressEventArgs e)
        {
            switch (e.KeyChar)
            {
                case 'w':
                    _snakeDir.X = 0;
                    _snakeDir.Y = -_snakeStep;
                    break;
                case 'a':
                    _snakeDir.X = -_snakeStep;
                    _snakeDir.Y = 0;
                    break;
                case 's':
                    _snakeDir.X = 0;
                    _snakeDir.Y = _snakeStep;
                    break;
                case 'd':
                    _snakeDir.X = _snakeStep;
                    _snakeDir.Y = 0;
                    break;
            }
        }
    }
}
Размещено в Без категории
Просмотров 187 Комментарии 2
Всего комментариев 2
Комментарии
  1. Старый комментарий
    Аватар для SoftIce
    Цитата:
    C#
    1
    2
    
    // Set a game field size
    ClientSize = new Size(п»ї200, 200);п»ї
    Что это за символы ?
    Запись от SoftIce размещена 05.02.2019 в 06:54 SoftIce вне форума
  2. Старый комментарий
    Аватар для 8Observer8
    I don't know what it is but I copied it again and replaced. Thank you!
    Запись от 8Observer8 размещена 05.02.2019 в 10:50 8Observer8 вне форума
 
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2019, vBulletin Solutions, Inc.
Рейтинг@Mail.ru