mapcreator git · master
SDL3 2.5D game and engine using assets, with map editor
C++ 99.3%git clone https://git.christianimmanuel.de/sdl-graphics/mapcreator.gitwget https://git.christianimmanuel.de/sdl-graphics/mapcreator/archive/mapcreator.tar.gzsrc/game/state_playing.cpp raw
#include "state_playing.hpp"
#include "inventory/weapon.hpp"
#include "map/map.hpp"
#include "building/research.hpp"
#include "building/craft.hpp"
#include "game/game.hpp"
#include "defaults/ui.hpp"
#include "character/message.hpp"
#include "defaults/shuffle_texture.hpp"
StatePlaying::StatePlaying() {
std::cout << "CREATE STATE_PLAYING " << this << std::endl;
}
StatePlaying::~StatePlaying() {
std::cout << "STATEPL DTOR " << this << std::endl;
}
StatePlaying::StatePlaying(StatePlaying&&) {
std::cout << "[StatePlaying] Move constructor called!" << std::endl;
}
bool StatePlaying::Init(Game* game) {
std::cout << "Call init state_game\n";
Default::now = SDL_GetPerformanceCounter();
Default::last = 0;
Default::delta_time = 0.0;
cursor = game->cursor;
cursor->set_State(CursorState::HIDDEN);
// INIT Bird
Bird::Init(game->renderer);
player = std::make_unique<Character>();
player->Init(game->renderer);
std::cout << "PLAYER:: " << this << " " << player << std::endl;
// INIT Weapons
Weapon::Init(game->renderer);
// INIT Building
BuildingData::Init(game->renderer);
// INIT Enemy
Enemy::init_All(game->renderer);
Map::tile_map = Map::load_MapTiles(Map::save_path);
if (Map::tile_map.size() == 0) Map::Init();
Map::load_TileCollision(Map::save_collission_path);
if (Map::tile_collission_map.size() == 0) Map::init_Collider();
Map::offset = {0, 0};
Default::game_scale = 4.0;
// START CHEAT
if (game->is_cheating) {
player->inventory->add_Resource(ResourceType::WOOD, 120, player->messages.get());
player->inventory->add_Resource(ResourceType::STONE, 120, player->messages.get());
player->inventory->add_Resource(ResourceType::CLAY, 120, player->messages.get());
player->inventory->add_Resource(ResourceType::IRON, 120, player->messages.get());
player->set_ResourceDiscovery(ResourceType::WOOD);
player->set_ResourceDiscovery(ResourceType::STONE);
player->set_ResourceDiscovery(ResourceType::CLAY);
player->set_ResourceDiscovery(ResourceType::IRON);
player->researched_items[static_cast<size_t>(ItemType::SWORD_WOOD)] = true;
player->researched_items[static_cast<size_t>(ItemType::WOODAXE_STONE)] = true;
player->researched_items[static_cast<size_t>(ItemType::CULTIVATOR)] = true;
player->researched_buildings[static_cast<size_t>(BuildingType::CRAFTING_WOOD_1)] = true;
player->set_BuildingDiscovery();
player->inventory->add_Item(ItemType::SWORD_WOOD, player->messages.get());
player->inventory->add_Item(ItemType::WOODAXE_STONE, player->messages.get());
player->inventory->add_Item(ItemType::BUILDING_TOOL, player->messages.get());
player->inventory->add_Item(ItemType::CULTIVATOR, player->messages.get());
player->inventory->add_Vegetable(VegetableData::Type::CARROT, 4, player->messages.get());
player->inventory->add_Vegetable(VegetableData::Type::CABBAGE, 4, player->messages.get());
player->is_attackable = true;
}
// END CHEAT
// Enemy
Enemy::enemies.clear();
Enemy::enemies_to_spawn.clear();
/*
*/
Enemy::init_SpawnEnemy(0, WeaponType::SWORD, WeaponMaterial::WOOD, {850, 480}, {16,16,2,false,false,0,1.2});
Enemy::init_SpawnEnemy(0, WeaponType::SWORD, WeaponMaterial::WOOD, {450, 480}, {16,16,2,false,false,0,1.2});
Enemy::init_SpawnEnemy(0, WeaponType::SWORD, WeaponMaterial::WOOD, {150, 480}, {16,16,2,false,false,0,1.2});
/*
Enemy::init_SpawnEnemy(1, WeaponType::SWORD, WeaponMaterial::WOOD, {140, 100}, {6,6,1,false,false,0,1.2});
Enemy::init_SpawnEnemy(1, WeaponType::SWORD, WeaponMaterial::WOOD, {100, 10}, {6,6,1,false,false,0,1.2});
Enemy::init_SpawnEnemy(1, WeaponType::SWORD, WeaponMaterial::WOOD, {100, 130}, {6,6,1,false,false,0,1.2});
Enemy::init_SpawnEnemy(1, WeaponType::SWORD, WeaponMaterial::WOOD, {200, 100}, {6,6,1,false,false,0,1.2});
Enemy::init_SpawnEnemy(1, WeaponType::SWORD, WeaponMaterial::WOOD, {600,100}, {6,6,1,false,false,0,1.2});
Enemy::init_SpawnEnemy(1, WeaponType::SWORD, WeaponMaterial::WOOD, {600,100}, {6,6,1,false,false,0,1.2});
*/
//Enemy::init_SpawnEnemy(1, WeaponType::SWORD, WeaponMaterial::WOOD, {150, 100}, {6,6,1,false,false,0,1.2});
//for (int i = 0; i < 12; i++) Enemy::init_SpawnEnemy(1, WeaponType::SWORD, WeaponMaterial::WOOD, {600,100}, {6,6,1,false,false,0,1.2});
return true;
}
inline void setActiveMenu(CharacterMenuType& active_menu, const CharacterMenuType& new_menu, AnimatedCursor* cursor) {
switch (active_menu) {
case CharacterMenuType::NONE:
active_menu = new_menu;
cursor->set_State(CursorState::ANIMATED);
break;
default:
active_menu = CharacterMenuType::NONE;
cursor->set_State(CursorState::HIDDEN);
break;
}
}
void StatePlaying::handle_Events(SDL_Event& event, Game* game) {
if (game->input.cursor_over_tileset) {
game->input.mouse_game_offset = {(int)Tile::tileset_offset.x,
(int)Tile::tileset_offset.y };
}
game->input.clicked_on_map = false;
//std::cout << "ET: " << (int)event.type << std::endl;
switch (event.type) {
case SDL_EVENT_KEY_DOWN: {
if (event.key.scancode >= SDL_SCANCODE_1 && event.key.scancode <= SDL_SCANCODE_6) {
player->inventory->selected_hotbar_last = player->inventory->selected_hotbar;
player->inventory->selected_hotbar = (int)(event.key.scancode - SDL_SCANCODE_1) + 1;
} if (event.key.scancode == SDL_SCANCODE_0) {
Default::game_scale = 4.0;
}
break;
}
case SDL_EVENT_KEY_UP:
switch (event.key.scancode) {
case SDL_SCANCODE_B: {
InventoryItem *sel_item = nullptr;
if (player->selected_item->object_type == InventoryObjectType::ITEM) {
sel_item = static_cast<InventoryItem*>(player->selected_item);
if (sel_item->type == ItemType::BUILDING_TOOL)
setActiveMenu(player->active_menu, CharacterMenuType::BUILDING, cursor);
else
player->messages->Add(MessageKey::BUILDING_TOOL_REQUIRED);
} else
player->messages->Add(MessageKey::BUILDING_TOOL_REQUIRED);
break;
}
case SDL_SCANCODE_R:
Inventory::selected_hotbar = !Inventory::selected_hotbar ? Inventory::selected_hotbar_last : 0;
break;
case SDL_SCANCODE_E:
setActiveMenu(player->active_menu, CharacterMenuType::INVENTORY, cursor);
Inventory::draw_menu = !Inventory::draw_menu;
break;
case SDL_SCANCODE_K: {
Building::construction_mode = Building::construction_mode == BuildingStatus::DECONSTRUCT ?
BuildingStatus::CONSTRUCTING:
BuildingStatus::DECONSTRUCT;
InventoryItem *it = static_cast<InventoryItem*>(player->selected_item);
if (it && it->type == ItemType::CULTIVATOR)
player->cultivation_logic.is_removing = !player->cultivation_logic.is_removing;
break;
}
case SDL_SCANCODE_F5:
player->health_Reduce(100000000);
break;
case SDL_SCANCODE_F11: // FOR TESTING
Enemy::init_SpawnEnemy(0, WeaponType::SWORD, WeaponMaterial::WOOD, {150, 100}, {16,16,2,false,false,0,1.2});
return;
default:
break;
}
break;
case SDL_EVENT_MOUSE_BUTTON_UP:
if (!game->input.pressed_ctrl && !game->input.pressed_shift)
game->input.clicked_on_map = true;
break;
default:
break;
}
}
void update_CameraOffset(
const SDL_FPoint& player_world,
const SDL_Rect& win_size
) {
const float inv_scale = 1.0f / Default::game_scale;
const float logical_w = win_size.w * inv_scale;
const float logical_h = win_size.h * inv_scale;
const float margin_x = logical_w * 0.4f;
const float margin_y = logical_h * 0.4f;
const float player_screen_x = player_world.x + Map::offset.x;
const float player_screen_y = player_world.y + Map::offset.y;
float target_offset_x = Map::offset.x;
float target_offset_y = Map::offset.y;
// Horizontal deadzone
if (player_screen_x < margin_x) {
target_offset_x = margin_x - player_world.x;
}
else if (player_screen_x > logical_w - margin_x) {
target_offset_x = (logical_w - margin_x) - player_world.x;
}
// Vertical deadzone
if (player_screen_y < margin_y) {
target_offset_y = margin_y - player_world.y;
}
else if (player_screen_y > logical_h - margin_y) {
target_offset_y = (logical_h - margin_y) - player_world.y;
}
// --- Smooth interpolation ---
const float follow_speed = 10.0f; // higher = snappier
const float t = 1.0f - std::exp(-follow_speed * Default::delta_time);
Map::offset.x += (target_offset_x - Map::offset.x) * t;
Map::offset.y += (target_offset_y - Map::offset.y) * t;
}
void StatePlaying::Update(Game* game) {
// SET Map offset
Map::set_Offset(game->input);
// VEGETABLES
for (Vegetable* veg : VegetableData::all_vegetables) {
veg->Grow(Default::get_TimeSinceStartInSec());
}
// CHARACTER
player->handle_Input(game->input, game->win_size);
player->Update();
if (player->status == CharacterStatus::DEAD && player->death_shuffler == nullptr) {
player->death_shuffler = new PixelShuffler(game->renderer, player->active_anim->surface);
player->shuffle_timer = 0.0f;
Animation::audio->Play("character.dead");
return;
}
// MESSAGES
player->messages->Update();
// START ENEMY HANDLING
// spawn
for (size_t i = 0; i < Enemy::enemies_to_spawn.size(); ) {
SpawnParams &sp = Enemy::enemies_to_spawn[i];
if (Enemy::spawn_Enemy(sp))
Enemy::enemies_to_spawn.erase(Enemy::enemies_to_spawn.begin() + static_cast<long>(i));
else
++i;
}
// get moves
Enemy::run_GetMovesThreads();
// update moves
for (Enemy* enemy : Enemy::enemies)
enemy->Update(*player);
// clear dead
Enemy::remove_Dead();
// END ENEMY HANDLING
// CAMERA
update_CameraOffset({player->x+player->tile_size/2, player->y+player->tile_size/2}, game->win_size);
}
void StatePlaying::Render(Game* game) {
if (!game->renderer)
std::cerr << "ERROR in StatePlayin::Render\n";
player->messages->render_InventoryMessages(game, player->inventory.get());
switch (player->active_menu) {
case CharacterMenuType::NONE: break;
case CharacterMenuType::BUILDING:
BuildingData::draw_WorkbenchMenu(game->renderer, game->win_size, player->discovered_buildings);
break;
case CharacterMenuType::INVENTORY:
player->inventory->draw_Menu( game->renderer, game->win_size, Ui::font_menu, player->researched_items, Inventory::cursor_OverCraftButton(game->input.mouse_state_raw));
break;
case CharacterMenuType::RESEARCH:
Research::draw_ReserachMenu(game->renderer, game->win_size, Building::selected_building_type, player->researched_buildings, player->researched_items, Research::cursor_OverResearchButton(game->input.mouse_state_raw));
break;
case CharacterMenuType::WORKBENCH:
Craft::draw_CraftMenu(game, Building::selected_building_type, Craft::cursor_OverCraftButton(game->input.mouse_state_raw));
break;
}
player->inventory->draw_Hotbar(game->renderer, Ui::font_menu);
//player->messages->render_ResourceMessages(game, player->inventory->resources);
Ui::draw_BottomLeftBars(game->renderer, game->win_size, *player);
}
void StatePlaying::Load(SDL_Renderer* renderer, std::string path) {
Map::tile_map = Map::load_MapTiles(path + "/map");
std::cout << "STATE LOAD\n";
Map::load_TileCollision(path + "/collisions");
if (!renderer)
std::cerr << "FUCK NO RENDERER..\n";
Enemy::load_All(path+"/enemies");
for (size_t i = 0; i < Enemy::enemies_to_spawn.size(); ) {
SpawnParams &sp = Enemy::enemies_to_spawn[i];
if (Enemy::spawn_Enemy(sp))
Enemy::enemies_to_spawn.erase(Enemy::enemies_to_spawn.begin() + static_cast<long>(i));
else
++i;
}
player->Load(path);
}
void StatePlaying::Save(std::string path) {
Map::save_MapTiles(Map::tile_map, path + "/map");
Map::save_TileCollision(path + "/collisions");
Enemy::save_All(path+"/enemies");
player->Save(path);
}