GitHub项目成品及工程仓库

开始

刚学习完面向对象以及Unity核心,跟着唐老狮做了一个坦克迷宫的游戏(详情见GitHub仓库之TankGame),一起学习的同门带土兄发现Unity正在举办开发者挑战赛,抱着综合运用一下学到的知识的心态,我报名了这项比赛,没想到取得了不错的成绩。。

开发

我想做一个跑酷类型的游戏,与传统跑酷类似的是玩家不移动而地图移动,不过我找到的美术资源比较适合做玩家上下移动而非左右移动,这算是一个比较新的点,也因为这个原因在开发过程中遇到了一些小问题。。

游戏介绍

(详情参见GitHub仓库中的说明文档,此处仅展示游戏截图)

游戏截图1

代码部分展示

面板的处理不细说了,主要聊聊代码部分。
游戏中的代码包含3个部分:

  • BeginScene
  • GameScene
  • Data

按场景和功能分类,对于场景来说,每部分代码控制UI面板以及背景音乐。

BeginScene

面板基类

由于游戏中会出现许许多多的面板,我们不妨设置一个面板基类,用于实现所有面板要处理的共同逻辑。其余面板只需继承这个基类面板,在其基础上补充功能即可。

以下是一个面板基类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class BasePanel<T> : MonoBehaviour where T : class
{
// 单例模式:两个关键的静态成员
    private static T instance;
    public static T Instance => instance;

    private void Awake()
    {
        instance = this as T;
    }
   
    // 显示自己的方法
    public virtual void ShowMe()
    {
        this.gameObject.SetActive(true);
    }
    // 隐藏自己的方法
    public virtual void HideMe()
    {
        this.gameObject.SetActive(false);
    }
}

其中比较需要注意的点在于:

  1. 虚函数:供子类重写显示自己和隐藏自己的方法

  2. 单例模式:由于运行时面板全局唯一的特性,可以采用单例模式,简化代码。

  3. 泛型:整个游戏中会有很多面板,采用泛型可以将面板的共同逻辑封装在一个面板基类中,简化代码逻辑。

  • 之前instance的实例化是new T(),不过现在这个面板基类继承了MonoBehaviour就不能直接new了;

  • 那么instance的赋值应该在哪实现呢?在Awake()中。让这个instance的值为当前这个脚本所挂载的面板,也就是this

  • 问题又出现了,当前的this类型是T,而T的类型是子类继承时决定的,现在让他为this也就是BasePanel,显然与T类型不一样,因此,需要asT

  • 使用as的条件是T是一个类对象,因此,需要进行泛型约束,加上where T : class

其他面板

其他面板(BeginPanel开始界面、RankPanel排行榜界面、SettingPanel设置界面)继承了面板基类,注意点如下:

  • 注意显隐,避免穿透
  • 排行榜控件较多,可以直接通过代码查找
  • text控件需要的是string类型,遇到分数时记得使用ToString()函数转变
  • 得到时间时得到的是秒,需要把秒数转化为时 分 秒的格式存储起来,具体操作如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
int time = (int)list[i].time;
//默认是0,初始化为空方便拼接
labTime[i].text = "";
//得到 几个小时
if (time / 3600 > 0)
{
labTime[i].text += time / 3600 + "时";
}
if (time % 3600 / 60 > 0 || labTime[i].text != "")
{
labTime[i].text += time % 3600 / 60 + "分";
}
labTime[i].text += time % 60 + "秒";

背景音乐

同样用到单例模式,初始化是设置音乐大小和开关,内有改变音量和开关音乐的方法。

GameScene

GameScene包含部分如下:

  • AnimationBG背景的移动动画
  • Object物体:
    • People人物
    • Reward奖励
    • Weapon武器
  • Spawner随机生成
  • UI
    • GamePanel
    • LoadPanel
    • LosePanel
    • QuitPanel
    • WinPanel

写游戏场景时,我遇到了许许多多的问题,不过经过一次次调试都解决了。

其中我记忆里比较深刻的问题是人物在移动时通过碰到磁铁道具吸引的金币总是到处乱飘,并且最终落点总在人物模型之后。

思考了很久,问了带领我的青女学长,也向AI寻求帮助都没成功解决。

最后我发现,因为人物是没有移动的,只是背景有动画,各种武器、奖励、怪物都以一定的速度向左移动,因此,在给物体加上磁力时它具有一个初速度,如果检测到碰撞到磁铁,就应该把物体的初速度置为0。

想到这个解决办法并看着问题成功解决真的特别特别有成就感!!让我在游戏开发的道路上更加具有信心和挑战精神 =v=

其他还有一些初次开发没有注意到的问题,例如:人物移动时应该在某一边界内、子弹的数目应该限量等等问题都是我的小伙伴们试玩发现并指出的~特别感谢大家( ̄▽ ̄)/

Data

Data包括三个部分:

  • GameDataMgr数据管理类
  • MusicData音乐数据
  • RankInfo排行榜信息

其中,数据管理类负责实现各种数据(包括音效数据、排行榜数据)的开启或关闭音乐(音效)、增大或调小音乐(音效)、添加排行榜信息、存储改变后的数据。

总结

这次的GameJam是一次难得的经历,虽然没有和其他网络上的人一起合作开发,不过经过限时挑战、独立制作、修复bug、完成游戏的整个过程我因为找不到bug而苦恼过、完成游戏制作而满足过、也因为最终取得不错的成绩而开心过。总之,游戏开发任重道远,希望我保持初心,成为一个更好的 game developer!!