I am trying to define a sequence of behaviours involving AI behaviour using panda sequence class. First I define a walk behaviour using seek function and I activate obstacle avoidance. Next I define fall behaviour . Each behaviour has its own animation.when running the code, there are four main problems:
1- The animation of the second behaviour is activated , but the first one doesn’t
2- The behaviour is different each time I run the code
3- I cannot set the time of each action on the sequence
4- The seek behaviour may not stop if the actor was not able to reach target
I am still a beginner and it’s my first time using the engine, so may be I did something wrong.
Thanks in advance.
import math
import sys
import time
from direct.actor.Actor import Actor, CollisionSphere
from direct.interval.FunctionInterval import Func, Wait
from direct.interval.MetaInterval import Sequence, Parallel
from direct.showbase.InputStateGlobal import inputState
from direct.showbase.ShowBase import ShowBase, CollisionNode, CollisionTraverser, CollisionHandlerEvent, CollisionRay, \
CollisionHandlerFloor, NodePath
from direct.showbase.ShowBaseGlobal import globalClock
from direct.interval.ActorInterval import ActorInterval
from panda3d.ai import AIWorld, AICharacter
from panda3d.core import AmbientLight, CollisionBox, CollisionCapsule, CollisionPlane, Plane
from panda3d.core import DirectionalLight
from panda3d.core import Vec3
from panda3d.core import Vec4
from panda3d.core import Point3
from panda3d.core import TransformState
from panda3d.core import BitMask32
from panda3d.core import Filename
from panda3d.core import PNMImage
from panda3d.physics import ForceNode, LinearVectorForce, ActorNode, PhysicsCollisionHandler
class MObj(object):
def __init__(self,name,loader):
self.name = name
m = loader.loadModel("./models/cube/cube")
self.model=m
self.add_bounding_box()
self.add_collision_ray()
#
#
# def add_bounding_box(self):
# min,max = self.model.getTightBounds()
# sz = max-min
# # cs = CollisionBox(Point3(0,0,0),sz.x//2,sz.y//2,sz.z//2)
# cs = CollisionBox(Point3(0,0,0),2.0,2.0,2.0)
# self.cnodepath = self.model.attachNewNode(CollisionNode(self.name))
# self.cnodepath.node().addSolid(cs)
# self.cnodepath.show()
#
# self.cnodepath.node().setFromCollideMask(0)
#
# self.cnodepath.node().addSolid(CollisionRay(0, 0, 0, 0, 0, -1))
def add_bounding_box(self):
min,max = self.model.getTightBounds()
sz = max-min
# cs = CollisionBox(Point3(0,0,0),sz.x//2,sz.y//2,sz.z//2)
cs = CollisionBox(Point3(0,0,0),2.0,2.0,2.0)
self.cnodepath = self.model.attachNewNode(CollisionNode(self.name))
self.cnodepath.node().addSolid(cs)
self.cnodepath.show()
self.cnodepath.node().setFromCollideMask(0)
def add_collision_ray(self):
self.raynodepath = self.model.attachNewNode(CollisionNode(self.name+str(1)))
self.raynodepath.node().addSolid(CollisionRay(0, 0, 0, 0, 0, -1))
def set_pos(self,pos):
self.model.set_pos(pos)
def set_scale(self,scale):
self.model.set_scale(scale)
def get_pos(self):
return self.model.get_pos()
def reparent(self,parent):
self.model.reparentTo(parent)
class Character(object):
def __init__(self,name,gravity):
self.name = name
self.speed = 20
self.mass = 100
self.actorNP = Actor('models/boy3/jack_walk.egg', {
'stand': 'models/boy3/jack-stand.egg',
'fall':'models/boy3/jack-fall.egg',
'walk':'models/boy3/jack_walk-Armature|mixamo.com|Layer0.007.egg'})
self.add_physics(gravity)
self.add_bounding_box()
# self.add_ai_behavior()
def add_ai_behavior(self):
self.AIChar = AICharacter(self.name,self.anp,100,0.05,5)
def add_bounding_box(self):
min,max = self.actorNP.getTightBounds()
vec = max-min
self.boundingX = (vec).x
self.boundingY = (vec).y
self.boundingZ = (vec).z
self.cnp=self.actorNP.attachNewNode(CollisionNode(self.name))
self.cnp.node().addSolid(CollisionSphere(Vec3(0.0,0.0,0.0),1.0))
#self.cnp.node().addSolid(CollisionSphere(Vec3(self.boundingX/2,self.boundingY/2,self.boundingZ/2),self.boundingX))
#self.cnp.node().addSolid(CollisionCapsule(min,max,0.5))
self.cnp.show()
#cnp.node().setFromCollideMask(BitMask32.bit(2))
#self.cnp.node().setIntoCollideMask(0)
def set_pos(self,pos): #basically sets the position of the physics node
self.anp.set_pos(pos)
def set_scale(self,scale):
self.actorNP.set_scale(scale)
def get_pos(self):
return self.anp.get_pos()
def add_physics(self,gravity):
self.an = ActorNode()
self.an.getPhysical(0).addLinearForce(gravity)
def get_speed(self):
return self.speed
#last thing to be done
def reparent(self,parent):
self.anp = parent.attachNewNode(self.an)
self.actorNP.reparentTo(self.anp)
def do_animation_sequence(self):
self.actorNP.loop("walk")
ai_behaviour = self.AIChar.getAiBehaviors()
ai_behaviour.seek(Point3(1,5,-5))
ai_behaviour.obstacleAvoidance(5.0)
class PhysicsManager(object):
def __init__(self):
self.floor_mask = BitMask32.bit(1)
self.off_mask = BitMask32.allOff()
self.traverser = CollisionTraverser('MainCollsionTraverser')
self.pusher = PhysicsCollisionHandler()
self.pusher.addInPattern("into-%in")
self.pusher.addOutPattern("out-%in")
self.floor_handler = CollisionHandlerFloor()
def get_collision_traverser(self):
return self.traverser
def attach_collision_node_to_pusher_handler(self,cnp,node):
self.pusher.addCollider(cnp,node)
def get_pusher_handler(self):
return self.pusher
def attach_collision_node_to_floor_handler(self,cnp,node):
self.floor_handler.addCollider(cnp,node)
def get_floor_handler(self):
return self.floor_handler
#
# class Action(object):
#
# def __init_(self,actors,type,name):
# self.type = type
# self.name = name
# self.actors = actors
# if self.type == "inplace":
# self.time = 20
# elif self.type == "sound":
# self.time = 40
# pass
# #shall depend on the length of the voice record
# else: #translational
# if(len(self.actors)==2):
# pos1 = self.actors[0].get_pos()
# pos2 = self.actors[1].get_pos()
# dist = math.abs(pos1.x-pos2.x)+math.abs(pos1.y-pos2.y)
# speed = self.actor[0].get_speed()
# self.time = dist//speed + 5
#
# def get_time(self):
# return self.time
#
#
class walk_towards(object):
def __init__(self,actor1,object):
self.actor1 = actor1
self.object = object
self.pos1 = actor1.get_pos()
self.pos2 = object.get_pos()
dist = abs(self.pos1.x-self.pos2.x)+abs(self.pos1.y-self.pos2.y)
speed = actor1.get_speed()
self.time = dist//speed + 5
def get_time(self):
return self.time
def play(self):
#check if actor has the walk animation implemented
self.actor1.actorNP.loop("walk")
print("walking")
ai_behaviour = self.actor1.AIChar.getAiBehaviors()
ai_behaviour.seek(self.pos2-(1,1,0))
ai_behaviour.obstacleAvoidance(2.0)
class fall_down(object):
def __init__(self,actor1):
self.actor = actor1
def play(self):
self.actor.actorNP.play("fall")
class Scene_Manager(ShowBase):
def __init__(self):
ShowBase.__init__(self)
base.setBackgroundColor(0.1, 0.1, 0.8, 1)
base.setFrameRateMeter(True)
base.cam.setPos(0, 0, 40)
base.cam.setHpr(-90,0,0)
base.cam.lookAt(0, 0, 0)
#Physics handling
self.set_up_physics()
self.PM = PhysicsManager()
base.cTrav = self.PM.get_collision_traverser()
#set up ai
self.set_up_ai()
#Create tasks
self.taskMgr.add(self.update_ai_world,"updateAI")
#add ground
self.add_ground()
#add objects in different positions on the map
self.object1 = MObj("Box1",self.loader)
self.object1.set_pos(Point3(0,0,-5))
self.object1.reparent(self.render)
self.object1.set_scale(0.5)
self.attach_object_to_physics_world(self.object1)
self.AIWorld.addObstacle(self.object1.cnodepath)
self.object2 = MObj("Box2",self.loader)
self.object2.set_pos(Point3(3,0,-5))
self.object2.reparent(self.render)
self.object2.set_scale(0.5)
self.attach_object_to_physics_world(self.object2)
self.AIWorld.addObstacle(self.object2.cnodepath)
self.object3 = MObj("Box3",self.loader)
self.object3.set_pos(Point3(6,0,-5))
self.object3.reparent(self.render)
self.object3.set_scale(0.5)
self.AIWorld.addObstacle(self.object3.cnodepath)
self.attach_object_to_physics_world(self.object3)
self.object4 = MObj("Box4",self.loader)
self.object4.set_pos(Point3(-3,0,-5))
self.object4.reparent(self.render)
self.object4.set_scale(0.5)
self.attach_object_to_physics_world(self.object4)
self.AIWorld.addObstacle(self.object4.cnodepath)
self.object5 = MObj("Box5",self.loader)
self.object5.set_pos(Point3(-5,-0,-5))
self.object5.reparent(self.render)
self.object5.set_scale(0.5)
self.attach_object_to_physics_world(self.object5)
self.AIWorld.addObstacle(self.object5.cnodepath)
self.object6 = MObj("Box6",self.loader)
self.object6.set_pos(Point3(-6,0,-5))
self.object6.reparent(self.render)
self.object6.set_scale(0.5)
self.attach_object_to_physics_world(self.object6)
self.AIWorld.addObstacle(self.object6.cnodepath)
#add Actors to the scene
self.actor1 = Character("Jack",self.gravityForce)
self.actor1.reparent(self.render)
self.actor1.add_ai_behavior()
self.attach_node_to_physics_world(self.actor1)
self.AIWorld.addAiChar(self.actor1.AIChar)
self.actor1.set_pos(Point3(1,-5,-5))
self.actor1.set_scale(2.0)
#self.actor1.do_animation_sequence()
self.walk = walk_towards(self.actor1,self.object1)
self.fall = fall_down(self.actor1)
self.seq = Sequence(Parallel(Func(self.walk.play),Wait(self.walk.get_time()+10)),Func(self.fall.play))
#
#seq = Sequence(Func(walk.play),Wait(walk.get_time()),Func(fall.play))
#seq = Sequence(Parallel(Func(walk.play),walk.get_time()),Func(fall.play))
self.seq.start()
#self.taskMgr.add(self.AIbehav,"behave")
#actor1.do_animation_sequence()
# myInterval1 = actor1.actorNP.actorInterval(
# "walk"
#
#
#
#
# )
# myInterval2 = actor1.actorNP.actor_interval(
# "fall"
# )
#
#
# myInterval3 = actor1.actorNP.actor_interval("stand")
#
# seq = Sequence()
# seq.append(myInterval1)
# seq.extend([myInterval2,myInterval3])
# seq.loop()
self.taskMgr.add(self.check_state,"check")
# Add collision handler events
self.accept("into-%s"%self.object1.name,self.collide)
# def AIbehav(self,task):
# print(self.ai_behaviour.behaviorStatus("seek"))
# return task.cont
def check_state(self,task):
if(self.actor1.AIChar.getAiBehaviors().behaviorStatus("seek")=="done"):
print("done")
# self.actor1.AIChar.getAiBehaviors().removeAi("seek")
return task.cont
def collide(self,col_entry):
print(col_entry.getFromNodePath().getParent().getParent().node().getChildren()[0])
# col_entry.getFromNodePath().getParent().node().play("fall")
#col_entry.getFromNodePath().getParent().stop()
def attach_node_to_physics_world(self,actor1):
base.physicsMgr.attachPhysicalNode(actor1.an)
self.PM.attach_collision_node_to_pusher_handler(actor1.cnp,actor1.anp)
base.cTrav.addCollider(actor1.cnp,self.PM.get_pusher_handler())
def attach_object_to_physics_world(self,object):
self.PM.attach_collision_node_to_floor_handler(object.raynodepath,object.model)
object.raynodepath.node().setFromCollideMask(self.PM.floor_mask)
object.raynodepath.node().setIntoCollideMask(self.PM.off_mask)
base.cTrav.addCollider(object.raynodepath,self.PM.get_floor_handler())
def set_up_physics(self):
base.enableParticles()
gravityFN= ForceNode('world-forces')
gravityFNP=self.render.attachNewNode(gravityFN)
self.gravityForce=LinearVectorForce(0,0,-9.81) #gravity acceleration
gravityFN.addForce(self.gravityForce)
base.physicsMgr.addLinearForce(self.gravityForce)
def set_up_ai(self):
self.AIWorld = AIWorld(self.render)
def update_physics_world(self):
pass
def update_ai_world(self,task):
self.AIWorld.update()
return task.cont
def add_ground(self):
ground = CollisionNode('ground')
cs = CollisionPlane(Plane(Vec3(0, 0, 1), Point3(0, 0, -6)))
ground.addSolid(cs)
cnp2=self.render.attachNewNode(ground)
cnp2.show()
cnp2.node().setIntoCollideMask(BitMask32.allOn())
if __name__=="__main__":
scene = Scene_Manager()
scene.run()