Unity-实现功能

游戏全局·

进入游戏·

进入游戏的第一个界面,应该放置多个按钮,以供玩家选择是否开始游戏、退出游戏。

GameManager - 游戏管理器·

用来控制游戏的整体进程,以及界面文本、按钮的功能实现。
也常用于记录各种需要在整个游戏过程中持久化的数据。

GameManager 的用处:

  1. 整个游戏过程中有且仅有一个 GameManager,且位于场景的根目录
  2. 在 GameManager 里会有一个叫 Value 的整型变量,记录当前场景。
  3. 切换游戏场景的时候 GameManager 不能被销毁
  4. 每一个场景中都会有一个按钮,点击后会跳转到另一场景,并且对 GameManager.Value 进行 +/- 1 操作

使用 DontDestroyOnLoad() 方法让 GameManager 在切换游戏场景的时候不会被销毁,且只会存在一个GameManager:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class GameManager : MonoBehaviour
{
public static GameManager Instance { get; private set; }
public int Value { get; set; } = 0;

private void Awake()
{
// 单例模式核心,↓↓↓
if (Instance == null)
{
Instance = this;
DontDestroyOnLoad(gameObject);
}
else
{
Destroy(gameObject);
}
// ↑↑↑
}
}

参考资料:Unity 单例模式

开始游戏·

1
2
3
4
5
6
7
8
9
10
11
using UnityEngine;
using UnityEngine.SceneManagement;

public class GameMenu : MonoBehaviour {

public void OnStartGame()
{
SceneManager.LoadScene(1);
}
}

退出游戏·

分为两种情况:

  1. 使用Unity调试时
    UnityEditor.EditorApplication.isPlaying = false;
  2. 打包发布后
    Application.Quit();
1
2
3
4
5
6
7
8
9
10
11
12
using UnityEngine;

public class GameMenu : MonoBehaviour {
public void OnExitGame()
{
#if UNITY_EDITOR
UnityEditor.EditorApplication.isPlaying = false;
#else
Application.Quit();
#endif
}
}

数据保存·

JsonUtility·

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
/// <summary>
/// 需要保存的JSON数据表
/// </summary>
[System.Serializable]
class SaveData
{
public int score;
}

/// <summary>
/// 保存数据,使用JSON格式保存
/// </summary>
public void SaveScore()
{
SaveData data = new SaveData();
data.score = BestScore;

string json = JsonUtility.ToJson(data);

File.WriteAllText(Application.persistentDataPath + "/savefile.json", json);
}

/// <summary>
/// 读取数据,读取JSON文件的内容
/// </summary>
public void LoadScore()
{
string path = Application.persistentDataPath + "/savefile.json";
if (File.Exists(path))
{
string json = File.ReadAllText(path);
SaveData data = JsonUtility.FromJson<SaveData>(json);

BestScore = data.score;
}
}

JsonUtility.ToJson - 生成 JSON 格式的对象数据·

public static string ToJson (object obj);
public static string ToJson (object obj, bool prettyPrint);

obj 要转换为 JSON 形式的对象。
prettyPrint 如果为 true,则格式化输出以实现可读性。如果为 false,则格式化输出以实现最小大小。默认为 false。

返回值:string JSON 格式的对象数据。
描述:生成 对象的公共字段 的 JSON 表示形式。

JsonUtility.FromJson - 以JSON 格式的数据创建对象·

public static T FromJson (string json);

json 对象的 JSON 表示形式。

返回值:T 对象的实例。
描述:通过 JSON 表示形式创建对象。(对象的数据格式应与源数据格式一致,即转换成 JSON 表示形式之前的对象数据格式)

JsonUtility.FromJsonOverwrite - 以JSON 数据形式覆盖对象数据·

public static void FromJsonOverwrite (string json, object objectToOverwrite);

json 对象的 JSON 表示形式。
objectToOverwrite 应覆盖的对象。

描述:通过读取对象的 JSON 表示形式覆盖其数据。
此方法非常类似于 JsonUtility.FromJson,只是它将 JSON 数据加载到现有对象中,而不是创建新对象并将 JSON 数据加载到其中。这样,无需进行任何分配即可更新存储在类或对象中的值。

数据保存目录·

Application.persistentDataPath - 持久性数据目录路径·

此值是一个目录路径,您可以在其中存储要在运行之间保留的数据。在 iOS 和 Android 上发布时,persistentDataPath 指向设备上的公共目录。应用更新不会擦除此位置中的文件。用户仍然可以直接删除这些文件。

构建 Unity 应用程序时,将生成一个基于捆绑标识符的 GUID。此 GUID 是 persistentDataPath 的一部分。如果在将来的版本中保留相同的捆绑标识符,则应用程序在每次更新时都会继续访问相同的位置。

1
string persistentUrl = $"{Application.persistentDataPath}/{this.localInfoName}";    //持久化地址

Windows Store Apps: Application.persistentDataPath 指向 %userprofile%\AppData\Local\Packages<productname>\LocalState。

Windows EditorStandalone Player: Application.persistentDataPath 通常指向 %userprofile%\AppData\LocalLow<companyname><productname>。如果前者不可用,则由带有 FOLDERID_LocalAppDataLow 的 SHGetKnownFolderPath 或带有 CSIDL_LOCAL_APPDATA 的 SHGetFolderPathW 解决。

WebGL: Application.persistentDataPath 指向 /idbfs/ ,其中数据路径是去掉所有内容的 URL,包括最后一个 ‘/’ 之后的任何 '?'成分。

Linux: Application.persistentDataPath 指向 $XDG_CONFIG_HOME/unity3d 或 $HOME/.config/unity3d。

iOS: Application.persistentDataPath 指向 /var/mobile/Containers/Data/Application//Documents。

tvOS: 不支持 Application.persistentDataPath 并返回空字符串。

Android: Application.persistentDataPath 在大多数设备上指向 /storage/emulated/0/Android/data//files(如果存在,一些旧手机可能指向 SD 卡上的位置),这个路径是通过 android.content.Context.getExternalFilesDir 解析的。

Mac: Application.persistentDataPath 指向用户库文件夹(这个文件夹通常是隐藏的)。在最近的 Unity 版本中,用户数据被写入 ~/Library/Application Support/company name/product name。旧版本的 Unity 写入 ~/Library/Caches ,或 ~/Library/Application Support/unity.company name.product name. 这些文件夹都是 Unity 搜索的。该应用程序会查找并使用系统上包含所需数据的最旧文件夹。

角色控制·

  • Rigidbody.velocity
    直接给物体设定速度,适合物理类移动
  • transform.Translate
    适合非物理的移动,难以控制边界限制问题,俗称“卡墙里”。
  • Rigidbody.Force
    给物体施加力的作用,适合物理类移动
  • 角色控制器
  • Rigidbody.MovePosition
    直接改变物体的位置,适配了物理碰撞
  • transform.Position
    直接改变物体的位置,适合非物理碰撞的移动

移动·

跳跃·

游戏细节·

基于轴心的排序图层渲染顺序·

调整精灵轴心

物理系统 - 刚体与碰撞体之间的关系·

案例
不需要移动的物体,可以只加碰撞体,用于处理交互;
需要移动的物体,则需要刚体支持。

瓦片地图碰撞和复合器·

添加瓦片地图碰撞

角色受伤后的无敌时间·

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
using UnityEngine;

public class PlayerController : MonoBehaviour
{
public float timeInvincible = 2.0f;

bool isInvincible;
float invincibleTimer;

void Update()
{
if (isInvincible)
{
invincibleTimer -= Time.deltaTime;
if (invincibleTimer < 0)
isInvincible = false;
}
}

public void ChangeHealth(int amount)
{
if (amount < 0)
{
if (isInvincible)
return;

isInvincible = true;
invincibleTimer = timeInvincible;
}

currentHealth = Mathf.Clamp(currentHealth + amount, 0, maxHealth);
}
}

变量 1:一个名为 timeInvincible 的公共浮点变量,用于设置无敌的时间
变量 2:一个名为 isInvincible 的私有 bool 变量,用于存储当前是否处于无敌状态
变量 3:一个名为 invincibleTimer 的私有浮点变量。此变量将存储玩家在恢复到可受伤状态之前剩下的无敌状态时间

ChangeHealth 函数
在 ChangeHealth 函数中,你添加了一项检查以查看当前是否正在伤害角色(换言之,如果变化小于 0,则表示减小生命值)。如果是这样,你首先要检查 玩家 是否已经处于无敌状态,如果是,那么将退出该函数,因为她现在无法受到伤害。否则,由于 玩家 正受到伤害,你将 isInvincible bool 设置为 true 并将 invincibleTimer 变量设置为 timeInvincible,从而使 玩家 处于无敌状态。

Update 函数
在 Update 函数中,如果 玩家 处于无敌状态,则从计时器减去 deltaTime。这实际上是在倒计时。当该时间小于或等于零时,计时器结束,玩家 的无敌状态也结束,因此通过将 bool 重置为 false 来消除她的无敌状态。这样,下次调用 ChangeHealth 来伤害 玩家 时,你就不会提前退出并再次伤害她、重置她的无敌状态等等。

使UI绑定到某个对象上,而不是屏幕上·

案例 - 附加在对象上的Canvas - Ruby’s Adventure 2D
比如:你需要让对话框显示在一个角色上方的一个小框中。这意味着画布将存在于世界(world space)中,位于头顶上方,而不是始终叠加在屏幕固定位置上。

2D游戏中的各种平台·

基础平台、单向可穿越平台、移动平台等;并且可相互组合。

可使用 2D 平台效应器 (Platform Effector 2D)来实现某些平台的功能。