Форум программистов, компьютерный форум, киберфорум
C# Windows Forms
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.91/70: Рейтинг темы: голосов - 70, средняя оценка - 4.91
0 / 0 / 0
Регистрация: 06.05.2019
Сообщений: 1

Генерация проходимого лабиринта для игры

06.05.2019, 17:12. Показов 13950. Ответов 8

Студворк — интернет-сервис помощи студентам
помогите пожалуйста я написал часть игры лабиринт надо чтобы он генерировался случайно но был проходим. там должны быть еда стены и враги и сам герой. вот что пока есть:
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
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
 
 
 namespace jfnvf
    {
        public partial class Form1 : Form
        {
            int[,] Map;
 
            public Form1()
            {
                
                Random rnd = new Random();
                Map = new int[60, 30];
                for (int x = 0; x < 60; x++)
                    for (int y = 0; y < 30; y++)
                        Map[x, y] = rnd.Next(4);
            }
 
            void DrawBox(int x, int y, Brush br, Graphics gr)
            {
                gr.FillRectangle(br, x * 20, y * 20, 20, 20);
            }
 
            private void pictureBox2_Paint(object sender, PaintEventArgs e)
            {
                e.Graphics.FillRectangle(Brushes.Red, 100, 100, 50, 50);
                for (int x = 0; x < 60; x++)
                    for (int y = 0; y < 30; y++)
                    {
                        switch (Map[x, y])
                        {
                            case 0:
                                DrawBox(x, y, Brushes.White, e.Graphics);
                                break;
                            case 1:
                                DrawBox(x, y, Brushes.Yellow, e.Graphics);
                                break;
                            case 2:
                                DrawBox(x, y, Brushes.Black, e.Graphics);
                                break;
                            case 3:
                                DrawBox(x, y, Brushes.Purple, e.Graphics);
                                break;
                        }
                    }
 
            }
        }
    }
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
06.05.2019, 17:12
Ответы с готовыми решениями:

Генерация лабиринта
Нужно написать программу на C# в формах, которая будет генерировать лабиринт. Вначале я должен указать путь к выходу, а потом относительно...

Генерация рандомного лабиринта с циклами
Суть задачи: нужно написать программу , которая генерировала бы случайные лабиринты с циклами(по сути это будут уровни для игры)....

Генерация проходимого лабиринта
Придумал идею генерации лабиринта, не знаю теорию графов вообще. Суть в следующем: есть булевский массив - 0 стены нет, 1 - стена есть. На...

8
 Аватар для ashsvis
923 / 503 / 202
Регистрация: 08.10.2018
Сообщений: 1,553
Записей в блоге: 11
06.05.2019, 17:35
Цитата Сообщение от Андрей рыгало Посмотреть сообщение
надо чтобы он генерировался случайно но был проходим. там должны быть еда стены и враги и сам герой. вот что пока есть:

Потрудитесь-ка объяснить, где здесь у вас: еда стены и враги и сам герой?
2
 Аватар для aenye
304 / 186 / 45
Регистрация: 05.07.2018
Сообщений: 580
06.05.2019, 17:50
ashsvis,

Не по теме:


аывхахфывахывха )000))) Хух, не хорошо ржать конечно, но....

0
 Аватар для ashsvis
923 / 503 / 202
Регистрация: 08.10.2018
Сообщений: 1,553
Записей в блоге: 11
06.05.2019, 18:10
aenye,

Не по теме:

я просто тоже ужасно люблю всяческие лабиринты...



Добавлено через 15 минут
Андрей рыгало,
вот интересный примерчик на хабре: Генерация и решение лабиринта с помощью метода поиска в глубину по графу
0
 Аватар для ashsvis
923 / 503 / 202
Регистрация: 08.10.2018
Сообщений: 1,553
Записей в блоге: 11
07.05.2019, 19:18
Статья, опубликованная в хабре (автор Михаил Лубинец, @mersinvald), на которую я ссылался, вдохновила на следующее:

Создадим приложение WinForms со стандартной формой Form1.
Для формы включим свойство AutoScroll = true. Далее, разместим на форме панель типа Panel с именем panel1, левый верхний
угол которой совместим с левым верхним углом формы, а размер panel1 оставим произвольным.
В коде формы напишем следующее:
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
public partial class Form1 : Form
{
    int side = 20;
    State[,] Map;
    int width = 61;
    int height = 31;
    Point currentCell;
    Stack<Point> stack;
    Random rnd;
    bool builded = false;
 
    public Form1()
    {
        InitializeComponent();
        panel1.Size = new Size(width * side, height * side);
        stack = new Stack<Point>();
        rnd = new Random(); // new Random(DateTime.Now.Millisecond);
        Map = new State[width, height];
        InitMap();
        // выбираем начальную точку стартовой
        currentCell = new Point(1, 1);
    }
    ...
}
Частные поля формы содержат:
side - размер базовой ячейки, в пикселях;
width и height - ширина и высота лабиринта в ячейках;
Для хранения лабиринта создан двухмерный массив - State[,] Map, где State - перечисление:
C#
1
2
3
4
5
6
public enum State
{
    Wall,
    Cell,
    Visited
}
В конструкторе формы задаём размеры panel1: panel1.Size = new Size(width * side, height * side); При этом у формы появятся полосы прокрутки.
Далее произведём инициализацию вспомогательных объектов для стека, генератора случайных чисел и массива Map.
Метод InitMap() создаст начальную сетку ячеек:

Код метода InitMap()

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/// <summary>
/// Создание начальной сетки ячеек
/// </summary>
private void InitMap()
{
    for (var i = 0; i < width; i++)
    {
        for (var j = 0; j < height; j++)
        {
            if (i % 2 != 0 && j % 2 != 0 &&         // если ячейка нечетная по x и y, 
                i < width - 1 && j < height - 1)    // и при этом находится в пределах стен лабиринта
                Map[i, j] = State.Cell;             // то это КЛЕТКА
            else Map[i, j] = State.Wall;            // в остальных случаях это СТЕНА.
        }
    }
}

Назначаем стартовую ячейку: currentCell = new Point(1, 1);

Два обработчика подключены к панели panel1:
Обработчик для рисования на поверхности panel1

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
private void panel1_Paint(object sender, PaintEventArgs e)
{
    for (int x = 0; x < width; x++)
        for (int y = 0; y < height; y++)
        {
            switch (Map[x, y])
            {
                case State.Cell:
                    DrawBox(x, y, Brushes.White, e.Graphics);
                    break;
                case State.Wall:
                    DrawBox(x, y, Brushes.Black, e.Graphics);
                    break;
                case State.Visited:
                    DrawBox(x, y, Brushes.Red, e.Graphics);
                    break;
            }
        }
}
 
/// <summary>
/// Рисуем ячейку лабиринта на поверхности рисования
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
/// <param name="br"></param>
/// <param name="gr"></param>
void DrawBox(int x, int y, Brush br, Graphics gr)
{
    gr.FillRectangle(br, x * side, y * side, side, side);
}

Обработчик клика мышки на поверхности panel1:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
private void panel1_Click(object sender, EventArgs e)
{
    if (builded)
    {
        InitMap();
        // выбираем начальную точку стартовой
        currentCell = new Point(1, 1);
    }
    BuildMap();
    PrepareAfterBuildMap();
    builded = true;
    panel1.Invalidate();
}
Метод BuildMap() по подготовленной карте Map строит лабиринт:
Код метода BuildMap()

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
/// <summary>
/// Построение лабиринта
/// </summary>
private void BuildMap()
{
    while (true)
    {
        // перемещаемся к случайному не посещённому соседу, пока таковые есть.
        var neighbours = GetNeighbours(currentCell);
        if (neighbours.Length != 0)
        {
            var randNum = rnd.Next(neighbours.Length);
            // выбираем случайного соседа
            var neighbourCell = neighbours[randNum];
            // если соседей больше чем один
            if (neighbours.Length > 1)
                stack.Push(currentCell); // то запоминаем ячейку для возврата
            // убираем стену между текущей и соседней точками
            RemoveWall(currentCell, neighbourCell);
            // помечаем текущую ячейку как посещённую
            Map[currentCell.X, currentCell.Y] = State.Visited;
            // делаем соседнюю ячейку текущей и отмечаем ее посещённой
            currentCell = neighbourCell;
        }
        else if (stack.Count > 0) // если нет соседей, возвращаемся на предыдущую запомненную ячейку
        {
            Map[currentCell.X, currentCell.Y] = State.Visited;
            currentCell = stack.Pop();
        }
        else
            break;
    }
}

Метод PrepareAfterBuildMap() очищает для созданного лабиринта состояние State.Visited и устанавливает состояние State.Cell
Код метода PrepareAfterBuildMap()

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
/// <summary>
/// Очистка посещённых ячеек после построения лабиринта
/// </summary>
private void PrepareAfterBuildMap()
{
    for (var i = 0; i < width; i++)
    {
        for (var j = 0; j < height; j++)
        {
            if (Map[i, j] == State.Visited)
                Map[i, j] = State.Cell;          
        }
    }
}

Код вспомогательных функций GetNeighbours() и RemoveWall(), используемых в методе BuildMap()

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
/// <summary>
/// Функция RemoveWall убирает стенку между двумя клетками
/// </summary>
/// <param name="first"></param>
/// <param name="second"></param>
private void RemoveWall(Point first, Point second)
{
    var xDiff = second.X - first.X;
    var yDiff = second.Y - first.Y;
    int addX, addY;
    var target = new Point();
 
    addX = (xDiff != 0) ? (xDiff / Math.Abs(xDiff)) : 0;
    addY = (yDiff != 0) ? (yDiff / Math.Abs(yDiff)) : 0;
 
    target.X = first.X + addX; // координаты стенки
    target.Y = first.Y + addY;
 
    Map[target.X, target.Y] = State.Visited;
}
 
/// <summary>
/// Функция GetNeighbours возвращает массив не посещённых соседей клетки
/// </summary> 
/// <param name="c"></param>
/// <returns></returns>
private Point[] GetNeighbours(Point c)
{
    const int distance = 2;
    var points = new List<Point>();
    var x = c.X;
    var y = c.Y;
    var up = new Point(x, y - distance);
    var rt = new Point(x + distance, y);
    var dw = new Point(x, y + distance);
    var lt = new Point(x - distance, y);
    var d = new Point[] { dw, rt, up, lt };
    foreach (var p in d)
    {
        // если не выходит за границы лабиринта
        if (p.X > 0 && p.X < width && p.Y > 0 && p.Y < height)
        {
            // и не посещена\является стеной
            if (Map[p.X, p.Y] != State.Wall && Map[p.X, p.Y] != State.Visited)
                points.Add(p); // записать в массив
        }
    }
    return points.ToArray();
}

При клике мышкой по поверхности panel1 строится ещё один случайный замечательный лабиринт:
Вариант 1:

Вариант 2:


Я думаю, это можно использовать как начальный этап для создания программы - игры, которую задумал TC
1
 Аватар для ashsvis
923 / 503 / 202
Регистрация: 08.10.2018
Сообщений: 1,553
Записей в блоге: 11
07.05.2019, 19:28
Осталось добавить еду стены и врагов и самого героя
0
 Аватар для ashsvis
923 / 503 / 202
Регистрация: 08.10.2018
Сообщений: 1,553
Записей в блоге: 11
30.11.2021, 08:34
Пересобрал проект с программой генератора лабиринта под VS2019:
Labirint.zip

На гитхабе: https://github.com/ashsvis/Labirint
1
0 / 0 / 0
Регистрация: 10.11.2022
Сообщений: 1
12.11.2022, 11:55
а как добавить игрока допустим, не полностью разобрался в коде
0
 Аватар для ashsvis
923 / 503 / 202
Регистрация: 08.10.2018
Сообщений: 1,553
Записей в блоге: 11
12.11.2022, 15:25
multitronix, “не полностью разобрался в коде"
Почитайте по ссылке в ответе #4

Добавлено через 2 часа 30 минут
Цитата Сообщение от multitronix Посмотреть сообщение
а как добавить игрока допустим
Для начала нужно расширить enum State, добавив в него значение для игрока
(и для еды и для врагов...), ну а потом придумать, как эти состояния будут отображаться, как
их можно будет перемещать по клеткам...
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
12.11.2022, 15:25
Помогаю со студенческими работами здесь

Генерация лабиринта с бOльшим количеством комнат
В общем говоря, данж я сгенирировал рекурсией, и есть одна загвоздка, когда рандом сотворяет большую комнату и допустим одно ветвление, как...

Генерация 2D лабиринта. Как продолжить после первого шага?
как мне продолжить рандом, когда после первой ставится рандомно и чтобы продолжалось using System; using System.Collections.Generic; ...

Генерация уровней для Лабиринта
Привет. Есть небольшой проект: Лабиринт. Как можно реализовать генерацию уровня для лабиринта? 3D. Рандомный спавн сделать не трудно, но...

Генерация лабиринта
Здравствуйте, прошу помощи в решении проблемы! Делаю курсовую на тему кратчайший путь из лабиринта. Нужно сгенерировать лабринт, нашел...

Генерация лабиринта
Добрый вечер! Подскажите, как решить ошибку (Вызвано исключение по адресу 0x00271DF4 в Kursovaya.exe: 0xC0000005: нарушение прав доступа...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
9
Ответ Создать тему
Новые блоги и статьи
Инструменты COM: Сохранение данный из VARIANT в файл и загрузка из файла в VARIANT
bedvit 28.01.2026
Сохранение базовых типов COM и массивов (одномерных или двухмерных) любой вложенности (деревья) в файл, с возможностью выбора алгоритмов сжатия и шифрования. Часть библиотеки BedvitCOM Использованы. . .
Киев стоит - украинская песня
zorxor 28.01.2026
wfWdiRqdTxc О Господи, Вечный, Ты . . . Я помоги, Бесконечный. . . Я прошу Ты. . . Я погибаю, спаси. . . Я прошу Тебя Вечный. . .
Загрузка PNG с альфа-каналом на SDL3 для Android: с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 28.01.2026
Содержание блога SDL3 имеет собственные средства для загрузки и отображения PNG-файлов с альфа-каналом и базовой работы с ними. В этой инструкции используется функция SDL_LoadPNG(), которая. . .
Загрузка PNG с альфа-каналом на SDL3 для Android: с помощью SDL3_image
8Observer8 27.01.2026
Содержание блога SDL3_image - это библиотека для загрузки и работы с изображениями. Эта пошаговая инструкция покажет, как загрузить и вывести на экран смартфона картинку с альфа-каналом, то есть с. . .
влияние грибов на сукцессию
anaschu 26.01.2026
Бифуркационные изменения массы гриба происходят тогда, когда мы уменьшаем массу компоста в 10 раз, а скорость прироста биомассы уменьшаем в три раза. Скорость прироста биомассы может уменьшаться за. . .
Воспроизведение звукового файла с помощью SDL3_mixer при касании экрана Android
8Observer8 26.01.2026
Содержание блога SDL3_mixer - это библиотека я для воспроизведения аудио. В отличие от инструкции по добавлению текста код по проигрыванию звука уже содержится в шаблоне примера. Нужно только. . .
Установка Android SDK, NDK, JDK, CMake и т.д.
8Observer8 25.01.2026
Содержание блога Перейдите по ссылке: https:/ / developer. android. com/ studio и в самом низу страницы кликните по архиву "commandlinetools-win-xxxxxx_latest. zip" Извлеките архив и вы увидите. . .
Вывод текста со шрифтом TTF на Android с помощью библиотеки SDL3_ttf
8Observer8 25.01.2026
Содержание блога Если у вас не установлены Android SDK, NDK, JDK, и т. д. то сделайте это по следующей инструкции: Установка Android SDK, NDK, JDK, CMake и т. д. Сборка примера Скачайте. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru