HI guys. I am having trouble with collision masks in panda3d . I am doing this experiment. I have created two actors in the scene. Each one of them has a collision ray as a from object and a collision sphere. I am using the collision ray to check for intersections with the sphere of the other actor, so as to implement the object avoidance steering behavior. For each ray , I have a collision handler queue. The problem is that the intersections are not detected and the actors collide into one another.
import math
import sys
import time
from direct.actor.Actor import Actor, CollisionSphere
from direct.interval.FunctionInterval import Func, Wait, messenger
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, CollisionHandlerPusher, Vec2, CollisionHandlerQueue, CollisionEntry
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
from sympy import Point
class AI_behaviour(object):
def get_force(self):
pass
def is_complete(self):
pass
def get_weight(self):
pass
class seek(AI_behaviour):
def __init__(self,actor,target):
self.actor = actor
self.target = target
self.threshold = 2
self.target.set_excluded_obstacle()
self.actor.activate_obstacle_avoidance()
def get_force(self):
print("actor pos = ",self.actor.get_pos())
desired_velocity = self.target.get_pos() - self.actor.get_pos()
desired_velocity.z = 0
desired_velocity = desired_velocity.normalized()*self.actor.get_max_speed()
velocity = self.actor.get_velocity()
steering_force = desired_velocity - velocity
force_mag = int(math.sqrt(steering_force.x*steering_force.x+steering_force.y*steering_force.y))
if force_mag> self.actor.get_max_force():
steering_force = steering_force.normalized()*self.actor.get_max_force()
print("normalized seek force = ",steering_force)
return steering_force
def is_complete(self):
actor_pos = self.actor.get_pos()
target_pos = self.target.get_pos()
dx = actor_pos.x - target_pos.x
dy = actor_pos.y - target_pos.y
dist = int(math.sqrt(dx*dx + dy*dy))
if dist < self.threshold:
self.actor.deactivate_obstacle_avoidance()
self.target.reset_excluded_obstacle()
return True
return False
def get_weight(self):
return 0.5
class AIChar(object):
def __init__(self,name,actor,mass,speed,force,render,obs_avoid = False,obs_avoid_t = 5.0):
self.maxspeed = speed
self.maxforce = force
self.actor = actor
self.name = name
self.AI_behaviours = []
self.velocity = Vec3(0.0001,0.0001,0)
self.force = Vec3(0,0,0)
self.render = render
self.mass = mass
self.obstacleAvoidance = obs_avoid
self.cnp = self.actor.attachNewNode(CollisionNode(name+"_ray"))
self.collision_handler = CollisionHandlerQueue()
self.obs_threshold = obs_avoid_t
def add_ai_behaviour(self,behaviour):
self.AI_behaviours.append(behaviour)
def activate_obstacle_avoidance(self):
self.obstacleAvoidance = True
def deactivate_obstacle_avoidance(self):
self.obstacleAvoidance = False
def apply_force(self,f):
f = f.normalized()
f = f * self.maxforce
old_velocity = -(self.render.getRelativeVector(self.actor,Vec3(0,1,0))).normalized()
self.velocity = self.velocity + (f/self.mass)
new_velocity = self.velocity.normalized()
print("new velocity = ",new_velocity)
angle = old_velocity.signedAngleDeg(new_velocity,Vec3(0,0,1))
old_orientation = self.actor.getHpr()
new_orientation = Vec3(old_orientation.x+angle,old_orientation.y,old_orientation.z)
self.actor.setHpr(new_orientation)
v_mag =int(math.sqrt( self.velocity.x*self.velocity.x + self.velocity.y*self.velocity.y))
if v_mag>self.maxspeed:
self.velocity = self.velocity.normalized()*self.maxspeed
self.actor.set_pos(self.actor.getPos()+self.velocity)
def get_ai_behaviours(self):
return self.AI_behaviours
def remove_ai_behaviour(self,behaviour):
self.AI_behaviours.remove(behaviour)
def get_velocity(self):
return self.velocity
def avoid_obstacles(self,obstacle):
obstacle_pos = obstacle.getIntoNodePath().get_parent().get_pos()
actor_pos = self.actor.get_pos()
collision_contact_point = obstacle.getSurfacePoint(self.render)
adj = collision_contact_point - obstacle_pos
adj.z =0
dx = collision_contact_point.x - obstacle_pos.x
dy = collision_contact_point.y - obstacle_pos.y
dist = int(math.sqrt(dx*dx+dy*dy))
if dist < self.obs_threshold:
diff = self.obs_threshold - dist
adj = adj.normalized()
force = adj*diff
return force
else:
return Vec3(0,0,0)
def create_collision_ray(self):
self.cnp2=self.actor.attachNewNode(CollisionNode(self.name))
self.cnp2.node().addSolid(CollisionSphere(Vec3(0.0,0.0,0.0),2.0))
self.cnp2.node().setCollideMask(BitMask32.bit(2))
self.cnp2.show()
ray = CollisionRay(0,0,1,0,-1,0)
self.cnp.node().clearSolids()
self.cnp.node().addSolid(ray)
self.cnp.node().setCollideMask(0)
self.cnp.node().setFromCollideMask(BitMask32.bit(2))
self.cnp.show()
return self.cnp
def get_collision_handler_queue(self):
return self.collision_handler
def get_pos(self):
return self.actor.get_pos()
def get_max_force(self):
return self.maxforce
def get_max_speed(self):
return self.maxspeed
class MyAIWorld(object):
def __init__(self,render):
self.AIChars = []
self.render = render
self.obs_avoid_weight = 0.9
def add_AI_char(self,char):
self.AIChars.append(char)
def combine_steering_forces(self,forces):
force = Vec3(0,0,0)
if(len(forces)==1):
print("only seek force",forces[0][0])
force = force + forces[0][0]
else:
for f,w in forces:
force= force + (f*w)
return force
def update(self):
traverser = CollisionTraverser()
queues = {}
forces = {}
for char in self.AIChars:
forces[char]=[]
if char.obstacleAvoidance:
queue = char.get_collision_handler_queue()
from_char_ray = char.create_collision_ray()
traverser.addCollider(from_char_ray,queue)
queues[char] = queue
for behaviour in char.get_ai_behaviours():
if behaviour.is_complete():
char.remove_ai_behaviour(behaviour)
else:
force = behaviour.get_force()
forces[char].append((force,behaviour.get_weight()))
traverser.traverse(self.render)
traverser.showCollisions(self.render)
for char,queue in queues.items():
if queue.get_num_entries()!=0:
queue.sortEntries()
closest_obstacle = queue.get_entry(0)
force = char.avoid_obstacles(closest_obstacle)
forces[char].append((force,self.obs_avoid_weight))
for char in self.AIChars:
if len(forces[char])!=0:
net_force = self.combine_steering_forces(forces[char])
char.apply_force(net_force)
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()
self.excluded_obstacle = False
def add_bounding_box(self):
min,max = self.model.getTightBounds()
sz = max-min
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().setIntoCollideMask(BitMask32.bit(2))
def set_excluded_obstacle(self):
self.cnodepath.node().setIntoCollideMask(0)
def reset_excluded_obstacle(self):
self.cnodepath.node().setIntoCollideMask(BitMask32.bit(2))
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):
self.name = name
self.speed = 5
self.mass = 100
self.force = 0.05
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_origin-Armature|mixamo.com|Layer0.002.egg',
'talk':'models/boy3/jack-talk-Armature|mixamo.com|Layer0.001.egg',
'idle':'models/boy3/jack-idle-Armature|mixamo.com|Layer0.egg',
'sit':'models/boy3/jack-sit-Armature|mixamo.com|Layer0.002.egg'})
self.add_physics()
def set_pos(self,pos):
self.anp.set_pos(pos)
def add_ai_behavior(self,render):
self.AIChar = AIChar(self.name,self.anp,self.mass,self.speed,self.force,render,obs_avoid=True)
def set_scale(self,scale):
self.actorNP.set_scale(scale)
def get_pos(self):
return self.anp.get_pos()
def add_physics(self):
self.an = ActorNode()
def get_speed(self):
return self.speed
def reparent(self,parent):
self.anp = parent.attachNewNode(self.an)
self.actorNP.reparentTo(self.anp)
class walk_towards(object):
def __init__(self,actor1,object1,last= True):
self.actor1 = actor1
self.object = object1
self.last = last
self.pos1 = actor1.get_pos()
self.pos2 = object1.get_pos()
self.type = "pending"
speed = actor1.AIChar.get_velocity()
self.seq = Sequence(self.actor1.actorNP.actorInterval("walk",loop = 1))
self.isplaying = False
def get_time(self):
return self.time
def play(self):
self.isplaying = True
print("walking")
print("creating seek behaviour")
self.seek_behav = seek(self.actor1.AIChar,self.object)
self.actor1.AIChar.add_ai_behaviour(self.seek_behav)
self.seq.loop()
def stop(self):
print("action stopped")
self.seq.finish()
if self.last==True:
self.actor1.actorNP.loop("idle")
print("finish called")
def is_complete(self):
if self.seek_behav.is_complete():
return True
else:
return False
class Scene_Manager(ShowBase):
def __init__(self):
ShowBase.__init__(self)
self.pending_actions = []
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)
self.set_up_ai()
self.taskMgr.add(self.update_ai_world,"updateAI")
self.add_ground()
self.object1 = MObj("Box1",self.loader)
self.object1.set_pos(Point3(-8,-10,-4))
self.object1.reparent(self.render)
self.object1.set_scale(0.5)
self.object2 = MObj("Box2",self.loader)
self.object2.set_pos(Point3(8,-10,-5))
self.object2.reparent(self.render)
self.object2.set_scale(0.5)
self.actor1 = Character("Jack")
self.actor1.reparent(self.render)
self.actor1.add_ai_behavior(self.render)
self.AIWorld.add_AI_char(self.actor1.AIChar)
self.actor1.set_pos(Point3(5,-10,-6))
self.actor1.set_scale(2.0)
self.actor2 = Character("Jack2")
self.actor2.reparent(self.render)
self.actor2.add_ai_behavior(self.render)
self.AIWorld.add_AI_char(self.actor2.AIChar)
self.actor2.set_pos(Point3(-5,-10,-6))
self.actor2.set_scale(2.0)
self.walk = walk_towards(self.actor1,self.object1)
self.walk2 = walk_towards(self.actor2,self.object2)
self.pending_actions.append([self.walk])
self.pending_actions.append([self.walk2])
self.taskMgr.add(self.check_state,"check")
#base.cTrav.showCollisions(self.render)
def check_state(self,task):
for seq_action in self.pending_actions:
if len(seq_action)!=0:
if not seq_action[0].isplaying:
seq_action[0].play()
for seq_action in self.pending_actions:
if len(seq_action)!=0:
if seq_action[0].is_complete():
seq_action[0].stop()
seq_action.pop(0)
print("action completed")
return task.cont
# def set_up_physics(self):
# base.enableParticles()
# gravityFN= ForceNode('world-forces')
# gravityFNP=self.render.attachNewNode(gravityFN)
# gravityFN.addForce(self.gravityForce)
def set_up_ai(self):
self.AIWorld = MyAIWorld(self.render)
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()