最近玩了shank系列的开发公司新出的游戏饥荒(Don't Starve),容量很小,200MB左右,所以可以归类为小游戏。。但是游戏性却是相当的高,游戏中各物件的交互出奇的丰富和复杂,我相信该游戏90%的创意和亮点就在于这丰富的可交互性中(想想神作辐射系列吧,我大学那会玩辐射2可是玩的的不亦乐乎!)。

这么棒的gameplay制作,我们需要把功劳归到开发组策划和程序的完美配合上。他们为什么可以做得这么好捏?我发现可以说是脚本系统完美应用的结果。在游戏目录data\script下,就是游戏的全部lua脚本,可阅读可修改,有Components,有StateGraph,有Behaviours tree,相当的有可参考性!

首先我发现data\script\prefabs目录下是所有对象(物品,角色)的基本配置(组成动画,掉落物品,component组装,behavior赋予)。比如咱们看二师兄pigman的脚本文件。。

local assets =
{Asset("ANIM", "anim/ds_pig_basic.zip"),Asset("ANIM", "anim/ds_pig_actions.zip"),Asset("ANIM", "anim/ds_pig_attacks.zip"),Asset("ANIM", "anim/pig_build.zip"),Asset("ANIM", "anim/pigspotted_build.zip"),Asset("ANIM", "anim/pig_guard_build.zip"),Asset("ANIM", "anim/werepig_build.zip"),Asset("ANIM", "anim/werepig_basic.zip"),Asset("ANIM", "anim/werepig_actions.zip"),Asset("SOUND", "sound/pig.fsb"),
}local prefabs =
{"meat","monstermeat","poop","tophat","strawhat","pigskin",
}local function SetWerePig(inst)inst:AddTag("werepig")inst:RemoveTag("guard")local brain = require "brains/werepigbrain"inst:SetBrain(brain)inst:SetStateGraph("SGwerepig")inst.AnimState:SetBuild("werepig_build")inst.components.sleeper:SetResistance(3)inst.components.combat:SetDefaultDamage(TUNING.WEREPIG_DAMAGE)inst.components.combat:SetAttackPeriod(TUNING.WEREPIG_ATTACK_PERIOD)inst.components.locomotor.runspeed = TUNING.WEREPIG_RUN_SPEED inst.components.locomotor.walkspeed = TUNING.WEREPIG_WALK_SPEED inst.components.sleeper:SetSleepTest(WerepigSleepTest)inst.components.sleeper:SetWakeTest(WerepigWakeTest)inst.components.lootdropper:SetLoot({"meat","meat", "pigskin"})inst.components.lootdropper.numrandomloot = 0inst.components.health:SetMaxHealth(TUNING.WEREPIG_HEALTH)inst.components.combat:SetTarget(nil)inst.components.combat:SetRetargetFunction(3, WerepigRetargetFn)inst.components.combat:SetKeepTargetFunction(WerepigKeepTargetFn)inst.components.trader:Disable()inst.components.follower:SetLeader(nil)inst.components.talker:IgnoreAll()inst.Label:Enable(false)inst.Label:SetText("")
endlocal function common()local inst = CreateEntity()local trans = inst.entity:AddTransform()local anim = inst.entity:AddAnimState()local sound = inst.entity:AddSoundEmitter()local shadow = inst.entity:AddDynamicShadow()shadow:SetSize( 1.5, .75 )inst.Transform:SetFourFaced()inst.entity:AddLightWatcher()inst.entity:AddLabel()inst.Label:SetFontSize(24)inst.Label:SetFont(TALKINGFONT)inst.Label:SetPos(0,3.8,0)--inst.Label:SetColour(180/255, 50/255, 50/255)inst.Label:Enable(false)MakeCharacterPhysics(inst, 50, .5)inst:AddComponent("locomotor") -- locomotor must be constructed before the stategraphinst.components.locomotor.runspeed = TUNING.PIG_RUN_SPEED --5inst.components.locomotor.walkspeed = TUNING.PIG_WALK_SPEED --3
inst:AddTag("character")inst:AddTag("pig")inst:AddTag("scarytoprey")anim:SetBank("pigman")anim:PlayAnimation("idle_loop")anim:Hide("hat")------------------------------------------inst:AddComponent("eater")inst.components.eater:SetOmnivore()inst.components.eater:SetCanEatHorrible()inst.components.eater.strongstomach = true -- can eat monster meat!
    inst.components.eater:SetOnEatFn(OnEat)------------------------------------------inst:AddComponent("combat")inst.components.combat.hiteffectsymbol = "pig_torso"MakeMediumBurnableCharacter(inst, "pig_torso")inst:AddComponent("named")inst.components.named.possiblenames = STRINGS.PIGNAMESinst.components.named:PickNewName()------------------------------------------inst:AddComponent("werebeast")inst.components.werebeast:SetOnWereFn(SetWerePig)inst.components.werebeast:SetTriggerLimit(4)------------------------------------------inst:AddComponent("follower")inst.components.follower.maxfollowtime = TUNING.PIG_LOYALTY_MAXTIME------------------------------------------inst:AddComponent("health")------------------------------------------
inst:AddComponent("inventory")------------------------------------------
inst:AddComponent("lootdropper")------------------------------------------
inst:AddComponent("knownlocations")inst:AddComponent("talker")inst.components.talker.ontalk = ontalk------------------------------------------
inst:AddComponent("trader")inst.components.trader:SetAcceptTest(ShouldAcceptItem)inst.components.trader.onaccept = OnGetItemFromPlayerinst.components.trader.onrefuse = OnRefuseItem------------------------------------------
inst:AddComponent("sanityaura")inst.components.sanityaura.aurafn = CalcSanityAura------------------------------------------
inst:AddComponent("sleeper")------------------------------------------MakeMediumFreezableCharacter(inst, "pig_torso")------------------------------------------
inst:AddComponent("inspectable")inst.components.inspectable.getstatus = function(inst)if inst:HasTag("werepig") thenreturn "WEREPIG"elseif inst:HasTag("guard") thenreturn "GUARD"elseif inst.components.follower.leader ~= nil thenreturn "FOLLOWER"endend------------------------------------------
   inst.OnSave = function(inst, data)data.build = inst.buildend        inst.OnLoad = function(inst, data)    if data theninst.build = data.build or builds[1]if not inst.components.werebeast:IsInWereState() theninst.AnimState:SetBuild(inst.build)endendend           inst:ListenForEvent("attacked", OnAttacked)    inst:ListenForEvent("newcombattarget", OnNewTarget)return inst
endlocal function normal()local inst = common()inst.build = builds[math.random(#builds)]inst.AnimState:SetBuild(inst.build)SetNormalPig(inst)return inst
endlocal function guard()local inst = common()inst.build = guardbuilds[math.random(#guardbuilds)]inst.AnimState:SetBuild(inst.build)SetGuardPig(inst)return inst
endreturn Prefab( "common/characters/pigman", normal, assets, prefabs),Prefab("common/character/pigguard", guard, assets, prefabs) 

主要值得注意的有几个地方:

  1. SetStateGraph()
  2. SetBrain()
  3. AddComponent()

我阅读了这么一会儿,这3个东西就是一个游戏对象的重要组成部分。它们的脚本分别位于

data\script\stategraphs,data\script\brains,data\script\components目录下。

StateGraph

看这个名字我猜测这个部分应该是处理状态机的吧。二师兄的状态脚本为SGpig.lua。里面定义了一些状态如:funnyidle,death,frozen等。还可以参考data\script下的stategraph.lua文件。

Brain

几乎每个角色都有相应的这个脚本。这个brain对象就是对该角色behavior tree的一个封装。比如二师兄的pigbrain.lua文件。。我们从最上面的require部分可以得知,二师兄可以有这些behavior: wander, follow, runaway, panic, ChaseAndAttack, findlight等。那么我们至少可以得知,该游戏看来是将behavior tree这部分脚本化了,值得学习哟。

behavior方面的脚本主要就是data\script\behaviourtree.lua文件和data\script\behaviours整个目录了。前者定义了行为树类和它的各种五花八门的功能node,序列节点,条件节点,选择节点,优先级节点,并行节点,decorate节点等。后者是一些定义好的behavior。

Component

基于组件的entity系统。既然逻辑都脚本化了,组件模块肯定也要随之脚本化。一来提供开放接口在逻辑脚本中调用,二来方便策划扩展新的组件。

我们看到,二师兄是由这么些组件搭建成的:eater, combat, health, trader, sleeper等等。所有组件都在data\script\Component目录下,相当多,一共167个文件!想知道二师兄为什么战斗跑位这么风骚吗?战斗逻辑就在combat.lua这个组件里。

从该游戏身上,我们要认识到,一个好游戏不是凭空而来的,它的每个亮点都对应了开发人员背后的思考和汗水。仅仅从捞钱出发,把玩家当SB的中国式特色(极品装备,一刷就爆;我不断的寻找,油腻的师姐在哪里!)的开发套路是不可能做出真正的好游戏的!应用脚本系统,把角色怪物配置,状态逻辑,交互逻辑等XXXX逻辑相关的部分脚本化,我觉得在技术上不是特别特别难的事情(策划要给力。。),只要坚持下去做,一定能带来很多好处,让项目良性发展。

  • 配合工具,就像星际2的一站式银河编辑器一样,让策划能进行独立设计和扩展,解救客户端程序于无尽的琐碎小事中。
  • 我觉得将逻辑代码脚本化后,使得整个客户端的代码整洁性能大幅度提升,一定不能小瞧破窗户理论带来的危害。。逻辑这个脏乱差的模块统一在脚本里管理起来就好多了。我总感觉自己有很严重的代码洁癖。
  • 脚本化后,有了对外开放的API集,提供MOD功能也方便了。

转载于:https://www.cnblogs.com/mavaL/p/3279582.html

Don't Starve,好脚本,好欢乐相关推荐

  1. 欢乐球球脚本 python_Unity 欢乐球球

    //-1 自己控制球的弹跳力代码如下 -2) 在Project视图中给球添加Physical Materical 设置弹力以后 拉给球的Collider的Materical 属性) SphereCol ...

  2. 猫和老鼠欢乐互动辅助材料 游戏玩法脚本挂机技巧

    猫和老鼠欢乐互动是由动漫题材<猫和老鼠>为原型改编的一款休闲化2D富有情怀的手游.游戏中将经典场景重现,对人联网对战,猫和老鼠阵营供你选择,完成不一样的任务,开启一场欢乐之旅. 将上新的飞 ...

  3. IE安全系列:脚本先锋(4)

    脚本先锋系列第四章,也是最后一章.将介绍对Shellcode的调试,以及SWF.PDF漏洞的利用文件的简单处理过程. \\ 下一部分预告: \\ IE安全系列:中流砥柱(I) - JScript 5 ...

  4. 怀旧服野外pvp最多的服务器,魔兽怀旧服:最想要去的服务器,野外PVP很“传统”,很欢乐!...

    游戏中我们是朋友,聊天侃地,在这里我们可以无拘无束地发言,不会有任何人阻挠,还有大家最喜欢喷的小编,请把口水收集好,随时准备和小编一起对喷! 魔兽怀旧服最想要去的服务器,野外PVP很"传统& ...

  5. 【微信小游戏实战】零基础制作《欢乐停车场》二、关卡设计

    1.游戏立项 微信小游戏中有一款<欢乐停车场Plus>的小游戏,大家可以搜索玩下.这是一款益智类的小游戏,游戏中有红.黄.绿.蓝.紫5辆豪车6个停车位,玩家通过可行走路线移动小车,最终让各 ...

  6. 3D 小游戏《欢乐贪吃龙》关键技术盘点 | Cocos 技术派第13期

    <欢乐贪吃龙>是由 SK2GAME 基于 Cocos Creator v2.2 研发的一款 3D 休闲小游戏,游戏画面卡通精美,玩法简单,玩家将扮演一只"贪吃龙",在 ...

  7. 天野商业脚本开发第三期培训

    易语言基础 1:关于易语言必须了解的基本知识 2:易语言核心支持库命令讲解之一 3:易语言核心支持库命令讲解之二 4:易语言常用组件讲解 5:易语言模块制作和DLL制作.易语言调试功能讲解 6:易语言 ...

  8. 2021年“春秋杯”新年欢乐赛--十二宫的挑衅

    前言 没怎么打,随便玩了一下.发现有一道十二宫杀手密码比较有趣.总结一下 题目说明 标题:十二宫的挑衅 题目文件:Twelve_palaces_of_serial_killers.png(翻译:十二宫 ...

  9. 《欢乐坦克大战》微信小游戏开发总结

    <欢乐坦克大战>微信小游戏开发总结 <欢乐坦克大战>微信小游戏开发总结 前言 <欢乐坦克大战>是一款支持3V3实时对战并首批参与上线的微信小游戏中的作品.因为该游戏 ...

  10. linux中登录远程主机,LinuxSSH登录远程主机并执行脚本

    两台Centos6.5 64位主机: N206 N203N206的export.sh,远程执行N203主机上/root/share.sh脚本#!/bin/bash source ~/.bash_pro ...

最新文章

  1. Java-学习笔记-6-继承
  2. 安卓手机充电慢_3.0适用苹果安卓手机充电器头
  3. mxnet 常用层,卷积激活损失
  4. linux把目录下的文件设置属性为rx,LINUX的文件属性与目录配置
  5. java继承中的 equals + hashCode+toString
  6. Storm记录02-- Storm是什么
  7. 数字城市杭州执法管理平台测试计划【软件测试与工程】
  8. java界面编程 pdf_java – PDF页面使用itext重新排序
  9. OpenCV编译时提示错误“ Built target libprotobuf”
  10. yyyy-MM-dd HH:mm:ss和yyyy-MM-dd hh:mm:ss的区别
  11. arduino i2c EEPROM(AT24C02、AT24C08、AT24C16、AT24C32、AT24C64)驱动
  12. word流程图两条线的端点连接_word流程图连接线怎么用
  13. 学生信息管理系统(数据库)
  14. 小白ARM平台移植 USB 蓝牙、交叉编译 bluez-4.95
  15. 创建parquet类型的hive外表
  16. C#asp.net旅游网站系统
  17. 记一次网络风暴/网络环路
  18. 转战pytorch(3)——跟上脚步(以Albert为例)
  19. springboot引入rabbit mq
  20. 高速铁路GNSS位移变形监测预警系统解决方案

热门文章

  1. 12.利用API抓取数据
  2. MySQL 5.7新特性:并行复制原理(MTS)
  3. 3. mysql-视图
  4. ROS2学习笔记(四)-- 用方向键控制小车行走
  5. ONLYOFFICE权限开发之二
  6. dnsmasq-ipv6测试
  7. Eclipse插件(RCP)自定义编辑器添加Dirty效果
  8. 自动化运维---playbook(应用变量)
  9. 废弃的Android手机用起来,就是一台小型服务器!
  10. 成功项目经理的能力提升