Как стать автором
Обновить

Пример создания простой 2D игры для Android с использованием игрового движка Unity

Время на прочтение6 мин
Количество просмотров161K

Введение




Прежде всего, хочу сразу отметить, что я не являюсь профессиональным разработчиком. В этой статье я постараюсь изложить свой опыт создания игры «Feel Speed Racing». Данный материал, скорее всего не будет интересен тем, кто уже имеет большой опыт в разработке игр, но начинающим разработчикам, которые хоть немного работали с Unity думаю, будет интересно.

Дизайн


Концепция игры заключается в том, что автомобиль должен пройти, как можно большее расстояние при этом на дороге динамически появляются препятствия их надо объезжать мимо иначе «игра окончена» еще нужно следить за шкалой топлива и собирать на дороге топливные баки, по истечению которой игра тоже останавливается.

Разработка


Игра состоит из 2-х сцен: главное меню и сама игровая сцена:



Где «menu» это главное меню а «1» это игровая сцена.

Главное меню




Для создания столь незамысловатого меню нам потребуется элемент управления GUI, который является стандартным в Unity.



В качестве фона я использовал спрайт с именем «background» заполненный серым цветом. Вы же можете выбрать что угодно.



Далее создаем скрипт «menu.cs»(Щелкаем правой кнопкой->выбираем Create-> C# Script) и вешаем его на background.

Содержимое скрипта:

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;

public class menu : MonoBehaviour {
	
	public GUIStyle mystyle; //объявляется для того чтобы изменять начертание GUI компонентов(шрифт, размер и.т.п.)
	string score; //переменная для хранения пройденной дистанции
	void Start () 
	{
		StreamReader scoredata = new StreamReader (Application.persistentDataPath + "/score.gd"); //создание файловой переменной
		score = scoredata.ReadLine (); //чтение строки
		scoredata.Close (); //закрытие файловой переменной
	}
	
	
	void Update () {
	
	}
	void OnGUI(){
		GUI.Box (new Rect (Screen.width*0.15f, Screen.height*0.8f, Screen.width*0.7f, Screen.height*0.1f), "MAX DISTANCE:"+score,mystyle); //создаем небольшое окошко для показа пройденного расстояния
		if (GUI.Button (new Rect (Screen.width*0.15f, Screen.height*0.25f, Screen.width*0.7f, Screen.height*0.1f), "Start game",mystyle)) //создаем кнопку для запуска игровой сцены
		{
			Application.LoadLevel(1);//Загрузка игровой сцены
		}
		if (GUI.Button (new Rect (Screen.width*0.15f, Screen.height*0.4f, Screen.width*0.7f, Screen.height*0.1f), "Exit",mystyle)) //создаем кнопку для выхода из игры
		{
			Application.Quit();//Выход из игры
		}
	}
}

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



Шрифт, цвет и размер GUI элементов вы можете изменить с помощью MyStyle.

Создание игровой сцены




Основными на этой сцене элементами является дорога, автомобиль и шкала топлива.

1. Дорога:

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



Кидаем спрайт с дорогой на игровую сцену и подгоняем по размерам камеры.



Затем добавляем как дочерние объекты внутрь дороги 4 блока с препятствиями, топливный бак и не забываем добавить к ним Box Collider 2D.Еще надо отметить Is Triger для пересечения с автомобилем.



Теперь создаем скрипт moveroad.cs и вешаем его на нашу дорогу.

Добавляем в него следующий код:

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
public class moveroad : MonoBehaviour {

	public GUIStyle mystyle;//создание стиля
	int f,fuelst;
	float score=0,speed=-0.2f,data,fuelpos;// переменные для хранения расстояния, скорости и рекорда
	public GameObject block;// игровой объект для размещения блока
	public GameObject block1;
	public GameObject block2;
	public GameObject block3;
	public GameObject fuel;
	bool turbotriger=false;

	void Start () 
	{
		StreamReader scoredata = new StreamReader (Application.persistentDataPath + "/score.gd");
		data = float.Parse(scoredata.ReadLine ());//чтение с файла информации о рекорде
		scoredata.Close ();
	}
	

	void Update () 
	{
		transform.Translate (new Vector3 (0f,speed,0f));//движение дороги с заданной выше скоростью
		score = score + (speed*-10);// подсчет расстояния
		if (transform.position.y < -19f) // если дорога уходит за пределы камеры то она "теле портируется" вверх
		{
			transform.position=new Vector3(0f,33.4f,0f);//новая позиция дороги
			block.transform.position=new Vector3(10.15f,block.transform.position.y,block.transform.position.z); 
			block1.transform.position=new Vector3(8.42f,block1.transform.position.y,block1.transform.position.z); 
			block2.transform.position=new Vector3(6.62f,block2.transform.position.y,block2.transform.position.z); 
			block3.transform.position=new Vector3(4.95f,block3.transform.position.y,block3.transform.position.z); 
			fuel.transform.position=new Vector3(11.86f,fuel.transform.position.y,fuel.transform.position.z);
                        //скрытие за пределы камеры всех препятствий(блоков)
			f = Random.Range (0, 5);//случайное появление на дороге 1-го из 4-х блоков или канистры с бензином
			switch (f) 
			{
			case 0:block.transform.position=new Vector3(2.40f,block.transform.position.y,block.transform.position.z); break;
			case 1:block1.transform.position=new Vector3(0.90f,block1.transform.position.y,block1.transform.position.z); break;
			case 2:block2.transform.position=new Vector3(-0.80f,block2.transform.position.y,block2.transform.position.z); break;
			case 3:block3.transform.position=new Vector3(-2.35f,block3.transform.position.y,block3.transform.position.z); break;
			case 4:
				fuelst=Random.Range(0,4);
				if(fuelst==0){fuelpos=2.40f;}
				if(fuelst==1){fuelpos=0.90f;}
				if(fuelst==2){fuelpos=-0.80f;}
				if(fuelst==3){fuelpos=-2.35f;}
				fuel.transform.position=new Vector3(fuelpos,fuel.transform.position.y,fuel.transform.position.z);
				break;
			}
			if (score>data)// если текущее пройденное расстояние превышает то что записано в файле рекорда то идет обновление данных
			{
				StreamWriter scoredata=new StreamWriter(Application.persistentDataPath + "/score.gd");//создаем файловую переменную для хранения пройденного расстояния
				scoredata.WriteLine(score);//записываем новое значение в файл
				scoredata.Close();//закрываем файловую переменную
			}
		}
		
	}
	void OnGUI(){
		GUI.Box (new Rect (0, 0, Screen.width, Screen.height*0.05f), "Distance(m): " + score,mystyle);//создаем окно для подсчета расстояния
	}
}



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



Что бы решить эту проблему надо создать дубликат уже готовой дороги и немного изменить скрипт.



Должно получиться вот так.

2. Автомобиль:



Кидаем спрайт автомобиля на сцену и устанавливаем его в любое место на дороге. Затем создаем скрипт carcontroller.cs и вешаем его на автомобиль.

Содержимое carcontroller.cs:

using UnityEngine;
using System.Collections;
using UnityStandardAssets.CrossPlatformInput;

public class carconroller : MonoBehaviour 
{

	void Start () 
	{

	}
	
	
	public void Update () 
	{
		if (transform.rotation.z !=0) //проверка столкновения коллайдера автомобиля и препятствия, при столкновении происходит загрузка меню
		{
			Application.LoadLevel (0);
		}
		
	}
	}
	public void OnGUI()
	{
		if (GUI.RepeatButton (new Rect (Screen.width*0.1f, Screen.height*0.9f, Screen.width*0.2f, Screen.height*0.08f), "L")) //создаем кнопку для движения влево
		{
			if (transform.position.x > -2.4f)
			{
				transform.Translate (new Vector3 (-0.05f, 0f, 0f));
			}
		}

		if (GUI.RepeatButton (new Rect (Screen.width*0.7f, Screen.height*0.9f, Screen.width*0.2f, Screen.height*0.08f), "R")) //создаем кнопку для движения вправо
		{
			if (transform.position.x < 2.4f)
			{
				transform.Translate (new Vector3 (0.05f, 0f, 0f)); 
			}
		}
	}

}

Теперь автомобиль может перемещаться.

3.Шкала топлива:



Для создания шкалы потребовалось 2 спрайта одинаковых размеров, но разных цветов (красный, зеленый). И сделать один из них дочерним (зеленый).

Далее создаем скрипт fuelscript.cs, вешаем его на fuel и добавляем в него код:

using UnityEngine;
using System.Collections;

public class fuelscript : MonoBehaviour {

	public GameObject fuelall;
	float mytimer=100f;// задание плавающего числа
	// Use this for initialization
	void Start () 
	{

	}
	void Update () 
	{
		mytimer = 100f;
		mytimer -= Time.deltaTime;//изменения числа с течением времени
		if (mytimer/mytimer==1f) //проверка на период времени в 1 секунду
		{
			fuelall.transform.position=new Vector3(fuelall.transform.position.x-0.0011f,fuelall.transform.position.y,fuelall.transform.position.z);
			fuelall.transform.localScale = new Vector3(fuelall.transform.localScale.x-0.001f, 1, 1);
                        //выше идет сдвижение влево и уменьшение по ширине зеленой полосы для имитации шкалы
		}
		if (fuelall.transform.localScale.x < 0) //если шкала исчезла то загрузка идет загрузка главного меню 
		{
			Application.LoadLevel(0);
		}
	}
}



Дорога у меня это road183 и ее дубликат road183(1). В ее дочерний объект fueltrack нужно добавить скрипт для обнаружения пересечения с автомобилем и восполнения топлива.

Создаем скрипт triger.cs и вешаем его на fueltrack в обеих дорогах и отмечаем как Is Triger. Код:

using UnityEngine;
using System.Collections;

public class triger : MonoBehaviour {


	public GameObject fuel;//добавляем сюда greenfuel
	// Use this for initialization
	void Start () {
	
	}
	
	// Update is called once per frame
	void Update () {

	}
	void  OnTriggerEnter2D(Collider2D col)
	{
		if (col.gameObject.name == "playercar") //проверка пересечения автомобиля и объекта fuel
		{
			fuel.transform.position=new Vector3(0,fuel.transform.position.y,fuel.transform.position.z);
			fuel.transform.localScale = new Vector3(1, 1, 1);
                        //восстановление у объекта fuel стандартных значений
		}
	}


}

Итог


В момент выпуска игры на Google Play я особо не занимался ее продвижением ну и само собой закачек не набралось.

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

Теги:
Хабы:
Если эта публикация вас вдохновила и вы хотите поддержать автора — не стесняйтесь нажать на кнопку
+5
Комментарии15

Публикации

Истории

Работа

Ближайшие события

Weekend Offer в AliExpress
Дата20 – 21 апреля
Время10:00 – 20:00
Место
Онлайн
Конференция «Я.Железо»
Дата18 мая
Время14:00 – 23:59
Место
МоскваОнлайн