Jump to content

Stategraphs, brains and animations problem: trying to create a creature


Recommended Posts

I'm trying to create a creature who simply follow the player but there's some problems (of course!)

 

problem 1. walking animation doesn't work...

 

here's names I used on spriter

 

idle_down (idle animation works)

idle_up

idle_side

 

walk_pre_down

walk_pre_up

walk_pre_side

 

walk_loop_down

walk_loop_up

walk_loop_side

 

and the SG

 

 

require("stategraphs/commonstates")

local states=
{

    State{

        name = "idle",

        tags = {"idle", "canrotate"},

        onenter = function(inst, playanim)

            inst.AnimState:PlayAnimation("idle", true)
        end,

    },

    State{

        name = "walk",

        tags = {"walk", "canrotate", "moving" },

        onenter = function(inst, playanim)

            inst.AnimState:PlayAnimation("walk", true)

            inst.components.locomotor:WalkForward()            
        end,
    },

}

local event_handlers=
{

    EventHandler("locomote",
        function(inst)

            if inst.components.locomotor:WantsToMoveForward() then

            else

                if not inst.sg:HasStateTag("idle") then

                    inst.sg:GoToState("idle")
                end
            end
        end),
}

return StateGraph("headbanger", states, event_handlers, "idle", {})

 

 

problem n.2

 

Tried to add  "follower" component, but the creature simply turns in the direction the player is, doesn't follow.

here's the brain

 

 

require "behaviours/follow"
require "behaviours/wander"
require "behaviours/faceentity"


local MIN_FOLLOW_DIST = 0
local MAX_FOLLOW_DIST = 12
local TARGET_FOLLOW_DIST = 6

local MAX_WANDER_DIST = 3


local function GetFaceTargetFn(inst)
    return inst.components.follower.leader
end

local function KeepFaceTargetFn(inst, target)
    return inst.components.follower.leader == target
end


local HeadBangerBrain = Class(Brain, function(self, inst)
    Brain._ctor(self, inst)
end)


function HeadBangerBrain:OnStart()
    local root =
    PriorityNode({
        --WhileNode( function() return self.inst.components.health.takingfiredamage end, "OnFire", Panic(self.inst)),
        Follow(self.inst, function() return self.inst.components.follower.leader end, MIN_FOLLOW_DIST, TARGET_FOLLOW_DIST, MAX_FOLLOW_DIST),
        FaceEntity(self.inst, GetFaceTargetFn, KeepFaceTargetFn),
        --Wander(self.inst, function() return self.inst.components.knownlocations:GetLocation("home") end, MAX_WANDER_DIST),
        
    }, .25)
    self.bt = BT(self.inst, root)
end

return HeadBangerBrain

 

 

 

It's the first time I'm creating a creature from 0... What am I doing wrong?

Link to comment
Share on other sites

I'm trying to create a creature who simply follow the player but there's some problems (of course!)

 

problem 1. walking animation doesn't work...

 

here's names I used on spriter

 

idle_down (idle animation works)

idle_up

idle_side

 

walk_pre_down

walk_pre_up

walk_pre_side

 

walk_loop_down

walk_loop_up

walk_loop_side

 

and the SG

 

 

require("stategraphs/commonstates")

local states=

{

    State{

        name = "idle",

        tags = {"idle", "canrotate"},

        onenter = function(inst, playanim)

            inst.AnimState:PlayAnimation("idle", true)

        end,

    },

    State{

        name = "walk",

        tags = {"walk", "canrotate", "moving" },

        onenter = function(inst, playanim)

            inst.AnimState:PlayAnimation("walk", true)

            inst.components.locomotor:WalkForward()            

        end,

    },

}

local event_handlers=

{

    EventHandler("locomote",

        function(inst)

            if inst.components.locomotor:WantsToMoveForward() then

            else

                if not inst.sg:HasStateTag("idle") then

                    inst.sg:GoToState("idle")

                end

            end

        end),

}

return StateGraph("headbanger", states, event_handlers, "idle", {})

 

 

problem n.2

 

Tried to add  "follower" component, but the creature simply turns in the direction the player is, doesn't follow.

here's the brain

 

 

require "behaviours/follow"

require "behaviours/wander"

require "behaviours/faceentity"

local MIN_FOLLOW_DIST = 0

local MAX_FOLLOW_DIST = 12

local TARGET_FOLLOW_DIST = 6

local MAX_WANDER_DIST = 3

local function GetFaceTargetFn(inst)

    return inst.components.follower.leader

end

local function KeepFaceTargetFn(inst, target)

    return inst.components.follower.leader == target

end

local HeadBangerBrain = Class(Brain, function(self, inst)

    Brain._ctor(self, inst)

end)

function HeadBangerBrain:OnStart()

    local root =

    PriorityNode({

        --WhileNode( function() return self.inst.components.health.takingfiredamage end, "OnFire", Panic(self.inst)),

        Follow(self.inst, function() return self.inst.components.follower.leader end, MIN_FOLLOW_DIST, TARGET_FOLLOW_DIST, MAX_FOLLOW_DIST),

        FaceEntity(self.inst, GetFaceTargetFn, KeepFaceTargetFn),

        --Wander(self.inst, function() return self.inst.components.knownlocations:GetLocation("home") end, MAX_WANDER_DIST),

        

    }, .25)

    self.bt = BT(self.inst, root)

end

return HeadBangerBrain

 

 

 

It's the first time I'm creating a creature from 0... What am I doing wrong?

 

Well, for the walk animations, I think you need:

 

walk

walk_pre

walk_loop

walk_post

 

Then amend "_direction" to those, for each direction you use.

 

For the follow component, are you setting the player as the leader in its prefab?

Link to comment
Share on other sites

Well, for the walk animations, I think you need:

 

walk

walk_pre

walk_loop

walk_post

 

Then amend "_direction" to those, for each direction you use.

 

For the follow component, are you setting the player as the leader in its prefab?

 

I tried

 

inst:AddComponent("follower")

    inst.components.follower.leader = GetPlayer()

 

and

    GetPlayer().components.leader:AddFollower(inst)

 

but the creature just looks at me..

 

so I THINK the problem is in the brain :/

Link to comment
Share on other sites

I tried

 

inst:AddComponent("follower")

    inst.components.follower.leader = GetPlayer()

 

and

    GetPlayer().components.leader:AddFollower(inst)

 

but the creature just looks at me..

 

so I THINK the problem is in the brain :/

 

Okay, so for the follower line in the brain, try this:

Follow(self.inst, function() return self.inst.components.follower and self.inst.components.follower.leader end, MIN_FOLLOW_DIST, TARGET_FOLLOW_DIST, MAX_FOLLOW_DIST),
Link to comment
Share on other sites

 

Okay, so for the follower line in the brain, try this:

Follow(self.inst, function() return self.inst.components.follower and self.inst.components.follower.leader end, MIN_FOLLOW_DIST, TARGET_FOLLOW_DIST, MAX_FOLLOW_DIST),

 

Nothing, it keeps looking..

 

Maybe I wrote something wrong in the prefab.lua?

 

local function fn()

    local inst = CreateEntity()

    local trans = inst.entity:AddTransform()

    local anim = inst.entity:AddAnimState()

    

    anim:SetBank("headbanger")

    anim:SetBuild("headbanger")

    

    inst.Transform:SetFourFaced()

    inst.Transform:SetScale(0.8, 0.8, 0.8)

    

    MakeCharacterPhysics(inst, 10, .5)

    inst:SetStateGraph("SGheadbanger")

    

        inst:AddComponent("locomotor")

        inst.components.locomotor.walkspeed = 7

        inst.components.locomotor.runspeed = 7

        inst:AddComponent("follower")

        inst.components.follower.leader = GetPlayer()

        

    inst.components.follower.maxfollowtime = 99999999

    GetPlayer().components.leader:AddFollower(inst)

    inst.components.follower:AddLoyaltyTime(9999999)

    

    local brain = require "brains/headbanger_brain"

    inst:SetBrain(brain)

    inst.entity:AddSoundEmitter()

        

    return inst

end

Link to comment
Share on other sites

Nothing, it keeps looking..

 

Maybe I wrote something wrong in the prefab.lua?

 

local function fn()

    local inst = CreateEntity()

    local trans = inst.entity:AddTransform()

    local anim = inst.entity:AddAnimState()

    

    anim:SetBank("headbanger")

    anim:SetBuild("headbanger")

    

    inst.Transform:SetFourFaced()

    inst.Transform:SetScale(0.8, 0.8, 0.8)

    

    MakeCharacterPhysics(inst, 10, .5)

    inst:SetStateGraph("SGheadbanger")

    

        inst:AddComponent("locomotor")

        inst.components.locomotor.walkspeed = 7

        inst.components.locomotor.runspeed = 7

        inst:AddComponent("follower")

        inst.components.follower.leader = GetPlayer()

        

    inst.components.follower.maxfollowtime = 99999999

    GetPlayer().components.leader:AddFollower(inst)

    inst.components.follower:AddLoyaltyTime(9999999)

    

    local brain = require "brains/headbanger_brain"

    inst:SetBrain(brain)

    inst.entity:AddSoundEmitter()

        

    return inst

end

 

What prints if you add

print(inst.components.follower.leader)

to the prefab after you set the leader?

 

Link to comment
Share on other sites

Okay, so the entity is correctly identifying the player as its leader. Does the entity properly move around (at all)?

 

Yes, if I make it manually walk ( WalkInDirection ) it moves

 

and he turns in the direction the player is

Link to comment
Share on other sites

Nothing... :/ How annoying when those things happens

 

Yes, but a learning experience. :p

 

Try commenting out your current "walk" state, and add this separately from the states block:

CommonStates.AddWalkStates(states, {    walktimeline =    {        TimeEvent(1*FRAMES, function(inst)            inst.components.locomotor:RunForward()        end),        TimeEvent(14*FRAMES, function(inst)            PlayFootstep(inst)            inst.components.locomotor:WalkForward()        end),    }}, nil, true)

 

Link to comment
Share on other sites

 

Yes, but a learning experience. :razz:

 

Try commenting out your current "walk" state, and add this separately from the states block:

CommonStates.AddWalkStates(states, {    walktimeline =    {        TimeEvent(1*FRAMES, function(inst)            inst.components.locomotor:RunForward()        end),        TimeEvent(14*FRAMES, function(inst)            PlayFootstep(inst)            inst.components.locomotor:WalkForward()        end),    }}, nil, true)

 

Still nothing...

 

With all this learning experience we will level up soon xD

Link to comment
Share on other sites

 

Quite possibly.

 

So, add this event to your "idle" state:

events={        EventHandler("animover", function(inst) inst.sg:GoToState("idle") end),},

 

Ok I think I fixed it :D

 

I wrote

 

" inst.components.locomotor:WalkForward() "

 

here

 

 

local event_handlers=

{

    EventHandler("locomote",

        function(inst)

            if inst.components.locomotor:WantsToMoveForward() then

            inst.components.locomotor:WalkForward()

            else

                if not inst.sg:HasStateTag("idle") then

                    inst.sg:GoToState("idle")

                end

            end

        end),

}

 

 

The animations still doesn't play anyway mmh...

Link to comment
Share on other sites

 

Quite possibly.

 

So, add this event to your "idle" state:

events={        EventHandler("animover", function(inst) inst.sg:GoToState("idle") end),},

 

Thank you for your help :)

 

Mmmh... What could be wrong now, with animations?

I'm never 100% sure when using spriter >_<

Link to comment
Share on other sites

Thank you for your help :-)

 

Mmmh... What could be wrong now, with animations?

I'm never 100% sure when using spriter >_<

 

I'm not entirely sure. Check your log.txt and see if it's trying to call a non-existant animation or something similar.

 

Link to comment
Share on other sites

I'm pretty sure that instead of writing inst.components.locomotor.WalkForward(), you want to do this: inst.sg:GoToState("walk").  In your walk state you will also need to change the inst.AnimState:PlayAnimation("walk") to inst.AnimState:PlayAnimation("walk_loop").  Your stategraph doesn't have code for walk_pre and walk_post, however, so it won't look complete unless you add that.

Link to comment
Share on other sites

you were right, thanks.

But there's a strange bug: the creature start the animation (with walk_pre) only when it stops moving.

When moving it got stuck on idle animation...

 

Here's the current SG

 

--require("stategraphs/commonstates")

local events =
{
    --[[CommonHandlers.OnStep(),
    CommonHandlers.OnLocomote(false,true),
    EventHandler("animover", function(inst) inst.sg:GoToState("idle") end), ]]
    EventHandler("locomote", function(inst)
        
        local is_moving = inst.sg:HasStateTag("moving")

        local should_move = inst.components.locomotor:WantsToMoveForward()
        
        if is_moving then
            inst.sg:GoToState("walk_start")
        end
        
       --[[ if is_moving and not should_move then

                inst.sg:GoToState("walk_stop")
           
        elseif (not is_moving and should_move) or (is_moving and should_move) then
            
                inst.sg:GoToState("walk_start")
            
        end --]]
    end),
}

local states=
{

    State{

        name = "idle",

        tags = {"idle", "canrotate"},

        onenter = function(inst, playanim)

            inst.AnimState:PlayAnimation("idle", true)
        end,

    },

    State{
        name = "walk_start",
        tags = {"moving", "canrotate"},
        
        onenter = function(inst)
            inst.components.locomotor:WalkForward()
            inst.AnimState:PlayAnimation("walk_pre")
        end,

        events=
        {   
            EventHandler("animover", function(inst) inst.sg:GoToState("walk") end ),        
        },
    },
    
    State{

        name = "walk",

        tags = { "moving", "canrotate" },

        onenter = function(inst, playanim)

            inst.AnimState:PlayAnimation("walk_loop", true)
            inst.components.locomotor:WalkForward()            
        end,
    },

    State{
        name = "walk_stop",
        tags = {"canrotate"},
        
        onenter = function(inst)
            inst.Physics:Stop()
            inst.AnimState:PlayAnimation("walk_pst")
        end,
        
        events=
        {   
            EventHandler("animover", function(inst) inst.sg:GoToState("idle") end ),        
        },
    },
        
}

CommonStates.AddWalkStates(states, {
    walktimeline =
    {
        TimeEvent(1*FRAMES, function(inst)
            inst.components.locomotor:WalkForward()
        end),
        TimeEvent(14*FRAMES, function(inst)
            PlayFootstep(inst)
            inst.components.locomotor:WalkForward()
        end),
    }
}, nil, true)

local event_handlers=
{

    EventHandler("locomote",
        function(inst)

        if inst.components.locomotor:WantsToMoveForward() then
            inst.sg:GoToState("walk_start")
        else
            
            if not inst.sg:HasStateTag("idle") then
                inst.sg:GoToState("walk_stop")
              end
            end
        end),
}

return StateGraph("headbanger", states, event_handlers, "idle", {})

 

I modified it many many times but It gives always the same result

Link to comment
Share on other sites

You are trying to do two of the same thing at the same time. You cannot use the Commonstates unless you have all of the animations that are needed in that state. You are also trying to make it walk on your own, so you have Commonstates and your states fighting I think. Looking at the code, it is hard to tell what exactly the problem is. I will when I have more time, but it will be easier if you use EITHER Commonstates or your own states, and eliminate the other (I comment large chunks out until I know I won't need them).

 

Not to be shameless, but I recommend getting the grasshopper mod from my sig. It has custom walk states using my animations, stategraph, etc. The stategraph calls are a little convoluted as I tried everything to get them to hop properly. I can help you with any questions you have.

 

Disclaimer: This is all "as far as I know".

 

EDIT: Oh and I would stick with the animations you previously had with the up, down, and side prefixes if you have already made them.

Link to comment
Share on other sites

You are trying to do two of the same thing at the same time. You cannot use the Commonstates unless you have all of the animations that are needed in that state. You are also trying to make it walk on your own, so you have Commonstates and your states fighting I think. Looking at the code, it is hard to tell what exactly the problem is. I will when I have more time, but it will be easier if you use EITHER Commonstates or your own states, and eliminate the other (I comment large chunks out until I know I won't need them).

 

Not to be shameless, but I recommend getting the grasshopper mod from my sig. It has custom walk states using my animations, stategraph, etc. The stategraph calls are a little convoluted as I tried everything to get them to hop properly. I can help you with any questions you have.

 

Disclaimer: This is all "as far as I know".

 

EDIT: Oh and I would stick with the animations you previously had with the up, down, and side prefixes if you have already made them.

 

Uhm... I don't think I understand... Sorry what should I remove (for sure)?

 

EDIT: Ah ok... So I have to use commonstate OR my states (sorry I didn't sleep this night so I'm a bit slow xD) Ok...

But I already commented away the "require commonstates" and the animation stucks... I'm going to test some things (and look on your mod of course)

Link to comment
Share on other sites

Ok, I fixed it! Finally :grin:

 

here's how I did it:

 

 


local events =
{
    CommonHandlers.OnStep(),
    CommonHandlers.OnLocomote(false,true),
   
    EventHandler("animover", function(inst)
        
        local is_moving = inst.sg:HasStateTag("moving")
        local should_move = inst.components.locomotor:WantsToMoveForward()
        
    if is_moving and not should_move then
                
        inst.sg:GoToState("walk_stop")
           
   elseif (not is_moving and should_move) then
                inst.sg:GoToState("walk_start")
            
        end
    end),
  
}

local states=
{

    State{

        name = "idle",

        tags = {"idle", "canrotate"},

        onenter = function(inst, playanim)

            inst.AnimState:PlayAnimation("idle", true)
        end,

    },

    State{
        name = "walk_start",
        tags = {"moving", "canrotate"},
        
        onenter = function(inst)
            inst.AnimState:PlayAnimation("walk_pre")
            inst.components.locomotor:WalkForward()
        end,

        events=
        {   
            EventHandler("animover", function(inst) inst.sg:GoToState("walk") end ),        
        },
    },
    
    State{

        name = "walk",

        tags = {"walk", "canrotate", "moving", "nostop" },

        onenter = function(inst, playanim)

            inst.AnimState:PlayAnimation("walk_loop", true)
            inst.components.locomotor:WalkForward()            
        end,
    },

    State{
        name = "walk_stop",
        tags = {"canrotate"},
        
        onenter = function(inst)
            inst.Physics:Stop()
            inst.AnimState:PlayAnimation("walk_pst")
        end,
        
        events=
        {   
            EventHandler("animover", function(inst) inst.sg:GoToState("idle") end ),        
        },
    },
            
}
--[[
CommonStates.AddWalkStates(states, {
    walktimeline =
    {
        TimeEvent(1*FRAMES, function(inst)
            inst.components.locomotor:WalkForward()
            inst.sg:GoToState("walk_start")
        end),
        TimeEvent(14*FRAMES, function(inst)
            PlayFootstep(inst)
            inst.components.locomotor:WalkForward()
            inst.sg:GoToState("walk")
        end),
    }
}, nil, true)]]


return StateGraph("headbanger", states, events, "idle", {})

 

 

Finally! (now I should modify a bit the animations because there are horrible xD) But it wooorks :grin:

 

Thanks you everyone for the help

Link to comment
Share on other sites

Ok, I fixed it! Finally :grin:

 

here's how I did it:

 

 

local events =

{

    CommonHandlers.OnStep(),

    CommonHandlers.OnLocomote(false,true),

   

    EventHandler("animover", function(inst)

        

        local is_moving = inst.sg:HasStateTag("moving")

        local should_move = inst.components.locomotor:WantsToMoveForward()

        

    if is_moving and not should_move then

                

        inst.sg:GoToState("walk_stop")

           

   elseif (not is_moving and should_move) then

                inst.sg:GoToState("walk_start")

            

        end

    end),

  

}

local states=

{

    State{

        name = "idle",

        tags = {"idle", "canrotate"},

        onenter = function(inst, playanim)

            inst.AnimState:PlayAnimation("idle", true)

        end,

    },

    State{

        name = "walk_start",

        tags = {"moving", "canrotate"},

        

        onenter = function(inst)

            inst.AnimState:PlayAnimation("walk_pre")

            inst.components.locomotor:WalkForward()

        end,

        events=

        {   

            EventHandler("animover", function(inst) inst.sg:GoToState("walk") end ),        

        },

    },

    

    State{

        name = "walk",

        tags = {"walk", "canrotate", "moving", "nostop" },

        onenter = function(inst, playanim)

            inst.AnimState:PlayAnimation("walk_loop", true)

            inst.components.locomotor:WalkForward()            

        end,

    },

    State{

        name = "walk_stop",

        tags = {"canrotate"},

        

        onenter = function(inst)

            inst.Physics:Stop()

            inst.AnimState:PlayAnimation("walk_pst")

        end,

        

        events=

        {   

            EventHandler("animover", function(inst) inst.sg:GoToState("idle") end ),        

        },

    },

            

}

--[[

CommonStates.AddWalkStates(states, {

    walktimeline =

    {

        TimeEvent(1*FRAMES, function(inst)

            inst.components.locomotor:WalkForward()

            inst.sg:GoToState("walk_start")

        end),

        TimeEvent(14*FRAMES, function(inst)

            PlayFootstep(inst)

            inst.components.locomotor:WalkForward()

            inst.sg:GoToState("walk")

        end),

    }

}, nil, true)]]

return StateGraph("headbanger", states, events, "idle", {})

 

 

Finally! (now I should modify a bit the animations because there are horrible xD) But it wooorks :grin:

 

Thanks you everyone for the help

Glad to hear it

Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.

Please be aware that the content of this thread may be outdated and no longer applicable.

×
  • Create New...