【学习笔记】Unity3D官方游戏教程:2D Roguelike

2017-10-12 by Liuqingwen | Tags: Unity3D

一、前言

继续上次的 3D 游戏: Survival Shooter 以及 Tanks tutorial 学习总结之后,这次是官方的另一个游戏教程: 2D Roguelike

这是官方的一个 2D 游戏,也是自己认真学习并制作的第一个 2D 游戏。相对于 3D 游戏, 2D 游戏制作和代码编写上感觉会简单点,但是不能小瞧 2D 游戏,毕竟手机上很多游戏都是 2D 画面。

最近很忙,写代码的时间大幅缩水,编写代码的效率也降低了不少,得加油了!总之,学而时习之不亦乐乎,学而不思则罔,思而不学则殆!没毛病,老铁! joy

二、知识点

1. DontDestroyOnLoad 的使用

我们知道,每次加载新的场景的时候,所有当前场景的物体都会被销毁,如果想要保存当前场景的一些数据,我自己的做法是保存数据到一个全局类中。不过,通过这次学习可以使用 DontDestroyOnLoad 来保证当前物体不会被销毁。

GameManager.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
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);
}

这里新建了一个静态实例是为了能在其他地方引用到它,而且这个实例是唯一且数据不会被销毁的。 smile

2. 关卡场景加载方法

在 Unity 当中加载场景非常简单,不过那是“简单的场景”,如果场景非常庞大,想象一下,加载新的场景是需要时间的,这时候我们恰好又要在场景加载完后做一些初始化,初始化代码怎么放呢?

这里可以使用 Unity 中的 RuntimeInitializeOnLoadMethod 标签(我暂时这么叫吧,哈),结合 C# 中的 delegate 时间机制,非常简单就能实现,参考如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//加载场景的代码,注意放到方法里
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 游戏中就让我重新认识了不少关键字: abstractvirtualnew

以游戏代码为例, Player 玩家和 Enemy 敌人都是继承于 MovingObject 基类的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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 也是用来描述抽象方法的,但是这个方法并不抽象,可以有实际代码,子类可以不重写,它的作用就是告诉子类:你可以重新我
  • protectedoverride 就没什么好说的了,这和 Java 中差不多,表示子类属性方法可见性以及重写父类方法( C# 父类中的 virtual 方法)

4. Unity 中各种平台代码的混写方式

这个好像和 C++ 中写法一样,不是很熟悉,不过也很简单,模板代码吧:

1
2
3
4
5
6
7
8
9
#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


Kommentare: