From 837ace3c2abed01142a9793b23b24f84f92408f0 Mon Sep 17 00:00:00 2001 From: Tamir Atias Date: Tue, 21 Feb 2012 02:00:36 +0200 Subject: [PATCH] [Fix] Pathfinding fixes... --- src/Unuk/Player.cpp | 5 +- src/libUnuk/Engine/Character.cpp | 13 +-- src/libUnuk/Engine/Character.h | 2 + src/libUnuk/Engine/NPC.cpp | 138 ++++++++++++++++------------ src/libUnuk/Engine/WorldManager.cpp | 12 +-- src/libUnuk/LevelGen/AStarTile.cpp | 38 +++++--- src/libUnuk/LevelGen/AStarTile.h | 3 +- src/libUnuk/LevelGen/LevelGen.cpp | 97 ++++++++++--------- src/libUnuk/LevelGen/LevelGen.h | 18 ++-- 9 files changed, 176 insertions(+), 150 deletions(-) diff --git a/src/Unuk/Player.cpp b/src/Unuk/Player.cpp index 36e5baa..c3b1f47 100644 --- a/src/Unuk/Player.cpp +++ b/src/Unuk/Player.cpp @@ -100,9 +100,10 @@ void Player::Update(void) { // For now The camera will be static. //SetCamera(); + + tileX = x / AStarTile::FAKE_SIZE; + tileY = y / AStarTile::FAKE_SIZE; - int tileX = x / TILE_WIDTH; - int tileY = y / TILE_HEIGHT; if(tileX != _lastTileX || tileY != _lastTileY) { _lastTileX = tileX; _lastTileY = tileY; diff --git a/src/libUnuk/Engine/Character.cpp b/src/libUnuk/Engine/Character.cpp index d815fbb..fbb1f31 100644 --- a/src/libUnuk/Engine/Character.cpp +++ b/src/libUnuk/Engine/Character.cpp @@ -1,10 +1,7 @@ #include "Character.h" // Pixels * 60 / sec -const float Character::CHARACTER_SPEED = 3.5f; - -static listcollisionList; -static list::iterator collisionIter; +const float Character::CHARACTER_SPEED = 1.0f; Character::Character(LevelGen* mapArg) { map = mapArg; @@ -24,8 +21,6 @@ Character::Character(LevelGen* mapArg) { _texture = NULL; - collisionList.push_front(this); - _healthBar.SetBackgroundRGB(0, 0, 0); _healthBar.SetForegroundRGB(255, 0, 0); @@ -34,12 +29,6 @@ Character::Character(LevelGen* mapArg) { Character::~Character(void) { SDL_FreeSurface(_texture); - for(collisionIter = collisionList.begin(); collisionIter != collisionList.end(); collisionIter++) { - if((*collisionIter) == this) { - collisionList.erase(collisionIter); - break; - } - } } void Character::LoadSprites(string filename, int wArg, int hArg) { diff --git a/src/libUnuk/Engine/Character.h b/src/libUnuk/Engine/Character.h index 6843146..00557ef 100644 --- a/src/libUnuk/Engine/Character.h +++ b/src/libUnuk/Engine/Character.h @@ -46,6 +46,7 @@ public: void OnAttack(void); // Overload new and delete operators to utilize MemManager. + /* inline void* operator new(size_t size) { return gMemManager.Allocate(size); } @@ -61,6 +62,7 @@ public: inline void operator delete [](void* object) { gMemManager.Free(object); } + */ enum { FACING_UP, diff --git a/src/libUnuk/Engine/NPC.cpp b/src/libUnuk/Engine/NPC.cpp index 59adb2b..e2c1422 100644 --- a/src/libUnuk/Engine/NPC.cpp +++ b/src/libUnuk/Engine/NPC.cpp @@ -31,58 +31,78 @@ void NPC::Update(void) { } void NPC::Move(void) { + Character::HealthBarScroll(); + + xVel = 0.0f; + yVel = 0.0f; + + if(!_walkInPath) { + return; + } + Vec2 realPos(x, y); - Vec2 tilePos(tileX, tileY); + + Character* player = map->GetPlayer(); + + SDL_Rect selfRect; + selfRect.x = x - 5; + selfRect.y = y - 5; + selfRect.w = w + 5; + selfRect.h = h + 5; + + SDL_Rect playerRect; + playerRect.x = player->GetX() - 5; + playerRect.y = player->GetY() - 5; + playerRect.w = player->GetWidth() + 5; + playerRect.h = player->GetHeight() + 5; + + if(CheckCollisionRect(selfRect, playerRect)) { + _walkInPath = false; + return; + } + + float targetX = (float)(tileX * AStarTile::FAKE_SIZE); + float targetY = (float)(tileY * AStarTile::FAKE_SIZE); - if(realPos != tilePos) { - float targetX = (float)(tileX * AStarTile::FAKE_SIZE); - float targetY = (float)(tileY * AStarTile::FAKE_SIZE); - - float dx = targetX - realPos.x; - float dy = targetY - realPos.y; - - float distance = sqrtf(dx*dx + dy*dy); - - if(fabs(distance) > CHARACTER_SPEED) { - dx /= distance; - dy /= distance; - dx *= CHARACTER_SPEED; - dy *= CHARACTER_SPEED; - - xVel = dx; - yVel = dy; - - map->MoveIfPossible(this, xVel, yVel, false); - - Character::HealthBarScroll(); - - _moving = true; - } else { - xVel = 0.0f; - yVel = 0.0f; - _moving = false; - } - } else { - xVel = 0.0f; - yVel = 0.0f; - _moving = false; - } - - if(_walkInPath && !_moving) { - Vec2 targetPos((float)_target->GetX(), (float)_target->GetY()); - if(fabs(Vec2::Distance(targetPos, realPos)) <= CHARACTER_SPEED) { - _target = _astar.GetSolutionNext(); - if(_target == NULL || _target == _lastTarget) { - _walkInPath = false; - } else { - tileX = _target->GetX() / AStarTile::FAKE_SIZE; - tileY = _target->GetY() / AStarTile::FAKE_SIZE; - } - } - } + float dx = targetX - realPos.x; + float dy = targetY - realPos.y; + + if(dx > 0.0f) { + xVel = CHARACTER_SPEED; + } + else if(dx < 0.0f) { + xVel = -CHARACTER_SPEED; + } + if(dy > 0.0f) { + yVel = CHARACTER_SPEED; + } + else if(dy < 0.0f) { + yVel = -CHARACTER_SPEED; + } + + if(xVel != 0.0f || yVel != 0.0f) { + map->MoveIfPossible(this, xVel, yVel, false); + } + else { + _target = _astar.GetSolutionNext(); + + if(_target == NULL || _target == _lastTarget) { + _walkInPath = false; + } else { + tileX = _target->GetX() / AStarTile::FAKE_SIZE; + tileY = _target->GetY() / AStarTile::FAKE_SIZE; + } + } } void NPC::OnPlayerMove(Player* player) { + Vec2 selfPos(x, y); + Vec2 playerPos(player->GetX(), player->GetY()); + if(Vec2::DistanceSquared(selfPos, playerPos) > 96*96) { + return; + } + + AStarTile& start = map->GetAStarTile(x / AStarTile::FAKE_SIZE, y / AStarTile::FAKE_SIZE); AStarTile& goal = map->GetAStarTile(player->GetX() / AStarTile::FAKE_SIZE, player->GetY() / AStarTile::FAKE_SIZE); @@ -90,7 +110,6 @@ void NPC::OnPlayerMove(Player* player) { _walkInPath = false; - // Dirty loop to calculate the path while(true) { unsigned int state = _astar.SearchStep(); if(state == AStarSearch::SEARCH_STATE_SUCCEEDED) { @@ -101,13 +120,18 @@ void NPC::OnPlayerMove(Player* player) { } } - _lastTarget = _astar.GetSolutionEnd(); - _target = _astar.GetSolutionStart(); - _target = _astar.GetSolutionNext(); - if(!_target) { - _walkInPath = false; - } else { - tileX = _target->GetX() / AStarTile::FAKE_SIZE; - tileY = _target->GetY() / AStarTile::FAKE_SIZE; - } + if(_walkInPath) { + _lastTarget = _astar.GetSolutionEnd(); + + _target = _astar.GetSolutionStart(); + _target = _astar.GetSolutionNext(); + + if(_target == NULL) { + _walkInPath = false; + _target = NULL; + } else { + tileX = _target->GetX() / AStarTile::FAKE_SIZE; + tileY = _target->GetY() / AStarTile::FAKE_SIZE; + } + } } diff --git a/src/libUnuk/Engine/WorldManager.cpp b/src/libUnuk/Engine/WorldManager.cpp index 23c2806..3bf8650 100644 --- a/src/libUnuk/Engine/WorldManager.cpp +++ b/src/libUnuk/Engine/WorldManager.cpp @@ -83,12 +83,12 @@ bool WorldManager::CheckCollision(const SDL_Rect& charRect, Character* exclude) if(npc == exclude) { continue; } - - SDL_Rect npcRect; - npcRect.x = npc->GetX(); - npcRect.y = npc->GetY(); - npcRect.w = npc->GetWidth(); - npcRect.h = npc->GetHeight(); + + SDL_Rect npcRect; + npcRect.x = npc->GetX(); + npcRect.y = npc->GetY() + (npc->GetHeight() / 4) * 3; + npcRect.w = npc->GetWidth(); + npcRect.h = npc->GetHeight() / 4; if(CheckCollisionRect(npcRect, charRect)) { return true; diff --git a/src/libUnuk/LevelGen/AStarTile.cpp b/src/libUnuk/LevelGen/AStarTile.cpp index d6c49ad..d9eb4ae 100644 --- a/src/libUnuk/LevelGen/AStarTile.cpp +++ b/src/libUnuk/LevelGen/AStarTile.cpp @@ -21,33 +21,45 @@ float AStarTile::GetCost(AStarTile& goal) { } bool AStarTile::GetSuccessors(AStarSearch* search) { - if(_level->MetaTilePassable((x - 1) * FAKE_SIZE, y * FAKE_SIZE)) { + if(!_level) { + return false; + } + + if(x > 0) { AStarTile& successor = _level->GetAStarTile(x - 1, y); - if(!search->AddSuccessor(successor)) { - return false; + if(successor._passable) { + if(!search->AddSuccessor(successor)) { + return false; + } } } - if(_level->MetaTilePassable((x + 1) * FAKE_SIZE, y * FAKE_SIZE)) { + if(x < (levelWidth / FAKE_SIZE)) { AStarTile& successor = _level->GetAStarTile(x + 1, y); - if(!search->AddSuccessor(successor)) { - return false; + if(successor._passable) { + if(!search->AddSuccessor(successor)) { + return false; + } } } - if(_level->MetaTilePassable(x * FAKE_SIZE, (y - 1) * FAKE_SIZE)) { + if(y > 0) { AStarTile& successor = _level->GetAStarTile(x, y - 1); - if(!search->AddSuccessor(successor)) { - return false; + if(successor._passable) { + if(!search->AddSuccessor(successor)) { + return false; + } } } - if(_level->MetaTilePassable(x * FAKE_SIZE, (y + 1) * FAKE_SIZE)) { + if(y < (levelHeight / FAKE_SIZE)) { AStarTile& successor = _level->GetAStarTile(x, y + 1); - if(!search->AddSuccessor(successor)) { - return false; + if(successor._passable) { + if(!search->AddSuccessor(successor)) { + return false; + } } } return true; -} \ No newline at end of file +} diff --git a/src/libUnuk/LevelGen/AStarTile.h b/src/libUnuk/LevelGen/AStarTile.h index ea6e007..1de6a1a 100644 --- a/src/libUnuk/LevelGen/AStarTile.h +++ b/src/libUnuk/LevelGen/AStarTile.h @@ -18,8 +18,7 @@ public: int GetX() { return x * FAKE_SIZE; } int GetY() { return y * FAKE_SIZE; } - static const int FAKE_SIZE = 64 - ; + static const int FAKE_SIZE = 16; private: LevelGen* _level; diff --git a/src/libUnuk/LevelGen/LevelGen.cpp b/src/libUnuk/LevelGen/LevelGen.cpp index 902c3a2..501677f 100644 --- a/src/libUnuk/LevelGen/LevelGen.cpp +++ b/src/libUnuk/LevelGen/LevelGen.cpp @@ -17,8 +17,8 @@ void LevelGen::New(void) { _world = WorldManager(this); - levelWidth = TILE_ARRAY_SIZE; - levelHeight = TILE_ARRAY_SIZE; + levelWidth = TILE_ARRAY_WIDTH; + levelHeight = TILE_ARRAY_HEIGHT; for(x = 0; x < levelWidth; x++) { for(y = 0; y < levelHeight; y++) { @@ -258,23 +258,23 @@ void LevelGen::Render(void) { void LevelGen::Unload(void) { _tileTextures.Unload(); _entityTextures.Unload(); - for(int x = 0; x < TILE_ARRAY_SIZE; x++) { - for(int y = 0; y < TILE_ARRAY_SIZE; y++) { + for(int x = 0; x < TILE_ARRAY_WIDTH; x++) { + for(int y = 0; y < TILE_ARRAY_HEIGHT; y++) { _tile[x][y] = MapTile(); } } } void LevelGen::DoMagic(void) { - GenerateEntities("tree", 25); - GenerateEntities("hedge", 15); - GenerateEntities("barrel", 40); - GenerateEntities("barrel2", 100); - GenerateEntities("stone", 35); - GenerateEntities("stone2", 35); - GenerateEntities("closedChest", 100); - GenerateEntities("closedChestMetal", 150); - GenerateEntities("closedChestMetal2", 250); + GenerateEntities("tree", 45); + GenerateEntities("hedge", 35); + GenerateEntities("barrel", 60); + GenerateEntities("barrel2", 120); + GenerateEntities("stone", 55); + GenerateEntities("stone2", 55); + GenerateEntities("closedChest", 120); + GenerateEntities("closedChestMetal", 170); + GenerateEntities("closedChestMetal2", 270); MakeWalkingPaths(); GenerateEnemies(); } @@ -283,8 +283,8 @@ void LevelGen::GenerateEntities(const string& name, int frequency) { int nextEntityGen = 1 + (rand() % frequency); std::string filename = "../Data/Media/Images/Entities/" + name + ".png"; - for(int x = 0; x < BOUNDARIES_X; x++) { - for(int y = 0; y < BOUNDARIES_Y; y++) { + for(int x = 0; x < TILE_ARRAY_WIDTH; x++) { + for(int y = 0; y < TILE_ARRAY_HEIGHT; y++) { nextEntityGen--; if(!_tile[x][y].GetTileSolidity() && !_tile[x][y].GetEntitySolitity() && nextEntityGen <= 0) { _tile[x][y].SetEntityTextureName(name); @@ -304,10 +304,10 @@ void LevelGen::GenerateEntities(const string& name, int frequency) { void LevelGen::MakeWalkingPaths(void) { int lastOpenY = rand() % 5; - for(int x = 0; x < BOUNDARIES_X; x++) { + for(int x = 0; x < TILE_ARRAY_WIDTH; x++) { bool pathFound = false; - for(int y = 0; y < BOUNDARIES_Y; y++) { + for(int y = 0; y < TILE_ARRAY_HEIGHT; y++) { if(!_tile[x][y].GetEntitySolitity()) { pathFound = true; break; @@ -324,8 +324,8 @@ void LevelGen::MakeWalkingPaths(void) { } void LevelGen::FindSpawnPoint(int& xArg, int& yArg, int objWidth, int objHeight) { - xArg = rand() % (BOUNDARIES_X * TILE_WIDTH); - yArg = rand() % (BOUNDARIES_Y * TILE_HEIGHT); + xArg = rand() % (TILE_ARRAY_WIDTH * TILE_WIDTH); + yArg = rand() % (TILE_ARRAY_HEIGHT * TILE_HEIGHT); if((xArg + objWidth + 1) > SCREEN_WIDTH) { xArg = SCREEN_WIDTH - objWidth - 1; @@ -355,8 +355,8 @@ void LevelGen::FindSpawnPoint(int& xArg, int& yArg, int objWidth, int objHeight) } } - for(int i = 0; i < BOUNDARIES_X; i++) { - for(int j = 0; j < BOUNDARIES_Y; j++) { + for(int i = 0; i < TILE_ARRAY_WIDTH; i++) { + for(int j = 0; j < TILE_ARRAY_HEIGHT; j++) { if(_tile[i][j].GetTileSolidity()) { FindSpawnPoint(xArg, yArg, objWidth, objHeight); return; @@ -395,8 +395,8 @@ void LevelGen::MoveIfPossible(Character* character, float xVel, float yVel, bool return; } - int targetX = character->GetX() + xVel; - int targetY = character->GetY() + yVel; + float targetX = character->GetX() + xVel; + float targetY = character->GetY() + yVel; if(targetX < 0 || targetX > (SCREEN_WIDTH - character->GetWidth()) || targetY < 0 || targetY > (SCREEN_HEIGHT - character->GetHeight())) { @@ -416,8 +416,8 @@ void LevelGen::MoveIfPossible(Character* character, float xVel, float yVel, bool charRect.w = character->GetWidth(); charRect.h = character->GetHeight() / 4; - for(int i = 0; i < BOUNDARIES_X; i++) { - for(int j = 0; j < BOUNDARIES_Y; j++) { + for(int i = 0; i < TILE_ARRAY_WIDTH; i++) { + for(int j = 0; j < TILE_ARRAY_HEIGHT; j++) { if(!_tile[i][j].GetEntitySolitity()) { continue; } @@ -434,8 +434,10 @@ void LevelGen::MoveIfPossible(Character* character, float xVel, float yVel, bool } } - if(_world.CheckCollision(charRect, character)) { - return; + if(true) { + if(_world.CheckCollision(charRect, character)) { + return; + } } if(!isPlayer) { @@ -453,20 +455,15 @@ void LevelGen::MoveIfPossible(Character* character, float xVel, float yVel, bool character->SetXY(targetX, targetY); } -bool LevelGen::MetaTilePassable(int xArg, int yArg) { - if(xArg < 0 || xArg > SCREEN_WIDTH || - yArg < 0 || yArg > SCREEN_HEIGHT) { - return false; - } -/* - SDL_Rect moverRect; - moverRect.x = xArg; - moverRect.y = yArg; - moverRect.w = 40; - moverRect.h = 45; +bool LevelGen::AStarTilePassable(int xArg, int yArg) { + SDL_Rect tileRect; + tileRect.x = xArg * AStarTile::FAKE_SIZE; + tileRect.y = yArg * AStarTile::FAKE_SIZE; + tileRect.w = 40; + tileRect.h = 45; - for(int i = 0; i < BOUNDARIES_X; i++) { - for(int j = 0; j < BOUNDARIES_Y; j++) { + for(int i = 0; i < TILE_ARRAY_WIDTH; i++) { + for(int j = 0; j < TILE_ARRAY_HEIGHT; j++) { if(!_tile[i][j].GetEntitySolitity()) { continue; } @@ -477,7 +474,7 @@ bool LevelGen::MetaTilePassable(int xArg, int yArg) { entityRect.w = _tile[i][j].GetEntityWidth(); entityRect.h = _tile[i][j].GetEntityHeight(); - if(CheckCollisionRect(moverRect, entityRect)) { + if(CheckCollisionRect(tileRect, entityRect)) { return false; } } @@ -485,22 +482,24 @@ bool LevelGen::MetaTilePassable(int xArg, int yArg) { SDL_Rect playerRect; playerRect.x = _player->GetX(); - playerRect.y = _player->GetY(); + playerRect.y = _player->GetY() + (_player->GetHeight() / 4) * 3; playerRect.w = _player->GetWidth(); - playerRect.h = _player->GetHeight(); + playerRect.h = _player->GetHeight() / 4; - if(CheckCollisionRect(moverRect, playerRect)) { + if(CheckCollisionRect(tileRect, playerRect)) { return false; } -*/ + return true; } void LevelGen::UpdateAStarTiles(void) { - for(int x = 0; x < ASTAR_ARRAY_SIZE; x++) { - for(int y = 0; y < ASTAR_ARRAY_SIZE; y++) { - bool passable = MetaTilePassable(x * AStarTile::FAKE_SIZE, y * AStarTile::FAKE_SIZE); - _astarTile[x][y] = AStarTile(this, x, y, passable); + int maxX = levelWidth / AStarTile::FAKE_SIZE; + int maxY = levelHeight / AStarTile::FAKE_SIZE; + + for(int x = 0; x < maxX; x++) { + for(int y = 0; y < maxY; y++) { + _astarTile[x][y] = AStarTile(this, x, y, AStarTilePassable(x, y)); } } } diff --git a/src/libUnuk/LevelGen/LevelGen.h b/src/libUnuk/LevelGen/LevelGen.h index 41a93fb..55d4c49 100644 --- a/src/libUnuk/LevelGen/LevelGen.h +++ b/src/libUnuk/LevelGen/LevelGen.h @@ -34,7 +34,6 @@ public: void FindSpawnPoint(int& xArg, int& yArg, int objWidth, int objHeight); void MoveIfPossible(Character* character, float xVel, float yVel, bool isPlayer = false); - bool MetaTilePassable(int xArg, int yArg); bool GetTileSolidity(int xArg, int yArg); int GetTileX(int xArg, int yArg); @@ -54,7 +53,8 @@ public: WorldManager& GetWorld(void) { return _world; } - void SetPlayer(Player* player) { _player = player; } + void SetPlayer(Player* player) { _player = player; } + Player* GetPlayer() { return _player; } private: void Unload(void); @@ -62,20 +62,20 @@ private: void GenerateEntities(const std::string& name, int frequency); void MakeWalkingPaths(void); void GenerateEnemies(void); + bool AStarTilePassable(int xArg, int yArg); void UpdateAStarTiles(void); string _currentMap; int x; int y; - static const int TILE_ARRAY_SIZE = 15; - MapTile _tile[TILE_ARRAY_SIZE][TILE_ARRAY_SIZE]; + static const int TILE_ARRAY_WIDTH = (SCREEN_WIDTH / TILE_WIDTH) + 1; + static const int TILE_ARRAY_HEIGHT = (SCREEN_HEIGHT / TILE_HEIGHT) + 1; + MapTile _tile[TILE_ARRAY_WIDTH][TILE_ARRAY_HEIGHT]; - static const int ASTAR_ARRAY_SIZE = TILE_ARRAY_SIZE * (TILE_WIDTH / AStarTile::FAKE_SIZE); - AStarTile _astarTile[ASTAR_ARRAY_SIZE][ASTAR_ARRAY_SIZE]; - - static const int BOUNDARIES_X = (SCREEN_WIDTH / TILE_WIDTH); - static const int BOUNDARIES_Y = (SCREEN_HEIGHT / TILE_HEIGHT); + static const int ASTAR_ARRAY_WIDTH = TILE_ARRAY_WIDTH * (TILE_WIDTH / AStarTile::FAKE_SIZE); + static const int ASTAR_ARRAY_HEIGHT = TILE_ARRAY_HEIGHT * (TILE_HEIGHT / AStarTile::FAKE_SIZE); + AStarTile _astarTile[ASTAR_ARRAY_WIDTH][ASTAR_ARRAY_HEIGHT]; TextureManager _tileTextures; TextureManager _entityTextures;