Downloads

← Back Basic 3D example
Version:
1.1
Format:
Unity project zip archive
Dependencies:
BGDatabase

Description

This project represents a simple 3D game prototype. It's an endless game, the player should collect objects on two levels. Each object has its own type and some gold attached to it. Once all objects are collected, new objects are spawned. The game progress can be saved and loaded.

Features

  1. Very simple project with simple scripts
  2. Code generation usage example
  3. Data binders usage example
  4. Save Load addon usage example
  5. Text tutorial available (read below)

Setup:

  1. Download zip archive, unzip it and open the project in Unity Editor (version >= 2019 LTS)
  2. Import BGDatabase asset
  3. If you use Unity 2022, you may see compilation errors in the console. Import "Unity UI" package using Unity package manager
  4. Run example scene (BGDatabaseBasic3DExample\Scenes\BGExample1.unity)

Database schema

Here is the database schema, we use for that example.

  1. Scene- is linked to Unity scene, it's name should be equal to Unity scene name. It has the following fields:
    1. spawnPosition [Vector3]- position, the player will be moved then he's spawned in this scene
    2. spawnRotation [Vector3]- rotation, the player will be rotated then he's spawned in this scene
    3. bounds [Bounds]- area for spawning objects
  2. Collectable - is Scene's nested field, meaning it defines its own table (meta), which is connected to Scene table (meta). It stores all collectable objects in the scene and have the following fields:
    1. position [Vector3]- position of the object
    2. gold [int]- amount of gold, attached to the object
    3. type [relationSingle]- type of the object
  3. CollectableType - type of the Collectable
    1. prefab [unityPrefab]- prefab to use as an object to spawn
    2. audio [audioClip]- sound to play then object is collected
  4. Player - single entity table (meta), which store info about player
    1. gold [int]- amount of gold player gathered
    2. position [Vector3]- player's position, used by SaveLoad addon to save and load player's position
    3. rotation [Quaternion]- player's rotation, used by SaveLoad addon to save and load player's position
    4. scene [string]- player's scene, used by SaveLoad addon to save and load player's position

Save/Load settings

Let's look at the save/load setting to understand how they can be used to save/load your data during gameplay. You can find more information about Save/Load here

About Code Generation

We use code generation in this example (and we strongly recommend you to use it too). The long story short - instead of using basic API like this entity.Set("gold", entity.Get<int>("gold") +1)); code generation allows you to use code like this entity.gold=entity.gold+1;. As you can see code generation provides huge benefit, you can learn more about code generation here .

To distinct database fields from normal fields we use f_, m_ or d_ field prefixes in the examples below. We use all 3 types of code generation (for illustrative purpose), each prefix correspond to code generation type:

  1. BGM_ClassName and m_FieldName - MonoBehaviour generated classes (generated classes extends from MonoBehaviour and can be attached to GameObject)
  2. BGE_ClassName and f_FieldName - Extension classes (instead of creating basic BGEntity class, the database populated with classes which inherited from BGEntity and have all additional properties for all fields)
  3. BGD_ClassName and d_FieldName - Dna generated classes (this is a special case and can be avoided)

Code explanation

Some non relevant code is omitted.

  1. BGCollectable.cs- This script is attached to every collectable object. This script is hooked to a database by extending from BGM_Collectable class (generated by code generator), which in turn is extended from BGEntityGo- our component we use to connect GameObjects to database. When new collectable object is spawned in the scene by BGSpawner.cs, Entity field is assigned- and object become linked to a particular table row.
    This script has 4 tasks:
    1. Show gold amount on the TextMesh component. This is done by this code Text.text = "Gold:" + m_gold;. m_gold field reads/write data from/to database
    2. Add some gold to the player
    3. Play sound effect when object's collected.
    4. Remove the object when it's collected from scene and from database.
    
    public class BGCollectable : BGM_Collectable
    {
        //this callback is called then connected entity is changed
        public override void EntityChanged()
        {
            Text.text = "Gold:" + m_gold;
        }
    
        private void OnTriggerEnter(Collider other)
        {
            if (other.gameObject.CompareTag("Player"))
            {
                var player = other.GetComponent<BGPlayer>();
    
                //add gold
                player.m_gold += m_gold;
    
                //play sound
                var audioSource = player.GetComponent<AudioSource>();
                audioSource.clip = m_type.f_audio;
                audioSource.Play();
    
                //remove from database & scene
                Entity.Delete();
                Destroy(gameObject);
            }
        }
    }
            
  2. BGGoToScene.cs- this script is attached to a portal to another scene. When the player collides with this portal, he's moved to another scene. This script is also hooked up to a database, namely to Scene row, pointing to a scene to load. When the player collides with this object, script read data about this scene from database, updates Player table with position and rotation from Scene table and loads target scene.
    
    public class BGGoToScene : BGM_Scene
    {
        private void OnTriggerEnter(Collider other)
        {
            if (other.gameObject.CompareTag("Player"))
            {
                //get reference to player
                var player = other.GetComponent<BGPlayer>();
    
                //set player position & rotation to scene's spawn position & rotation
                player.m_position = m_spawnPosition;
                player.m_rotation = Quaternion.Euler(m_spawnRotation);
    
                //load the scene
                SceneManager.LoadScene(Entity.Name);
            }
        }
    }
            
  3. BGSpawner.cs- this script fills database with new objects and also spawn them to the scene. It hooked up to Scene table. It uses database events, to find the moment all objects are collected.
    
    public class BGSpawner :BGM_Scene
    {
        public override void  Start()
        {
            base.Start();
            Spawn();
            //use database events to keep track the moment, when all collectables are gathered
            BGRepo.I.Events.AddAnyEntityDeletedListener(BGE_Collectable.MetaDefault.Id, CheckForNewSpawns);
        }
    
        public override void OnDestroy()
        {
            base.OnDestroy();
            BGRepo.I.Events.RemoveAnyEntityDeletedListener(BGE_Collectable.MetaDefault.Id, CheckForNewSpawns);
        }
    
        //spawn unity's gameobjects - corresponding to Repo objects
        private void Spawn()
        {
            //fetch collectables from database
            var collectables = m_Collectable;
    
            //no collectables- no luck
            if (BGUtil.IsEmpty(collectables)) return;
    
            //spawn collectables objects
            foreach (BGEntity collectable in collectables)
            {
                //create collectable GameObject
                var newCollectable = Instantiate(collectable.f_type.f_prefab,
                    collectable.f_position, Quaternion.identity);
    
                //we know - collectable prefab has BGCollectable script attached
                // so hook it up to table's row
                newCollectable.GetComponent<BGCollectable>().Entity = collectable;
            }
        }
    
        //This method create new collectables randomly for all scenes if all objects are collected
        public void CheckForNewSpawns(object sender, BGEventArgsAnyEntity args)
        {
            //there are still some collectables
            if (BGE_Collectable.CountEntities > 0) return;
    
            //ok, we gathered all objects- lets spawn new ones
            BGE_Scene.ForEachEntity(scene =>
            {
    
                //number of collectables for one scene
                var count = Random.Range(3, 6);
                for (var i = 0; i < count; i++)
                {
                    //nested meta has utility method, which auto assign new collectable to owner entity (scene)
                    var newCollectable = BGE_Collectable.NewEntity(scene);
    
                    //set gold
                    newCollectable.f_gold = Random.Range(1, 10);
    
                    //bounds determines scene's frontiers
                    var bounds = scene.f_bounds;
                    //set position
                    newCollectable.f_position = new Vector3(Random.Range(bounds.min.x, bounds.max.x),
                        bounds.center.y, Random.Range(bounds.min.z, bounds.max.z));
    
                    //set type
                    newCollectable.f_type = BGE_CollectableType.GetEntity(Random.Range(0, BGE_CollectableType.CountEntities));
                }
            });
    
            //spawn GameObjects for current scene
            Spawn();
        }
    }
            
  4. BGPlayer.cs- this script is attached to the player and hooked up to a first row of Player table via extending from BGM_Player.
    1. It initializes its position and rotation from database in the Start method
    2. It implements BGAddonSaveLoad.BeforeSaveReciever interface to ensure OnBeforeSave method is called before saving. In this method it saves its own position and amount of gold to the database, so while saving those values will be put to the save file.
    
    public class BGPlayer : BGM_Player, BGAddonSaveLoad.BeforeSaveReciever
    {
        public override void Start()
        {
            base.Start();
            //get pos and rotation from the table
            transform.position = m_position;
            transform.rotation = m_rotation;
        }
    
        //this method is called before saving
        void BGAddonSaveLoad.BeforeSaveReciever.OnBeforeSave()
        {
            //save current position, rotation and scene to the database
            m_position = transform.position;
            m_rotation = transform.rotation;
            m_scene = BGE_Scene.FindEntity(scene => string.Equals(scene.Name, SceneManager.GetActiveScene().name));
        }
    }
            
  5. BGSavingLoading.cs It Provides Save/Load functions via SaveLoad addon. More information about Save/Load addon can be found here
    
    public class BGSavingLoading : MonoBehaviour
    {
        //... some code is omitted
        public void Save()
        {
            //save
            var bytes = BGRepo.I.Addons.Get<BGAddonSaveLoad>().Save();
            File.WriteAllBytes(SaveFilePath, bytes);
        }
    
        public void Load()
        {
            //load
            if (!HasSavedFile) return;
    
            var content = File.ReadAllBytes(SaveFilePath);
    
            BGRepo.I.Addons.Get<BGAddonSaveLoad>().Load(content);
    
            //load saved scene
            SceneManager.LoadScene(R.Player.d_scene.Get(PlayerEntity).Name);
        }
    }
            

Releases

Click to see all releases
Version Release date Log
1.1 Nov 10, 2021 Graph binder adn action field examples are added
1.0 March 30, 2020 Initial release
← Back to Downloads