Commit 61439a47 authored by Robert Scott James's avatar Robert Scott James

Merge branch 'vision' into 'master'

Vision

Completed vision tracing and display. Doesn't take into account entities yet but this isn't too much of an issue at the moment.

See merge request !1
parents a39baff7 c15c8b86
......@@ -15,6 +15,7 @@ add_executable(IdleCrawler
src/dungeon/rectangle.cpp
src/dungeon/space.cpp
src/entity/entity.cpp
src/entity/vision/vision.cpp
src/entity/vision/alive/alive.cpp
src/entity/vision/alive/mob/basicSolver.cpp
src/entity/vision/alive/mob/randomMove.cpp
......
......@@ -143,4 +143,4 @@ void Space::draw(Display*& dpy,Window& w,GC& gc,int scale){
XFillRectangle (dpy, w, gc, x*scale, y*scale, scale, scale);
}
}
}
\ No newline at end of file
}
......@@ -8,10 +8,11 @@ enum TILE_TYPES {
FLOOR,
DOOR,
STAIRS_UP,
STAIRS_DOWN
STAIRS_DOWN,
UNSEEN
};
const char TILES_TYPES_MAP[]= {' ','#','.','+','^','v'};
const int TILE_COLOUR_MAP[] = {0x607D8B,0x212121,0xFAFAFA,0x795548,0x4CAF50,0xFF9800};
const char TILES_TYPES_MAP[]= {' ','#','.','+','^','v','+'};
const int TILE_COLOUR_MAP[] = {0x607D8B,0x212121,0xFAFAFA,0x795548,0x4CAF50,0xFF9800,0x607D8B};
enum LOCATION {
TOP_LEFT, TOP_CENTER, TOP_RIGHT,
......@@ -19,4 +20,4 @@ enum LOCATION {
BOTTOM_LEFT, BOTTOM_CENTER, BOTTOM_RIGHT
};
#endif
\ No newline at end of file
#endif
#include <stack>
#include <queue>
#include <iostream>
#include <tuple>
#include "entity.h"
#include "../dungeon/space.h"
BasicSolver::BasicSolver(Dungeon &_dungeon,int _x,int _y) : Mob(_dungeon,_x,_y){
std::stack<std::tuple<int,int>> trail;
findSolution();
}
void BasicSolver::findSolution(){
std::queue<std::tuple<int,int>> toDo;
int tiles[dungeon.getWidth()*dungeon.getHeight()] = {0};
int height = dungeon.getHeight();
toDo.push(std::make_tuple(x,y));
tiles[x*height+y] = 1;
while (!toDo.empty()){
std::tuple<int,int> pos = toDo.front();
toDo.pop();
int doX = std::get<0>(pos);
int doY = std::get<1>(pos);
int doN = tiles[doX*height+doY]+1;
if(dungeon.getTile(doX,doY) == STAIRS_DOWN){
trail.push(std::make_tuple(doX,doY));
break;
}
if(tiles[(doX-1)*height+doY] == 0 && dungeon.getTile(doX-1,doY) != WALL){
tiles[(doX-1)*height+doY] = doN;
toDo.push(std::make_tuple(doX-1,doY));
}
if(tiles[(doX+1)*height+doY] == 0 && dungeon.getTile(doX+1,doY) != WALL){
tiles[(doX+1)*height+doY] = doN;
toDo.push(std::make_tuple(doX+1,doY));
}
if(tiles[doX*height+doY-1] == 0 && dungeon.getTile(doX,doY-1) != WALL){
tiles[doX*height+doY-1] = doN;
toDo.push(std::make_tuple(doX,doY-1));
}
if(tiles[doX*height+doY+1] == 0 && dungeon.getTile(doX,doY+1) != WALL){
tiles[doX*height+doY+1] = doN;
toDo.push(std::make_tuple(doX,doY+1));
}
}
if (trail.empty()){
std::cerr << "Could not solve" << std::endl;
return;
}
while (1){
std::tuple<int,int> pos = trail.top();
int doX = std::get<0>(pos);
int doY = std::get<1>(pos);
int doN = tiles[doX*height+doY]-1;
if (doN == 0) {break;}
if(tiles[(doX-1)*height+doY] == doN){
trail.push(std::make_tuple(doX-1,doY));
}
else if(tiles[(doX+1)*height+doY] == doN){
trail.push(std::make_tuple(doX+1,doY));
}
else if(tiles[doX*height+doY-1] == doN){
trail.push(std::make_tuple(doX,doY-1));
}
else if(tiles[doX*height+doY+1] == doN){
trail.push(std::make_tuple(doX,doY+1));
} else {
std::cerr << "ERR" << std::endl;
break;
}
}
}
void BasicSolver::turn(){
if (trail.empty()){
return;
//dungeon.populate();
std::tuple<int,int> start = dungeon.upStairPosition();
moveTo(std::get<0>(start),std::get<1>(start));
findSolution();
}
std::tuple<int,int> pos = trail.top();
int toX = std::get<0>(pos);
int toY = std::get<1>(pos);
trail.pop();
moveTo(toX,toY);
}
......@@ -4,7 +4,7 @@
#include <tuple>
#include "hero.h"
BasicSolverHero::BasicSolverHero(Dungeon &_dungeon,int _x,int _y) : Hero(_dungeon,_x,_y){
BasicSolverHero::BasicSolverHero(Dungeon &_dungeon,int _x,int _y,int _viewDistance) : Hero(_dungeon,_x,_y,_viewDistance){
std::stack<std::tuple<int,int>> trail;
findSolution();
}
......@@ -82,6 +82,7 @@ void BasicSolverHero::findSolution(){
}
void BasicSolverHero::turn(){
updateFOW();
if (trail.empty()){
return;
//dungeon.populate();
......
......@@ -16,3 +16,7 @@ bool Hero::levelComplete(){
return(false);
}
}
void Hero::turn(){ //Helpful for debugging
updateFOW();
}
......@@ -8,6 +8,7 @@ class Hero: public Alive {
using Alive::Alive;
//Hero(Dungeon &, int, int);
bool levelComplete();
void turn();
protected:
};
......@@ -15,7 +16,7 @@ class Hero: public Alive {
// Hero Basic Solver
class BasicSolverHero: public Hero {
public:
BasicSolverHero(Dungeon &,int,int);
BasicSolverHero(Dungeon &,int,int,int);
void turn();
void findSolution();
protected:
......
......@@ -4,7 +4,7 @@
#include <tuple>
#include "mob.h"
BasicSolver::BasicSolver(Dungeon &_dungeon,int _x,int _y) : Mob(_dungeon,_x,_y){
BasicSolver::BasicSolver(Dungeon &_dungeon,int _x,int _y,int _viewDistance) : Mob(_dungeon,_x,_y,_viewDistance){
std::stack<std::tuple<int,int>> trail;
findSolution();
}
......
......@@ -13,7 +13,7 @@ protected:
class RandomMove: public Mob {
public:
RandomMove(Dungeon &,int,int,int);
RandomMove(Dungeon &,int,int,int,int);
void turn();
protected:
std::default_random_engine generator;
......@@ -21,7 +21,7 @@ class RandomMove: public Mob {
class BasicSolver: public Mob {
public:
BasicSolver(Dungeon &,int,int);
BasicSolver(Dungeon &,int,int,int);
void turn();
protected:
void findSolution();
......
......@@ -6,7 +6,7 @@
//Random move example
RandomMove::RandomMove(Dungeon &_dungeon,int _x,int _y,int seed) : Mob(_dungeon,_x,_y){
RandomMove::RandomMove(Dungeon &_dungeon,int _x,int _y,int _viewDistance,int seed) : Mob(_dungeon,_x,_y,_viewDistance){
generator = std::default_random_engine(seed);
}
......
#include "vision.h"
#include "../entity.h"
#include <queue>
#include <iostream>
int sgn(int val){
return (0<val) - (val<0);
}
Vision::Vision(Dungeon &_dungeon,int _x,int _y,int _viewDistance) : Entity(_dungeon,_x,_y){
viewDistance = _viewDistance;
fov = new TILE_TYPES[dungeon.getWidth()*dungeon.getHeight()];
for(int i=0;i<dungeon.getWidth()*dungeon.getHeight();i++){
fov[i] = UNSEEN;
}
canSee = new char[(viewDistance*2+1)*(viewDistance*2+1)];
}
char Vision::canSeeTile(int xFr,int yFr,int xTo,int yTo){
float deltaX = xTo-xFr;
float deltaY = yTo-yFr;
char majorX;
int majorC;
int major1;
int major2;
float m;
int minor;
int minorC;
//std::cerr << "Checking line:" << xFr << "," << yFr << " -> " << xTo << "," << yTo << std::endl;
if(deltaX == 0 && deltaY == 0){
return 1;
} else if (xFr < 0 || xFr >= dungeon.getWidth() || yFr < 0 || yFr >= dungeon.getHeight()){
return 0;
} else if (abs(deltaX) > abs(deltaY)){
//std::cerr << "\tLine is major X" << std::endl;
majorX = 1;
majorC = sgn(deltaX);
major1 = xFr;
major2 = xTo;
m = fabs(deltaY/deltaX);
minor = yFr;
minorC = sgn(deltaY);
} else {
//std::cerr << "\tLine is major Y" << std::endl;
majorX = 0;
majorC = sgn(deltaY);
major1 = yFr;
major2 = yTo;
m = fabs(deltaX/deltaY);
minor = xFr;
minorC = sgn(deltaX);
}
//std::cerr << "\t\t(m:" << m << ")" << std::endl;
float err = 0;
major1+=majorC;
for(int major=major1;major!=major2;major+=majorC){
err+=m;
//std::cerr << " (err:" << err << ")" << std::endl;
if (err >= 0.5){
minor += minorC;
err--;
}
if (majorX){
//std::cerr << "\t\tLooking up" << major << "," << minor;
if (dungeon.getTile(major,minor) == WALL){
//std::cerr << " Wall found." << std::endl;
return 0;
}
} else {
//std::cerr << "\t\tLooking up" << minor << "," << major;
if (dungeon.getTile(minor,major) == WALL){
//std::cerr << " Wall found." << std::endl;
return 0;
}
}
}
return 1;
}
/*/Returns 1 if can 0 if can't
char Vision::canSeeTile(int xFr,int yFr,int xTo,int yTo){
if (xFr == xTo && yFr == yTo){
return 1;
} else if (xTo < 0 || xTo >= dungeon.getWidth() || yTo < 0 || yTo >= dungeon.getHeight() ){
return 0;
} else if (abs(xFr-xTo) > abs(yFr-yTo)){
return _cstX(xFr,yFr,xTo,yTo);
} else {
return _cstY(yFr,yFr,xTo,yTo);
}
}
*/
void Vision::updateFOW(){
const int VIEW_DIAM = viewDistance*2+1;
//Ray trace to each square
for(int sx=0;sx<VIEW_DIAM;sx++){
for(int sy=0;sy<VIEW_DIAM;sy++){
canSee[sy*VIEW_DIAM+sx] = canSeeTile(x+sx-viewDistance,y+sy-viewDistance,x,y);
}
}
//std::cerr << "view bounds" << (x-viewDistance) << "," << (y-viewDistance) << " to " << (x+viewDistance) << "," << (y+viewDistance) << std::endl;
/*/Flood fill to remove issues
std::queue<std::tuple<int,int>> toDo;
toDo.push(std::make_tuple(viewDistance,viewDistance));
while(!toDo.empty()){
std::tuple<int,int> pos = toDo.front();
toDo.pop();
int doX = std::get<0>(pos);
int doY = std::get<1>(pos);
if (vMap[doX*(viewDistance*2+1)+doY] != 1){
continue;
}
vMap[doX*viewDistance+doY] = 2;
if(doX>0){
toDo.push(std::make_tuple(doX-1,doY));
}
if(doY>0){
toDo.push(std::make_tuple(doX,doY-1));
}
if(doX<viewDistance*2+1){
toDo.push(std::make_tuple(doX+1,doY));
}
if(doY<viewDistance*2+1){
toDo.push(std::make_tuple(doX,doY+1));
}
}//*/
//Update
for(int sx=0;sx<VIEW_DIAM;sx++){
for(int sy=0;sy<VIEW_DIAM;sy++){
if (canSee[sy*VIEW_DIAM+sx] == 1){ //Change back to 2 when uncommenting the above!!!
int mapX = (x+sx-viewDistance);
int mapY = (y+sy-viewDistance);
fov[ mapY*dungeon.getWidth() + mapX ] = dungeon.getTile(mapX,mapY);
}
}
}
}
void Vision::drawLevel(Display*& dpy,Window& w,GC& gc,int scale){
Colormap colormap;
colormap = DefaultColormap(dpy, 0);
const int VIEW_DIAM = viewDistance*2+1;
for(int dx=0;dx<dungeon.getWidth();dx++){
for(int dy=0;dy<dungeon.getHeight();dy++){
int colour = TILE_COLOUR_MAP[fov[ dy*dungeon.getWidth() + dx ]];
int lx = dx-x+viewDistance;
int ly = dy-y+viewDistance;
if (lx<0 || ly<0 || lx>=VIEW_DIAM || ly>=VIEW_DIAM || canSee[ly*VIEW_DIAM+lx] == 0){
colour &= 0x555555;
}
XSetForeground(dpy, gc, colour);
XFillRectangle (dpy, w, gc, dx*scale, dy*scale, scale, scale);
}
}
}
......@@ -5,10 +5,14 @@
class Vision: public Entity { // This class is supposed to give the hero, mob, anything else that needs vision it's field of view. Therefore everything that needs to see or react to the environment needs to inherit from it.
public:
using Entity::Entity;
//Vision(Dungeon &, int, int);
Vision(Dungeon&, int, int, int);
char canSeeTile(int, int, int, int);
void updateFOW();
void drawLevel(Display*&,Window&,GC&,int);
protected:
TILE_TYPES *fov;
int viewDistance;
char *canSee;
void fogofwar();
};
......
......@@ -54,7 +54,8 @@ void Game::loop(){
// Create hero at coordinates of the dungeon start
std::tuple<int,int> heroStart = levels.back().upStairPosition();
BasicSolverHero levelHero = BasicSolverHero(levels.back(),std::get<0>(heroStart), std::get<1>(heroStart));
BasicSolverHero levelHero = BasicSolverHero(levels.back(),std::get<0>(heroStart), std::get<1>(heroStart),256 /*vision*/);
//Hero levelHero = Hero(levels.back(),std::get<0>(heroStart), std::get<1>(heroStart),20 /*vision*/);
theHero = &levelHero;
// Generate nMobs
......@@ -71,7 +72,7 @@ void Game::loop(){
mobx = x_dist(generator);
moby = y_dist(generator);
}
std::shared_ptr<RandomMove> r(new RandomMove( levels.back(), mobx, moby, milliseconds_since_epoch+n));
std::shared_ptr<RandomMove> r(new RandomMove( levels.back(), mobx, moby, 0 /*vision*/, milliseconds_since_epoch+n));
entities.emplace_back( r );
}
......@@ -82,32 +83,29 @@ void Game::loop(){
while(theHero->getCurrentHealth() > 0){
usleep(10000);
// Draw the Dungeon
levels.back().draw(dpy,double_buffer,gc,scale);
// Take hero turn.
theHero->turn();
// Now all the other Entities take turns but none extra for now
for(int _nMob = 0; _nMob < entities.size(); _nMob++){
usleep(10000);
// Take hero turn.
theHero->turn();
// Now all the other Entities take turns but none extra for now
for(int _nMob = 0; _nMob < entities.size(); _nMob++){
entities[_nMob]->turn();
}
}
// Draw the Dungeon
theHero->drawLevel(dpy,double_buffer,gc,scale);
// Now draw the hero
theHero->draw(dpy,double_buffer,gc,scale);
// Now draw the hero
theHero->draw(dpy,double_buffer,gc,scale);
for(int _nMob = 0; _nMob < entities.size(); _nMob++){
for(int _nMob = 0; _nMob < entities.size(); _nMob++){
entities[_nMob]->draw(dpy,double_buffer,gc,scale);
}
}
XCopyArea(dpy, double_buffer, w, gc, 0, 0, wa.width, wa.height, 0, 0);
XFlush(dpy);
if(theHero->levelComplete() == true){
XCopyArea(dpy, double_buffer, w, gc, 0, 0, wa.width, wa.height, 0, 0);
XFlush(dpy);
if(theHero->levelComplete() == true){
break;
}
}
}
if(theHero->getCurrentHealth() == 0){
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment