tilemap.cpp \
moving_object.h \
moving_object.cpp \
-serializable.h
+serializable.h \
+vector.cpp \
+vector.h
# EOF #
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "camera.h"
+#include <stdexcept>
+#include <sstream>
#include <math.h>
#include "lispwriter.h"
#include "player.h"
#include "globals.h"
Camera::Camera(Player* newplayer, Level* newlevel)
- : player(newplayer), level(newlevel), scrollchange(NONE)
+ : player(newplayer), level(newlevel), do_backscrolling(true),
+ scrollchange(NONE), auto_idx(0), auto_t(0)
{
if(!player || !level)
mode = MANUAL;
}
void
+Camera::read(LispReader& reader)
+{
+ std::string modename;
+
+ reader.read_string("mode", &modename);
+ if(modename == "normal") {
+ mode = NORMAL;
+
+ do_backscrolling = true;
+ reader.read_bool("backscrolling", &do_backscrolling);
+ } else if(modename == "autoscroll") {
+ mode = AUTOSCROLL;
+
+ lisp_object_t* cur = 0;
+ reader.read_lisp("path", &cur);
+ if(cur == 0) {
+ throw std::runtime_error("No path specified in autoscroll camera.");
+ }
+ float speed = .5;
+ while(!lisp_nil_p(cur)) {
+ if(strcmp(lisp_symbol(lisp_car(lisp_car(cur))), "point") != 0) {
+ std::cerr << "Warning: unknown token in camera path.\n";
+ continue;
+ }
+
+ LispReader reader(lisp_cdr(lisp_car(cur)));
+
+ ScrollPoint point;
+ if(!reader.read_float("x", &point.position.x) ||
+ !reader.read_float("y", &point.position.y)) {
+ throw std::runtime_error("x and y missing in point of camerapath");
+ }
+ reader.read_float("speed", &speed);
+ point.speed = speed;
+ scrollpoints.push_back(point);
+
+ cur = lisp_cdr(cur);
+ }
+ } else if(modename == "manual") {
+ mode = MANUAL;
+ } else {
+ std::stringstream str;
+ str << "invalid camera mode '" << modename << "'found in worldfile.";
+ throw std::runtime_error(str.str());
+ }
+}
+
+void
Camera::write(LispWriter& writer)
{
writer.start_list("camera");
if(mode == NORMAL) {
writer.write_string("mode", "normal");
+ writer.write_bool("backscrolling", do_backscrolling);
} else if(mode == AUTOSCROLL) {
writer.write_string("mode", "autoscroll");
+ writer.start_list("path");
+ for(std::vector<ScrollPoint>::iterator i = scrollpoints.begin();
+ i != scrollpoints.end(); ++i) {
+ writer.start_list("point");
+ writer.write_float("x", i->position.x);
+ writer.write_float("y", i->position.y);
+ writer.write_float("speed", i->speed);
+ writer.end_list("point");
+ }
+
+ writer.end_list("path");
} else if(mode == MANUAL) {
writer.write_string("mode", "manual");
}
}
void
+Camera::keep_in_bounds()
+{
+ // don't scroll before the start or after the level's end
+ if(translation.y > level->height * 32 - screen->h)
+ translation.y = level->height * 32 - screen->h;
+ if(translation.y < 0)
+ translation.y = 0;
+ if(translation.x > level->width * 32 - screen->w)
+ translation.x = level->width * 32 - screen->w;
+ if(translation.x < 0)
+ translation.x = 0;
+}
+
+void
Camera::scroll_normal(float elapsed_time)
{
assert(level != 0 && player != 0);
// finally scroll with calculated speed
translation.y -= speed_y * elapsed_time;
-
- // don't scroll before the start or after the level's end
- if(translation.y > level->height * 32 - screen->h)
- translation.y = level->height * 32 - screen->h;
- if(translation.y < 0)
- translation.y = 0;
}
/****** Horizontal scrolling part *******/
|| (player->dir == ::RIGHT && scrollchange == LEFT))
scrollchange = NONE;
// when in left 1/3rd of screen scroll left
- if(player->base.x < translation.x + screen->w/3 && level->back_scrolling)
+ if(player->base.x < translation.x + screen->w/3 && do_backscrolling)
scrollchange = LEFT;
// scroll right when in right 1/3rd of screen
else if(player->base.x > translation.x + screen->w/3*2)
// apply scrolling
translation.x -= speed_x * elapsed_time;
- // don't scroll before the start or after the level's end
- if(translation.x > level->width * 32 - screen->w)
- translation.x = level->width * 32 - screen->w;
- if(translation.x < 0)
- translation.x = 0;
+ keep_in_bounds();
}
void
Camera::scroll_autoscroll(float elapsed_time)
{
- // TODO
+ if(player->dying)
+ return;
+
+ if(auto_t - elapsed_time >= 0) {
+ translation += current_dir * elapsed_time;
+ auto_t -= elapsed_time;
+ } else {
+ // do the rest of the old movement
+ translation += current_dir * auto_t;
+ elapsed_time -= auto_t;
+ auto_t = 0;
+
+ // construct path for next point
+ if(auto_idx+1 >= scrollpoints.size()) {
+ keep_in_bounds();
+ return;
+ }
+ Vector distance = scrollpoints[auto_idx+1].position
+ - scrollpoints[auto_idx].position;
+ current_dir = distance.unit() * scrollpoints[auto_idx].speed;
+ auto_t = distance.norm() / scrollpoints[auto_idx].speed;
+
+ // do movement for the remaining time
+ translation += current_dir * elapsed_time;
+ auto_t -= elapsed_time;
+ auto_idx++;
+ }
+
+ keep_in_bounds();
}
#ifndef __VIEWPORT_H__
#define __VIEWPORT_H__
+#include <vector>
#include "vector.h"
#include "game_object.h"
#include "serializable.h"
}
/// parse camera mode from lisp file
- void parse_camera(LispReader& reader);
+ void read(LispReader& reader);
/// write camera mode to a lisp file
virtual void write(LispWriter& writer);
{
NORMAL, AUTOSCROLL, MANUAL
};
+ CameraMode mode;
private:
void scroll_normal(float elapsed_time);
void scroll_autoscroll(float elapsed_time);
+ void keep_in_bounds();
enum LeftRightScrollChange
{
Player* player;
Level* level;
- CameraMode mode;
// normal mode
+ bool do_backscrolling;
LeftRightScrollChange scrollchange;
// autoscroll mode
+ class ScrollPoint {
+ public:
+ Vector position;
+ float speed;
+ };
+ std::vector<ScrollPoint> scrollpoints;
+ size_t auto_idx;
+ float auto_t;
+ Vector current_dir;
};
#endif
bkgd_image = "arctis.jpg";
width = 0;
height = 0;
- start_pos_x = 100;
- start_pos_y = 170;
+ start_pos.x = 100;
+ start_pos.y = 170;
time_left = 100;
gravity = 10.;
back_scrolling = false;
reader.read_int("version", &version);
if(!reader.read_int("width", &width))
st_abort("No width specified for level.", "");
- if (!reader.read_int("start_pos_x", &start_pos_x)) start_pos_x = 100;
- if (!reader.read_int("start_pos_y", &start_pos_y)) start_pos_y = 170;
+ if (!reader.read_float("start_pos_x", &start_pos.x)) start_pos.x = 100;
+ if (!reader.read_float("start_pos_y", &start_pos.y)) start_pos.y = 170;
time_left = 500;
if(!reader.read_int("time", &time_left)) {
printf("Warning no time specified for level.\n");
}
}
- { // Read BadGuys
+ { // Read Objects
lisp_object_t* cur = 0;
if (reader.read_lisp("objects", &cur))
{
}
}
-#if 0 // TODO fix this or remove it
- // Convert old levels to the new tile numbers
- if (version == 0)
- {
- std::map<char, int> transtable;
- transtable['.'] = 0;
- transtable['x'] = 104;
- transtable['X'] = 77;
- transtable['y'] = 78;
- transtable['Y'] = 105;
- transtable['A'] = 83;
- transtable['B'] = 102;
- transtable['!'] = 103;
- transtable['a'] = 84;
- transtable['C'] = 85;
- transtable['D'] = 86;
- transtable['E'] = 87;
- transtable['F'] = 88;
- transtable['c'] = 89;
- transtable['d'] = 90;
- transtable['e'] = 91;
- transtable['f'] = 92;
-
- transtable['G'] = 93;
- transtable['H'] = 94;
- transtable['I'] = 95;
- transtable['J'] = 96;
-
- transtable['g'] = 97;
- transtable['h'] = 98;
- transtable['i'] = 99;
- transtable['j'] = 100
- ;
- transtable['#'] = 11;
- transtable['['] = 13;
- transtable['='] = 14;
- transtable[']'] = 15;
- transtable['$'] = 82;
- transtable['^'] = 76;
- transtable['*'] = 80;
- transtable['|'] = 79;
- transtable['\\'] = 81;
- transtable['&'] = 75;
-
- int x = 0;
- int y = 0;
- for(std::vector<int>::iterator i = ia_tm.begin(); i != ia_tm.end(); ++i)
- {
- if (*i == '0' || *i == '1' || *i == '2')
- {
- badguy_data.push_back(BadGuyData(static_cast<BadGuyKind>(*i-'0'),
- x*32, y*32, false));
- *i = 0;
- }
- else
- {
- std::map<char, int>::iterator j = transtable.find(*i);
- if (j != transtable.end())
- *i = j->second;
- else
- printf("Error: conversion will fail, unsupported char: '%c' (%d)\n", *i, *i);
- }
- ++x;
- if (x >= width)
- {
- x = 0;
- ++y;
- }
- }
- }
-#endif
+ { // Read Camera
+ lisp_object_t* cur = 0;
+ if (reader.read_lisp("camera", &cur))
+ {
+ LispReader reader(cur);
+ if(world)
+ world->camera->read(reader);
+ }
+ }
}
lisp_free(root_obj);
int width;
int height;
int bkgd_speed;
- int start_pos_x;
- int start_pos_y;
+ Vector start_pos;
float gravity;
bool back_scrolling;
float hor_autoscroll_speed;
void
Player::init()
{
- Level* plevel = World::current()->get_level();
-
holding_something = false;
base.width = 32;
size = SMALL;
got_power = NONE_POWER;
- base.x = plevel->start_pos_x;
- base.y = plevel->start_pos_y;
+ base.x = 0;
+ base.y = 0;
previous_base = old_base = base;
dir = RIGHT;
old_dir = dir;
duck = false;
+ dead = false;
dying = DYING_NOT;
last_ground_y = 0;
{
bool jumped_in_solid = false;
+ if(dying && !dying_timer.check()) {
+ dead = true;
+ return;
+ }
+
if (input.fire == UP)
holding_something = false;
void
Player::kill(HurtMode mode)
{
+ if(dying)
+ return;
+
play_sound(sounds[SND_HURT], SOUND_CENTER_SPEAKER);
physic.set_velocity_x(0);
physic.enable_gravity(true);
physic.set_acceleration(0, 0);
physic.set_velocity(0, 7);
- if(dying != DYING_SQUISHED)
--player_status.lives;
dying = DYING_SQUISHED;
+ dying_timer.start(3000);
}
}
-void
-Player::is_dying()
-{
- remove_powerups();
- dying = DYING_NOT;
-}
-
-bool Player::is_dead()
-{
- float scroll_x =
- World::current()->camera->get_translation().x;
- float scroll_y =
- World::current()->camera->get_translation().y;
- if(base.y > screen->h + scroll_y || base.y > World::current()->get_level()->height*32 ||
- base.x < scroll_x - AUTOSCROLL_DEAD_INTERVAL) // can happen in auto-scrolling
- return true;
- else
- return false;
-}
-
/* Remove Tux's power ups */
void
Player::remove_powerups()
}
void
+Player::move(const Vector& vector)
+{
+ base.x = vector.x;
+ base.y = vector.y;
+ old_base = previous_base = base;
+}
+
+void
Player::check_bounds(Camera& viewport,
bool back_scrolling, bool hor_autoscroll)
{
if (base.y > World::current()->get_level()->height * /*TILE_HEIGHT*/ 32)
{
kill(KILL);
+ return;
}
- if(base.x < viewport.get_translation().x && (!back_scrolling || hor_autoscroll)) // can happen if back scrolling is disabled
+ bool adjust = false;
+ // can happen if back scrolling is disabled
+ if(base.x < viewport.get_translation().x) {
base.x = viewport.get_translation().x;
+ adjust = true;
+ }
+ if(base.x >= viewport.get_translation().x + screen->w - base.width) {
+ base.x = viewport.get_translation().x + screen->w - base.width;
+ adjust = true;
+ }
+
+ if(adjust) {
+ // squished now?
+ if(collision_object_map(base)) {
+ kill(KILL);
+ return;
+ }
+ }
if(hor_autoscroll)
{
int size;
bool duck;
bool holding_something;
+ bool dead;
DyingType dying;
Direction dir;
Timer frame_timer;
Timer kick_timer;
Timer shooting_timer; // used to show the arm when Tux is shooting
+ Timer dying_timer;
Physic physic;
public:
void collision(void* p_c_object, int c_object);
void kill(HurtMode mode);
- void is_dying();
- bool is_dead();
void player_remove_powerups();
void check_bounds(Camera& viewport, bool back_scrolling, bool hor_autoscroll);
bool on_ground();
bool under_solid();
bool tiles_on_air(int tiles);
void grow();
+ void move(const Vector& vector);
+ bool is_dead() const
+ { return dead; }
private:
void init();
--- /dev/null
+#include "vector.h"
+#include <math.h>
+
+Vector Vector::unit() const
+{
+ return *this / norm();
+}
+
+float Vector::norm() const
+{
+ return sqrt(x*x + y*y);
+}
return Vector(x * s, y * s);
}
+ Vector operator/(float s) const
+ {
+ return Vector(x / s, y / s);
+ }
+
const Vector& operator +=(const Vector& other)
{
x += other.x;
return *this;
}
+ // scalar product of 2 vectors
+ float operator*(const Vector& other) const
+ {
+ return x*other.x + y*other.y;
+ }
+
+ float norm() const;
+ Vector unit() const;
+
// ... add the other operators as needed, I'm too lazy now ...
float x, y; // leave this public, get/set methods just give me headaches
// world calls child functions
current_ = this;
+ tux = new Player(displaymanager);
+ add_object(tux);
+
level = new Level();
+ camera = new Camera(tux, level);
+ add_object(camera);
+
if(level_nr >= 0) {
level->load(filename, level_nr, this);
} else {
level->load(filename, this);
}
-
- tux = new Player(displaymanager);
- add_object(tux);
-
+ tux->move(level->start_pos);
+
set_defaults();
level->load_gfx();
add_object(new TileMap(displaymanager, level));
level->load_song();
- camera = new Camera(tux, level);
- add_object(camera);
-
apply_bonuses();
}