万能鲨鱼飞禽走兽兽玩家多么?有能交流的论坛么?

> WOW资深玩家时评:熊猫人 只不过是开始
WOW资深玩家时评:熊猫人 只不过是开始
发布时间:12-08-22 09:16
来源:52PK独家
【52PK 8月22日消息】到今天为止,已经看过多少部WOW的剧情CG和宣传片了?
在诸多宣传片里,纳克萨玛斯版本那一部最让我难忘。克尔苏加德,一个普通的人类法师,不甘于平凡,执意追求更高荣耀;他走过冰雪覆盖的原野,攀登遥不可及的深渊,面对地穴恶魔和幽灵而面不改色,最终背叛了自己的老师安东尼达斯,成为纳克萨玛斯的主人&&在游戏中他被人类王子阿尔萨斯杀死,随即他以灵魂形态出现告诉玩家,死亡,只不过是开始。
曾经,我拥有8000多分的DKP,12万G,以及一匹漂亮的火凤凰,而它们都已消逝在历史的风中。8000多DKP随公会大团解散烟消云灭,12万G在CTM之后不过是两三张点卡,而如今火凤凰紫凤凰元龙灵兽大飞蛇飞禽走兽层出不穷。我拥有的一切在今天都成了过去,我的时代已经结束,我再找不到留下的理由。
常在想,对我来说WOW还剩下些什么?最初,吸引我来到这个世界里的,是一系列的剧情设定。西式背景、职业、怪物,精灵与矮人并存,巨魔共牛头齐舞。在TBC里,我看到了传奇英雄凯尔萨斯、瓦斯琪和伊利丹的毁灭,甚至战胜了燃烧军团的两个副帅阿克蒙德与基尔加丹;在WLK里,我们都向往着那最终的目标,巫妖王阿尔萨斯。他一倒下,魔兽的历史就结束了。再也没有故事交代之后发生了什么,而对于我们这一代人来说,在我们的年轻时代所看到的,所最熟悉的,恰恰正是《魔兽争霸3》所讲述的故事,在很多人看来那就是魔兽的一切。这一切,随着WLK的结束而结束,游戏中熟悉的角色一个接一个死去,身边的玩家一个接一个离开,英雄,已经没有英雄了。
对于我这样一个曾经进度排进全国前十的团队领袖来说,我不认为有什么Boss的战术、战法能再推出多少花样。时光+点燃的彩狗、华丽的克苏恩分散站位、旧版四马人的8T战术&&能维持一个团队、一个公会的是什么?归根结底,是兴趣,是乐趣。对于DKP、对于装备的渴望是有限的,而对于&未知&的探求是无限的。CTM的最大问题就是提供了过少的可能性,兼之缺乏背景故事的支撑,陷入不愠不火的尴尬也在情理之中。大灾变片头CG中死亡之翼出场气势如虹,横贯东西,片尾英雄谷的雕像倒地却犹如一个不祥之兆,这的确是一场灾变,对任何人来说都是如此。作为一个奇幻游戏,我们无法想象这个世界没有英雄;作为一个RPG游戏,我们没有理由不希望这个英雄不是自己。
看到《熊猫人之谜》片头CG之前,我一直听说新资料片是联盟和部落战争的不断升级,可出乎意料,我竟从CG的干戈中看到了玉帛。不由想起当年那段震撼人心的语音:&&&自从联盟与部落并肩作战,共同对抗燃烧军团的入侵,已经过去了四年。虽然成功的保护了艾泽拉斯的和平,联盟与部落之间那脆弱的协议却早已荡然无存&&如今,震天的战鼓再一次响起!&自那之后,联盟与部落只有一次合作,那是在遥远的安其拉时代,他们曾共同对抗其拉虫人,那是2006年春节,距离今天已经六年了&&甚至比联盟与部落并肩对抗燃烧军团入侵的时间还长。
看到在熊猫人面前联盟与部落的勇士联手,我有些惊讶,又有些期待。J.AllenBrack表示:MOP的剧情与过去最大的不同是:在过去的版本中总会出现一个声名显赫最终大boss,而MOP中会让你领略人性的美好和最终的和平&&说好的战争升级呢?如果之前的消息都是在忽悠,我情愿被忽悠,我期待被忽悠,我没有道理不急着想知道迷雾后面有些什么。
十年前,我第一次接触到《魔兽争霸3》,眼看着阿尔萨斯受到玛尔加尼斯的诱惑,杀死克尔苏加德,带领军队远赴诺森德&&在那之后,我就无比期盼接下来会发生的事情,我迫切想知道事情会变成怎么样。如果能有一个确切的结果,我并不在乎之前的等待,以及在这段等待过程中我是什么形态。克尔苏加德曾是那样高不可攀的存在,战胜他象征着人类与传说中的英雄并驾齐驱。他的战利品在TBC里很快就一文不值,但曾经战胜过地球时代的克尔苏加德,见证他的死亡,那就足够让一个老WOW玩家铭记一生。
死亡,只不过是开始。
一个MMORPG游戏,要经营那么庞大的世界观,就必须有个与之匹配的好故事,至少要能吸引玩家探究下去。MOP的片头CG让我得以窥见冰山一角,原来,我对这个游戏的爱从来就没有消失,不同的是,从前我是一个RL,一个会长,现在我只是一个普普通通的玩家,真正的玩家。所以我反而庆幸这段AFK的经历,这让我的归来宛如新生,我有了一个全新的开始,终于可以心无旁骛地去感受,看看游戏变了多少,又能改变我多少,看看它能不能带给我十年之前的那种激动。
熊猫人之谜壁纸
熊猫人之谜壁纸
关注52PK微信公众号
扫描二维码或添加微信号:love52pk 关注“52PK游戏网”
第一时间获取最火游戏激活码
最有趣游戏资讯
*网友评论仅代表其个人看法,并不表明本站同意其观点及描述。口袋飞禽走兽
类别:动作冒险
版本: v1.2.0版中文版
类型:单机
语言:简体中文
大小:32 MB
手机扫描二维码下载
《口袋飞禽走兽》作为一款移植游戏来说,这款游戏从经典的街机移植到苹果手机上来了。游戏的整体内容没有做太大的改变,并且游戏的规则和街机厅规则完全一致。喜欢这款赌机游戏的玩家们可以来下载哦!
口袋飞禽走兽应用介绍
游戏厅人气最高的飞禽走兽游戏登陆苹果手机,100%街机完美移植!高清画面震撼您的双眼!本游戏是游戏厅人气最高的游戏!现在您可以随时随地和各路高手一起游戏,用您的胆略和智慧驰骋江湖!
口袋飞禽走兽游戏特色
▲ 街机完美移植 完美移植游戏厅街机,高清画质,震撼音乐,让您随时随地体验街机刺激感觉!▲ 免费金币天天送 注册即有金币赠送,每日登录即可领取免费金币!▲ 多人联网PK 游戏中4大嗨场,多个房间选择!▲ 经典玩法,应有尽有 囊括飞禽走兽所有经典玩法,押动物,押飞禽,还有金鲨鱼、银鲨鱼,找回难忘的乐趣! ▲ 游戏大奖,一个不少 彩金、金鲨、银鲨正是你力挽狂澜的时候!
口袋飞禽走兽游戏操作
游戏操作简单、极易上手,是打发无聊时间的最佳选择!把大型游戏机装进口袋,随时随地抓几只鲨鱼大赚一把吧!同时,还可邀请朋友互动一下,比一比谁的运气更佳!
口袋飞禽走兽游戏评测
百乐飞禽走兽iphone版v1.2.0是一款游戏厅人气最高的动作街机游戏,游戏具有100%街机完美移植的功能,高清画面震撼您的双眼。经典玩法,应有尽有,多个房间供玩家选择,并且游戏规则和一般街机厅规则完全一致,容易使玩家找回难忘的乐趣,让玩家随时随地体验街机刺激的感觉!人生是由无数的随机事件连接而成,机会总是藏在诸多的可能性中,如果运气是成功的加速器,那么,您的选择便是直达成功的方向盘!面对未知的风险,需要我们以理性的头脑去分析,赌博如此,生活、爱情与事业亦如此,恐惧与贪婪永远是您最大的敌人!本游戏在为您提供娱乐的同时还可锻炼智商和情商!总之,《口袋飞禽走兽》这款游戏虽说是移植游戏,但是游戏内容一点都不必街机游戏来的差。除了高品质的游戏画面以外还有相当震撼的音乐。小编个人觉得通过这款手机游戏还能提高玩家们的玩机技术哦!
简体中文 | IOS, Android16-12-01
简体中文 | IOS, Android16-12-01
简体中文 | IOS, Android16-12-01
简体中文 | IOS, Android16-12-01
简体中文 | IOS, Android16-11-30
简体中文 | IOS, Android16-11-30
简体中文 | IOS, Android16-11-30
简体中文 | IOS, Android16-11-30
简体中文 | IOS, Android16-11-29
简体中文 | IOS, Android16-11-29飞禽走兽皆为我所用&《热血江湖2》灵兽盘点
&&&&来源:&&&&
原标题:飞禽走兽皆为我所用 《热血江湖2》灵兽盘点
  17game旗下3D飘逸武侠网游《热血江湖2》改编自韩国同名人气漫画,以传统武侠题材为背景,多元化的轻功武侠战斗玩法让所有玩家都能体验与众不同的热血游戏激情。在《热血江湖2》的游戏中,有许多独特的系统玩法,灵兽系统作为特色系统之一,在玩家日常的游戏中占据重要的地位。
  《热血江湖2》当中的灵兽拥有多种不同的种类,如野兽类助战灵兽天山黑虎、飞禽类助战灵兽万里血鹰以及最常见的骑乘助战类灵兽麒麟、雪狐等等,可以说从天上到地面的飞禽走兽应有尽有,而且都可以在游戏中被玩家召唤出来和玩家一起共同作战。
  玩家可以在达到60级时领取灵兽管理人处的灵兽任务,通过完成任务来获得自己的第一只灵兽。比较特殊的是,天山黑虎则是玩家在农场建造兽栏建筑而获得的,属于农场特有灵兽。在游戏中,玩家需要分享人物经验来帮助灵兽升级,而随着灵兽的不断成长,越来越多的灵兽技能也会随之解锁。而游戏当中的所有灵兽均可以被加配额外的灵兽装备,以此来获得更高的基础属性。骑乘类的灵兽更是能够装备可供灵兽飞行之用的“灵兽之翼”。通过“灵兽之翼”玩家可骑乘灵兽在游戏当中进行飞行,同时更可以在骑乘状态下直接对敌人发起技能攻击。
  灵兽可骑乘可战斗,可随时随地与玩家并肩作战、驰骋沙场。赶快加入《热血江湖2》的武侠世界,收集各种不同的灵兽,并提升灵兽的力量、敏捷、体力、智能、智慧等属性,让它成为你闯荡江湖的好帮手!
(责编:董思睿、沈光倩)
善意回帖,理性发言!
使用其他账号登录:
恭喜你,发表成功!
请牢记你的用户名:,密码:,立即进入修改密码。
s后自动返回
5s后自动返回
恭喜你,发表成功!
5s后自动返回
最新评论热门评论
游戏新闻|精彩博客
24小时排行&|&
人 民 网 版 权 所 有 ,未 经 书 面 授 权 禁 止 使 用
Copyright &
by .cn all rights reserved
人 民 网 版 权 所 有 ,未 经 书 面 授 权 禁 止 使 用
Copyright &
by .cn. all rights reserved飞禽走兽奢华驾乘 武林2新骑宠扎堆登场
飞禽走兽奢华驾乘 武林2新骑宠扎堆登场
《武林群侠传2》不删档内测首次更新,全新内容闪亮登场,更多的丰富和精彩为这个劲爆的江湖再添火热激情。天山神鸠、四大门派专属坐骑等飞禽走兽成为游戏中最新的奢华驾乘,给广大玩家带来尊贵的骑乘体验。
天山神鸠是《武林群侠传2》最大气的双载飞行类坐骑,也是最具升值潜力的坐骑。它庞大的羽翼可达到遮天蔽日的效果,让玩家在人群中格外引人注目,空中飞行的快感更加能让玩家体验到俯瞰江湖的豪迈。天山神鸠为双载坐骑,玩家可与朋友或情侣共同骑乘,共享武林美景!
双载飞骑天山神鸠
四大门派专属坐骑
刑天残虎、毒龙血灵、风云飞鹰、无极飞骑,《武林群侠传2》四大门派专属坐骑也于昨日震撼开放。四大门派坐骑也为双载坐骑,玩家可与朋友或情侣共同骑乘。四种不同的飞禽走兽极能展现《武林群侠传2》四大门派的特色,玩家达到40级即可骑乘。
为满足更多玩家的需求,《武林群侠传2》四大门派专属坐骑同时也在免费商城中上架,不花钱同样也能体验到奢华驾乘的尊贵与自豪。
门派坐骑-毒龙血灵
天山神鸠与四大门派专属坐骑,以华丽而强悍的外观和双人同乘的特点迅速跻身为游戏中最奢华的坐骑。玩家可使用疾风丹对坐骑进行强化,提升坐骑速度,享受风驰电掣的疾速快感!
《武林群侠传2》新骑宠扎堆登场,双载坐骑自在享受!
支持键盘 ← 和 → 分页
类型:大型RPG
特征:动作
类型:大型RPG
特征:沙盒
类型:大型RPG
特征:沙盒
你不知道点进去会是什么
Wan网页游戏免费玩indienova 独立游戏 - 知乎专栏
{"debug":false,"apiRoot":"","paySDK":"/api/js","wechatConfigAPI":"/api/wechat/jssdkconfig","name":"production","instance":"column","tokens":{"X-XSRF-TOKEN":null,"X-UDID":null,"Authorization":"oauth c3cef7c66aa9e6a1e3160e20"}}
{"database":{"Post":{"":{"title":"《InsideUE4》GamePlay架构(一)Actor和Component","author":"fjz13","content":"引言如果让你来制作一款3D游戏引擎,你会怎么设计其结构?尽管游戏的类型有很多种,市面上也有众多的3D游戏引擎,但绝大部分游戏引擎都得解决一个基本问题:抽象模拟一个3D游戏世界。根据基本的图形学知识,我们知道,为了展示这个世界,我们需要一个个带着“变换”的“游戏对象”,接着让它们父子嵌套以表现更复杂的结构。本质上,其他的物理模拟,游戏逻辑等功能组件,最终目的也只是为了操作这些“游戏对象”。 这件事,在Unity那里就直接成了“GameObject”和“Component”;在Cocos2dx那里是一个个的“CCNode”,操纵部分直接内嵌在了CCNode里面;在Medusa里是一个个“INode”和“IComponent”。 那么在UE4的眼中,它是怎么看待游戏的3D世界的?创世记UE创世,万物皆UObject,接着有Actor。UObject:起初,UE创世,有感于天地间C++原始之气一片混沌虚无,便撷取凝实一团C++之气,降下无边魔力,洒下秩序之光,便为这个世界生成了坚实的土壤UObject,并用UClass一一为此命名。 藉着UObject提供的元数据、反射生成、GC垃圾回收、序列化、编辑器可见,Class Default Object等,UE可以构建一个Object运行的世界。(后续会有一个大长篇深挖UObject)Actor:世界有了土壤之后,但还少了一些生动色彩,如果女娲造人一般,UE取一些UObject的泥巴,派生出了Actor。在UE眼中,整个世界从此了有了一个个生动的“演员”,众多的“演员”们,一起齐心协力为观众上演一场精彩的游戏。 脱胎自Object的Actor也多了一些本事:Replication(网络复制),Spawn(生生死死),Tick(有了心跳)。 Actor无疑是UE中最重要的角色之一,组织庞大,最常见的有StaticMeshActor, CameraActor和 PlayerStartActor等。Actor之间还可以互相“嵌套”,拥有相对的“父子”关系。思考:为何Actor不像GameObject一样自带Transform? 我们知道,如果一个对象需要在3D世界中表示,那么它必然要携带一个Transform matrix来表示其位置。关键在于,在UE看来,Actor并不只是3D中的“表示”,一些不在世界里展示的“不可见对象”也可以是Actor,如AInfo(派生类AWorldSetting,AGameMode,AGameSession,APlayerState,AGameState等),AHUD,APlayerCameraManager等,代表了这个世界的某种信息、状态、规则。你可以把这些看作都是一个个默默工作的灵体Actor。所以,Actor的概念在UE里其实不是某种具象化的3D世界里的对象,而是世界里的种种元素,用更泛化抽象的概念来看,小到一个个地上的石头,大到整个世界的运行规则,都是Actor. 当然,你也可以说即使带着Transform,把坐标设置为原点,然后不可见不就行了?这样其实当然也是可以,不过可能因为UE跟贴近C++一些的缘故,所以设计哲学上就更偏向于C++的哲学“不为你不需要的东西付代价”。一个Transform再加上附带的逆矩阵之类的表示,内存占用上其实也是挺可观的。要知道UE可是会抠门到连bool变量都要写成uint bPending:1;位域来节省一个字节的内存的。 换一个角度讲,如果把带Transform也当成一个Actor的额外能力可以自由装卸的话,那其实也可以自圆其说。经过了UE的权衡和考虑,把Transform封装进了SceneComponent,当作RootComponent。但在权衡到使用的便利性的时候,大部分Actor其实是有Transform的,我们会经常获取设置它的坐标,如果总是得先获取一下SceneComponent,然后再调用相应接口的话,那也太繁琐了。所以UE也为了我们直接提供了一些便利性的Actor方法,如(Get/Set)ActorLocation等,其实内部都是转发到RootComponent。/*~\n * Returns location of the RootComponent \n * this is a template for no other reason than to delay compilation until USceneComponent is defined\n */ \ntemplate&class T&\nstatic FORCEINLINE FVector GetActorLocation(const T* RootComponent)\n{\n
return (RootComponent != nullptr) ? RootComponent-&GetComponentLocation() : FVector(0.f,0.f,0.f);\n}\nbool AActor::SetActorLocation(const FVector& NewLocation, bool bSweep, FHitResult* OutSweepHitResult, ETeleportType Teleport)\n{\n
if (RootComponent)\n
const FVector Delta = NewLocation - GetActorLocation();\n
return RootComponent-&MoveComponent(Delta, GetActorQuat(), bSweep, OutSweepHitResult, MOVECOMP_NoFlags, Teleport);\n
else if (OutSweepHitResult)\n
*OutSweepHitResult = FHitResult();\n
}\\n}\n\n同理,Actor能接收处理Input事件的能力,其实也是转发到内部的UInputComponent* InputC同样也提供了便利方法。Component世界纷繁复杂,光有一种Actor可不够,自然就需要有各种不同技能的Actor各司其职。在早期的远古时代,每个Actor拥有的技能都是与生俱有,只能父传子一代代的传下去。随着游戏世界的越来越绚丽,需要的技能变得越来越多和频繁改变,这样一组合,唯出身论的Actor数量们就开始爆炸了,而且一个个也越来越胖,最后连UE这样的神也管理不了了。终于,到了第4个纪元,UE窥得一丝隔壁平行宇宙Unity的天机。下定决心,让Actor们轻装上阵,只提供一些通用的基本生存能力,而把众多的“技能”抽象成了一个个“Component”并提供组装的接口,让Actor随用随组装,把自己武装成一个个专业能手。看见UActorComponent的U前缀,是不是想起了什么?没错,UActorComponent也是基础于UObject的一个子类,这意味着其实Component也是有UObject的那些通用功能的。(关于Actor和Component之间Tick的传递后续再细讨论)下面我们来细细看一下Actor和Component的关系: TSet&UActorComponent*& OwnedComponents 保存着这个Actor所拥有的所有Component,一般其中会有一个SceneComponent作为RootComponent。 TArray&UActorComponent*& InstanceComponents 保存着实例化的Components。实例化是个什么意思呢,就是你在蓝图里Details定义的Component,当这个Actor被实例化的时候,这些附属的Component也会被实例化。这其实很好理解,就像士兵手上拿着把武器,当我们拥有一队士兵的时候,自然就一一对应拥有了不同实例化的武器。但OwnedComponents里总是最全的。ReplicatedComponents,InstanceComponents可以看作一个预先的分类。一个Actor若想可以被放进Level里,就必须实例化USceneComponent* RootComponent。但如果你光看代码的话,OwnedComponents其实也是可以包容多个不同SceneComponent的,然后你可以动态获取不同的SceneComponent来当作RootComponent,只不过这种用法确实不太自然,而且也得非常小心维护不同状态,不推荐如此用。在我们的直觉印象里,一个封装过后的Actor应该是一个整体,它能被放进Level中,拥有变换,这一整个整体的概念更加符合自然意识,所以我想,这也是UE为何要在Actor里一一对应一个RootComponent的原因。再来说说Component下面的家族(为了阐明概念,只列出了最常见的):ActorComponent下面最重要的一个Component就非SceneComponent莫属了。SceneComponent提供了两大能力:一是Transform,二是SceneComponent的互相嵌套。 思考:为何ActorComponent不能互相嵌套?而在SceneComponent一级才提供嵌套? 首先,ActorComponent下面当然不是只有SceneComponent,一些UMovementComponent,AIComponent,或者是我们自己写的Component,都是会直接继承ActorComponent的。但很奇怪的是,ActorComponent却是不能嵌套的,在UE的观念里,好像只有带Transform的SceneComponent才有资格被嵌套,好像Component的互相嵌套必须和3D里的transform父子对应起来。 老实说,如果让我来设计Entity-Component模式,我很可能会为了通用性而在ActorComponent这一级直接提供嵌套,这样所有的Component就与生俱来拥有了组合其他Component的能力,灵活性大大提高。但游戏引擎的设计必然也经过了各种权衡,虽然说架构上显得并不那么的统一干净,但其实也大大减少了被误用的机会。实体组件模式推崇的“组合优于继承”的概念确实很强大,但其实同时也带来了一些问题,如Component之间如何互相依赖,如何互相通信,嵌套过深导致的接口便利损失和性能损耗,真正一个让你随便嵌套的组件模式可能会在使用上更容易出问题。 从功能上来说,UE更倾向于编写功能单一的Component(如UMovementComponent),而不是一个整合了其他Component的大管家Component(当然如果你偏要这么干,那UE也阻止不了你)。 而从游戏逻辑的实现来说,UE也是不推荐把游戏逻辑写在Component里面,所以你其实也没什么机会去写一个很复杂的Component.思考:Actor的SceneComponent哲学 很多其他游戏引擎,还有一种设计思路是“万物皆Node”。Node都带变换。比如说你要设计一辆汽车,一种方式是车身作为一个Node,4个轮子各为车身的子Node,然后移动父Node来前进。而在UE里,一种很可能的方式就变成,汽车是一个Actor,车身作为RootComponent,4个轮子都作为RootComponent的子SceneComponent。请读者们细细体会这二者的区别。两种方式都可以实现出优秀的游戏引擎,只是有些理念和侧重点不同。 从设计哲学上来说,其实你把万物看成是Node,或者是Component,并没有什么本质上的不同。看作Node的时候,Node你就要设计的比较轻量廉价,这样才能比较没有负担的创建多个,同理Component也是如此。Actor可以带多个SceneComponent来渲染多个Mesh实体,同样每个Node带一份Mesh再组合也可以实现出同样效果。 个人观点来说,关键的不同是在于你是怎么划分要操作的实体的粒度的。当看成是Node时,因为Node身上的一些通用功能(事件处理等),其实我们是期望着我们可以非常灵活的操作到任何一个细小的对象,我们希望整个世界的所有物体都有一些基本的功能(比如说被拾取),这有点完美主义者的思路。而注重现实的人就会觉得,整个游戏世界里,有相当大一部分对象其实是不那么动态的。比如车子,我关心的只是整体,而不是细小到每一个车轱辘。这种理念就会导成另外一种设计思路:把要操作的实体按照功能划分,而其他的就尽量只是最简单的表示。所以在UE里,其实是把5个薄薄的SceneComponent表示再用Actor功能的盒子装了起来,而在这个盒子内部你可以编写操作这5个对象的逻辑。换做是Node模式,想编写操作逻辑的话,一般就来说就会内化到父Node的内部,不免会有逻辑与表现掺杂之嫌,而如果Node要把逻辑再用组合分离开的话,其实也就转化成了某种ScriptComponent。思考:Actor之间的父子关系是怎么确定的?你应该已经注意到了Actor里面的TArray&AActor*& Children字段,所以你可能会期望看到Actor:AddChild之类的方法,很遗憾。在UE里,Actor之间的父子关系却是通过Component确定的。同一般的Parent:AddChild操作原语不同,UE里是通过Child:AttachToActor或Child:AttachToComponent来创建父子连接的。void AActor::AttachToActor(AActor* ParentActor, const FAttachmentTransformRules& AttachmentRules, FName SocketName)\n{\n
if (RootComponent && ParentActor)\n
USceneComponent* ParentDefaultAttachComponent = ParentActor-&GetDefaultAttachComponent();\n
if (ParentDefaultAttachComponent)\n
RootComponent-&AttachToComponent(ParentDefaultAttachComponent, AttachmentRules, SocketName);\n
}\n}\nvoid AActor::AttachToComponent(USceneComponent* Parent, const FAttachmentTransformRules& AttachmentRules, FName SocketName)\n{\n
if (RootComponent && Parent)\n
RootComponent-&AttachToComponent(Parent, AttachmentRules, SocketName);\n
}\n}\n3D世界里的“父子”关系,我们一般可能会认为就是3D世界里的变换的坐标空间“父子”关系,但如果再度扩展一下,如上所述,一个Actor可是可以带有多个SceneComponent的,这意味着一个Actor是可以带有多个Transform“锚点”的。创建父子时,你到底是要把当前Actor当作对方哪个SceneComponent的子?再进一步,如果你想更细控制到Attach到某个Mesh的某个Socket(关于Socket Slot,目前可以简单理解为一个虚拟插槽,提供变换锚点),你就更需要去寻找到特定的变换锚点,然后Attach的过程分别在Location,Roator,Scale上应用Rule来计算最后的位置。/** Rules for attaching components - needs to be kept synced to EDetachmentRule */\nUENUM()\nenum class EAttachmentRule : uint8\n{\n
/** Keeps current relative transform as the relative transform to the new parent. */\n
KeepRelative,\n
/** Automatically calculates the relative transform such that the attached component maintains the same world transform. */\n
KeepWorld,\n
/** Snaps transform to the attach point */\n
SnapToTarget,\n};\n所以Actor父子之间的“关系”其实隐含了许多数据,而这些数据都是在Component上提供的。Actor其实更像是一个容器,只提供了基本的创建销毁,网络复制,事件触发等一些逻辑性的功能,而把父子的关系维护都交给了具体的Component,所以更准确的说,其实是不同Actor的SceneComponent之间有父子关系,而Actor本身其实并不太关心。接下来的左侧派生链依次提供了物理,材质,网格最终合成了一个我们最普通常见的StaticMeshComponent。而右侧的ChildActorComponent则是提供了Component之下再叠加Actor的能力。聊一聊ChildActorComponent 同作为最常用到的Component之一,ChildActorComponent担负着Actor之间互相组合的胶水。这货在蓝图里静态存在的时候其实并不真正的创建Actor,而是在之后Component实例化的时候才真正创建。void UChildActorComponent::OnRegister()\n{\n
Super::OnRegister();\n
if (ChildActor)\n
if (ChildActor-&GetClass() != ChildActorClass)\n
DestroyChildActor();\n
CreateChildActor();\n
ChildActorName = ChildActor-&GetFName();\n
USceneComponent* ChildRoot = ChildActor-&GetRootComponent();\n
if (ChildRoot && ChildRoot-&GetAttachParent() != this)\n
// attach new actor to this component\n
// we can't attach in CreateChildActor since it has intermediate Mobility set up\n
// causing spam with inconsistent mobility set up\n
// so moving Attach to happen in Register\n
ChildRoot-&AttachToComponent(this, FAttachmentTransformRules::SnapToTargetNotIncludingScale);\n
// Ensure the components replication is correctly initialized\n
SetIsReplicated(ChildActor-&GetIsReplicated());\n
else if (ChildActorClass)\n
CreateChildActor();\n
}\n}\nvoid UChildActorComponent::OnComponentCreated()\n{\n
Super::OnComponentCreated();\n
CreateChildActor();\n}\n这就导致了一个问题,当你把一个ActorClass拖进Level后,这个Actor实际是已经实例化了,你可以直接调整这个Actor的属性。但是你把它拖到另一个Actor Class里,它只会给你空空白白的ChildActorComponent的DetailsPanel,你想调整Actor的属性,就只能等生成了之后,用蓝图或代码去修改。这一点来说,其实还是挺不方便的,我个人觉得应该是还有优化的空间。修订4.14 Child Actor TemplatesUE终于听到了人民群众的呼声,在4.14里增加了Child Actor Templates来支持在子ChildActor的DetailsPannel里查看和修改属性。 后记花了这么多篇幅,才刚刚讲到Actor和Component这两个最基本的整体设计,而关于Actor,Component生命周期,Tick,事件传递等机制性的问题,还都没有展开。UE作为从1代至今4代,久经磨练的一款成熟引擎,GamePlay框架部分其实也就不到十个类,而这些类之间怎么组织,为啥这么设计,有什么权衡和考虑,我相信这里面其实是非常有讲究的。如果是UE的总架构师来讲解的话,肯定能有非常多的心得体会故事。而我们作为学习者,也应该尽量去体会琢磨它的用心,一方面磨练我们自己的架构设计能力,一方面也让我们更能掌握这个游戏的引擎。 从此篇开始,会循序渐进的探讨各个部分的结构设计,最后再从整体的框架上讨论该结构的优劣点。上篇:下篇:引用UE4.14---------------------------------------------------------------------------------------------------------------------------知乎专栏:UE4深入学习QQ群:(非新手入门群,请先学习完官方文档和视频教程) 微信公众号:aboutue,关于UE的一切新闻资讯、技巧问答、文章发布,欢迎关注。个人原创,未经授权,谢绝转载!","updated":"T06:07:30.000Z","canComment":false,"commentPermission":"anyone","commentCount":6,"likeCount":55,"state":"published","isLiked":false,"slug":"","isTitleImageFullScreen":false,"rating":"none","sourceUrl":"","publishedTime":"T14:07:30+08:00","links":{"comments":"/api/posts//comments"},"url":"/p/","titleImage":"/v2-abf21ac2e3c_r.jpg","summary":"","href":"/api/posts/","meta":{"previous":null,"next":null},"snapshotUrl":"","commentsCount":6,"likesCount":55},"":{"title":"《InsideUE4》GamePlay架构(二)Level和World","author":"fjz13","content":"引言上文谈到Actor和Component的关系,UE利用Actor的概念组成一片游戏对象森林,并利用Component组装扩展Actor的能力,让世界里拥有了形形色色的Actor们,拥有了自由表达3D世界的能力。 那么,这些Actor们,到底是怎么组织起来的呢?既然提到了世界,我们的直觉反应是采用一个\"World\"对象来包容所有的Actor们。但是当游戏的虚拟世界非常巨大时,这种方式就捉襟见肘了。首先,目前虽然PC的性能日益强大,但是依然内存也限制了不能一下子加载进所有的游戏资源;其次,因为玩家的活动和可见范围有限,为了最优性能,把即使是很远的跟玩家无关的对象也考虑进来也明显是不明智的。所以我们需要一种更细粒度的概念来划分世界。 不同的游戏引擎们,看待这个过程的角度和理念也不一样。Cocos2dx会认为游戏世界是由Scene组成的,Scene再由一个个Layer层叠表现,然后再有一个Director来导演整个游戏。Unity觉得世界也是由Scene组成的,然后一个Application来扮演上帝来LoadLevel,后来换成了SceneManager。其他的,有的会称为关卡(Level)或地图(map)等等。而UE中把这种拆分叫做关卡(Level),由一个或多个Level组成一个World。 不要觉得这种划分好像很随意,只是个名字不同而已。实际上一个游戏引擎的“世界观”关系到了一整串后续的内容组织,玩家的管理,世界的生成,变换和毁灭。游戏引擎内部的资源的加载释放也往往都是和这种划分(Level)绑定在一起的。Level在UE的世界中,我们之前已经有了空气(C++),土壤(UObject),物件(Actor)。而现在UE又施展神力创建了一片片大陆(Level),在这片大陆上(.map文件),Actor们秩序井然,各种地形拔地而起,植被繁茂,天空雾云缭绕,圣光普照,这也是玩家们降生开始精彩冒险的地方。 可以从ULevel的前缀U看出来Level(大陆)也确实是继承于UObject(土壤)的。那既然同属于Object下面的各Actor们都拥有了一定的智能能力(支持蓝图脚本),Level自然也得体现出大地的意志,所以默认带了一个土地公(ALevelScriptActor),允许我们在关卡里编写脚本,可以对本关卡里的所有Actor通过名字呼之则来,关卡蓝图实际上就代表着该片大陆上的运行规则。 在Level已经有了管理者之后,一开始大家都挺满意,但渐渐的就发现,好像各个Level需要的功能好像都差不多,都是修改一下光照,物理等一些属性。所以为了方便起见,UE便给每一个Level也都默认配了一个书记官(Info),他一一记录着本Level的各种规则属性,在UE需要的时候便负责相告。更重要的是,在Level需要有其他管理人员一起协助的时候,他也记录着“游戏模式”的名字来让UE可以指派。 前面我们说过,有一些Actor是不“显示”的(没有SceneComponent),是不能“摆放”到Level里的,但是它依然可以在关卡里出力。其中一个家族系列就是AInfo和其之类。今天我们只简单介绍一下跟Level直接相关的一位书记官:AWorldSettings。 其实虽然名字叫做WorldSettings,但其实只是跟Level相关,我猜可能是在上古时代,当时整个世界只有一块大陆,人们就以为当前的大陆就是整个世界,所以给这块大陆的设置就起名为WorldSettings,后来等技术进步了,发现必须有其他大陆了,这个名字已经用得太多反而不好改了,就只好遗留下来了。当然也有可能是因为当Level被添加进World后,这个Level的Settings如果是主PersistentLevel,那它就会被当作整个World的WorldSettings。 注意,Actors里也保存着AWorldSettings和ALevelScriptActor的指针,所以Actors实际上确实是保存了所有Actor。思考:为何AWorldSettings要放进在Actors[0]的位置?而ALevelScriptActor却不用?void ULevel::SortActorList()\n{\n
TArray&AActor*& NewA\n
TArray&AActor*& NewNetA\n
NewActors.Reserve(Actors.Num());\n
NewNetActors.Reserve(Actors.Num());\n
// The WorldSettings tries to stay at index 0\n
NewActors.Add(WorldSettings);\n
// Add non-net actors to the NewActors immediately, cache off the net actors to Append after\n
for (AActor* Actor : Actors)\n
if (Actor != nullptr && Actor != WorldSettings && !Actor-&IsPendingKill())\n
if (IsNetActor(Actor))\n
NewNetActors.Add(Actor);\n
NewActors.Add(Actor);\n
iFirstNetRelevantActor = NewActors.Num();\n
NewActors.Append(MoveTemp(NewNetActors));\n
Actors = MoveTemp(NewActors);
// Replace with sorted list.\n
// Add all network actors to the owning world\n
//[...]\n}\n实际上通过这一段代码可知,Actors们的排序依据是把那些“非网络”的Actor放在前面,而把“网络可复制”的Actor们放在后面,然后加一个起始索引标记iFirstNetRelevantActor,相当于为网络Actor划分了一个缓存,从而加速了网络复制时的检测速度。AWorldSettings因为都是静态的数据提供者,在游戏运行过程中也不会改变,不需要网络复制,所以也就可以一直放在前列,而如果再加个规则,一直放在第一个的话,也能同时把AWorldSettings和其他的前列Actor们再度区分开,在需要的时候也能加速判断。ALevelScriptActor因为是代表关卡蓝图,是允许携带“复制”变量函数的,所以也有可能被排序到后列。思考:既然ALevelScriptActor也继承于AActor,为何关卡蓝图不设计能添加Component? 观察到,平常我们在创建Actor的时候,我们蓝图界面是可以创建Component的。 那为什么在关卡蓝图里,却不能这么做(没有提供该界面功能)? 我虽然在图里标出了Level中拥有ModelComponents,但那其实只是针对BSP应用的一个子集。通过源码发现,其实UE自己也是在C++里往ALevelScriptActor添加UInputComponent来实现关卡蓝图可以响应事件。void ALevelScriptActor::PreInitializeComponents()\n{\n
if (UInputDelegateBinding::SupportsInputDelegate(GetClass()))\n
// create an InputComponent object so that the level script actor can bind key events\n
InputComponent = NewObject&UInputComponent&(this);\n
InputComponent-&RegisterComponent();\n
UInputDelegateBinding::BindInputDelegates(GetClass(), InputComponent);\n
Super::PreInitializeComponents();\n}其实既然ALevelScriptActor是个Actor,那意味着我们当然可以为它添加组件,实际上也确实可以这么做。比如你可以在关卡蓝图里这么干: 而如果你实际意识到关卡蓝图本身就是一个看不见的Actor,你就可以在上面用Actor的各种操作: 在关卡蓝图里的self其实也是个Actor!虽然一般这么干也没什么毛用。 那么好好想想,为啥UE要给你这么一个关卡蓝图界面呢? 在此,我也只能进行一番猜测,ALevelScriptActor作为一个特化的Actor,却把Components列表界面给隐藏了,说明UE其实是不希望我们去复杂化关卡构成的。 假设说UE开放了关卡Component,那么我们在创建组件时就必然要考虑一个问题:哪些是ActorComponent,哪些是LevelComponent,再怎么ALevelScriptActor本质是个Actor,但Level的概念还是要突出,ALevelScriptActor的Actor本质是要隐藏的。所以用户就会多一些心智负担,可能混淆。而如果像这样不开放,大家的思路就都转向先创建个Actor,然后再往之上添加component,思路会比较统一清晰。 再之,从游戏逻辑的组织上来说,Level其实更应该表现为一个Actor的容器。UE其实也是不鼓励在Level里编写太复杂的逻辑的。所以才接着会有了之后的GameMode,Controller那些真正的逻辑控制类(后续会再细讨论)。 所以游戏引擎也并不是说最大化的暴露一切功能给你就是最好的,有时候选择太多了反而容易出错。在这一点上,我觉得UE很好的保持了克制,为我们提供了一个优秀的清晰的不易出错的框架,同时也对高阶用户保留了灵活性。World终于,到了把大陆们(Level)拼装起来的时候了。可以用SubLevel的方式: 也支持WorldComposition的方式自动把项目里的所有Level都组合起来,并设置摆放位置: 具体摆放的操作和技巧并不是本文的重点。简单本质来说,就是一个World里有多个Level,这些Level在什么位置,是在一开始就加载进来,还是Streaming运行时加载。 UE里每个World支持一个PersistentLevel和多个其他Level: Persistent的意思是一开始就加载进World,Streaming是后续动态加载的意思。Levels里保存有所有的当前已经加载的Level,StreamingLevels保存整个World的Levels配置列表。PersistentLevel和CurrentLevel只是个快速引用。在编辑器里编辑的时候,CurrentLevel可以指向其他Level,但运行时CurrentLevel只能是指向PersistentLevel。思考:为何要有主PersistentLevel? 首先,World至少得有一个Level,就像你也得先出生在一块大陆上才可以继续谈起去探索别的新大陆。所以这块玩家出生的大陆就是主Level了。当然了,因为我们也可以同时配置别的Level一开始就加载进来,其实跟PersistentLevel是差不多等价的,但再考虑到另一问题:Levels拼接进World一起之后,各自有各自的worldsetting,那整个World的配置应该以谁的为主?AWorldSettings* UWorld::GetWorldSettings( bool bCheckStreamingPesistent, bool bChecked ) const\n{\n
checkSlow(IsInGameThread());\n
AWorldSettings* WorldSettings =\n
if (PersistentLevel)\n
WorldSettings = PersistentLevel-&GetWorldSettings(bChecked);\n
if( bCheckStreamingPesistent )\n
if( StreamingLevels.Num() & 0 &&\n
StreamingLevels[0] &&\n
StreamingLevels[0]-&IsA&ULevelStreamingPersistent&()) \n
ULevel* Level = StreamingLevels[0]-&GetLoadedLevel();\n
if (Level != nullptr)\n
WorldSettings = Level-&GetWorldSettings();\n
return WorldS\n}可以看出,World的Settings也是以PersistentLevel为主的,但这也并不以为着其他Level的Settings就完全没有作用了,本篇也无法一一列出所有配置选项来说明,简单来说,就是需要在整个世界范围内起作用的配置选项(比如VR的WorldToMeters,KillZ,WorldGravity其他大部分都是)就是需要从主PersistentLevel的配置中提取。而一些配置选项可以在单独Level中起作用的,比如在编辑Level时的光照质量配置就是一个个Level单独的,目前这种配置很少,但可能以后也会增加。在这里只是阐明一个为主其他为辅的Level配置系统。思考:Levels们的Actors和World有直接关系吗? 当别的Level被添加进当前World之后,我们能直接在WorldOutliner里看到其他Level的Actor们。 但这并不代表着World直接引用了Level里的Actor们。TActorIteratorBase(World的Actor迭代器)内部的实现也只是在遍历Levels来获得所有Actor。当然World为了更快速的操作Controllers和Pawn也都保存了引用。但Levels却共享着World的一个PhysicsScene,这也意味着Levels里的Actors的物理实体其实都是在World里的,这也好理解,毕竟物理的碰撞之类的当然要是全局的了。再说到导航,World在拼接Level的时候,也是会同时把两个Level的导航网格给“拼接”起来的。当然目前还不是深入细节的时候,现在只要从大局上明白World-Level-Actor的关系。思考:为什么要在Level里保存Actors,而不是把所有Map的Actors配置都生成在World一个总Actors里? 这肯定也是一种实现方式,好处是把整个World看成一个整体,所有的actors都从属于world,这样就不存在Level边界,可以更整体的处理Actors的作用范围和判定问题,实现上也少了拼接导航等步骤。当然坏处也是模糊了Level边界,这样在加载进一个Level之后,之后再动态释放,就需要再重新再从整体中抽离出部分来释放,这个筛选过程也会产生比较大的损耗。试着去理解UE的权衡,应该是尽量的把损耗平摊(这里是把Level加载释放的损耗尽量减小),才不会产生比较大的帧率波动,让玩家感觉到卡帧。总结Level作为Actor的容器,同时也划分了World,一方面支持了Level的动态加载,另一方面也允许了团队的实时协作,大家可以同时并行编辑不同的Level。一般而言,一个玩家从游戏开始到结束,UE会创造一个GameWorld给玩家并一直存在。玩家切换场景或关卡,也只是在这个World中加载释放不同的Level。既然Level拥有了管理者(LevelScriptActor),玩家可以编写特定关卡的逻辑,那么我们能否对World这种层次编写逻辑呢?答案是肯定的,不过本文篇幅有限,敬请期待下篇。上篇:下篇:UE4.14---------------------------------------------------------------------------------------------------------------------------知乎专栏:UE4深入学习QQ群:(非新手入门群,请先学习完官方文档和视频教程) 微信公众号:aboutue,关于UE的一切新闻资讯、技巧问答、文章发布,欢迎关注。个人原创,未经授权,谢绝转载!","updated":"T06:25:08.000Z","canComment":false,"commentPermission":"anyone","commentCount":8,"likeCount":36,"state":"published","isLiked":false,"slug":"","isTitleImageFullScreen":false,"rating":"none","sourceUrl":"","publishedTime":"T14:25:08+08:00","links":{"comments":"/api/posts//comments"},"url":"/p/","titleImage":"/v2-0f7fea665f4a717d0ed1_r.jpg","summary":"","href":"/api/posts/","meta":{"previous":null,"next":null},"snapshotUrl":"","commentsCount":8,"likesCount":36},"":{"title":"《InsideUE4》GamePlay架构(三)WorldContext,GameInstance,Engine","author":"fjz13","content":"引言前文提到说一个World管理多个Level,并负责它们的加载释放。那么,问题来了,一个游戏里是只有一个World吗?WorldContext答案是否定的,首先World就不是只有一种类型,比如编辑器本身就也是一个World,里面显示的游戏场景也是一个World,这两个World互相协作构成了我们的编辑体验。然后点播放的时候,引擎又可以生成新的类型World来让我们测试。简单来说,UE其实是一个平行宇宙世界观。 以下是一些世界类型:namespace EWorldType\n{\n\tenum Type\n\t{\n\t\tNone,\t\t// An untyped world, in most cases this will be the vestigial worlds of streamed in sub-levels\n\t\tGame,\t\t// The game world\n\t\tEditor,\t\t// A world being edited in the editor\n\t\tPIE,\t\t// A Play In Editor world\n\t\tPreview,\t// A preview world for an editor tool\n\t\tInactive\t// An editor world that was loaded but not currently being edited in the level editor\n\t};\n}而UE用来管理和跟踪这些World的工具就是WorldContext: FWorldContext保存着ThisCurrentWorld来指向当前的World。而当需要从一个World切换到另一个World的时候(比如说当点击播放时,就是从Preview切换到PIE),FWorldContext就用来保存切换过程信息和目标World上下文信息。所以一般在切换的时候,比如OpenLevel,也都会需要传FWorldContext的参数。一般就来说,对于独立运行的游戏,WorldContext只有唯一个。而对于编辑器模式,则是一个WorldContext给编辑器,一个WorldContext给PIE(Play In Editor)的World。一般来说我们不需要直接操作到这个类,引擎内部已经处理好各种World的协作。 不仅如此,同时FWorldContext还保存着World里Level切换的上下文:struct FWorldContext\n{\n
[...]\n\tTEnumAsByte&EWorldType::Type&\tWorldT\n\n\tFSeamlessTravelHandler SeamlessTravelH\n\n\tFName ContextH\n\n\t/** URL to travel to for pending client connect */\n\tFString TravelURL;\n\n\t/** TravelType for pending client connects */\n\tuint8 TravelT\n\n\t/** URL the last time we traveled */\n\tUPROPERTY()\n\tstruct FURL LastURL;\n\n\t/** last server we connected to (for \"reconnect\" command) */\n\tUPROPERTY()\n\tstruct FURL LastRemoteURL;\n\n}\n这里的TravelURL和TravelType就是负责设定下一个Level的目标和转换过程。// Traveling from server to server.\nUENUM()\nenum ETravelType\n{\n\t/** Absolute URL. */\n\tTRAVEL_Absolute,\n\t/** Partial (carry name, reset server). */\n\tTRAVEL_Partial,\n\t/** Relative URL. */\n\tTRAVEL_Relative,\n\tTRAVEL_MAX,\n};\n\nvoid UEngine::SetClientTravel( UWorld *InWorld, const TCHAR* NextURL, ETravelType InTravelType )\n{\n\tFWorldContext &Context = GetWorldContextFromWorldChecked(InWorld);\n\t// set TravelURL.
Will be processed safely on the next tick in UGameEngine::Tick().\n\tContext.TravelURL
= NextURL;\n\tContext.TravelType
= InTravelT\n
[...]\n}\n粗略的流程是UE在OpenLevel的时候, 先设置当前World的Context上的TravelURL,然后在UEngine::TickWorldTravel的时候判断TravelURL非空来真正执行Level的切换。具体的Level切换详细流程比较复杂,目前先从大局上理解整体结构。总而言之,WorldContext既负责World之间切换的上下文,也负责Level之间切换的操作信息。思考:为何Level的切换信息不放在World里? 因为UE有一个逻辑,一个World只有一个PersistentLevel(见上篇),而当我们OpenLevel一个PersistentLevel的时候,实际上引擎做的是先释放掉当前的World,然后再创建个新的World。所以如果我们把下一个Level的信息放在当前的World中,就不得不在释放当前World前又拷贝回来一遍了。 而LoadStreamLevel的时候,就只是在当前的World中载入对象了,所以其实就没有这个限制了。void UGameplayStatics::LoadStreamLevel(UObject* WorldContextObject, FName LevelName,bool bMakeVisibleAfterLoad,bool bShouldBlockOnLoad,FLatentActionInfo LatentInfo)\n{\n\tif (UWorld* World = GEngine-&GetWorldFromContextObject(WorldContextObject))\n\t{\n\t\tFLatentActionManager& LatentManager = World-&GetLatentActionManager();\n\t\tif (LatentManager.FindExistingAction&FStreamLevelAction&(LatentInfo.CallbackTarget, LatentInfo.UUID) == nullptr)\n\t\t{\n\t\t\tFStreamLevelAction* NewAction = new FStreamLevelAction(true, LevelName, bMakeVisibleAfterLoad, bShouldBlockOnLoad, LatentInfo, World);\n\t\t\tLatentManager.AddNewAction(LatentInfo.CallbackTarget, LatentInfo.UUID, NewAction);\n\t\t}\n\t}\n}\nWorld-&GetLatentActionManager()其实也算是保存在当前World里了。思考:为何World和Level的切换要放在下一帧再执行? 首先Level的加载显然是比较慢的,需要载入Map,相应的Mesh,Material……等等。所以这个操作就必须异步化,异步的话其实就剩下两种方式,一种是先记录下来信息之后再执行;一种是命令模式立马往队列里压个命令之后再执行。注意,因为OpenLevel还要相应在主线程生成相应Actor对象,所以有些部分还是要在主线程完成的。这两种模式其实都可以达成需求,前者更加简单明了,后者相对统一。UE也是个进化过来的引擎,也并不是所有的代码都完美无缺。猜想其实也是一开始这么简单就这么做了,后来也没有特别大的改动的动力就一直这样了。引擎最终比的是生产效率的提高,确实也不是代码有多优雅。GameInstance那么这些WorldContexts又是保存在哪里的呢?追根溯源: GameInstance里会保存着当前的WorldConext和其他整个游戏的信息。明白了GameInstance是比World更高的层次之后,我们也就能明白为何那些独立于Level的逻辑或数据要在GameInstance中存储了。 这一点其实也很好理解,大凡游戏引擎都会有一个Game的概念,不管是叫Application还是Director,它都是玩家能直接接触到的最根源的操作类。而UE的GameInstance因为继承于UObject,所以就拥有了动态创建的能力,所以我们可以通过指定GameInstanceClass来让UE创建使用我们自定义的GameInstance子类。所以不论是C++还是BP,我们通常会继承于GameInstance,然后在里面编写应用于整个游戏范围的逻辑。 因为经常有初学者会问到:我的Level切换了,变量数据就丟了,我应该把那些数据放在哪?再清晰直白一点,GameInstance就是你不管Level怎么切换,还是会一直存在的那个对象!Engine让我们继续再往上,终于得见UE大神: 此处UEngine分化出了两个子类:UGameEngine和UEditorEngine。众所周知,UE的编辑器也是UE用自己的引擎渲染出来的,采用的也是Slate那套UI框架。好处有很多,比如跨平台比较统一,UI框架可以复用一套控件库,Dogfood等等,此处不再细讲。所以本质上来说,UE的编辑器其实也是个游戏!我们是在编辑器这个游戏里面创造我们自己的另一个游戏。话虽如此,但比较编辑器和游戏还是有一定差别的,所以UE会在不同模式下根据编译环境而采用不同的具体Engine类,而在基类UEngine里通过一个WorldList保存了所有的World。Standlone Game:会使用UGameEngine来创建出唯一的一个GameWorld,因为也只有一个,所以为了方便起见,就直接保存了GameInstance指针。而对于编辑器来说,EditorWorld其实只是用来预览,所以并不拥有OwningGameInstance,而PlayWorld里的OwningGameInstance才是间接保存了GameInstance.目前来说,因为UE还不支持同时运行多个World(当前只能一个,但可以切换),所以GameInstance其实也是唯一的。提前说些题外话,虽然目前网络部分还没涉及到,但是当我们在Editor里进行MultiplePlayer的测试时,每一个Player Window里都是一个World。如果是DedicateServer模式,那DedicateServer也会是一个World。 最后实例化出来的UEngine实例用一个全局的GEngine变量来保存。至此,我们已经到了引擎的最根处://UnrealEngine\\Engine\\Source\\Runtime\\Engine\\Private\\UnrealEngine.cpp\nENGINE_API UEngine*\tGEngine = NULL;\nGEngine可以说是一切开始的地方了。翻看引擎源码,到处也可以看见从GEngine-&出来的引用。GamePlayStatics既然我们在引擎内部C++层次已经有了访问World操作Level的能力,那么在暴露出的蓝图系统里,UE为了我们的使用方便,也在Engine层次为我们提供了便利操作蓝图函数库。UCLASS ()\nclass UGameplayStatics : public UBlueprintFunctionLibrary \n我们在蓝图里见到的GetPlayerController、SpawActor和OpenLevel等都是来至于这个类的接口。这个类比较简单,相当于一个C++的静态类,只为蓝图暴露提供了一些静态方法。在想借鉴或者是查询某个功能的实现时,此处往往会是一个入口。总结从结构上而言,我们已经来到了最根源的地方。GEngine仿佛就是一棵大树的根,当我们拎起它的时候,也会带出整个游戏世界的各个对象。但目前这些对象:Object-&Actor+Component-&Level-&World-&WorldContext-&GameInstance-&Engine,确实已经足够表达UE游戏世界的各个部分。 那作为GamePlay部分而言,我们还有一个问题:UE是如何把在该对象结构上表达游戏逻辑的? 如果说:“程序=数据+算法”的话,那UE的GamePlay我们已经讨论完了数据部分,而下篇我们将开始讨论UE的游戏逻辑“算法”部分。上篇:下篇:UE4.14---------------------------------------------------------------------------------------------------------------------------知乎专栏:UE4深入学习QQ群:(非新手入门群,请先学习完官方文档和视频教程) 微信公众号:aboutue,关于UE的一切新闻资讯、技巧问答、文章发布,欢迎关注。个人原创,未经授权,谢绝转载!","updated":"T06:03:25.000Z","canComment":false,"commentPermission":"anyone","commentCount":8,"likeCount":30,"state":"published","isLiked":false,"slug":"","isTitleImageFullScreen":false,"rating":"none","sourceUrl":"","publishedTime":"T14:03:25+08:00","links":{"comments":"/api/posts//comments"},"url":"/p/","titleImage":"/v2-a8de534fdd9dc42c233a5c2f5bfd2332_r.png","summary":"","href":"/api/posts/","meta":{"previous":null,"next":null},"snapshotUrl":"","commentsCount":8,"likesCount":30},"":{"title":"《InsideUE4》GamePlay架构(四)Pawn","author":"fjz13","content":"我像是一颗棋 进退任由你决定 我不是你眼中唯一将领 却是不起眼的小兵引言欢迎来到GamePlay架构章节的下半部分! 在上一篇的内容里,我们谈到了UE的3D游戏世界是由Object-&Actor+Component-&Level-&World-&WorldContext-&GameInstance-&Engine来逐渐层层构建而成的。那么从这下半章节开始,我们就将要开始逐一分析,UE是如何在每一个对象层次上表达游戏逻辑的。和分析对象节点树一样,我们也将采用自底向上的方法,从最原始简单的对象开始。首先需要明确的是,本部分接下来要讲述的UE的GamePlay逻辑框架部分,只是讨论UE的设计思想和理念,并不是表示其在所有其他游戏引擎中是最优最完美的方案,同时当然也不是开发人员务必遵守的金科玉律,你依然可以也应该根据自己实际情况灵活变通。UE经过了很多权衡设计和历史进化,最后选择了该设计方案,一方面和对象层级相辅相成,另一方面也提供了足够的自由度可以供你腾挪。 实现一个游戏业务功能的方式有多种,你应该尽量妥善的权衡你当前的现实情况,考虑生产效率、维护性、功能实现、易理解、性能等等多种因素,然后选择你认为最恰当的方式。如果你当前在制作一个快速原型Demo,你大可以简单粗暴,我也不赞成时刻谨遵教条主义一定要分层拆分如何如何;而如果是面对一个正式的比较大型项目,随着规模的扩大,我们就得利用清晰的概念来帮助我们减轻心智负担。UE作为一个老牌的经历了十几年风风雨雨的游戏引擎,也当然有它的一套GamePlay哲学。我们选择了UE,接受了在UE的工作流之下工作,如果我们能比较好的理解它的概念和思想,就能更加的“顺”着它的思路,得心应手海阔任鱼跃。而如果我们“逆”着这个框架来搞自己的一套,一是不免有无法充分利用UE的嫌疑,二也是以UE的庞大和根深错节难免让你碰一头灰费力不讨好。Note1:虽然本部分会涉及到游戏的业务逻辑编写部分,但并不打算详细讨论AI(BehaviorTree,Navigation等)。AI也是一个很大的话题,值得专门开个大章节讨论,我们现在不应该委屈她。 Note2:本部分也不会细讨论输入事件的处理,游戏逻辑确实一大部分是由输入事件驱动起来的,不过我们此时只是简单聊一下概念,后续会有章节再细讨论输入事件的路由流程。 Note3:联机游戏的游戏逻辑自然也是非常重要的,但为了简化本章节的概念,所以网络联机的逻辑同步等也都不会涉及。留待后续网络章节再好好的阐述。ComponentActor可以说是由Component组成的,所以Component其实是我们对象树里最底层的员工了。在UE里,Component表达的是“功能”的概念。比如说你要实现一个可以响应的WASD移动的功能,或者是VR里抓取的功能,甚至是嵌套另一个Actor的功能,这些都是一个个组件。正确理解“功能”和“游戏业务逻辑”的区分是理解Component的关键要点。 所以我们在这一个层级上要编写的逻辑,是实现一个个“与特定游戏无关”的功能。理想情况下,等你的一个游戏完成,你那些已经实现完成的Components是可以无痛迁移到下一个游戏中用的。换言之,一旦你发现你在Component中含有游戏的业务逻辑代码,这就是所谓的“Bad Smell”了,要警惕游戏架构是否恰当,是否没有很清晰的概念划分。Actor如果说UE是一个大国家的话,那Actor无疑就是人口最大的民族了。StaticMeshActor,CameraActor……我们天天口里嚷嚷的也都是它。和Unity的Prefab对应的,在UE里我们用的最多的也是BlueprintActor了,我们也常常自定义我们的Actor子类来组装其他Component和Actor,然后再编写一些协作逻辑代码,就似乎完成了一个骁勇善战的特种兵,接下来就可以撒豆成兵般的往Level中扔了。 用的越广泛越多,往往错的也越多。似乎是受到了一种朴素的子承父业的精神感染,也或许是我们的面向对象编程都学得太好的缘故,我们都非常倾向于直接在Actor里堆砌逻辑。右键一个BlueprintActor,刚添加完Component,就立马撸起袖子来,Event、Function和Variable一个个罗列开来,噼里啪啦无不快活!但是且慢,这是最好的方式了吗?让我们一路带着这个问题,试着从UE角度去推演一下,重走一下Actor进化之路。在本章节旅程的终点,我保证,我们可以比较清楚的回答这个问题。其实所有的游戏引擎在构建完节点树之后,都会面临这么一个问题,我的游戏逻辑写在哪里? 有的原始的如Cocos2dx懒得想那么多,干脆就直接码在Node里面得了,所以你翻看Cocos2dx的源码你就会经常发现它的逻辑和表现往往是交杂在一起的,简单直接暴力美学,面向对象继承玩得溜。而面向组合阵营的领军Unity则干脆就把Component思想再应用极致一点,我的逻辑为什么不能也是一个组件?所以Unity里的ScriptComponent也是这种组合思想的体现,模型统一架构优雅,MonoBehavior立大功了!但是在一个Component(ScriptComponent)里去操作管理其他的Components,本身却其实并不是那么优雅,因为有些Component之上的协调管理的事务,从层次上来说,应该放在更高的一个概念上实现。UE在思考这个问题时,却是感觉有些理想主义,颇有些C++的理念,力求不为你不需要的东西付代价,宁愿有时候折衷,也想保住最优性能。UE的架构中也大量应用了各种继承,有些继承链也能拉得很长,同时一方面也吸纳了组合的优点,我们也能见到UE的源码中类的成员变量也是组合了好多其他对象。所以接下来的该介绍的就是UE综合应用这两种思想的设计产物。面向对象派生下来的Pawn和Character,支持组合的Controller们。Pawn那么第二个至关重要的的问题是,哪些Actor需要附加逻辑? 在游戏中,我们之所以会觉得一个角色生动,是因为它会响应我们的交互,并给出恰当的反应。而我们所谓的游戏业务逻辑,实际上编写的就是该如何对玩家的输入提供反馈。同样,一个Actor想要变得“生动”,就得有响应外部输入的能力,否则就只是自动运转麻木的机器人。但是在一个比较大型的3D游戏中,Actor有千千万万,然后并不是所有的Actor都需要和玩家互动,得宠的能直接面圣和玩家互动的Actor也是比较少的。我们经常都只是操作我们的“角色”,让“角色”和场景里的其他物体互动。比如FPS游戏里我们操作的主角或者是FlappyBird里的那只小鸟。所以从这一点上来看,UE中Actor就立马又可以划分出一个类别了,这些Actor们可谓是玩家们的宠儿,它们是玩家们的亲卫兵,对,它的名字就是Pawn! 同其他AInfo一样,UE也是从Actor中再派生出了APawn,并定义了3块基本的模板方法接口: 1. 可被Controller控制 2. PhysicsCollision表示 3. MovementInput的基本响应接口为了更好理解这个概念,让我们看一下用搜索引擎搜一下Pawn得到的图: 没错,Pawn的英文翻译过来可以是兵卒,所以如果把UE游戏看作是一场棋盘上的游戏的话,那这些Pawn就可以看作是在UE的3D世界中玩家可以操纵的棋子,而其他的Actor则可以构成棋盘等。如果是人机对战的话,对方玩家是机器AI,同样需要控制Pawn棋子。所以Pawn就是那些可以被玩家(你或AI)控制的Actor!再考察到UE是做FPS游戏起家的,所以你可以想象这个Pawn就相当于战场里最基本的士兵的表示。一个士兵在战场中首先需要表达自身的存在(PhysicsCollision),可以移动(MovementInput),然后可以响应输入和处理逻辑(Controller),有了这三个基本要素,运用你的想象力,你就可以大概构想出一个被玩家控制的“兵卒”的模样和概念了。 要非常清楚一点的是,Actor是我们用来表示3D游戏中对象的,所以Pawn继承于Actor,概念的重点是在于更清楚的去表示,而不是重点在于Pawn被当作逻辑的载体,就像棋子本身只能简单的表达出出个棋子,但是该如何走还是得再靠外部的Controller机制。你也可以想象成提线木偶,那个木偶就是Pawn,而提线的是Controller。Pawn表达的最关键点是可被玩家操纵的能力。因为UE从FPS进化过来的关系,所以附带的物理表示和移动也一并加了进去,应该也是为了方便的缘故。就像我知道Damage这种业务逻辑部分按照纯粹性来说是不应该出现在引擎的代码里的,但是Actor里就是这么加上了,用的时候也确实能得到便利。游戏引擎是个工程,而不是科学研究,有时候确实模块划分也不是那么纯粹。思考:为何Actor也能接受Input事件? 我上述的对Pawn的描述可能会让你觉得,似乎Pawn既然就是用来被玩家控制的,那么理所当然的我们应该在Pawn上同时实现对输入的接受。但我们会发现实际上EnableInput接口却是在Actor上的,同时InputComponent也是在Actor里面的,意味着实际上你也可以在Actor上绑定处理输入事件。官方的输入事件处理流程图也是表明了这一点: (暂时不用细研究这个图,我们以后会再次见到的。) 我们在此暂不细讨论输入流程为何如此设计,只谈谈该如何理解这一事实。首先应该不难理解输入的处理功能可以实现化出InputComponent,而“输入”的种类也有很多(按键、摇杆、触摸和陀螺仪等等),我们也不能确定和分类哪些Actor的子类该接受哪些种类的输入事件;同时又因为Actor也是由Component组件化组装而成的,UE不可能为了输入的处理就改变Component的组织方式,所以还不如泛泛的在Actor的基类里提供InputComponent的集成,这样反而保证了灵活性。 理解这个问题的要点在于正确区分“输入响应”和“逻辑控制”。比如说WASD移动,Actor拥有最基本的输入响应,它可以响应WASD的按键事件。但是按键了之后呢?该如何移动?Pawn就定义了一个基本的MovementInput套路,相当于把WASD的输入响应再往前包装处理了一步。而“逻辑控制”指的是更高层上的比如寻路或自动巡逻等行为。 作为GamePlay中至关重要的一个逻辑概念,让我再罗嗦强调一遍应该不为过吧。Pawn实现的是“可被控制”的概念。因为“被控制了”之后经常要被移动(UE对FPS是真爱啊),所以Pawn就索性把移动的接口也定义了一下(当然,为了灵活性,内部转交给MovementComponent再处理),既然能移动了,但也不能随便在地图里乱走吧,所以碰撞(物理表示)看来也是需要的啊,好吧,那就加上,齐活了。DefaultPawn,SpectatorPawn,Character让我一口气介绍下面这三位: DefaultPawn因为我们每次想自己搞Pawn都得从Pawn派生过来,然后再一个个添加组件。UE知道我们大家都很懒,所以提供了一个默认的Pawn:DefaultPawn,默认带了一个DefaultPawnMovementComponent、spherical CollisionComponent和StaticMeshComponent。也是上述Pawn阐述过的三件套,只不过都是默认套餐。SpectatorPawnUE的FPS做的太好了,就会有一些观众想要观战。观战的玩家们虽然也在当前地图里,但是我们并不需要真正的去表示它们,只要给他们一些摄像机“漫游”的能力。所以派生于DefaultPawn的SpectatorPawn提供了一个基本的USpectatorPawnMovement(不带重力漫游),并关闭了StaticMesh的显示,碰撞也设置到了“Spectator”通道。Character因为我们是人,所以在游戏中,代入的角色大部分也都是人。大部分游戏中都会有用到人形的角色,既然如此,UE就为我们直接提供了一个人形的Pawn来让我们操纵。 像人一样行走的CharacterMovementComponent, 尽量贴合的CapsuleComponent,再加上骨骼上蒙皮的网格。同样的三件套,不一样的配方。 有些人一开始的时候会困惑应该选择Pawn还是Character,其实从继承体系中就可以了解到Character只不过是Pawn的加强特化版本。一般来说,如果你控制的角色是人形的带骨骼的,那就选择Character吧。而如果是VR中的一双手(假设只有一双手),因为移动模式和显示都算不太上人形,顶多只能算是个漂浮的“幽灵”,所以还是用Pawn方便些。后期如果你想加上人形模型和IK了,那么再把Mesh替换成SkeletalMesh也就行了。Pawn因为是基础款,所以提供了最大的灵活性。总结本篇主要探讨了从Actor到Pawn的分化过程,请读者们也好好自己体会一下这一过程中UE的设计和思量。一个游戏引擎对3D游戏世界的抽象是建立在很多概念之上的,UE的逻辑和实现也都是基于对这些概念的实现和封装。而如果读者你并不清晰理解这些概念,那么就很难正确的应用和组织游戏的逻辑各个部分。本系列教程一如开篇所说,并不会教你应用的各种技巧,而把重点放在讨论UE背后的各种概念,这些才是让我们的头脑保持清晰的关键之处。 因为在下笔力有限,很遗憾,我们心心念念的Controller只好留待下篇了。我在谈Pawn的时候,因为Pawn和Controller是那么紧密的关联着,所以也不得不事先一再的剧透提到Controller。但Controller作为GamePlay逻辑的最最重要的一个载体,可探讨的点也非常的多,所以留待下篇吧。上篇:下篇:引用UE4.14---------------------------------------------------------------------------------------------------------------------------知乎专栏:UE4深入学习QQ群:(非新手入门群,请先学习完官方文档和视频教程) 微信公众号:aboutue,关于UE的一切新闻资讯、技巧问答、文章发布,欢迎关注。个人原创,未经授权,谢绝转载!","updated":"T05:48:35.000Z","canComment":false,"commentPermission":"anyone","commentCount":11,"likeCount":49,"state":"published","isLiked":false,"slug":"","isTitleImageFullScreen":false,"rating":"none","sourceUrl":"","publishedTime":"T13:48:35+08:00","links":{"comments":"/api/posts//comments"},"url":"/p/","titleImage":"/v2-a4260cb93ebf9a5d4cee3f9bcab755dd_r.jpg","summary":"","href":"/api/posts/","meta":{"previous":null,"next":null},"snapshotUrl":"","commentsCount":11,"likesCount":49},"":{"title":"《暗黑地牢》:随机性与策略性的悖论之美","author":"jiang-qing-bo-30","content":"你是一名十字军战士,此刻你面对着主的雕像双膝跪地。你向主恳求救赎,因为你永远忘不掉发生在你身上的事,这次冒险只有你一个人回来了。你头疼欲裂,心魔灼身,银白色的头盔上仍还残留着鲜血,它们好像眨巴着眼睛,一滴一滴地,一滴一滴地,似乎要贯穿你的心脏,同时逼迫你去想象那些恐怖的画面。约翰是一名赏金猎人,身材高大,身上一副维京盔甲凛然不可犯,你很信任他,几个月来你们是队伍的先登,他就像一名狂战士一般,战斗方式野蛮恐怖,他对那些怪物的尖叫声嗜爱不已。然而他死了,他被一头凶猛的大鳄扯碎了尸体咽了下去,这次尖叫的是他。弗农是你的老相识,虽然以出老千和酗酒闻名村镇,但是却异样勇敢与沉着,他是一名弩手,喜欢站在你的背后给予怪物致命一击,然而怪物用长满钉刺的触手将他从队伍中拖了出来,徒留地上一片血滩。最后你想方设法地保护玛丽,她是一名修女,你已做好必死保护她的决心,这是骑士的荣耀,也是以主之名。然而她已不堪重负,长途漫漫的黑暗、此起彼伏的魑魅魍魉、阵阵不断的鬼哭鸦鸣、战友的相继身亡,这一切已经让这位本已脆弱的女性心神崩溃,她双目发红,低吟不断,你只能眼睁睁地看着她渐渐地,渐渐地,没入黑暗。她身上的修女头巾,你现在仍然紧紧地攥在手上。克苏鲁神话的黑暗风格《暗黑地牢(Darkest Dungeon)》 是由Red Hook(红钩)工作室于日发售的一款暗黑系的Roguelike风格的回合制RPG游戏。而游戏近日又推出了DLC《血色之庭》(The Crimson Court),DLC只是给原版游戏加入了一些新的人物、建筑和一个新的场景地图“The Crimson Court”,同时加入了隐藏要素“吸血鬼的邀请函”,游戏的核心机制没有改变。因此本篇评测自然就不能算即时性的介绍文章,因此笔者打算从相对新奇的角度来对《暗黑地牢》做出评论,希望能收旧瓶装新酒之效。对于玩家而言,首先映入眼帘的便是游戏里的黑暗哥特式风格的整体画面,哥特式风格在绝大部分游戏中都有所体现。而在本游戏中哥特风格主要表现为:冷峻刺骨的整体气氛、恐怖颓废的建筑群落、凄凉幽深的外部环境、尖削分明的人物线条、浓深的整体颜色对比、混沌不明的世界秩序、以及稀缺的日光和巫术、吸血鬼、诅咒、乌鸦、死亡等一系列象征元素。这种整体画面风格推崇混沌、无秩序、无所依赖,黑色相对于黄色具有画面优势,暗喻黑暗对光明、混沌对有序的侵蚀与吞噬。\n同样游戏的怪物风格、传说故事、恐怖末日的整体氛围又都来源于克苏鲁神话。克苏鲁神话尽管是一个相对庞杂的神话系统,但整体风格仍算鲜明。在克苏鲁神话中,宇宙是一个与科学、秩序、人类理性相对的容器,因为科学与理性使人们免于恐惧,而克苏鲁神话中的宇宙恰恰拥抱这种人类原始的恐惧与混乱。那些人类生活中日常的动植物,本是人类已经了解的对象,但在神话中却都成了人类的梦靥,饥渴地环伺猎捕着人类。以上对于血缘玩家来说可以说一点都不陌生。游戏为了进一步烘托恐怖幽森的气氛,还会不断在玩家的操作行动中给予旁白反馈,例如敌方如果是中了出血效果而死的话,则会出现一声朗读咒语般的旁白:“慢慢地、轻轻地、这就是生命被夺走的样子。”游戏不仅在画面风格与叙事上继承了克苏鲁神话,而且还加入了“stress”(精神紧张度)来还原人类探索未知深处的恐惧感。游戏中队员在探索地下城、遭遇怪物奇袭攻击、我军被暴击、遭遇埋伏、从地下城撤退时都会降低精神值。精神值过低时便会出现出旷工不干事、成功地给予友军致命一击、魔法师物理攻击对方坦克种种令人啼笑皆非的事,也就是本文开头脑补的修女的故事(文学源于脑补),这一个设计可堪称是RPG回合类游戏中大胆的创新,并且这种创新刚好接续了克苏鲁神话的传统,可谓梅开二朵共连一枝。随机化的游戏机制也许是为了可以让玩家在Roguelike的基础上更一步体会到命运的不可掌控,又或者是游戏的设计师以前就是设计赌博随机类游戏的,玩家在游戏中不得不面对相当大体量的随机化系统。至于这个游戏是有多注重随机性,我总结如下:1游戏副本是随机的,当然这样说有点不负责任,事实上游戏副本中的怪物配置、宝藏数量、路程长短是按一定比例分配的,玩家对此可以在战略上进行妥善筹备。\n2场景中人物什么时候饿、挖到什么宝藏、什么时候降低精神值、偷袭与被偷袭是随机,当然这种随机性对于玩家只是徒增新鲜感而已。某些人物技能的效果值变动幅度也比较大,例如频繁登上各大卫视,第十八代治肾传人,北京大学医学院院长的老中医学者,他的治疗技能效果初始便在0-15左右摆动。这就比较考验玩家平时拜佛的积极性和上香的做功了。不要怀疑你吃的是假药,因为你还不够虔诚,看的电视不够多。(不知道我说的是什么梗的,可百度“刘洪滨”)4如果以上的随机性还有值得鼓掌的敌方的话,那人物属性的随机性红钩估计只能得0分。队伍中的每一个人员都有自己的特性或者说癖好,比如十字军战士特性是虔诚,那么他就只能在修道院回复精神,另外一些特性则影响人物的基础属性。属性可以通过探索完一个副本随机得到,所以不要问我为什么一名十字军战士奋勇杀敌后得到的属性是“从爱尔兰到契丹,你出老千的名声无人不知无人不晓”。(known cheat)对职业控来说游戏提供的队伍职业种类比较可观,有十字军、强盗、恶女、修女、老中医、盗墓者、赏金猎人、老兵、小丑、驯狗师以及DLC新加入的角色苦修者。角色都享有专属的技能,拥有自己更偏好的站位,且角色的技能施放与角色站位具有高度相关性,譬如老中医就不能站在最前面了,因为平凡地出现终究会被拆穿(我没有说谎,我何必说谎,你懂我的,我对你从来就不会假装)。技能类型依然是物理、buff/debuff、治愈等几类,某些技能附带击晕、拉位、推位、流血等效果,这些效果再加上战术上较大的随机性又进一步扩展了战场的变动。城市中建筑的升级材料来源于副本所得。酒吧与修道院都是治疗人的建筑,其中有许多活动,这些活动与人物的不同特征具有关联,从宏观战略来考虑,如何分配人物的休息与战斗也许就是玩家主动性体现的第一步。混沌与秩序性亚里士多德曾说:“人是政治的动物”,在亚里士多德看来,人有这样一种倾向:将原本无逻辑的事物按照人自身理性逻辑进行区分,分辨善恶。对于游戏来说也是如此,玩家在游戏中从对游戏一无所知到熟练上手,甚至达到“庖丁解牛”般神乎其技的境界,都表征着人心理层面对未知与迷茫的深深抗拒。玩家想要的是尽可能快地组建一支稳定的部队,就如人类对恐惧与随机性的排斥一样,玩家玩游戏的总体倾向是要追求秩序感,追求理性之光能照耀的地方,追求游戏进程能够处于自己的意料之中。如果从这种角度来看《暗黑地牢》,会发现这款游戏的随机性的设置是多么违反人性,玩家的运筹帷幄的能力似乎都被消解地干干净净,只有徒劳、徒费、徒伤自我的精力。但我本人觉得亚里士多德的话只说对了人性的一部分,还有一种人性,追求的是失序、混沌、破坏、好奇、过度与惊异,尼采曾将其叫做“酒神精神”,酒神指的是希腊神话中的狄俄尼索斯,尼采认为他象征着希腊悲剧的狂热、兴奋、不稳定的一面,当然,也象征着人性。从这种角度来看待《暗黑地牢》,就会发现红钩工作室的匠心独运。游戏内部流动着克苏鲁神话的文化基因,正如前文所述,克苏鲁神话本身就推崇混沌与恐惧,突出人内心的原始情愫,人的理性面对魔神的渺小与无力。因此重随机性再加上Roguelike游戏的死不复生,便让玩家从头到尾都战战兢兢,不敢固步自封,命运的无常随时威胁着你,就像魂系列的玩家都明白的一个道理:你要战胜的其实是自己内心的恐惧与骄傲。游戏设计学中一般都认为游戏设计中游戏的随机性与游戏的策略性是相对立的,就如玩大富翁的人不会体会到文明系列的策略性,掷骰子的时候不会体验到下围棋的腹中藏兵。然而这毕竟是两个极端的案例,某些涉猎游戏比较广泛的玩家估计是不会同意这种简单的列举的,试想一想那个叫“paradox”的游戏公司,paradox即“悖论”,而它开发出来的p社五萌就是游戏策略与随机性结合的典范。也许正如起名,“paradox”公司处处都在寻找悖论的美妙之处。只要随机性对策略深度构不成决定意义上的破坏,那么玩家在决策的时候就不得不考虑这种随机性。例如在《欧陆风云4》里玩家尽量会将自己的稳定性保持在0及以上,为的就是防备随机事件带来的-1稳定。这时候的随机性就是玩家的考虑因子了,如果处理的好的话,那么玩家就既要处理策略因子(也就是那些原本就留给玩家策略处理的东西),同时又必须要处理随机因子(也就是游戏系统的随机性让玩家不得不防的东西)。当然必须得承认,红钩在这方面并没有走得非常成熟。我们可以看到红钩下了很大一盘棋,《暗黑地牢》的精神值、人不复生、职业随机化刷出、有限的休息活动、人物属性的或好或坏就是为了干一件事,即阻碍或者延长游戏玩家组建自己的万金油队伍,然而副本的单调与职业技能之间的不平衡让玩家不久就能知道人物之间的孰优孰劣,这估计很让红钩伤心。但是尽管如此,红钩的探索精神是值得令人称道的。最后,红钩在steam上因为延迟推出汉化的原因让庞大数量的玩家刷差评,有兴趣的读者可以了解下事件始末,本人不做评价。由于steam 未将商品的评价分为内容评价与销售评价,游戏作品本身就不得不承担了不该承担的罪罚。你是一名十字军战士,此刻你听到外面群起骚动,他们纷纷谈论你的英雄事迹。你出了门,对他们冷眼相对,你离开了这个村子。你,来到了一块墓地,那里有你30多个曾经的兄弟,你吻了吻自己的剑,留下了男人的泪。","updated":"T05:07:19.000Z","canComment":false,"commentPermission":"anyone","commentCount":33,"likeCount":70,"state":"published","isLiked":false,"slug":"","isTitleImageFullScreen":false,"rating":"none","sourceUrl":"","publishedTime":"T13:07:19+08:00","links":{"comments":"/api/posts//comments"},"url":"/p/","titleImage":"/v2-2d4c8cbec0b5bb27e65b17caee9c09ff_r.png","summary":"","href":"/api/posts/","meta":{"previous":null,"next":null},"snapshotUrl":"","commentsCount":33,"likesCount":70},"":{"title":"《铲子骑士》:FC动作与场景元素的集大成者","author":"jiang-qing-bo-30","content":"一具血红色的幽灵斗篷随风摆荡,你蹲踞在高塔上,就像一尊古旧的石像。这里只有背影对着空墙,留在了像素游戏的历史上。YachtClubGames工作室凭着其不屈不挠的匠人精神完成了《铲子骑士》的本体与瘟疫骑士和幽灵骑士的DLC,就像《痛苦之灵》中形影相吊的幽灵骑士一般,这些作品仿佛是在自我温暖着寒冷的身体。《痛苦之灵》虽以独立游戏形式发售,但是拥有本体的玩家却可以通过更新的方式免费得尝。在某种程度上,这正是工作室散尽资产的报恩方式,就像幽灵骑士的哀婉,凭吊了一个时代。这个时代叫做FC时代,铲子骑士系列虽然是现时代8-bit的像素闯关游戏,但其本质上仍然烙印着FC近战闯关类游戏的血肉,毋宁说,它们是FC游戏的招魂幡,持续不断地向现代旅客诉说着某所古代建筑的重重魅影。笔者将就最近发售的《铲子骑士:痛苦之灵》谈谈这些“古代建筑”的伟大不朽,即便它们或已深埋。《痛苦之灵》属于FC时代的叙事机制:动作叙事系统熟悉《黑暗之魂》系列(或者说宫崎英高系列)的玩家都知道,魂系列的游戏破碎了线性叙事的文本,将其强制性的植入玩家的动作所能遍及的范围,这是一种成功的用动作而非电影CG来叙事的专属于游戏的叙事方式。同样FC及其模仿类型的游戏也都会强调这种动作叙事,这是他们的灵魂。什么叫动作叙事呢?《痛苦之灵》的动作叙事系统的单元:普攻、跳、方向与层次设置如果要像分解广播体操一样分解一个FC近战闯关游戏(如双截龙、忍者龙剑传等)来分解痛苦之灵的动作,它将包含有两个部分:第一部分是动作硬核,这代表着一款游戏的动作性的基础灵魂。另一部分则是副武器设置,但在本作中副武器设置是无序配置的,这就是游戏设计者的暗示:特定的副武器对于任何一关都不是必须的,有时只需硬杠就能完成。《痛苦之灵》的动作硬核就是传统FC动作游戏的三板斧:普攻、跳、方向,试想我们如何就这三个动作单元展开一幅生动的游戏画像?
《痛苦之灵》用了内部结构法,即将普攻、跳与方向无矛盾地互相搭配衍生出:跳攻(跳跃与普攻的结合)、跳向控制(跳跃与方向结合)与方向性跳攻(三者的结合)而斩掉了方向攻(如赤影战士只需站在原地就可控制方向的锁链攻击)方向攻容易对前三者带来矛盾,例如赤影战士的方向攻对于动作苦手是一种福利,但是对于游戏本身设置的可以行云流水地攀旋跃跳的攻击的可能性与挑战性来说是一种损害。方向性跳攻意味着玩家要熟练三个动作单元并利用身体记忆去应对复杂场景,而方向攻则可能减轻这种负担并把设计者精心制作的多层次关卡给破坏掉。例如在《痛苦之灵》的这种场景下:左有油桶会倒油而下、右有长范围攻击的锤战士、右下有一击毙命的铁铆钉。并且按从上到下构成了三种危险的层局,而水平从左到右方向也构成了三个层局,就像摄影中所讲的线条一样将全场景分成了三个部分。层局越丰富,难度也就越大。既不能密密麻麻的让危险层局占领整个屏幕(如射击游戏雷电),这会给人的视觉以无条理感同时也几乎无法给予玩家自我场面判断的成就感,但也不能过于一马平川。对其的合理掌控只能用人的体验亲自去测量,而《痛苦之灵》的层局布置的体验如此之好,我们几乎能推断游戏制作方的用心之良苦。在《痛苦之灵》中玩家必须运用自己的身体记忆去牢牢掌握这三个动作单元,而一路走来玩家几乎都是在三位合一的状态下不断进行方向性跳攻以应对这些设计者精心设计的层次布局。《痛苦之灵》在这个方面足以与FC时代任何一款游戏媲美,或者说《痛苦之灵》的游戏设计者们对他们的前辈是如此尊重以至于不甘落后。这就是硬派动作游戏的灵魂:“给我1+1+1,我可以给你算出一个世界。”《痛苦之灵》的动作叙事系统场景:为动作单元延伸出空间玩过洛克人元祖(Megaman)玩家都知道,玩家可以在游戏中选择任意关卡,不同关卡对应着不同特色的场景元素。这些场景元素包括但不限于:风景、敌人及其使用的武器、路面、场景,而这些场景都因当初选择的BOSS的特性构成了一个小天地。《痛苦之灵》中幽灵骑士要奉天承运运用强力去征服八位骑士以让他们俯首于女巫,这八位骑士分别是:巫妖庭院的幻影射手、发条之塔的修补匠骑士、自尊荒野古堡的国王骑士、搁浅之船的极地骑士、热血公国的瘟疫骑士、失落之城的鼹鼠骑士、铁鲸港湾的宝藏骑士、飞行机械的螺旋桨骑士。这种堂而皇之的借鉴不失为致敬前辈(洛克人)的例行公事。这几位骑士的设置绝非是完全随意的选择。每一位骑士特性都是一种场景的可能性,都是FC横版游戏历史上不断沉淀遗留下来的经验。如果运用一种结构主义式的分析路径我们几乎可以看到FC的历史到底遗留给我们多少场景制作经验,这些经验是一代又一代的游戏设计师们利用有限资源创造出的一种类型化场景:巫妖庭院-恐惧幽森的整体元素风格-类似恶魔城一般的场景,黑色光影、破败不堪、古堡鬼怪。发条之塔-工业文明的整体风格元素-机械、齿轮、机油自尊荒野古堡-辉煌璀璨的殿堂式整体风格-金色背景、宫殿、王座搁浅之船-冰雪世界的整体风格-白色背景、冰与雪、路面湿滑热血公国-火焰的整体风格-黄色背景、火焰陷阱与敌人失落之城-森林绿地与地下风格-绿色背景、土壤、萌萌的昆虫铁鲸港湾-水世界-海洋、蓝色主调、海洋生物、水与墙共同构成一个似海非海的梦幻场景,玩家行走会延迟以模拟游泳。飞行机械-天空世界-天空色(视日昼而定),着落点与着落点之间的差距设定,对玩家跳跃能力的考验。每一个场景的BOSS都是这个场景的风格的主宰者,似乎是凭借着他们

我要回帖

更多关于 飞禽走兽什么压法能赢 的文章

 

随机推荐