MyCurry/src/gamelib/ingamescene.cpp

161 lines
5.7 KiB
C++

/*
Copyright 2016, 2017 Michele "King_DuckZ" Santullo
This file is part of MyCurry.
MyCurry 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.
MyCurry 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 MyCurry. If not, see <http://www.gnu.org/licenses/>.
*/
#include "ingamescene.hpp"
#include "sdlmain.hpp"
#include "mycurry_toplevelConfig.h"
#include "key.hpp"
#include "inputbag.hpp"
#include "movingobject.hpp"
#include "worldgrid.hpp"
#include "worldviewport.hpp"
#include "texture.hpp"
#include "rect.hpp"
#include "character.hpp"
#include "csvloader.hpp"
#include "worlditems.hpp"
#include "gameactions.hpp"
#include "vector.hpp"
#include "drawing_queue.hpp"
#include "safe_stack_object.hpp"
#include <SDL2/SDL.h>
#include <algorithm>
#include <vector>
#include <fstream>
#include <boost/utility/string_ref.hpp>
#include <boost/lexical_cast.hpp>
#include <cassert>
#include <ciso646>
namespace curry {
namespace {
void add_layer_assert_done (DrawingQueue& parDQ, DrawaLayerNames parName) {
const bool layer_added = parDQ.add_layer(parName);
assert(layer_added);
static_cast<void>(layer_added);
}
} //unnamed namespace
struct IngameScene::LocalData {
LocalData (const vec2us& parTileSize, cloonel::SDLMain* parSDLMain, cloonel::InputBag* parInputBag) :
world(parTileSize),
viewport(&world, vec2f(cl_vec2us(parSDLMain->WidthHeight())), WorldSizeNotifiable::DeferredRegister(&world, &viewport)),
player(parTileSize),
character(parInputBag, WorldSizeNotifiable::DeferredRegister(&world, &character))
{
}
WorldGrid world;
WorldViewport viewport;
SafeStackObject<Texture> worldtiles;
MovingObject player;
Character character;
WorldItems moveable_items;
};
IngameScene::IngameScene (cloonel::SDLMain* parSDLMain) :
GameSceneBase(parSDLMain),
m_local_data(std::make_unique<LocalData>(vec2us(32), parSDLMain, &this->input_bag()))
{
using cloonel::Key;
using cloonel::InputDevice_Keyboard;
auto& inp = this->input_bag();
inp.AddAction(ActionLeft, Key(InputDevice_Keyboard, SDL_SCANCODE_LEFT), "Move left");
inp.AddAction(ActionUp, Key(InputDevice_Keyboard, SDL_SCANCODE_UP), "Move up");
inp.AddAction(ActionRight, Key(InputDevice_Keyboard, SDL_SCANCODE_RIGHT), "Move right");
inp.AddAction(ActionDown, Key(InputDevice_Keyboard, SDL_SCANCODE_DOWN), "Move down");
add_layer_assert_done(drawing_queue(), DrawaLayerNames::Background);
add_layer_assert_done(drawing_queue(), DrawaLayerNames::Characters);
#if !defined(NDEBUG)
add_layer_assert_done(drawing_queue(), DrawaLayerNames::Debug);
#endif
}
IngameScene::~IngameScene() noexcept = default;
void IngameScene::on_prepare() {
m_local_data->worldtiles->load(RESOURCES_PATH "nonfree_texture.png", *this->sdl_main(), RGBA{255, 255, 255, 0});
CSVJointData tiles = load_csv({
RESOURCES_PATH "nonfree_map_ground.csv",
RESOURCES_PATH "nonfree_map_transparent.csv"
});
vec2us world_size(tiles.width, tiles.height);
m_local_data->world.set_layers(world_size, tiles.tables);
m_local_data->world.set_tile_properties(tiles.tile_properties);
#if !defined(NDEBUG)
std::cout << "World size set to " << world_size << '\n';
#endif
m_local_data->viewport.allow_overscan(false);
m_local_data->character.add_texture(RESOURCES_PATH "LPC_Sara_Preview.png", *this->sdl_main());
const float speed_per_sec =
static_cast<float>(
std::max(m_local_data->world.tile_size().x(), m_local_data->world.tile_size().y())
) * 4.5f;
m_local_data->character.set_speed(speed_per_sec);
assert(m_local_data->moveable_items.no_items_registered());
m_local_data->moveable_items.register_observer(&m_local_data->character);
}
void IngameScene::on_update (float parDeltaT) {
const auto& world = m_local_data->world;
auto& viewport = m_local_data->viewport;
m_local_data->moveable_items.move_items(parDeltaT);
viewport.set_position(m_local_data->character.position() - (viewport.size() - m_local_data->character.width_height()) / 2.0f);
//TODO: move drawing code into the world map or something
const auto tilesize(static_cast<vec2f>(world.tile_size()));
const auto tilecount(m_local_data->worldtiles->width_height() / world.tile_size());
for (auto tile : viewport) {
for (uint16_t z = 0; z < m_local_data->world.layer_count(); ++z) {
if (tile.index[z] < 0)
continue;
vec2f idx(static_cast<float>(tile.index[z] % tilecount.x()), static_cast<float>(tile.index[z] / tilecount.x()));
vec2f src_rect_xy = idx * tilesize;
vec2f pixel_pos = vector_cast<vec2f>(tile.pixel_pos);
Rect<float> src_rect(src_rect_xy, src_rect_xy + tilesize);
Rect<float> dst_rect(pixel_pos, pixel_pos + tilesize);
this->draw(DrawaLayerNames::Background, m_local_data->worldtiles, src_rect, dst_rect);
}
}
m_local_data->character.draw(drawing_queue(), viewport);
}
void IngameScene::on_destroy() noexcept {
m_local_data->moveable_items.unregister_all();
m_local_data->worldtiles->unload();
m_local_data->character.unload_textures();
}
void IngameScene::draw (DrawaLayerNames parLayer, Kakoune::SafePtr<Texture>& parTexture, Rect<float> parSrc, Rect<float> parDest) {
DrawingQueue::ItemInfo item{};
item.source = parSrc;
item.destination = parDest;
item.texture = parTexture;
drawing_queue().add_for_rendering(parLayer, std::move(item));
assert(not item.texture);
}
} //namespace curry