X-Git-Url: https://git.verplant.org/?a=blobdiff_plain;f=src%2Fobject%2Ftilemap.cpp;h=576cf48674c48b1ce63c52e0876ea142031c1b3f;hb=fea3446f05e1e7673607b835c269d3e8d1929ab3;hp=578bb51c9d9f652b849786e0bde11f332048c9d2;hpb=37e3ad0ee2ec05d6bfebf611d45046b49fa33387;p=supertux.git diff --git a/src/object/tilemap.cpp b/src/object/tilemap.cpp index 578bb51c9..576cf4867 100644 --- a/src/object/tilemap.cpp +++ b/src/object/tilemap.cpp @@ -1,7 +1,7 @@ // $Id$ // -// SuperTux - A Jump'n Run -// Copyright (C) 2004 Matthias Braun // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License @@ -16,66 +16,83 @@ // 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 #include #include #include #include -#include - -#include "tilemap.h" -#include "video/drawing_context.h" -#include "level.h" -#include "tile.h" -#include "resources.h" -#include "tile_manager.h" -#include "app/globals.h" -#include "lisp/lisp.h" -#include "lisp/writer.h" -#include "object_factory.h" +#include + +#include "tilemap.hpp" +#include "video/drawing_context.hpp" +#include "level.hpp" +#include "tile.hpp" +#include "resources.hpp" +#include "tile_manager.hpp" +#include "lisp/lisp.hpp" +#include "lisp/writer.hpp" +#include "object_factory.hpp" +#include "main.hpp" +#include "log.hpp" +#include "scripting/tilemap.hpp" +#include "scripting/squirrel_util.hpp" TileMap::TileMap() - : solid(false), speed(1), width(0), height(0), layer(LAYER_TILES), - drawing_effect(0) + : solid(false), speed_x(1), speed_y(1), width(0), height(0), z_pos(0), x_offset(0), y_offset(0), + drawing_effect(NO_EFFECT), alpha(1.0), current_alpha(1.0), remaining_fade_time(0), + draw_target(DrawingContext::NORMAL) { tilemanager = tile_manager; - - if(solid) - flags |= FLAG_SOLID; } -TileMap::TileMap(const lisp::Lisp& reader) - : solid(false), speed(1), width(0), height(0), layer(LAYER_TILES), - drawing_effect(0) +TileMap::TileMap(const lisp::Lisp& reader, TileManager* new_tile_manager) + : solid(false), speed_x(1), speed_y(1), width(-1), height(-1), z_pos(0), + x_offset(0), y_offset(0), + drawing_effect(NO_EFFECT), alpha(1.0), current_alpha(1.0), + remaining_fade_time(0), + draw_target(DrawingContext::NORMAL) { - tilemanager = tile_manager; + tilemanager = new_tile_manager; + if(tilemanager == 0) + tilemanager = tile_manager; + + reader.get("name", name); + reader.get("z-pos", z_pos); + reader.get("solid", solid); + reader.get("speed", speed_x); + reader.get("speed-y", speed_y); - std::string layer_str; - if(reader.get("layer", layer_str)) { - if(layer_str == "background") - layer = LAYER_BACKGROUNDTILES; - else if(layer_str == "interactive") - layer = LAYER_TILES; - else if(layer_str == "foreground") - layer = LAYER_FOREGROUNDTILES; - else - std::cerr << "Unknown layer '" << layer_str << "' in tilemap.\n"; + if(solid && ((speed_x != 1) || (speed_y != 1))) { + log_warning << "Speed of solid tilemap is not 1. fixing" << std::endl; + speed_x = 1; + speed_y = 1; } - reader.get("solid", solid); - reader.get("speed", speed); + const lisp::Lisp* pathLisp = reader.get_lisp("path"); + if (pathLisp) { + path.reset(new Path()); + path->read(*pathLisp); + walker.reset(new PathWalker(path.get(), /*running*/false)); + Vector v = path->get_base(); + set_x_offset(v.x); + set_y_offset(v.y); + } + + std::string draw_target_s = "normal"; + reader.get("draw-target", draw_target_s); + if (draw_target_s == "normal") draw_target = DrawingContext::NORMAL; + if (draw_target_s == "lightmap") draw_target = DrawingContext::LIGHTMAP; - if(solid && speed != 1) { - std::cout << "Speed of solid tilemap is not 1. fixing.\n"; - speed = 1; + if (reader.get("alpha", alpha)) { + current_alpha = alpha; } - if(solid) - flags |= FLAG_SOLID; - - if(!reader.get("width", width) || - !reader.get("height", height)) - throw std::runtime_error("No width or height specified in tilemap."); + + reader.get("width", width); + reader.get("height", height); + if(width < 0 || height < 0) + throw std::runtime_error("Invalid/No width/height specified in tilemap."); if(!reader.get_vector("tiles", tiles)) throw std::runtime_error("No tiles in tilemap."); @@ -89,16 +106,16 @@ TileMap::TileMap(const lisp::Lisp& reader) tilemanager->get(*i); } -TileMap::TileMap(int layer_, bool solid_, size_t width_, size_t height_) - : solid(solid_), speed(1), width(0), height(0), layer(layer_), - drawing_effect(0) +TileMap::TileMap(std::string name, int z_pos, bool solid, size_t width, size_t height) + : solid(solid), speed_x(1), speed_y(1), width(0), height(0), z_pos(z_pos), + x_offset(0), y_offset(0), drawing_effect(NO_EFFECT), alpha(1.0), + current_alpha(1.0), remaining_fade_time(0), + draw_target(DrawingContext::NORMAL) { + this->name = name; tilemanager = tile_manager; - - resize(width_, height_); - if(solid) - flags |= FLAG_SOLID; + resize(width, height); } TileMap::~TileMap() @@ -110,86 +127,123 @@ TileMap::write(lisp::Writer& writer) { writer.start_list("tilemap"); - if(layer == LAYER_BACKGROUNDTILES) - writer.write_string("layer", "background"); - else if(layer == LAYER_TILES) - writer.write_string("layer", "interactive"); - else if(layer == LAYER_FOREGROUNDTILES) - writer.write_string("layer", "foreground"); - else { - writer.write_string("layer", "unknown"); - std::cerr << "Warning unknown layer in tilemap.\n"; - } + writer.write_int("z-pos", z_pos); writer.write_bool("solid", solid); - writer.write_float("speed", speed); + writer.write_float("speed", speed_x); + writer.write_float("speed-y", speed_y); writer.write_int("width", width); writer.write_int("height", height); writer.write_int_vector("tiles", tiles); - + writer.end_list("tilemap"); } void -TileMap::action(float ) +TileMap::update(float elapsed_time) { + // handle tilemap fading + if (current_alpha != alpha) { + remaining_fade_time = std::max(0.0f, remaining_fade_time - elapsed_time); + if (remaining_fade_time == 0.0f) { + current_alpha = alpha; + } else { + float amt = (alpha - current_alpha) / (remaining_fade_time / elapsed_time); + if (amt > 0) current_alpha = std::min(current_alpha + amt, alpha); + if (amt < 0) current_alpha = std::max(current_alpha + amt, alpha); + } + if ((alpha < 0.25) && (current_alpha < 0.25)) set_solid(false); + if ((alpha > 0.75) && (current_alpha > 0.75)) set_solid(true); + } + + // if we have a path to follow, follow it + if (walker.get()) { + Vector v = walker->advance(elapsed_time); + set_x_offset(v.x); + set_y_offset(v.y); + } } void TileMap::draw(DrawingContext& context) { + // skip draw if current opacity is set to 0.0 + if (current_alpha == 0.0) return; + context.push_transform(); + context.push_target(); + context.set_target(draw_target); + + if(drawing_effect != 0) context.set_drawing_effect(drawing_effect); + if(current_alpha != 1.0) context.set_alpha(current_alpha); - if(drawing_effect != 0) - context.set_drawing_effect(drawing_effect); float trans_x = roundf(context.get_translation().x); float trans_y = roundf(context.get_translation().y); - context.set_translation(Vector(trans_x * speed, trans_y * speed)); + context.set_translation(Vector(trans_x * speed_x, trans_y * speed_y)); /** if we don't round here, we'll have a 1 pixel gap on screen sometimes. * I have no idea why */ - float start_x = roundf(context.get_translation().x); - if(start_x < 0) start_x = 0; - float start_y = roundf(context.get_translation().y); - if(start_y < 0) start_y = 0; - float end_x = std::min(start_x + screen->w, float(width * 32)); - float end_y = std::min(start_y + screen->h, float(height * 32)); - start_x -= int(start_x) % 32; - start_y -= int(start_y) % 32; - int tsx = int(start_x / 32); // tilestartindex x - int tsy = int(start_y / 32); // tilestartindex y + float start_x = int((roundf(context.get_translation().x) - roundf(x_offset)) / 32) * 32 + roundf(x_offset); + float start_y = int((roundf(context.get_translation().y) - roundf(y_offset)) / 32) * 32 + roundf(y_offset); + float end_x = std::min(start_x + SCREEN_WIDTH + 32, float(width * 32 + roundf(x_offset))); + float end_y = std::min(start_y + SCREEN_HEIGHT + 32, float(height * 32 + roundf(y_offset))); + int tsx = int((start_x - roundf(x_offset)) / 32); // tilestartindex x + int tsy = int((start_y - roundf(y_offset)) / 32); // tilestartindex y Vector pos; int tx, ty; for(pos.x = start_x, tx = tsx; pos.x < end_x; pos.x += 32, ++tx) { for(pos.y = start_y, ty = tsy; pos.y < end_y; pos.y += 32, ++ty) { + if ((tx < 0) || (ty < 0)) continue; const Tile* tile = tilemanager->get(tiles[ty*width + tx]); assert(tile != 0); - tile->draw(context, pos, layer); + tile->draw(context, pos, z_pos); } } - if (debug_grid) - { - for (pos.x = start_x; pos.x < end_x; pos.x += 32) - { - context.draw_filled_rect(Vector (pos.x, start_y), Vector(1, fabsf(start_y - end_y)), - Color(225, 225, 225), LAYER_GUI-50); - } + context.pop_target(); + context.pop_transform(); +} - for (pos.y = start_y; pos.y < end_y; pos.y += 32) - { - context.draw_filled_rect(Vector (start_x, pos.y), Vector(fabsf(start_x - end_x), 1), - Color(225, 225, 225), LAYER_GUI-50); - } - } +void +TileMap::goto_node(int node_no) +{ + if (!walker.get()) return; + walker->goto_node(node_no); +} - context.pop_transform(); +void +TileMap::start_moving() +{ + if (!walker.get()) return; + walker->start_moving(); +} + +void +TileMap::stop_moving() +{ + if (!walker.get()) return; + walker->stop_moving(); +} + +void +TileMap::expose(HSQUIRRELVM vm, SQInteger table_idx) +{ + if (name.empty()) return; + Scripting::TileMap* interface = new Scripting::TileMap(this); + expose_object(vm, table_idx, interface, name, true); +} + +void +TileMap::unexpose(HSQUIRRELVM vm, SQInteger table_idx) +{ + if (name.empty()) return; + Scripting::unexpose_object(vm, table_idx, name); } void TileMap::set(int newwidth, int newheight, const std::vector&newt, - int newlayer, bool newsolid) + int new_z_pos, bool newsolid) { if(int(newt.size()) != newwidth * newheight) throw std::runtime_error("Wrong tilecount count."); @@ -200,18 +254,16 @@ TileMap::set(int newwidth, int newheight, const std::vector&newt, tiles.resize(newt.size()); tiles = newt; - layer = newlayer; + z_pos = new_z_pos; solid = newsolid; - if(solid) - flags |= FLAG_SOLID; // make sure all tiles are loaded for(Tiles::iterator i = tiles.begin(); i != tiles.end(); ++i) - tilemanager->get(*i); + tilemanager->get(*i); } void -TileMap::resize(int new_width, int new_height) +TileMap::resize(int new_width, int new_height, int fill_id) { if(new_width < width) { // remap tiles for new width @@ -221,18 +273,18 @@ TileMap::resize(int new_width, int new_height) } } } - - tiles.resize(new_width * new_height); - + + tiles.resize(new_width * new_height, fill_id); + if(new_width > width) { // remap tiles for(int y = std::min(height, new_height)-1; y >= 0; --y) { for(int x = new_width-1; x >= 0; --x) { if(x >= width) { - tiles[y * new_width + x] = 0; + tiles[y * new_width + x] = fill_id; continue; } - + tiles[y * new_width + x] = tiles[y * width + x]; } } @@ -242,13 +294,17 @@ TileMap::resize(int new_width, int new_height) width = new_width; } +void +TileMap::set_solid(bool solid) +{ + this->solid = solid; +} + const Tile* TileMap::get_tile(int x, int y) const { if(x < 0 || x >= width || y < 0 || y >= height) { -#ifdef DEBUG - //std::cout << "Warning: tile outside tilemap requested!\n"; -#endif + //log_warning << "tile outside tilemap requested" << std::endl; return tilemanager->get(0); } @@ -258,7 +314,7 @@ TileMap::get_tile(int x, int y) const const Tile* TileMap::get_tile_at(const Vector& pos) const { - return get_tile(int(pos.x)/32, int(pos.y)/32); + return get_tile(int(pos.x - x_offset)/32, int(pos.y - y_offset)/32); } void @@ -271,7 +327,40 @@ TileMap::change(int x, int y, uint32_t newtile) void TileMap::change_at(const Vector& pos, uint32_t newtile) { - change(int(pos.x)/32, int(pos.y)/32, newtile); + change(int(pos.x - x_offset)/32, int(pos.y - y_offset)/32, newtile); +} + +void +TileMap::change_all(uint32_t oldtile, uint32_t newtile) +{ + for (size_t x = 0; x < get_width(); x++) + for (size_t y = 0; y < get_height(); y++) { + if (get_tile(x,y)->getID() == oldtile) change(x,y,newtile); + } +} + +void +TileMap::fade(float alpha, float seconds) +{ + this->alpha = alpha; + this->remaining_fade_time = seconds; +} + + +void +TileMap::set_alpha(float alpha) +{ + this->alpha = alpha; + this->current_alpha = alpha; + this->remaining_fade_time = 0; + if (current_alpha < 0.25) set_solid(false); + if (current_alpha > 0.75) set_solid(true); +} + +float +TileMap::get_alpha() +{ + return this->current_alpha; } IMPLEMENT_FACTORY(TileMap, "tilemap");