forum.boolean.name

forum.boolean.name (http://forum.boolean.name/index.php)
-   Проекты на Unity (http://forum.boolean.name/forumdisplay.php?f=147)
-   -   Android game: Feel RoundAbout + механика игры (http://forum.boolean.name/showthread.php?t=19118)

slee 25.04.2014 20:43

Android game: Feel RoundAbout + механика игры
 
Всем привет!

В этой теме я хочу рассказать Вам о своей игре и процессе ее разработки.

О игре:

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

Контролируя полет птицы, попытайтесь пролететь как можно больше кругов.

Ссылка на игру - скачать из Google Play.

Скрины:

Цитата:

Типичный флаппи берд.




О разработке:

Концепт игры не мой, на ее создание меня вдохновила игра Mr Flap – ссылка на Google Play.

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

Продолжение под спойлером:

Изначально я решил делать игру без физики и начал я с движения куба по кругу.

Сначала я создал куб и пустой объект, а затем вложил куб в пустышку. На пустой объект я накинул C# скрипт, который будет вращать пустой объект и куб соответственно.

Код:

// update
void Update ()
{
    // rotate
    gameObject.transform.Rotate(0,0, 0.3f);
} // update end

Потом я создал сферу и установил цвет фона для камеры, добавил спрайты глаз, клюва и крыльев. Результат:



На этом этапе у меня была птица, которая двигалась по кругу и следующее, что я сделал - заставил птицу взлетать и падать на сферу.

Т.к. в этой игре, я решил не использовать физику, гравитацию решил сделать так:

Код:

// object's
public Transform targetSphere;
public float gravityPower;
 
// update
void Update ()
{
    // gravity emulate
    gameObject.transform.position = Vector3.MoveTowards(transform.position, targetSphere.position, gravityPower * Time.deltaTime);
} // update end

Флаппы птицы сделал так(версия пк):

Код:

// int's
private bool flapTimeStart = false; // flapp action
private float flapTime; // flapp time
public float upSpeed;
public float rightSpeed;
 
// update
void Update ()
{
  // flapp action
  if (Input.GetMouseButtonUp(0)) { flapTimeStart = true; }
  // flapp engine
  if (flapTimeStart)
  {
      if (flapTime > 0) { flapTime -= 1.0f * Time.deltaTime; transform.Translate(Vector3.up * upSpeed * Time.deltaTime); transform.Translate(Vector3.right * rightSpeed * Time.deltaTime); }
  }
  if (flapTime <= 0) { flapTime = 0.1f; flapTimeStart = false; }
} // update end

Теперь птица может летать. Она летает вокруг сферы и взлетает когда я нажимаю кнопку мыши. Но есть две проблемы:

1) Птица проваливается в сферу;
2) Птица может улететь за края экрана;

Чтобы ограничить движения птицы, я использовал систему триггеров:

Код:

// trigger enter
void OnTriggerEnter(Collider MyTrigger)
{
    // stops triggers
    if (MyTrigger.gameObject.name == "Sphere") { stopMove = true; }
    if (MyTrigger.gameObject.name == "archway") { flapTimeStart = false; flapTime = 0.1f; transform.Translate(Vector3.down * 15.5f * Time.deltaTime); }
} // trigger enter end

Так вот, при входе в сферу, отключается притяжение.

А когда летящая птица выходит за края белого круга отключается возможность флаппа и птица отбрасывается назад к сфере.



Так что теперь моя птица может летать только в заданной области. :)

Следующее, что я сделал - создал систему стен



С вращения используется тот же метод, что и с полетом птицы. А для движения стен, я использовал этот код:

Код:

// int's
private bool iniLock = false; // ini lock
private int randomOrientation; // randomize orientation
private bool OrientationSide; // randomize orientation ~~~ true = move to right(+); ~~~ false = move to left(-); //
private float randomSpeed;
 
// start
void Start ()
{
    if (!iniLock)
    {
        //randomOrientation = Random.Range(-0.6f, 0.68f);
        // randomize orientation
        randomOrientation = Random.Range(1, 10);
        if (randomOrientation > 1 && randomOrientation < 5) { OrientationSide = true; }
        else if (randomOrientation >= 5 && randomOrientation < 10) { OrientationSide = false; }
        // randomize speed
        randomSpeed = Random.Range(0.1f, 0.35f);
        // ini lock
        iniLock = true;
    } // ini lock
} // start end
 
// update
void Update()
{
    // orientation move
    if (OrientationSide && !dd.finishGame)
    {
        if (gameObject.transform.localPosition.x < 0.68f) { gameObject.transform.localPosition += new Vector3(randomSpeed * Time.deltaTime, 0, 0); }
        if (gameObject.transform.localPosition.x >= 0.68f) { OrientationSide = false; }
    }
    else if (!OrientationSide && !dd.finishGame)
    {
        if (gameObject.transform.localPosition.x > -0.6f) { gameObject.transform.localPosition -= new Vector3(randomSpeed * Time.deltaTime, 0, 0); }
        if (gameObject.transform.localPosition.x <= -0.6f) { OrientationSide = true; }
    }
} // update end

Самая сложная часть позади... (хотя, что тут сложного?)

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

Когда птица пересекает пунктирную линию, выполняется этот код:

Код:

dd.newColorNum = Random.Range(1,8);
А в другом скрипте, который подключен ко всем необходимым спрайтам, такой код:

Код:

// update
void Update ()
{
    if (dd.newColorNum == 1) { GetComponent<SpriteRenderer>().color = new Color( 0, 0.7f, 1, 1); }
    if (dd.newColorNum == 2) { GetComponent<SpriteRenderer>().color = new Color(0.7f, 0, 1, 1); }
    if (dd.newColorNum == 3) { GetComponent<SpriteRenderer>().color = new Color(1, 0.6f, 0, 1); }
    if (dd.newColorNum == 4) { GetComponent<SpriteRenderer>().color = new Color(0.411f, 0.862f, 0, 1); }
    if (dd.newColorNum == 5) { GetComponent<SpriteRenderer>().color = new Color(0.113f, 0.333f, 0.568f, 1); }
    if (dd.newColorNum == 6) { GetComponent<SpriteRenderer>().color = new Color(0.368f, 0.25f, 0.156f, 1); }
    if (dd.newColorNum == 7) { GetComponent<SpriteRenderer>().color = new Color(0.243f, 0.266f, 0.464f, 1); }
    if (dd.newColorNum == 8) { GetComponent<SpriteRenderer>().color = new Color(0.913f, 0.505f, 0.25f, 1); }
} // update end

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

Чтобы изменить фоновый цвет камеры, я использовал стандартное обращение:

Код:

if (dd.newColorNum == 1) { camera.backgroundColor = new Color(0, 0.7f, 1, 1); }
Скрипт соответственно прикреплен к камере.

Конец

В общем-то это и есть самое интересное... хотя нет, не все!

Еще я хотел бы поделится с Вами небольшим опытом касательно Google Play Services:

В моей предыдущей игре Earth Defense 2 (ссылка) я впервые использовал Google Play Services и по неопытности установил принудительную авторизацию при старте игры.

Это привело к тому, что на многих устройствах игра крашилась на старте.

Соответственно практически сразу посыпались плохие отзывы, которые, впрочем, были исправлены после обновления.

Так вот, ВСЕГДА давайте пользователю выбор! Это касаться не только google сервисов, а и любых функций...

В этой игре я использовал такое диалоговое окно:



Вот теперь все, вроде :)

Буду очень рад, если эта мини-статья будет кому-то полезна. Большое спасибо за внимание.


PS: Весь код написан на C# для Unity3d за выходные.

Mr_F_ 25.04.2014 20:49

Ответ: Android game: Feel RoundAbout + механика игры
 


это жесть, чтобы проверить выхождение за круг, достаточно дистанцию чекнуть, причём без sqrt, причём в 2д.

Arton 25.04.2014 20:58

Ответ: Android game: Feel RoundAbout + механика игры
 
Можно пожалуйста всю эту простыню под сполеры убрать.

slee 25.04.2014 21:04

Ответ: Android game: Feel RoundAbout + механика игры
 
Цитата:

Сообщение от Mr_F_ (Сообщение 279435)


это жесть, чтобы проверить выхождение за круг, достаточно дистанцию чекнуть, причём без sqrt, причём в 2д.

Буду рад узнать как это делается. Можно пример?

И еще вопрос: разве простой триггер грузит больше постоянного вычисления дистанции?

Спасибо!

slee 25.04.2014 21:14

Ответ: Android game: Feel RoundAbout + механика игры
 
Цитата:

Сообщение от Arton (Сообщение 279438)
Можно пожалуйста всю эту простыню под сполеры убрать.

Я бы с радостью, но черт знает как тут спойлер юзать... вроде стандартный [spoiler] не работает, попробовал несколько вариантов, не вышло.

Справку по здешним bb на стр редактирования не нашел... Буду рад, если вы мне подскажите. Спасибо!

Mr_F_ 25.04.2014 21:23

Ответ: Android game: Feel RoundAbout + механика игры
 
Цитата:

Буду рад узнать как это делается. Можно пример?
в 3д в юнити:

Код:

// Init
const float outOfLevelDist = 10;
const float tooCloseDist = 2;
float outOfLevelSqrDist = outOfLevelDist * outOfLevelDist;
float tooCloseSqrDist = tooCloseDist * tooCloseDist;
-----
// Update
float sqrDist = (birdPos - circlePos).sqrMagnitude;
if (sqrDist > outOfLevelSqrDist) улетели за пределы
if (sqrDist < tooCloseSqrDist) заехали в круг


Если круг находится в нуле, и считаем в 2д, то можно упростить до:

Код:

float sqrDist = birdPos.x*birdPos.x + birdPos.y*birdPos.y;
-----

Цитата:

разве простой триггер грузит больше постоянного вычисления дистанции?
по-твоему триггер будет работать быстрее 2х умножений и одного сложения в кадр?

slee 25.04.2014 21:31

Ответ: Android game: Feel RoundAbout + механика игры
 
Цитата:

Сообщение от Mr_F_ (Сообщение 279442)
в 3д в юнити:

Код:

// Init
const float outOfLevelDist = 10;
const float tooCloseDist = 2;
float outOfLevelSqrDist = outOfLevelDist * outOfLevelDist;
float tooCloseSqrDist = tooCloseDist * tooCloseDist;
-----
// Update
float sqrDist = (birdPos - circlePos).sqrMagnitude;
if (sqrDist > outOfLevelSqrDist) улетели за пределы
if (sqrDist < tooCloseSqrDist) заехали в круг


Если круг находится в нуле, и считаем в 2д, то можно упростить до:

Код:

float sqrDist = birdPos.x*birdPos.x + birdPos.y*birdPos.y;
-----


по-твоему триггер будет работать быстрее 2х умножений и одного сложения в кадр?


Большое спасибо за толковый пример! Реально здорово узнать что-то новое... хотя и так все подносом - я просто не подумал о таком варианте решения задачи.

---

Я не утверждаю, что триггер будет работать быстрее - я просто спрашиваю)

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

Спасибо!

Mr_F_ 25.04.2014 21:36

Ответ: Android game: Feel RoundAbout + механика игры
 
Цитата:

На мой взгляд триггер более оптимален, тк он, в отличии от вычислений, не используется постоянно. Или я чего-то не понимаю? Поправьте пожалуйста...
физическому движку каждый кадр необходимо проверить, попадает ли птица внутрь или нет.
конечно при большом числе триггеров, он не будет прям попадание в каждый проверять, там свои оптимизации типа деревьев и проверки попадания сначала в AABB триггера - но в любом случае, тут как ни крути, дофига работы по сравнению с проверкой дистанции)
ты сам то думал, как триггеры могут быть реализованы, если бы ты их сам писал? они же не по волшебству пашут.

в случае с мешем-триггером, особенно из такого числа трианглов, конечная проверка будет весьма небыстрая. не знаю даже точно, как считают попадание в невыпуклый примитив, но это всегда куда сложнее, чем в выпуклый (convex), а для проверки попадания в выпуклый, движку нужно проверить с какой стороны находится объект (все его формообразующие точки) за каждой плоскостью триггера. жопа, короче.

slee 25.04.2014 21:45

Ответ: Android game: Feel RoundAbout + механика игры
 
Цитата:

Сообщение от Mr_F_ (Сообщение 279445)
физическому движку каждый кадр необходимо проверить, попадает ли птица внутрь или нет.
конечно при большом числе триггеров, он не будет прям попадание в каждый проверять, там свои оптимизации типа деревьев и проверки попадания сначала в AABB триггера - но в любом случае, тут как ни крути, дофига работы по сравнению с проверкой дистанции)
ты сам то думал, как триггеры могут быть реализованы, если бы ты их сам писал? они же не по волшебству пашут.

в случае с мешем-триггером, особенно из такого числа трианглов, конечная проверка будет весьма небыстрая. не знаю даже точно, как считают попадание в невыпуклый примитив, но это всегда куда сложнее, чем в выпуклый (convex), а для проверки попадания в выпуклый, нужно проверить с какой стороны находится объект (все его формообразующие точки) за каждой плоскостью триггера. жопа, короче.

ОГРОМНОЕ СПАСИБО!

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

что может быть проще для понимания?!
- Есть граница, при пересечении которой выполняется действие.. и усе))

Теперь то я задумался, а как оно работает, сейчас(пока ждал ответ) уже нагуглил массу инфы - буду просвещаться.

Спасибо!

Arton 25.04.2014 22:38

Ответ: Android game: Feel RoundAbout + механика игры
 
Цитата:

Сообщение от slee (Сообщение 279441)
Я бы с радостью, но черт знает как тут спойлер юзать... вроде стандартный [spoiler] не работает, попробовал несколько вариантов, не вышло.

Справку по здешним bb на стр редактирования не нашел... Буду рад, если вы мне подскажите. Спасибо!

Сполер никогда не работал здесь, насколько мне известно. В расширеном режиме кнопка сверху:


Либо:
PHP код:

[offtop]Бла-бла-бла[/offtop


slee 25.04.2014 22:47

Ответ: Android game: Feel RoundAbout + механика игры
 
Цитата:

Сообщение от Arton (Сообщение 279449)
Сполер никогда не работал здесь, насколько мне известно. В расширеном режиме кнопка сверху:


Либо:
PHP код:

[offtop]Бла-бла-бла[/offtop


Угу, теперь буду знать, большое спасибо!))

impersonalis 28.04.2014 12:01

Ответ: Android game: Feel RoundAbout + механика игры
 
Цитата:

Сообщение от Mr_F_ (Сообщение 279435)


это жесть, чтобы проверить выхождение за круг, достаточно дистанцию чекнуть, причём без sqrt, причём в 2д.

Успокойся, это же юнити. *трололо*

den 28.04.2014 21:10

Ответ: Android game: Feel RoundAbout + механика игры
 
Кто тут любит постить учебник геометрии за 7 класс?


Часовой пояс GMT +4, время: 15:28.

vBulletin® Version 3.6.5.
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Перевод: zCarot