Browse Source

Implement quadtree and dynamic loading; almost fix dab format

master
Josh Gordon 4 years ago
parent
commit
4b0b820c68
  1. 22
      Characters/Gruss.txt
  2. BIN
      app/Cave.png
  3. BIN
      app/action/Cave.dab
  4. BIN
      app/action/Cave.png
  5. 17
      app/action/Character.cpp
  6. 10
      app/action/Character.h
  7. 15
      app/action/Level.h
  8. 4
      app/action/Makefile
  9. 190
      app/action/Map.cpp
  10. 66
      app/action/Map.h
  11. 11
      app/action/Texture.cpp
  12. BIN
      app/action/action
  13. BIN
      app/action/assets/0.png
  14. BIN
      app/action/assets/1.png
  15. BIN
      app/action/assets/2.png
  16. BIN
      app/action/assets/Cave.bmp
  17. BIN
      app/action/assets/Cave.dab
  18. 20
      app/action/main.cpp
  19. 16
      app/action/test.cpp
  20. BIN
      app/action/treetest
  21. BIN
      app/procgen/Cave.bmp
  22. BIN
      app/procgen/Cave.dab
  23. BIN
      app/procgen/Cave.png
  24. 20
      app/procgen/cave.py

22
Characters/Gruss.txt

@ -4,7 +4,7 @@ Gruss Montaigne
Align: Chaotic Good
Race: Halfing
Class: Gloom-Stalker Ranger 10
Class: Gloom-Stalker Ranger 11
Str: 7 (-2)
Dex: 20 (16 base, +2 race, +2 increase) (+5)
@ -13,10 +13,10 @@ Int: 8 (-1)
Wis: 12 (+1)
Cha: 5 (-3)
HP: 46/74
HP: 55/83 (11/11d10 hit die)
AC: 17 (10 base, +5 dex, +2 armor)
Proficiency: +4
Saves: Wis (+5), Dex (+9), Int (+3) +1
Saves: Wis (+6), Dex (+10), Int (+4)
Skills: Perception, Nature, Survival
Languages: Common, Halfling, Draconic
@ -29,32 +29,38 @@ Attacks:
Dragonslayer Shortsword 1d20+6 hit (1d20+1+5), 1d6+6 damage (1d6 + 1 + 5)
Extra Attack 1d20+6 hit, 1d6+6 damage
TWF 1d20+5 hit, 1d6+5 damage
On Miss:
One more attack (Stalker's Flurry)
Ranged:
Longbow 1d20+5 hit, 1d8 damage
Speed: 25
Spells: max [4,3,2]
Known 6: used [3,3,2]
Spells: max [4,3,3]
Known 7: used [2,3,3]
1 Hunter's Mark
2 Spike Growth
2 Rope Trick
2 Healing Spirit
3 Water Walk
3 Fear
3 Protection From Energy
Inventory:
405 gold
Dragonslayer Shortsword
Shortsword
Silvered Scimitar
Studded leather armor
Longbow
Explorer's pack
20 arrows
18 arrows
Potion of Healing x10 (2d4+2 hp)
Alchemist's Fire
Robe of Stars (+1 saving throws, 6/6 5th level magic missiles, regens 1d6 per day)
Robe of Stars (+1 saving throws, 5/6 5th level magic missiles, regens 1d6 per day)
Ornate Bow made of Ivory and Gold
Dragon motif arrows x50
Ring with shield
Info
----

BIN
app/Cave.png

After

Width: 1920  |  Height: 1080  |  Size: 114 KiB

BIN
app/action/Cave.dab

BIN
app/action/Cave.png

Before

Width: 1920  |  Height: 1080  |  Size: 114 KiB

After

Width: 1920  |  Height: 1080  |  Size: 116 KiB

17
app/action/Character.cpp

@ -20,13 +20,14 @@ void Character::handleEvent(SDL_Event& e) {
//update function
void Character::move() {
printf("Moving char at (%d,%d)\n",x_,y_);
x_ += vx_;
if((x_ < 0) || (x_ + sprite_.getWidth() > L_W))
if((x_ < 0) || (x_ + sprite_.getWidth() > L_W*TILE_SIZE))
x_ -= vx_;
y_ += vy_;
if((y_ < 0) || (y_ + sprite_.getHeight() > L_H))
if((y_ < 0) || (y_ + sprite_.getHeight() > L_H*TILE_SIZE))
y_ -= vy_;
//camera time
@ -38,10 +39,10 @@ void Character::move() {
camera_.x = 0;
if(camera_.y < 0)
camera_.y = 0;
if(camera_.x > L_W - camera_.w)
camera_.x = L_W - camera_.w;
if(camera_.y > L_H - camera_.h)
camera_.y = L_H - camera_.h;
if(camera_.x > L_W*TILE_SIZE - camera_.w)
camera_.x = L_W*TILE_SIZE - camera_.w;
if(camera_.y > L_H*TILE_SIZE - camera_.h)
camera_.y = L_H*TILE_SIZE - camera_.h;
//handle fog of war here
}
@ -50,6 +51,6 @@ void Character::render() {
sprite_.render(x_ - camera_.x, y_ - camera_.y);
}
SDL_Rect* Character::getCamera() {
return &camera_;
SDL_Rect Character::getCamera() {
return camera_;
}

10
app/action/Character.h

@ -7,8 +7,10 @@
extern const int S_W; //screen dimensions
extern const int S_H;
extern const int L_W; //level dimensions
extern const int L_H;
extern int L_W; //level dimensions
extern int L_H;
extern const int TILE_SIZE;
class Character {
@ -19,7 +21,7 @@ private:
SDL_Rect camera_;
public:
static const int CHAR_SPEED = 1;
static const int CHAR_SPEED = 10;
Character(std::string filepath, int x, int y): x_(x), y_(y), vx_(0), vy_(0), camera_({0,0,S_W,S_H}) {
sprite_.loadFromFile(filepath);
@ -34,5 +36,5 @@ public:
void render();
SDL_Rect* getCamera();
SDL_Rect getCamera();
};

15
app/action/Level.h

@ -1,15 +0,0 @@
#pragma once
#include "Texture.h"
//very unfinished, do not use
class Level {
private:
Texture texture_;
//list of players?
//list of monsters?
SDL_Rect camera;
public:
};

4
app/action/Makefile

@ -1,7 +1,7 @@
CC = clang++
FLAGS = -lSDL2 -lSDL2_image -lSDL2_gfx
EXEC = action
SRC = main.cpp Texture.cpp Character.cpp Timer.cpp
SRC = main.cpp Texture.cpp Character.cpp Timer.cpp Map.cpp
all: main.cpp Texture.cpp Character.cpp Timer.cpp
all: $(SRC)
$(CC) $(FLAGS) -o $(EXEC) $(SRC)

190
app/action/Map.cpp

@ -0,0 +1,190 @@
#include "Map.h"
Tile tileIndex(int b, int g, int r) {
if(b == 255 && g == 255 && r == 255) {
return GRASS;
}
return WALL;
}
Quad::Quad() {
init(L_W,L_H);
}
void Quad::init(int w,int h) {
int i = 1;
while(i < w || i < h)
i <<= 1;
bound = {0,0,i,i};
data = WALL;
tl = tr = bl = br = NULL;
}
void Quad::boundstring() {
std::cout << "{" << bound.x << "," << bound.y << "," << bound.w << "," << bound.h << "}\n";
}
void Quad::free() {
if(bound.w*bound.h == 1) {
delete this;
return;
}
if(tl)
tl->free();
tl = NULL;
if(tr)
tr->free();
tr = NULL;
if(bl)
bl->free();
bl = NULL;
if(br)
br->free();
br = NULL;
}
inline bool Quad::inbounds(int x, int y) {
return (x - bound.x >= 0) &&
(y - bound.y >= 0) &&
(x-bound.x < bound.w) &&
(y-bound.y < bound.h);
}
void Quad::insert(int x, int y, Tile t) {
//std::cout << "Insert called at " << x << "," << y << " on " << this << "\n";
if(!inbounds(x,y)) {
std::cout << "Not inbounds\n";
return;
}
if(bound.w*bound.h == 1) {
data = t;
//std::cout <<"Data is set to" << t << "\n";
return;
}
if(x-bound.x < bound.w/2) { //left
if(y - bound.y < bound.h/2) { //top
if(!tl) {
tl = new Quad();
tl->bound = {bound.x,bound.y,bound.w/2,bound.h/2};
}
tl->insert(x,y,t);
} else { //bottom
if(!bl) {
bl = new Quad();
bl->bound = {bound.x,bound.y+bound.h/2,bound.w/2,bound.h/2};
}
bl->insert(x,y,t);
}
} else { //right
if(y - bound.y < bound.h/2) { //top
if(!tr) {
tr = new Quad();
tr->bound = {bound.x+bound.w/2,bound.y,bound.w/2,bound.h/2};
}
tr->insert(x,y,t);
} else { //bottom
if(!br) {
br = new Quad();
br->bound = {bound.x+bound.w/2,bound.y+bound.h/2,bound.w/2,bound.h/2};
}
br->insert(x,y,t);
}
}
}
Tile Quad::lookup(int x, int y) {
if(bound.w*bound.h == 1) {
return data;
}
if(x - bound.x < bound.w/2) {
if(y - bound.y < bound.h/2) {
if(tl)
return tl->lookup(x,y);
return WALL;
}
if(tr)
return tr->lookup(x,y);
return WALL;
} else {
if(y - bound.y < bound.h/2) {
if(bl)
return bl->lookup(x,y);
return WALL;
}
if(br)
return br->lookup(x,y);
return WALL;
}
}
void Quad::print(int spaces) {
for(int i = 0; i < spaces; ++i) {
std::cout << " ";
}
if(data == WALL)
std::cout << "WALL\n";
if(data == STONE)
std::cout << "STONE\n";
if(data == GRASS)
std::cout << "GRASS\n";
if(tl)
tl->print(spaces+2);
if(tr)
tr->print(spaces+2);
if(bl)
bl->print(spaces+2);
if(br)
br->print(spaces+2);
}
Map::Map() {
tiles = new Quad();
numTilesX = numTilesY = -1;
for(int i = 0; i < NUM_TILE_IDs; ++i) {
std::string filename = "assets/" + std::to_string(i) + ".png";
std::cout << "Loading texture " << filename << "\n";
textures[i].loadFromFile(filename);
}
}
Map::~Map() {
tiles->free();
delete tiles; //This destructor may seem excessive, but all three of these lines have a separate purpose.
tiles = NULL; //c'est la C++
}
void Map::loadFromFile(std::string fpath) {
FILE* f = fopen(fpath.c_str(),"rb");
int w,h;
fread(&w,sizeof(int),1,f);
fread(&h,sizeof(int),1,f);
std::cout << "Width: " << w << " Height: " << h << "\n";
tiles->init(w,h);
std::cout << "Tiles init'd\n";
int t;
for(int i = 0; i < w*h; ++i) {
fread(&t,sizeof(int),1,f);
tiles->insert(i/w,i%w,static_cast<Tile>(t));
//std::cout << "Loading " << t << "\n";
}
fclose(f);
numTilesX = w;
numTilesY = h;
}
void Map::render(SDL_Rect camera) {
std::cout << "Rendering map\n";
for(int x = camera.x/TILE_SIZE; x < 1+(camera.x + camera.w)/TILE_SIZE; ++x){
for(int y = camera.y/TILE_SIZE; y < 1+(camera.y + camera.h)/TILE_SIZE; ++y) {
Tile t = tiles->lookup(x,y);
//std::cout << "Tile at " << x << "," << y << " is " << t << "\n";
textures[t].render(x*TILE_SIZE - camera.x,y*TILE_SIZE - camera.y);
}
}
}
void Map::print() {
tiles->print(0);
}

66
app/action/Map.h

@ -0,0 +1,66 @@
#pragma once
#include <string>
#include <iostream>
#include <SDL2/SDL.h>
#include "Texture.h"
extern const int S_W; //screen dimensions
extern const int S_H;
extern int L_W; //level dimensions
extern int L_H;
extern const int TILE_SIZE;
static const int NUM_TILE_IDs = 3;
enum Tile {
WALL,
STONE,
GRASS
};
class Quad {
private:
SDL_Rect bound;
Tile data;
inline bool inbounds(int,int);
void boundstring();
Quad *tl,*tr,*bl,*br;
public:
Quad();
void init(int,int);
//~Quad(){free();}
void free();
void insert(int,int,Tile);
Tile lookup(int,int); //defaults to wall
void print(int);
};
class Map {
private:
int numTilesX,numTilesY;
Quad* tiles;
Texture textures[NUM_TILE_IDs];
public:
Map();
~Map();
void loadFromFile(std::string fpath);
void render(SDL_Rect camera);
//DEBUG
void print();
int getW(){ return numTilesX; }
int getH(){ return numTilesY; }
};

11
app/action/Texture.cpp

@ -1,5 +1,8 @@
#include "Texture.h"
#include <sys/stat.h>
Texture::Texture() {
texture_ = NULL;
w_ = -1;
@ -11,6 +14,14 @@ Texture::~Texture() {
}
bool Texture::loadFromFile(std::string path) {
struct stat buf;
#ifdef EXISTS_CHECK
if(stat(path.c_str(),&buf) != 0) {
return false;
}
#endif
free();
SDL_Texture* newTexture = NULL;

BIN
app/action/action

BIN
app/action/assets/0.png

After

Width: 64  |  Height: 64  |  Size: 220 B

BIN
app/action/assets/1.png

After

Width: 64  |  Height: 64  |  Size: 1.9 KiB

BIN
app/action/assets/2.png

After

Width: 64  |  Height: 64  |  Size: 5.1 KiB

BIN
app/action/assets/Cave.bmp

BIN
app/action/assets/Cave.dab

20
app/action/main.cpp

@ -7,17 +7,20 @@
#include "Timer.h"
#include "Texture.h"
#include "Character.h"
#include "Map.h"
//screen width, height
const int S_W = 640;
const int S_H = 480;
const int L_W = 1920;
const int L_H = 1080;
int L_W = -1;
int L_H = -1;
const int MAX_FPS = 60;
const int TICKS_PER_FRAME = 1000 / MAX_FPS;
const int TILE_SIZE = 64;
void init();
void close();
@ -33,8 +36,15 @@ int main(int argc, char** argv) {
init();
Texture map;
map.loadFromFile("Cave.png");
Map map;
map.loadFromFile("assets/Cave.dab");
L_W = map.getW();
L_H = map.getH();
//map.print();
//exit(1);
printf("Width: %d, Height: %d\n",L_W,L_H);
Character ch("sp.png",0,0);
@ -64,7 +74,7 @@ int main(int argc, char** argv) {
SDL_RenderClear(renderer);
map.render(0,0,ch.getCamera());
map.render(ch.getCamera());
ch.render();
SDL_RenderPresent(renderer);

16
app/action/test.cpp

@ -0,0 +1,16 @@
#include "Map.h"
const int S_W = 640;
const int S_H = 480;
const int L_W = 1920;
const int L_H = 1080;
int main() {
Map m;
m.loadFromFile("assets/Cave.bmp");
m.print();
return 0;
}

BIN
app/action/treetest

BIN
app/procgen/Cave.bmp

BIN
app/procgen/Cave.dab

BIN
app/procgen/Cave.png

Before

Width: 1920  |  Height: 1080  |  Size: 114 KiB

20
app/procgen/cave.py

@ -2,6 +2,9 @@ import numpy as np
import cv2
from random import randint, choice, shuffle
import sys
import struct
CAVE_W = 1080//4
CAVE_H = 1920//4
@ -56,8 +59,25 @@ def genCave():
dilation = cv2.dilate(upscale,kernel,iterations=2)
return dilation
def writeDab(fname,im):
with open(fname,'wb+') as f:
w,h,c = im.shape
f.write(struct.pack('i',w))
f.write(struct.pack('i',h))
for i in range(w):
for j in range(h):
if(i % 10 == 0):
print("Writing data...")
if(np.sum(im[i,j,:]) == 0):
d = 0
elif(np.sum(im[i,j,:]) == 255*3):
d = 1
db = struct.pack('i',d)
f.write(db)
def driver():
c = genCave()
writeDab("Cave.dab",c)
cv2.imwrite("Cave.png",c)
driver()
Loading…
Cancel
Save