AI for Panda3D: PandAI v1.0!

Hmm this seems right. But it is hard to debug with just the code you sent me.

Could you maybe give me a simple demo of just obstacle avoidance working in your game. For example, have a small scene with just one worker obstacle avoiding one house, using pursue.

If that works fine, then it could be something else in the game logic. Maybe self.worker or self.house becoming null or something less trivial.

here is something strange ,why error c:\panda.
my panda folder is d:\panda

File “main25.py”, line 618, in AIUpdate
self.AIWorld.update()
AssertionError: !is_infinite() at line 60 of c:\panda3d-1.7.0\built\include\boun
dingSphere.I

The path is irrelevant, it contains the source file at the time of compiling, not any file on your system.

The error says that there is an infinite bounding volume somewhere. I don’t know what could cause that, but have you tried commenting out PandAI-specific code? This way, you can isolate and see if the problem is actually caused by PandAI or if the update function merely triggers the error.

if i comment this line panda dont crash,problem is actor,

self.AIWorld.addAiChar(self.AIChar)

solved

Cool.

Could you post your fix please, so that other users with a similar query might be able to fix it too.

Thanks.

problem is because i used 2 ground collisions to get Z position for one actor

[code]

self.ralphGroundRay = CollisionRay()
self.ralphGroundRay.setOrigin(0,0,1000)
self.ralphGroundRay.setDirection(0,0,-1)
self.ralphGroundCol = CollisionNode(‘ralphRay’)
self.ralphGroundCol.addSolid(self.ralphGroundRay)
self.ralphGroundCol.setFromCollideMask(BitMask32.bit(0))
self.ralphGroundCol.setIntoCollideMask(BitMask32.allOff())
self.ralphGroundColNp = self.ralph.attachNewNode(self.ralphGroundCol)
self.ralphGroundHandler = CollisionHandlerQueue()
self.trav.addCollider(self.ralphGroundColNp, self.ralphGroundHandler)

and

curralphpos=self.ralph.getPos(self.root)
self.ralph.setZ(self.root, self.terrain.getElevation(curralphpos.getX(),curralphpos.getY()))
return Task.cont

if you change to defaultcollidemask everithing works fine with both
self.floaterGroundCol.setFromCollideMask(GeomNode.getDefaultCollideMask())

hi,new problem, my character sometime go thru obstacle

Hello!

I have posted my problem with AI and scaled models in this topic [url]troubles with PandaAI behaviour and scaled models], but later found suggestion to post problems in this thread. In short, with model scaled down or up (in blender, egg-trans or setScale), it dont reach its target as opposed to non-scaled model. I assume its something about how panda AI treats model origin point and calculate where movement complete. At this image http://www.elantum.com/scale.png big plane is non-scaled, small scaled in blender around model origin. All other params is the same. And it looks like scaled model stops at same point, where non-scaled will stop.

Please can somebody explain why this happen? Is it normal? How AI decide where to stop, is it use models origins or something else?

Thanks for any help

is there any way to use pandai with ode

@driver

Are you using obstacle avoidance or path finding ? If it is obstacle avoidance, sometimes if the velocity is too high it cannot steer away effectively.

Ode and PandAI can be done. It is a bit complicated but it is possible. The best suggestion I have is to use empty nodepaths as AI characters to give you the AI velocity, then apply ODE physics on it and then translate the resultant to your actual model.

@crolli

Yes PandAI has problems with scale. This is a bug which we did not get time to fix. I am guessing you are referring to seek/pursue and stopping. My suggestion would be to use empty nodepaths as AI characters and translate that motion onto your character (This is a very useful mechanism). The problem is with our distance check from AI to target doesn’t get adjusted based on scale.

its not work


import direct.directbase.DirectStart
from pandac.PandaModules import OdeWorld, OdeSimpleSpace, OdeJointGroup
from pandac.PandaModules import OdeBody, OdeMass, OdeBoxGeom, OdePlaneGeom
from pandac.PandaModules import BitMask32, CardMaker, Vec4, Quat
from random import randint, random
from direct.actor.Actor import Actor
from panda3d.ai import *
from direct.showbase.DirectObject import DirectObject
from direct.task import Task 
from pandac.PandaModules import *
import math,random,sys,os

 
 
 
 
class ODEEngine(DirectObject):
 def __init__(self):
   from pandac.PandaModules import loadPrcFileData
   loadPrcFileData("", "want-directtools #t")
   loadPrcFileData("", "want-tk #t")
   loadPrcFileData("", """sync-video 0
"""
) 
 

   self.world = OdeWorld()
   self.world.setGravity(0, 0, -90.81)

   self.world.initSurfaceTable(1)
   self.world.setSurfaceEntry(0, 0, 150, 0.0, 9.1, 0.9, 0.00001, 0.0, 0.002)

   self.space = OdeSimpleSpace()
   self.space.setAutoCollideWorld(self.world)
   self.contactgroup = OdeJointGroup()
   self.space.setAutoCollideJointGroup(self.contactgroup)

   self.ralph = Actor ("models/ralph",
                                     {"run":"models/ralph-run",
                                      "walk":"models/ralph-walk"})
   self.arrow = loader.loadModel("arrow")



   self.ralph.setTextureOff()
 

   self.objects = []


   for i in range(1):  
    self.ralphNP = NodePath(PandaNode("ralphnode"))
    self.ralphNP.reparentTo(render)
    self.ralph.reparentTo(self.ralphNP)
    
    self.ralphNP.setPos(0,0,15)
    self.ralph.setHpr(0,0,0)
  
  
  

    self.ralphNP.setHpr(0,0,0)

    self.ralphBody = OdeBody(self.world)
    M = OdeMass()
    M.setBox(50, 1, 1, 1)
    self.ralphBody.setMass(M)
    self.ralphBody.setPosition(self.ralphNP.getPos(render))
    self.ralphBody.setQuaternion(self.ralphNP.getQuat(render))

    self.boxGeom = OdeBoxGeom(self.space, 1, 1, 1)
    self.boxGeom.setCollideBits(BitMask32(0x00000002))
    self.boxGeom.setCategoryBits(BitMask32(0x00000001))
    self.boxGeom.setBody(self.ralphBody)
    self.objects.append((self.ralphNP, self.ralphBody))
  
  
    self.arrowNP = self.arrow.copyTo(render)
    self.arrowNP.setPos(5,5,5)
    self.arrowBody = OdeBody(self.world)
    self.arrowBody.setMass(M)
    self.arrowBody.setPosition(self.arrowNP.getPos(render))
    self.arrowBody.setQuaternion(self.arrowNP.getQuat(render))

    self.arrowGeom = OdeBoxGeom(self.space, 1, 1, 1)
    self.arrowGeom.setCollideBits(BitMask32(0x00000001))
    self.arrowGeom.setCategoryBits(BitMask32(0x00000002))
    self.arrowGeom.setBody(self.arrowBody)
    self.objects.append((self.arrowNP, self.arrowBody))
  
    self.setupAI()
  

  
  
  
  

   cm = CardMaker("ground")
   cm.setFrame(-20, 20, -20, 20)
   ground = render.attachNewNode(cm.generate())
   ground.setPos(0, 0, 0); ground.lookAt(0, 0, -1)
   groundGeom = OdePlaneGeom(self.space, Vec4(0, 0, 1, 0))
   groundGeom.setCollideBits(BitMask32(0x00000001))
   groundGeom.setCategoryBits(BitMask32(0x00000002))
 

   base.disableMouse()
   base.camera.setPos(0, 40, 20)
   base.camera.lookAt(0, 0, 0)

   taskMgr.doMethodLater(0.5, self.simulationTask, "Physics Simulation")
 

   oderay = OdeRayGeom(self.space , -7)

   oderay.set(0, 0, 0,0,0,7)
   
   
   base.setFrameRateMeter(True)
   


 def setupAI(self):
    self.AIWorld = AIWorld(render)
    self.AIChar = AICharacter("ralph",self.ralphNP,60,0.5,15)
    self.AIWorld.addAiChar(self.AIChar)
    self.AIBehaviors = self.AIChar.getAiBehaviors()
    self.AIBehaviors.pursue(self.arrow)
    
 
    taskMgr.add(self.AIUpdate,"AIUpdate")
    return
 def run(self):
        run() 

 def simulationTask(self,task):
  self.space.autoCollide() 

  self.world.quickStep(globalClock.getDt())
  for self.np, self.body in self.objects :
    self.np.setPosQuat(render, self.body.getPosition(), Quat(self.body.getQuaternion()))
    self.contactgroup.empty() 
 


 
 def AIUpdate(self,task):
        self.AIWorld.update()
        self.AIBehaviors.pursue(self.arrow)
        return task.cont 

ode = ODEEngine() 
ode.run()

obstacle avoidiance solved.
object must be one sided obstacle.setTwoSided(False)

NNair, thanks for answer and tip. Is updating model position and rotation from dummy node after aiworld.update will be enough? Or may be better way exists to translate?
As for scaling problem, finally I think its a normal. As I saw in sources for seek/pursue, it stops when distance between target/seeker from 0 to 1 unit (as result of int casting in condition). So, with large models distance will be invisible; but if models are near 1 unit in size distance becames visible… and think thats normal behaviour.

Cool. Thanks for posting your replies guys !

@crolli

Yes. I would do it after the aiworld update.

[EDIT] To really do it right, would be to edit the C++ source code in the update function of the AIBehavior or AICharacter to incorporate ODE physics. This way you wouldn’t have to use empty node paths and make your code look redundant.

This my code:

file_object = open(sys.path[0]+"/navmesh.csv", "w")
try:
	file_object.write("Grid Size,")
	file_object.write(str(gridSize))
	file_object.write("\nNULL, NodeType, GridX, GridY, Length, Width, Height, PosX, PosY, PosZ")
	for x in range(0,gridSize):
		for y in range(0,gridSize):
			file_object.write("\n")
			### I use self.get_height(x,y) to get terrain height. ###
			hmax = self.get_height(x+0.5,y+0.5)
			hmin = hmax
			h = [self.get_height(x+0.5,y-0.5),
				self.get_height(x-0.5,y-0.5),
				self.get_height(x-0.5,y-0.5)]
			### Get max height and min height ###
			for i in h:
				if i>hmax:
					hmax = i
				elif i<hmin:
					hmin = i
			if hmax-hmin<0.3:
				file_object.write("0,0,")
				file_object.write(str(x))
				file_object.write(",")
				file_object.write(str(y))
				file_object.write(",1,1,0,")
				file_object.write(str(x))
				file_object.write(",")
				file_object.write(str(y))
				file_object.write(",0")
			else:
				file_object.write("1,1,0,0,0,0,0,0,0,0")
			for dx in range(-1,2):
				for dy in range(-1,2):
					if dx != 0 or dy != 0 and dx>=0 and dy >=0 and dx<gridSize and dy<gridSize:
						file_object.write("\n")
						if abs(self.get_height(x,y)-self.get_height(x+dx,y+dy))<0.3:
							file_object.write("0,1,")
							file_object.write(str(x+dx))
							file_object.write(",")
							file_object.write(str(y+dy))
							file_object.write(",1,1,0,")
							file_object.write(str(x+dx))
							file_object.write(",")
							file_object.write(str(y+dy))
							file_object.write(",0")
						else:
							file_object.write("1,1,0,0,0,0,0,0,0,0")
finally:
	file_object.close()

I do not know whether it is correct.

PS: get_height:

def get_height(self,x,y):
	"""使用碰撞来获得某一点的高度"""
	result = self.world.rayTestClosest(Point3(x,y,100), Point3(x,y,-100))
	tag_x, tag_y, tag_z = result.getHitPos()
	return tag_z

How to get all the path nodes? Like this:

Or this: