collisionSegments colliding

this time, no menu’s or cards, but collision

i have a collision segment for interaction with objects linked to ‘e’, and one for battle with characters linked to ‘mouse1’ (those are the trigger events for reading the collision data)

they both origin at the same point and go in the same direction but with varying lengths.

the problem is that they collide with eachoter, so i cant read the first collision mark as the object.

should i experiment with other entries?
or is there a way to stop them from colliding woth eachother?

… That’s very odd. To the best of my knowledge, CollisionSegments shouldn’t act as “into” objects at all (that is, things - even other CollisionSegments - shouldn’t collide with them, only they with other objects).

Could you perhaps post the relevant code here, all of setting up the segments, activating them in your events and handling the collisions, please?

well, for starters, i get an error generated (doesnt cause a game shutdown) that says: “invalid attempt to detect collision from CollisionSegment into CollisionSegment!” and some explanation about how this shouldnt be.

the code is just a copycat:
creation:

	mouseray=CollisionNode('mouseray')
	battleray=CollisionNode('battleray')
	mouseraypath=base.camera.attachNewNode(mouseray)
	battleraypath=base.camera.attachNewNode(battleray)
	self.cambeam=CollisionSegment(0,0,0,0,10,0)
	self.battlebeam=CollisionSegment(0,0,0,0,5,0)
	mouseraypath.node().addSolid(self.cambeam)
	battleraypath.node().addSolid(self.battlebeam)
	traverser = CollisionTraverser('traverser')
	base.cTrav = traverser
	queue = CollisionHandlerQueue()
	battle = CollisionHandlerQueue()
	traverser.traverse(render)
	traverser.addCollider(mouseraypath,queue)
	traverser.addCollider(battleraypath,battle)

the event code is copied from the manual:

def pick(self,handler):
	if(handler.getNumEntries()>0):
	  handler.sortEntries()
	  picked=handler.getEntry(0).getIntoNodePath()
	  picked=picked.findNetTag('collisiontag')
	  if not (picked.isEmpty()):
		self.interact(picked)
def combat(self,handler):
	if(handler.getNumEntries()>0):
	  handler.sortEntries()
	  picked=handler.getEntry(0).getIntoNodePath()
	  picked=picked.findNetTag('instance')
	  type=picked.getTag('type')
	  if not (picked.isEmpty()):
		self.damage(picked,type)

instance refers to a tag added to every enemy that increases its value for every enemy created (they spawn at runtime)

allthough the code for the mouseray and method “pick” seem to work fine.

it could be i misread the error and they dont actually “collide” but then again clicking on the enemy doesnt cause any actions.

in case it helps, this is the spawn code:

def spawnmonster(self,task):
	global i
	task.delayTime=random.randrange(10,30) 
	self.enemy = Actor("cat-humans/bvwf2004brotherlittle/littlebrother")
	self.enemy.setPos(random.randrange(-10,10),random.randrange(-10,10),0)

	self.enemy.setTag('type','1')
	encol=CollisionNode('encol')
	encolpath=self.enemy.attachNewNode(encol)
	ecs=CollisionSphere(0,0,0,2)
	encolpath.setPos(0,0,1)
	encolpath.node().addSolid(ecs)
	encolpath.show()
	self.enemy.reparentTo(render)
	self.enemy.setTag('instance',str(i))	
	i+=1
	return task.again

changing the getEntry in combat from 0 to 1 cuases a fatal error, so i know the combat method is called, the problem must be in the enemy code somewhere.
it also tells me the collisionSegments collidiing isnt the problem, because that would mean the enemy is collision 1 instead of 0, and 1 doesnt exist

and the code that is called after combat method:

def damage(self,object,type):
	global xp
	if(type==1):
	  object.destroy()
	  xp+=50  
	  xpcounter.setText(str(xp))

This, I think, is the problem to be solved.

As I recall, collision objects can be given bitmasks - values that determine which objects they may or may not be tested against. By default, I believe that collision objects added to a traverser will test against all other collision objects in the scene; bitmasks allow us to be a little more selective.

I suggest reading this page; then try setting the “into” collision mask for both of your segments to 0.

Not necessarily, I don’t think: if it’s happening before your segments reach an enemy, then you should get a collision that has only one entry, that being the problematic collision between segments. If there were an enemy involved, I’d imagine that you’d have two entries: one for the enemy, and one for the segment.

I suspect that if the segments weren’t colliding you wouldn’t be seeing these callbacks until you approached an enemy.

well, im quite sure the enemy collided, because the collisionsphere is visible and i changed the distance the segment goes to 100. (and i was standing next to the enemy, or the neutral thingy i will replace with an enemy)

well, the error is gone now, but still nothing happens. could you help me with that too?

Hmm… Going back over your code, I see only one call to “traverse()”, and that before you add the segments to your traverser.

In particular, you don’t seem to be calling it when you attempt to pick or combat objects, as I seem to recall is intended (and I don’t believe that it’s called for or useful before you add the segments to your traverser.

where should i put it then?

where should i put it then?

Directly before both instances of “if(handler.getNumEntries()>0):”, I believe: traverse is, if I’m not much mistaken, the call that instructs the traverser to perform collision detection.

that gives an error about the name not being defined.
should i make it self.traverser?

still nothing

i think the traverser.traverse was fine where it was…

from the manual…

Hmm… You’re right, by the looks of that (although I’m pretty confident that the call to “traverse” before the addition of the segments to the traverser has no useful effect). I was going by this page, where they appear to be using a traverser that has not been assigned to base.cTrav.

On the other hand, (and which is a side-note, really, and not likely your problem), do you really want the traversal to be run every frame, or only when you click / press “e”? You might find it more efficient to not assign your traverser to base.cTrav and to call “traverse” yourself.

However, back to your issue, perhaps it would help if we checked on those collisions. Have you tried (since the error went away) placing printouts in your combat or pick methods to see whether the methods are ever being called, and if so how far into them the execution reaches? Have you tried printing out the entries returned, if any? The results of that might help us.

I also don’t see anything that sets your segments to follow the mouse position. If you go to the page that I linked above, you should see a mention of “pickerRay.setFromLens”, which might help. However, if you aren’t moving your objects yet this may not have much effect.

Finally, perhaps visualising collisions might help: try adding “traverser.showCollisions(render)”, after creation of the traverser, I think.

wel, they arent following the mouse, because they arent supposed to. every frame i set the mouse position to the center of the screen. i feel it smoothens the turning of the character (wich is done by mouse position)

the collsision between the battleray and the enemy is definately happening: a big red square and a line.

i just dont know what goes wrong.

any ideas on how to print the info we need?
not really looked into that

The warning you were getting about invalid collision attempts between the two CollisionSegments is just a warning; since they can’t collide with each other it doesn’t hurt anything. But in general use the bitmasks to prevent different collision tasks from interfering. For example, say you have a collision sphere for doing wall collisions and a collision segment for checking the ground; you might want to mask those so the segment doesn’t collide with the sphere.

I think you do need to have a call to traverse() before checking the queue; in your case, in each of the keyboard event handlers. Yes, you should make it self.traverser; and maybe don’t assign it to base.cTrav, that one gets called every frame which you don’t need. You just need to traverse in response to a key press.

BTW be careful with resetting the mouse position, it has very different behavior on different platforms (well, specifically OSX), so try and get someone with a mac to test your code to verify what you’re doing works.

You’re seeing the line and red square if you turned on collision debugging, but it doesn’t necessarily mean anything gets into your queue.

Do you only have one enemy? if you call spawnmonster() multiple times, each one overwrites self.enemy.

Try making a list instead (self.enemies[]) and appending each enemy to it. I have this vague recollection that this is important with Actor objects to keep persistence.

if !work:
postAllCode()