themselfes. This could speed up rendering of tilemaps.
[H] implement quadtree to speed up collision detection
[?] remove badguyspecs and bitmask files
+[M] Make the gamelogic run in a fixed logical framerate
--Miscellaneous--
[?] think about how to implement scripting, and how to make a simple and easy to
directories();
dictionary_manager.add_directory(datadir + "/locale");
+ dictionary_manager.set_charset("iso8859-1");
}
/* --- SETUP --- */
Dictionary& dict = dictionaries[lang];
dict.set_language(get_language_def(lang));
+ if(charset != "")
+ dict.set_charset(charset);
for (SearchPath::iterator p = search_path.begin(); p != search_path.end(); ++p)
{
}
void
+DictionaryManager::set_charset(const std::string& charset)
+{
+ dictionaries.clear(); // changing charset invalidates cache
+ this->charset = charset;
+ set_language(language);
+}
+
+void
DictionaryManager::set_language_alias(const std::string& alias,
const std::string& language)
{
void
DictionaryManager::add_directory(const std::string& pathname)
{
+ dictionaries.clear(); // adding directories invalidates cache
search_path.push_back(pathname);
- // cache is outdated now
- dictionaries.clear();
set_language(language);
}
SearchPath search_path;
typedef std::map<std::string, std::string> Aliases;
Aliases language_aliases;
+ std::string charset;
std::string language;
Dictionary* current_dict;
Dictionary empty_dict;
public:
DictionaryManager();
-
+
/** Return the currently active dictionary, if none is set, an empty
dictionary is returned. */
Dictionary& get_dictionary()
/** Set a language based on a four? letter country code */
void set_language(const std::string& langspec);
+ /** Set a charset that will be set on the returned dictionaries */
+ void set_charset(const std::string& charset);
+
/** Define an alias for a language */
void set_language_alias(const std::string& alias, const std::string& lang);
*/
enum HitResponse
{
- ABORT_MOVE, // don't move the object
- FORCE_MOVE, // do the move ignoring the collision
- CONTINUE // move object out of collision and check for collisions again
- // if this happens to often then the move will just be aborted
+ // note: keep the elements in this order
+
+ /// don't move the object
+ ABORT_MOVE = 0,
+ /// move object out of collision and check for collisions again
+ /// if this happens to often then the move will just be aborted
+ CONTINUE,
+ /// do the move ignoring the collision
+ FORCE_MOVE
};
/**
{
Sprite::Sprite(SpriteData& newdata)
- : data(newdata)
+ : data(newdata), frame(0), animation_loops(-1)
{
action = data.actions.begin()->second;
- reset();
+ last_ticks = SDL_GetTicks();
}
Sprite::Sprite(const Sprite& other)
: data(other.data), frame(other.frame),
- animation_loops(other.animation_loops), last_tick(other.last_tick),
- action(other.action), next_action(other.next_action)
+ animation_loops(other.animation_loops),
+ action(other.action)
{
+ last_ticks = SDL_GetTicks();
}
Sprite::~Sprite()
}
void
-Sprite::set_action(std::string name)
+Sprite::set_action(std::string name, int loops)
{
- if(!next_action.empty() && animation_loops > 0) {
- next_action = name;
+ if(action && action->name == name)
return;
- }
+
SpriteData::Action* newaction = data.get_action(name);
- if(!action)
+ if(!action) {
+#ifdef DEBUG
+ std::cerr << "Action '" << name << "' not found.\n";
+#endif
return;
+ }
action = newaction;
-}
-
-void
-Sprite::start_animation(int loops)
-{
- reset();
animation_loops = loops;
-}
-
-void
-Sprite::reset()
-{
frame = 0;
- last_tick = SDL_GetTicks();
- animation_reversed = false;
- animation_loops = -1;
- next_action.clear();
}
bool
}
void
-Sprite::reverse_animation(bool reverse)
-{
- animation_reversed = reverse;
-
- if(animation_reversed)
- frame = get_frames()-1;
- else
- frame = 0;
-}
-
-void
Sprite::update()
{
if(animation_loops == 0)
- {
- if(frame >= get_frames() || frame < 0)
- frame = 0;
return;
- }
- float frame_inc = (action->fps/1000.0) * (SDL_GetTicks() - last_tick);
- last_tick = SDL_GetTicks();
+ Uint32 ticks = SDL_GetTicks();
+ float frame_inc = action->fps * float(ticks - last_ticks)/1000.0;
+ last_ticks = ticks;
- if(animation_reversed)
- frame -= frame_inc;
- else
- frame += frame_inc;
-
- if(animation_reversed) {
- if(frame < 0 || frame >= (float)get_frames()) {
- // last case can happen when not used reverse_animation()
- float excedent = frame - 0;
- frame = get_frames() - 1;
- if(animation_loops > 0)
- {
- animation_loops--;
- if(animation_loops == 0 && !next_action.empty())
- {
- set_action(next_action);
- start_animation(-1);
- }
- }
-
- if(fabsf(excedent) < get_frames())
- frame += excedent;
- }
- }
- else
- {
- if(frame >= (float)get_frames())
- {
- float excedent = frame - get_frames();
- frame = 0;
- if(animation_loops > 0)
- {
- animation_loops--;
- if(animation_loops == 0 && !next_action.empty())
- {
- set_action(next_action);
- start_animation(-1);
- }
- }
-
- if(excedent < get_frames())
- frame += excedent;
+ frame += frame_inc;
+
+ float lastframe = frame;
+ frame = fmodf(frame+get_frames(), get_frames());
+ if(frame != lastframe) {
+ if(animation_loops > 0) {
+ animation_loops--;
+ if(animation_loops == 0)
+ frame = 0;
}
}
}
#include <string>
#include <vector>
+#include <cassert>
#include <map>
#include "utils/lispreader.h"
Uint32 drawing_effect = NONE_EFFECT);
/** Set action (or state) */
- void set_action(std::string act);
+ void set_action(std::string act, int loops = -1);
- /* Start an animation
- -1 - for infinite
- 0 - stopped
- 1,2,3 - one, two, three times... */
- void start_animation(int loops);
/* Stop animation */
void stop_animation()
- { start_animation(0); }
+ { animation_loops = 0; }
/** Check if animation is stopped or not */
bool check_animation();
- /** Reverse the animation */
- void reverse_animation(bool reverse);
float get_fps() const
{ return action->fps; }
{ if(frame_ > get_frames()) frame = 0; else frame = frame_; }
Surface* get_frame(unsigned int frame)
{
- if(frame < action->surfaces.size())
- return action->surfaces[frame];
- else
- return action->surfaces[0];
+ assert(frame < action->surfaces.size());
+ return action->surfaces[frame];
}
+
private:
void update();
- void reset();
SpriteData& data;
float frame;
int animation_loops;
- bool animation_reversed;
- float last_tick;
+ Uint32 last_ticks;
SpriteData::Action* action;
- std::string next_action;
};
} //namespace SuperTux
}
flags |= FLAG_NO_COLLDET;
break;
+ case STATE_FALLING:
+ flags |= FLAG_NO_COLLDET;
+ break;
default:
break;
}
}
void
-Dispenser::active_action(float elapsed_time)
+Dispenser::active_action(float )
{
if (dispense_timer.check()) {
launch_badguy();
#include "flower.h"
#include "oneup.h"
#include "star.h"
+#include "badguy/badguy.h"
+#include "coin.h"
static const float BOUNCY_BRICK_MAX_OFFSET=8;
static const float BOUNCY_BRICK_SPEED=90;
HitResponse
Block::collision(GameObject& other, const CollisionHit& hitdata)
{
- // TODO kill badguys when bumping them...
-
Player* player = dynamic_cast<Player*> (&other);
if(player) {
// collided from below?
}
}
+ if(bouncing) {
+ BadGuy* badguy = dynamic_cast<BadGuy*> (&other);
+ if(badguy) {
+ badguy->kill_fall();
+ }
+ Coin* coin = dynamic_cast<Coin*> (&other);
+ if(coin) {
+ coin->collect();
+ }
+ }
+
return FORCE_MOVE;
}
#include "video/drawing_context.h"
#include "special/sprite_manager.h"
#include "player.h"
+#include "sector.h"
#include "scene.h"
+#include "gameobjs.h"
Coin::Coin(const Vector& pos)
{
sprite->draw(context, get_pos(), LAYER_TILES);
}
+void
+Coin::collect()
+{
+ Sector::current()->player->get_status().incCoins();
+ Sector::current()->add_object(new BouncyCoin(get_pos()));
+ remove_me();
+}
+
HitResponse
Coin::collision(GameObject& other, const CollisionHit& )
{
if(player == 0)
return ABORT_MOVE;
- player->get_status().incCoins();
- remove_me();
+ collect();
return ABORT_MOVE;
}
virtual void action(float elapsed_time);
virtual void draw(DrawingContext& context);
+ void collect();
+
private:
Sprite* sprite;
};
}
void
-TuxBodyParts::set_action(std::string action)
+TuxBodyParts::set_action(std::string action, int loops)
{
if(head != NULL)
- head->set_action(action);
+ head->set_action(action, loops);
if(body != NULL)
- body->set_action(action);
+ body->set_action(action, loops);
if(arms != NULL)
- arms->set_action(action);
+ arms->set_action(action, loops);
if(feet != NULL)
- feet->set_action(action);
-}
-
-void
-TuxBodyParts::one_time_animation()
-{
- if(head != NULL)
- head->start_animation(1);
- if(body != NULL)
- body->start_animation(1);
- if(arms != NULL)
- arms->start_animation(1);
- if(feet != NULL)
- feet->start_animation(1);
+ feet->set_action(action, loops);
}
void
if(size == BIG)
{
if(dir == LEFT)
- tux_body->head->set_action("idle-left");
+ tux_body->head->set_action("idle-left", 1);
else // dir == RIGHT
- tux_body->head->set_action("idle-right");
-
- tux_body->head->start_animation(1);
+ tux_body->head->set_action("idle-right", 1);
}
}
delete feet;
}
- void set_action(std::string action);
+ void set_action(std::string action, int loops = -1);
void one_time_animation();
void draw(DrawingContext& context, const Vector& pos, int layer,
Uint32 drawing_effect = NONE_EFFECT);
context.pop_transform();
}
+static const float DELTA = .001;
+
void
Sector::collision_tilemap(MovingObject* object, int depth)
{
return;
}
// move out of collision and try again
- object->movement += hit.normal * (hit.depth + .05);
+ object->movement += hit.normal * (hit.depth + DELTA);
collision_tilemap(object, depth+1);
}
if(response1 == ABORT_MOVE)
object1->movement = Vector(0, 0);
if(response2 == CONTINUE)
- object2->movement += hit.normal * (hit.depth + .05);
+ object2->movement += hit.normal * (hit.depth + DELTA);
} else if(response2 != CONTINUE) {
if(response2 == ABORT_MOVE)
object2->movement = Vector(0, 0);
if(response1 == CONTINUE)
- object1->movement += -hit.normal * (hit.depth + .05);
+ object1->movement += -hit.normal * (hit.depth + DELTA);
} else {
- object1->movement += -hit.normal * (hit.depth/2 + .05);
- object2->movement += hit.normal * (hit.depth/2 + .05);
+ object1->movement += -hit.normal * (hit.depth/2 + DELTA);
+ object2->movement += hit.normal * (hit.depth/2 + DELTA);
}
}
}
for(std::vector<GameObject*>::iterator i = gameobjects.begin();
i != gameobjects.end(); ++i) {
GameObject* gameobject = *i;
- if(!gameobject->is_valid()
- || gameobject->get_flags() & GameObject::FLAG_NO_COLLDET)
+ if(!gameobject->is_valid())
continue;
MovingObject* movingobject = dynamic_cast<MovingObject*> (gameobject);
if(!movingobject)
continue;
+ if(movingobject->get_flags() & GameObject::FLAG_NO_COLLDET) {
+ movingobject->bbox.move(movingobject->movement);
+ movingobject->movement = Vector(0, 0);
+ continue;
+ }
// collision with tilemap
if(! (movingobject->movement == Vector(0, 0)))
Door::event(Player& , EventType type)
{
if(type == EVENT_ACTIVATE) {
- sprite->set_action("open");
- sprite->start_animation(1);
+ sprite->set_action("open", 1);
}
}