Add check trigger to replace item trigger

This commit is contained in:
Benau 2019-02-27 11:31:19 +08:00
parent fe4a9c5406
commit 9b4b283c4c
17 changed files with 191 additions and 123 deletions

View File

@ -211,8 +211,8 @@
<!-- time: How long a switch is being effective.
items for each item list the index of the item it is switched with.
Order: giftbox, banana, big-nitro, small-nitro, bubble-gum, nolok-bubble-gum,
easter egg, trigger-->
<switch time="5" items="1 0 4 4 2 2 6 7"/>
easter egg-->
<switch time="5" items="1 0 4 4 2 2 6"/>
<!-- disappear-counter: How often bubblegum gets driven over before it disappears.
shield-time: How long the bubblegum shield lasts

View File

@ -1,5 +1,5 @@
# Modify this file to change the last-modified date when you add/remove a file.
# This will then trigger a new cmake run automatically.
# This will then trigger a new cmake run automatically.
file(GLOB_RECURSE STK_HEADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.hpp")
file(GLOB_RECURSE STK_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.cpp")
file(GLOB_RECURSE STK_SHADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "data/shaders/*")

View File

@ -195,13 +195,10 @@ Item::Item(ItemType type, const Vec3& xyz, const Vec3& normal,
const AbstractKart *owner)
: ItemState(type, owner)
{
assert(type != ITEM_TRIGGER); // use other constructor for that
m_was_available_previously = true;
m_distance_2 = 1.2f;
initItem(type, xyz, normal);
m_graphical_type = getGrahpicalType();
m_listener = NULL;
LODNode* lodnode =
new LODNode("item", irr_driver->getSceneManager()->getRootSceneNode(),
@ -238,23 +235,6 @@ Item::Item(ItemType type, const Vec3& xyz, const Vec3& normal,
m_node->grab();
} // Item(type, xyz, normal, mesh, lowres_mesh)
//-----------------------------------------------------------------------------
/** \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)
: ItemState(ITEM_TRIGGER)
{
m_distance_2 = distance*distance;
initItem(ITEM_TRIGGER, xyz, /*normal not required*/Vec3(0,1,0));
m_graphical_type = ITEM_TRIGGER;
m_node = NULL;
m_listener = trigger;
m_was_available_previously = true;
} // Item(xyz, distance, trigger)
//-----------------------------------------------------------------------------
/** Initialises the item. Note that m_distance_2 must be defined before calling
* this function, since it pre-computes some values based on this.

View File

@ -42,19 +42,6 @@ namespace irr
}
using namespace irr;
// ============================================================================
/**
* \ingroup items
* \brief Listener class to go with Items of type ITEM_TRIGGER
*/
class TriggerItemListener
{
public:
virtual ~TriggerItemListener() {}
virtual void onTriggerItemApproached() = 0;
};
// ============================================================================
/** \ingroup items
* Contains the state information of an item, i.e. all non-visual information
@ -83,11 +70,7 @@ public:
/** For easter egg mode only. */
ITEM_EASTER_EGG,
/** An invisible item that can be used to trigger some behavior when
* approaching a point
*/
ITEM_TRIGGER,
ITEM_LAST = ITEM_TRIGGER,
ITEM_LAST = ITEM_EASTER_EGG,
ITEM_COUNT,
ITEM_NONE
};
@ -235,7 +218,7 @@ public:
virtual void switchTo(ItemType type)
{
// triggers and easter eggs should not be switched
if (m_type == ITEM_TRIGGER || m_type == ITEM_EASTER_EGG) return;
if (m_type == ITEM_EASTER_EGG) return;
m_original_type = m_type;
setType(type);
return;
@ -246,8 +229,6 @@ public:
*/
virtual bool switchBack()
{
// triggers should not be switched
if (m_type == ITEM_TRIGGER) return true;
// 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.
@ -352,9 +333,6 @@ private:
/** Stores if the item was available in the previously rendered frame. */
bool m_was_available_previously;
/** callback used if type == ITEM_TRIGGER */
TriggerItemListener* m_listener;
/** square distance at which item is collected */
float m_distance_2;
@ -378,8 +356,6 @@ public:
Item(ItemType type, const Vec3& xyz, const Vec3& normal,
scene::IMesh* mesh, scene::IMesh* lowres_mesh,
const AbstractKart *owner);
Item(const Vec3& xyz, float distance,
TriggerItemListener* trigger);
virtual ~Item ();
virtual void updateGraphics(float dt) OVERRIDE;
virtual void reset() OVERRIDE;
@ -392,8 +368,6 @@ public:
virtual void collected(const AbstractKart *kart) OVERRIDE
{
ItemState::collected(kart);
if (m_listener != NULL)
m_listener->onTriggerItemApproached();
} // isCollected
//-------------------------------------------------------------------------
/** Switch backs to the original item. Returns true if the item was not
@ -426,8 +400,7 @@ public:
return lc.length2() < m_distance_2;
} // hitKart
// ------------------------------------------------------------------------
bool rotating() const
{ return getType() != ITEM_BUBBLEGUM && getType() != ITEM_TRIGGER; }
bool rotating() const { return getType() != ITEM_BUBBLEGUM; }
public:
// ------------------------------------------------------------------------

View File

@ -86,7 +86,6 @@ void ItemManager::loadDefaultItemMeshes()
item_names[ItemState::ITEM_BUBBLEGUM ] = "bubblegum";
item_names[ItemState::ITEM_NITRO_BIG ] = "nitro-big";
item_names[ItemState::ITEM_NITRO_SMALL] = "nitro-small";
item_names[ItemState::ITEM_TRIGGER ] = "trigger";
item_names[ItemState::ITEM_BUBBLEGUM_NOLOK] = "bubblegum-nolok";
item_names[ItemState::ITEM_EASTER_EGG ] = "easter-egg";
@ -353,23 +352,6 @@ Item* ItemManager::placeItem(ItemState::ItemType type, const Vec3& xyz,
return item;
} // placeItem
//-----------------------------------------------------------------------------
/** Creates a new trigger item. This is not synched between client and
* server, since the triggers are created at startup only and should
* therefore always be in sync.
* \param xyz Position of the item.
* \param listener The listener object that gets called when a kart
* triggers this trigger.
*/
Item* ItemManager::placeTrigger(const Vec3& xyz, float distance,
TriggerItemListener* listener)
{
Item* item = new Item(xyz, distance, listener);
insertItem(item);
return item;
} // placeTrigger
//-----------------------------------------------------------------------------
/** Set an item as collected.
* This function is called on the server when an item is collected, or on

View File

@ -137,8 +137,6 @@ public:
const AbstractKart* parent,
const Vec3 *server_xyz = NULL,
const Vec3 *normal = NULL);
virtual Item* placeTrigger (const Vec3& xyz, float distance,
TriggerItemListener* listener);
void update (int ticks);
void updateGraphics (float dt);
void checkItemHit (AbstractKart* kart);

View File

@ -398,9 +398,6 @@ void LocalPlayerController::collectedItem(const ItemState &item_state,
//See Kart::collectedItem()
m_kart->playSound(m_ugh_sound);
break;
case Item::ITEM_TRIGGER:
// no default sound for triggers
break;
default:
m_kart->playSound(m_grab_sound);
break;

View File

@ -999,8 +999,6 @@ void SkiddingAI::evaluateItems(const ItemState *item, Vec3 kart_aim_direction,
break;
case Item::ITEM_BONUS_BOX:
break;
case Item::ITEM_TRIGGER: return; break;
default: assert(false); break;
} // switch

View File

@ -1074,8 +1074,6 @@ void SkiddingAI::evaluateItems(const ItemState *item, Vec3 kart_aim_direction,
break;
case Item::ITEM_BONUS_BOX:
break;
case Item::ITEM_TRIGGER: return; break;
default: assert(false); break;
} // switch

View File

@ -25,13 +25,14 @@
#include "items/item.hpp"
#include "modes/world.hpp"
#include "race/race_manager.hpp"
#include "tracks/check_manager.hpp"
CheckCylinder::CheckCylinder(const XMLNode &node, unsigned int index, TriggerItemListener* listener)
: CheckStructure(node, index)
CheckCylinder::CheckCylinder(const XMLNode &node,
std::function<void()> triggering_function)
: CheckStructure(CheckManager::get()->getCheckStructureCount())
{
m_radius2 = 1;
m_height = 0;
m_listener = listener;
node.get("height", &m_height);
node.get("radius", &m_radius2);
m_radius2 *= m_radius2;
@ -43,6 +44,7 @@ CheckCylinder::CheckCylinder(const XMLNode &node, unsigned int index, TriggerIte
{
m_is_inside[i] = false;
}
m_triggering_function = triggering_function;
} // CheckCylinder
// ----------------------------------------------------------------------------
@ -57,6 +59,9 @@ CheckCylinder::CheckCylinder(const XMLNode &node, unsigned int index, TriggerIte
bool CheckCylinder::isTriggered(const Vec3 &old_pos, const Vec3 &new_pos,
int kart_id)
{
// kart_id will be -1 if called by CheckManager::getChecklineTriggering
if (kart_id < 0 || kart_id >= (int)m_is_inside.size())
return false;
// TODO: this is the code for a sphere, rewrite for cylinder
Vec3 old_pos_xz(old_pos.x(), 0.0f, old_pos.z());
Vec3 new_pos_xz(new_pos.x(), 0.0f, new_pos.z());
@ -70,8 +75,8 @@ bool CheckCylinder::isTriggered(const Vec3 &old_pos, const Vec3 &new_pos,
bool triggered = (old_dist2>=m_radius2 && new_dist2 < m_radius2) ||
(old_dist2< m_radius2 && new_dist2 >=m_radius2);
if (triggered && m_listener != NULL)
m_listener->onTriggerItemApproached();
if (triggered && m_triggering_function)
m_triggering_function();
return triggered;
} // isTriggered

View File

@ -20,6 +20,7 @@
#define HEADER_CHECK_CYLINDER_HPP
#include "tracks/check_structure.hpp"
#include <functional>
class XMLNode;
class CheckManager;
@ -46,10 +47,11 @@ private:
/** Stores the distance of each kart from the center of this sphere.
* This saves some computations. */
std::vector<float> m_distance2;
TriggerItemListener* m_listener;
/** Function to call when triggered. */
std::function<void()> m_triggering_function;
public:
CheckCylinder(const XMLNode &node, unsigned int index,
TriggerItemListener* listener);
CheckCylinder(const XMLNode &node,
std::function<void()> triggering_function);
virtual ~CheckCylinder() {};
virtual bool isTriggered(const Vec3 &old_pos, const Vec3 &new_pos,
int kart_id);

View File

@ -59,6 +59,9 @@ CheckSphere::CheckSphere(const XMLNode &node, unsigned int index)
bool CheckSphere::isTriggered(const Vec3 &old_pos, const Vec3 &new_pos,
int kart_id)
{
// kart_id will be -1 if called by CheckManager::getChecklineTriggering
if (kart_id < 0 || kart_id >= (int)m_is_inside.size())
return false;
float old_dist2 = (old_pos-m_center_point).length2();
float new_dist2 = (new_pos-m_center_point).length2();
m_is_inside[kart_id] = new_dist2<m_radius2;

View File

@ -59,13 +59,14 @@ public:
* CANNON: Causes the kart to be shot to a specified point.
* GOAL: Causes a point to be scored when a soccer ball crosses its line
* AMBIENT_SPHERE: Modifies the ambient color.
* TRIGGER: Run custom trigger function
* A combination of an activate and new_lap line are used to
* avoid shortcuts: a new_lap line is deactivated after crossing it, and
* you have to cross a corresponding activate structure to re-activate it,
* enabling you to count the lap again.
*/
enum CheckType {CT_NEW_LAP, CT_ACTIVATE, CT_TOGGLE, CT_CANNON,
CT_GOAL, CT_AMBIENT_SPHERE};
CT_GOAL, CT_AMBIENT_SPHERE, CT_TRIGGER};
protected:
/** Stores the previous position of all karts. This is needed to detect
@ -82,6 +83,9 @@ protected:
* debugging (use --check-debug option). */
unsigned int m_index;
/** For CheckTrigger or CheckCylinder */
CheckStructure(unsigned index) : m_active_at_reset(true), m_index(index),
m_check_type(CT_TRIGGER) {}
private:
/** The type of this checkline. */
CheckType m_check_type;

View File

@ -0,0 +1,56 @@
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2019 SuperTuxKart-Team
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "tracks/check_trigger.hpp"
#include "karts/abstract_kart.hpp"
#include "modes/world.hpp"
#include "tracks/check_manager.hpp"
#include "utils/time.hpp"
/** Constructor for a checksphere.
* \param check_manager Pointer to the check manager, which is needed when
* resetting e.g. new lap counters.
* \param node XML node containing the parameters for this checkline.
*/
CheckTrigger::CheckTrigger(const Vec3& center, float distance,
std::function<void()> triggering_function)
: CheckStructure(CheckManager::get()->getCheckStructureCount()),
m_center(center), m_distance2(distance * distance),
m_triggering_function(triggering_function)
{
m_last_triggered_time = StkTime::getRealTimeMs();
} // CheckSphere
// ----------------------------------------------------------------------------
/** Copied from item state.
*/
bool CheckTrigger::isTriggered(const Vec3 &old_pos, const Vec3 &new_pos,
int kart_id)
{
// kart_id will be -1 if called by CheckManager::getChecklineTriggering
if (kart_id < 0 || kart_id >= (int)World::getWorld()->getNumKarts())
return false;
if (m_last_triggered_time + 2000 > StkTime::getRealTimeMs())
return false;
AbstractKart* k = World::getWorld()->getKart(kart_id);
if ((k->getXYZ() - m_center).length2() < m_distance2)
{
m_last_triggered_time = StkTime::getRealTimeMs();
return true;
}
return false;
} // isTriggered

View File

@ -0,0 +1,64 @@
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2019 SuperTuxKart-Team
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#ifndef HEADER_CHECK_TRIGGER_HPP
#define HEADER_CHECK_TRIGGER_HPP
#include "tracks/check_structure.hpp"
#include "utils/cpp2011.hpp"
#include "utils/types.hpp"
#include <functional>
/** This class implements a check point like item, but used only for scripting
* or sound trigger.
* \ingroup tracks
*/
class CheckTrigger : public CheckStructure
{
private:
/** Center of the trigger. */
const Vec3 m_center;
/** Squared of the triggering distance. */
const float m_distance2;
/** Function to call when triggered. */
const std::function<void()> m_triggering_function;
/** Time since last trigger, if any triggering between 2 seconds ignored
* (like items). */
uint64_t m_last_triggered_time;
public:
CheckTrigger(const Vec3& center, float distance,
std::function<void()> triggering_function);
// ------------------------------------------------------------------------
virtual ~CheckTrigger() {}
// ------------------------------------------------------------------------
virtual bool isTriggered(const Vec3 &old_pos, const Vec3 &new_pos,
int kart_id) OVERRIDE;
// ------------------------------------------------------------------------
virtual void trigger(unsigned int kart_index) OVERRIDE
{
m_triggering_function();
CheckStructure::trigger(kart_index);
}
}; // CheckSphere
#endif

View File

@ -44,7 +44,7 @@
#include "states_screens/dialogs/tutorial_message_dialog.hpp"
#include "tracks/check_cylinder.hpp"
#include "tracks/check_manager.hpp"
#include "tracks/check_sphere.hpp"
#include "tracks/check_trigger.hpp"
#include "tracks/model_definition_loader.hpp"
#include "tracks/track.hpp"
#include "tracks/track_manager.hpp"
@ -683,7 +683,10 @@ TrackObjectPresentationSound::TrackObjectPresentationSound(
if (trigger_when_near)
{
ItemManager::get()->placeTrigger(m_init_xyz, trigger_distance, this);
CheckManager::get()->add(
new CheckTrigger(m_init_xyz, trigger_distance, std::bind(
&TrackObjectPresentationSound::onTriggerItemApproached,
this)));
}
if (disable_for_multiplayer)
@ -1067,7 +1070,7 @@ TrackObjectPresentationActionTrigger::TrackObjectPresentationActionTrigger(
}
m_xml_reenable_timeout = 999999.9f;
xml_node.get("reenable-timeout", &m_xml_reenable_timeout);
m_reenable_timeout = 0.0f;
setReenableTimeout(0.0f);
if (m_action.empty())
{
@ -1098,17 +1101,16 @@ TrackObjectPresentationActionTrigger::TrackObjectPresentationActionTrigger(
if (m_type == TRIGGER_TYPE_POINT)
{
// TODO: rewrite as a sphere check structure?
ItemManager::get()->placeTrigger(m_init_xyz, trigger_distance, this);
// 0 is the index, and is mostly used for debugging (i.e. to identify which check
// structure information is printed about) - not sure how to best use this
// with items added outside of the checkline manager. Best option would be to
// change CheckManager::add() to create the object?
// CheckManager::get()->add(new CheckSphere(xml_node, 0 /* TODO what is this? */));
CheckManager::get()->add(
new CheckTrigger(m_init_xyz, trigger_distance, std::bind(
&TrackObjectPresentationActionTrigger::onTriggerItemApproached,
this)));
}
else if (m_type == TRIGGER_TYPE_CYLINDER)
{
CheckManager::get()->add(new CheckCylinder(xml_node, 0 /* TODO what is this? */, this));
CheckManager::get()->add(new CheckCylinder(xml_node, std::bind(
&TrackObjectPresentationActionTrigger::onTriggerItemApproached,
this)));
}
else
{
@ -1129,19 +1131,22 @@ TrackObjectPresentationActionTrigger::TrackObjectPresentationActionTrigger(
float trigger_distance = distance;
m_action = script_name;
m_xml_reenable_timeout = 999999.9f;
m_reenable_timeout = 0.0f;
setReenableTimeout(0.0f);
m_type = TRIGGER_TYPE_POINT;
ItemManager::get()->placeTrigger(m_init_xyz, trigger_distance, this);
CheckManager::get()->add(
new CheckTrigger(m_init_xyz, trigger_distance, std::bind(
&TrackObjectPresentationActionTrigger::onTriggerItemApproached,
this)));
} // TrackObjectPresentationActionTrigger
// ----------------------------------------------------------------------------
void TrackObjectPresentationActionTrigger::onTriggerItemApproached()
{
if (m_reenable_timeout > 0.0f)
if (m_reenable_timeout > StkTime::getRealTimeMs())
{
return;
}
m_reenable_timeout = m_xml_reenable_timeout;
setReenableTimeout(m_xml_reenable_timeout);
int kart_id = 0;
Camera* camera = Camera::getActiveCamera();

View File

@ -21,16 +21,18 @@
#define HEADER_TRACK_OBJECT_PRESENTATION_HPP
#include "graphics/lod_node.hpp"
#include "items/item.hpp"
#include "utils/cpp2011.hpp"
#include "utils/no_copy.hpp"
#include "utils/log.hpp"
#include "utils/leak_check.hpp"
#include "utils/time.hpp"
#include "utils/vec3.hpp"
#include <vector3d.h>
#include <IAnimatedMeshSceneNode.h>
#include <memory>
#include <limits>
#include <string>
class SFXBase;
@ -268,8 +270,7 @@ public:
/** \ingroup tracks
* A track object representation that consists of a sound emitter
*/
class TrackObjectPresentationSound : public TrackObjectPresentation,
public TriggerItemListener
class TrackObjectPresentationSound : public TrackObjectPresentation
{
private:
@ -290,7 +291,7 @@ public:
scene::ISceneNode* parent,
bool disable_for_multiplayer);
virtual ~TrackObjectPresentationSound();
virtual void onTriggerItemApproached() OVERRIDE;
void onTriggerItemApproached();
virtual void updateGraphics(float dt) OVERRIDE;
virtual void move(const core::vector3df& xyz, const core::vector3df& hpr,
const core::vector3df& scale, bool isAbsoluteCoord) OVERRIDE;
@ -383,14 +384,15 @@ enum ActionTriggerType
/** \ingroup tracks
* A track object representation that consists of an action trigger
*/
class TrackObjectPresentationActionTrigger : public TrackObjectPresentation,
public TriggerItemListener
class TrackObjectPresentationActionTrigger : public TrackObjectPresentation
{
private:
/** For action trigger objects */
std::string m_action, m_library_id, m_triggered_object, m_library_name;
float m_xml_reenable_timeout, m_reenable_timeout;
float m_xml_reenable_timeout;
uint64_t m_reenable_timeout;
ActionTriggerType m_type;
@ -403,24 +405,25 @@ public:
virtual ~TrackObjectPresentationActionTrigger() {}
virtual void onTriggerItemApproached() OVERRIDE;
void onTriggerItemApproached();
// ------------------------------------------------------------------------
/** Reset the trigger (i.e. sets it to active again). */
virtual void reset() OVERRIDE { m_reenable_timeout = 0.0f; }
virtual void reset() OVERRIDE
{ m_reenable_timeout = StkTime::getRealTimeMs(); }
// ------------------------------------------------------------------------
virtual void update(float dt) OVERRIDE
/** Sets the trigger to be enabled or disabled. getRealTimeMs is used to
* to avoid called update which duplicated in network rewinding. */
virtual void setEnable(bool status) OVERRIDE
{
if (m_reenable_timeout < 900000.0f)
{
m_reenable_timeout -= dt;
}
m_reenable_timeout = status ? StkTime::getRealTimeMs() :
std::numeric_limits<uint64_t>::max();
}
// ------------------------------------------------------------------------
/** Sets the trigger to be enabled or disabled. */
virtual void setEnable(bool status) OVERRIDE
{ m_reenable_timeout = status ? 0.0f : 999999.9f; }
// ------------------------------------------------------------------------
void setReenableTimeout(float time) { m_reenable_timeout = time; }
void setReenableTimeout(float time)
{
m_reenable_timeout =
StkTime::getRealTimeMs() + (uint64_t)(time * 1000.0f);
}
}; // class TrackObjectPresentationActionTrigger