И вот моя первая попытка выбраться на просторы Хабрахабр.

Недавно в свет вышла моя игра Evasion. Простая аркада, в которой нужно уклоняться от препятствия. Игра сама по себе легка в разработке, но в каждой простоте есть свои подводные камни. О парочке из них я и хочу поговорить в данной статье.


Красный шар движется в точку касания пальца.

Редактор уровней


Уровни в Evasion представлены в виде матрицы спрайтов, которые падают с определенной скоростью. Когда нижний ряд опускается ниже допустимых координат, он перемещается на самый верх. В итоге получается подобие конвейерной ленты. В момент перемещения меняются препятствия, соответственно и изображение на спрайтах. У каждого вида препятствия есть свой id. Информация об уровне хранится в двумерном массиве.

Таким способом меняются препятствия:

   public static bool Next_M(int Series) // Получаем номер ряда
    {
        if (Set < 0)
            Set = 0;

        if (Set < mLvl) // Если уровень не закончился 
        {
            // xR - количество столбцов в уровне 
            for (int i = 0; i < xR; i++)
            {
                M_Load(Series, i, Level[i, Set]);  // Меняем препятствия на те, которые содержатся в массиве Level
            }

            Set++;
        }
        else // Иначе финиш 
        {
            for (int i = 0; i < xR; i++) 
            {
                M_Load(Series, i, 0);
            }

            if (Finish) 
            {
                Finish = false;
                return true;
            }
        }

        return false;
    }  

Поначалу, чтобы создавать уровни, приходилось вводить стринговое выражение и его уже конвертировать в целочисленное значение.

Base[0] = "040900080205080202000204050000001500060001001515141314140706000705110704040004020406"; // Первый уровень во всей красе

Но быстро понял, что так дела не делаются. Процесс работы был медленным, муторным, а исправление ошибок каралось углубленным поиском иголки в стоге сена. Итогом стало решение создание быстрого и удобного редактора уровня.


Центральная лента опускается слайдами.

Редактор упростил разработку в несколько раз. Можно быстро построить уровень и там же его протестировать. И если в вашей игре есть возможность облегчить жизнь, создав редактор уровней, не поленитесь потратить на него своё время, оно того стоит. К тому же это можно преподнести, как дополнительную опцию в игре (если ваш редактор удобен в использовании обычным смертным).

Хоть редактор в Evasion присутствует, он только для ознакомления. Хотя и можно сделать сохранение уровней, возможность делится с друзьями и так далее. Но это уже совсем другая история…

Бесконечный режим


Не имея больших познаний в математике, рандоманая генерация уровня стала для меня непостижимой задачей. Единственным выходом было создание небольших блоков длиной в 3 – 5 спрайтов и их повторение. Скучная и нудная реализация, но другого выбора не было. Пока однажды, сидя в БФУ на паре математике, в голову не пришло одно единственное слово: множества!

Все препятствия можно разделить на множества:

  1. Все виды препятствий
  2. Все препятствия сверху (Подмножество первого массива)
  3. Все препятствия снизу
  4. Слева
  5. Справа

Те виды, у которых несколько препятствий попадают в несколько массивов сразу. Случайным образом узнаем, где вход, где выход и дистанцию между ними. Всё происходит в пределах одного ряда. В зависимости от дистанции узнаем, где и в каком месте исключить появление непроходимого места.

   public static void Next_M(int S)
    {
        int Di = Math.Abs(In - Ou); // Узнаем дистанцию между входом и выходом


        if (Di == 0) // В зависимости от дистанции генерируем препятствие
        {
            List<int> Cut = Draw(0, 1); // 0 - исключаем препятствие снизу, 1 - сверху
            M_Load(S, In, Cut[StaticVolue.Rnd(0, Cut.Count)]); 
        }
        else
        {
            List<int> Cut = new List<int>();

            if (In > Ou)
            {
                Cut = Draw(0, 2);
                M_Load(S, In, Cut[StaticVolue.Rnd(0, Cut.Count)]);

                for (int C = In - 1; C >= Ou; C--)
                {
                    if (C == Ou)
                    {
                        Cut = Draw(1, 3);
                        M_Load(S, C, Cut[StaticVolue.Rnd(0, Cut.Count)]);
                    }
                    else
                    {
                        Cut = Draw(2, 3);
                        M_Load(S, C, Cut[StaticVolue.Rnd(0, Cut.Count)]);
                    }
                }
            }
            else
            {
                Cut = Draw(0, 3);
                M_Load(S, In, Cut[StaticVolue.Rnd(0, Cut.Count)]);

                for (int C = In + 1; C <= Ou; C++)
                {
                    if (C == Ou)
                    {
                        Cut = Draw(1, 2);
                        M_Load(S, C, Cut[StaticVolue.Rnd(0, Cut.Count)]);
                    }
                    else
                    {
                        Cut = Draw(2, 3);
                        M_Load(S, C, Cut[StaticVolue.Rnd(0, Cut.Count)]);
                    }
                }
            }
        }

        In = Ou; 
        Ou = StaticVolue.Rnd(0, Matrix_Control.xR);
    }

static List<int> Draw(int A)
    {
        List<int> CellSet = new List<int>();
        bool ice;

        for (int y = 0; y < AllCell.Length; y++) 
        {
            ice = true;

            for (int i = 0; i < 9; i++)
            {
                if (AllCell[y] == EnterCell[A, i]) // Из всех видов исключаем те препятствия, которые содержатся в массиве A
                {
                    ice = false;
                }
            }

            if (ice)
                CellSet.Add(AllCell[y]);
        }

        return CellSet;
    }

Вот такая реализация рандомного уровня получилась. Если у вас есть идеи, как это можно было бы сделать лучше, пишите в комментариях.

Музыкальное сопровождение


Хотелось сказать пару слов о музыке в игре.

Что, если ты студент и у тебя нету денег на хорошую музыку, а бесплатные варианты не устраивают? Тут есть два выхода: либо самому написать или же иметь хороших друзей, желательно со своей группой. Так уж получилось, что писать музыку самостоятельно я не умею, а вот с друзьями мне повезло.

Музыку для моей игры любезно предоставила наша местная Калининградская группа «Houston, we've got problems!» Для тех, кто любит post-rock, рекомендую ознакомиться с их творчеством.

На этом всё. Удачи всем в проектах.

Комментарии (0)