Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
137 changes: 134 additions & 3 deletions src/object/coin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,17 @@
#include "object/bouncy_coin.hpp"
#include "object/player.hpp"
#include "object/tilemap.hpp"
#include "supertux/constants.hpp"
#include "supertux/flip_level_transformer.hpp"
#include "supertux/level.hpp"
#include "supertux/sector.hpp"
#include "util/reader_mapping.hpp"
#include "util/writer.hpp"

namespace {
const float GROUND_FRICTION = 0.1f;
} // namespace

Coin::Coin(const Vector& pos, bool count_stats, const std::string& sprite_path) :
MovingSprite(pos, sprite_path, LAYER_OBJECTS - 1, COLGROUP_TOUCHABLE),
PathObject(),
Expand All @@ -37,7 +42,16 @@ Coin::Coin(const Vector& pos, bool count_stats, const std::string& sprite_path)
m_physic(),
m_collect_script(),
m_starting_node(0),
m_count_stats(count_stats)
m_count_stats(count_stats),
m_on_ground(false),
m_on_ice(false),
m_at_ceiling(false),
m_last_movement(0.0f, 0.0f),
m_on_grab_script(),
m_on_ungrab_script(),
m_running_grab_script(false),
m_running_ungrab_script(false),
m_last_sector_gravity(10.0f)
{
SoundManager::current()->preload("sounds/coin.wav");
}
Expand All @@ -51,10 +65,21 @@ Coin::Coin(const ReaderMapping& reader, bool count_stats) :
m_physic(),
m_collect_script(),
m_starting_node(0),
m_count_stats(count_stats)
m_count_stats(count_stats),
m_on_ground(false),
m_on_ice(false),
m_at_ceiling(false),
m_last_movement(0.0f, 0.0f),
m_on_grab_script(),
m_on_ungrab_script(),
m_running_grab_script(false),
m_running_ungrab_script(false),
m_last_sector_gravity(10.0f)
{
reader.get("starting-node", m_starting_node, 0);
reader.get("collect-script", m_collect_script, "");
reader.get("on-grab-script", m_on_grab_script, "");
reader.get("on-ungrab-script", m_on_ungrab_script, "");

parse_type(reader);
init_path(reader, true);
Expand Down Expand Up @@ -101,6 +126,40 @@ Coin::finish_construction()
void
Coin::update(float dt_sec)
{
if (!is_grabbed())
{
if (get_bbox().get_top() > Sector::get().get_height())
{
remove_me();
return;
}

// Check for ice
Rectf icebox = get_bbox().grown(-1.f);
icebox.set_bottom(get_bbox().get_bottom() + 8.f);
m_on_ice = !Sector::get().is_free_of_tiles(icebox, true, Tile::ICE);

// Water physics
bool in_water = !Sector::get().is_free_of_tiles(get_bbox(), true, Tile::WATER);
m_physic.set_gravity_modifier(in_water ? 0.2f : 1.f);

m_col.set_movement(m_physic.get_movement(dt_sec) *
Vector(in_water ? 0.4f : 1.f, in_water ? 0.6f : 1.f));

// Handle gravity direction changes
const float sector_gravity = Sector::get().get_gravity();
if (m_last_sector_gravity != sector_gravity)
{
if ((sector_gravity < 0.0f && m_last_sector_gravity >= 0.0f) ||
(sector_gravity >= 0.0f && m_last_sector_gravity < 0.0f))
{
m_on_ground = false;
m_at_ceiling = false;
}
m_last_sector_gravity = sector_gravity;
}
}

// If we have a path to follow, follow it.
if (get_walker()) {
Vector v(0.0f, 0.0f);
Expand Down Expand Up @@ -281,7 +340,10 @@ HeavyCoin::collision_solid(const CollisionHit& hit)
{
float clink_threshold = 100.0f; // Sets the minimum speed needed to result in collision noise.
// TODO: Colliding with HeavyCoins should have their own unique sound.

if (is_grabbed())
// Don't do anything while being carried
return;

if (hit.bottom) {
if (m_physic.get_velocity_y() > clink_threshold && !m_last_hit.bottom)
SoundManager::current()->play("sounds/coin2.ogg", get_pos());
Expand All @@ -303,6 +365,10 @@ HeavyCoin::collision_solid(const CollisionHit& hit)
SoundManager::current()->play("sounds/coin2.ogg", get_pos());
m_physic.set_velocity_y(-m_physic.get_velocity_y());
}
if (m_on_ground || (hit.bottom && m_on_ice))
{
m_physic.set_velocity_x(m_physic.get_velocity_x() * (1.f - (GROUND_FRICTION * (m_on_ice ? 0.5f : 1.f))));
}

// Only make a sound if the coin wasn't hittin anything last frame (A coin
// stuck in solid matter would flood the sound manager - see #1555 on GitHub).
Expand Down Expand Up @@ -392,4 +458,69 @@ HeavyCoin::on_flip(float height)
MovingSprite::on_flip(height);
}

void
Coin::grab(MovingObject& object, const Vector& pos, Direction dir)
{
Portable::grab(object, pos, dir);

// Update position and movement
Vector movement = pos - get_pos();
m_col.set_movement(movement);
m_last_movement = movement;

// Update collision group
set_group(COLGROUP_TOUCHABLE);

// Reset ground/ceiling state
m_on_ground = false;
m_at_ceiling = false;

// Handle grab script
m_running_ungrab_script = false;
if (!m_on_grab_script.empty() && !m_running_grab_script)
{
m_running_grab_script = true;
Sector::get().run_script(m_on_grab_script, "Coin::on_grab");
}
}

void
Coin::ungrab(MovingObject& object, Direction dir)
{
auto player = dynamic_cast<Player*>(&object);

// Reset collision group and states
set_group(COLGROUP_MOVING_STATIC);
m_on_ground = false;
m_at_ceiling = false;

if (player)
{
// Handle swimming physics
if (player->is_swimming() || player->is_water_jumping())
{
float swimangle = player->get_swimming_angle();
m_physic.set_velocity(player->get_velocity() + Vector(std::cos(swimangle), std::sin(swimangle)));
}
else
{
// Normal throwing physics
m_physic.set_velocity_x(fabsf(player->get_physic().get_velocity_x()) < 1.f ? 0.f :
player->m_dir == Direction::LEFT ? -200.f : 200.f);
m_physic.set_velocity_y((dir == Direction::UP) ? -500.f : (dir == Direction::DOWN) ? 500.f :
(glm::length(m_last_movement) > 1) ? -200.f : 0.f);
}
}

// Handle ungrab script
m_running_grab_script = false;
if (!m_on_ungrab_script.empty() && !m_running_ungrab_script)
{
m_running_ungrab_script = true;
Sector::get().run_script(m_on_ungrab_script, "Coin::on_ungrab");
}

Portable::ungrab(object, dir);
}

/* EOF */
18 changes: 17 additions & 1 deletion src/object/coin.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,15 @@
#include "object/path_object.hpp"
#include "object/moving_sprite.hpp"
#include "supertux/physic.hpp"
#include "object/portable.hpp"

class Path;
class PathWalker;
class TileMap;

class Coin : public MovingSprite,
public PathObject
public PathObject,
public Portable
{
friend class HeavyCoin;

Expand All @@ -45,6 +47,9 @@ class Coin : public MovingSprite,
virtual std::string get_display_name() const override { return display_name(); }
virtual GameObjectClasses get_class_types() const override { return MovingSprite::get_class_types().add(typeid(PathObject)).add(typeid(Coin)); }

virtual void grab(MovingObject& object, const Vector& pos, Direction dir) override;
virtual void ungrab(MovingObject& object, Direction dir) override;

virtual ObjectSettings get_settings() override;
GameObjectTypes get_types() const override;
std::string get_default_sprite_name() const override;
Expand All @@ -63,6 +68,17 @@ class Coin : public MovingSprite,

void collect();

protected:
bool m_on_ground;
bool m_on_ice;
bool m_at_ceiling;
Vector m_last_movement;
std::string m_on_grab_script;
std::string m_on_ungrab_script;
bool m_running_grab_script;
bool m_running_ungrab_script;
float m_last_sector_gravity;

private:
enum Type {
NORMAL,
Expand Down
51 changes: 49 additions & 2 deletions src/object/coin_explode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,52 @@

#include "math/random.hpp"
#include "object/coin.hpp"
#include "sprite/sprite.hpp"
#include "sprite/sprite_manager.hpp"
#include "supertux/sector.hpp"

#include <list>

CoinExplode::CoinExplode(const Vector& pos, bool count_stats, const std::string& sprite) :
GameObject("coin-explode"),
m_sprite(sprite),
position(pos),
m_count_stats(count_stats)
{
}

CoinExplode::CoinExplode(const ReaderMapping& reader) :
GameObject(reader),
m_sprite("images/objects/coin/coin.sprite"),
position(),
m_count_stats(true)
{
reader.get("x", position.x);
reader.get("y", position.y);
bool emerge = false;
}

void
CoinExplode::update(float dt_sec)
{
if (is_grabbed())
// Don't do anything while being carried
return;
Comment on lines +49 to +51
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This statement looks equivalent to an empty method? Is this part work in progress?

}

void
CoinExplode::draw(DrawingContext& context)
{
// Draw the coin sprite so it's visible
auto sprite = SpriteManager::current()->create(m_sprite);
if (sprite)
{
sprite->draw(context.color(), position, LAYER_OBJECTS);
}
}

void
CoinExplode::update(float )
CoinExplode::explode()
{
float mag = 100.0f; // Magnitude at which coins are thrown.
float rand = 30.0f; // Max variation to be subtracted from the magnitude.
Expand All @@ -53,8 +86,22 @@ CoinExplode::update(float )
}

void
CoinExplode::draw(DrawingContext &)
CoinExplode::grab(MovingObject& object, const Vector& pos, Direction dir)
{
position = pos;
Portable::grab(object, pos, dir);
}

void
CoinExplode::ungrab(MovingObject& object, Direction dir)
{
position = object.get_pos();

// Explode immediately when ungrabbed
explode();

Portable::ungrab(object, dir);
}


/* EOF */
16 changes: 15 additions & 1 deletion src/object/coin_explode.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,23 +19,37 @@

#include "math/vector.hpp"
#include "supertux/game_object.hpp"
#include "object/portable.hpp"
#include "util/reader_mapping.hpp"

class CoinExplode final : public GameObject
class CoinExplode final : public GameObject,
public Portable
{
public:
CoinExplode(const Vector& pos, bool count_stats = true,
const std::string& sprite_path = "images/objects/coin/coin.sprite");
CoinExplode(const ReaderMapping& reader);
virtual GameObjectClasses get_class_types() const override { return GameObject::get_class_types().add(typeid(CoinExplode)); }
static std::string class_name() { return "coin_explode"; }
virtual std::string get_class_name() const override { return class_name(); }
static std::string display_name() { return _("Coin Explode"); }
virtual std::string get_display_name() const override { return display_name(); }
virtual bool is_portable() const override { return true; }

virtual void update(float dt_sec) override;
virtual void draw(DrawingContext& context) override;
virtual bool is_saveable() const override {
return false;
}

virtual void grab(MovingObject& object, const Vector& pos, Direction dir) override;
virtual void ungrab(MovingObject& object, Direction dir) override;

private:
std::string m_sprite;
Vector position;
const bool m_count_stats;
void explode();
};

#endif
Expand Down
Loading
Loading