设计一个和饥荒的cookpot类似的烹煮锅
作为一个建筑应该有配方、建造时的动画等
作为一个烹煮锅额外有烹煮动画,有容器,容器背景图,有烹煮按钮,(由于饥荒的cookpot容量是4格的,那我这里做一个3格的)
有自己的几套料理配方,烹煮成功后,产品直接给到容器里,需要玩家打开拿取(这里就没有做烹煮成功,料理摆在锅子上的动画)
1require "prefabutil"
2local assets =
3{
4 Asset("ANIM", "anim/sollypot.zip"),
5 Asset("ANIM", "anim/ui_sollypot_1x3.zip"),
6 Asset("ATLAS", "images/inventoryimages/sollypot.xml")
7}
8local function onhammered(inst, worker) --被锤子锤爆时的function (可以直接照搬)
9 --如果有可燃烧组件并且在燃烧则执行灭火
10 if inst.components.burnable ~= nil and inst.components.burnable:IsBurning() then
11 inst.components.burnable:Extinguish()
12 end
13 --锤爆掉落物品
14 inst.components.lootdropper:DropLoot()
15 if inst.components.container ~= nil then
16 inst.components.container:DropEverything()
17 end
18 local fx = SpawnPrefab("collapse_small")
19 fx.Transform:SetPosition(inst.Transform:GetWorldPosition())
20 fx:SetMaterial("wood")
21 inst:Remove()
22end
23
24local function onhit(inst, worker) --被锤子锤时的fn (可以直接照搬)
25 if not inst:HasTag("burnt") then
26 inst.AnimState:PlayAnimation("hit_idle_loop")
27 inst.AnimState:PushAnimation("idle", false)
28 if inst.components.container ~= nil then
29 inst.components.container:DropEverything()
30 inst.components.container:Close()
31 end
32 end
33end
34
35local function onbuilt(inst) --建造时的fn(可以直接照搬)
36 inst.AnimState:PlayAnimation("place_camppot") --播放建造动画
37 inst.AnimState:PushAnimation("idle", true) --完成时播放idle
38 inst.SoundEmitter:PlaySound("dontstarve/common/cook_pot_craft")
39end
40
41local function onopen(inst) --开盖子的fn(可以直接照搬)
42 if not inst:HasTag("burnt") then
43 inst.AnimState:PlayAnimation("open",false)
44 local container = inst.components.container
45 for i = 1, container:GetNumSlots() do
46 local item = container:GetItemInSlot(i)
47 if item and item.components.perishable then
48 item.components.perishable.localPerishMultiplyer = 1 --腐烂速度乘数
49 end
50 end
51 inst.SoundEmitter:KillSound("snd")
52 inst.SoundEmitter:PlaySound("dontstarve/common/cookingpot_open")
53 inst.SoundEmitter:PlaySound("dontstarve/common/cookingpot", "snd")
54 end
55end
56
57local function onclose(inst) --关盖子的fn(照搬即可)
58 if not inst:HasTag("burnt") then
59 inst.AnimState:PlayAnimation("close",false)
60 local container = inst.components.container
61 for i = 1, container:GetNumSlots() do
62 local item = container:GetItemInSlot(i)
63 if item and item.components.perishable then
64 item.components.perishable.localPerishMultiplyer = 1
65 end
66 end
67 inst.SoundEmitter:KillSound("snd")
68 inst.SoundEmitter:PlaySound("dontstarve/common/cookingpot_close")
69 end
70end
71
72local function onsave(inst, data)
73 if inst:HasTag("burnt") or (inst.components.burnable ~= nil and inst.components.burnable:IsBurning()) then
74 data.burnt = true
75 end
76end
77
78local function onload(inst, data)
79 if data ~= nil and data.burnt then
80 inst.components.burnable.onburnt(inst)
81 end
82end
83
84local function fn()
85 local inst = CreateEntity()
86
87 inst.entity:AddTransform()
88 inst.entity:AddAnimState()
89 inst.entity:AddSoundEmitter()
90 --inst.entity:AddMiniMapEntity()
91 inst.entity:AddLight()
92 inst.entity:AddNetwork()
93
94 --inst.MiniMapEntity:SetIcon(name..".png")
95
96 inst:AddTag("structure")
97
98 inst.AnimState:SetBank("sollypot")
99 inst.AnimState:SetBuild("sollypot")
100 inst.AnimState:PlayAnimation("idle")
101
102 MakeSnowCoveredPristine(inst)
103
104 inst.entity:SetPristine()
105
106 inst.Light:Enable(false) --添加光照,默认false
107 inst.Light:SetRadius(.6)
108 inst.Light:SetFalloff(1)
109 inst.Light:SetIntensity(.5)
110 inst.Light:SetColour(235/255,62/255,12/255)
111
112 if not TheWorld.ismastersim then
113 return inst
114 end
115
116 inst:AddComponent("inspectable")
117
118 inst:AddComponent("talker")
119
120 inst:AddComponent("lootdropper")
121 inst:AddComponent("workable")
122 inst.components.workable:SetWorkAction(ACTIONS.HAMMER)
123 inst.components.workable:SetWorkLeft(4)
124 inst.components.workable:SetOnFinishCallback(onhammered)
125 inst.components.workable:SetOnWorkCallback(onhit)
126
127 --MakeSmallBurnable(inst, nil, nil, true)
128 MakeMediumPropagator(inst)
129
130 inst:ListenForEvent("onbuilt", onbuilt)
131 MakeSnowCovered(inst)
132
133 --添加容器
134 inst:AddComponent("container")
135 inst.components.container.acceptsstacks = false --这里是容器内物品不可堆叠
136 local spconttab = {}
137 local containers = require("containers")
138 local old_widgetsetup = containers.widgetsetup
139 function containers.widgetsetup(container, prefab, data)
140 local t = data or spconttab[prefab or container.inst.prefab]
141 local pref = prefab or container.inst.prefab
142 if pref == "sollypot" then
143 local t = spconttab[pref]
144 if t ~= nil then
145 for k, v in pairs(t) do
146 container[k] = v
147 end
148 container:SetNumSlots(container.widget.slotpos ~= nil and #container.widget.slotpos or 0)
149 end
150 else
151 return old_widgetsetup(container, prefab)
152 end
153 end
154 local pt = Vector3(inst.Transform:GetWorldPosition()) --我们获取一下锅子的位置,以便后续设置容器的相对位置,注意要用Vector3
155 spconttab.sollypot =
156 {
157 widget =
158 {
159 slotpos = {
160 Vector3(pt.x, pt.y-5+79, pt.z+30),
161 Vector3(pt.x, pt.y-5, pt.z+30),
162 Vector3(pt.x, pt.y-5-79, pt.z+30),
163 },
164 animbank = "ui_sollypot_1x3",
165 animbuild = "ui_sollypot_1x3",
166 pos = Vector3(pt.x+60, pt.y+150, pt.z+30), --这里是刚才获取到pt位置做一个偏移,以便容器显示在锅子的右上方
167 side_align_tip = 100,
168 },
169 type = "sollypot",
170 }
171
172 for k, v in pairs(spconttab) do
173 containers.MAXITEMSLOTS = math.max(containers.MAXITEMSLOTS, v.widget.slotpos ~= nil and #v.widget.slotpos or 0)
174 end
175 inst.components.container:WidgetSetup("sollypot")
176 inst.components.container.onopenfn = onopen
177 inst.components.container.onclosefn = onclose
178
179 inst.OnSave = onsave
180 inst.OnLoad = onload
181
182 return inst
183end
184
185return Prefab("common/objects/sollypot", fn, assets),
186MakePlacer("common/sollypot_placer", "sollypot", "sollypot", "idle")
以上一个简单的建筑类预制物就写好了(照搬即可)
下面我们要添加一个烹煮按钮,我们想要它能实现:能正确判断食谱,经过一段时间烹煮给出对应的产品
--添加烹煮按钮
local widgetbuttoninfo = {
text = "boil", --按钮上的文字
position = Vector3(pt.x, pt.y-5-79-59, pt.z+30), --按钮位置
fn = function(inst)
--这里是按钮功能部分[1]
end }
inst.components.container.widget.buttoninfo = widgetbuttoninfo
--这里我们写了一个带有烹煮时间boiltime和产品productname参数的为按钮服务的功能函数boilbuttonpress()[2]
1local function boilbuttonpress(inst,boiltime,productname)
2 inst.Light:Enable(true) --烹煮按钮成功按下时会启用光照
3 inst.components.container:Close() --自动关闭容器
4 inst.AnimState:PlayAnimation("cooking_boil_small",true) --播放烹煮动画
5 inst.components.container:DestroyContents() --删除容器内的食材
6 inst.components.container.canbeopened = false --使烹煮过程中容器无法打开
7 inst.SoundEmitter:KillSound("snd") --这里注意先kill声音snd,再播放声音snd,就不会出现可能出现的音效叠加问题
8 inst.SoundEmitter:PlaySound("dontstarve/common/cookingpot_rattle", "snd")
9
10 inst.boiltimetask = inst:DoTaskInTime(boiltime, function() --这里用了一个DoTaskInTime,在烹煮时间到了后执行函数
11 inst.Light:Enable(false) --烹煮完成 关闭光照
12 inst.components.container.canbeopened = true --容器可被正常打开
13 inst.AnimState:PlayAnimation("steam",false) --播放完成动画
14 inst.AnimState:PushAnimation("idle", false)
15 inst.SoundEmitter:KillSound("snd")
16 inst.SoundEmitter:PlaySound("dontstarve/common/cookingpot_finish")
17 inst.components.container:GiveItem(SpawnPrefab(productname)) --给容器烹煮的产品
18 inst.boiltimetask = nil
19 end)
20end
下面我们看按钮功能部分[1],由于容器只有3个格子,我们直接去写个if判断一下容器内物品是不是对应的食材即可
1local icc = inst.components.container --这里一定要先local一下
2--例:食谱a 1个怪兽肉+1个大肉+1个大蒜 40秒= 怪味肉饼monstermeatloaf
3if (icc:Has("monstermeat",1) or icc:Has("monstermeat_cooked",1)) and (icc:Has("meat",1) or icc:Has("meat_cooked",1)) and (icc:Has("garlic",1) or icc:Has("garlic_cooked",1)) then
4 boilbuttonpress(inst,40,"monstermeatloaf")
5end
6--例:食谱b 2个便便+1个草 3秒= aoligei
7if icc:Has("poop",2) and icc:Has("cutgrass",1) then
8 boilbuttonpress(inst,3,"aoligei")
9end
制作完毕我发现了一个问题:
当烹煮过程中,我们退出了游戏再进时,锅子里的食材没了,同时因为烹煮没有完成所以得不到产品
解决这一问题的方法应该不少,我这里想的办法是:如果烹煮时退了游戏再进,直接返还3个原材料到容器内,一劳永逸:
先给boilbuttonpress()[2]里开头加几句:
local itm_a = inst.components.container.slots[1]
local itm_b = inst.components.container.slots[2]
local itm_c = inst.components.container.slots[3]
inst.desinv_a = itm_a.prefab
inst.desinv_b = itm_b.prefab
inst.desinv_c = itm_c.prefab
以上几句实现 先获取容器内物品再存起来
然后我们再写一下save和load:
1local function onsave(inst, data)
2 if inst:HasTag("burnt") or (inst.components.burnable ~= nil and inst.components.burnable:IsBurning()) then
3 data.burnt = true
4 end
5 if inst.boiltimetask ~= nil then --当inst.boiltimetask不是无效值,也就是在烹煮过程中退出了游戏
6 data.boiltask = true
7 data.desinv_a = inst.desinv_a
8 data.desinv_b = inst.desinv_b
9 data.desinv_c = inst.desinv_c
10 else
11 data.boiltask = false
12 end
13end
14
15local function onload(inst, data)
16 if data ~= nil and data.burnt then
17 inst.components.burnable.onburnt(inst)
18 end
19 if data ~= nil and data.boiltask then
20 inst.Light:Enable(false)
21 inst.components.container:GiveItem(SpawnPrefab(data.desinv_a))
22 inst.components.container:GiveItem(SpawnPrefab(data.desinv_b))
23 inst.components.container:GiveItem(SpawnPrefab(data.desinv_c))
24 end
25end
问题解决
~以上