shooting on terrain with collisions
shooting on terrain with collisions
Hey all, I could use a little help figuring out how to shoot on terrain. I've got the code form the techdemo working (sort of).
I have three problems:
First, when I shoot into the air (or not at the terrain), I can't see my shot. Well, I can initially because it starts in front of my nose, but I don't see it fly away like it should. I noticed that it does this on the techdemo as well.
Second, when shooting at the terrain, it's like the shot never collides with the terrain, but just keeps flying through.
Third, when I shoot multiple times, my audiere stream for the shooting sound won't play until the current sound is done playing.
Can anyone give me a little help? Feel free to point out the obvious as I'm sure it's something easy that I overlooked...
Thanks!
Dopyiii
I have three problems:
First, when I shoot into the air (or not at the terrain), I can't see my shot. Well, I can initially because it starts in front of my nose, but I don't see it fly away like it should. I noticed that it does this on the techdemo as well.
Second, when shooting at the terrain, it's like the shot never collides with the terrain, but just keeps flying through.
Third, when I shoot multiple times, my audiere stream for the shooting sound won't play until the current sound is done playing.
Can anyone give me a little help? Feel free to point out the obvious as I'm sure it's something easy that I overlooked...
Thanks!
Dopyiii
I thought you might want some code instead of reading my mind Here's the (probably very familiar) code that I'm using (if you need something else let me know):
I don't remember making any changes to this code. I think that the only real difference is that I'm using an ITerrainSceneNode (here it's called "selector") instead of the Quake level node stuff that's used in the demo.
Right off, I see that I should probably put Impacts in my class, not just in this function...
I appreciate the help!
Code: Select all
void View::shoot()
{
scene::ISceneManager* sm = device->getSceneManager();
scene::ICameraSceneNode* camera = sm->getActiveCamera();
core::array<SParticleImpact> Impacts;
if (!camera || !selector)
return;
SParticleImpact imp;
imp.when = 0;
// get line of camera
core::vector3df start = camera->getPosition();
core::vector3df end = (camera->getTarget() - start);
end.normalize();
start += end*5.0f;
end = start + (end * camera->getFarValue());
core::triangle3df triangle;
core::line3d<f32> line(start, end);
// get intersection point with map
if (sm->getSceneCollisionManager()->getCollisionPoint(line, selector, end, triangle))
{
// collides with wall
core::vector3df out = triangle.getNormal();
out.setLength(0.03f);
imp.when = 1;
imp.outVector = out;
imp.pos = end;
}
else
{
// doesnt collide with wall
end = (camera->getTarget() - start);
end.normalize();
end = start + (end * 1000);
}
// create fire ball
scene::ISceneNode* node = 0;
node = sm->addBillboardSceneNode(0,
core::dimension2d<f32>(25,25), start);
node->setMaterialFlag(video::EMF_LIGHTING, false);
node->setMaterialTexture(0, device->getVideoDriver()->getTexture("../media/fireball.bmp"));
node->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR);
f32 length = (f32)(end - start).getLength();
const f32 speed = 0.9f;
u32 time = (u32)(length / speed);
scene::ISceneNodeAnimator* anim = 0;
// set flight line
anim = sm->createFlyStraightAnimator(start, end, time);
node->addAnimator(anim);
anim->drop();
anim = sm->createDeleteAnimator(time);
node->addAnimator(anim);
anim->drop();
if (imp.when)
{
// create impact note
imp.when = device->getTimer()->getTime() + (time - 100);
Impacts.push_back(imp);
}
if(sfx)
{
attack->play();
}
}
Right off, I see that I should probably put Impacts in my class, not just in this function...
I appreciate the help!
yeh, ive noticed the collision too. i think it has something to do with the terrain and getfarpoint
reason: it sends a line through the terrain at the far point. however, there is no far point if the camera is dealing with with the skybox, so the far point is set to the cam position, and that will be right at the veiwpoint.
the way to solve this is to not use the skybox scene node, or use some other way of getting the far point
reason: it sends a line through the terrain at the far point. however, there is no far point if the camera is dealing with with the skybox, so the far point is set to the cam position, and that will be right at the veiwpoint.
the way to solve this is to not use the skybox scene node, or use some other way of getting the far point
I'll have to test this code out, I've never done collisions with projectiles like this, I've always checked possibles collision each render, to handle moving objects. What you're doing will only work for colliding with whats in the path of the projectile at the time it's fired.
From what I can see, with a quick glance over the code, it should work. You're selector is being properly initialized, right?
From what I can see, with a quick glance over the code, it should work. You're selector is being properly initialized, right?
Okay, I knew it had to be something dumb... I just had to make my Impacts array a class member instead of a local variable.
I still haven't figured out the whole shooting in the air problem... I didn't think that the skybox would interfere with getting a far point. How else could I do it?
And I think I can fix the whole sound problem assuming that Audiere is thread safe - I can just put the play function in a new thread each time I shoot. That should work, shouldn't it? Does anyone do it differently?
Spintz, my selector's working fine. I have it doing my gravity for me. Also, I'm curious how you do your projectile collision. I think that I'd be better off using something a little more robust than this (since I will have dynamic objects crusing around in my game). Could you show me how you do it?
Thanks!
I still haven't figured out the whole shooting in the air problem... I didn't think that the skybox would interfere with getting a far point. How else could I do it?
And I think I can fix the whole sound problem assuming that Audiere is thread safe - I can just put the play function in a new thread each time I shoot. That should work, shouldn't it? Does anyone do it differently?
Spintz, my selector's working fine. I have it doing my gravity for me. Also, I'm curious how you do your projectile collision. I think that I'd be better off using something a little more robust than this (since I will have dynamic objects crusing around in my game). Could you show me how you do it?
Thanks!
For the Audiere sound, you could reset it before the next time you play so something like:
This works for me...
Code: Select all
mEffect->reset();
mEffect->setRepeat(Repeat);
mEffect->setVolume(Volume);
mEffect->play();
Well, what I did, was created a class for my projectiles ( bullets, rockets, etc. ) and they have an update function, which gets called every render with the time difference since the last render. I move the projectile based on it's speed and the time that has elapsed. First though, I calculate what it's new position would be, based on the time delta and it's speed and then check collision from it's current position to the new estimated position. If there's no collison, I update the position and move on to the next projectile, if there is a collision, you handle it appropriately.dopyiii wrote:Spintz, my selector's working fine. I have it doing my gravity for me. Also, I'm curious how you do your projectile collision. I think that I'd be better off using something a little more robust than this (since I will have dynamic objects crusing around in my game). Could you show me how you do it?
The sample code I have for this is from NX++, but you should get the concept from it and be able to port it to Irrlicht very easily.....
CRockets.h -
CRockets.cpp -
CRockets.h -
Code: Select all
#ifndef __CROCKETS_H__
#define __CROCKETS_H__
#include <nx++/irrlicht.h>
#include <nx++/NXRoot.h>
#include "CGameCore.h"
using namespace irr;
class CRockets
{
public:
CRockets ( );
~CRockets ( );
void addRocket ( f32 size, f32 speed, f32 ttl );
void update ( f32 timeDelta );
private:
struct CRocket
{
~CRocket ( )
{
if ( ParticleNode )
ParticleNode->remove ( );
if ( SceneNode )
SceneNode->remove ( );
}
scene::IAnimatedMeshSceneNode* SceneNode;
scene::IParticleSystemSceneNode* ParticleNode;
core::vector3df Direction;
float Speed;
f32 TTL;
};
core::list<CRocket*> Rockets;
scene::IAnimatedMesh* RocketMesh;
video::ITexture* TrailTexture;
gamecore::CGameCore* GameCore;
};
#endif // __CROCKETS_H__
Code: Select all
#include "CRockets.h"
#include "CHUD.h"
#include "CTargets.h"
#include "CExplosions.h"
#include "CNinja.h"
CRockets::CRockets ( ) : GameCore(gamecore::CGameCore::GetInstance()), RocketMesh(0), TrailTexture(0)
{
RocketMesh = GameCore->GetResourceManager()->getMesh ( "media/missile.x" );
RocketMesh->grab ( );
TrailTexture = GameCore->GetResourceManager()->getTexture ( "media/Particle.bmp" );
GameCore->GetVideoDriver ( )->makeColorKeyTexture(TrailTexture,core::position2d<s32>(0,0));
}
CRockets::~CRockets ( )
{
Rockets.clear ( );
RocketMesh->drop ( );
}
void CRockets::addRocket ( f32 size, f32 speed, f32 ttl )
{
core::line3d<f32> line =
GameCore->GetCollisionManager()->getRayFromScreenCoordinates(GameCore->GetCursorControl()->getPosition());
core::vector3df target;
core::triangle3df triangle;
if ( !GameCore->GetCollisionManager()->getCollisionPoint(line, GameCore->GetMetaSelector(), target, triangle ) )
{
target = line.end;
}
core::vector3df position;
core::vector3df angle = line.getYXangle ( );
position = GameCore->GetNinja()->getSceneNode()->getPosition();
position.Y += GameCore->GetNinja()->getSceneNode()->getBoundingBox().MaxEdge.Y - GameCore->GetNinja()->getSceneNode()->getBoundingBox().MinEdge.Y;
CRocket* rocket = new CRocket ( );
rocket->Direction = target - position;
rocket->Direction.normalize ( );
rocket->Speed = speed;
rocket->TTL = ttl;
rocket->SceneNode = GameCore->GetSceneManager ( )->addAnimatedMeshSceneNode ( RocketMesh );
rocket->SceneNode->setScale ( core::vector3df ( size, size, size ) );
rocket->SceneNode->setPosition ( position );
rocket->SceneNode->setRotation ( angle );
rocket->ParticleNode = GameCore->GetSceneManager ( )->addParticleSystemSceneNode ( false, 0 );
rocket->ParticleNode->setMode ( scene::EPSM_GLOBAL_EMITTER_LOCAL );
rocket->ParticleNode->setMaterialTexture ( 0, TrailTexture );
rocket->ParticleNode->setMaterialType ( video::EMT_TRANSPARENT_ADD_COLOR );
rocket->ParticleNode->setParticleSize ( core::dimension2d<f32> ( 1.0f, 1.0f ) );
core::vector3df direction = rocket->Direction;
direction /= 3.0f;
scene::IParticleEmitter* pe = rocket->ParticleNode->createPointEmitter ( direction, 2500,
2500, video::SColor ( 201, 255, 255, 255 ), video::SColor ( 201, 255, 255, 255),
800, 1000, 2 );
rocket->ParticleNode->setEmitter ( pe );
pe->drop ( );
Rockets.push_back ( rocket );
}
void CRockets::update ( f32 timeDelta )
{
core::line3d<f32> line;
core::triangle3df triangle;
core::vector3df intersection;
core::vector3df position;
core::list<CRocket*>::Iterator rocketsItTemp;
core::list<CRocket*>::Iterator rocketsIt = Rockets.begin ( );
while ( rocketsIt != Rockets.end ( ) )
{
position = (*rocketsIt)->SceneNode->getPosition ( );
position += (*rocketsIt)->Direction * ( timeDelta * (*rocketsIt)->Speed );
if ( GameCore->GetMetaSelector ( ) )
{
line.start = (*rocketsIt)->SceneNode->getPosition ( );
line.end = position;
if ( GameCore->GetCollisionManager ( )->getCollisionPoint (line,
GameCore->GetMetaSelector ( ), intersection, triangle ) )
{
rocketsItTemp = rocketsIt + 1;
delete (*rocketsIt);
Rockets.erase ( rocketsIt );
rocketsIt = rocketsItTemp;
// check to see if it colliding with a box
scene::ISceneNode* nodeHit = GameCore->GetCollisionManager ( )->getSceneNodeFromRayBB ( line );
if ( nodeHit )
if ( nodeHit->getID ( ) > 999 )
GameCore->GetTargets ( )->RemoveTargetById ( nodeHit->getID ( ) );
GameCore->GetExplosions ( )->addStandardExplosion ( intersection, core::dimension2d<f32>(7,6),
core::vector3df ( 0.0f, 0.0001f, 0.0f ), 50, 75,
video::SColor ( 225, 255, 0, 0 ), video::SColor ( 225, 255, 128, 0 ),
video::SColor ( 225, 0, 0, 0 ), 4000, 1000, 2500, 180, 3 );
//GameCore->GetExplosions ( )->addLargeExplosion ( 6, intersection, core::dimension2d<f32>(7,6),
// core::vector3df ( 0.0f, -0.003f, 0.0f ), 50, 75,
// video::SColor ( 225, 255, 0, 0 ), video::SColor ( 225, 255, 128, 0 ),
// video::SColor ( 225, 0, 0, 0 ), 4000, 1000, 1500, 45, 3 );
continue;
}
}
(*rocketsIt)->SceneNode->setPosition ( position );
(*rocketsIt)->ParticleNode->setPosition ( position );
(*rocketsIt)->TTL -= timeDelta;
if ( (*rocketsIt)->TTL <= 0 )
{
rocketsItTemp = rocketsIt + 1;
delete (*rocketsIt);
Rockets.erase ( rocketsIt );
rocketsIt = rocketsItTemp;
}
else
{
rocketsIt++;
}
}
}
Thanks for the code Spintz, but I'm too dumb to figure it out. Well, too dumb or too burned out by this project. Probably a little of both
One interesting thing that I found was that the techdemo way of shooting works fine if you have a collision with the map/terrain, whatever. But, if you don't (like shooting at the skybox, etc), then the animator actually moves backwards. I set the far value to be really big and when I shot at the skybox, sure enough it started at the far value and came back at me.
So, here's how I fixed it. In the if/else that gets the collisionPoint to test if it hits the map/terrain, in the else code I changed
to
Now, I can shoot blissfully off into space...
Of course, Spintz' way of doing stuff is probably better (okay, yeah, it IS better). If you get bored and want to translate Spintz' code into a generic "irrlicht only" code, that'd be super. But this quick and dirty method will work just fine for what I'm doing right now.
Thanks again for all of your help!
One interesting thing that I found was that the techdemo way of shooting works fine if you have a collision with the map/terrain, whatever. But, if you don't (like shooting at the skybox, etc), then the animator actually moves backwards. I set the far value to be really big and when I shot at the skybox, sure enough it started at the far value and came back at me.
So, here's how I fixed it. In the if/else that gets the collisionPoint to test if it hits the map/terrain, in the else code I changed
Code: Select all
end = (start - camera->getTarget() );
Code: Select all
end = (camera->getTarget() - start);
Of course, Spintz' way of doing stuff is probably better (okay, yeah, it IS better). If you get bored and want to translate Spintz' code into a generic "irrlicht only" code, that'd be super. But this quick and dirty method will work just fine for what I'm doing right now.
Thanks again for all of your help!
Ooops. Reverse - switch that. It was end = (camera->getTarget() - start); and is now end = (start - camera->getTarget() );:oops:
I know that many people have asked how to shoot (despite this code in the techdemo). I'm sure that all noobs (especially me) would appreciate your rewritten code
I'm not in any real rush, but I'll look forward to seeing it.
Thanks Spintz!
I know that many people have asked how to shoot (despite this code in the techdemo). I'm sure that all noobs (especially me) would appreciate your rewritten code
I'm not in any real rush, but I'll look forward to seeing it.
Thanks Spintz!