zoukankan      html  css  js  c++  java
  • Unity3D 游戏开发构架篇 ——角色类的设计与持久化

    在游戏开发中,游戏角色占了很大的篇幅,可以说游戏中所有的内容都是由主角所带动。这里就介绍一下角色类的设计和持久化。

    一、角色类应用场景和设计思想

      游戏中的角色类型不一而足,有不同的技能,有不同的属性等等。有些一个玩家只有一个角色,有些一个玩家可以有多个角色。这里就目前项目来描述一下角色类的构造,思路都是类似的。

      早期我写角色类都是直接一个Class,然后想到什么属性就往里面添加,如果游戏过程中需要对属性的修改,逻辑判断也写在这个类中,这样必然导致类的庞大和臃肿,最后你自己也忘记了自己写在什么地方了。

      后期的逻辑如果修改了,姑且不论属性之间的互相连带和逻辑连带,你的查找就是一件麻烦事。

      这里我们讨论一下一个玩家账号多个角色的构造。

      定为一个角色类,包括玩家的疲劳,金币,元宝等等。角色类包括多个英雄对象。

      一个英雄类,包括英雄的属性,等级等等,英雄对象包括多个属性对象。

      一个属性类,包括属性的值,下一级属性的值等等。

      对这些类的修改,类的内部只提供接口,逻辑的判断存在于外部的部件中,而不是自己类的内部实现。这样代码就简洁明了不少,同样逻辑修改也只需要查找对应的部件即可。

      当然还有更复杂的,如下图所示:

      一个基础属性类衍生出来了Attribute,Virtal,SKill等等。

    二、持久化的应用场景和设计思想

      角色化类创建后,这个类不论游戏的关闭和开启都要和上一次的一样。可以采用持久化的方案。C#中一般采取序列化到本地二进制文件或者XML文件等流序列化。

      当然你也可以采用Unity3D的ScriptableObject方案。

      http://blog.csdn.net/jjiss318/article/details/7195052

    三、核心代码

      BaseState.CS

      基础属性类,可以枚举中动态添加

        [Serializable]
        public class BaseState
        {
            public int _baseValue;
            public int _grown;
            public int _max_baseValue;
    		public Attribute _name;
    
    		
    
    
            public BaseState(int _baseValue, int _grown, Attribute _name, int _max_baseValue)
            {
                this._baseValue = _baseValue;
                this._grown = _grown;
                this._name = _name;
                this._max_baseValue = _max_baseValue;
            }
            //调整接口如下
    		…………………………
        }
    	public enum Attribute
        {
            Might,
            Constitution
        }
    

      BaseCharacter.CS

      基础英雄类,可以枚举中动态添加

      

        [Serializable]
        public class BaseCharacter
        {
            public Character _name;
            public Currency_Kind mycurrency;
            public int price;
            public bool _isLocked;
            public int _level;
            public int _max_level;
            public BaseState[] attribute_list;
    
            public BaseCharacter ( Character _name,Currency_Kind _kind, int price,int _max_level)
            {
                this._name = _name;
                this.mycurrency = _kind;
                this.price = price;
                _isLocked = true;
                _level=0;
                this._max_level = _max_level;
                this.attribute_list= new BaseState[Enum.GetValues(typeof(Attribute)).Length];
                AddAllAttriute(this._name,this.attribute_list);
            }
            private void AddAllAttriute(Character _name, BaseState[] attribute_list)
            {
                AttributeDateBase.GetBaseArrayByName(_name,attribute_list);
            }
    
            
        }
        public enum Character {
            Moking,
            Super_Pig
        }

      序列化方法,这里就采用本地二进制方法

    //持久化英雄数组
            public static void Load()
            {
                Globals.Character = new BaseCharacter[Enum.GetValues(typeof(Character)).Length];
                Debug.Log("load");
    
                //second load
                if (File.Exists(fileName))
                {
                    try
                    {
                        using (FileStream fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read))
                        {
    
                            BinaryFormatter b = new BinaryFormatter();
                            //这里貌似最好一个个序列化
                            //BaseCharacter[] gp = (BaseCharacter[])b.Deserialize(fileStream);
                            for (int i = 0; i <  Globals.Character.Length; i++)
                            {
                                Globals.Character[i] = (BaseCharacter)b.Deserialize(fileStream);
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        Utils.WriteLog("Globals.Save occurs an error:" + ex);
                    }
                }
                else {
                    HeroDateBase.GetBaseArray(Globals.Character);
                }
    
            }
            public static void Save()
            {
                if (Globals.Character == null && Globals.Character.Length <=0)
                {
                    return;
                }
                try
                {
                    using (FileStream fs = new FileStream(fileName, FileMode.Create, FileAccess.Write))
                    {
                        BinaryFormatter b = new BinaryFormatter();
                        //也要一个个反序列化
                        for (int i = 0; i < Globals.Character.Length; i++)
                        {
                            b.Serialize(fs, Globals.Character[i]);    
                        }
                        
                        Debug.Log("Serialize Save");
                    }
                }
                catch (Exception ex)
                {
                    Utils.WriteLog("Globals.Save occurs an error:" + ex);
                }
    
            }

      搞完了英雄类和属性类的持久化,角色类的持久化也就大同小异了,不过角色也就是玩家一个游戏只有一个,也就不用枚举了。

    四、总结

      考虑到英雄类和属性类的字段动态增长,可能每次游戏开辟的内存不同,那么此时反序列化的出来的数据覆盖会不会有错呢?可以考虑一下。

  • 相关阅读:
    linux脚本练习之将数据导入oracle表
    linux脚本之一个程序调用另一个程序
    使用客户端Navicat连接数据库oracle19c
    centos7安装与卸载oracle19c
    Redis-cluster集群搭建(redis版本5.0.4)
    linux下redis的哨兵模式
    使用POI导入Excel文件
    MySQL8.0搭建MGR集群(MySQL-shell、MySQL-router)
    MySQL Shell用法
    CentOS 7下使用rpm包安装MySQL8.0
  • 原文地址:https://www.cnblogs.com/chongxin/p/3716925.html
Copyright © 2011-2022 走看看