This commit is contained in:
2026-05-02 15:18:39 +02:00
parent 8be2cea49a
commit 56d567b77d
19 changed files with 634 additions and 94 deletions

View File

@@ -1,22 +1,129 @@
#include <game/agame/enemy.hpp>
#include <object/components/boxcollider.hpp>
#include <game/agame/player.hpp>
#include <state/gamestate.hpp>
#include <algorithm>
#include <cmath>
#include <utils.hpp>
#include <game/gamemanager.hpp>
#include <window/window.hpp>
namespace Game::AGame {
void Enemy::start() {
mZIndex = 20;
addComponent<Object::Components::BoxCollider>();
LOG("Enemy started: " << getName());
// Initialize random movement
const float angle = static_cast<float>(Utils::getUtils().rirng32(0, 360)) * 3.14159f / 180.f;
const float speed = 20.f + static_cast<float>(Utils::getUtils().rirng32(0, 30));
mMoveSpeedX = std::cos(angle) * speed;
mMoveSpeedY = std::sin(angle) * speed;
mDirectionChangeTimer = 0.f;
}
void Enemy::update(float deltaTime) {
return;
(void)deltaTime;
auto* player = GameManager::getEntityByName<Player>("Player");
if (!player) {
mIsVisible = false;
return;
}
// Enemies are always visible
mIsVisible = true;
// Semi-random movement with periodic direction changes
mDirectionChangeTimer += deltaTime;
if (mDirectionChangeTimer > 2.0f) {
const float angle = static_cast<float>(Utils::getUtils().rirng32(0, 360)) * 3.14159f / 180.f;
const float speed = 20.f + static_cast<float>(Utils::getUtils().rirng32(0, 30));
mMoveSpeedX = std::cos(angle) * speed;
mMoveSpeedY = std::sin(angle) * speed;
mDirectionChangeTimer = 0.f;
}
// Move enemy
mTransform.x += mMoveSpeedX * deltaTime;
mTransform.y += mMoveSpeedY * deltaTime;
// Clamp to land section
const float landBoundaryX = GameManager::getSharedData<float>("terrainLandBoundaryX");
const float entityWidth = getTexture() ? getTexture()->getWidth() * mTransform.adjustedScaleX() : 0.f;
const float entityHeight = getTexture() ? getTexture()->getHeight() * mTransform.adjustedScaleY() : 0.f;
const float halfWidth = entityWidth / 2.f;
const float halfHeight = entityHeight / 2.f;
// Get window dimensions for boundary calculations
int w = 0, h = 0;
SDL_GetWindowSizeInPixels(Window::Window::getSDLWindowBackend(), &w, &h);
const float leftEdge = -w / 2.f + 25.f;
if (mTransform.x - halfWidth < leftEdge) {
mTransform.x = leftEdge + halfWidth;
mMoveSpeedX = std::abs(mMoveSpeedX);
}
if (mTransform.x + halfWidth > landBoundaryX - 25.f) {
mTransform.x = landBoundaryX - 25.f - halfWidth;
mMoveSpeedX = -std::abs(mMoveSpeedX);
}
if (mTransform.y - halfHeight < -h / 2.f + 25.f) {
mTransform.y = -h / 2.f + 25.f + halfHeight;
mMoveSpeedY = std::abs(mMoveSpeedY);
}
if (mTransform.y + halfHeight > h / 2.f - 25.f) {
mTransform.y = h / 2.f - 25.f - halfHeight;
mMoveSpeedY = -std::abs(mMoveSpeedY);
}
}
bool Enemy::hasAdjacentEnemy() {
if (!getTexture()) return false;
const float detectionRadius = 40.f;
const float enemyWidth = getTexture()->getWidth() * mTransform.adjustedScaleX();
const float enemyHeight = getTexture()->getHeight() * mTransform.adjustedScaleY();
const float centerX = mTransform.x + enemyWidth / 2.f;
const float centerY = mTransform.y + enemyHeight / 2.f;
auto entities = GameManager::getEntityByName<Object::Entity>("Dummy");
if (!entities) {
auto snapshot = State::GameState::getInstance().getEntitiesSnapshot();
for (auto* other : snapshot) {
if (!other || other == this || !dynamic_cast<Enemy*>(other)) continue;
auto* otherEnemy = dynamic_cast<Enemy*>(other);
if (!otherEnemy || !otherEnemy->getTexture()) continue;
const float otherWidth = otherEnemy->getTexture()->getWidth() * otherEnemy->getTransform()->adjustedScaleX();
const float otherHeight = otherEnemy->getTexture()->getHeight() * otherEnemy->getTransform()->adjustedScaleY();
const float otherCenterX = otherEnemy->getTransform()->x + otherWidth / 2.f;
const float otherCenterY = otherEnemy->getTransform()->y + otherHeight / 2.f;
const float dx = centerX - otherCenterX;
const float dy = centerY - otherCenterY;
if (dx * dx + dy * dy <= detectionRadius * detectionRadius) {
return true;
}
}
}
return false;
}
void Enemy::onCollisionEnter(Object::Entity* other) {
LOG("Enemy '" << getName() << "' collided with '" << other->getName() << "' (onCollisionEnter); Killing myself now!");
GameManager::setSharedData("enemyActiveCount", GameManager::getSharedData<int>("enemyActiveCount") - 1);
// Find in state
auto* player = dynamic_cast<Player*>(other);
if (!player || !mIsVisible) {
return;
}
if (hasAdjacentEnemy()) {
LOG("Player collided with a strong group of polluters; game over!");
GameManager::setSharedData("gameLost", true);
GameManager::destroyEntity(player);
return;
}
LOG("Enemy '" << getName() << "' collided with player; removing polluter and awarding points");
GameManager::setSharedData("enemyActiveCount", std::max(0, GameManager::getSharedData<int>("enemyActiveCount") - 1));
GameManager::setSharedData("gameScore", GameManager::getSharedData<int>("gameScore") + 100);
GameManager::destroyEntity(this);
}
}