Problems with animation of multiple entities

blz

10-11-2011 21:52:20

Hello,

I've been attempting to extend the code from Intermediate Tutorial 1 such that I can animate the translation of an arbitrary number of entities. In order to do this, I have created an animableEntity class in which all animation-related data is placed. This includes a pointer to the SceneNode and entity objects (see code below).

I have three distinct problems which I will outline below. I have also attempted to whittle my code down to a manageable testcase -- please note that this code (like all tutorial code) relies on the sample framework.

Problem 1: Entity overshoots destination and moves off screen

Problem Description: If you run the code provided at the bottom of this post, you should see two non-animated robots and a single animated one. The non-animated robots are simply references. The one on the left marks the starting position for the animated entity and the one on the right marks the prescribed destination. Instead of walking in a straight line towards the robot on the right, the animated robot walks through his destination and off the screen, only to suddenly reappear at his destination 30 seconds to a minute later.

I am reusing the code from Intermediate Tutorial I which places the entity at its prescribed destination if the distance to said destination is <= 0.0. I suspect this is not the problem, since I have not touched these particular lines, but here they are just in case I missed something:

move = self.walkSpeed * self.ev_evt.timeSinceLastFrame
self.distance -= move
if self.distance <= 0.0: # if unit has overshot destination, place on destination
self.node.setPosition(self.destination)
if not self.nextLocation(): # if no waypoints remaining
self.stopWalking()
else:
self.node.translate(self.destination * move)


Problem 2: Entity translation speed is correlated with distance to destination

This is also quite strange. I noticed that my animated robot will move faster if the waypoint is placed farther away. I can't even begin to understand what could be the cause of this! Again, the code above has not been significantly modified from the Intermediate Tutorial I code. Any suggestions?

Problem 3: Entities cannot be scaled by calling entity.scale

This should be fairly self-explanatory. I call startEnt.scale = (.1, .1, .1) at lines 134 and 139, but the two nonanimated robots are as large as the animated one! Any ideas what may be the cause?

Complete Testcase (apologies for the length, but I don't know how to make it any shorter!)

import ogre.renderer.OGRE as ogre
import SampleFramework as sf
import ogre.gui.CEGUI as CEGUI
import ogre.io.OIS as OIS

class animableEntity:
def __init__(self, entity, node):
# Identity
self.entity = entity
self.entity
self.node = node
# Movement
self.wayPoints = []
#self.walkSpeed = 35.0
self.walkSpeed = 1
self.destination = None
self.direction = ogre.Vector3().ZERO
self.distance = 0.0 # dist left to travel
self.walking = False
# Animation
self.ev_evt = None # contains timeSinceLastFrame
self.animationState = self.entity.getAnimationState('Idle')
self.animationState.setLoop(True)
self.animationState.setEnabled(True)

def go(self, evt):
'''Calls all relevant functions for a single unit: movement, shooting, etc...'''
self.ev_evt = evt
self.walk()
self.animationState.addTime(self.ev_evt.timeSinceLastFrame)

def walk(self):
if not self.walking:
if len(self.wayPoints):
self.startWalking() ## if you're not already walking AND there are waypoints, start walking
else:
self.step()

def addWaypoint(self, coords_Vector3):
'''Takes in ogre.Vector3'''
self.wayPoints.append(coords_Vector3)

def startWalking(self):
if self.nextLocation():
self.animationState = self.entity.getAnimationState('Walk')
self.animationState.setLoop(True)
self.animationState.setEnabled(True)
self.walking = True

def stopWalking(self):
self.animationState = self.entity.getAnimationState('Idle')
self.animationState.setLoop(True)
self.animationState.setEnabled(True)
self.walking = False

def nextLocation(self):
'''
Prepares translation-related member variables for next waypoint.
Must be run prior to moving to waypoint.
Returns ogre.Vector3 with coords to next waypoint.
'''
if len(self.wayPoints) == 0:
return False
self.destination = self.wayPoints.pop(0) # FIFO behavior
self.direction = self.destination - self.node.getPosition()
self.distance = self.direction.normalise()
self.handleTurns()
return True

def handleTurns(self):
src = self.node.getOrientation() * ogre.Vector3().UNIT_X
if 1.0 + src.dotProduct(self.direction) < 0.0001:
self.node.yaw(ogre.Degree(180))
else:
quat = src.getRotationTo(self.direction)
self.node.rotate(quat)

def step(self):
move = self.walkSpeed * self.ev_evt.timeSinceLastFrame
self.distance -= move
if self.distance <= 0.0: # if unit has overshot destination, place on destination
self.node.setPosition(self.destination)
if not self.nextLocation(): # if no waypoints remaining
self.stopWalking()
else:
self.node.translate(self.destination * move)

class EventListener(sf.FrameListener):
'''Handles input, update model and perform checks before rendering'''
def __init__(self, win, cam, sc, ent, node):
## Subclass any Python-Ogre class and you *must* call its constructor
sf.FrameListener.__init__(self, win, cam, True, True)

## Initialize Class Variables
self.moveSpeed = 50
self.rotateSpeed = 1/500.0
self.sceneManager = sc
self.camera = cam
self.aEnt = []

## Testcase Varaibles
self.aEntInit = False
self.ent = ent
self.node = node

def frameStarted(self, evt):
# Process samepleframework frame listener. Needs to happen first, as we will manipulate the translate vector.
if not sf.FrameListener.frameStarted(self, evt):
return False

if not self.aEntInit:
self.aEnt.append(animableEntity(self.ent, self.node))
self.aEnt[0].addWaypoint(ogre.Vector3(400,0,0)) ## Waypoint
self.aEntInit = True

## Unit animation and transform
for unit in self.aEnt:
unit.go(evt) # process unit
# print unit.node.getPosition() ## DEBUG
# print "\n" ## END DEBUG

return True

class TutorialApplication(sf.Application):
'''Application Class'''

def _createScene(self):
self.ent = self.sceneManager.createEntity('Robot','robot.mesh')
location = ogre.Vector3().ZERO
self.node = self.sceneManager.getRootSceneNode().createChildSceneNode('RobotNode', location)
self.node.attachObject(self.ent)

startEnt = self.sceneManager.createEntity('startRobot', 'robot.mesh')
startEnt.scale = (.1, .1, .1)
startNode = self.sceneManager.getRootSceneNode().createChildSceneNode('StartNode', location)
startNode.attachObject(startEnt)

refEnt = self.sceneManager.createEntity('refRobot', 'robot.mesh')
refEnt.scale = (.01, .01, .01)
refNode = self.sceneManager.getRootSceneNode().createChildSceneNode('refNode', ogre.Vector3(400,0,0))
refNode.attachObject(refEnt)

def _createCamera(self):
self.camera = self.sceneManager.createCamera('PlayerCam')
self.camera.setPosition(600, 1000, 1000)
self.camera.lookAt(ogre.Vector3(600,0,0))
self.camera.nearClipDistance = 5

def _createFrameListener(self):
self.frameListener = EventListener(self.renderWindow,
self.camera,
self.sceneManager,
self.ent,
self.node
)
self.root.addFrameListener(self.frameListener)
self.frameListener.showDebugOverlay(True)

if __name__ == '__main__':
ta = TutorialApplication()
ta.go()


I realize this post is a fairly open-ended cry for debugging help, but I've looked at this for several days and I really don't know where to go from here. :( Any sort of help would be immensely appreciated!

Thank you in advance!
- blz

dermont

11-11-2011 03:19:54

For the scale problem, apply the scale to the scenenode.

startEnt = self.sceneManager.createEntity('startRobot', 'knot.mesh')
startNode = self.sceneManager.getRootSceneNode().createChildSceneNode('StartNode', location)
startNode.attachObject(startEnt)
startNode.scale(.3, .3, .3)


For your other problems, a typo in your node translate code.

def step(self):
...
else:
self.node.translate(self.direction * move)

blz

13-11-2011 21:50:51

Hi dermont,

Thank you so much for your help! That certainly seems to have fixed all of the animation problems.

The scaleing problems still persist, however...

In any case, good eye! I hope I can repay you someday :D

- Blz

dermont

14-11-2011 02:52:26

Hi dermont,

Thank you so much for your help! That certainly seems to have fixed all of the animation problems.

The scaleing problems still persist, however...

In any case, good eye! I hope I can repay you someday :D

- Blz


What version of python-ogre are you using? Do you have a simple example of your scaling problem? Something along the lines of:

import sys
sys.path.insert(0,'..')
import PythonOgreConfig

import ogre.renderer.OGRE as ogre
import SampleFramework as sf
import ogre.io.OIS as OIS

class Test(sf.Application):

def _createScene(self):
NUM_ROBOTS = 5
for j in range(NUM_ROBOTS):
ent = self.sceneManager.createEntity('Robot%d'%(j),'robot.mesh')
node = self.sceneManager.getRootSceneNode().createChildSceneNode(ogre.Vector3( -100 + j * 50 ,0,0))
node.attachObject(ent)
## combining it's current scale with the passed in scaling factor.
node.scale(.3*(j+1), .3*(j+1), .3*(j+1))

if __name__ == '__main__':
ta = Test()
ta.go()


I tried out your demo and scaling appears to work OK:

def _createScene(self):
self.ent = self.sceneManager.createEntity('Robot','robot.mesh')
location = ogre.Vector3().ZERO
self.node = self.sceneManager.getRootSceneNode().createChildSceneNode('RobotNode', location)
self.node.attachObject(self.ent)

startEnt = self.sceneManager.createEntity('startRobot', 'robot.mesh')
#startEnt.scale = (.1, .1, .1)
startNode = self.sceneManager.getRootSceneNode().createChildSceneNode('StartNode', location)
startNode.attachObject(startEnt)
startNode.scale(2.3, 2.3, 2.3)

refEnt = self.sceneManager.createEntity('refRobot', 'robot.mesh')
#refEnt.scale = (.01, .01, .01)
refNode = self.sceneManager.getRootSceneNode().createChildSceneNode('refNode', ogre.Vector3(400,0,0))
refNode.attachObject(refEnt)
refNode.scale(0.5, 0.5, 0.5)
....

blz

17-11-2011 12:47:53

dermont,

I've managed to fix the problem. It's a silly syntactic oversight on my part.

The code should look like:

node.scale(1,1,1)


Instead of


node.scale = (1,1,1)


Consider this problem solved! Thanks again for your generous help.

-blz