Ссылка на проект в GitHub.
В данной статье хочу разобрать создание змейки.
Первое с чего нужно начать это создать свой класс игры и унаследовать от базового класса Game.
class Snake : Gameв нём уже реализовано игровое поле и события которые возникают при переходе игры из одного состояния в другое. По сути всё что нам нужно сделать это объявить обработку событий.
public Snake() : base()
{
	OnPreview += BasePreview;
	OnNewGame += Snake_OnNewGame;
	OnUpdateGame += Snake_OnUpdateGame;
	OnGameOver += DrawScore;
}Для событий OnPreview и OnGameOver уже есть готовые заглушки в классе Game их можно не реализовывать. Остаётся только инициализировать новую игру и обработать события обновления.
private GameBlock head;
private List<GameBlock> body;
private GameBlock eat;
private void Snake_OnNewGame()
{
	head = new GameBlock()	{ X = 10, Y = 10, Vector = Vector.Up, Color = GameColor.Green };
	body = new List<GameBlock>();
	body.Add( head );
	body.Add( new GameBlock() { X = 10, Y = 11, Vector = Vector.Up, Color = GameColor.Black } );
	body.Add( new GameBlock() { X = 10, Y = 12, Vector = Vector.Up, Color = GameColor.Black } );
	CreateEat();
	DrawField();
}Для отрисовки поля можно работать с ним напрямую, а можно использовать уже готовый класс GameBlock в нём реализованы такие вещи как положение, направление движения и цвет.
В данной функции мы объявили тело змейки, создаём первый кусочек еды и выводим происходящие на поле.
private void CreateEat()
{
	var emptyBlocks = new List<GameBlock>();
	for( int i = 0; i < MainForm.FIELD_SIZE; i++ )
		for( int j = 0; j < MainForm.FIELD_SIZE; j++ )
			if( CheckEmptyBlock( i, j ) )
				emptyBlocks.Add(new GameBlock() { X = i, Y = j, Color = GameColor.Red } );
	if (emptyBlocks.Count > 0)
		eat = emptyBlocks[random.Next( emptyBlocks.Count )];
}Для создания еды мы получаем список пустых блоков и с помощью рандомизатора (который уже объявлен в Game) выбираем случайный. На случай если змейка заняла всё поле стоит проверка на размер списка.
Собственно, функция проверки пустой клетки:
private bool CheckEmptyBlock(int x, int y) => !( x < 0 || y < 0 || x == MainForm.FIELD_SIZE || y == MainForm.FIELD_SIZE ) && !body.Exists( a => a.Equals( new GameBlock() { X = x, Y = y } ) );Отрисовка поля выглядит следующим образом:
private void DrawField()
{
	Field.Clear( GameColor.White );
	Field.DrawGameBlock( eat );
	Field.DrawGameBlocks( body );
	WriteScore();
}Как не трудно догадаться, поле очищается белым цветом и выводятся еда со змеёй. WriteScore ещё одна стандартная функция для вывода счёта в специальную строку состояния.
Итак переходим к событию обновления игры, которое происходит с периодичностью в 300 мс.
private void Snake_OnUpdateGame( Controller controller )
{
	ControlMove( controller.GameKey );
	if( CheckGameOver() )
		GameOver();
	else
		SnakeMove();
}В нём происходит четыре вещи: изменения направления движения, проверка на конец игры, вызов события конца игры и перемещении змеи в случае, если всё в порядке.
private void ControlMove( GameKey key )
{
	switch( key )
	{
		case GameKey.Left:  head.Vector  = head.Vector == Vector.Right ? Vector.Right : Vector.Left;  break;
		case GameKey.Right: head.Vector  = head.Vector == Vector.Left  ? Vector.Left  : Vector.Right; break;
		case GameKey.Up:    head.Vector  = head.Vector == Vector.Down  ? Vector.Down  : Vector.Up;    break;
		case GameKey.Down:  head.Vector  = head.Vector == Vector.Up    ? Vector.Up    : Vector.Down;  break;
		default: break;
	}
}Чтобы изменить направление движения в змейке нам нужно поменять вектор в её голове. Поэтому в контроле движения есть проверка на случай инверсии вектора, для того чтобы змейка не начала залезать сама на себя.
private bool CheckGameOver()
{
	switch( head.Vector )
	{
		case Vector.Up: return !CheckEmptyBlock( head.X, head.Y - 1 );
		case Vector.Down: return !CheckEmptyBlock( head.X, head.Y + 1 );
		case Vector.Left: return !CheckEmptyBlock( head.X - 1, head.Y ); 
		case Vector.Right: return !CheckEmptyBlock( head.X + 1, head.Y );
		default: throw new NotImplementedException();
	}
}Для проверки конца игры достаточно проверить является ли блок по направлению свободным или нет. Как можно догадаться еда в проверке игнорируется.
Осталось разобрать функцию передвижения змейки:
private void SnakeMove()
{
	var temp = body.Last().Copy();
	foreach( var block in body )
		block.Move();
	for( int i = body.Count - 1; i > 0; i-- )
		body[i].Vector = body[i - 1].Vector;
	if( head.Equals( eat ) )
	{
		score++;
		body.Add( temp );
		CreateEat();
	}
	DrawField();
}Конец хвоста копируется для того чтобы в случае, если была достигнута еда добавить его как наращение змеи. Передвинуть блоки не составляет труда, потому что в классе блока уже реализована эта функция. Затем происходит распределение векторов по движению змеи и проверка на пересечение с едой. Если еда найдена счёт инкрементируется, змея увеличивается и создаётся новая еда. Для того чтобы наша игра отобразилась в списке игр, её нужно добавить в инициализацию формы:
List<Game> games = new List<Game>();
games.Add( new Snake() );
games.Add( new Tetris() );
games.Add( new Life() );
Application.Run( new MainForm( games ) );Вот собственно и всё. Весь код игры занял всего 102 строчки. Как можно увидеть из примера в проект уже добавлены тетрис и игра жизнь. Ниже можно ознакомиться с получившемся результатом.

Меню выбора игры

Процесс игры

Конец игры
Комментарии (8)
 - Nidere18.04.2019 21:11- Человек, которому хватит знаний работать с Вашим инструментом, вполне способен обойтись и без него. 
 А выбрав в качестве альтернативы ту же Unity (C# же) — получить в свое распоряжение бесконечно более широкий функционал: хорошо описанный, поддерживаемый и постоянно дорабатывающийся, с которым работают тысячи людей по всему миру.
 
 Вместо того, чтобы учиться работать с вашим инструментом, о котором все забудут через N времени. - EvokSinister19.04.2019 07:12- Соглашусь с вами. Но есть один момент: мне кажется, что данный пример очень прост. Он прост и он может заинтересовать человека, повторившего его, посмотреть что-нибудь посложнее. Скажем, ту же Unity. 
  - virtual_hack2root20.04.2019 09:53- Поэтому недавно я решил написать проект, в котором можно будет писать простенькие игры без каких-либо проблем. 
 В защиту автора, указанный вами движок Unity 3d, не подходит под описание задач, под которые сторился проект, врояд-ли на Unity можно и 300000 строк кода написать что-то стоящее, без дизайнера уровней и анимационной студии в придачу и бюджета на 2-3 миллина долларов, то есть уровень ААА, тут скорее вопрос о создании песочницы для начинающих программистов и среды, состоящей из 50 строк кода. Указанные примеры змейки в 93 байта — это чистая математика, углубленноме изучение команд ассемблера и его side effects, особенностей аппаратной реализации, и кроме того — знание платформы PC XT, ни о каких начинающих прогарммистах и речи быть не может. Основная проблема начинающих программистов — чрезвычайно высокий порог входа, в тот же Unity, сная лишь синтатксис языка, в Unity вы ничего не добьетесь, не понимая принципов ООП, интерфейсы, паттерны посетитель, событие, синглтон, фабрика, фасад. Тут же в статье речь идет об одаренных школьниках начальной школы, скорее, чем о профессиональных разработчиках, для которых интересно поиграться с кодом змейки или тетриса - Nidere20.04.2019 10:43+1- Извиняюсь, а Вы Unity вообще в глаза видели когда-нибудь? 
 Какой еще порог входа?
 На Unity подобные вещи даже обезьяна сделать может — движок именно что облегчает работу. - alex_liebert Автор21.04.2019 09:31- Я использовал Unity и с тезисом про обезьяну не согласен. Движок очень мощный имеет множество настроек и функционала. Возможно, у Вас сложилось такое впечатление из-за готовых уроков на YouTube, но когда ты садишься и хочешь написать свою игру даже такую простую возникает множество вопросов на которые новичку не так просто найти ответы. 
 
 
 
 
           
 

shiru8bit
Игры 'по типу GameBoy' — это скорее Pokemon и прочие полноценные 8-битные игры в портативном формате. А в статье речь скорее идёт про подобие Super Brick Game.
К слову, текущий size coding рекорд по змейке что-то около 93 байт, Тетрис около 140 байт (на ассемблере x86).