Skip to content

bruno0135/PhysicsGame

Repository files navigation

#include "Scene.h" #include "Engine.h" #include "Input.h" #include "Textures.h" #include "Audio.h" #include "Render.h" #include "Window.h" #include "Log.h" #include "Entity.h" #include "EntityManager.h" #include "Player.h" #include "Map.h" #include "Item.h" #include "EnemySpider.h" #include "EnemyBat.h" #include "Physics.h" #include <pugixml.hpp>

Scene::Scene() { name = "scene"; }

Scene::~Scene() {}

bool Scene::Awake() { LOG("Loading Scene");

player = std::dynamic_pointer_cast<Player>(
    Engine::GetInstance().entityManager->CreateEntity(EntityType::PLAYER));

coin = std::dynamic_pointer_cast<Item>(
    Engine::GetInstance().entityManager->CreateEntity(EntityType::ITEM));
coin->position = coinInitialPos;

spider1 = std::dynamic_pointer_cast<EnemySpider>(
    Engine::GetInstance().entityManager->CreateEntity(EntityType::ENEMY_GROUND));
spider1->position = Vector2D(800, 300);

spider2 = std::dynamic_pointer_cast<EnemySpider>(
    Engine::GetInstance().entityManager->CreateEntity(EntityType::ENEMY_GROUND));
spider2->position = Vector2D(1500, 300);

bat1 = std::dynamic_pointer_cast<EnemyBat>(
    Engine::GetInstance().entityManager->CreateEntity(EntityType::ENEMY_FLY));
bat1->position = Vector2D(1000, 200);

bat2 = std::dynamic_pointer_cast<EnemyBat>(
    Engine::GetInstance().entityManager->CreateEntity(EntityType::ENEMY_FLY));
bat2->position = Vector2D(1700, 200);

return true;

}

bool Scene::Start() { Engine::GetInstance().audio->PlayMusic("Assets/Audio/Music/backgroundmusic.wav");

Engine::GetInstance().map->Load("Assets/Maps/", "Mapa5.tmx");

// Cargar textura de vidas
heartsTexture = Engine::GetInstance().textures->Load("Assets/Textures/Vidas.png");
if (heartsTexture)
{
    Engine::GetInstance().textures->GetSize(heartsTexture, heartW, heartH);
}
else
{
    LOG("Scene: could not load hearts texture Vidas.png");
}

return true;

}

bool Scene::PreUpdate() { return true; }

bool Scene::Update(float dt) { float camSpeed = 1.0f;

if (Engine::GetInstance().input->GetKey(SDL_SCANCODE_UP) == KEY_REPEAT)
    Engine::GetInstance().render->camera.y -= (int)ceil(camSpeed * dt);
if (Engine::GetInstance().input->GetKey(SDL_SCANCODE_DOWN) == KEY_REPEAT)
    Engine::GetInstance().render->camera.y += (int)ceil(camSpeed * dt);
if (Engine::GetInstance().input->GetKey(SDL_SCANCODE_LEFT) == KEY_REPEAT)
    Engine::GetInstance().render->camera.x -= (int)ceil(camSpeed * dt);
if (Engine::GetInstance().input->GetKey(SDL_SCANCODE_RIGHT) == KEY_REPEAT)
    Engine::GetInstance().render->camera.x += (int)ceil(camSpeed * dt);

// F1 - Cargar Nivel 1 (Mapa5.tmx)
if (Engine::GetInstance().input->GetKey(SDL_SCANCODE_F1) == KEY_DOWN)
{
    LoadMap1();
}

// F2 - Cargar Nivel 2 (map2.tmx) - Solo player y música
if (Engine::GetInstance().input->GetKey(SDL_SCANCODE_F2) == KEY_DOWN)
{
    LoadMap2();
}

// F5 - Guardar partida
if (Engine::GetInstance().input->GetKey(SDL_SCANCODE_F5) == KEY_DOWN)
{
    SaveGame();
}

// F6 - Cargar partida
if (Engine::GetInstance().input->GetKey(SDL_SCANCODE_F6) == KEY_DOWN)
{
    LoadGame();
}

return true;

}

bool Scene::PostUpdate() { if (Engine::GetInstance().input->GetKey(SDL_SCANCODE_ESCAPE) == KEY_DOWN) return false;

// HUD de vidas
if (heartsTexture && player)
{
    int maxLives = player->GetMaxDeaths();
    int usedLives = player->GetDeathCount();
    int livesLeft = maxLives - usedLives;

    if (livesLeft < 0) livesLeft = 0;
    if (livesLeft > maxLives) livesLeft = maxLives;

    int startX = 10;
    int startY = 10;
    int spacing = (heartW > 0 ? heartW + 4 : 40);

    for (int i = 0; i < livesLeft; ++i)
    {
        int x = startX + i * spacing;
        int y = startY;

        Engine::GetInstance().render->DrawTexture(
            heartsTexture,
            x,
            y,
            nullptr,
            0.0f
        );
    }
}

return true;

}

bool Scene::CleanUp() { LOG("Freeing scene");

if (heartsTexture)
{
    Engine::GetInstance().textures->UnLoad(heartsTexture);
    heartsTexture = nullptr;
}

return true;

}

void Scene::ResetLevel() { if (!coin || !coin->active) { coin = std::dynamic_pointer_cast( Engine::GetInstance().entityManager->CreateEntity(EntityType::ITEM));

    coin->position = coinInitialPos;
    coin->Start();
}

}

Vector2D Scene::GetPlayerPosition() const { if (player) return player->position; return Vector2D(0, 0); }

void Scene::ResetEnemies() { LOG("Resetting all enemies to initial positions");

if (spider1) spider1->ResetPosition();
if (spider2) spider2->ResetPosition();
if (bat1) bat1->ResetPosition();
if (bat2) bat2->ResetPosition();

}

// ==================================================================== // CAMBIO DE MAPAS // ====================================================================

void Scene::LoadMap1() { LOG("Loading Map 1 (Mapa5.tmx) - Full level with enemies");

// 1. Limpiar el mapa anterior completamente
Engine::GetInstance().map->CleanUp();

// 2. Limpiar física
Engine::GetInstance().physics->CleanUp();
Engine::GetInstance().physics->Start();

// 3. Cargar el nuevo mapa
Engine::GetInstance().map->Load("Assets/Maps/", "Mapa5.tmx");

// 4. Recrear el cuerpo físico del player
if (player)
{
    player->CleanUp();  // Limpia el pbody anterior
    player->Start();    // Crea un nuevo pbody
}

// 5. Recrear los cuerpos físicos de los enemigos y moneda
if (coin)
{
    coin->CleanUp();
    coin->Start();
    coin->isPicked = false;
    coin->position = coinInitialPos;
}

if (spider1) { spider1->CleanUp(); spider1->Start(); }
if (spider2) { spider2->CleanUp(); spider2->Start(); }
if (bat1) { bat1->CleanUp(); bat1->Start(); }
if (bat2) { bat2->CleanUp(); bat2->Start(); }

// 6. Resetear posiciones del jugador
if (player)
{
    player->ResetToInitialSpawn();
    Vector2D spawnPos = player->position;
    float groundY = Engine::GetInstance().map->GetGroundYBelow(spawnPos.getX(), spawnPos.getY());
    if (player->pbody)
    {
        player->pbody->SetPosition((int)spawnPos.getX(), (int)(groundY - player->texH / 2));
        Engine::GetInstance().physics->SetLinearVelocity(player->pbody, 0.0f, 0.0f);
    }
}

// 7. Resetear enemigos
ResetEnemies();

LOG("Map 1 loaded successfully");

}

void Scene::LoadMap2() { LOG("Loading Map 2 (map2.tmx) - Player only, no enemies");

// 1. Limpiar el mapa anterior completamente
Engine::GetInstance().map->CleanUp();

// 2. Limpiar física
Engine::GetInstance().physics->CleanUp();
Engine::GetInstance().physics->Start();

// 3. Cargar el nuevo mapa
Engine::GetInstance().map->Load("Assets/Maps/", "map2.tmx");

// 4. Recrear el cuerpo físico del player
if (player)
{
    player->CleanUp();  // Limpia el pbody anterior
    player->Start();    // Crea un nuevo pbody
}

// 5. Desactivar todos los enemigos y la moneda
if (coin) coin->Disable();
if (spider1) spider1->Disable();
if (spider2) spider2->Disable();
if (bat1) bat1->Disable();
if (bat2) bat2->Disable();

// 6. Solo resetear el player
if (player)
{
    player->ResetToInitialSpawn();
    Vector2D spawnPos = player->position;
    float groundY = Engine::GetInstance().map->GetGroundYBelow(spawnPos.getX(), spawnPos.getY());
    if (player->pbody)
    {
        player->pbody->SetPosition((int)spawnPos.getX(), (int)(groundY - player->texH / 2));
        Engine::GetInstance().physics->SetLinearVelocity(player->pbody, 0.0f, 0.0f);
    }
}

// La música ya está sonando, no hace falta cambiarla
LOG("Map 2 loaded - Only player active");

}

// ==================================================================== // SISTEMA SAVE/LOAD // ====================================================================

bool Scene::SaveGame() { LOG("Saving game state...");

pugi::xml_document saveDoc;
pugi::xml_node root = saveDoc.append_child("save");

// Guardar Player usando position (público)
if (player)
{
    pugi::xml_node playerNode = root.append_child("player");

    playerNode.append_attribute("x").set_value((int)player->position.getX());
    playerNode.append_attribute("y").set_value((int)player->position.getY());
    playerNode.append_attribute("deathCount").set_value(player->GetDeathCount());

    LOG("Player saved at (%.1f, %.1f)", player->position.getX(), player->position.getY());
}

// Guardar Spider1 usando position (público)
if (spider1)
{
    pugi::xml_node spiderNode = root.append_child("spider1");

    spiderNode.append_attribute("x").set_value((int)spider1->position.getX());
    spiderNode.append_attribute("y").set_value((int)spider1->position.getY());

    LOG("Spider1 saved at (%.1f, %.1f)", spider1->position.getX(), spider1->position.getY());
}

// Guardar Spider2
if (spider2)
{
    pugi::xml_node spiderNode = root.append_child("spider2");

    spiderNode.append_attribute("x").set_value((int)spider2->position.getX());
    spiderNode.append_attribute("y").set_value((int)spider2->position.getY());

    LOG("Spider2 saved at (%.1f, %.1f)", spider2->position.getX(), spider2->position.getY());
}

// Guardar Bat1
if (bat1)
{
    pugi::xml_node batNode = root.append_child("bat1");

    batNode.append_attribute("x").set_value((int)bat1->position.getX());
    batNode.append_attribute("y").set_value((int)bat1->position.getY());

    LOG("Bat1 saved at (%.1f, %.1f)", bat1->position.getX(), bat1->position.getY());
}

// Guardar Bat2
if (bat2)
{
    pugi::xml_node batNode = root.append_child("bat2");

    batNode.append_attribute("x").set_value((int)bat2->position.getX());
    batNode.append_attribute("y").set_value((int)bat2->position.getY());

    LOG("Bat2 saved at (%.1f, %.1f)", bat2->position.getX(), bat2->position.getY());
}

// Guardar archivo
bool result = saveDoc.save_file("savegame.xml");

if (result)
{
    LOG("Game saved successfully to savegame.xml");
}
else
{
    LOG("ERROR: Failed to save game to savegame.xml");
}

return result;

}

bool Scene::LoadGame() { LOG("Loading game state...");

pugi::xml_document saveDoc;
pugi::xml_parse_result result = saveDoc.load_file("savegame.xml");

if (!result)
{
    LOG("ERROR: Could not load savegame.xml: %s", result.description());
    return false;
}

pugi::xml_node root = saveDoc.child("save");
if (!root)
{
    LOG("ERROR: savegame.xml has no <save> root node");
    return false;
}

// Cargar Player
pugi::xml_node playerNode = root.child("player");
if (playerNode && player && player->pbody)
{
    int px = playerNode.attribute("x").as_int();
    int py = playerNode.attribute("y").as_int();

    player->pbody->SetPosition(px, py);
    player->position.setX((float)px);
    player->position.setY((float)py);

    // Resetear velocidad
    Engine::GetInstance().physics->SetLinearVelocity(player->pbody, 0.0f, 0.0f);

    LOG("Player loaded at (%d, %d)", px, py);
}

// Cargar Spider1 - usando position y ResetPosition() modificado
pugi::xml_node spider1Node = root.child("spider1");
if (spider1Node && spider1)
{
    int sx = spider1Node.attribute("x").as_int();
    int sy = spider1Node.attribute("y").as_int();

    // Actualizar initialPosition temporalmente para que ResetPosition use estos valores
    Vector2D savedPos((float)sx, (float)sy);
    spider1->initialPosition = savedPos;
    spider1->ResetPosition();

    LOG("Spider1 loaded at (%d, %d)", sx, sy);
}

// Cargar Spider2
pugi::xml_node spider2Node = root.child("spider2");
if (spider2Node && spider2)
{
    int sx = spider2Node.attribute("x").as_int();
    int sy = spider2Node.attribute("y").as_int();

    Vector2D savedPos((float)sx, (float)sy);
    spider2->initialPosition = savedPos;
    spider2->ResetPosition();

    LOG("Spider2 loaded at (%d, %d)", sx, sy);
}

// Cargar Bat1
pugi::xml_node bat1Node = root.child("bat1");
if (bat1Node && bat1)
{
    int bx = bat1Node.attribute("x").as_int();
    int by = bat1Node.attribute("y").as_int();

    Vector2D savedPos((float)bx, (float)by);
    bat1->initialPosition = savedPos;
    bat1->ResetPosition();

    LOG("Bat1 loaded at (%d, %d)", bx, by);
}

// Cargar Bat2
pugi::xml_node bat2Node = root.child("bat2");
if (bat2Node && bat2)
{
    int bx = bat2Node.attribute("x").as_int();
    int by = bat2Node.attribute("y").as_int();

    Vector2D savedPos((float)bx, (float)by);
    bat2->initialPosition = savedPos;
    bat2->ResetPosition();

    LOG("Bat2 loaded at (%d, %d)", bx, by);
}

LOG("Game loaded successfully from savegame.xml");
return true;

}

#pragma once

#include "Module.h" #include "Player.h" #include "Item.h" #include "Vector2D.h" #include

class EnemySpider; class EnemyBat;

class Scene : public Module { public: Scene(); virtual ~Scene(); bool Awake() override; bool Start() override; bool PreUpdate() override; bool Update(float dt) override; bool PostUpdate() override; bool CleanUp() override;

void ResetLevel();
void ResetEnemies();

Vector2D GetPlayerPosition() const;

// Sistema Save/Load
bool SaveGame();
bool LoadGame();

// Cambio de mapas
void LoadMap1();  // Carga Mapa5.tmx con todos los enemigos
void LoadMap2();  // Carga map2.tmx solo con player y música

private: std::shared_ptr player;

std::shared_ptr<Item> coin;
Vector2D coinInitialPos = Vector2D(1300, 375);

// Referencias a los enemigos
std::shared_ptr<EnemySpider> spider1;
std::shared_ptr<EnemySpider> spider2;
std::shared_ptr<EnemyBat>    bat1;
std::shared_ptr<EnemyBat>    bat2;

// HUD de vidas
SDL_Texture* heartsTexture = nullptr;
int heartW = 0;
int heartH = 0;

};

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors