从游戏设计中获取软件系统设计方案

一.前言

  在这次的高级软件工程课程中,我学会了什么是软件:软件的基本构成元素、软件的基本结构、软件中的一些特殊机制和软件的内在特性。软件设计模式:设计模式涉及的基本概念、设计模式的分类、常用的设计模式和设计模式背后的设计原则。常用的软件架构:MVC,MVVM等。软件架构的描述方法:分解视图Decomposition View、依赖视图Dependencies View、泛化视图 Generalization View、执行视图Execution View、实现视图Implementation View、部署视图Deployment View和工作任务分配视图Work-assignment View。学习了这些知识之后我就能够对自己的工程实践项目进行软件系统分析和设计,最终形成软件系统概念原型。

  我的工程实践项目是在Unity平台上实现蛇的模拟与仿真。课题主要工作为使用相关技术模拟蛇的移动姿态、使用物理引擎实现蛇与环境交互的能力。3D贪吃蛇为该项目的展现形式。3D贪吃蛇是一个角色扮演类游戏,玩家可通过操控蛇移动与环境交互、获取道具。

  游戏中物理引擎的作用是模拟当有外力作用到对象上时对象间的相互影响,比如赛车游戏中,驾驶员驾驶赛车和墙体发生碰撞,进而出现被反弹的效果。物理引擎在这里用来模拟真实的碰撞后效果。通过物理引擎,实现这些物体之间相互影响的效果是相当简单的。目前主流的物理引擎有PhysX(NVIDIA旗下)、BULLET(AMD旗下)以及haVOK(INTEL旗下)。PhysX包含了对布料,破碎,车辆,角色模拟等等的完整支持,功能齐全。Bullet只能提供最基础的碰撞/刚体/Softbody模拟。而Unity引擎中内置的正是PhysX。在 Unity 3D 中,物理引擎是游戏设计中最为重要的步骤,主要包含刚体、碰撞、物理材质以及关节运动等。

  目前3D游戏中蛇类的运动呈现有两种方式:一种是蛇类运动动画配合动画师调整关键帧实现运动,这种方式能够较为精确地呈现蛇的整个运动过程,但是需要人工进行动作的定位与矫正,耗费人力。另一种是基于物理模拟,计算蛇运动过程中身体关节之间的约束,与环境的交互等,来变现蛇的运动状态,这种方法的呈现效果依赖物理仿真的真实程度。

 

二.软件设计方案

2.1 项目介绍

  随着计算机技术的发展,用户娱乐方式的不断丰富,电子游戏逐渐成为众多用户休闲娱乐的一种方式。与此同时,用户在游戏中对真实沉浸感的要求也越来越高,对真实感官的极致体验逐渐成为电子游戏发展的一种趋势,而物理仿真是评价游戏沉浸式体验的一大标准,是连接用户所熟悉的日常生活与虚拟环境的关键桥梁,也是用户最容易感知与现实差别的关键因素。在现代游戏制作中,物理仿真被广泛应用在游戏的各个方面,如旗帜的飘动、飞机的飞行、汽车的运动等,通过准确把握现实复杂环境中的物理特性模拟为人眼能够接受的动画效果,给用户带来更丰富更逼真的沉浸式体验。3D贪吃蛇中有三种角色:玩家、贪吃蛇和3D地图(场景系统)。在游戏过程中,同一时刻只允许一名玩家的存在。贪吃蛇是游戏的主角,由玩家操控。场景系统负责系统资源的管理,场景的绘制,游戏胜负的判定等。

2.2 项目完整设计方案

  本项目的焦点是物理模拟,我们应该专注的是贪吃蛇的运动轨迹设计,以及其与相关环境的碰撞检测,与传统的贪吃蛇游戏不同的地方是该项目设置的是其在3D空间的实现,我们需要考虑果子生成的地点。在空中生成的果子是否有可能被贪吃蛇吃到,在考虑玩家控制角色的运动模拟时需要判断是否能够通过攀爬周边物体(比如树,石头)来实现空间上的上升,以及相关力的控制、运动轨迹的模拟。

  在完成了角色的运动模拟之后,我们应该考虑的是环境的渲染以及角色与环境的交互,考虑的因素主要有角色与物体的碰撞检测、角色与地面或者树木的摩擦力设计以及角色移动时环境的变化(如角色在草地上移动时造成的草的晃动)等。初步设计的环境是以森林为背景,主要的地形有草地、池塘和丘陵等。在进行环境渲染的同时还需要考虑环境中物体表面的摩擦力与物体表面角度的设计,这将决定角色是否能够在其表面运动。

 

图1 系统总体结构设计图

   3D贪吃蛇中有三种角色:玩家、贪吃蛇和3D地图(场景系统)。在游戏过程中,同一时刻只允许一名玩家的存在。贪吃蛇是游戏的主角,由玩家操控。场景系统负责系统资源的管理,场景的绘制,游戏胜负的判定等。

用例名称

说明

玩家操控贪吃蛇移动

玩家能够使用某种输入设备(键盘、鼠标、游戏手柄等)对贪吃蛇输入指令,贪吃蛇做出对应移动

贪吃蛇吃果子

贪吃蛇在移动的过程中与果子发生碰撞,即代表吃掉果子,身体会延长

贪吃蛇死亡

蛇头碰撞到蛇身,或者碰撞到场景内的陷阱类物体时,玩家本次游戏失败

场景生成果子

游戏的场景系统按照某种规则(包括随机)在场景中生成果子,等待玩家操作贪吃蛇吃

分数统计

游戏系统按照贪吃蛇吃果子的数量统计玩家分数D

关卡切换

游戏场景系统能够设定一系列 3D 关卡,在玩家满足要求时切换关卡

数据保存

游戏可以写入和读取玩家存档,保存玩家的游戏进度,历史分数等信息

表1 系统用例分析

 

2.2.1 角色实体实现

  该部分主要需要实现的功能是贪吃蛇实体的结构设计,包括角色内部各个部分的交互,初步的实现可以将蛇体划分为很多个细小的部分,每个部分之间有相关约束设计,每当蛇体移动时各个部分的移动将会根据约束来完成,整个角色的移动模拟就能够实现蛇体的模拟。

  此次角色实体实现还包括蛇体的UI设计,包括图层、材料、蛇头和蛇身样式的设计,还有当蛇身长度变化,蛇的实体变化。以及蛇身内部的自我碰撞检测方法的实现。

 

图2 角色实体实现

2.2.2 运动环境渲染

  运动环境主要指的是游戏场景的设计,以及场景内部细节的具体实现。比如树木、山川、草地、池塘和丘陵等地形,除了设置环境的界面细节之外,还需要给某些场景设置具体的参数,比如物体表面摩擦力的设计,物体角度设计等,通过这些参数来判断角色是否能在其上移动。

 

图3 运动环境渲染

2.2.3 角色运动的物理模拟

  项目的物理模拟是需要实现的核心技术模块,通过学习现实中蛇的运动模式,来完成在游戏中的实现。主要运动的方式有:蜿蜒式:蜿蜒式是其中一个为人熟知的蛇行移动手段,亦即“S”形的波浪式走法。这种移动手法是最多蛇类(陆地型及水行型亦然)所采用的,它们会先从颈部位置开始,有规律地收放全身的肌肉,缓缓地把身体往前猱动,让身体形成一条顺畅的流线模式,达至前进的效果。侧行式:侧行式是大多数蛇类(尤指新蛇科)的移动方式之一,多用于行走在松散或湿滑的地形之上。蠕动式:蠕动式是一种比较缓慢的蛇行法。这种行走方式亦常见于毛虫类或鳞翅目生物的幼虫阶段,亦称为“直线蠕动。风琴式:风琴式算得上是蛇类进行攀爬时所运用的行走方式。通过研究这些真实运动方式的实现方式并对他们的运动进行受力分析,来完成在游戏中的物理模拟。

 

 

图3 角色运动的物理模拟

2.2.4 角色与场景的交互  

  为了增加运动的真实性,考虑蛇本身的运动对环境的影响是至关重要的,例如在草地中移动导致草的摆动,在沙漠中移动留下足迹等。

图4 角色与场景的交互

2.2.5 角色移动目标的生成

  游戏的主要游戏性设计就是通过玩家控制角色吃到目标(果实)来实现的。在生成果实的过程中应该充分考虑角色是否能够到达目标位置。

 

图5 角色移动目标的生成

 

三.系统架构

3.1 设计模式选择

  在游戏设计中有很多经常使用的设计模式:主要有单例模式、观察者模式和状态模式。

  游戏中的模块管理是对一些游戏资源、数据的组织、功能划分、工具开发等,比较笼统。一般会对有一个Manager/System来负责一个模块的封装和管理,便于开发使用。因此通常我们会在代码中看到各种各样的管理模块,例如Unity中的:ResourceManager、UIManager、SchedulerManager、NetManager、EventManager、PoolManager等等。要开发这些管理模块,自然就少不了单例模式(Singleton Pattern)。

图6 单例模式描述图

 

  而在交互中我们一般都要求 “高内聚、低耦合”,围绕这个宗旨软件开发中出现了很多的设计框架,在游戏设计中MVC扩展和变种模式是经常被使用到的。解决耦合问题我们通常就会用到一个基础的模式:观察者模式( Observer Pattern)。

 

图7 游戏设计中的观察者模式

  游戏中会根据不同的功能切分成不同的模块,不同模块之间根据不同的条件进行切换。这个地方就要用到状态模式(State Pattern)了,游戏中最实用的就是有限状态机(FSM)、层次状态机(HFSM)、行为树(BehaviorTree)。在状态模式(State Pattern)中,类的行为是基于它的状态改变的。这种类型的设计模式属于行为型模式。

 

图8 状态模式描述图

3.2 软件架构选择

  在主要的软件开发开始之前,我们必须选择一个合适的体系结构,它将为我们提供所需的功能和质量属性。

  在游戏设计中最常用的软件架构毋庸置疑的是客户-服务器模式。即Client-Server(C/S)结构。C/S结构通常采取两层结构。服务器负责数据的管理,客户机负责完成与用户的交互任务。客户机通过局域网与服务器相连,接受用户的请求,并通过网络向服务器提出请求,对数据库进行操作。服务器接受客户机的请求,将数据提交给客户机,客户机将数据进行计算并将结果呈现给用户。服务器还要提供完善安全保护及对数据完整性的处理等操作,并允许多个客户机同时访问服务器,这就对服务器的硬件处理数据能力提出了很高的要求。

  在C/S结构中,应用程序分为两部分:服务器部分和客户机部分。服务器部分是多个用户共享的信息与功能,执行后台服务,如控制共享数据库的操作等;客户机部分为用户所专有,负责执行前台功能,在出错提示、在线帮助等方面都有强大的功能,并且可以在子程序间自由切换。C/S结构在技术上已经很成熟,它的主要特点是交互性强、具有安全的存取模式、响应速度快、利于处理大量数据。但是C/S结构缺少通用性,系统维护、升级需要重新设计和开发,增加了维护和管理的难度,进一步的数据拓展困难较多,所以C/S结构只限于小型的局域网 。
  在游戏设计中,C/S模式的优势尽显。C/S结构的优点是能充分发挥客户端PC的处理能力,很多工作可以在客户端处理后再提交给服务器。对应的优点就是客户端响应速度快。具体表现在以下两点:(1)应用服务器运行数据负荷较轻。最简单的C/S体系结构的数据库应用由两部分组成,即客户应用程序和数据库服务器程序。二者可分别称为前台程序与后台程序。运行数据库服务器程序的机器,也称为应用服务器。一旦服务器程序被启动,就随时等待响应客户程序发来的请求;客户应用程序运行在用户自己的电脑上,对应于数据库服务器,可称为客户电脑,当需要对数据库中的数据进行任何操作时,客户程序就自动地寻找服务器程序,并向其发出请求,服务器程序根据预定的规则作出应答,送回结果,应用服务器运行数据负荷较轻。(2)数据的储存管理功能较为透明。在数据库应用中,数据的储存管理功能,是由服务器程序和客户应用程序分别独立进行的,并且通常把那些不同的(不管是已知还是未知的)前台应用所不能违反的规则,在服务器程序中集中实现,例如访问者的权限,编号可以重复、必须有客户才能建立订单这样的规则。所有这些,对于工作在前台程序上的最终用户,是“透明”的,他们无须过问(通常也无法干涉)背后的过程,就可以完成自己的一切工作。在客户服务器架构的应用中,前台程序不是非常“瘦小”,麻烦的事情都交给了服务器和网络。在C/S体系下,数据库不能真正成为公共、专业化的仓库,它受到独立的专门管理。
 

3.3 API接口

在本次的工程实践上最经常也是最重要使用的API就是Unity提供的各种函数和类完成游戏的设计。

1、Event Function:事件函数

  • Reset() :被附加脚本时、在游戏物体的组件上按Reset时会触发该事件函数
  • Start() :在游戏初始化时会执行一次
  • Update() :每一帧都会运行这个方法
  • FixedUpdate(): 会在指定帧调用该方法多少次
  • LateUpdate(): 晚于Update的运行顺序,但是FPS和Update是一样的
  • Awake() Start() : 都是在游戏物体初始化运行一次,但是Awake的运行顺序高于Start的,并且只要脚本中存在Awake方法,则无论是否挂载了该脚本都会执行该方法
  • OnEnable(): 当将物体的SetActive设置为true时就会自动调用调用该方法
  • OnDestory(): 当关闭游戏则会调用该方法

2、Time时间类函数:

  • Time.time 表示从游戏开发到现在的时间,会随着游戏的暂停而停止计算。
  • Time.timeSinceLevelLoad 表示从当前Scene开始到目前为止的时间,也会随着暂停操作而停止。
  • Time.deltaTime 表示从上一帧到当前帧时间,以秒为单位。【一般用来控制角色、动画的运动】
  • Time.fixedTime 表示以秒计游戏开始的时间,固定时间以定期间隔更新(相当于fixedDeltaTime)直到达到time属性。
  • Time.fixedDeltaTime 表示以秒计间隔,在物理和其他固定帧率进行更新,在Edit->ProjectSettings->Time的Fixed Timestep可以自行设置。
  • Time.SmoothDeltaTime 表示一个平稳的deltaTime,根据前 N帧的时间加权平均的值。
  • Time.timeScale 时间缩放,默认值为1,若设置<1,表示时间减慢,若设置>1,表示时间加快,可以用来加速和减速游戏,回放等、非常有用。如果游戏中控制运动的都是使用了Time.deltatime的话,则可以通过设置Time.timeScale=0来暂停其运动等。

3、GameObject类:

(1)创建游戏物体的三种方法:

  • 通过其构造器来创建 GameObject go=new GameObejct("游戏物体名"); //一般是用来创建空的游戏来存放其他东西的。
  • Instantiate GameObject.Instantiate(prefab) //根据Prefab或者是另外一个游戏物体来创建(克隆Colon),可以实例粒子、等其他的游戏物体,很是常用的
  • CreattePrimitive GameObject.CreatePrimitive(PrimitiveType.**) //创建原始的游戏物体,基本的几何体

(2)为游戏物体添加组件, 其中组件可以是我们自己自定义的脚本。GameObject.AddComponent<组件名>

(3)属性、变量:

  • GameObject.activeInHierarchy 游戏物体是否处于激活状态,与父类有关,父类被取消激活,则子类也是取消激活的
  • GameObject.activeSelf 自身的激活状态,与父类无关,只与自身有关。【控制组件的激活与取消激活则使用.enable=false/true】
  • GameObject.tag 游戏物体的tag标签,具体的由程序员自定义设置
  • GameObject.SetActive(false/true) 通过参数的控制来设置其游戏物体的激活状态,true为激活状态,反之为取消激活状态。

4、MonoBehaviours的类:

(1)继承的变量成员

  • enabled: 返回该组件是否被激活或者是被禁用,可以通过该变量来进行设置
  • isActiveAndEnabled: 只能返回该组件是否激活的标志位,不能设置该变量,为只读的
  • tag :该组件所对应的游戏物体的标签
  • name :该组件所对应的游戏物体的名字

(2)Invoke等方法、变量:将添加要调用的方法添加到等待队列中,然后等待用户设定的时间后,进行队列中的方法调用。

  • nvoke("方法1",float time): 在等待time的时间后调用方法1
  • bool i= IsInvoking("方法1") 返回bool值,如果方法被添加到队列中,但没有被运行则返回true,如果经过一段时间后该方法被调用了则会返回false;
  • nvokeRepeating("方法1",time,number): 等待time时间后,会重复开始运行方法1,每秒钟运行number次。
  • CancelInvoke() 会暂停通过Involve/InvokeRepeating的运行,但是一般来说CancelInvoke会和InvokeRepeating组合调用。参数由自己设定

 

四.软件系统概念原型

4.1 分解视图  

  分解是构建软件架构模型的关键步骤,分解视图也是描述软件架构模型的关键视图,一般分解视图呈现为较为明晰的分解结构(breakdown structure)特点。分解视图用软件模块勾划出系统结构,往往会通过不同抽象层级的软件模块形成层次化的结构。

 

4.2 依赖视图  

  依赖视图展现了软件模块之间的依赖关系。比如一个软件模块A调用了另一个软件模块B,那么我们说软件模块A直接依赖软件模块B。如果一个软件模块依赖另一个软件模块产生的数据,那么这两个软件模块也具有一定的依赖关系。依赖视图在项目计划中有比较典型的应用。比如它能帮助我们找到没有依赖关系的软件模块或子系统,以便独立开发和测试,同时进一步根据依赖关系确定开发和测试软件模块的先后次序。依赖视图在项目的变更和维护中也很有价值。比如它能有效帮助我们理清一个软件模块的变更对其他软件模块带来影响范围。

4.3 执行视图 

  执行视图展示了系统运行时的时序结构特点,比如流程图、时序图等。执行视图中的每一个执行实体,一般称为组件(Component),都是不同于其他组件的执行实体。如果有相同或相似的执行实体那么就把它们合并成一个。执行实体可以最终分解到软件的基本元素和软件的基本结构,因而与软件代码具有比较直接的映射关系。在设计与实现过程中,我们一般将执行视图转换为伪代码之后,再进一步转换为实现代码。

4.4 部署视图 

  部署视图是将执行实体和计算机资源建立映射关系。这里的执行实体的粒度要与所部署的计算机资源相匹配,比如以进程作为执行实体那么对应的计算机资源就是主机,这时应该描述进程对应主机所组成的网络拓扑结构,这样可以清晰地呈现进程间的网络通信和部署环境的网络结构特点。当然也可以用细粒度的执行实体对应处理器、存储器等。部署视图有助于设计人员分析一个设计的质量属性,比如软件处理网络高并发的能力、软件对处理器的计算需求等。

 

4.5 实现视图 

  实现视图是描述软件架构与源文件之间的映射关系。比如软件架构的静态结构以包图或设计类图的方式来描述,但是这些包和类都是在哪些目录的哪些源文件中具体实现的呢?一般我们通过目录和源文件的命名来对应软件架构中的包、类等静态结构单元,这样典型的实现视图就可以由软件项目的源文件目录树来呈现。实现视图有助于码农在海量源代码文件中找到具体的某个软件单元的实现。实现视图与软件架构的静态结构之间映射关系越是对应的一致性高,越有利于软件的维护,因此实现视图是一种非常关键的架构视图。

 

五.数据库设计

概念数据模型:

数据模型设计

序号

表名

名称

功能

1

user

用户数据模型

存储用户ID和密码

2

Snake

角色数据模型

用于存储游戏角色的基本数据

3

circustances

环境数据模型

存储环境的一些基本信息

物理数据模型:

Snake数据模型

字段名

名称

类型

长度

是否主键

允许空值

Snake_id

属性编号

int

20

是

否

Snake_name

名称

Varchar

100

否

否

Snake_length

蛇身长度

float

20

否

否

Snake_image

图层

string

100

否

是

Snake_crash

是否碰撞

bool

4

否

是

 

环境数据模型

字段名

名称

类型

长度

是否主键

允许空值

id

环境编号

int

20

是

否

name

名称

Varchar

100

否

否

width

宽度

float

20

否

是

length

长度

float

20

否

是

color

颜色编号

int

20

否

是

position

位置编号

int

20

否

否

texture

图层

string

100

否

是

iscrash

是否碰撞

bool

4

否

是

 

用户

字段名

名称

类型

长度

主键

允许空值

User_id

用户编号

int

11

是

否

User_name

用户名

Varchar

10

否

否

User_password

用户密码

Varchar

10

否

否

User_sex

用户性别

Varchar

2

否

是

User_tel

联系方式

Varchar

11

否

是

User_mail

用户邮箱

Varchar

20

否

是

User_update

用户注册日期

date

 

否

否

六.运行环境和技术选型

  作为一项在Unity中编辑的游戏项目,只需要利用Unity的导出打包功能就能够在各种主流平台上运行,比如Android、Ios、Macos和Windows等等。在开发过程中主要用到Unity、Rider、Git和各种代码调试工具。

七.概念原型的核心工作机制

  本项目的核心机制就是对角色的物理模拟。目前3D游戏中蛇类的运动呈现有两种方式:一种是蛇类运动动画配合动画师调整关键帧实现运动,这种方式能够较为精确地呈现蛇的整个运动过程,但是需要人工进行动作的定位与矫正,耗费人力。另一种是基于物理模拟,计算蛇运动过程中身体关节之间的约束,与环境的交互等,来变现蛇的运动状态,这种方法的呈现效果依赖物理仿真的真实程度。通过在游戏中研究并模拟生活中的具体事务的物理特性,实现真实的物理效果以满足游戏特性,提升用户沉浸式体验,利用Unity引擎在游戏中实现蛇类的真实运动物理模拟,为用户带来更加真实的游戏体验。物理引擎是游戏设计中最为重要的步骤,主要包含刚体、碰撞、物理材质以及关节运动等。

   相比于基于关键帧的蛇类运动动画模拟,物理仿真的蛇类运动动画可以极大的节省时间、人力和物力的成本,通过对原本复杂环境中蛇类运动方式的问题简化分解为单个场景下蛇类的运动与动力学模型,并在实际模拟中叠加不同的多个场景(如路面,草地,水中、树上等)参数实现自然状态中蛇类真实运动,就可以很快的计算获得一个看起来不错,能够欺骗玩家眼睛并能够被玩家喜爱的动画效果。

参考文献:

1.https://gameinstitute.qq.com/community/detail/127414

2.https://www.jianshu.com/p/4b974a22c59b

 

posted @ 2020-12-29 16:48  大大大大大柠檬  阅读(422)  评论(0)    收藏  举报