📜 ⬆️ ⬇️

Some experience developing games on Unity3D

I do not consider myself an experienced programmer, and the more serious game developer. I am a person who is interested in programming and I get a little bit. The article does not claim to be called educational material or instruction.

Screenshots to attract attention:
imageimage

Moral issue

Is it worth doing this without having serious knowledge in game development, modeling, programming? The answer to the question from me will not follow, it will be for everyone. I can definitely say for sure - I did not regret. I will try to briefly and clearly identify and describe the bottlenecks with which I encountered, lay a map on the rake.
')
Unity3d

Unity3d has recently been allowed to use for free and at full power. I have long tossed between several engines, but c # turned out to be a decisive advantage for me. In addition, Unity3d is a very convenient way to build a user interface. For those who are not afraid of Lua, I can also advise Project Anarchy, or the Unreal Engine 4, if you are not squeamish about visual programming. I got the impression that Unity3D is great for mobile development. Unfortunately, Unity3D has a weak Russian-speaking community and often has to go to the official qa.

Game architecture

I have attempted to apply existing patterns, but in the end it all came down to “for now let it lie here”. There are many components in Unity that are difficult to attribute to some type. Most likely the reason for this is my inexperience, but in the end, such scripts as BotSpawner remained to lie in the root of the Scripts folder without having a shelter.

Save to Unity and Database

I used embedded PlayerPrefs and sqlite . Sqlite can now be used out of the box in the free version. For me, sql tables were convenient for storing data of goods when trading. The most convenient tool for managing tables is sqlitebrowser , we stopped him trying some competitors.

Writing and reading in PlayerPrefs is similar to:
public class DB : MonoBehaviour { public int currentShipBodyState { get { return PlayerPrefs.GetInt("currentShipBodyState"); } set { PlayerPrefs.SetInt("currentShipBodyState", value); } } } 

followed by elegant reading and writing:
 db.currentShipBodyState = 100; int shbs = db.currentShipBodyState; 


Sqlite demanded big gestures. Below is an example of using Sqlite in Unity3d version 5.
To use Sqlite in the editor, it is enough to create the StreamingAssets directory and place the database file there. In order to work with the database on the android device, the database file must be placed in Application.persistentDataPath . The official documentation is characterized as a public directory that is not overwritten when the program is updated. You also need to create the Plugins and Plugins \ Android directory. In the first place sqlite3.dll and System.Data.dll in Plugins \ Android place libsqlite3.so.

Universal kalo code for connecting to the database:
 public IDbConnection connector() { //      if (Application.platform != RuntimePlatform.Android) { //database.Open(Application.dataPath + "/StreamingAssets/db.sqlite"); dbconn = (IDbConnection)new SqliteConnection("URI=file:" + Application.dataPath + "/StreamingAssets/db.sqlite"); dbconn.Open(); //Open connection to the database. } // android else { //    string filepath = Application.persistentDataPath + "/" + "db.sqlite"; //       ,    if (!File.Exists(filepath)) { WWW loadDB = new WWW("jar:file://" + Application.dataPath + "!/assets/" + "db.sqlite"); while (!loadDB.isDone) { } File.WriteAllBytes(filepath, loadDB.bytes); } dbconn = (IDbConnection)new SqliteConnection("URI=file:" + Application.persistentDataPath + "/db.sqlite"); dbconn.Open(); //Open connection to the database. } return dbconn; } 


database queries, these are ordinary sql queries:
 public List<string> getItemInfoFromIslandByItemName(string item) { dbconn = connector(); dbcmd = dbconn.CreateCommand(); string sqlQuery = "SELECT island_resources.amount, island_resources.weight, island_resources.title, island_resources.price, island_resources.sell_price,ship_resources.amount FROM island_resources INNER JOIN ship_resources ON island_resources.title=ship_resources.title WHERE island_resources.title='" + item + "' AND island_resources.island_id=" + zones_filter(current_zone_name) + " "; dbcmd.CommandText = sqlQuery; reader = dbcmd.ExecuteReader(); System.Object[] values = new System.Object[reader.FieldCount]; int fieldCount = reader.GetValues(values); List<string> list = new List<string>(); for (int i = 0; i < fieldCount; i++) { list.Add( values[i].ToString() ); } clean(); return list; } 


Modeling, landscape and water

I studied modeling on the go, video lessons. Ships (two available ships) are the fruits of my labors. It turned out to be harder to texture, it took no more than 30 minutes on the model.
The landscape was an unexpected problem. The built-in terrain creation system is unsuitable for mobile devices due to high draw calls (dc). In my game, a large map and many islands. I had to take a lot of effort to get a quality landscape. To create a relief, I can advise GeoControl from which you can import a height map into Unity, then convert it to a mesh using a special plug-in. The resulting mesh needs to be optimized in the 3d editor, I use Maya. As a result, the number of dc does not exceed 100. I tried a huge amount of water assets, the choice fell on standard water4 water.

AI

To control the bots did not use the search paths. I decided to build an "intelligence" on the detection of obstacles and reactions from the ship's navigation system. The ship of the bot we shoot rays in 3 directions, when an obstacle is detected by one of the rays, the command "steering" is transmitted. When a protagonist ship is detected (when approaching the minimum distance), the bot receives the target of the pursuit and tries to get into a position convenient for the shot. When a protagonist is detected, the lateral rays transmit the command to the script responsible for firing. If there are no obstacles in the vicinity, the bots live their life and travel along the “sea routes” from island to island.

In-game purchases Unity3d

The choice fell on OpenIAB . Incredibly simple solution to a complex problem.
1. In the content section for google play sales, create a product.
2. Create a script in which you make several simple operations.
Code
  private void Awake() { //     OpenIABEventManager.billingSupportedEvent += OnBillingSupported; OpenIABEventManager.billingNotSupportedEvent += OnBillingNotSupported; OpenIABEventManager.queryInventorySucceededEvent += OnQueryInventorySucceeded; OpenIABEventManager.queryInventoryFailedEvent += OnQueryInventoryFailed; OpenIABEventManager.purchaseSucceededEvent += OnPurchaseSucceded; OpenIABEventManager.purchaseFailedEvent += OnPurchaseFailed; OpenIABEventManager.consumePurchaseSucceededEvent += OnConsumePurchaseSucceeded; OpenIABEventManager.consumePurchaseFailedEvent += OnConsumePurchaseFailed; OpenIABEventManager.transactionRestoredEvent += OnTransactionRestored; OpenIABEventManager.restoreSucceededEvent += OnRestoreSucceeded; OpenIABEventManager.restoreFailedEvent += OnRestoreFailed; } //    void Start () { OpenIAB.mapSku(SKU_COINS_2000, OpenIAB_Android.STORE_GOOGLE, "id   "); OpenIAB.mapSku(SKU_COINS_5000, OpenIAB_Android.STORE_GOOGLE, "id   "); var public_key = "      api"; var options = new OnePF.Options(); options.storeKeys.Add(OpenIAB_Android.STORE_GOOGLE, public_key); options.verifyMode = OptionsVerifyMode.VERIFY_ONLY_KNOWN; OpenIAB.init(options); } 


3. In a convenient way for you, call OpenIAB.purchaseProduct (id of the item you created);

If the purchase is successful, the OnPurchaseSucceded method is called with which we listened for the successful execution of the purchase operation. If the purchase is successful, the product must be consumed, otherwise the second purchase will not be available.
 private void OnPurchaseSucceded(Purchase purchase) { OpenIAB.consumeProduct(purchase); } 

If you use it successfully, OnConsumePurchaseSucceeded is called here, you can make an entry to assign the goods to the player, etc.

Sound management, solving the problem of simultaneous playback of several sounds on one object

Create an empty object on which we hang this script:
 public class AudioManager : MonoBehaviour { public Transform target; //      "" //  public AudioClip cannon_fire_sound_AC; //   private AudioSource cannon_fire_sound_AS; //   public static bool is_cannon_fire; void Update () { this.transform.position = target.transform.position; if (is_cannon_fire) { cannon_fire_sound_AS = AddAudio(cannon_fire_sound_AC, false, false, 0.5f); cannon_fire_sound_AS.Play(); is_cannon_fire = false; } } AudioSource AddAudio(AudioClip clip, bool loop, bool playAwake, float vol) { var newAudio = gameObject.AddComponent<AudioSource>(); newAudio.clip = clip; newAudio.loop = loop; newAudio.playOnAwake = playAwake; newAudio.volume = vol; newAudio.minDistance = 10; return newAudio; } } 

Then from the right place we call AudioManager.is_cannon_fire = true; // not the best name for the variable

Admob

Trying to understand the intricacies of Admob. I filled up the account for 500r for tests and launched the promotion by setting the daily limit to 100r. After a couple of hours, I admire this:

Honestly I did not understand where such amounts came from, most likely my inattention to details. But still, I hope this is not an invoice from Admob.

The game was called Pirates and traders , Google Play is available. Naturally requires improvements and development. Those interested can touch, the search at the time of writing is on the 29th place.

Source: https://habr.com/ru/post/265107/


All Articles