2017-10-12 by Liuqingwen | Tags: Unity3D | Hits
继续上次的 3D 游戏: Survival Shooter 以及 Tanks tutorial 学习总结之后,这次是官方的另一个游戏教程: 2D Roguelike
这是官方的一个 2D 游戏,也是自己认真学习并制作的第一个 2D 游戏。相对于 3D 游戏, 2D 游戏制作和代码编写上感觉会简单点,但是不能小瞧 2D 游戏,毕竟手机上很多游戏都是 2D 画面。
最近很忙,写代码的时间大幅缩水,编写代码的效率也降低了不少,得加油了!总之,学而时习之不亦乐乎,学而不思则罔,思而不学则殆!没毛病,老铁!
1. DontDestroyOnLoad 的使用
我们知道,每次加载新的场景的时候,所有当前场景的物体都会被销毁,如果想要保存当前场景的一些数据,我自己的做法是保存数据到一个全局类中。不过,通过这次学习可以使用 DontDestroyOnLoad
来保证当前物体不会被销毁。
public static GameManager instance = null;
private void Awake() {
//确保当前 GameManager 是单一实例
if (GameManager.instance == null) {
GameManager.instance = this;
}else if (GameManager.instance != this) {
Destroy(this.gameObject);
return;
}
//保证当前 GameManager 不会被销毁
DontDestroyOnLoad(this.gameObject);
}
这里新建了一个静态实例是为了能在其他地方引用到它,而且这个实例是唯一且数据不会被销毁的。
2. 关卡场景加载方法
在 Unity 当中加载场景非常简单,不过那是“简单的场景”,如果场景非常庞大,想象一下,加载新的场景是需要时间的,这时候我们恰好又要在场景加载完后做一些初始化,初始化代码怎么放呢?
这里可以使用 Unity 中的 RuntimeInitializeOnLoadMethod
标签(我暂时这么叫吧,哈),结合 C# 中的 delegate 时间机制,非常简单就能实现,参考如下代码:
//加载场景的代码,注意放到方法里
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex, LoadSceneMode.Single);
//这个方法只家在一次,这个标签的参数指明了这个方法是在场景加载完后才会调用
//(否则这个方法会在场景加载开始的时候就会调用,这不是我们想要的)
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterSceneLoad)]
private static void CallbackInitialization() {
SceneManager.sceneLoaded += OnSceneLoaded;
}
// C# 事件,调用这个方法!
private static void OnSceneLoaded(Scene scene, LoadSceneMode mode) {
//After scene loaded, do something here...
}
这个对我来说是新知识点,有待加强学习啊!
3. 几个关键字:abstract/protected/virtual/override/new
学过 Java 的同学对方法重写非常熟悉,但是 C# 中的一些机制却又有另一片天空,这个 2D 游戏中就让我重新认识了不少关键字: abstract
、 virtual
、 new
等
以游戏代码为例, Player
玩家和 Enemy
敌人都是继承于 MovingObject
基类的:
public abstract class MovingObject : MonoBehaviour {
private int foodPoints;
protected new Rigidbody2D rigidbody2D;
protected virtual bool AttemptMove<T>(int xDir, int yDir) where T : Component {
//do something here...
}
protected abstract void OnCantMove<T>(T component) where T : Component;
}
public class Player : MovingObject {
protected override bool AttemptMove<T>(int xDir, int yDir) where T : Component {
//do something here...
}
protected override void OnCantMove<T>(T component) {
//do something here...
}
}
public class Enemy : MovingObject {
protected override void OnCantMove<T>(T component) {
//do something here...
}
}
简单的说一下代码中的关键字的含义:
new
关键字用在属性面前用于区分(隐藏)基类同名的属性,比如基类 MonoBehaviour
就有一个属性是: rigidbody2D
abstract
用来描述抽象类和抽象方法,抽象方法没有具体实现,但是子类必须实现virtual
也是用来描述抽象方法的,但是这个方法并不抽象,可以有实际代码,子类可以不重写,它的作用就是告诉子类:你可以重新我protected
和 override
就没什么好说的了,这和 Java 中差不多,表示子类属性方法可见性以及重写父类方法( C# 父类中的 virtual
方法)4. Unity 中各种平台代码的混写方式
这个好像和 C++ 中写法一样,不是很熟悉,不过也很简单,模板代码吧:
#if UNITY_IOS || UNITY_ANDROID
private Vector2 touchOrigin = -Vector2.one;
#endif
#if UNITY_IOS || UNITY_ANDROID
//code here for MOBILE platform
#elif UNITY_STANDALONE || UNITY_EDITOR || UNITY_WEBPLAYER
//code here for other platform
#endif
没什么好说的,继续学习!
资料: 2D Roguelike (Unity3D) : https://unity3d.com/learn/tutorials/projects/2d-roguelike-tutorial 简单易懂的解释c#的abstract和virtual的用法和区别: http://blog.csdn.net/wzj0808/article/details/51388034