[Fix] Pathfinding fixes...

This commit is contained in:
Tamir Atias 2012-02-21 02:00:36 +02:00
parent 61f1f2b2a4
commit 837ace3c2a
9 changed files with 176 additions and 150 deletions

View File

@ -101,8 +101,9 @@ void Player::Update(void) {
// For now The camera will be static. // For now The camera will be static.
//SetCamera(); //SetCamera();
int tileX = x / TILE_WIDTH; tileX = x / AStarTile::FAKE_SIZE;
int tileY = y / TILE_HEIGHT; tileY = y / AStarTile::FAKE_SIZE;
if(tileX != _lastTileX || tileY != _lastTileY) { if(tileX != _lastTileX || tileY != _lastTileY) {
_lastTileX = tileX; _lastTileX = tileX;
_lastTileY = tileY; _lastTileY = tileY;

View File

@ -1,10 +1,7 @@
#include "Character.h" #include "Character.h"
// Pixels * 60 / sec // Pixels * 60 / sec
const float Character::CHARACTER_SPEED = 3.5f; const float Character::CHARACTER_SPEED = 1.0f;
static list<Character*>collisionList;
static list<Character*>::iterator collisionIter;
Character::Character(LevelGen* mapArg) { Character::Character(LevelGen* mapArg) {
map = mapArg; map = mapArg;
@ -24,8 +21,6 @@ Character::Character(LevelGen* mapArg) {
_texture = NULL; _texture = NULL;
collisionList.push_front(this);
_healthBar.SetBackgroundRGB(0, 0, 0); _healthBar.SetBackgroundRGB(0, 0, 0);
_healthBar.SetForegroundRGB(255, 0, 0); _healthBar.SetForegroundRGB(255, 0, 0);
@ -34,12 +29,6 @@ Character::Character(LevelGen* mapArg) {
Character::~Character(void) { Character::~Character(void) {
SDL_FreeSurface(_texture); 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) { void Character::LoadSprites(string filename, int wArg, int hArg) {

View File

@ -46,6 +46,7 @@ public:
void OnAttack(void); void OnAttack(void);
// Overload new and delete operators to utilize MemManager. // Overload new and delete operators to utilize MemManager.
/*
inline void* operator new(size_t size) { inline void* operator new(size_t size) {
return gMemManager.Allocate(size); return gMemManager.Allocate(size);
} }
@ -61,6 +62,7 @@ public:
inline void operator delete [](void* object) { inline void operator delete [](void* object) {
gMemManager.Free(object); gMemManager.Free(object);
} }
*/
enum { enum {
FACING_UP, FACING_UP,

View File

@ -31,47 +31,61 @@ void NPC::Update(void) {
} }
void NPC::Move(void) { void NPC::Move(void) {
Vec2 realPos(x, y); Character::HealthBarScroll();
Vec2 tilePos(tileX, tileY);
xVel = 0.0f;
yVel = 0.0f;
if(!_walkInPath) {
return;
}
Vec2 realPos(x, y);
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;
}
if(realPos != tilePos) {
float targetX = (float)(tileX * AStarTile::FAKE_SIZE); float targetX = (float)(tileX * AStarTile::FAKE_SIZE);
float targetY = (float)(tileY * AStarTile::FAKE_SIZE); float targetY = (float)(tileY * AStarTile::FAKE_SIZE);
float dx = targetX - realPos.x; float dx = targetX - realPos.x;
float dy = targetY - realPos.y; float dy = targetY - realPos.y;
float distance = sqrtf(dx*dx + dy*dy); if(dx > 0.0f) {
xVel = CHARACTER_SPEED;
if(fabs(distance) > CHARACTER_SPEED) { }
dx /= distance; else if(dx < 0.0f) {
dy /= distance; xVel = -CHARACTER_SPEED;
dx *= CHARACTER_SPEED; }
dy *= CHARACTER_SPEED; if(dy > 0.0f) {
yVel = CHARACTER_SPEED;
xVel = dx; }
yVel = dy; else if(dy < 0.0f) {
yVel = -CHARACTER_SPEED;
}
if(xVel != 0.0f || yVel != 0.0f) {
map->MoveIfPossible(this, xVel, yVel, false); map->MoveIfPossible(this, xVel, yVel, false);
Character::HealthBarScroll();
_moving = true;
} else {
xVel = 0.0f;
yVel = 0.0f;
_moving = false;
} }
} else { 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(); _target = _astar.GetSolutionNext();
if(_target == NULL || _target == _lastTarget) { if(_target == NULL || _target == _lastTarget) {
_walkInPath = false; _walkInPath = false;
} else { } else {
@ -80,9 +94,15 @@ void NPC::Move(void) {
} }
} }
} }
}
void NPC::OnPlayerMove(Player* player) { 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& 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); 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; _walkInPath = false;
// Dirty loop to calculate the path
while(true) { while(true) {
unsigned int state = _astar.SearchStep(); unsigned int state = _astar.SearchStep();
if(state == AStarSearch<AStarTile>::SEARCH_STATE_SUCCEEDED) { if(state == AStarSearch<AStarTile>::SEARCH_STATE_SUCCEEDED) {
@ -101,13 +120,18 @@ void NPC::OnPlayerMove(Player* player) {
} }
} }
if(_walkInPath) {
_lastTarget = _astar.GetSolutionEnd(); _lastTarget = _astar.GetSolutionEnd();
_target = _astar.GetSolutionStart(); _target = _astar.GetSolutionStart();
_target = _astar.GetSolutionNext(); _target = _astar.GetSolutionNext();
if(!_target) {
if(_target == NULL) {
_walkInPath = false; _walkInPath = false;
_target = NULL;
} else { } else {
tileX = _target->GetX() / AStarTile::FAKE_SIZE; tileX = _target->GetX() / AStarTile::FAKE_SIZE;
tileY = _target->GetY() / AStarTile::FAKE_SIZE; tileY = _target->GetY() / AStarTile::FAKE_SIZE;
} }
} }
}

View File

@ -86,9 +86,9 @@ bool WorldManager::CheckCollision(const SDL_Rect& charRect, Character* exclude)
SDL_Rect npcRect; SDL_Rect npcRect;
npcRect.x = npc->GetX(); npcRect.x = npc->GetX();
npcRect.y = npc->GetY(); npcRect.y = npc->GetY() + (npc->GetHeight() / 4) * 3;
npcRect.w = npc->GetWidth(); npcRect.w = npc->GetWidth();
npcRect.h = npc->GetHeight(); npcRect.h = npc->GetHeight() / 4;
if(CheckCollisionRect(npcRect, charRect)) { if(CheckCollisionRect(npcRect, charRect)) {
return true; return true;

View File

@ -21,33 +21,45 @@ float AStarTile::GetCost(AStarTile& goal) {
} }
bool AStarTile::GetSuccessors(AStarSearch<AStarTile>* search) { bool AStarTile::GetSuccessors(AStarSearch<AStarTile>* 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); AStarTile& successor = _level->GetAStarTile(x - 1, y);
if(successor._passable) {
if(!search->AddSuccessor(successor)) { if(!search->AddSuccessor(successor)) {
return false; return false;
} }
} }
}
if(_level->MetaTilePassable((x + 1) * FAKE_SIZE, y * FAKE_SIZE)) { if(x < (levelWidth / FAKE_SIZE)) {
AStarTile& successor = _level->GetAStarTile(x + 1, y); AStarTile& successor = _level->GetAStarTile(x + 1, y);
if(successor._passable) {
if(!search->AddSuccessor(successor)) { if(!search->AddSuccessor(successor)) {
return false; return false;
} }
} }
}
if(_level->MetaTilePassable(x * FAKE_SIZE, (y - 1) * FAKE_SIZE)) { if(y > 0) {
AStarTile& successor = _level->GetAStarTile(x, y - 1); AStarTile& successor = _level->GetAStarTile(x, y - 1);
if(successor._passable) {
if(!search->AddSuccessor(successor)) { if(!search->AddSuccessor(successor)) {
return false; return false;
} }
} }
}
if(_level->MetaTilePassable(x * FAKE_SIZE, (y + 1) * FAKE_SIZE)) { if(y < (levelHeight / FAKE_SIZE)) {
AStarTile& successor = _level->GetAStarTile(x, y + 1); AStarTile& successor = _level->GetAStarTile(x, y + 1);
if(successor._passable) {
if(!search->AddSuccessor(successor)) { if(!search->AddSuccessor(successor)) {
return false; return false;
} }
} }
}
return true; return true;
} }

View File

@ -18,8 +18,7 @@ public:
int GetX() { return x * FAKE_SIZE; } int GetX() { return x * FAKE_SIZE; }
int GetY() { return y * FAKE_SIZE; } int GetY() { return y * FAKE_SIZE; }
static const int FAKE_SIZE = 64 static const int FAKE_SIZE = 16;
;
private: private:
LevelGen* _level; LevelGen* _level;

View File

@ -17,8 +17,8 @@ void LevelGen::New(void) {
_world = WorldManager(this); _world = WorldManager(this);
levelWidth = TILE_ARRAY_SIZE; levelWidth = TILE_ARRAY_WIDTH;
levelHeight = TILE_ARRAY_SIZE; levelHeight = TILE_ARRAY_HEIGHT;
for(x = 0; x < levelWidth; x++) { for(x = 0; x < levelWidth; x++) {
for(y = 0; y < levelHeight; y++) { for(y = 0; y < levelHeight; y++) {
@ -258,23 +258,23 @@ void LevelGen::Render(void) {
void LevelGen::Unload(void) { void LevelGen::Unload(void) {
_tileTextures.Unload(); _tileTextures.Unload();
_entityTextures.Unload(); _entityTextures.Unload();
for(int x = 0; x < TILE_ARRAY_SIZE; x++) { for(int x = 0; x < TILE_ARRAY_WIDTH; x++) {
for(int y = 0; y < TILE_ARRAY_SIZE; y++) { for(int y = 0; y < TILE_ARRAY_HEIGHT; y++) {
_tile[x][y] = MapTile(); _tile[x][y] = MapTile();
} }
} }
} }
void LevelGen::DoMagic(void) { void LevelGen::DoMagic(void) {
GenerateEntities("tree", 25); GenerateEntities("tree", 45);
GenerateEntities("hedge", 15); GenerateEntities("hedge", 35);
GenerateEntities("barrel", 40); GenerateEntities("barrel", 60);
GenerateEntities("barrel2", 100); GenerateEntities("barrel2", 120);
GenerateEntities("stone", 35); GenerateEntities("stone", 55);
GenerateEntities("stone2", 35); GenerateEntities("stone2", 55);
GenerateEntities("closedChest", 100); GenerateEntities("closedChest", 120);
GenerateEntities("closedChestMetal", 150); GenerateEntities("closedChestMetal", 170);
GenerateEntities("closedChestMetal2", 250); GenerateEntities("closedChestMetal2", 270);
MakeWalkingPaths(); MakeWalkingPaths();
GenerateEnemies(); GenerateEnemies();
} }
@ -283,8 +283,8 @@ void LevelGen::GenerateEntities(const string& name, int frequency) {
int nextEntityGen = 1 + (rand() % frequency); int nextEntityGen = 1 + (rand() % frequency);
std::string filename = "../Data/Media/Images/Entities/" + name + ".png"; std::string filename = "../Data/Media/Images/Entities/" + name + ".png";
for(int x = 0; x < BOUNDARIES_X; x++) { for(int x = 0; x < TILE_ARRAY_WIDTH; x++) {
for(int y = 0; y < BOUNDARIES_Y; y++) { for(int y = 0; y < TILE_ARRAY_HEIGHT; y++) {
nextEntityGen--; nextEntityGen--;
if(!_tile[x][y].GetTileSolidity() && !_tile[x][y].GetEntitySolitity() && nextEntityGen <= 0) { if(!_tile[x][y].GetTileSolidity() && !_tile[x][y].GetEntitySolitity() && nextEntityGen <= 0) {
_tile[x][y].SetEntityTextureName(name); _tile[x][y].SetEntityTextureName(name);
@ -304,10 +304,10 @@ void LevelGen::GenerateEntities(const string& name, int frequency) {
void LevelGen::MakeWalkingPaths(void) { void LevelGen::MakeWalkingPaths(void) {
int lastOpenY = rand() % 5; int lastOpenY = rand() % 5;
for(int x = 0; x < BOUNDARIES_X; x++) { for(int x = 0; x < TILE_ARRAY_WIDTH; x++) {
bool pathFound = false; 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()) { if(!_tile[x][y].GetEntitySolitity()) {
pathFound = true; pathFound = true;
break; break;
@ -324,8 +324,8 @@ void LevelGen::MakeWalkingPaths(void) {
} }
void LevelGen::FindSpawnPoint(int& xArg, int& yArg, int objWidth, int objHeight) { void LevelGen::FindSpawnPoint(int& xArg, int& yArg, int objWidth, int objHeight) {
xArg = rand() % (BOUNDARIES_X * TILE_WIDTH); xArg = rand() % (TILE_ARRAY_WIDTH * TILE_WIDTH);
yArg = rand() % (BOUNDARIES_Y * TILE_HEIGHT); yArg = rand() % (TILE_ARRAY_HEIGHT * TILE_HEIGHT);
if((xArg + objWidth + 1) > SCREEN_WIDTH) { if((xArg + objWidth + 1) > SCREEN_WIDTH) {
xArg = SCREEN_WIDTH - objWidth - 1; 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 i = 0; i < TILE_ARRAY_WIDTH; i++) {
for(int j = 0; j < BOUNDARIES_Y; j++) { for(int j = 0; j < TILE_ARRAY_HEIGHT; j++) {
if(_tile[i][j].GetTileSolidity()) { if(_tile[i][j].GetTileSolidity()) {
FindSpawnPoint(xArg, yArg, objWidth, objHeight); FindSpawnPoint(xArg, yArg, objWidth, objHeight);
return; return;
@ -395,8 +395,8 @@ void LevelGen::MoveIfPossible(Character* character, float xVel, float yVel, bool
return; return;
} }
int targetX = character->GetX() + xVel; float targetX = character->GetX() + xVel;
int targetY = character->GetY() + yVel; float targetY = character->GetY() + yVel;
if(targetX < 0 || targetX > (SCREEN_WIDTH - character->GetWidth()) || if(targetX < 0 || targetX > (SCREEN_WIDTH - character->GetWidth()) ||
targetY < 0 || targetY > (SCREEN_HEIGHT - character->GetHeight())) { 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.w = character->GetWidth();
charRect.h = character->GetHeight() / 4; charRect.h = character->GetHeight() / 4;
for(int i = 0; i < BOUNDARIES_X; i++) { for(int i = 0; i < TILE_ARRAY_WIDTH; i++) {
for(int j = 0; j < BOUNDARIES_Y; j++) { for(int j = 0; j < TILE_ARRAY_HEIGHT; j++) {
if(!_tile[i][j].GetEntitySolitity()) { if(!_tile[i][j].GetEntitySolitity()) {
continue; continue;
} }
@ -434,9 +434,11 @@ void LevelGen::MoveIfPossible(Character* character, float xVel, float yVel, bool
} }
} }
if(true) {
if(_world.CheckCollision(charRect, character)) { if(_world.CheckCollision(charRect, character)) {
return; return;
} }
}
if(!isPlayer) { if(!isPlayer) {
SDL_Rect playerRect; SDL_Rect playerRect;
@ -453,20 +455,15 @@ void LevelGen::MoveIfPossible(Character* character, float xVel, float yVel, bool
character->SetXY(targetX, targetY); character->SetXY(targetX, targetY);
} }
bool LevelGen::MetaTilePassable(int xArg, int yArg) { bool LevelGen::AStarTilePassable(int xArg, int yArg) {
if(xArg < 0 || xArg > SCREEN_WIDTH || SDL_Rect tileRect;
yArg < 0 || yArg > SCREEN_HEIGHT) { tileRect.x = xArg * AStarTile::FAKE_SIZE;
return false; tileRect.y = yArg * AStarTile::FAKE_SIZE;
} tileRect.w = 40;
/* tileRect.h = 45;
SDL_Rect moverRect;
moverRect.x = xArg;
moverRect.y = yArg;
moverRect.w = 40;
moverRect.h = 45;
for(int i = 0; i < BOUNDARIES_X; i++) { for(int i = 0; i < TILE_ARRAY_WIDTH; i++) {
for(int j = 0; j < BOUNDARIES_Y; j++) { for(int j = 0; j < TILE_ARRAY_HEIGHT; j++) {
if(!_tile[i][j].GetEntitySolitity()) { if(!_tile[i][j].GetEntitySolitity()) {
continue; continue;
} }
@ -477,7 +474,7 @@ bool LevelGen::MetaTilePassable(int xArg, int yArg) {
entityRect.w = _tile[i][j].GetEntityWidth(); entityRect.w = _tile[i][j].GetEntityWidth();
entityRect.h = _tile[i][j].GetEntityHeight(); entityRect.h = _tile[i][j].GetEntityHeight();
if(CheckCollisionRect(moverRect, entityRect)) { if(CheckCollisionRect(tileRect, entityRect)) {
return false; return false;
} }
} }
@ -485,22 +482,24 @@ bool LevelGen::MetaTilePassable(int xArg, int yArg) {
SDL_Rect playerRect; SDL_Rect playerRect;
playerRect.x = _player->GetX(); playerRect.x = _player->GetX();
playerRect.y = _player->GetY(); playerRect.y = _player->GetY() + (_player->GetHeight() / 4) * 3;
playerRect.w = _player->GetWidth(); playerRect.w = _player->GetWidth();
playerRect.h = _player->GetHeight(); playerRect.h = _player->GetHeight() / 4;
if(CheckCollisionRect(moverRect, playerRect)) { if(CheckCollisionRect(tileRect, playerRect)) {
return false; return false;
} }
*/
return true; return true;
} }
void LevelGen::UpdateAStarTiles(void) { void LevelGen::UpdateAStarTiles(void) {
for(int x = 0; x < ASTAR_ARRAY_SIZE; x++) { int maxX = levelWidth / AStarTile::FAKE_SIZE;
for(int y = 0; y < ASTAR_ARRAY_SIZE; y++) { int maxY = levelHeight / AStarTile::FAKE_SIZE;
bool passable = MetaTilePassable(x * AStarTile::FAKE_SIZE, y * AStarTile::FAKE_SIZE);
_astarTile[x][y] = AStarTile(this, x, y, passable); for(int x = 0; x < maxX; x++) {
for(int y = 0; y < maxY; y++) {
_astarTile[x][y] = AStarTile(this, x, y, AStarTilePassable(x, y));
} }
} }
} }

View File

@ -34,7 +34,6 @@ public:
void FindSpawnPoint(int& xArg, int& yArg, int objWidth, int objHeight); void FindSpawnPoint(int& xArg, int& yArg, int objWidth, int objHeight);
void MoveIfPossible(Character* character, float xVel, float yVel, bool isPlayer = false); void MoveIfPossible(Character* character, float xVel, float yVel, bool isPlayer = false);
bool MetaTilePassable(int xArg, int yArg);
bool GetTileSolidity(int xArg, int yArg); bool GetTileSolidity(int xArg, int yArg);
int GetTileX(int xArg, int yArg); int GetTileX(int xArg, int yArg);
@ -55,6 +54,7 @@ public:
WorldManager& GetWorld(void) { return _world; } WorldManager& GetWorld(void) { return _world; }
void SetPlayer(Player* player) { _player = player; } void SetPlayer(Player* player) { _player = player; }
Player* GetPlayer() { return _player; }
private: private:
void Unload(void); void Unload(void);
@ -62,20 +62,20 @@ private:
void GenerateEntities(const std::string& name, int frequency); void GenerateEntities(const std::string& name, int frequency);
void MakeWalkingPaths(void); void MakeWalkingPaths(void);
void GenerateEnemies(void); void GenerateEnemies(void);
bool AStarTilePassable(int xArg, int yArg);
void UpdateAStarTiles(void); void UpdateAStarTiles(void);
string _currentMap; string _currentMap;
int x; int x;
int y; int y;
static const int TILE_ARRAY_SIZE = 15; static const int TILE_ARRAY_WIDTH = (SCREEN_WIDTH / TILE_WIDTH) + 1;
MapTile _tile[TILE_ARRAY_SIZE][TILE_ARRAY_SIZE]; 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); static const int ASTAR_ARRAY_WIDTH = TILE_ARRAY_WIDTH * (TILE_WIDTH / AStarTile::FAKE_SIZE);
AStarTile _astarTile[ASTAR_ARRAY_SIZE][ASTAR_ARRAY_SIZE]; static const int ASTAR_ARRAY_HEIGHT = TILE_ARRAY_HEIGHT * (TILE_HEIGHT / AStarTile::FAKE_SIZE);
AStarTile _astarTile[ASTAR_ARRAY_WIDTH][ASTAR_ARRAY_HEIGHT];
static const int BOUNDARIES_X = (SCREEN_WIDTH / TILE_WIDTH);
static const int BOUNDARIES_Y = (SCREEN_HEIGHT / TILE_HEIGHT);
TextureManager _tileTextures; TextureManager _tileTextures;
TextureManager _entityTextures; TextureManager _entityTextures;