美文网首页01_Unity3d
游戏开发学习笔记

游戏开发学习笔记

作者: 道阻且长_行则将至 | 来源:发表于2017-10-31 14:18 被阅读98次

    14.Unity游戏开发中的生命周期

    时间:2017/12/5
    主题:经验总结
    内容:

    • C#对象的生命周期

    了解对象生命周期前,要先理解类、对象与引用是怎么回事。

    • :是定义在代码文件中,保存在硬盘上 ,是对象的蓝本,它描述了对象在内存中大概是什么样子的。
    • 对象: 我们都知道.net将值类型存储在栈中,引用类型存储在堆中,这样做的原因是栈中的数据是轻量级的,而堆中的数据是重量级,目的是在应用程序在操作它们的时候比较方便存取,从而提高程序的运行速度。创建一个对象实例,用new+类名+(),就创建了一个对象实例,创建的这个对象实例是引用类型,被存储在托管堆中,以后就不用管它了,new关键字返回一个对象实例存在的地址,这个存储地址(引用)变量,被放在栈中,实际上应用程序在运行时都是操作的这个引用。
    • 引用:上面说了,就是指 堆数据在堆中的地址 存储在栈上。
    下面进入题,说下对象的生命周期:

    在传统的非托管C++中,用构造函数创建对象实例,清除内存中的对象实例用析构函数,也就是必须要程序员手写消灭对象实例的方法,这样做的话,如果析构函数执行失败,或是由于程序员的疏忽,忘记了析构代码,那么该对象所占有的内存会一直存在内存中(直到应用程序结束),那么这样很容易造成内存资源的浪费,有效的内存空间得不到充分的利用,从而造成内存泄露。那么在.net框架中,这样的情况将不再存在,.net中不用程序显示回收内存,自带的垃圾收集器会帮我们解决这一困扰,那么垃圾收集器是如何工作的呢?
    还是先说下创建对象实例时的内存管理:实际上内存分配存在一个内存指针,它总是指向下一个对象应该放置位置,即当创建一个对象实例,看内存指针在哪里,就将这个对象实例放在指针指向的位置,然后指针再移动到下一个可以存放对象的地址,等待下一个对象的到来。

    创建一个对象实例要经过三步:
    1. 计算新的对象实例要用多少地址

    2. 如果堆中的地址够用,就将调用构造函数创建这个对象将把它放在内存指针指向的位置

    3. 返回对象的引用,并将指针指向下一个对象应该存放的地址。

    接下来到了垃圾回收了! 如果在计算新对象所用空间时发现空闲内在已经不够用了,那么.net就会调用垃圾收集程序做一次垃圾收集。CLR逐个排查不可达的对象,对么在托管堆中这个排查会浪费大量的时间,为了优化这个排查过程,将堆上的每一个对象对归属为某一个代中。CLR将内存中的对象分为0~2代(.net2.0中)。其中

    0代指的是从来没有被标记过垃圾收集的新对象(一般是函数域内的对象,被视为最先收集的对象)
    1代是指在上一次垃圾收集中没有被回收的对象
    2代是在一次以上没有被回收的对象(一般是应该程序的根级)

    当内存中没有位置了,垃圾收集器就开始依次调查和收集0代对象中是否有不可达对象,如果是不可达的,就将它清除,如果是可达的对象就将它标记为1代;直到可以有足够的位置存放新对象,这时不一定所有的0代对象对被清除了,那么它们被标记为1代;(1代是否被标记为2代?)如果被0代对象全部排查过了了,还不够分配给新对象 ,那么就开始排查1代对象,没有被回收的1代对象被标记为2代。如果排查过1代对象仍然不够,就开始排查第2代,就是这样2代对象存在的时间很长。

    注意:进行垃圾收集时.net会将正在运行的进程中的线程全部挂起,等待清理完了,再将它们释放。这样做的目的是确保应用程序在回收过程中不会访问堆。

    无论是指类型的变量或是类类型的变量,其存储单元都是在栈中分配的,唯一不同的是类类型的变量实际上存储的是该类对象的指针,相当于vc6中的CType*,只是在.net平台的语言中将指针的概念屏蔽掉了。我们都知道栈的一大特点就是LIFO(后进先出),这恰好与作用域的特点相对应(在作用域的嵌套层次中,越深层次的作用域,其变量的优先级越高)。因此,再出了“}”后,无论是值类型还是类类型的变量(对象指针)都会被立即释放(值得注意的是:该指针所指向的托管堆中的对象并未被释放,正等待GC的回收)。.NET中的栈空间是不归GC管理的,GC仅管理托管堆。

    我想就我的理解简要说明一下:
    1. GC只收集托管堆中的对象。
    2. 所有值类型的变量都在栈中分配,超出作用域后立即释放栈空间,这一点与VC6完全一样。
    3. 区别类类型的变量和类的对象,这是两个不同的概念。类类型的变量实际上是该类对象的指针变量。如C#中的定义CTypemyType;与VC6中的定义CType* myType;是完全一样的,只是.net语言将*号隐藏了。与VC6相同,必须用new 关键字来构造一个对象,如(C#):CType myType=new CType();其实这一条语句有两次内存分配,一次是为类类型变量myType在栈中分配空间(指针类型所占的空间,对32位系统分配32位,64位系统则分配64位,在同一个系统中,所有指针类型所占的内存空间都是一样的,而
      不管该类型的指针所指向的是何种类型的对象),另一次是在托管堆(GC所管理的堆)中构造一个CType类型的对象并将该对象的起始地址赋给变量myType。正因为如此才造成了在同一个作用域中声明的类类型的变量和该类型的对象的生存期不一样。
    • Unity Monobehaviour对象的生命周期

    Unity3D 脚本生命周期
    Unity 生命周期:http://docs.unity3d.com/Manual/ExecutionOrder.html

    1、静态构造函数

    当程序集被加载的时候就被调用了,如果你的unity处于编辑状态时,此时你保存一个脚本(从而迫使重新编译),静态构造函数会立即被调用,因为unity加载了DLL。并且它将不会再次运行,永远只会执行一次,unity运行时,是不会再次执行了!在一个已部署的游戏上,这个构造器将会在unity加载过程的早期被调用!

    2、非静态构造器

    Unity将会在一个貌似随机的时间调用一个对象的默认构造器。当你编辑一个游戏时,在你保存一个脚本(从而迫使重新编译)后,这构造器将会被立马调用!

    程序运行时被随机调用多次,程序结束时也被调用了(自己测试发现)

    所以不要使用构造器去初始化字段的值,unity的Awake就是专门为这个目的设计的。

    3、Awake

    只会被调用一次,在Start方法之前被调用! 主要用于字段值的初始化工作,禁用脚本,创建游戏对象,或者

    Resources.Load(Prefab)

    对象

    4、Start

    只执行一次,在Awake方法执行结束后执行,但在Update方法执行前执行, 主要用于程序UI的初始化操作,比如获取游戏对象或者组件

    5、Update

    每一帧执行的,监听用户输入,播放动画,当机器忙或者性能差的时候,他会停止执行,会产生停顿的感觉,例如一个人本来在1米的位置,突然到了5米的位置上,产生了跳帧,而下面的FixedUpdate方法则相反!会一米一米的去执行!(自己调试发现,Update是先于OnGUI执行的,且执行一次Update之后,会执行两次OnGUI)

    6、FixedUpdate

    不管当前机器忙不忙,都会保证每一帧执行一次!避免跳帧!固定更新。固定更新常用于移动模型等操作。

    7、LateUpdate

    先执行Update,然后才去执行lateUpdate(Update方法执行完,必定接着执行LateUpdate,而Update和FixedUpdate方法的执行顺序不确定,而且有时候FIxedUpdate执行了多帧,而Update却只执行了一帧,这就是因为跳帧的缘故造成的(取决于你的机器性能)!),如果现在有100个脚本,分别有100个 Update()函数,其中只有一个LateUpdate,那么在同一帧中,等待100个Update()执行完后,才执行这一个LateUpdate()。

    8、OnGUI

    在这里面进行GUI的绘制,且GUI是每帧擦除重绘的!仅仅只是绘制!没有生命周期的概念!所有关于绘制GUI的代码,都要直接或者间接地写到OnGUI方法中!

    9、OnDestroy

    当前脚本销毁时调用

    10、OnEnable

    脚本可用时被调用、如果脚本是不可用的,将不会被调用!

    如果有三个对象,a1 > a2 > a3 (父子级的关系),挂有三个脚本s1,s2,s3,三个脚本都有Awake,Start,OnEnable,OnDisable,Update方法,那么unity执行的顺序为:

    awake1,OnEnable1,awake2,OnEnable2,awake3,OnEnable3,Start1,Start2,Start3,Update1,Update2,Update3

    如果在脚本s2的Awake方法中设置脚本s1不可用(s1.enabled=false),那么脚本的执行结果为:

    awake1,OnEnable1,OnDisable1,awake2,OnEnable2,awake3,OnEnable3,Start2,Start3,Update2,Update3

    如果在脚本s2的Awake方法中设置脚本s3不可用(s3.enabled=false),那么脚本的执行结果为:

    awake1,OnEnable1,awake2,OnEnable2,awake3,Start1,Start2,Update1,Update2

    如果在脚本s2的Start方法中设置脚本s3不可用(s3.enabled=false),那么脚本的执行结果为:

    awake1,OnEnable1,awake2,OnEnable2,awake3,OnEnable3,Start1,OnDisable3,Start2,Update1,Update2

    总结: 关键是看设置脚本不可用的位置:

    A

    (1)如果在父级的Awake方法里面设置子级的脚本不可用
    那么仅仅只会执行子级里面的Awake方法,当子级被激活后(enabled=true),会先执行OnEnable,然后执行Start方法,Update等帧序列方法都会开始执行

    (2) 如果在父级的Start方法里面设置子级的脚本不可用
    那么会执行子集里面的Awake,OnEnable和OnDisable方法,当子级被激活后(enabled=true),会先执行OnEnable,然后执行Start方法,Update等帧序列方法也都会开始执行

    B

    (1) 如果在子级的Awake方法里面设置父级的脚本不可用
    那么会执行父级里面的Awake,OnEnable和OnDisable方法,当父级被激活后(enabled=true),会先执行OnEnable,然后执行Start方法,Update等帧序列方法都会开始执行

    (2)如果在子级的Start方法里面设置父级的脚本不可用
    那么会执行父集里面的Awake,OnEnable,Start和OnDisable方法,当父级被激活后(enabled=true),会先执行OnEnable,Update等帧序列方法也都会开始执行

    如果被激活的脚本之前没有调用Start方法,那么当此脚本被激活后,会调用一次Start方法!具体,看生命周期第一幅图,在文章后面!

    11、OnDisable

    如果脚本被设置为不可用将会被执行,程序结束时也会执行一次!

    OnEnableOnDisable 只受脚本的可用状态的影响(enabled)

    OnBecameVisibleOnBecameInvisible 是受对象是否可见的影响(如下)!即使脚本设置为不可用,OnBecameVisibleOnBecameInvisible也会被执行,主要是看对象是否在场景中显示了!

    OnBecameVisible 和 OnBecameInvisible :

    (1)当一开始加载一个对象时:

    Game 显示 Scene 显示 OnBecameInvisible 不执行 OnBecameVisible 执行

    Game 不显示 Scene 不显示 OnBecameInvisible 不执行 OnBecameVisible 不执行

    Game 不显示 Scene 显示 OnBecameInvisible 不执行 OnBecameVisible 执行

    Game 显示 Scene 不显示 OnBecameInvisible 不执行 OnBecameVisible 执行

    小结:只要Game和Scene中有一个显示了,OnBecameVisible 就会执行!而OnBecameInvisible 一直都不会执行

    (2)当移动对象时:

    game 和 scene 对象必须在两个场景中同时消失 OnBecameInVisible 才执行

    scene 和 game 只要有一方进入了场景 OnBecameVisible 就执行了

    脚本执行顺序总结:

    假如现在有三个GameObject对象:a1 > a2 > a3 (a1为a2的父节点,a2为a1的父节点,unity执行脚本的顺序是从上往下执行,也就是说先执行父节点上的脚本,再去执行子节点的脚本,子节点上如果有多个脚本,那么也是自上而下的顺序执行),这三个对象对应各有一个脚本:s1,s2,s3,且这三个脚本代码都一样,都有Awake,Start,Update,LateUpdate,FixUpdate,那么当运行程序时,程序会进行分组,即把s1,s2,s3中的Awake方法组成一组,把Start方法组成一组,把Update方法组成一组,把LateUpdate方法组成一组,把FixUpdate方法组成一组,最后按照Awake,Start,FixUpdate,Update,LateUpdate(FixUpdate和Update顺序不确定)的顺序依次执行!即把Awake组里面的Awake方法全执行完,再去依次执行Start,FixUpdate,Update,LateUpdate组里面的代码:执行顺序如下:

    Awak1 Awak2 Awak3 Start1 Start2 Start3 FixUpdate1 FixUpdate2 FixUpdate3 Update1 Update2 Update3 LateUpdate1 LateUpdate2 LateUpdate3


    image.png
    image.png
    image.png

    13.游戏类型

    时间:2017/12/5
    主题:经验总结
    内容:

    • ACT 动作游戏
         Action Game
      
    • ARPG 动作+角色扮演游戏
        Action RPG
      
    • AVG 冒险游戏
        Advanture Game
      
    • AAVG 动作+冒险游戏
        Action Adventure Game
      
    • CAG 卡片游戏
        Card Game
      
    • FPS 第一人称视点射击游戏
        First Person Shooting
      
    • FTG 格斗游戏
        Fighting Game
      
    • MMORPG 大型多人在线角色扮演游戏
       Massive Multiplayer Online Role-Playing Game
      
    • MUG 音乐游戏
        Music Game
      
    • PUZ 益智类游戏
        Puzzle
      
    • RAC 赛车游戏
        RACe Game
      
    • RPG 角色扮演游戏
        Role-Playing Game
      
    • RTS 即时战略游戏
        Real-Time Strategy Game
      
    • SFTG 模拟格斗类游戏
        Simulation FTG
      
    • SLG 模拟/战略游戏
        SimuLation Game
      
    • SPG 运动游戏
        SPort Game
      
    • SRPG 战略角色扮演游戏
        Simulation RPG
      
    • STG 射击游戏
        Shooting Game
      
    • TAB 桌面游戏
        TABle
      
    • ETC 其他类游戏

    12.C#的类型约束

    时间:2017/11/29
    主题:经验总结
    内容:
    这是参数类型约束,指定T必须是Class类型。

    public class Singleton<T> where T : class, new()
    {
    
    }
    
    

    .NET支持的类型参数约束有以下五种:

    where T : struct  //T必须是一个结构类型
    where T : class  //T必须是一个Class类型
    where T : new()  //T必须要有一个无参构造函数
    where T : NameOfBaseClass  // T必须继承名为NameOfBaseClass的类
    where T : NameOfInterface  //T必须实现名为NameOfInterface的接口
    

    11.Unity3D之Vector3.Dot(点积)和Vector3.Cross(叉积)的使用

    时间:2017/11/23
    主题:经验总结
    内容:

    在Unity3D中, Vector3.Dot 表示求两个向量的点积; Vector3.Cross 表示求两个向量的叉积。

    点积计算的结果为数值,而叉积计算的结果为向量。两者要注意区别开来。

    在几何数学中:

    1.点积

    点积的计算方式为: a·b=|a|·|b|cos<a,b> 其中|a|和|b|表示向量的模,<a,b>表示两个向量的夹角。另外在 点积 中,<a,b>和<b,a> 夹角是不分顺序的。 所以通过点积,我们其实是可以计算两个向量的夹角的。

    另外通过点积的计算我们可以简单粗略的判断当前物体是否朝向另外一个物体: 只需要计算当前物体的transform.forward向量与 (otherObj.transform.position – transform.position)的点积即可, 大于0则面对,否则则背对着。当然这个计算也会有一点误差,但大致够用。

    2.叉积

    叉积的定义: c =a x b 其中a,b,c均为向量。即两个向量的叉积得到的还是向量!

    性质1: c⊥a,c⊥b,即向量c垂直与向量a,b所在的平面 。

    性质2: 模长|c|=|a||b|sin<a,b>

    性质3: 满足右手法则 。从这点我们有axb ≠ bxa,而axb = – bxa。所以我们可以使用叉积的正负值来判断向量a,b的相对位置,即向量b是处于向量a的顺时针方向还是逆时针方向。

    根据上面的性质2,我们也同样的可以计算出两个向量的夹角。


    10.编程感悟

    时间:2017/11/16
    主题:经验总结
    内容:
    项目进行到了改bug阶段,改了几天bug,忽然感觉编程就像挖水道,为了把水引到目的地,我们动用各种工具,分流,改变形态,汇集,调整,最终打通水路,顺利完成目标,这时的满足感和成就感令人沉醉.
    ssh://developer@192.168.1.252/git/EatChicken3D.git


    9.UGui背包系统的实现

    时间:2017/11/14
    主题:经验总结
    内容:

    需要的UI组件:

    • Button
      必备组件,背包的格子本质上就是一个按钮,可以触发背包的各种事件.
    • Grid Layout Group
      这个组件能让背包变得更像背包,因为它能够把背包的格子很好的排列起来.
    • Scroll View
      当需要能滚动的背包时就需要这个组件了,比如骑马与砍杀的背包系统
    • Mask
      这个组件在滚动背包中是必不可少的,只显示固定的区域

    基本思路:

    背包系统的设计,主要包括两大方面的设计,第一.物品类的设计,主要包括物品基类及各个继承类的属性设计.
    第二.背包类的设计,主要包括背包基类及各个具体实现类的功能接口的设计.其他功能如装备提示,整理排序等也都很好实现.

    主要模块:

    1. 物品类数据模型的设计
    2. 背包类功能接口的设计
    3. 背包管理器和提示信息,整理排序的设计.

    延伸扩展:

    背包系统和游戏中很多其他的系统都很相像,如商店系统,锻造系统,抽奖系统等,实现大概思路也都差不多,主要的思想就是设计好数据模型和相应的增删改查工作,说到底,UI只是表现形式而已.


    8.Unity3d 单例模式的几种实现

    时间:2017/11/13
    主题:经验总结
    内容:

    今天我们要说的就是GOF23中设计模式里面的一个,叫做单例模式。
    单例模式中,一个实例不允许有第二个自己存在,要保证实例唯一。他的一般解释就是,保证一个类只有一个实例,并提供一访问他的全局访问点。单例模式因为封装他的唯一实例,他就可以严格的控制客户怎样访问他以及何时访问他。下面我们就单例模式在unity引擎开发中的实现来做一些简单说明。

    第一种实现方式:

    using UnityEngine;
    
    using System.Collections;
    
    public class SigletonOnlyOne : MonoBehaviour
    
    {
    
        public static SigletonOnlyOne instance;
    
        public void Start()
    
        {
    
            if (instance==null)
    
            {
    
                instance = this;
    
            }
    
        }
    
        public string ShowMsg(string msg)
    
        {
    
            return msg;
    
        }
    
    }
    
    • 优点:

    不需要重构什么,直接编码。方便其他类使用。

    • 缺点:

    每个要实现单例的类都需要手动写上相同的代码,代码重复对我们来说可不是好事情。同时需要把实现单例的类手动绑定到游戏对象上才可以使用。

    第二种实现方式:

    using UnityEngine;
    
    using System.Collections;
    
    /// <summary>
    
    /// 定义单例模板基类。
    
    /// </summary>
    
    /// <typeparam name="T"></typeparam>
    
    public class Singleton<T> : MonoBehaviour where T : MonoBehaviour
    
    {
    
        private static T instance;
    
        public static T Instance
    
        {
    
            get { return Singleton<T>.instance; }
    
        }
    
        public void Awake()
    
        {
    
            if (instance == null)
    
            {
    
                instance = GetComponent<T>();
    
            }
    
        }
    
        public void OnApplicationQuit()
    
        {
    
            instance = null;
    
            Debug.Log("quit");
    
        }
    
    }
    
    • 优点:

    通过代码重构,去除掉了重复的代码。想具有单例功能的类。只需要继承模板基类就可以具有单例的作用。

    • 缺点:

    模板单例不需要绑定到游戏对象,但是被其他脚本调用的需要手动绑定到游戏对象上才可以使用。

    第三种实现方式:

    using UnityEngine;
    
    using System.Collections;
    
    /// <summary>
    
    /// 定义单例模板基类。
    
    /// </summary>
    
    /// <typeparam name="T"></typeparam>
    
    public class Singleton<T> : MonoBehaviour where T : MonoBehaviour
    
    {
    
        private static T instance;
    
        public static T Instance
    
        {
    
            get
    
            {
    
                if (instance == null)
    
                {
    
                    GameObject singleton = new GameObject();
    
                    singleton.name = "Singleton";
    
                    instance = singleton.AddComponent<T>();
    
                }
    
                return instance;
    
            }
    
        }
    
        public void OnApplicationQuit()
    
        {
    
            instance = null;
    
            Debug.Log("quit");
    
        }
    
    }
    
    • 优点:

    不需要手动绑定单例到游戏对象就可以使用。

    • 缺点:

    这些都是游戏对象,在unity3d中只能在主线程中进行调用。所以网络多线程方面会产生单例的不唯一性,在这里就可以忽略了。

    第四种实现方式:

    using System;
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    namespace ETAFramework
    {
        /// <summary>
        /// 普通单例模式
        /// </summary>
        public class Singleton<T> where T : new()
        {
    
            private static T _instance;
            private static readonly object _syslock = new object();
    
            public static T getInstance()
            {
                if (_instance == null)
                {
                    //双检锁
                    lock (_syslock)
                    {
                        if (_instance == null)
                        {
                            _instance = new T();
                        }
                        else
                        {
                            return _instance;
                        }
                    }
                }
                
                return _instance;
            }
            
        }
    }
    

    第五种实现方式:

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using System;
    
    namespace ETAGame
    {
        /// <summary>
        /// 单例模式模板类
        /// </summary>
        public static class Singleton<T> where T : class
        {
            /*  Instance    */
            private static T _instance;
    
            private static readonly object syslock = new object();
    
            /* Serve the single instance to callers */
            public static T Instance
            {
                get
                {
                    if (_instance == null)
                    {  
                        lock (syslock)
                        {  
                            if (_instance == null)
                            {  
                                _instance = (T)Activator.CreateInstance(typeof(T), true);
    
                                return _instance;  
                            }
                            else
                            {  
                                return _instance;  
                            }  
                        }  
                    }
                    else
                    {  
                        return _instance;  
                    }  
                }
            }
        }
    }
    
    

    第六种实现方式:

    using System;
    
    public class Singleton<T> where T : class, new()
    {
        private static T s_instance;
    
        public static T instance
        {
            get
            {
                if (Singleton<T>.s_instance == null)
                {
                    Singleton<T>.CreateInstance();
                }
                return Singleton<T>.s_instance;
            }
        }
    
        protected Singleton()
        {
        }
    
        public static void CreateInstance()
        {
            if (Singleton<T>.s_instance == null)
            {
                Singleton<T>.s_instance = Activator.CreateInstance<T>();
                (Singleton<T>.s_instance as Singleton<T>).Init();
            }
        }
    
        public static void DestroyInstance()
        {
            if (Singleton<T>.s_instance != null)
            {
                (Singleton<T>.s_instance as Singleton<T>).UnInit();
                Singleton<T>.s_instance = (T)((object)null);
            }
        }
    
        public static T GetInstance()
        {
            if (Singleton<T>.s_instance == null)
            {
                Singleton<T>.CreateInstance();
            }
            return Singleton<T>.s_instance;
        }
    
        public static bool HasInstance()
        {
            return Singleton<T>.s_instance != null;
        }
    
        public virtual void Init()
        {
        }
    
        public virtual void UnInit()
        {
        }
    }
    
    

    8.Unity3d Awake() 和 Start()的区别

    时间:2017/11/13
    主题:经验总结
    内容:
    Awake函数在这个脚本在场景中加载时就会调用,至于所有脚本的Awake函数的调用顺序是未知的。
    然后,在所有的Awake函数调用完毕后,才开始调用Start函数。需要注意的是,Start函数也不是一定立即执行的,它是在该脚本第一次调用Update函数之前调用的,也就是说,如果这个脚本一开始的状态是disable的,那么直到它变成enable状态,在Update函数第一次执行前,才会执行Start函数。
    两个函数的执行顺序是时间有时正是某些Bug的产生原因!而且这些Bug往往很难发现。


    8.Unity2017游戏模块设计思想

    时间:2017/11/2
    主题:经验总结
    内容:

    • 游戏模块设计分层

    7.Unity2017 Splash设置

    时间:2017/11/1
    主题:经验总结
    内容:

    1 2

    6.圆形多个物品生成点公式

    时间:2017/10/31
    主题:经验总结
    内容:

    公式推导:

    image.png

    代码示例:

    image.png

    5.万能游戏框架学习笔记

    时间:2017/10/25
    主题:学习笔记
    内容:

    万能框架设计模式

    设计模式 工厂模式
    设计模式 策略模式
    设计模式 观察者模式
    设计模式 单例模式
    设计模式 代理模式
    设计模式 门面模式
    设计模式 建造者模式
    设计模式 组合模式
    对模式用法总结

    万能框架之框架实现

    框架原理讲解
    框架实现 消息类 实现
    框架实现之 事件系统,数据结构 消息链表实现
    框架实现 各个模块manager
    互动答疑
    框架实现 个模块基础类
    框架实现 使用注意事项

    万能框架之socket网络通信模块

    网络通信 Socket 网络的讲解
    网络通信 Socket客户端的实现
    网络通信 Socket 消息的接收 封装
    网络通信 Socket 类与框架的整合
    网络通信之 C# Protobuffer 使用

    万能框架之 资源管理

    资源管理 Editor 类使用案例
    资源管理之Itween 与Editor
    资源管理之 Transform 与Editor
    资源管理之AssetBundle 实现 自动打包工具 编写
    自动打包实现 及
    资源管理之AssetBundle 动态加载实现
    资源管理之AssetBundle 内存管理 及依赖关系 管理(一)
    资源管理之AssetBundle 内存管理 及依赖关系 管理(二)

    万能框架之 RPG游戏实战

    RPG游戏实战 RPG游戏UI 制作
    RPG游戏实战 主角色人物控制 动画控制
    RPG游戏实战 主角色人物控制 动画控制 及答疑
    RPG游戏实战 3D数学与向量
    RPG游戏实战 矩形 攻击
    RPG游戏实战 NPC 控制
    RPG游戏实战 NPC 逻辑控制
    完善游戏
    RPG游戏实战 小地图实现
    RPG游戏实战 顶点Mesh讲解
    RPG游戏实战 人物换装
    RPG游戏实战 BlendShape 动画
    RPG游戏实战 Mesh 顶点操作

    万能框架之 热更新

    热更新 Lua 变量 控制流
    热更新 Lua 函数
    热更新 Lua 字典 与数组
    热更新 Lua 面对对象编程
    热更新 Lua 深层次堆栈讲解
    热更新 Lua 框架 消息实现
    热更新 消息处理中心实现
    热更新 链表实现
    热更新 各个Base 实现
    热更新之Lua 加密 实现
    热更新之Lua 与 C# 通信
    热更新之Lua 与 C# 通信

    万能框架之 python工具篇
    Python 基础知识讲解
    Python 控制语句讲解
    工具篇 Python 基础知识讲解
    工具篇 Python 控制语句讲解
    工具篇 Python 数组
    工具篇 Python 字典讲解
    工具篇 解包APK实现
    工具篇 解包APK实现
    工具篇 签名实现
    工具篇 Python自动打包全实现

    主程面试技巧篇:

    面试技巧之简历篇
    面试技巧之面试技巧
    面试技巧之工作技巧篇

    万能框架目录说明 根目录说明

    Assetbundle: 全部打包的资源临时文件夹
    ITools: 工程中常用的工具
    BuildLua:加密lua python脚本
    protoc-gen-lua-master: protobuffer 生成工具。
    Python: 包括python 安装包 和 常用 exe 工具。 可以将bin 放入环境变量中。
    luaEncoder: 对lua 进行加密用的工具。

    image02

    Art: 用到的资源全部放在这里
    codeandweb.com:Texturepacker 工具 文件夹
    Editor: lua 要wrap的文件
    FrameExaple:框架的例子都在这
    Lua: 做热更新写的lua 脚本都放这里
    Plugins: 框架和lua 的dll 全在这
    Scripts: 开发游戏的各个模块都在这

    脚本目录说明

    Animal: 动画工具
    Asset: assetbundle 模块
    Camera: 相机常用功能
    Configer: 全局的配置文件都在这。
    DB: sqlite3 常用的功能
    Editor: 工具栏的工具全在这。
    ForLua: 为了lua 写的一些功能。
    GameLogic: 游戏逻辑
    GameManager: 整个游戏控制
    Net:常用的 tcp udp通讯类
    Particle: 例子常用的工具类
    SkyBox: SkyBox 常用工具
    Tools: 封装的各种工具类。
    UI: UI 各种工具类。


    4.游戏编程中需要重点掌握的设计模式

    时间:2017/10/25
    主题:经验总结
    内容:
    设计模式共有23种,这是基本常识,设计模式这本书如果从头学起来,非常抽象,不容易理解。游戏开发常用的设计模式:单例模式,工厂模式,抽象工厂模式,状态模式,观察者模式等这几个要重点掌握。除了提到的这几个,还有一个应用非常广泛的设计模式就是MVC设计模式,它的全称:Model,View,Controller,中文意思就是模型,视图,控制器。它以前主要是应用在Web端,现在我们拿来将其应用到游戏开发中。

    • 单例模式
    • 工厂模式
    • 抽象工厂模式
    • 状态模式
    • 观察者模式
    • MVC设计模式
    6种设计原则
    23中设计模式解析

    3.U3D编程进阶的一些思想

    时间:2017/10/24
    主题:经验总结
    内容:
    所谓编程,就是选择好恰当的数据结构设计好数据模型,选择恰当的设计模式划分不同功能的各个模块,处理好各个模块的引用关系,然后在控制模块的脚本里做好逻辑判断从输入产生输出。

    • 生命周期思想:
      要时刻注意着游戏中各种对象和组件的生命周期,一个对象从出生到销毁要有一个清晰的认识。如果编程时这个认识不清,非常容易造成空引用,内存占用过多,功能不执行等问题。
    • 面向对象思想:
      写代码不能想到哪里写到哪里,写的时候脑子里要思考怎么才能更好的调用和维护,这方面比较抽象,只能通过多写代码,多做项目来增长经验了。
    • 分层思想:
      一个游戏项目的架构从大方面可以分为框架层和业务层,双方要保持经纬分明,业务层只能调用而不能修改框架层的逻辑,从小方面可以分为数据模块,UI模块和业务模块,也就是MVC设计,这三个模块各自做好自己的事互相之间的交叉要尽量减少。
    • 引用思想:
      不要怕脚本太多,哪怕脚本再多,每个脚本都能取到任何一个对象或数据的引用,都能取的到,就看怎么组织代码了。不同作用的代码为什么要分开,是为了,其实只是为了方便管理和维护,你甚至可以把项目的所有脚本都写到一个类里面,照样可以跑起来,但是这样的话维护起来就非常麻烦了。 把不同作用的代码分门别类放好,有对数据进行增删改查的,有负责对象的具体行为的,有和UI进行交互的,各司其职。
    • 输入输出思想:
      程序就是输入处理后产生输出,每个函数就是输入输出,每个类就是大型的函数,每个模块就是更大型的函数,功能都是输入输出。

    2.学什么和怎么学

    时间:2017/10/22
    主题:学习规划
    内容:
    做Unity3d一年多了,感觉我还是非常喜欢这个行业的.也非常喜欢程序员这个职业,但是最近一段时间心有一些浮躁,想学的东西有太多,但是时间是一定的,面面俱到注定无法取得很大的成就,因此我把以后的学习路线做一个简单的规划,把钢使在刀刃上.

    学习内容
    • 持续学习的内容:
      C#编程, Unity3d游戏开发, 包括各种API, 功能模块, 设计思想, 游戏框架构等项目编程知识. 这是我的饭碗,一定要不断加强.
    • 需要补习的内容:
      微积分, 线性代数, 数据结构和算法, 计算机图形学, 操作系统, 计算机网络等计算机底层知识. 学习这些基础知识能提高我的上限.
    • 业余学习的内容:
      Shader, C++, Python等未来可能会用到的知识以及独立游戏制作需要的其他软件. 这些知识能让我掌握职业主动权.
    学习时间:

    每天下班后2小时和节假日.

    学习方式:

    看教程,看书,结合做项目,学习过程要形成笔记.方便以后查阅.


    1.学习笔记的建立和约定

    时间:2017/10/22
    主题:学习规划
    内容:
    用来记录日常学习遇到的知识点.以后都按照第一条的也就是现在写的这条的格式进行记录. 为了方便查看,笔记按照从后往前的顺序写.

    相关文章

      网友评论

        本文标题:游戏开发学习笔记

        本文链接:https://www.haomeiwen.com/subject/xulbpxtx.html