Minigame Learning for Day 3
2017-07-25 08:56
405 查看
C# 基础 —— 类中私有构造函数作用
如果类成员有private 修饰符,就不允许在类范围以外访问这个类成员。对类构造函数应用private修饰符时,则禁止外部类创建该类的实例。尽管看上去不好理解(既然不能实例化,那么这个类还有什么用处?),但实际上这是一个功能极其强大的特性。
最明显的是,如果类只通过静态方法和字段来提供功能,那么就常常使用私有构造函数。
现在可能会很自然地出现这样一个问题:要避免实例化,使用私有构造函数好,还是使用抽象类更好一些?答案在于要理解这二者的区别。
首先来考虑继承,虽然抽象类不能实例化,但其真正的目的是用于作为基类,以便派生类(可实例化)创建自己的实现。
使用私有构造函数不允许外部方法实例化这个类,但却允许此类中的公共方法(有时也称为工厂方法,factory method)创建对象。也就是说,类可以创建自身的实例,控制外界对它的访问,以及控制创建的实例个数。
C# 基础 —— C#中的构造函数
构造函数主要是用来创建对象时为对象赋初值来初始化对象。总与new运算符一起使用在创建对象的语句中。A a = new A( );构造函数具有和类一样的名称;但它是一个函数具有函数的所有特性,同一个类里面可以有多个参数不同的构造函数,也就是函数的多态。
构造函数是在实例化类时最先执行的方法,通过这个特性可以给对象赋初值。
构造函数没有返回值,也不能用void修饰,只有访问修饰符。
每个类中都有一个构造函数,如果用户定义的类中没有显式的定义任何构造函数,编译器就会自动为该类型生成默认构造函数(自动创建无参构造函数)
C#基础 —— 重载与覆盖
所谓重载指的是同一个类中有两个或多个名字相同但是参数不同的方法。重载,必然发生在一个类中,函数名相同,参数类型或者顺序不同构成重载,与返回类型无关。override:过载也称为重写,是指子类对父类中虚函数或抽象函数的“覆盖”(这也就是有些书将过载翻译为覆盖的原因),但是这种“覆盖”和用new关键字来覆盖是有区别的。
new:覆盖指的是不同类中(基类或派生类)有两个或多个返回类型、方法名、参数都相同,但是方法体不同的方法。但是这种覆盖是一种表面上的覆盖,所以也叫隐藏,被覆盖的父类方法是可以调用得到的。
重载覆盖的发生条件:
重载,必然发生在一个类中,函数名相同,参数类型或者顺序不同构成重载,与返回类型无关。
重写,必然发生在基类和派生类中,其类函数用virtual修饰,派生类用override修饰
覆盖,在子类中写一个和基类一样名字(参数不同也算)的非虚函数,会让基类中的函数被隐藏,编译后会提示要求使用New关键字。
C# 基础 —— 静态类与非静态类、静态成员的区别
静态类静态类与非静态类的重要区别在于静态类不能实例化,也就是说,不能使用 new 关键字创建静态类类型的变量。在声明一个类时使用static关键字,具有两个方面的意义:首先,它防止程序员写代码来实例化该静态类;其次,它防止在类的内部声明任何实例字段或方法。
静态类的主要特性:
仅包含静态成员
无法实例化
是密封的
不能包含实例构造函数
静态成员
1、非静态类可以包含静态的方法、字段、属性或事件
2、无论对一个类创建多少个实例,它的静态成员都只有一个副本
注意:
1:静态类在内存中是一直有位置的;
2:非静态类在实例化后是在内存中是独立的,会存储在内存的静态区,它的变量不会重复,在使用后会及时销毁,所以不会出现未知的错误。
3:建议更多地使用一般类(非静态类),因为static会提前占用系统资源,使用之前要考虑清楚。
使用选择
当定义的类不需要进行实例化时,我们使用静态类;如果需要实例化对象,需要继承等特性时,应该使用非静态类,并且将统一使用的变量和方法设为静态的,那么所有实例对象都能访问。
C# 设计模式——单例模式
1、单例模式的介绍:单例模式就是保证一个类只有一个实例的一种实现方法。确保一个类只有一个实例,并提供一个全局访问点。
2、为什么会有单例模式?操作系统只能有一个任务管理器,现实生活中有这样的应用场景,自然在软件设计领域必须有这样的解决方案。(软件设计也是现实生活中的抽象)
3、剖析单例模式的实现思路
剖析过程:从单例模式概念(确保一个类只有一个实例,并提供一个访问它的全局访问点)入手,可以把概念拆分为两个部分:(1)确保一个类只有一个实例;(2)提供一个访问它的全局访问点
菜鸟:怎样确保一个类只有一个实例了? 老鸟:那就让我帮你分析下,你创建类的实例会想到用什么方式来创建的呢? 新手:用new关键字啊,只要new下就创建了该类的一个实例了,之后就可以使用该类的一些属性和实例方法了 老鸟:那你想过为什么可以使用new关键字来创建类的实例吗? 菜鸟:这个还有条件的吗?........., 哦,我想起来了,如果类定义私有的构造函数就不能在外界通过new创建实例了(注:有些初学者就会问,有时候我并没有在类中定义构造函数为什么也可以使用new来创建对象,那是因为编译器在背后做了手脚了,当编译器看到我们类中没有定义构造函数,此时编译器会帮我们生成一个公有的无参构造函数) 老鸟:不错,回答的很对,这样你的疑惑就得到解答了啊 菜鸟:那我要在哪里创建类的实例了? 老鸟:你傻啊,当然是在类里面创建了(注:这样定义私有构造函数就是上面的一个思考过程的,要创建实例,自然就要有一个变量来保存该实例把,所以就有了私有变量的声明,但是实现中是定义静态私有变量,朋友们有没有想过——这里为什么定义为静态的呢?对于这个疑问的解释为:每个线程都有自己的线程栈,定义为静态主要是为了在多线程确保类有一个实例) 菜鸟:哦,现在完全明白了,但是我还有另一个疑问——现在类实例创建在类内部,那外界如何获得该类的一个实例来使用它了? 老鸟:这个,你可以定义一个公有方法或者属性来把该类的实例公开出去了(注:这样就有了公有方法的定义了,该方法就是提供方法问类的全局访问点)
/// <summary> /// 单例模式的实现(该实现方法仅在单线程下是完美的) /// </summary> public class Singleton { //定义一个静态变量来保存类的实例 private static Singleton _instance; //定义私有构造函数,使外界不能创建该类实例 private Singleton() { } /// <summary> /// 定义公有方法提供一个全局访问点,同时你也可以定义公有属性来提供全局访问点 /// </summary> /// <returns></returns> public static Singleton GetInstance() { if (_instance == null) { _instance = new Singleton(); } return _instance; } }
LockStep框架使用
1、新建工程2、导入相关文件
Morefunlockstep.dll(新建一个Plugins文件夹,.dll文件放进来)
NetPkg四个网络模块脚本(新建一个DemoNet文件夹)
NetPkg.cs、NetPkgManager、NetPkgSender(不用任何修改)
NetPkgHandle.cs(注意加入游戏的回应,设置随机数种子):GameManager.Instance.SetRandom(rsp.randomSeed);
GameManager.cs(自己新建)
using System.Collections; using System.Collections.Generic; using UnityEngine; using Morefun.LockStep; public class GameManager : Singleton<GameManager> { public FRandom random { get; private set; } public void SetRandom(int seed) { random = new FRandom(seed); } }
Editor文件夹(GameIdBuild.cs)
Resources文件夹(GameID文件夹/GameID文件)
3、LockStep 和 Game 启动、初始化 —— Main.cs
using System.Collections; using System.Collections.Generic; using UnityEngine; using Morefun.LockStep; using Morefun.LockStep.Net; public class Main : MonoBehaviour { private void Start() { LockstepDebug.RegisteLogCallback(Debug.Log, Debug.LogWarning, Debug.LogError, null); LockStepManager.Init(OnLockstepTick, OnLockstepFrameMiss); LockStepManager.maxTimesPerFrame = 10; LockStepManager.Play(); Game.Start(); RequestHandle.RegistMessages(); NetPkgManager.ConnectToDemoServer(); } private void OnLockstepTick() { } private void OnLockstepFrameMiss(LList<int> missedFrameList) { int frameCount = missedFrameList.Count; for (int i = 0; i < frameCount; i++) { NetPkgSender.SendGetLostFrame((uint)missedFrameList[i], 1); } } private void Update() { NetPkgManager.Update(); LockStepManager.Update(); } private void OnDestroy() { NetPkgManager.Close(); LockStepManager.Stop(); } }
4、连接服务器创建房间(UI 和 脚本)
using System.Collections; using System.Collections.Generic; using UnityEngine; using Morefun.LockStep.Net; using UnityEngine.UI; public class LoginUI : MonoBehaviour { private static LoginUI _instance; public static LoginUI Instance { get { return _instance; } } private void Awake() { _instance = this; } public InputField roomField; public InputField nameField; public void SendJoin() { NetPkgManager.Join(nameField.text.ToCharArray(), (ushort)short.Parse(roomField.text)); } public void SendReady() { NetPkgSender.SendGameReady(NetPkgManager.LocalUIN); } }
相关文章推荐
- Minigame Learning for Day 7
- Minigame Learning for Day 5
- Minigame Learning for Day 4
- Minigame Learning for Day 6
- Minigame Learning for Day 1
- Minigame Learning for Day 2
- Minigame Learning for Day 8
- Crazy Learning for Day 13
- Ending Learning for Day 5
- Unity Learning for Day 5
- Data structures for game programming learning notes (二)——array
- Unity Learning for Day 14
- Crazy Learning for Day 10
- Data structures for game programming learning notes (三)——bitvector
- Unity Learning for Day 15
- Ending Learning for Day 11
- Unity Learning for Day 2
- Ending Learning for Day 14
- Unity Learning for Day 16
- Crazy Learning for Day 6