游戏开发中的表现层具体指什么?

问:

常说开发游戏时要分离逻辑和表现,表现不能影响逻辑,那么这里的逻辑和表现具体指什么?

比如,2d动作游戏中,玩家按d键后人物向右移动,按a键后人物转向并向左移动,按另一个键后人物向面前的敌人发出攻击技能。

那么在这个例子中,逻辑有哪些?表现有哪些?改变人物的位置和朝向属于逻辑还是表现?

猴与花果山:

简单的来说,就是渲染是完全依赖于逻辑数据,和一些补充数据来实现的,而逻辑中的任何内容都完全不应该依赖于渲染相关的信息。

首先我们先搞明白什么是逻辑表现(渲染)分离
他的效果是怎样的?就是DQ系列,比如DQ11里面:
在这里插入图片描述
DQ11是有3D模式和2D模式可以选择的,他们的区别仅仅是Render,也就是题目中说的”表现“,而背后的逻辑是一模一样的代码,不是3D一套2D一套的

因为逻辑代码都是一样的,比如你在上图中可以看到的战斗,他的结构大约是这样的(不具体):


//这是一场战斗
class Battle{
   public enemies:Array<Character>; //战斗中的敌人
   public players:Array<Character>; //战斗中的玩家小队成员
   
   //运行一回合战斗,返回出战斗回合中的信息
   public RunTurn():Array<TurnInfo>{...}
}

//角色对象
class Character{
   public name:string; //角色名
   public lv:number; //当前等级
   public hp:number; //当前血量
   public mp:number; //当前生命值
   public buffs:Array<BuffObj>; //角色的buff
   public battleClass:CharacterClass; //角色的职业枚举

   private baseProperty:CharacterProperty; //角色的血量等属性,裸体属性
   private equipmentProperty:CharacterProperty; //来自装备的属性
   private buffedProperty:CharacterProperty;  //来自buff的属性变化
   public get property(){...}; //角色的属性值,包括最大生命、最大法力、攻击力等
}

//每回合战斗信息
class TurnInfo{
   public character:Character; //相关的角色
   public action:BattleAction; //是一个行为的枚举,比如”做出动作“、”播放特效“等
}

根据这样一个结构(以上非完整的,而且是非常简单的),得出了每回合战斗的过程,也就是一个Array,然后根据这个数组的信息,辅以一些比如角色外观信息等策划配表信息,得出了这回合屏幕上每一帧应该渲染什么,形成动画。因此屏幕渲染用2D或者3D对于战斗来说都是无所谓的,战斗负责的只是处理数据+产生出渲染所需要的一些信息——这就叫表现和逻辑分离,表现依赖于逻辑。

逻辑依赖于视觉的设计和开发,往往是一些非常外行的、但也非常常见的设计,确切的说,就是不会做游戏的人才会犯得错误,最常见的行为就是”滑步问题“(图片不太好找,但确实是是游戏项目开发中最常遇到的问题之一),为了角色不滑步,强行调整角色的移动速度,甚至为此不让游戏有加速移动或者减速移动的设计,这就是一个典型的逻辑依赖于表现,因为角色滑不滑步,是美术的视觉效果,他不具有任何游戏性,因此开发中,绝不应该让服务于游戏性的数据、逻辑代码来为美术效果让步。

同样的逻辑依赖于视觉的设计和开发,也包括一些”动作游戏“中的伤害判定。最常见的是diablo类我们称作ARPG的游戏(这些游戏其实并不是动作游戏,只不过是即时的而已),每个攻击动作有一个攻击帧的概念,也就是当动画运行到第几帧的时候产生伤害判定。这里就出现了一个细节,外行的做法就是播放动画,当动画到某一帧的时候执行伤害等,这就有点像Flash里面的关键帧的概念——你动画播放到这一帧了就产生效果。但是问题也在这里,如果是单机游戏,因为卡一下跳帧了,很可能伤害就不产生了——这正是因为逻辑依赖了表现,都不表现了,逻辑就走不到了。而内行的做法(实际上大多ARPG因为恰好是网游,所以歪打正着用了内行的做法)是标准的逻辑和表现分离的,甚至是动画依赖于表现的,内行的做法是这样的——有一个timeline的结构:


//每一个技能逻辑上都是一个Timeline
class Timeline{
   //Timeline的核心数据是nodes,也就是每一个时间点会发生什么,比如timeline开始第0帧,播放一个动画
   //再比如timeline走到第37帧的时候发出子弹飞向那儿,这些都是timeline上的node,node决定了会发生什么
   //但是这个node其实是逻辑数据,我们看到”开始播放动画“,仅仅只是一个node,怎么播放update关心,我fixedUpdate可不管
   public nodes:Array<TimelineNode>;
   public ticked:number; //走了多少个tick
}
//每一个时间节点发生的事情
class TimelineNode{
   public tickElapsed:number; //在第几帧发生这件事情
}
//比如播放动画,就是一个timelineNode
class TimelineEvent_PlayAnimation extends TimelineNode{
   public animationId:string; //要播放的动画
   public timeScale:number = 1.00; //标准的播放速率

}

当timeline.nodes[x].tickElapsed==timeline.ticked的时候就会发生对应事情,如果是PlayAnimation就播放动画——这就是表现依赖于逻辑的做法。

比如,2d动作游戏中,玩家按d键后人物向右移动,按a键后人物转向并向左移动,按另一个键后人物向面前的敌人发出攻击技能。
那么在这个例子中,逻辑有哪些?表现有哪些?改变人物的位置和朝向属于逻辑还是表现?

首先我们看,改变角色的坐标(位置)、面向,其实都是逻辑变化,渲染的时候根据坐标和面向(还有当前第几帧、动画是什么等等等等信息)把人物画到屏幕上,就是一个标准的表现依赖于逻辑。这里有一个细节——因为”按另一个键后人物向面前的敌人发出攻击技能“有这么一个设定,所以”面向“是一个逻辑数据,如果没有这个设计的话,角色面向无所谓朝哪儿,只是为了游戏画面有了面向走的方向的时候,”面向“可以是一个渲染用的数据(表现)。

所以要如何区分什么是”逻辑“什么是”表现“?简单的说,方法就是:

  1. 列出所有的数据,也就是我常说的先做数据结构。
  2. 看哪些数据是和游戏规则无关的,把它们放到渲染相关的数据里去。
  3. 剩下还在逻辑数据中的,也就是和规则息息相关的,就是逻辑,其他的就是表现。

所以才有了上面说的细节,因为设定中转身影响子弹发出这个规则(子弹的方向),所以应当是一个逻辑数据。如果你对成为游戏开发的程序员(gameplay方向而非渲染程序员)或者成为一个优秀的游戏策划有兴趣,那你的确应该掌握这个技巧。

图片来源:http://www.cungun.com/ 页游

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值