Skip to content

Instantly share code, notes, and snippets.

@erikyuzwa
Created July 18, 2025 19:37
Show Gist options
  • Save erikyuzwa/ba8c6abd5c92d6c5ba5df4ef71219f18 to your computer and use it in GitHub Desktop.
Save erikyuzwa/ba8c6abd5c92d6c5ba5df4ef71219f18 to your computer and use it in GitHub Desktop.
hello world using libtcod 2.1.1 and C
#define SDL_MAIN_USE_CALLBACKS
#include <SDL3/SDL.h>
#include <SDL3/SDL_main.h>
#include "libtcod.h" // Include the main libtcod header
#include <stdio.h>
#include <stdlib.h>
// Define console dimensions
#define SCREEN_WIDTH 80
#define SCREEN_HEIGHT 50
const TCOD_ColorRGB BLACK = { 0, 0, 0 };
const TCOD_ColorRGB WHITE = { 255, 255, 255 };
const TCOD_ColorRGB YELLOW = { 255, 255, 0 };
typedef struct {
int x, y;
} Player;
typedef struct {
TCOD_Context* context;
TCOD_Tileset* tileset;
TCOD_Console* main_console;
TCOD_ContextParams params;
Player player;
bool is_running;
} AppState;
// Print libtcod log messages using SDL_Log
void print_log(const TCOD_LogMessage* message, void* userdata) {
SDL_Log("%s:%d:%d:%s\n", message->source, message->lineno, message->level, message->message);
}
SDL_AppResult SDL_AppInit(void** appstate, int argc, char** argv) {
SDL_Log("App Init");
SDL_SetLogPriorities(SDL_LOG_PRIORITY_VERBOSE);
TCOD_set_log_callback(print_log, NULL);
TCOD_set_log_level(TCOD_LOG_DEBUG);
AppState* state = (AppState*)SDL_calloc(1, sizeof(AppState));
if (!state) return SDL_APP_FAILURE;
const char* FONT = "assets/dejavu12x12_gs_tc.png";
state->tileset = TCOD_tileset_load(FONT, 32, 8, 256, TCOD_CHARMAP_TCOD);
// The main console to be presented.
state->main_console = TCOD_console_new(SCREEN_WIDTH, SCREEN_HEIGHT);
state->params = (TCOD_ContextParams) {
.console = state->main_console,
.window_title = "libtcod C sample",
.sdl_window_flags = SDL_WINDOW_RESIZABLE,
.renderer_type = TCOD_RENDERER_SDL2, //aka. SDL3
.tileset = state->tileset,
.vsync = false,
.argc = argc,
.argv = (const char* const*)argv,
};
TCOD_context_new(&state->params, &state->context);
state->player = (Player){ SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2 };
state->is_running = true;
*appstate = state;
return SDL_APP_CONTINUE;
}
SDL_AppResult SDL_AppIterate(void* appstate) {
AppState* state = (AppState*)appstate;
// clear the console
TCOD_console_clear(state->main_console);
// render our player
TCOD_console_put_rgb(state->main_console, state->player.x, state->player.y, '@', &YELLOW, &BLACK, 0);
// update the game screen
TCOD_context_present(state->context, state->main_console, NULL);
// return SDL_APP_SUCCESS to quit
return state->is_running ? SDL_APP_CONTINUE : SDL_APP_SUCCESS;
}
SDL_AppResult SDL_AppEvent(void* appstate, SDL_Event* event) {
AppState* state = (AppState*)appstate;
TCOD_context_convert_event_coordinates(state->context, event);
switch (event->type) {
case SDL_EVENT_WINDOW_CLOSE_REQUESTED:
SDL_Log("Window close requested");
state->is_running = false;
break;
case SDL_EVENT_KEY_DOWN:
switch (event->key.key) {
case SDLK_ESCAPE:
state->is_running = false;
break;
case SDLK_UP:
state->player.y -= 1;
break;
case SDLK_DOWN:
state->player.y += 1;
break;
case SDLK_LEFT:
state->player.x -= 1;
break;
case SDLK_RIGHT:
state->player.x += 1;
break;
}
break;
case SDL_EVENT_QUIT:
state->is_running = false;
break;
}
return SDL_APP_CONTINUE;
}
void SDL_AppQuit(void* appstate, SDL_AppResult result) {
SDL_Log("App Quit");
if (appstate != NULL) {
AppState* state = (AppState*)appstate;
// TODO: free up anything else
SDL_free(state);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment