restructuring and updating CMakeLists

This commit is contained in:
2017-07-16 14:04:41 -07:00
parent 769c37f148
commit aa593870df
16 changed files with 96 additions and 26 deletions

198
src/App.cpp Normal file
View File

@@ -0,0 +1,198 @@
#include "App.h"
#include <iostream>
#include "Map.h"
#include <chrono>
#ifdef linux
#elif defined _WIN32
#elif defined TARGET_OS_MAC
#endif
// ========== Constructors =============
App::App() {
window = new sf::RenderWindow(sf::VideoMode(WINDOW_WIDTH, WINDOW_HEIGHT), "aStart Pathing Demo");
}
App::~App() { }
// ========== Mutes =============
void App::Init() {
// Set up the background texture
background_texture = new sf::Texture();
background_texture->loadFromFile("../assets/background.png");
backgroundSprite.setTexture(*background_texture);
// Pixel array for drawing the tiles, explorer
_pixelArray = new sf::Uint8[WINDOW_WIDTH * WINDOW_HEIGHT * 4];
pixel_array_texture.create(WINDOW_WIDTH, WINDOW_HEIGHT);
// Create the explorer, giving it a reference to the map data
explorer = new Explorer(&map);
}
void App::Input() {
while (window->pollEvent(event)) {
if (event.type == sf::Event::Closed)
window->close();
// Set the destination
if (sf::Mouse::isButtonPressed(sf::Mouse::Left)) {
sf::Vector2i mouse_position = sf::Mouse::getPosition(*window);
explorer->setDestination(sf::Vector2i(mouse_position.x/ 5, mouse_position.y/ 5));
}
if (event.type == sf::Event::KeyPressed) {
if (event.key.code == sf::Keyboard::Q) {
explorer->setDestination(sf::Vector2i(20, 20));
}
if (event.key.code == sf::Keyboard::W) {
explorer->setDestination(sf::Vector2i(50, 50));
}
if (event.key.code == sf::Keyboard::E) {
explorer->setDestination(sf::Vector2i(100, 12));
}
}
}
}
void App::Update(double step_size) {
Input();
// Have the explorer go one move forward
explorer->move();
}
void App::Render() {
// HOUSEKEEPING
// Get the physics fps for the last render cycle
physics_fps = physics_frame_count * render_fps;
// Frame time in seconds
frame_time = delta_time * 1000;
// And the render fps
render_fps = 1000 / frame_time;
// RENDERING
// Clear and draw a fresh background
window->clear(sf::Color::Blue);
window->draw(backgroundSprite);
// Clean up the pixel array and reset everything to 0's again
for (int i = 0; i < WINDOW_WIDTH * WINDOW_HEIGHT * 4; i++) {
_pixelArray[i] = 0;
}
// Color all the tiles
for (int x = 0; x < Map::CELLS_WIDTH; x++) {
for (int y = 0; y < Map::CELLS_HEIGHT; y++) {
// Get the current cell position
sf::Vector2i pos;
pos.x = x;
pos.y = y;
// Use that to find the color of the tile at that position
sf::Color thing = map.getTile(pos)->getColor();
// Fill the 4x4 pixel area taken up by the cell
for (int x2 = 1; x2 < 5; x2++) {
for (int y2 = 1; y2 < 5; y2++) {
int pixel_x = (x * 5) + x2;
int pixel_y = (y * 5) + y2;
_pixelArray[(pixel_y * WINDOW_WIDTH + pixel_x) * 4] = thing.r; // Red
_pixelArray[(pixel_y * WINDOW_WIDTH + pixel_x) * 4 + 1] = thing.g; // Green
_pixelArray[(pixel_y * WINDOW_WIDTH + pixel_x) * 4 + 2] = thing.b; // Blue
_pixelArray[(pixel_y * WINDOW_WIDTH + pixel_x) * 4 + 3] = thing.a; // Alpha
}
}
}
}
// Draw the explorer
// Basically the same as above, fills 4x4 area where the explorer is located
for (int x2 = 1; x2 < 5; x2++) {
for (int y2 = 1; y2 < 5; y2++) {
int pixel_x = (explorer->getPosition().x * 5) + x2;
int pixel_y = (explorer->getPosition().y * 5) + y2;
sf::Color color = explorer->getColor();
_pixelArray[(pixel_y * WINDOW_WIDTH + pixel_x) * 4] = color.r; // Red
_pixelArray[(pixel_y * WINDOW_WIDTH + pixel_x) * 4 + 1] = color.g; // Green
_pixelArray[(pixel_y * WINDOW_WIDTH + pixel_x) * 4 + 2] = color.b; // Blue
_pixelArray[(pixel_y * WINDOW_WIDTH + pixel_x) * 4 + 3] = color.a; // Alpha
}
}
// Update and draw the pixel array
pixel_array_texture.update(_pixelArray);
pixel_array_sprite.setTexture(pixel_array_texture);
window->draw(pixel_array_sprite);
// Finish!
window->display();
}
void App::Run() {
Init();
while (window->isOpen()) {
// Time since app start
elapsed_time = time();
// Time between last frame start and this frame
// 2 seconds = 30 seconds - 28 seconds
delta_time = elapsed_time - current_time;
current_time = elapsed_time;
// Make sure we aren't taking too big of steps when lagging
if (delta_time > 0.02f)
delta_time = 0.02f;
// Add the delta time to the leftover time from the last frame
accumulator_time += delta_time;
// While there is time left
while ((accumulator_time - step_size) >= step_size) {
// Take away the time we will be simulating
accumulator_time -= step_size;
// Update the game for the timestep
Update(step_size);
physics_frame_count++;
}
Render();
}
}
float App::time() {
static std::chrono::time_point<std::chrono::system_clock> start;
static bool started = false;
if (!started) {
start = std::chrono::system_clock::now();
started = true;
}
std::chrono::time_point<std::chrono::system_clock> now = std::chrono::system_clock::now();
std::chrono::duration<double> elapsed_time = now - start;
return static_cast<float>(elapsed_time.count());
}

91
src/Explorer.cpp Normal file
View File

@@ -0,0 +1,91 @@
#include "Explorer.h"
#include <iostream>
#include "Pather.h"
Explorer::Explorer(Map* map_) {
color = sf::Color::Yellow;
position = sf::Vector2i(6, 10);
map = map_;
}
Explorer::~Explorer() {
}
sf::Vector2i Explorer::getPosition() {
return position;
}
sf::Color Explorer::getColor() {
return color;
}
void Explorer::setDestination(sf::Vector2i destination_) {
// Call a* to get path
plan(destination_);
}
bool Explorer::move() {
// While there are moves for us to take
if (!movement_stack.empty()) {
bool valid = false; // If the next move is valid, collision
int x = movement_stack.back();
switch (x) {
case 0: // North
if (!map->getTile(position.x, position.y - 1)->isSolid()) { // If the tile isn't solid
valid = true; // Set the move to valid
position = sf::Vector2i(position.x, position.y - 1); // Update the Explorers position
}
break;
case 1: // East
if (!map->getTile(position.x + 1, position.y)->isSolid()) {
valid = true;
position = sf::Vector2i(position.x + 1, position.y);
}
break;
case 2: // South
if (!map->getTile(position.x, position.y + 1)->isSolid()) {
valid = true;
position = sf::Vector2i(position.x, position.y + 1);
}
break;
case 3: // West
if (!map->getTile(position.x - 1, position.y)->isSolid()) {
valid = true;
position = sf::Vector2i(position.x - 1, position.y);
}
break;
}
// If the path was blocked
if (!valid) {
std::cout << "Path blocked" << std::endl;
// Flush the moves list
while (!movement_stack.empty()) {
movement_stack.pop_back();
}
return false;
}
// If everything went well, pop and return true
movement_stack.pop_back();
return true;
}
else
return false;
}
bool Explorer::plan(sf::Vector2i destination_) {
// Create a new pather with the map data
Pather pather(map);
// Get the movement list from the pather
movement_stack = pather.getPathTo(position, destination_);
return true;
}

79
src/Map.cpp Normal file
View File

@@ -0,0 +1,79 @@
#include "Map.h"
#include <stdlib.h>
Map::Map() {
Init();
}
Map::~Map() {
}
Tile* Map::getTile(sf::Vector2i position_) {
// If the position is within bounds
if (position_.x > CELLS_WIDTH || position_.x < 0
|| position_.y > CELLS_HEIGHT || position_.y < 0) {
return nullptr;
}
else
// Return the value specified
return tileArray[position_.x][position_.y];
}
bool Map::isTileSolid(sf::Vector2i position_) {
// If the position is within bounds
if (position_.x >= CELLS_WIDTH || position_.x < 0
|| position_.y >= CELLS_HEIGHT || position_.y < 0) {
return true; // If it isn't say that the tile is solid
}
else
// Return whether the tile is solid
return tileArray[position_.x][position_.y]->isSolid();
}
Tile* Map::getTile(int x_, int y_) {
// If the position is within bounds
if (x_ > CELLS_WIDTH || x_ < 0
|| y_ > CELLS_HEIGHT || y_ < 0) {
return nullptr;
}
else
// Return the value specified
return tileArray[x_][y_];
}
void Map::overwriteTile(sf::Vector2i position_, Tile* data) {
// If the position is within bounds
if (position_.x >= CELLS_WIDTH || position_.x < 0
|| position_.y >= CELLS_HEIGHT || position_.y < 0) {
return; // If it isn't just return
}
else { // If it is, then delete the old data, replace it with the new
delete tileArray[position_.x][position_.y];
tileArray[position_.x][position_.y] = data;
}
}
void Map::Init() {
// Fill up the map with a random scatter of solid and passable tiles
int q;
for (int x = 0; x < CELLS_WIDTH; x++) {
for (int y = 0; y < CELLS_HEIGHT; y++) {
q = rand() % 100;
if (q > 65) {
tileArray[x][y] = new Tile(true, 100.0, sf::Color::Cyan);
}
else {
tileArray[x][y] = new Tile(false, 0.0, sf::Color::Red);
}
}
}
}

125
src/Pather.cpp Normal file
View File

@@ -0,0 +1,125 @@
#include "Pather.h"
#include <iostream>
Pather::Pather(Map* map_) {
map = map_;
}
Pather::~Pather() {
}
sf::Vector2i Pather::getEndNodePosition() {
return end_node->getPosition();
}
node* Pather::getActiveNode() {
return active_node;
}
std::deque<int> Pather::getPathTo(sf::Vector2i start, sf::Vector2i end) {
// Clear the visited map of erroneous data
for (int i = 0; i < Map::CELLS_WIDTH; i++) {
for (int l = 0; l < Map::CELLS_HEIGHT; l++) {
visited_map(i, l) = 0;
}
}
// Place the start and end nodes
start_node = new node(start, 7000, 0, nullptr, this);
end_node = new node(end, 0, 0, nullptr, this);
// Set the entry point, clean up any stray data from last run
active_node = start_node;
open_list.clear();
closed_list.clear();
// Seed for the loop, hueristic is intentionally high
open_list.emplace(start_node, start_node->getHueristic());
// Set up the early exit, and enter into the loop
early_exit = false;
path_list = loop();
return path_list;
}
std::deque<int> Pather::loop() {
while (!open_list.empty() && !early_exit) {
if (closed_list.size() > 1000) { // Quits when the path gets to be over 1000 long, janky
no_path = true; // Signal no path was found
early_exit = true; // Break
break;
}
// Check to see if we're at our destination, break if we are
if (active_node->getPosition().x == end_node->getPosition().x && active_node->getPosition().y == end_node->getPosition().y) {
early_exit = true;
break;
}
// If we didn't get held up before, do a round of a*
else {
// Find the pair with the lowest hueristic
std::pair<node*, double> bestMin(start_node, 10000); // Get a clean value for the comparison
// Compare all the values in openList for the one with the smallest hueristic
// O(n) complexity so it can get verrrrryyyy slow
for (auto testMin: open_list) {
if (bestMin.second >= testMin.second)
bestMin = testMin;
}
// Set the new active node to the lowest hueristic that we found earlier
active_node = bestMin.first;
// Find the neighbors for that node
active_node->getNewNeighbors();
// Remove the active node from the openlist as you have visited it and called its neighbors
open_list.erase(active_node);
// Check to see if the node has already been added to the closed list, if not, add it
if (closed_list.count(active_node) == 0) {
closed_list.emplace(active_node, active_node->getHueristic());
}
}
}
// When we're done, get the return path
std::deque<int> return_path = returnPath();
if (no_path || return_path.empty()) { // If we had an error, display it
return std::deque<int>();
std::cout << " no return path " << std::endl;
}
return return_path;
}
std::deque<int> Pather::returnPath() {
// Deque that will be returned
std::deque<int> path;
// Backtrack through the active_nodes, adding their cameFrom value to the deque
while (active_node->getParent() != nullptr) {
path.push_back(active_node->getCameFrom());
node* parent = active_node->getParent();
delete active_node;
active_node = parent;
}
return path;
}

37
src/Tile.cpp Normal file
View File

@@ -0,0 +1,37 @@
#include "Tile.h"
Tile::Tile(bool solid_, double movement_penalty_, sf::Color color_) {
solid = solid_;
movement_penalty = movement_penalty_;
color = color_;
}
Tile::Tile() {
solid = false;
movement_penalty = 0.0;
color = sf::Color::Red;
}
Tile::~Tile() {
}
bool Tile::isSolid() {
return solid;
}
double Tile::getPenalty() {
return movement_penalty;
}
sf::Color Tile::getColor() {
return color;
}
void Tile::Rewrite(bool solid_, double movement_penalty_, sf::Color color_) {
solid = solid_;
movement_penalty = movement_penalty_;
color = color_;
}

12
src/main.cpp Normal file
View File

@@ -0,0 +1,12 @@
#include <SFML/Window.hpp>
#include <SFML/Graphics.hpp>
#include "App.h"
int main()
{
App app;
app.Run();
return 0;
}

110
src/node.cpp Normal file
View File

@@ -0,0 +1,110 @@
#include "Pather.h"
node::node(sf::Vector2i XY, double h, int cF, node* p, Pather* pather_) {
position = XY;
hueristic = h;
came_from = cF;
parent = p;
pather = pather_;
}
node::node() {
}
node::~node() {
}
void node::getNewNeighbors() {
// Get the end node position for calculating distance from end(hueristic)
int x = pather->getEndNodePosition().x;
int y = pather->getEndNodePosition().y;
sf::Vector2i dest0XY(position.x, position.y - 1); // North
if (!pather->map->isTileSolid(dest0XY) && pather->visited_map(dest0XY.x, dest0XY.y) != 1) {
// If so, find the distance between this node and the end node, the hueristic
int tempx = (x - dest0XY.x);
int tempy = (y - dest0XY.y);
// I think dv is the hueristic??
double dv = sqrt((tempx * tempx) + (tempy * tempy));
double v = dv;
// Take that value and create a new node
pather->open_list.emplace(new node(dest0XY, v, 0, pather->getActiveNode(), pather), v);
// Set that tile as visited so we don't get stuck in a loop
pather->visited_map(dest0XY.x, dest0XY.y) = 1;
}
sf::Vector2i dest1XY(position.x + 1, position.y); // East
if (!pather->map->isTileSolid(dest1XY) && pather->visited_map(dest1XY.x, dest1XY.y) != 1) {
// If so, find the distance between this node and the end node, the hueristic
int tempx = (x - dest1XY.x);
int tempy = (y - dest1XY.y);
// I think dv is the hueristic??
double dv = sqrt((tempx * tempx) + (tempy * tempy));
double v = dv;
// Take that value and create a new node
pather->open_list.emplace(new node(dest1XY, v, 1, pather->getActiveNode(), pather), v);
// Set that tile as visited so we don't get stuck in a loop
pather->visited_map(dest1XY.x, dest1XY.y) = 1;
}
sf::Vector2i dest2XY(position.x, position.y + 1); // South
if (!pather->map->isTileSolid(dest2XY) && pather->visited_map(dest2XY.x, dest2XY.y) != 1) {
// If so, find the distance between this node and the end node, the hueristic
int tempx = (x - dest2XY.x);
int tempy = (y - dest2XY.y);
// I think dv is the hueristic??
double dv = sqrt((tempx * tempx) + (tempy * tempy));
double v = dv;
// Take that value and create a new node
pather->open_list.emplace(new node(dest2XY, v, 2, pather->getActiveNode(), pather), v);
// Set that tile as visited so we don't get stuck in a loop
pather->visited_map(dest2XY.x, dest2XY.y) = 1;
}
sf::Vector2i dest3XY(position.x - 1, position.y); // West
if (!pather->map->isTileSolid(dest3XY) && pather->visited_map(dest3XY.x, dest3XY.y) != 1) {
// If so, find the distance between this node and the end node, the hueristic
int tempx = (x - dest3XY.x);
int tempy = (y - dest3XY.y);
// I think dv is the hueristic??
double dv = sqrt((tempx * tempx) + (tempy * tempy));
double v = dv;
// Take that value and create a new node
pather->open_list.emplace(new node(dest3XY, v, 3, pather->getActiveNode(), pather), v);
// Set that tile as visited so we don't get stuck in a loop
pather->visited_map(dest3XY.x, dest3XY.y) = 1;
}
}
sf::Vector2i node::getPosition() {
return position;
}
node* node::getParent() {
return parent;
}
double node::getHueristic() {
return hueristic;
}
int node::getCameFrom() {
return came_from;
}