You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
326 lines
8.3 KiB
326 lines
8.3 KiB
#include <iostream> |
|
#include <fstream> |
|
#include <vector> |
|
#include <SDL.h> |
|
#include <SDL_image.h> |
|
|
|
// 16*16 tiles |
|
#define RENDER_WIDTH 256 |
|
// 16*11 tiles |
|
#define RENDER_HEIGHT 176 |
|
|
|
#define WINDOW_WIDTH RENDER_WIDTH*4 |
|
#define WINDOW_HEIGHT RENDER_HEIGHT*4 |
|
#define WINDOW_TITLE "game" |
|
#define GFX_PATH "gfx/" |
|
#define LEVELS_FOLDER "lvls/" |
|
#define MAX_MAP_TILES_X 16 /*11*/ |
|
#define MAX_MAP_TILES_Y 11 /*16*/ |
|
#define TILE_WIDTH 16 |
|
#define TILE_HEIGHT 16 |
|
#define PLAYER_SPEED 1.0f |
|
|
|
#define UNUSED(x) (void)(x) |
|
|
|
//#define for_map for (int col = 0; col < MAX_MAP_TILES_Y; ++col) for (int row = 0; row < MAX_MAP_TILES_X; ++row) |
|
#define debug_print_rect(r) printf("x: %d, y: %d, w: %d, h: %d\n", r.x, r.y, r.w, r.h); |
|
|
|
#define USE_VSYNC 0 |
|
#define USE_LOGICAL_RENDER_VIEW 1 |
|
#define FPS 60 |
|
//#define USE_STATIC_ARRAY_LVL |
|
|
|
using namespace std; |
|
|
|
// Types |
|
struct Rect { |
|
SDL_Rect rect; |
|
|
|
Rect() { rect = {}; } |
|
|
|
Rect(int x, int y, int w, int h) { |
|
rect.x = x; rect.y = y; |
|
rect.w = w; rect.h = h; |
|
} |
|
|
|
Rect(Rect& r) { |
|
rect.x = r.rect.x; |
|
rect.y = r.rect.y; |
|
rect.w = r.rect.w; |
|
rect.h = r.rect.h; |
|
} |
|
|
|
bool operator ==(Rect& r) { |
|
auto s = r.rect; |
|
return (s.x == rect.x && |
|
s.y == rect.y && |
|
s.w == rect.w && |
|
s.h == rect.h); |
|
} |
|
|
|
bool operator !=(Rect& r) { |
|
auto s = r.rect; |
|
return (s.x != rect.x || |
|
s.y != rect.y || |
|
s.w != rect.w || |
|
s.h != rect.h); |
|
} |
|
|
|
void operator =(Rect& r) { |
|
rect.x = r.rect.x; |
|
rect.y = r.rect.y; |
|
rect.w = r.rect.w; |
|
rect.h = r.rect.h; |
|
} |
|
|
|
SDL_Rect* operator ()(){ |
|
return ▭ |
|
} |
|
|
|
void print() { |
|
auto r = rect; |
|
printf("x: %d, y: %d, w: %d, h: %d\n", r.x, r.y, r.w, r.h); |
|
} |
|
}; |
|
|
|
//typedef int Room[MAX_MAP_TILES_X][MAX_MAP_TILES_Y]; |
|
typedef int Room[MAX_MAP_TILES_Y][MAX_MAP_TILES_X]; |
|
struct R { |
|
Room room; |
|
int operator ()(int x, int y) { |
|
return room[x][y]; |
|
} |
|
}; |
|
|
|
/*struct Keys { |
|
static bool down_pressed; |
|
static bool up_pressed; |
|
static bool left_pressed; |
|
static bool right_pressed; |
|
}; |
|
bool Keys::down_pressed = false; |
|
bool Keys::up_pressed = false; |
|
bool Keys::left_pressed = false; |
|
bool Keys::right_pressed = false; |
|
*/ |
|
|
|
// Global variables |
|
vector<R> rooms; |
|
SDL_Window* window; |
|
SDL_Renderer* renderer; |
|
SDL_Texture* tiles; |
|
bool quit; |
|
|
|
struct Player { |
|
Rect src_rect; |
|
Rect body_hitbox; // player is a 16*16 tile + 8 pixels in height for the head, we ignore those |
|
int x, y; |
|
|
|
float speed; |
|
int x_vel, y_vel; |
|
|
|
Player() : src_rect(0, 39, TILE_WIDTH, TILE_HEIGHT + 10/*head size*/), body_hitbox(0, 48, TILE_WIDTH, TILE_HEIGHT), x(0), y(0), speed(PLAYER_SPEED) |
|
,x_vel(0), y_vel(0) {} |
|
|
|
void draw() { |
|
Rect dst(x, y, src_rect()->w, src_rect()->h); |
|
SDL_RenderCopy(renderer, tiles, src_rect(), dst()); |
|
} |
|
void update() { |
|
// TODO: time wtf, tick |
|
/*if (Keys::down_pressed) y += speed; |
|
if (Keys::up_pressed) y -= speed; |
|
if (Keys::left_pressed) x -= speed; |
|
if (Keys::right_pressed) x += speed;*/ |
|
x += x_vel; |
|
y += y_vel; |
|
} |
|
} player; |
|
|
|
// A room is a screen in the sense of a static screen, aka the player doesnt move a camera, |
|
// he just moves in the current room |
|
/* |
|
#ifndef USE_STATIC_ARRAY_LVL |
|
int room[MAX_MAP_TILES_X][MAX_MAP_TILES_Y]; |
|
#else |
|
int room[MAX_MAP_TILES_Y][MAX_MAP_TILES_X] = { |
|
{001, 001, 001, 001, 001, 001, 001, 001, 001, 001, 001, 001, 001, 001, 001, 001}, |
|
{001, 000, 000, 000, 000, 000, 000, 000, 000, 000, 000, 000, 000, 000, 000, 001}, |
|
{001, 000, 000, 000, 000, 000, 000, 000, 000, 000, 000, 000, 000, 000, 000, 001}, |
|
{001, 000, 000, 000, 000, 000, 001, 000, 001, 000, 000, 000, 000, 000, 000, 001}, |
|
{001, 000, 000, 000, 000, 000, 001, 000, 001, 000, 000, 000, 000, 000, 000, 001}, |
|
{001, 000, 000, 000, 000, 000, 001, 001, 001, 000, 000, 000, 000, 000, 000, 001}, |
|
{001, 000, 000, 000, 000, 000, 000, 000, 000, 000, 000, 000, 000, 000, 000, 001}, |
|
{001, 000, 000, 000, 000, 000, 000, 000, 000, 000, 000, 000, 000, 000, 000, 001}, |
|
{001, 000, 000, 000, 000, 000, 000, 000, 000, 000, 000, 000, 000, 000, 000, 001}, |
|
{001, 000, 000, 000, 000, 000, 000, 000, 000, 000, 000, 000, 000, 000, 000, 001}, |
|
{001, 001, 001, 001, 001, 001, 001, 001, 001, 001, 001, 001, 001, 001, 001, 001} |
|
}; |
|
#endif |
|
*/ |
|
Rect test_tile(0, 0, 16, 16); |
|
Rect dest_test_tile(0, 0, 16, 16); |
|
Rect stone_tile(0, 17, 16, 16); |
|
|
|
// Prototypes |
|
void die(const string& why); |
|
void endgame(); |
|
bool loadgraphics(); |
|
bool load_room(const string& name); |
|
void drawtile(Rect src, int x, int y); |
|
void draw_room(int* room_num); |
|
|
|
extern "C" int main(int argc, char** argv) { |
|
UNUSED(argc); |
|
UNUSED(argv); |
|
|
|
SDL_Init(SDL_INIT_VIDEO); |
|
IMG_Init(IMG_INIT_PNG); |
|
|
|
window = SDL_CreateWindow(WINDOW_TITLE, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, WINDOW_WIDTH, WINDOW_HEIGHT, 0); |
|
if (!window) die("failed to create window"); |
|
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED |
|
#if USE_VSYNC |
|
| SDL_RENDERER_PRESENTVSYNC); |
|
#else |
|
); |
|
#endif |
|
if (!renderer) die("failed to create renderer"); |
|
|
|
#if USE_LOGICAL_RENDER_VIEW |
|
SDL_RenderSetLogicalSize(renderer, RENDER_WIDTH, RENDER_HEIGHT); |
|
#endif |
|
|
|
if (!loadgraphics()) die("failed to load tiles.png"); |
|
|
|
#ifndef USE_STATIC_ARRAY_LVL |
|
if (!load_room("00")) die("Failed to load level 00"); |
|
if (!load_room("01")) die("Failed to load level 01"); |
|
#endif |
|
|
|
SDL_SetRenderDrawColor(renderer, 0, 255, 150, 255); |
|
|
|
int next_room(0); |
|
quit = false; |
|
//float now(0), secs(0), last_time(0); |
|
while (!quit) { |
|
SDL_Event e; |
|
|
|
while (SDL_PollEvent(&e)) { |
|
if (e.type == SDL_QUIT) quit = true; |
|
|
|
if (e.type == SDL_KEYDOWN) { |
|
switch (e.key.keysym.sym) { |
|
case SDLK_ESCAPE: quit = true; break; |
|
// Debug |
|
case SDLK_0: next_room = 0; break; |
|
case SDLK_1: next_room = 1; break; |
|
case SDLK_2: next_room = 2; break; |
|
// fin debug |
|
|
|
case SDLK_DOWN: player.y_vel = PLAYER_SPEED; break; |
|
case SDLK_UP: player.y_vel = -PLAYER_SPEED; break; |
|
case SDLK_RIGHT: player.x_vel = PLAYER_SPEED; break; |
|
case SDLK_LEFT: player.x_vel = -PLAYER_SPEED; break; |
|
} |
|
} else if (e.type == SDL_KEYUP) { |
|
switch (e.key.keysym.sym) { |
|
case SDLK_DOWN: if (player.y_vel > 0) player.y_vel = 0; break; |
|
case SDLK_UP: if (player.y_vel < 0) player.y_vel = 0; break; |
|
case SDLK_RIGHT: if (player.x_vel > 0) player.x_vel = 0; break; |
|
case SDLK_LEFT: if (player.x_vel < 0) player.x_vel = 0; break; |
|
} |
|
} |
|
} |
|
|
|
player.update(); //TODO: time and shit |
|
|
|
SDL_RenderClear(renderer); |
|
|
|
// Current room rendering |
|
draw_room(&next_room); |
|
player.draw(); |
|
|
|
/* |
|
float freq = SDL_GetPerformanceFrequency(); |
|
|
|
now = SDL_GetPerformanceCounter(); |
|
secs = (now - last_time) / freq; |
|
SDL_Delay(FPS - secs * 1000); |
|
*/ |
|
|
|
SDL_Delay(16); |
|
|
|
SDL_RenderPresent(renderer); |
|
} |
|
|
|
/*whats your*/endgame(); |
|
return 0; |
|
} |
|
|
|
void draw_room(int* room_num) { |
|
try { |
|
(void)rooms.at((unsigned)*room_num); |
|
} catch (const out_of_range& ex) { |
|
cerr << "out_of_range exception caught in draw_room routine: map nb " << *room_num << " doesnt exist or hasnt been loaded. Reseting to map nb 00." << endl; |
|
*room_num = 0; // reset room number |
|
return; |
|
} |
|
|
|
for (int y = 0; y < MAX_MAP_TILES_Y; ++y) { |
|
for (int x = 0; x < MAX_MAP_TILES_X; ++x) { |
|
int tile = rooms[(unsigned)*room_num](y, x); |
|
|
|
Rect defr(17, 0, 16, 16); |
|
Rect r = defr; |
|
|
|
switch (tile) { |
|
case 000: r = test_tile; break; |
|
case 002: r = stone_tile; break; |
|
default: r = defr; break; |
|
} |
|
drawtile(r, x * TILE_WIDTH, y * TILE_HEIGHT); |
|
} |
|
} |
|
} |
|
|
|
void die(const string& why) { |
|
cerr << why << endl; |
|
exit(-1); |
|
} |
|
|
|
void endgame() { |
|
if (tiles) free(tiles); |
|
if (renderer) SDL_DestroyRenderer(renderer); |
|
if (window) SDL_DestroyWindow(window); |
|
IMG_Quit(); |
|
SDL_Quit(); |
|
} |
|
|
|
bool loadgraphics() { |
|
tiles = IMG_LoadTexture(renderer, GFX_PATH "tiles.png"); |
|
if (!tiles) cerr << SDL_GetError() << endl; |
|
return (tiles) ? true : false; |
|
} |
|
|
|
bool load_room(const string& name) { |
|
// TODO: charger les maps dans une hashtable <UniqueConstID, map> ? le vector peut sort() etc, pas safe? |
|
cout << "loading level " << name << endl; |
|
ifstream file(LEVELS_FOLDER + name + ".lvl"); |
|
if (!file.is_open()) return false; |
|
|
|
R room; |
|
for (int y = 0; y < MAX_MAP_TILES_Y; ++y) { |
|
for (int x = 0; x < MAX_MAP_TILES_X; ++x) { |
|
//file >> room[y][x]; |
|
file >> room.room[y][x]; |
|
} |
|
} |
|
rooms.push_back(room); |
|
return true; |
|
} |
|
|
|
void drawtile(Rect src, int x, int y) { |
|
Rect r(x, y, TILE_WIDTH, TILE_HEIGHT); |
|
SDL_RenderCopy(renderer, tiles, &src.rect, &r.rect); |
|
} |