Added sdl version to exmplify extension of the main engine

This commit is contained in:
Tiehuis 2015-02-21 17:31:54 +13:00
parent 8cff1bb002
commit 3dd23136d5
6 changed files with 200 additions and 14 deletions

View File

@ -1,7 +1,7 @@
CC := clang CC := clang
CFLAGS += -O2 -Wall -Wextra CFLAGS += -g -Wall -Wextra
LFLAGS += LFLAGS +=
DEFINES := -DVT100 DEFINES := -DVT100 -D_REENTRANT -I/usr/include/SDL2
PROGRAM := 2048 PROGRAM := 2048
C_FILES := $(wildcard src/*.c) C_FILES := $(wildcard src/*.c)
@ -15,6 +15,9 @@ curses: $(O_FILES)
vt100: $(O_FILES) vt100: $(O_FILES)
$(CC) $(filter-out obj/gfx%.o, $(O_FILES)) obj/gfx_terminal.o -o $(PROGRAM) $(CC) $(filter-out obj/gfx%.o, $(O_FILES)) obj/gfx_terminal.o -o $(PROGRAM)
sdl: $(O_FILES)
$(CC) $(filter-out obj/gfx%.o, $(O_FILES)) obj/gfx_sdl.o -o $(PROGRAM) -lSDL2 -lSDL2_ttf
obj/%.o: src/%.c obj/%.o: src/%.c
$(CC) $(DEFINES) $(CFLAGS) -c -o $@ $< $(CC) $(DEFINES) $(CFLAGS) -c -o $@ $<

View File

@ -1,24 +1,25 @@
#2048-cli #2048-cli
A cli version of the game [2048](https://github.com/gabrielecirulli/2048) for your Linux A cli version/engine of the game [2048](https://github.com/gabrielecirulli/2048) for your Linux
terminal. terminal.
#####2048_curses.c
![Screenshot](http://i.imgur.com/QU7t5mH.png) ![Screenshot](http://i.imgur.com/QU7t5mH.png)
#####2048_no_curses.c There currently are 3 versions that can be run. These include a straight-forward terminal
![Screenshot](http://i.imgur.com/fwZEvdh.png) based, and two using the ncurses and SDL libraries. To add a new graphical version, simply
create a .c file which implements all the functions in gfx.h and add a Makefile entry.
## Installation
This requires the ncurses library to link against during compilation. It is available
in most package managers. The program creates and uses a file name `.hs2048g` in the
working directory. Any file with this name will be modified and replaced.
### Get ### Get
git clone https://github.com/Tiehuis/2048-cli.git git clone https://github.com/Tiehuis/2048-cli.git
make
make vt100
or
make curses
or
make sdl
### Run ### Run
./2048 ./2048
## Options ## Options
-s <size> Set the grid border length -s <size> Set the grid border length
@ -27,5 +28,7 @@ working directory. Any file with this name will be modified and replaced.
-c Enables color support (ncurses version only) -c Enables color support (ncurses version only)
-C Disables color support (ncurses version only) -C Disables color support (ncurses version only)
Fonts used in SDL version can be found [here](openfontlibrary.org).
## License ## License
This code is licensed under the [MIT License](https://github.com/Tiehuis/2048-cli/blob/master/LICENSE). This code is licensed under the [MIT License](https://github.com/Tiehuis/2048-cli/blob/master/LICENSE).

BIN
res/Anonymous Pro.ttf Normal file

Binary file not shown.

BIN
res/NotCourierSans.ttf Normal file

Binary file not shown.

View File

@ -270,7 +270,6 @@ int gamestate_tick(struct gfx_state *s, struct gamestate *g, int d, void (*callb
{ {
/* Reset move. Altered by gravitate and merge if we do move */ /* Reset move. Altered by gravitate and merge if we do move */
g->moved = 0; g->moved = 0;
printf("%d\n", d);
gravitate(s, g, d, callback); gravitate(s, g, d, callback);
merge(s, g, d, callback); merge(s, g, d, callback);
gravitate(s, g, d, callback); gravitate(s, g, d, callback);

181
src/gfx_sdl.c Normal file
View File

@ -0,0 +1,181 @@
#include <stdlib.h>
#include <SDL.h>
#include <SDL_ttf.h>
#include "gfx.h"
/* Side length of a 'pixel' in pixels */
#define TTF_FONT_PATH "res/Anonymous Pro.ttf"
#define TTF_FONT_PT 32
#define iterate(n, expression)\
do {\
int i;\
for (i = 0; i < n; ++i) { expression; }\
} while (0)
struct gfx_state {
SDL_Window *window;
SDL_Surface *surface;
TTF_Font *font;
int side_length;
int window_height;
int window_width;
};
struct gfx_state* gfx_init(struct gamestate *g)
{
struct gfx_state *s = malloc(sizeof(struct gfx_state));
SDL_Init(SDL_INIT_VIDEO);
TTF_Init();
s->font = TTF_OpenFont(TTF_FONT_PATH, TTF_FONT_PT);
s->side_length = TTF_FontLineSkip(s->font);
s->window_height = g->opts->grid_height * (g->print_width + 2) + 3;
s->window_width = g->opts->grid_width * (g->print_width + 2) + 1;
s->window = SDL_CreateWindow(
"2048",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
/* Spacing is inconsistent right now. Need to find width and
* height spacing to accurately resize window */
s->window_width * TTF_FONT_PT * 0.7,
s->window_height * s->side_length * 0.35,
SDL_WINDOW_OPENGL | SDL_WINDOW_ALLOW_HIGHDPI
);
s->surface = SDL_GetWindowSurface(s->window);
return s;
}
#define rect_set(r, xv, yv, wv, hv)\
do {\
r.x = xv; r.y = yv; r.w = wv; r.h = hv;\
} while (0)
void gfx_draw(struct gfx_state *s, struct gamestate *g)
{
/* This shouldn't ever overflow. Max width effectively is determined by the size
* of two integers' text representation */
const int buffer_length = 64;
char string_buffer[buffer_length];
/* Set up text object so we can write to sdl window */
SDL_Surface *text;
SDL_Color text_color = {255, 255, 255, 0};
SDL_Rect rect;
/* Clear screen */
SDL_FillRect(s->surface, NULL, SDL_MapRGB(s->surface->format, 0, 0, 0));
if (g->score_last)
snprintf(string_buffer, buffer_length, "Score: %ld (+%ld)", g->score, g->score_last);
else
snprintf(string_buffer, buffer_length, "Score: %ld", g->score);
rect_set(rect, 0, 0, 0, 0);
text = TTF_RenderText_Solid(s->font, string_buffer, text_color);
SDL_BlitSurface(text, NULL, s->surface, &rect);
snprintf(string_buffer, buffer_length, " Hi: %ld", g->score_high);
rect_set(rect, 0, s->side_length * 1, 0, 0);
text = TTF_RenderText_Solid(s->font, string_buffer, text_color);
SDL_BlitSurface(text, NULL, s->surface, &rect);
int i;
for (i = 0; i < g->opts->grid_width * (g->print_width + 2) + 1; ++i)
string_buffer[i] = '-';
string_buffer[i] = '\0';
rect_set(rect, 0, s->side_length * 2, 0, 0);
text = TTF_RenderText_Solid(s->font, string_buffer, text_color);
SDL_BlitSurface(text, NULL, s->surface, &rect);
int x, y;
char line_buffer[buffer_length];
for (y = 0; y < g->opts->grid_height; ++y) {
int line_index = 0;
line_buffer[line_index++] = '|';
for (x = 0; x < g->opts->grid_width; ++x) {
if (g->grid[x][y]) {
snprintf(string_buffer, buffer_length, "%*ld |", g->print_width, g->grid[x][y]);
strncpy(line_buffer + line_index, string_buffer, buffer_length - line_index);
line_index += strlen(string_buffer);
}
else {
snprintf(string_buffer, buffer_length, "%*s |", g->print_width, "");
strncpy(line_buffer + line_index, string_buffer, buffer_length - line_index);
line_index += strlen(string_buffer);
}
}
line_buffer[line_index] = 0;
rect_set(rect, 0, s->side_length * (y + 3), 0, 0);
text = TTF_RenderText_Solid(s->font, line_buffer, text_color);
SDL_BlitSurface(text, NULL, s->surface, &rect);
}
for (i = 0; i < g->opts->grid_height * (g->print_width + 2) + 1; ++i)
string_buffer[i] = '-';
string_buffer[i] = '\0';
rect_set(rect, 0, s->side_length * (y + 3), 0, 0);
text = TTF_RenderText_Solid(s->font, string_buffer, text_color);
SDL_BlitSurface(text, NULL, s->surface, &rect);
SDL_UpdateWindowSurface(s->window);
}
/* This getch we parse here, and we just return when we get an appropriate
* event */
int gfx_getch(struct gfx_state *s)
{
(void)s; /* Supress unused warning */
SDL_Event event;
while (1) {
while (SDL_WaitEvent(&event)) {
switch (event.type) {
case SDL_QUIT:
return 'q';
case SDL_KEYDOWN:
switch (event.key.keysym.sym) {
case SDLK_q:
return 'q';
case SDLK_UP:
case SDLK_w:
return 'w';
case SDLK_DOWN:
case SDLK_s:
return 's';
case SDLK_LEFT:
case SDLK_a:
return 'a';
case SDLK_RIGHT:
case SDLK_d:
return 'd';
default:
break;
}
break;
default:
break;
}
}
}
}
void gfx_sleep(int ms)
{
SDL_Delay(ms);
}
void gfx_destroy(struct gfx_state *s)
{
SDL_DestroyWindow(s->window);
TTF_Quit();
SDL_Quit();
}