165 lines
7.7 KiB
C++
165 lines
7.7 KiB
C++
#include <game/agame/friendly.hpp>
|
||
#include <game/gamemanager.hpp>
|
||
#include <game/agame/player.hpp>
|
||
#include <game/agame/trash.hpp>
|
||
#include <object/components/boxcollider.hpp>
|
||
#include <state/gamestate.hpp>
|
||
#include <algorithm>
|
||
#include <cmath>
|
||
#include <limits>
|
||
#include <utils.hpp>
|
||
#include <window/window.hpp>
|
||
|
||
namespace Game::AGame {
|
||
void Friendly::start() {
|
||
mZIndex = 20;
|
||
addComponent<Object::Components::BoxCollider>();
|
||
LOG("Zaveznik zagnan: " << getName());
|
||
|
||
const float landBoundaryX = GameManager::getSharedData<float>("terrainLandBoundaryX");
|
||
const float entityWidth = getTexture() ? getTexture()->getWidth() * mTransform.adjustedScaleX() : 0.f;
|
||
mOnSea = (mTransform.x + entityWidth / 2.f) > landBoundaryX;
|
||
|
||
if (!mOnSea) {
|
||
// Initialize random movement for land friendlies
|
||
const float angle = static_cast<float>(Utils::getUtils().rirng32(0, 360)) * 3.14159f / 180.f;
|
||
const float speed = LAND_SPEED_MIN + static_cast<float>(Utils::getUtils().rirng32(0, static_cast<int>(LAND_SPEED_MAX - LAND_SPEED_MIN)));
|
||
mMoveSpeedX = std::cos(angle) * speed;
|
||
mMoveSpeedY = std::sin(angle) * speed;
|
||
} else {
|
||
mMoveSpeedX = 0.f;
|
||
mMoveSpeedY = 0.f;
|
||
}
|
||
mDirectionChangeTimer = 0.f;
|
||
}
|
||
|
||
void Friendly::update(float deltaTime) {
|
||
// Auto-cleanup nearby trash
|
||
const float fw = getTexture() ? getTexture()->getWidth() * mTransform.adjustedScaleX() : 0.f;
|
||
const float fh = getTexture() ? getTexture()->getHeight() * mTransform.adjustedScaleY() : 0.f;
|
||
const float friendlyCenterX = mTransform.x + fw / 2.f;
|
||
const float friendlyCenterY = mTransform.y + fh / 2.f;
|
||
|
||
const float landBoundaryX = GameManager::getSharedData<float>("terrainLandBoundaryX");
|
||
mOnSea = friendlyCenterX > landBoundaryX;
|
||
|
||
if (mOnSea) {
|
||
auto snapshot = State::GameState::getInstance().getEntitiesSnapshot();
|
||
Trash* nearestTrash = nullptr;
|
||
float nearestDistanceSquared = std::numeric_limits<float>::max();
|
||
|
||
for (auto* entity : snapshot) {
|
||
if (!entity) continue;
|
||
auto* trash = dynamic_cast<Trash*>(entity);
|
||
if (!trash) continue;
|
||
|
||
const float tw = trash->getTexture() ? trash->getTexture()->getWidth() * trash->getTransform()->adjustedScaleX() : 0.f;
|
||
const float th = trash->getTexture() ? trash->getTexture()->getHeight() * trash->getTransform()->adjustedScaleY() : 0.f;
|
||
const float trashCenterX = trash->getTransform()->x + tw / 2.f;
|
||
const float trashCenterY = trash->getTransform()->y + th / 2.f;
|
||
const float dx = trashCenterX - friendlyCenterX;
|
||
const float dy = trashCenterY - friendlyCenterY;
|
||
const float distanceSquared = dx * dx + dy * dy;
|
||
|
||
if (distanceSquared < nearestDistanceSquared) {
|
||
nearestDistanceSquared = distanceSquared;
|
||
nearestTrash = trash;
|
||
}
|
||
}
|
||
|
||
if (nearestTrash) {
|
||
const float tw = nearestTrash->getTexture() ? nearestTrash->getTexture()->getWidth() * nearestTrash->getTransform()->adjustedScaleX() : 0.f;
|
||
const float th = nearestTrash->getTexture() ? nearestTrash->getTexture()->getHeight() * nearestTrash->getTransform()->adjustedScaleY() : 0.f;
|
||
const float trashCenterX = nearestTrash->getTransform()->x + tw / 2.f;
|
||
const float trashCenterY = nearestTrash->getTransform()->y + th / 2.f;
|
||
const float dx = trashCenterX - friendlyCenterX;
|
||
const float dy = trashCenterY - friendlyCenterY;
|
||
const float distance = std::sqrt(dx * dx + dy * dy);
|
||
|
||
if (distance > 0.0001f) {
|
||
mMoveSpeedX = (dx / distance) * SEA_SPEED;
|
||
mMoveSpeedY = (dy / distance) * SEA_SPEED;
|
||
}
|
||
}
|
||
} else {
|
||
// Semi-random movement with periodic direction changes on land
|
||
mDirectionChangeTimer += deltaTime;
|
||
if (mDirectionChangeTimer > 2.0f) {
|
||
const float angle = static_cast<float>(Utils::getUtils().rirng32(0, 360)) * 3.14159f / 180.f;
|
||
const float speed = LAND_SPEED_MIN + static_cast<float>(Utils::getUtils().rirng32(0, static_cast<int>(LAND_SPEED_MAX - LAND_SPEED_MIN)));
|
||
mMoveSpeedX = std::cos(angle) * speed;
|
||
mMoveSpeedY = std::sin(angle) * speed;
|
||
mDirectionChangeTimer = 0.f;
|
||
}
|
||
}
|
||
|
||
auto snapshot = State::GameState::getInstance().getEntitiesSnapshot();
|
||
for (auto* entity : snapshot) {
|
||
if (!entity) continue;
|
||
auto* trash = dynamic_cast<Trash*>(entity);
|
||
if (!trash) continue;
|
||
|
||
// Calculate distance to trash
|
||
const float tw = trash->getTexture() ? trash->getTexture()->getWidth() * trash->getTransform()->adjustedScaleX() : 0.f;
|
||
const float th = trash->getTexture() ? trash->getTexture()->getHeight() * trash->getTransform()->adjustedScaleY() : 0.f;
|
||
const float trashCenterX = trash->getTransform()->x + tw / 2.f;
|
||
const float trashCenterY = trash->getTransform()->y + th / 2.f;
|
||
const float dx = friendlyCenterX - trashCenterX;
|
||
const float dy = friendlyCenterY - trashCenterY;
|
||
const float distanceSquared = dx * dx + dy * dy;
|
||
|
||
if (distanceSquared <= CLEANUP_RADIUS * CLEANUP_RADIUS) {
|
||
// Clean up this trash: award points and remove it
|
||
GameManager::setSharedData("gameScore", GameManager::getSharedData<int>("gameScore") + CLEANUP_SCORE_BONUS);
|
||
GameManager::setSharedData("trashActiveCount", std::max(0, GameManager::getSharedData<int>("trashActiveCount") - 1));
|
||
GameManager::destroyEntity(trash);
|
||
}
|
||
}
|
||
|
||
// Move friendly
|
||
mTransform.x += mMoveSpeedX * deltaTime;
|
||
mTransform.y += mMoveSpeedY * deltaTime;
|
||
|
||
// Clamp to land section
|
||
const float halfWidth = fw / 2.f;
|
||
const float halfHeight = fh / 2.f;
|
||
|
||
// Use logical world dimensions (1280×720) not actual screen size
|
||
constexpr int w = 1280;
|
||
constexpr int h = 720;
|
||
const float leftEdge = -w / 2.f + 25.f;
|
||
|
||
if (mTransform.x - halfWidth < leftEdge) {
|
||
mTransform.x = leftEdge + halfWidth;
|
||
mMoveSpeedX = std::abs(mMoveSpeedX);
|
||
}
|
||
if (!mOnSea && mTransform.x + halfWidth > landBoundaryX - 25.f) {
|
||
mTransform.x = landBoundaryX - 25.f - halfWidth;
|
||
mMoveSpeedX = -std::abs(mMoveSpeedX);
|
||
}
|
||
if (mOnSea && 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);
|
||
}
|
||
}
|
||
|
||
void Friendly::onCollisionEnter(Object::Entity* other) {
|
||
auto* player = dynamic_cast<Player*>(other);
|
||
if (!player) {
|
||
return;
|
||
}
|
||
|
||
GameManager::setSharedData("friendlyActiveCount", std::max(0, GameManager::getSharedData<int>("friendlyActiveCount") - 1));
|
||
GameManager::setSharedData("gameScore", GameManager::getSharedData<int>("gameScore") - 50);
|
||
GameManager::destroyEntity(this);
|
||
}
|
||
}
|