Start work to have trigger items, and for now use them to play a sound when crossing the force fields in overworld. This is WIP.
git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/trunk@10646 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
parent
a5bc671821
commit
72b409344e
@ -90,8 +90,8 @@
|
||||
<powerup collect-mode="new"/>
|
||||
<!-- time: How long a switch is being effective.
|
||||
items for each item list the index of the item it is switched with.
|
||||
Order: item, banana, big-nitro, small-nitro, bubble-bum -->
|
||||
<switch time="5" items="1 0 4 4 2"/>
|
||||
Order: giftbox, banana, big-nitro, small-nitro, bubble-bum, trigger -->
|
||||
<switch time="5" items="1 0 4 4 2 5"/>
|
||||
|
||||
<!-- How often bubble gum get driven over before it disappears. -->
|
||||
<bubble-gum disappear-counter="1"/>
|
||||
|
@ -97,7 +97,7 @@ void STKConfig::load(const std::string &filename)
|
||||
|
||||
if(m_switch_items.size()!=Item::ITEM_LAST-Item::ITEM_FIRST+1)
|
||||
{
|
||||
fprintf(stderr,"No item switches defined in stk_config");
|
||||
fprintf(stderr,"Wrong number of item switches defined in stk_config");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
|
@ -33,10 +33,13 @@
|
||||
Item::Item(ItemType type, const Vec3& xyz, const Vec3& normal,
|
||||
scene::IMesh* mesh, scene::IMesh* lowres_mesh, unsigned int item_id)
|
||||
{
|
||||
assert(type != ITEM_TRIGGER); // use other constructor for that
|
||||
|
||||
setType(type);
|
||||
m_event_handler = NULL;
|
||||
m_xyz = xyz;
|
||||
m_deactive_time = 0;
|
||||
m_distance_2 = 0.8f;
|
||||
// Sets heading to 0, and sets pitch and roll depending on the normal. */
|
||||
m_original_hpr = Vec3(0, normal);
|
||||
m_item_id = item_id;
|
||||
@ -48,6 +51,7 @@ Item::Item(ItemType type, const Vec3& xyz, const Vec3& normal,
|
||||
: -1 ;
|
||||
m_original_mesh = mesh;
|
||||
m_original_lowmesh = lowres_mesh;
|
||||
m_listener = NULL;
|
||||
|
||||
LODNode* lodnode = new LODNode("item",
|
||||
irr_driver->getSceneManager()->getRootSceneNode(),
|
||||
@ -81,6 +85,34 @@ Item::Item(ItemType type, const Vec3& xyz, const Vec3& normal,
|
||||
m_node->grab();
|
||||
} // Item
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/** \brief Constructor to create a trigger item.
|
||||
* Trigger items are invisible and can be used to trigger a behavior when
|
||||
* approaching a point.
|
||||
*/
|
||||
Item::Item (const Vec3& xyz, float distance, TriggerItemListener* trigger,
|
||||
unsigned int item_id)
|
||||
{
|
||||
m_type = ITEM_TRIGGER;
|
||||
m_event_handler = NULL;
|
||||
m_xyz = xyz;
|
||||
m_deactive_time = 0;
|
||||
// Sets heading to 0, and sets pitch and roll depending on the normal. */
|
||||
m_original_hpr = Vec3(0, 0, 0);
|
||||
m_item_id = item_id;
|
||||
m_original_type = ITEM_NONE;
|
||||
m_collected = false;
|
||||
m_time_till_return = 0.0f; // not strictly necessary, see isCollected()
|
||||
m_disappear_counter = -1;
|
||||
m_original_mesh = NULL;
|
||||
m_original_lowmesh = NULL;
|
||||
m_node = NULL;
|
||||
m_listener = trigger;
|
||||
m_rotate = false;
|
||||
m_distance_2 = distance*distance;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Sets the type of this item, but also derived values, e.g. m_rotate.
|
||||
* (bubblegums do not return).
|
||||
@ -99,6 +131,9 @@ void Item::setType(ItemType type)
|
||||
*/
|
||||
void Item::switchTo(ItemType type, scene::IMesh *mesh, scene::IMesh *lowmesh)
|
||||
{
|
||||
// triggers should not be switched
|
||||
if (m_type == ITEM_TRIGGER) return;
|
||||
|
||||
m_original_type = m_type;
|
||||
setType(type);
|
||||
|
||||
@ -118,6 +153,9 @@ void Item::switchTo(ItemType type, scene::IMesh *mesh, scene::IMesh *lowmesh)
|
||||
*/
|
||||
void Item::switchBack()
|
||||
{
|
||||
// triggers should not be switched
|
||||
if (m_type == ITEM_TRIGGER) return;
|
||||
|
||||
// If the item is not switched, do nothing. This can happen if a bubble
|
||||
// gum is dropped while items are switched - when switching back, this
|
||||
// bubble gum has no original type.
|
||||
@ -144,8 +182,11 @@ void Item::switchBack()
|
||||
*/
|
||||
Item::~Item()
|
||||
{
|
||||
irr_driver->removeNode(m_node);
|
||||
m_node->drop();
|
||||
if (m_node != NULL)
|
||||
{
|
||||
irr_driver->removeNode(m_node);
|
||||
m_node->drop();
|
||||
}
|
||||
} // ~Item
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -165,7 +206,10 @@ void Item::reset()
|
||||
m_original_type = ITEM_NONE;
|
||||
}
|
||||
|
||||
m_node->setScale(core::vector3df(1,1,1));
|
||||
if (m_node != NULL)
|
||||
{
|
||||
m_node->setScale(core::vector3df(1,1,1));
|
||||
}
|
||||
} // reset
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -194,20 +238,26 @@ void Item::update(float dt)
|
||||
if(m_time_till_return<0)
|
||||
{
|
||||
m_collected=false;
|
||||
m_node->setScale(core::vector3df(1,1,1));
|
||||
|
||||
|
||||
if (m_node != NULL)
|
||||
{
|
||||
m_node->setScale(core::vector3df(1,1,1));
|
||||
}
|
||||
} // time till return <0 --> is fully visible again
|
||||
else if ( m_time_till_return <=1.0f )
|
||||
{
|
||||
// Make it visible by scaling it from 0 to 1:
|
||||
m_node->setVisible(true);
|
||||
m_node->setScale(core::vector3df(1,1,1)*(1-m_time_till_return));
|
||||
if (m_node != NULL)
|
||||
{
|
||||
// Make it visible by scaling it from 0 to 1:
|
||||
m_node->setVisible(true);
|
||||
m_node->setScale(core::vector3df(1,1,1)*(1-m_time_till_return));
|
||||
}
|
||||
} // time till return < 1
|
||||
} // if collected
|
||||
else
|
||||
{ // not m_collected
|
||||
|
||||
if(!m_rotate) return;
|
||||
if(!m_rotate || m_node == NULL) return;
|
||||
// have it rotate
|
||||
Vec3 rotation(0, dt*M_PI, 0);
|
||||
core::vector3df r = m_node->getRotation();
|
||||
@ -244,7 +294,15 @@ void Item::collected(const Kart *kart, float t)
|
||||
// Note if the time is negative, in update the m_collected flag will
|
||||
// be automatically set to false again.
|
||||
m_time_till_return = t;
|
||||
m_node->setVisible(false);
|
||||
if (m_node != NULL)
|
||||
{
|
||||
m_node->setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_listener != NULL)
|
||||
{
|
||||
m_listener->onTriggerItemApproached(this);
|
||||
}
|
||||
|
||||
if (dynamic_cast<ThreeStrikesBattle*>(World::getWorld()) != NULL)
|
||||
|
@ -34,9 +34,21 @@ using namespace irr;
|
||||
#include "utils/no_copy.hpp"
|
||||
|
||||
class LODNode;
|
||||
class Item;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* \ingroup items
|
||||
* \brief Listener class to go with Items of type ITEM_TRIGGER
|
||||
*/
|
||||
class TriggerItemListener
|
||||
{
|
||||
public:
|
||||
virtual ~TriggerItemListener() {}
|
||||
virtual void onTriggerItemApproached(Item* who) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* \ingroup items
|
||||
*/
|
||||
@ -56,7 +68,11 @@ public:
|
||||
ITEM_NITRO_BIG,
|
||||
ITEM_NITRO_SMALL,
|
||||
ITEM_BUBBLEGUM,
|
||||
ITEM_LAST = ITEM_BUBBLEGUM,
|
||||
/** An invisible item that can be used to trigger some behavior when
|
||||
* approaching a point
|
||||
*/
|
||||
ITEM_TRIGGER,
|
||||
ITEM_LAST = ITEM_TRIGGER,
|
||||
ITEM_COUNT,
|
||||
ITEM_NONE
|
||||
};
|
||||
@ -115,9 +131,18 @@ private:
|
||||
int m_disappear_counter;
|
||||
|
||||
void setType(ItemType type);
|
||||
|
||||
/** callback used if type == ITEM_TRIGGER */
|
||||
TriggerItemListener* m_listener;
|
||||
|
||||
/** square distance at which item is collected */
|
||||
float m_distance_2;
|
||||
|
||||
public:
|
||||
Item (ItemType type, const Vec3& xyz, const Vec3& normal,
|
||||
scene::IMesh* mesh, scene::IMesh* lowres_mesh, unsigned int item_id);
|
||||
Item (const Vec3& xyz, float distance, TriggerItemListener* trigger,
|
||||
unsigned int item_id);
|
||||
virtual ~Item ();
|
||||
void update (float delta);
|
||||
virtual void collected(const Kart *kart, float t=2.0f);
|
||||
@ -130,7 +155,7 @@ public:
|
||||
bool hitKart (Kart* kart ) const
|
||||
{
|
||||
return (m_event_handler!=kart || m_deactive_time <=0) &&
|
||||
(kart->getXYZ()-m_xyz).length2()<0.8f;
|
||||
(kart->getXYZ()-m_xyz).length2()<m_distance_2;
|
||||
} // hitKart
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
@ -110,7 +110,7 @@ void ItemManager::loadDefaultItems()
|
||||
// it is implemented as one, and so loaded here, too.
|
||||
static const std::string item_names[] = {"bonus-box", "banana",
|
||||
"nitro-big", "nitro-small",
|
||||
"bubblegum" };
|
||||
"bubblegum", "trigger" };
|
||||
const std::string file_name = file_manager->getDataFile("items.xml");
|
||||
const XMLNode *root = file_manager->createXMLTree(file_name);
|
||||
for(unsigned int i=Item::ITEM_FIRST; i<=Item::ITEM_LAST; i++)
|
||||
@ -122,6 +122,10 @@ void ItemManager::loadDefaultItems()
|
||||
node->get("model", &model_filename);
|
||||
node->get("lowmodel", &lowres_model_filename);
|
||||
}
|
||||
else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
scene::IMesh *mesh = irr_driver->getAnimatedMesh(model_filename);
|
||||
scene::IMesh *lowres_mesh = NULL;
|
||||
@ -182,6 +186,29 @@ Item* ItemManager::newItem(Item::ItemType type, const Vec3& xyz,
|
||||
return item;
|
||||
} // newItem
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Creates a new trigger item.
|
||||
* \param xyz Position of the item.
|
||||
*/
|
||||
Item* ItemManager::newItem(const Vec3& xyz, float distance, TriggerItemListener* listener)
|
||||
{
|
||||
// Find where the item can be stored in the index list: either in a
|
||||
// previously deleted entry, otherwise at the end.
|
||||
int index = -1;
|
||||
for(index=m_all_items.size()-1; index>=0 && m_all_items[index]; index--) {}
|
||||
|
||||
if(index==-1) index = m_all_items.size();
|
||||
Item* item;
|
||||
item = new Item(xyz, distance, listener, index);
|
||||
|
||||
if(index<(int)m_all_items.size())
|
||||
m_all_items[index] = item;
|
||||
else
|
||||
m_all_items.push_back(item);
|
||||
|
||||
return item;
|
||||
} // newItem
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Set an item as collected.
|
||||
* This function is called on the server when an item is collected, or on the
|
||||
|
@ -62,6 +62,7 @@ public:
|
||||
void loadDefaultItems();
|
||||
Item* newItem (Item::ItemType type, const Vec3& xyz,
|
||||
const Vec3 &normal, Kart* parent=NULL);
|
||||
Item* newItem (const Vec3& xyz, float distance, TriggerItemListener* listener);
|
||||
void update (float delta);
|
||||
void checkItemHit (Kart* kart);
|
||||
void cleanup ();
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "graphics/irr_driver.hpp"
|
||||
#include "io/file_manager.hpp"
|
||||
#include "io/xml_node.hpp"
|
||||
#include "items/item_manager.hpp"
|
||||
#include "modes/world.hpp"
|
||||
#include "tracks/track.hpp"
|
||||
|
||||
@ -56,6 +57,12 @@ TrackObject::TrackObject(const XMLNode &xml_node)
|
||||
|
||||
xml_node.get("lod_group", &m_lod_group);
|
||||
|
||||
/** For sound effects */
|
||||
bool trigger_when_near = false;
|
||||
|
||||
/** For sound effects */
|
||||
float trigger_distance = 1.0f;
|
||||
|
||||
// FIXME: at this time sound emitters are just disabled in multiplayer
|
||||
// otherwise the sounds would be constantly heard
|
||||
if (sound.size() > 0 && race_manager->getNumLocalPlayers() == 1)
|
||||
@ -65,7 +72,18 @@ TrackObject::TrackObject(const XMLNode &xml_node)
|
||||
float volume = 1.0;
|
||||
xml_node.get("volume", &volume );
|
||||
|
||||
SFXBuffer* buffer = new SFXBuffer(file_manager->getModelFile(sound),
|
||||
xml_node.get("play-when-near", &trigger_when_near);
|
||||
|
||||
xml_node.get("distance", &trigger_distance);
|
||||
|
||||
// first try track dir, then global dir
|
||||
std::string soundfile = file_manager->getModelFile(sound);
|
||||
if (!file_manager->fileExists(soundfile))
|
||||
{
|
||||
soundfile = file_manager->getSFXFile(sound);
|
||||
}
|
||||
|
||||
SFXBuffer* buffer = new SFXBuffer(soundfile,
|
||||
true /* positional */,
|
||||
rolloff,
|
||||
volume);
|
||||
@ -75,8 +93,11 @@ TrackObject::TrackObject(const XMLNode &xml_node)
|
||||
if (m_sound != NULL)
|
||||
{
|
||||
m_sound->position(m_init_xyz);
|
||||
m_sound->setLoop(true);
|
||||
m_sound->play();
|
||||
if (!trigger_when_near)
|
||||
{
|
||||
m_sound->setLoop(true);
|
||||
m_sound->play();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -91,6 +112,11 @@ TrackObject::TrackObject(const XMLNode &xml_node)
|
||||
{
|
||||
m_node = NULL;
|
||||
m_mesh = NULL;
|
||||
|
||||
if (trigger_when_near)
|
||||
{
|
||||
item_manager->newItem(m_init_xyz, trigger_distance, this);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -261,3 +287,12 @@ void TrackObject::update(float dt)
|
||||
{
|
||||
} // update
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/** Implement callback from TriggerItemListener. Not used by all track objects. */
|
||||
void TrackObject::onTriggerItemApproached(Item* who)
|
||||
{
|
||||
if (m_sound != NULL && m_sound->getStatus() == SFXManager::SFX_STOPPED)
|
||||
{
|
||||
m_sound->play();
|
||||
}
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ namespace irr
|
||||
}
|
||||
using namespace irr;
|
||||
|
||||
#include "items/item.hpp"
|
||||
#include "utils/no_copy.hpp"
|
||||
#include "utils/vec3.hpp"
|
||||
#include <string>
|
||||
@ -40,7 +41,8 @@ class SFXBase;
|
||||
* might also have a skeletal animation. This is used by objects that
|
||||
* have an IPO animation, as well as physical objects.
|
||||
*/
|
||||
class TrackObject : public scene::IAnimationEndCallBack, public NoCopy
|
||||
class TrackObject : public scene::IAnimationEndCallBack, public NoCopy,
|
||||
public TriggerItemListener
|
||||
{
|
||||
//public:
|
||||
// The different type of track objects: physical objects, graphical
|
||||
@ -115,6 +117,8 @@ public:
|
||||
|
||||
const std::string& getLodGroup() const { return m_lod_group; }
|
||||
|
||||
virtual void onTriggerItemApproached(Item* who);
|
||||
|
||||
}; // TrackObject
|
||||
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user