Jump to content

Recommended Posts

I'm trying to make a creature which for now should eat stuff on the ground.

 

It finds food and walks up to it, but it seemingly never enters the "eat" state, as the animation doesn't play and the food still is on the ground.

 

I've tried to look at several other 'eater' creatures, but I cannot figure out what I seem to have missed.

 

 

In the prefab, I've set the

inst:AddComponent("eater")inst.components.eater:SetOmnivore()inst:AddComponent("inventory")

although I'm not certain how the inventory is needed or how it works specifically for my creature? If you know, please share your wisdom! :grin:

 

 

Here is the brain

require "behaviours/wander"require "behaviours/runaway"require "behaviours/doaction"require "behaviours/panic"local AVOID_PLAYER_DIST = 3local AVOID_PLAYER_STOP = 5local SEE_FOOD_DIST = 50local foxpie_brain = Class(Brain, function(self, inst)    Brain._ctor(self, inst)end)--local function EatFoodAction(inst)    local target = nil    if inst.components.inventory and inst.components.eater then        target = inst.components.inventory:FindItem(function(item) return inst.components.eater:CanEat(item) end)    end    if not target then        target = FindEntity(inst, SEE_FOOD_DIST, function(item) return inst.components.eater:CanEat(item) end)        if target then            --check for scary things near the food            local predator = GetClosestInstWithTag("scarytoprey", target, 1)            if predator then target = nil end        end    end        if target then        local act = BufferedAction(inst, target, ACTIONS.EAT)        --act.validfn = function() return not (target.components.inventoryitem and target.components.inventoryitem.owner and target.components.inventoryitem.owner ~= inst) end        --act.distance = 0.5        return act    end    end-------------------------------function foxpie_brain:OnStart()    local root = PriorityNode(    {        WhileNode( function() return self.inst.components.health.takingfiredamage end, "OnFire", Panic(self.inst)),        RunAway(self.inst, "scarytoprey", AVOID_PLAYER_DIST, AVOID_PLAYER_STOP),        DoAction(self.inst, EatFoodAction),        StandStill(self.inst, function() return true end),    }, .25)        self.bt = BT(self.inst, root)    endreturn foxpie_brain

and here is the SG

require("stategraphs/commonstates")local actionhandlers = {    ActionHandler(ACTIONS.EAT, "eat"),}local events={    CommonHandlers.OnStep(),    --CommonHandlers.OnSleep(),    CommonHandlers.OnFreeze(),    EventHandler("attacked", function(inst) if inst.components.health:GetPercent() > 0 and not inst.sg:HasStateTag("transform") then inst.sg:GoToState("hit") end end),    EventHandler("locomote",         function(inst)           if inst.components.health:GetPercent() > 0 then              if inst.components.locomotor:WantsToMoveForward() then                  if not inst.sg:HasStateTag("moving") then                      inst.sg:GoToState("run")                  end              else                  if not inst.sg:HasStateTag("idle") then                      inst.sg:GoToState("idle")                  end              end            end        end),      EventHandler("death", function(inst) inst.sg:GoToState("death") end),    --EventHandler("doattack", function(inst) if inst.components.health:GetPercent() > 0 and not inst.sg:HasStateTag("transform") then inst.sg:GoToState("attack") end end),}local states={    State{        name = "idle",        tags = {"idle", "canrotate"},                onenter = function(inst, playanim)          inst.Physics:Stop()            if playanim then                inst.AnimState:PlayAnimation(playanim)                inst.AnimState:PushAnimation("idle", true)            else                inst.AnimState:PlayAnimation("idle", true)            end            end,    },    State{        name = "run",        tags = {"canrotate", "moving", "running" },        onenter = function(inst)          inst.Physics:Stop()          inst.components.locomotor:RunForward()            inst.AnimState:PlayAnimation("run", true)          end,    },         State{        name = "death",        tags = {"busy"},                onenter = function(inst)            --inst.SoundEmitter:PlaySound("dontstarve/creatures/perd/hurt")            inst.components.locomotor:StopMoving()            inst.AnimState:PlayAnimation("death")            inst.Physics:Stop()            RemovePhysicsColliders(inst)            inst.components.lootdropper:DropLoot(Vector3(inst.Transform:GetWorldPosition()))        end,            },        State{        name = "hit",        tags = {"busy"},                onenter = function(inst)            --inst.SoundEmitter:PlaySound("dontstarve/creatures/perd/hurt")            inst.AnimState:PlayAnimation("hit")            inst.Physics:Stop()        end,                events=        {            EventHandler("animover", function(inst) inst.sg:GoToState("idle") end ),        },            },        State{        name = "eat",                tags = {"busy"},                onenter = function(inst)            inst.Physics:Stop()              inst.AnimState:PlayAnimation("eat")                  end,                timeline=        {            TimeEvent(10*FRAMES, function(inst) inst:PerformBufferedAction()            end),        },                events=        {            EventHandler("animover", function(inst) inst.sg:GoToState("idle") end ),        },            },}CommonStates.AddFrozenStates(states)return StateGraph("foxpie", states, events, "idle", actionhandlers)

Thanks for your time ^v^

Hm, Do you know if it's entering the "eat" state or not?

It should preform the "eat" action, even if the animation doesn't play.

Try putting a print function in the "onenter" funtion of the eat state and see if it prints when it walks over to the food.

Oh. Yeah it enters the state and prints. Hm.

 

But even if there is a problem with the animation, the food should still disappear, right?

 

Yea, if it's still entering the state and not eating the food, then something is off.

 

Maybe it's just freezing before anything happens? I've been getting that since the new update. Sometimes stategraph errors will cause freezes instead of crashing the game with an error log.

 

Try also putting print functions between the eat action. Rearange the time event so it looks like this:

TimeEvent(10*FRAMES, function(inst) print("PRINT1")inst:PerformBufferedAction()print("PRINT2")end),

If print1 shows up and not print2, then something is going wrong with the buffered action (which is supposed to be where it eats the food).

 

If neither of them show up, then something is happening before it can even get to the part of the state where it eats

 

or wait, does he have an animation? Maybe it thinks the animation is done and is sending it to idle too early. You can try commenting out that EventHandler and see if that solves anything too.

Yea, if it's still entering the state and not eating the food, then something is off.

 

Maybe it's just freezing before anything happens? I've been getting that since the new update. Sometimes stategraph errors will cause freezes instead of crashing the game with an error log.

 

Try also putting print functions between the eat action. Rearange the time event so it looks like this:

TimeEvent(10*FRAMES, function(inst) print("PRINT1")inst:PerformBufferedAction()print("PRINT2")end),

If print1 shows up and not print2, then something is going wrong with the buffered action (which is supposed to be where it eats the food).

 

If neither of them show up, then something is happening before it can even get to the part of the state where it eats

 

or wait, does he have an animation? Maybe it thinks the animation is done and is sending it to idle too early. You can try commenting out that EventHandler and see if that solves anything too.

 

I tried to do both, and neither worked.

 

However, I tried to exchange my eating animation with the death animation (since I knew that one was working) and suddenly everything works.

 

Thanks a lot for your help though! ^^

I feel pretty silly for not having tried this, but I didn't think the animation mattered to this extent... I mean, I didn't get any messages anywhere for this. Hmm ah well!

 

Thanks again!

Edited by Zwynx

Actually, never mind, it doesn't work.

 

It works if the TimeEvent(10*FRAMES is TimeEvent(0*FRAMES and it doesn't play the animation regardless of what animation I use, even if it's a working one. But if is not a working one, it doesn't work even if I use TimeEvent(0*FRAMES.

 

If it's activated at 0 frames, the prints works and the food disappears though.

 

Also, my creature enters the idle state directly, whether I have Eventhandler section commented out or not.

Edited by Zwynx

The brain and SG is still pretty much the same since the original post, give or take some parts for testing. Here is the prefab too, in case it will shed some light on something I have missed.

local assets={    Asset("ANIM", "anim/foxpie.zip"),}local prefabs ={	"drumstick",	"smallmeat",	"feather_crow",}SetSharedLootTable( "foxpie",{    {'drumstick',            1.00},    {'drumstick',            1.00},    {'smallmeat',            0.50},    {'smallmeat',            0.30},    {'feather_crow',     0.30},    {'feather_crow',     0.10},})local function init_prefab()    local inst = CreateEntity()    local trans = inst.entity:AddTransform()    local anim = inst.entity:AddAnimState()    local physics = inst.entity:AddPhysics()    local shadow = inst.entity:AddDynamicShadow()    shadow:SetSize( 1, .75 )    inst.Transform:SetFourFaced()      anim:SetBank("foxpie")    anim:SetBuild("foxpie")        inst:AddComponent("locomotor")    inst.components.locomotor.runspeed = 2    --mass , radius    MakeCharacterPhysics(inst, 5, .5)    inst:SetStateGraph("SGfoxpie")    local brain = require "brains/foxpie_brain"    inst:SetBrain(brain)        inst:AddComponent("eater")    inst.components.eater:SetOmnivore()    --inst.components.eater:SetCarnivore()    --inst.components.eater:SetCanEatHorrible()    --inst.components.eater.strongstomach = true -- can eat monster meat!        inst:AddTag("character")    inst:AddComponent("inspectable")    --inst:AddTag("scarytoprey")        inst:AddComponent("health")    inst.components.health:SetMaxHealth(50)        inst:AddComponent("combat")    inst.components.combat.hiteffectsymbol = "pig_torso"    inst.components.combat:SetDefaultDamage(10)    inst.components.combat:SetAttackPeriod(10)        inst:AddComponent("lootdropper")    inst.components.lootdropper:SetChanceLootTable("foxpie")     inst:AddComponent("inventory")                MakeMediumBurnableCharacter(inst, "pig_torso")    MakeMediumFreezableCharacter(inst, "pig_torso")    return instendreturn Prefab( "monsters/foxpie", init_prefab, assets, prefabs)

Actually, never mind, it doesn't work.

 

It works if the TimeEvent(10*FRAMES is TimeEvent(0*FRAMES and it doesn't play the animation regardless of what animation I use, even if it's a working one. But if is not a working one, it doesn't work even if I use TimeEvent(0*FRAMES.

 

If it's activated at 0 frames, the prints works and the food disappears though.

 

Also, my creature enters the idle state directly, whether I have Eventhandler section commented out or not.

 

 

Hmm.

Wait, I thought TimeEvent 0 frames didn't work? Or do they actually work? I thought it would be the same as just using an OnEnter function. 

 

The time events really should be working if the EventHandler is commented out. TimeEvents happen regardless of what the animation does, unless it changes states before the designated time. I know this for a fact because smashup would have been way easier to program if TimeEvents worked that way.

Since it has the "busy" tag, it shouldn't be able to change states without an event handler forces it to.

 

I could see it being a problem using a broken animation if the event-handler thinks it's over and sends it to idle, but if it's commented out, then that should not be happening.

 

So when you say it directly enter the idle state, you mean it goes to it immediatley after the state starts?

is there a print event in Idle state confirming it goes straight to idle after entering the eat state?

 

This probably won't solve much but I'm just curious, is it any different if you put it in a TimeEvent 1 frame?

Hmm.

Wait, I thought TimeEvent 0 frames didn't work? Or do they actually work? I thought it would be the same as just using an OnEnter function. 

 

The time events really should be working if the EventHandler is commented out. TimeEvents happen regardless of what the animation does, unless it changes states before the designated time. I know this for a fact because smashup would have been way easier to program if TimeEvents worked that way.

Since it has the "busy" tag, it shouldn't be able to change states without an event handler forces it to.

 

I could see it being a problem using a broken animation if the event-handler thinks it's over and sends it to idle, but if it's commented out, then that should not be happening.

 

So when you say it directly enter the idle state, you mean it goes to it immediatley after the state starts?

is there a print event in Idle state confirming it goes straight to idle after entering the eat state?

 

This probably won't solve much but I'm just curious, is it any different if you put it in a TimeEvent 1 frame?

 

When the eventhandler is commented out and timeevent frame is set to 1 three different scenarios seem to happen;

The creature walks up to the food, then it enters eating and then idle again. All of this happens instantly. The food is still there and the creature is just sitting idle. This seems to only happen for the first food the creature ever encounters, I can't seem to provoke this behavior again even after numerous tries.

 

When I spawn new food (beyond the first):

It walks up to the food and loops the idle and eating states. I guess the food is in range for triggering the eating, but also so far away to trigger the searching for food? The food is still there, of course.

 

When I scare away the creature and it returns to the same food:

It walks up to the food and enters idle when arriving at the food. No eating, and the food is still there.

 

I will do more complete testing later, as well as testing for when the frame is 0 instead.

When the eventhandler is commented out and timeevent frame is set to 1 three different scenarios seem to happen;

The creature walks up to the food, then it enters eating and then idle again. All of this happens instantly. The food is still there and the creature is just sitting idle. This seems to only happen for the first food the creature ever encounters, I can't seem to provoke this behavior again even after numerous tries.

 

When I spawn new food (beyond the first):

It walks up to the food and loops the idle and eating states. I guess the food is in range for triggering the eating, but also so far away to trigger the searching for food? The food is still there, of course.

 

When I scare away the creature and it returns to the same food:

It walks up to the food and enters idle when arriving at the food. No eating, and the food is still there.

 

I will do more complete testing later, as well as testing for when the frame is 0 instead.

 

hmmm.. is it maybe just getting an error that immediately sends it back to idle?

I was working with a lot of stategraphs yesterday and at some point I actually had that happen to me. I had an error that, instead of crashing or freezing, seemed to send it right back to idle.

Now is sort of a weird time to be new to modding with all these strange error handling bugs (or changes?) that have been made lately, and I've been struggling with troubleshooting myself, since the source of errors are now really hard to find. I've just been throwing print functions before and after basically every line of code to see where stuff stops printing.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
  • Create New...