Files
letnik3koncni-prap/src/game/agame/friendly.cpp
2026-05-13 07:58:59 +02:00

165 lines
7.7 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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);
}
}