Defranco Posted December 30, 2015 Share Posted December 30, 2015 Using a enemy AI script made by someone else - Heres part of the code that seems to be the issue for LE 4.0 function Script:EndHurt() if self.mode=="hurt" then if self.target.health<=0 then self:SetMode("idle") return end if self.health<=0 then self:EndDeath() return end if self.target.health<=0 then gets a NIL error when certain scenarios happen between GOOD/BAD Npcs killing each other. -- Attempt to index field "target" (A nil value) When I put 1 NPC of each Good and Bad to fight, its fine. As soon as I add 3 or more in a area - it gives the error. If i have separate battles far apart its fine. Quote Link to comment Share on other sites More sharing options...
Rick Posted December 30, 2015 Share Posted December 30, 2015 It's possible that NPC's are sharing a target and if one kills the target but the other doesn't then things could get messed up since the target probably get deleted? Before using the target variable check if it's nil or not. if self.target ~= nil then if self.target.health <= 0 then end end Quote Link to comment Share on other sites More sharing options...
Defranco Posted December 30, 2015 Author Share Posted December 30, 2015 okay I switched it and that specific problem went away - Now I'm getting a new error Unable to find "target" (a nil value) for this line ---- if self.entity:Follow(self.target.entity,self.speed,self.maxaccel) then Seems to have a chain effect - my first thought was to put in another target check Now I fixed it by adding if self.target~=nil then to almost 6 script sections in the entire AI code --- this fixed it. but that seems like a lot of checks... From the code below - function Script:SetMode(mode) if mode~=self.mode then math.randomseed(Time:GetCurrent()) if self.debugMode then System:Print("AI mode set to: " .. mode) end local prevmode=self.mode self.mode=mode if mode=="idle" then local sound = self.sound.idle[math.random(1, #self.sound.idle)] if sound ~= nil then self.entity:EmitSound(sound,50,1,1,false) end self.target=nil local animationIndex = self.animation.idle[math.random(1, #self.animation.idle)] self.animationmanager:SetAnimationSequence(animationIndex, self.idleAnimationSpeed * Time:GetSpeed()) self.entity:Stop()--stop following anything elseif mode=="patrolling" then self.entity:GoToPoint(self.currentWaypoint:GetPosition(true), self.speed, self.maxaccel) self.isPatrolling = true local animationIndex = self.animation.run[math.random(1, #self.animation.run)] self.animationmanager:SetAnimationSequence(animationIndex, self.runAnimationSpeed * Time:GetSpeed(),300) elseif mode=="hurt" then self:EndHurt() elseif mode=="attack" then self:EndAttack() elseif mode=="chase" then System:Print("Now in chase mode") if self.entity:Follow(self.target.entity,self.speed,self.maxaccel) then System:Print("follow") self.followingtarget=true local animationIndex = self.animation.run[math.random(1, #self.animation.run)] self.animationmanager:SetAnimationSequence(animationIndex, self.runAnimationSpeed * Time:GetSpeed(),300) else System:Print("no path?") end elseif mode=="dying" then self.entity:Stop() local animationIndex = self.animation.die[math.random(1, #self.animation.die)] self.animationmanager:SetAnimationSequence(animationIndex, self.attackAnimationSpeed * Time:GetSpeed(),300,1,self,self.EndDeath) elseif mode=="dead" then local sound = self.sound.die[math.random(1, #self.sound.die)] if sound ~= nil then self.entity:EmitSound(sound,50,1,1,false) end self.entity:SetCollisionType(0) self.entity:SetMass(0) self.entity:SetShape(nil) self.entity:SetPhysicsMode(Entity.RigidBodyPhysics) self.enabled=false end end end Quote Link to comment Share on other sites More sharing options...
Rick Posted December 30, 2015 Share Posted December 30, 2015 Yes, ideally the code would be better structured so you could just do that check at the top of a function and if nil return from the function. However, the AI code is fairly messy. I was playing with Behavior Trees (found a lua lib and made it work with LE and extended it a little) and found that although building the tree can be complicated, it really helps break AI processes down into much more manageable code. I might share this at some point if I find time as I think it could be useful for people. Without a UI to build the tree it can seem complicated though as it's a big lua table with nested lua tables and that can get complicated to follow, but it's less spaghetti code and more config than the current AI example. Quote Link to comment Share on other sites More sharing options...
Defranco Posted December 30, 2015 Author Share Posted December 30, 2015 I reset it and tried a new approach;; I got it down to only 2 checks by removing the other 4...... Seems less messy :/ I'm surprised at myself for understanding else/if now. Thanks Rick! It's nice being able to PRINT stuff in the logs to see where the code is activating. if self.mode=="hurt" then if self.target~=nil then if self.target.health<=0 then self:SetMode("idle") return end else if self.target==nil then System:Print("!!!!!!") self:SetMode("idle") end end if self.health<=0 then self:EndDeath() return end And also elseif mode=="hurt" then self:EndHurt() elseif mode=="attack" then self:EndAttack() elseif mode=="chase" then if self.target~=nil then System:Print("Now in chase mode") if self.entity:Follow(self.target.entity,self.speed,self.maxaccel) then System:Print("follow") self.followingtarget=true local animationIndex = self.animation.run[math.random(1, #self.animation.run)] self.animationmanager:SetAnimationSequence(animationIndex, self.runAnimationSpeed * Time:GetSpeed(),300) else System:Print("no path?") end else self:SetMode("idle") end Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.