[SOLVED] Temporary attack hitboxes

Post Reply
Waschmaschine
Posts: 10
Joined: Wed Apr 15, 2015 9:50 pm

[SOLVED] Temporary attack hitboxes

Post by Waschmaschine »

Hello everyone,
I am currently using Ogre3D and Bullet to create a 3D game. I do not have a lot of Bullet experience, although.

Situation: I have two characters right now, which are both represented by capsules physically.

Here's an unnecessary screenshot:

Image

So let's say the player wants to attack the enemy penguin. My idea was to temporarily spawn an attack hitbox like Marth's red circles right here:

Image

How can you accomplish that in Bullet?
Do I just temporarily spawn some static btRigidBodies? But how can I register "the hit" in my Enemy class, where I control the rigid body?
I want to maybe change the penguin's animation to a hit animation. Also, can you recommend me any resources to learn more about Bullet? Thanks. :)
Last edited by Waschmaschine on Tue May 26, 2015 6:10 pm, edited 1 time in total.
xexuxjy
Posts: 225
Joined: Wed Jan 07, 2009 11:43 am
Location: London

Re: Temporary attack hitboxes

Post by xexuxjy »

Probably best thing to use is ghost collision objects as you don't really want them to effect the physics of the world. If you look at the ghost demo you'll see an example, including how you might use a collision callback or similar. You can use the callback to trigger situations in your game . e.g. you can test for a hit between the ghost hitboxes and your entity and send a 'message' to the entity to say it's been hit, and by what. You can them have some logic to play an animation, take damage etc.
Waschmaschine
Posts: 10
Joined: Wed Apr 15, 2015 9:50 pm

Re: Temporary attack hitboxes

Post by Waschmaschine »

xexuxjy wrote:Probably best thing to use is ghost collision objects as you don't really want them to effect the physics of the world. If you look at the ghost demo you'll see an example, including how you might use a collision callback or similar. You can use the callback to trigger situations in your game . e.g. you can test for a hit between the ghost hitboxes and your entity and send a 'message' to the entity to say it's been hit, and by what. You can them have some logic to play an animation, take damage etc.
Thank you for your response!
Here's what I did:

Code: Select all

// Create hitbox for attack
_phyAttackGhostObject = new btPairCachingGhostObject();
_phyAttackGhostObject->setCollisionShape(  new btSphereShape(0.5) );
_phyAttackGhostObject->setCollisionFlags(btCollisionObject::CF_NO_CONTACT_RESPONSE);
_phyAttackGhostObject->setUserPointer(this);
_phyWorld->getBroadphase()->getOverlappingPairCache()->setInternalGhostPairCallback(new btGhostPairCallback());  
-Set the UserPointer in my Enemy class
-Check for collision after simulation step. ( :?: Shouldn't this be done by the callback? :?: ) Code: http://www.bulletphysics.org/mediawiki- ... hostObject
-Added the line

Code: Select all

collisionEvent( manifold->getBody0(), manifold->getBody1() );
to the wiki code.

Code: Select all

void Player::collisionEvent(const btCollisionObject* pBody0, const btCollisionObject * pBody1){
	btCollisionObject* ghostObj = static_cast<btCollisionObject*>(_phyAttackGhostObject);
	if (ghostObj == pBody0){
		if (pBody1->getCollisionFlags() == btCollisionObject::CF_CHARACTER_OBJECT &&
			pBody1 != _phyGhostObject){
			Enemy* enemy = static_cast<Enemy*>(pBody1->getUserPointer());
			enemy->wasHit();
		}
	} else {
		if (pBody0->getCollisionFlags() == btCollisionObject::CF_CHARACTER_OBJECT &&
			pBody0 != _phyGhostObject){
			Enemy* enemy = static_cast<Enemy*>(pBody0->getUserPointer());
			enemy->wasHit();
		}
	}
}
-Set the world transform of the ghost object to be infront of the player when I attack, add it temporarily to the world.

And this works! Kind of, though:
Image
The sphere is not touching the left wall, but it registers a hit with my setup. It does not touch the floor!
Any advice for this or the callback?
xexuxjy
Posts: 225
Joined: Wed Jan 07, 2009 11:43 am
Location: London

Re: Temporary attack hitboxes

Post by xexuxjy »

Hmm, tricky to see from that. But I couldn't see anything obviously wrong.
Would you expect the sphere to intersect the floor based on it's size and the offset from the player you're generating it at? How far away from the wall do you have to be before it stops generating 'false' collisions?
Waschmaschine
Posts: 10
Joined: Wed Apr 15, 2015 9:50 pm

Re: Temporary attack hitboxes

Post by Waschmaschine »

xexuxjy wrote:Hmm, tricky to see from that. But I couldn't see anything obviously wrong.
Would you expect the sphere to intersect the floor based on it's size and the offset from the player you're generating it at?
No, when I move further away from the wall I do not get a collision, not even with the floor.
xexuxjy wrote:How far away from the wall do you have to be before it stops generating 'false' collisions?
The end of the wall is located at x=17.
This generates hits:

Code: Select all

hitboxTrans.setOrigin(btVector3(17.76135, 1.5, 0));
This does not:

Code: Select all

hitboxTrans.setOrigin(btVector3(17.7617, 1.5, 0));
With a radius of 0.5, I would expect hits at around 17.5, but this seems to be ca. 0.2615 units off.
Again, here's a screen of a collision. Note that I decoupled it from the player's position.
Image

Edit: I tried it again with a radius of 1.0, getting the same offset.
Bonus question: Why is

Code: Select all

   _phyWorld->getBroadphase()->getOverlappingPairCache()->setInternalGhostPairCallback(new btGhostPairCallback());   
necessary? I am using another GhostObject for the btKinematicCharacterController. If I comment this line out, my character is falling through the floor. And why do I only need to call it like this once when I got two ghost objects?
xexuxjy
Posts: 225
Joined: Wed Jan 07, 2009 11:43 am
Location: London

Re: Temporary attack hitboxes

Post by xexuxjy »

Memories a bit flakey on this but :

You set-up a single btGhostPairCallback (only once) to allow the broad-phase to pass on the results of it's collision tests to the ghost objects directly. The ghost objects are a bit different in that they remember the colliding pairs (rather than just having the impulses applied to them as the result of the collisions) . This is handy for things like triggers,sensors and the like.

If you remove that line then the code in your kinematic controller then it doesn't have any information it needs to keep itself off the ground , walk forward, step up and so on (I've glanced back over the code and when you provide the controller with a ghost shape it uses a special case for it's convexSweepTest that relies on the ghost object holding it's overlapping pairs).

Of course none of this solves your real problem of the collisions appearing in the 'wrong' place. It may be worth turning on the AABB's for visualisation as it looks like ghosts just use the AABB and it may help to show any discrepancies (though I'm not sure how the AABB can be that much out from the collision sphere....)
Waschmaschine
Posts: 10
Joined: Wed Apr 15, 2015 9:50 pm

Re: Temporary attack hitboxes

Post by Waschmaschine »

Thanks for clearing that up.
xexuxjy wrote: Of course none of this solves your real problem of the collisions appearing in the 'wrong' place. It may be worth turning on the AABB's for visualisation as it looks like ghosts just use the AABB and it may help to show any discrepancies (though I'm not sure how the AABB can be that much out from the collision sphere....)
How do I turn on the AABBs? This made me realize that the error source could be on the side of my DebugDrawer implementation, i.e. BtOgre.

Still, I debugged my code using this.

Code: Select all

btTransform t = _phyAttackGhostObject->getWorldTransform();
btVector3 v1,v2;
_phyAttackGhostObject->getCollisionShape()->getAabb(t,v1,v2);
std::cout << v1.x() << " " << v1.y() << " " << v1.z() << std::endl;
std::cout << v2.x() << " " << v2.y() << " " << v2.z() << std::endl;
Output:
17.2614 1 -0.5
18.2614 2 0.5

Again, I used the hit generating distance with the wall ending at x=17 and a radius of 0.5:

Code: Select all

btTransform hitboxTrans;
hitboxTrans.setIdentity();
hitboxTrans.setOrigin(btVector3(17.76135, 1.5, 0));
_phyAttackGhostObject->setWorldTransform(hitboxTrans);
The output seems OK because the difference in each dimension of the AABB is double the radius.
xexuxjy
Posts: 225
Joined: Wed Jan 07, 2009 11:43 am
Location: London

Re: Temporary attack hitboxes

Post by xexuxjy »

If you're using debug drawer you can include : DBG_DrawAabb in your draw mask .
If your project can be packaged up at all, i'd be happy to try and debug why you're getting those results.
Waschmaschine
Posts: 10
Joined: Wed Apr 15, 2015 9:50 pm

Re: Temporary attack hitboxes

Post by Waschmaschine »

xexuxjy wrote:If you're using debug drawer you can include : DBG_DrawAabb in your draw mask .
If your project can be packaged up at all, i'd be happy to try and debug why you're getting those results.
I've hacked together a minmal example:
http://pastebin.com/drCKCKrL

Additional include directories:
$(BULLET_ROOT)\src;

Additional library directories:
$(BULLET_ROOT)\lib\Debug;

Input:
BulletDynamics_Debug.lib;BulletCollision_Debug.lib;LinearMath_Debug.lib;
xexuxjy
Posts: 225
Joined: Wed Jan 07, 2009 11:43 am
Location: London

Re: Temporary attack hitboxes

Post by xexuxjy »

Thanks.

I've had a quick run through.
with position at 1.27 then the broadphase is generating a provisional overlap (probably down to the way the floats are quantized), with 1.30 then there is no overlap generated.

to get round this issue, you can change your checkCollision function as follows :

Code: Select all

for (int p = 0; p < manifold->getNumContacts(); p++){
    const btManifoldPoint&pt = manifold->getContactPoint(p);

    if (pt.getDistance() < 0.f)
    {
	// TODO: ADD STUFF
	collisionEvent(manifold->getBody0(), manifold->getBody1());

	const btVector3& ptA = pt.getPositionWorldOnA();
	const btVector3& ptB = pt.getPositionWorldOnB();
	const btVector3& normalOnB = pt.m_normalWorldOnB;
	/// work here

    }
}
it will then not generate collisions for 1.27 or 1.3 , but will for 0.8
Waschmaschine
Posts: 10
Joined: Wed Apr 15, 2015 9:50 pm

Re: Temporary attack hitboxes

Post by Waschmaschine »

xexuxjy wrote:Thanks.

I've had a quick run through.
with position at 1.27 then the broadphase is generating a provisional overlap (probably down to the way the floats are quantized), with 1.30 then there is no overlap generated.

to get round this issue, you can change your checkCollision function as follows :

Code: Select all

for (int p = 0; p < manifold->getNumContacts(); p++){
    const btManifoldPoint&pt = manifold->getContactPoint(p);

    if (pt.getDistance() < 0.f)
    {
	// TODO: ADD STUFF
	collisionEvent(manifold->getBody0(), manifold->getBody1());

	const btVector3& ptA = pt.getPositionWorldOnA();
	const btVector3& ptB = pt.getPositionWorldOnB();
	const btVector3& normalOnB = pt.m_normalWorldOnB;
	/// work here

    }
}
it will then not generate collisions for 1.27 or 1.3 , but will for 0.8
Thank you, we're done here. I guess I owe you a beverage of your liking. :D
xexuxjy
Posts: 225
Joined: Wed Jan 07, 2009 11:43 am
Location: London

Re: [SOLVED] Temporary attack hitboxes

Post by xexuxjy »

Heh, np. good luck with the rest of your project.
Post Reply