2 Commits

24 changed files with 874 additions and 407 deletions

View File

@@ -20,8 +20,19 @@ set(libdir "\${exec_prefix}/lib")
set(includedir "\${prefix}/include") set(includedir "\${prefix}/include")
# Add include directories # Add include directories
include_directories(${SDL3_INCLUDE_DIRS}) include_directories(${SDL3_INCLUDE_DIRS} include/)
add_executable(akgltest src/akgltest.c) add_executable(akgltest
src/actors.c
src/audio.c
src/events.c
src/controllers.c
src/gamemodes.c
src/init.c
src/SDL_AppInit.c
src/SDL_AppQuit.c
src/SDL_AppIterate.c
src/main.c
)
target_link_libraries(akgltest target_link_libraries(akgltest
PRIVATE PRIVATE

View File

@@ -1,4 +1,4 @@
Character definitions should allow for specifying multiple states per sprite mapping, rather than only one state per map. Use an array instead. When the game is running at high frame rate, character animation looks jittery, despite animations being timelocked.
Rendering should move to the SDL GPU renderer so i can do lighting and particles etc Rendering should move to the SDL GPU renderer so i can do lighting and particles etc
- Example suitable for my most primitive use case: https://github.com/TheSpydog/SDL_gpu_examples/blob/main/Examples/Blit2DArray.c - Example suitable for my most primitive use case: https://github.com/TheSpydog/SDL_gpu_examples/blob/main/Examples/Blit2DArray.c

View File

@@ -0,0 +1,68 @@
{
"name": "menupointer",
"movementspeed": 8,
"velocity_x": 0,
"velocity_y": 0,
"sprite_mappings": [
{
"state": [
"AKGL_ACTOR_STATE_ALIVE",
"AKGL_ACTOR_STATE_FACE_UP",
"AKGL_ACTOR_STATE_MOVING_UP"
],
"sprite": "menupointer"
},
{
"state": [
"AKGL_ACTOR_STATE_ALIVE",
"AKGL_ACTOR_STATE_FACE_DOWN",
"AKGL_ACTOR_STATE_MOVING_DOWN"
],
"sprite": "menupointer"
},
{
"state": [
"AKGL_ACTOR_STATE_ALIVE",
"AKGL_ACTOR_STATE_FACE_UP"
],
"sprite": "menupointer"
},
{
"state": [
"AKGL_ACTOR_STATE_ALIVE",
"AKGL_ACTOR_STATE_FACE_DOWN"
],
"sprite": "menupointer"
},
{
"state": [
"AKGL_ACTOR_STATE_ALIVE",
"AKGL_ACTOR_STATE_FACE_LEFT",
"AKGL_ACTOR_STATE_MOVING_LEFT"
],
"sprite": "menupointer"
},
{
"state": [
"AKGL_ACTOR_STATE_ALIVE",
"AKGL_ACTOR_STATE_FACE_RIGHT",
"AKGL_ACTOR_STATE_MOVING_RIGHT"
],
"sprite": "menupointer"
},
{
"state": [
"AKGL_ACTOR_STATE_ALIVE",
"AKGL_ACTOR_STATE_FACE_LEFT"
],
"sprite": "menupointer"
},
{
"state": [
"AKGL_ACTOR_STATE_ALIVE",
"AKGL_ACTOR_STATE_FACE_RIGHT"
],
"sprite": "menupointer"
}
]
}

BIN
assets/ffbg2.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 207 KiB

View File

@@ -4,7 +4,7 @@
"layers":[ "layers":[
{ {
"id":4, "id":4,
"image":"../assets/ffbg2-scaled.png", "image":"ffbg2-scaled.png",
"locked":true, "locked":true,
"name":"Image Layer 1", "name":"Image Layer 1",
"offsetx":5.6843418860808e-14, "offsetx":5.6843418860808e-14,
@@ -30,7 +30,7 @@
"name":"character", "name":"character",
"type":"string", "type":"string",
"value":"little guy" "value":"little guy"
}, },
{ {
"name":"state", "name":"state",
"type":"int", "type":"int",
@@ -57,7 +57,7 @@
{ {
"name":"state", "name":"state",
"type":"int", "type":"int",
"value":272 "value":276
}], }],
"rotation":0, "rotation":0,
"type":"actor", "type":"actor",
@@ -70,14 +70,14 @@
"height":32, "height":32,
"id":16, "id":16,
"name":"p_foreground", "name":"p_foreground",
"properties":[
{
"name":"scale",
"type":"float",
"value":1.5
}],
"rotation":0, "rotation":0,
"type":"perspective", "type":"perspective",
"properties": [
{
"name": "scale",
"type": "number",
"value": 1.5
}],
"visible":true, "visible":true,
"width":790, "width":790,
"x":0, "x":0,
@@ -87,14 +87,14 @@
"height":12, "height":12,
"id":17, "id":17,
"name":"p_vanishing", "name":"p_vanishing",
"properties":[
{
"name":"scale",
"type":"float",
"value":0.75
}],
"rotation":0, "rotation":0,
"type":"perspective", "type":"perspective",
"properties": [
{
"name": "scale",
"type": "number",
"value": 0.75
}],
"visible":true, "visible":true,
"width":53, "width":53,
"x":270.5, "x":270.5,
@@ -118,7 +118,7 @@
{ {
"columns":48, "columns":48,
"firstgid":1, "firstgid":1,
"image":"../assets/World_A1.png", "image":"World_A1.png",
"imageheight":576, "imageheight":576,
"imagewidth":768, "imagewidth":768,
"margin":0, "margin":0,
@@ -132,4 +132,4 @@
"type":"map", "type":"map",
"version":"1.8", "version":"1.8",
"width":64 "width":64
} }

BIN
assets/menupointer.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

100
assets/sidescroller.tmj Normal file
View File

@@ -0,0 +1,100 @@
{ "compressionlevel":-1,
"height":15,
"infinite":false,
"layers":[
{
"data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 1, 2, 2, 2, 2, 3, 0, 0, 0, 0, 0, 0, 1, 9, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 9],
"height":15,
"id":1,
"name":"Tile Layer 1",
"opacity":1,
"type":"tilelayer",
"visible":true,
"width":20,
"x":0,
"y":0
},
{
"draworder":"topdown",
"id":3,
"name":"Object Layer 1",
"objects":[
{
"gid":211,
"height":16,
"id":1,
"name":"player",
"properties":[
{
"name":"character",
"type":"string",
"value":"little guy"
},
{
"name":"state",
"type":"int",
"value":24
}],
"rotation":0,
"type":"actor",
"visible":true,
"width":16,
"x":304.261511065887,
"y":258.471635716103
}],
"opacity":1,
"type":"objectgroup",
"visible":true,
"x":0,
"y":0
},
{
"data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
"height":15,
"id":2,
"name":"Tile Layer 2",
"opacity":1,
"type":"tilelayer",
"visible":true,
"width":20,
"x":0,
"y":0
}],
"nextlayerid":4,
"nextobjectid":2,
"orientation":"orthogonal",
"renderorder":"right-down",
"tiledversion":"1.8.2",
"tileheight":32,
"tilesets":[
{
"columns":8,
"firstgid":1,
"image":"sidescrollertiles.png",
"imageheight":256,
"imagewidth":256,
"margin":0,
"name":"sidescroller",
"spacing":0,
"tilecount":64,
"tileheight":32,
"tilewidth":32
},
{
"columns":48,
"firstgid":65,
"image":"World_A1.png",
"imageheight":576,
"imagewidth":768,
"margin":0,
"name":"World_A1",
"spacing":0,
"tilecount":1728,
"tileheight":16,
"tilewidth":16
}],
"tilewidth":32,
"type":"map",
"version":"1.8",
"width":20
}

View File

@@ -0,0 +1,16 @@
{
"spritesheet": {
"filename": "../menupointer.png",
"frame_width": 50,
"frame_height": 49
},
"name": "menupointer",
"width": 50,
"height": 49,
"speed": 0,
"loop": false,
"loopReverse": false,
"frames": [
0
]
}

View File

@@ -58,7 +58,7 @@
{ {
"name":"state", "name":"state",
"type":"int", "type":"int",
"value":272 "value":276
}], }],
"rotation":0, "rotation":0,
"type":"actor", "type":"actor",

2
deps/libakgl vendored

64
include/akgltest.h Normal file
View File

@@ -0,0 +1,64 @@
#include <SDL3/SDL.h>
#include <SDL3/SDL_main.h>
#include <SDL3/SDL_properties.h>
#include <SDL3_image/SDL_image.h>
#include <SDL3_mixer/SDL_mixer.h>
#include <akgl/assets.h>
#include <akgl/error.h>
#include <akgl/iterator.h>
#include <akgl/tilemap.h>
#include <akgl/heap.h>
#include <akgl/game.h>
#include <akgl/controller.h>
#include <akgl/draw.h>
#include <akgl/sprite.h>
#include <akgl/actor.h>
#include <akgl/registry.h>
#include <akgl/text.h>
#include <akstdlib.h>
#define AKGLTEST_STATE_WAITFORINPUT 1 << 8
#define AKGLTEST_STATE_LOADING 1 << 9
#define AKGLTEST_STATE_RUNNING 1 << 10
#define AKGLTEST_STATE_MAPMENU 1 << 11
#define AKGLTEST_STATE_QUIT 1 << 12
#define AKGLTEST_CONTROLMAP_MENU 0
#define AKGLTEST_CONTROLMAP_INGAMEACTOR 1
extern int menuselection;
extern int maxmenu;
extern int kbid;
extern int jsid;
extern int numchars;
extern char *characterpaths[2];
extern int numsounds;
extern char *soundfiles[2];
extern int numsprites;
extern char *spritepaths[9];
extern char dirnamebuf[1024];
akerr_ErrorContext AKERR_NOIGNORE *akgltest_controller_bind_universal(char *actorname, int mapid, int kbid, int jsid);
akerr_ErrorContext AKERR_NOIGNORE *akgltest_controller_get_defaults(void *appstate, SDL_Event *event);
akerr_ErrorContext AKERR_NOIGNORE *akgltest_init_menupointer(void);
akerr_ErrorContext AKERR_NOIGNORE *akgltest_init_player(void);
akerr_ErrorContext AKERR_NOIGNORE *akgltest_iterate_mapmenu(void);
akerr_ErrorContext AKERR_NOIGNORE *akgltest_iterate_running(void);
akerr_ErrorContext AKERR_NOIGNORE *akgltest_iterate_waitforinput(void);
akerr_ErrorContext AKERR_NOIGNORE *akgltest_load_assets();
akerr_ErrorContext AKERR_NOIGNORE *akgltest_menupointer_logic_movement(akgl_Actor *obj, SDL_Time curtime);
akerr_ErrorContext AKERR_NOIGNORE *akgltest_release_actor(char *actorname);
akerr_ErrorContext AKERR_NOIGNORE *akgltest_set_actor_visible(char *actorname, bool visible);
akerr_ErrorContext AKERR_NOIGNORE *akgltest_set_gamemode_menu(akgl_Actor *appstate, SDL_Event *event);
akerr_ErrorContext AKERR_NOIGNORE *akgltest_set_gamemode_running(akgl_Actor *appstate, SDL_Event *event);
akerr_ErrorContext AKERR_NOIGNORE *music_toggle(akgl_Actor *obj, SDL_Event *event);
akerr_ErrorContext AKERR_NOIGNORE *quit_game(akgl_Actor *obj, SDL_Event *event);
akerr_ErrorContext AKERR_NOIGNORE *savegame(akgl_Actor *obj, SDL_Event *event);
akerr_ErrorContext AKERR_NOIGNORE *user_breakpoint(akgl_Actor *obj, SDL_Event *event);

8
include/demo.h Normal file
View File

@@ -0,0 +1,8 @@
#define AKGLTEST_STATE_WAITFORINPUT 1 << 8
#define AKGLTEST_STATE_LOADING 1 << 9
#define AKGLTEST_STATE_RUNNING 1 << 10
#define AKGLTEST_STATE_MAPMENU 1 << 11
#define AKGLTEST_STATE_QUIT 1 << 12
#define AKGLTEST_CONTROLMAP_MENU 0
#define AKGLTEST_CONTROLMAP_INGAMEACTOR 1

60
src/SDL_AppInit.c Normal file
View File

@@ -0,0 +1,60 @@
#include <akgltest.h>
SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
{
akgl_Actor *actorptr = NULL;
*appstate = (void *)&game.state;
PREPARE_ERROR(e);
AKGL_BITMASK_ADD(game.state.flags, AKGLTEST_STATE_LOADING);
ATTEMPT {
FAIL_ZERO_BREAK(e, appstate, AKERR_NULLPOINTER, "NULL appstate pointer");
strcpy((char *)&game.name, "sdl3-gametest");
strcpy((char *)&game.version, "0.0.1");
strcpy((char *)&game.uri, "net.aklabs.games.sdl3-gametest");
//CATCH(e, akgl_game_load("assets/savegame.bin"));
CATCH(e, akgl_game_init());
CATCH(e, akgl_game_state_lock());
CATCH(e, akgl_registry_load_properties("assets/properties.json"));
CATCH(e, akgl_render_init2d(&renderer));
CATCH(e, akgl_physics_init_sidescroller(&physics));
CATCH(e, akgl_controller_list_keyboards());
CATCH(e, akgltest_load_assets());
CATCH(e, akgl_heap_next_actor(&actorptr));
CATCH(e, akgl_actor_initialize((akgl_Actor *)actorptr, "player"));
actorptr->basechar = SDL_GetPointerProperty(
AKGL_REGISTRY_CHARACTER,
"little guy",
NULL);
FAIL_ZERO_BREAK(e, actorptr->basechar, AKERR_REGISTRY, "Can't load character 'little guy' from the registry");
actorptr->movement_controls_face = false;
actorptr->state = (AKGL_ACTOR_STATE_ALIVE | AKGL_ACTOR_STATE_FACE_LEFT);
actorptr->x = 320;
actorptr->y = 240;
actorptr->visible = false;
strcpy((char *)&dirnamebuf, "assets/memories.mp3");
CATCH(e, akgl_load_start_bgm((char *)&dirnamebuf));
CATCH(e, music_toggle(NULL, NULL));
CATCH(e, akgl_text_loadfont("C64Pro", "assets/C64_Pro-STYLE.ttf", 18));
} CLEANUP {
IGNORE(akgl_game_state_unlock());
} PROCESS(e) {
} HANDLE_DEFAULT(e) {
LOG_ERROR(e);
return SDL_APP_FAILURE;
} FINISH_NORETURN(e);
AKGL_BITMASK_DEL(game.state.flags, AKGLTEST_STATE_LOADING);
AKGL_BITMASK_ADD(game.state.flags, AKGLTEST_STATE_WAITFORINPUT);
return SDL_APP_CONTINUE;
}

29
src/SDL_AppIterate.c Normal file
View File

@@ -0,0 +1,29 @@
#include <akgltest.h>
SDL_AppResult SDL_AppIterate(void *appstate)
{
//SDL_FRect dest;
//b2Vec2 position;
PREPARE_ERROR(e);
ATTEMPT {
CATCH(e, akgl_game_state_lock());
if ( AKGL_BITMASK_HAS(game.state.flags, AKGLTEST_STATE_QUIT) ) {
return SDL_APP_FAILURE;
} else if ( AKGL_BITMASK_HAS(game.state.flags, AKGLTEST_STATE_RUNNING) ) {
CATCH(e, akgltest_iterate_running());
} else if ( AKGL_BITMASK_HAS(game.state.flags, AKGLTEST_STATE_WAITFORINPUT) ) {
CATCH(e, akgltest_iterate_waitforinput());
} else if ( AKGL_BITMASK_HAS(game.state.flags, AKGLTEST_STATE_MAPMENU) ) {
CATCH(e, akgltest_iterate_mapmenu());
}
} CLEANUP {
IGNORE(akgl_game_state_unlock());
} PROCESS(e) {
} HANDLE_DEFAULT(e) {
LOG_ERROR(e);
return SDL_APP_FAILURE;
} FINISH_NORETURN(e);
return SDL_APP_CONTINUE;
}

14
src/SDL_AppQuit.c Normal file
View File

@@ -0,0 +1,14 @@
#include <akgltest.h>
void SDL_AppQuit(void *appstate, SDL_AppResult result)
{
/* SDL will clean up the window/renderer for us. */
// SDL_DestroyTexture(ball.texture);
//b2DestroyWorld(physicsWorldId);
SDL_Log("Freeing music resources");
if ( bgm != NULL ) {
//Mix_FreeMusic(bgm);
}
SDL_Log("Quitting mixer");
// Mix_Quit();
}

86
src/actors.c Normal file
View File

@@ -0,0 +1,86 @@
#include <akgltest.h>
akerr_ErrorContext AKERR_NOIGNORE *akgltest_menupointer_logic_movement(akgl_Actor *obj, SDL_Time curtime)
{
PREPARE_ERROR(e);
FAIL_ZERO_RETURN(e, obj, AKERR_NULLPOINTER, "NULL actor");
if ( AKGL_BITMASK_HAS(obj->state, AKGL_ACTOR_STATE_MOVING_DOWN) ) {
if ( menuselection < maxmenu ) {
menuselection += 1;
} else {
menuselection = 0;
}
} else if ( AKGL_BITMASK_HAS(obj->state, AKGL_ACTOR_STATE_MOVING_UP) ) {
if ( menuselection == 0 ) {
menuselection = maxmenu;
} else {
menuselection -= 1;
}
}
obj->y = 85 + (menuselection * 100);
AKGL_BITMASK_DEL(obj->state, (AKGL_ACTOR_STATE_MOVING_UP | AKGL_ACTOR_STATE_MOVING_DOWN));
SUCCEED_RETURN(e);
}
akerr_ErrorContext AKERR_NOIGNORE *akgltest_init_menupointer(void)
{
PREPARE_ERROR(e);
akgl_Actor *actorptr = NULL;
PASS(e, akgl_heap_next_actor(&actorptr));
PASS(e, akgl_actor_initialize((akgl_Actor *)actorptr, "menupointer"));
actorptr->basechar = SDL_GetPointerProperty(
AKGL_REGISTRY_CHARACTER,
"menupointer",
NULL);
FAIL_ZERO_RETURN(e, actorptr->basechar, AKERR_REGISTRY, "menupointer character missing");
actorptr->movementlogicfunc = &akgltest_menupointer_logic_movement;
actorptr->movement_controls_face = false;
actorptr->state = (AKGL_ACTOR_STATE_ALIVE | AKGL_ACTOR_STATE_FACE_DOWN);
actorptr->x = 50;
actorptr->y = 100;
actorptr->layer = 1;
actorptr->visible = false;
SUCCEED_RETURN(e);
}
akerr_ErrorContext AKERR_NOIGNORE *akgltest_init_player(void)
{
PREPARE_ERROR(e);
akgl_Actor *actor = NULL;
akgl_Actor *actorptr = NULL;
PASS(e, akgl_heap_next_actor(&actorptr));
PASS(e, akgl_actor_initialize((akgl_Actor *)actorptr, "player"));
actorptr->basechar = SDL_GetPointerProperty(
AKGL_REGISTRY_CHARACTER,
"little guy",
NULL);
FAIL_ZERO_RETURN(e, actorptr->basechar, AKERR_REGISTRY, "little guy character missing");
actorptr->movement_controls_face = false;
actorptr->state = (AKGL_ACTOR_STATE_ALIVE | AKGL_ACTOR_STATE_FACE_LEFT);
actorptr->x = 320;
actorptr->y = 240;
actorptr->layer = 1;
actorptr->visible = false;
SUCCEED_RETURN(e);
}
akerr_ErrorContext AKERR_NOIGNORE *akgltest_release_actor(char *actorname)
{
PREPARE_ERROR(e);
akgl_Actor *actor = SDL_GetPointerProperty(AKGL_REGISTRY_ACTOR, actorname, NULL);
FAIL_ZERO_RETURN(e, actor, AKERR_REGISTRY, "%s", actorname);
PASS(e, akgl_heap_release_actor(actor));
SUCCEED_RETURN(e);
}
akerr_ErrorContext AKERR_NOIGNORE *akgltest_set_actor_visible(char *actorname, bool visible)
{
PREPARE_ERROR(e);
akgl_Actor *actorptr = NULL;
actorptr = SDL_GetPointerProperty(AKGL_REGISTRY_ACTOR, actorname, NULL);
FAIL_ZERO_RETURN(e, actorptr, AKERR_NULLPOINTER, "%s missing in registry", actorname);
actorptr->visible = visible;
SUCCEED_RETURN(e);
}

View File

@@ -18,6 +18,8 @@
#include <akgl/registry.h> #include <akgl/registry.h>
#include <akgl/text.h> #include <akgl/text.h>
#include <akstdlib.h>
#define AKGLTEST_STATE_WAITFORINPUT 1 << 8 #define AKGLTEST_STATE_WAITFORINPUT 1 << 8
#define AKGLTEST_STATE_LOADING 1 << 9 #define AKGLTEST_STATE_LOADING 1 << 9
#define AKGLTEST_STATE_RUNNING 1 << 10 #define AKGLTEST_STATE_RUNNING 1 << 10
@@ -28,7 +30,9 @@
#define AKGLTEST_CONTROLMAP_INGAMEACTOR 1 #define AKGLTEST_CONTROLMAP_INGAMEACTOR 1
int menuselection = 0; int menuselection = 0;
int maxmenu = 2; int maxmenu = 3;
int kbid = 0;
int jsid = 0;
int numchars = 2; int numchars = 2;
char *characterpaths[] = { char *characterpaths[] = {
@@ -57,143 +61,20 @@ char *spritepaths[] = {
char dirnamebuf[1024]; char dirnamebuf[1024];
akerr_ErrorContext AKERR_NOIGNORE *akgltest_set_gamemode_menu(akgl_Actor *appstate, SDL_Event *event)
{
akgl_Actor *menupointer = SDL_GetPointerProperty(AKGL_REGISTRY_ACTOR, "menupointer", NULL);
akgl_Actor *player = SDL_GetPointerProperty(AKGL_REGISTRY_ACTOR, "player", NULL);
PREPARE_ERROR(e);
PASS(e, akgl_tilemap_release(&gamemap));
FAIL_ZERO_RETURN(e, player, AKERR_NULLPOINTER, "missing actor");
FAIL_ZERO_RETURN(e, menupointer, AKERR_NULLPOINTER, "missing actor");
AKGL_BITMASK_DEL(game.state.flags, AKGLTEST_STATE_WAITFORINPUT);
AKGL_BITMASK_DEL(game.state.flags, AKGLTEST_STATE_RUNNING);
// Reset all the actors back to empty (except the player and menupointer)
for ( int i = 0 ; i < AKGL_MAX_HEAP_ACTOR; i++ ) {
if ( &HEAP_ACTOR[i] != player && &HEAP_ACTOR[i] != menupointer ) {
PASS(e, akgl_heap_release_actor(&HEAP_ACTOR[i]));
//SDL_ClearProperty(AKGL_REGISTRY_ACTOR, (char *)&HEAP_ACTOR[i].name);
//memset(&HEAP_ACTOR[i], 0x00, sizeof(akgl_Actor));
} else {
SDL_Log("Preserving menupointer and actor (%p)", &HEAP_ACTOR[i]);
}
}
GAME_ControlMaps[AKGLTEST_CONTROLMAP_INGAMEACTOR].target = NULL;
GAME_ControlMaps[AKGLTEST_CONTROLMAP_MENU].target = menupointer;
menupointer->visible = true;
AKGL_BITMASK_ADD(game.state.flags, AKGLTEST_STATE_MAPMENU);
SUCCEED_RETURN(e);
}
akerr_ErrorContext AKERR_NOIGNORE *akgltest_set_gamemode_running(akgl_Actor *appstate, SDL_Event *event)
{
akgl_Actor *menupointer = SDL_GetPointerProperty(AKGL_REGISTRY_ACTOR, "menupointer", NULL);
akgl_Actor *actorptr = SDL_GetPointerProperty(AKGL_REGISTRY_ACTOR, "player", NULL);
PREPARE_ERROR(e);
FAIL_ZERO_RETURN(e, menupointer, AKERR_NULLPOINTER, "missing actor");
FAIL_ZERO_RETURN(e, actorptr, AKERR_NULLPOINTER, "missing actor");
AKGL_BITMASK_DEL(game.state.flags, AKGLTEST_STATE_WAITFORINPUT);
AKGL_BITMASK_ADD(game.state.flags, AKGLTEST_STATE_MAPMENU);
GAME_ControlMaps[AKGLTEST_CONTROLMAP_INGAMEACTOR].target = actorptr;
GAME_ControlMaps[AKGLTEST_CONTROLMAP_MENU].target = NULL;
menupointer->visible = false;
actorptr->visible = true;
AKGL_BITMASK_DEL(game.state.flags, AKGLTEST_STATE_MAPMENU);
if ( menuselection == 0 ) {
strcpy((char *)&dirnamebuf, "assets/imagemap.tmj");
PASS(e, akgl_tilemap_load((char *)&dirnamebuf, (akgl_Tilemap *)&gamemap));
} else if ( menuselection == 1 ) {
strcpy((char *)&dirnamebuf, "assets/tilemap.tmj");
PASS(e, akgl_tilemap_load((char *)&dirnamebuf, (akgl_Tilemap *)&gamemap));
} else if ( menuselection == 2 ) {
AKGL_BITMASK_DEL(game.state.flags, AKGLTEST_STATE_RUNNING);
AKGL_BITMASK_ADD(game.state.flags, AKGLTEST_STATE_QUIT);
}
AKGL_BITMASK_ADD(game.state.flags, AKGLTEST_STATE_RUNNING);
SUCCEED_RETURN(e);
}
akerr_ErrorContext AKERR_NOIGNORE *akgltest_menupointer_logic_movement(akgl_Actor *obj, SDL_Time curtime)
{
PREPARE_ERROR(e);
FAIL_ZERO_RETURN(e, obj, AKERR_NULLPOINTER, "NULL actor");
if ( AKGL_BITMASK_HAS(obj->state, AKGL_ACTOR_STATE_MOVING_DOWN) ) {
if ( menuselection < maxmenu ) {
menuselection += 1;
} else {
menuselection = 0;
}
} else if ( AKGL_BITMASK_HAS(obj->state, AKGL_ACTOR_STATE_MOVING_UP) ) {
if ( menuselection == 0 ) {
menuselection = maxmenu;
} else {
menuselection -= 1;
}
}
obj->y = 85 + (menuselection * 100);
AKGL_BITMASK_DEL(obj->state, (AKGL_ACTOR_STATE_MOVING_UP | AKGL_ACTOR_STATE_MOVING_DOWN));
SUCCEED_RETURN(e);
}
akerr_ErrorContext AKERR_NOIGNORE *music_toggle(akgl_Actor *obj, SDL_Event *event)
{
SDL_PropertiesID bgmprops = 0;
PREPARE_ERROR(errctx);
if ( MIX_TrackPlaying(akgl_tracks[AKGL_GAME_AUDIO_TRACK_BGM]) ) {
FAIL_ZERO_RETURN(
errctx,
MIX_StopTrack(akgl_tracks[AKGL_GAME_AUDIO_TRACK_BGM], 0),
AKGL_ERR_SDL,
"%s",
SDL_GetError());
} else {
SDL_SetNumberProperty(bgmprops, MIX_PROP_PLAY_LOOPS_NUMBER, -1);
FAIL_ZERO_RETURN(
errctx,
MIX_PlayTrack(akgl_tracks[AKGL_GAME_AUDIO_TRACK_BGM], bgmprops),
AKGL_ERR_SDL,
"%s",
SDL_GetError());
}
SUCCEED_RETURN(errctx);
}
akerr_ErrorContext AKERR_NOIGNORE *savegame(akgl_Actor *obj, SDL_Event *event)
{
return akgl_game_save("assets/savegame.bin");
}
akerr_ErrorContext AKERR_NOIGNORE *quit_game(akgl_Actor *obj, SDL_Event *event)
{
PREPARE_ERROR(errctx);
AKGL_BITMASK_ADD(game.state.flags, AKGLTEST_STATE_QUIT);
SDL_Log("Quitting game");
SUCCEED_RETURN(errctx);
}
akerr_ErrorContext AKERR_NOIGNORE *akgltest_load_assets() akerr_ErrorContext AKERR_NOIGNORE *akgltest_load_assets()
{ {
PREPARE_ERROR(errctx); PREPARE_ERROR(e);
for ( int i = 0; i < numsprites ; i++) { for ( int i = 0; i < numsprites ; i++) {
strcpy((char *)&dirnamebuf, spritepaths[i]); strcpy((char *)&dirnamebuf, spritepaths[i]);
SDL_Log("Loading sprite %s (%d of %d)....", (char *)&dirnamebuf, i, numsprites); SDL_Log("Loading sprite %s (%d of %d)....", (char *)&dirnamebuf, i, numsprites);
PASS(errctx, akgl_sprite_load_json((char *)&dirnamebuf)); PASS(e, akgl_sprite_load_json((char *)&dirnamebuf));
} }
for ( int i = 0; i < numchars ; i++ ) { for ( int i = 0; i < numchars ; i++ ) {
strcpy((char *)&dirnamebuf, characterpaths[i]); strcpy((char *)&dirnamebuf, characterpaths[i]);
SDL_Log("Loading character %s (%d of %d)....", (char *)&dirnamebuf, i, numchars); SDL_Log("Loading character %s (%d of %d)....", (char *)&dirnamebuf, i, numchars);
PASS(errctx, akgl_character_load_json((char *)&dirnamebuf)); PASS(e, akgl_character_load_json((char *)&dirnamebuf));
} }
SUCCEED_RETURN(errctx);
}
akerr_ErrorContext AKERR_NOIGNORE *akgltest_set_actor_visible(char *actorname, bool visible)
{
PREPARE_ERROR(e);
akgl_Actor *actorptr = NULL;
actorptr = SDL_GetPointerProperty(AKGL_REGISTRY_ACTOR, actorname, NULL);
FAIL_ZERO_RETURN(e, actorptr, AKERR_NULLPOINTER, "%s missing in registry", actorname);
actorptr->visible = visible;
SUCCEED_RETURN(e); SUCCEED_RETURN(e);
} }
@@ -201,46 +82,33 @@ SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
{ {
akgl_Actor *actorptr = NULL; akgl_Actor *actorptr = NULL;
*appstate = (void *)&game.state; *appstate = (void *)&game.state;
PREPARE_ERROR(errctx); PREPARE_ERROR(e);
AKGL_BITMASK_ADD(game.state.flags, AKGLTEST_STATE_LOADING); AKGL_BITMASK_ADD(game.state.flags, AKGLTEST_STATE_LOADING);
ATTEMPT { ATTEMPT {
FAIL_ZERO_BREAK(errctx, appstate, AKERR_NULLPOINTER, "NULL appstate pointer"); FAIL_ZERO_BREAK(e, appstate, AKERR_NULLPOINTER, "NULL appstate pointer");
strcpy((char *)&game.name, "sdl3-gametest"); strcpy((char *)&game.name, "sdl3-gametest");
strcpy((char *)&game.version, "0.0.1"); strcpy((char *)&game.version, "0.0.1");
strcpy((char *)&game.uri, "net.aklabs.games.sdl3-gametest"); strcpy((char *)&game.uri, "net.aklabs.games.sdl3-gametest");
//CATCH(errctx, akgl_game_load("assets/savegame.bin")); //CATCH(e, akgl_game_load("assets/savegame.bin"));
CATCH(errctx, akgl_game_init()); CATCH(e, akgl_game_init());
CATCH(errctx, akgl_registry_load_properties("assets/properties.json")); CATCH(e, akgl_registry_load_properties("assets/properties.json"));
CATCH(errctx, akgl_render_init2d(&renderer)); CATCH(e, akgl_render_init2d(&renderer));
CATCH(errctx, akgl_controller_list_keyboards()); CATCH(e, akgl_physics_init_sidescroller(&physics));
CATCH(e, akgl_controller_list_keyboards());
CATCH(errctx, akgltest_load_assets()); CATCH(e, akgltest_load_assets());
CATCH(errctx, akgl_heap_next_actor(&actorptr)); CATCH(e, akgl_heap_next_actor(&actorptr));
CATCH(errctx, akgl_actor_initialize((akgl_Actor *)actorptr, "menupointer")); CATCH(e, akgl_actor_initialize((akgl_Actor *)actorptr, "player"));
actorptr->basechar = SDL_GetPointerProperty(
AKGL_REGISTRY_CHARACTER,
"menupointer",
NULL);
FAIL_ZERO_BREAK(errctx, actorptr->basechar, AKERR_REGISTRY, "menupointer character missing");
actorptr->movementlogicfunc = &akgltest_menupointer_logic_movement;
actorptr->movement_controls_face = false;
actorptr->state = (AKGL_ACTOR_STATE_ALIVE | AKGL_ACTOR_STATE_FACE_DOWN);
actorptr->x = 50;
actorptr->y = 100;
actorptr->visible = false;
CATCH(errctx, akgl_heap_next_actor(&actorptr));
CATCH(errctx, akgl_actor_initialize((akgl_Actor *)actorptr, "player"));
actorptr->basechar = SDL_GetPointerProperty( actorptr->basechar = SDL_GetPointerProperty(
AKGL_REGISTRY_CHARACTER, AKGL_REGISTRY_CHARACTER,
"little guy", "little guy",
NULL); NULL);
FAIL_ZERO_BREAK(errctx, actorptr->basechar, AKERR_REGISTRY, "Can't load character 'little guy' from the registry"); FAIL_ZERO_BREAK(e, actorptr->basechar, AKERR_REGISTRY, "Can't load character 'little guy' from the registry");
actorptr->movement_controls_face = false; actorptr->movement_controls_face = false;
actorptr->state = (AKGL_ACTOR_STATE_ALIVE | AKGL_ACTOR_STATE_FACE_LEFT); actorptr->state = (AKGL_ACTOR_STATE_ALIVE | AKGL_ACTOR_STATE_FACE_LEFT);
actorptr->x = 320; actorptr->x = 320;
@@ -248,18 +116,18 @@ SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
actorptr->visible = false; actorptr->visible = false;
strcpy((char *)&dirnamebuf, "assets/memories.mp3"); strcpy((char *)&dirnamebuf, "assets/memories.mp3");
CATCH(errctx, akgl_load_start_bgm((char *)&dirnamebuf)); CATCH(e, akgl_load_start_bgm((char *)&dirnamebuf));
CATCH(errctx, music_toggle(NULL, NULL)); CATCH(e, music_toggle(NULL, NULL));
CATCH(errctx, akgl_text_loadfont("C64Pro", "assets/C64_Pro-STYLE.ttf", 18)); CATCH(e, akgl_text_loadfont("C64Pro", "assets/C64_Pro-STYLE.ttf", 18));
} CLEANUP { } CLEANUP {
} PROCESS(errctx) { } PROCESS(e) {
} HANDLE_DEFAULT(errctx) { } HANDLE_DEFAULT(e) {
LOG_ERROR(errctx); LOG_ERROR(e);
return SDL_APP_FAILURE; return SDL_APP_FAILURE;
} FINISH_NORETURN(errctx); } FINISH_NORETURN(e);
AKGL_BITMASK_DEL(game.state.flags, AKGLTEST_STATE_LOADING); AKGL_BITMASK_DEL(game.state.flags, AKGLTEST_STATE_LOADING);
AKGL_BITMASK_ADD(game.state.flags, AKGLTEST_STATE_WAITFORINPUT); AKGL_BITMASK_ADD(game.state.flags, AKGLTEST_STATE_WAITFORINPUT);
@@ -267,230 +135,6 @@ SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
return SDL_APP_CONTINUE; return SDL_APP_CONTINUE;
} }
akerr_ErrorContext AKERR_NOIGNORE *akgltest_controller_bind_universal(char *actorname, int mapid, int kbid, int jsid)
{
akgl_Control control;
PREPARE_ERROR(e);
PASS(e, akgl_controller_default(mapid, actorname, kbid, jsid));
// set custom control maps */
memset((void *)&control, 0x00, sizeof(akgl_Control));
// Quit
control.key = SDLK_ESCAPE;
control.event_on = SDL_EVENT_KEY_DOWN;
control.handler_on = &akgltest_set_gamemode_menu;
PASS(e, akgl_controller_pushmap(mapid, &control));
// Toggle the music
control.key = SDLK_M;
control.event_on = SDL_EVENT_KEY_DOWN;
control.handler_on = &music_toggle;
PASS(e, akgl_controller_pushmap(mapid, &control));
// Save the game
control.key = SDLK_S;
control.event_on = SDL_EVENT_KEY_DOWN;
control.handler_on = &savegame;
PASS(e, akgl_controller_pushmap(AKGLTEST_CONTROLMAP_INGAMEACTOR, &control));
// Menu selection
control.key = SDLK_RETURN;
control.event_on = SDL_EVENT_KEY_DOWN;
control.handler_on = &akgltest_set_gamemode_running;
PASS(e, akgl_controller_pushmap(AKGLTEST_CONTROLMAP_MENU, &control));
if ( jsid != 0 ) {
// Gamepad Menu selection. Use whatever button they pushed as the action
control.button = SDL_GAMEPAD_BUTTON_START;
control.event_on = SDL_EVENT_GAMEPAD_BUTTON_UP;
control.handler_on = &akgltest_set_gamemode_running;
PASS(e, akgl_controller_pushmap(AKGLTEST_CONTROLMAP_MENU, &control));
// Toggle the music
control.button = SDL_GAMEPAD_BUTTON_SOUTH;
control.event_on = SDL_EVENT_GAMEPAD_BUTTON_UP;
control.handler_on = &music_toggle;
PASS(e, akgl_controller_pushmap(mapid, &control));
// Quit
control.button = SDL_GAMEPAD_BUTTON_EAST;
control.event_on = SDL_EVENT_GAMEPAD_BUTTON_UP;
control.handler_on = &akgltest_set_gamemode_menu;
PASS(e, akgl_controller_pushmap(mapid, &control));
}
SUCCEED_RETURN(e);
}
akerr_ErrorContext AKERR_NOIGNORE *akgltest_controller_get_defaults(void *appstate, SDL_Event *event)
{
akgl_Control control;
int kbid = 0;
int jsid = 0;
PREPARE_ERROR(e);
if (event->type == SDL_EVENT_GAMEPAD_BUTTON_DOWN || event->type == SDL_EVENT_GAMEPAD_BUTTON_UP) {
jsid = event->gbutton.which;
} else if (event->type == SDL_EVENT_KEY_DOWN || event->type == SDL_EVENT_KEY_UP) {
kbid = event->key.which;
}
PASS(e, akgltest_controller_bind_universal("player", AKGLTEST_CONTROLMAP_MENU, kbid, jsid));
PASS(e, akgltest_controller_bind_universal("menupointer", AKGLTEST_CONTROLMAP_INGAMEACTOR, kbid, jsid));
SUCCEED_RETURN(e);
}
SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event)
{
PREPARE_ERROR(errctx);
ATTEMPT {
FAIL_ZERO_BREAK(errctx, appstate, AKERR_NULLPOINTER, "NULL appstate pointer");
FAIL_ZERO_BREAK(errctx, event, AKERR_NULLPOINTER, "NULL event pointer");
if ( event->type == SDL_EVENT_GAMEPAD_BUTTON_DOWN ||
event->type == SDL_EVENT_GAMEPAD_BUTTON_UP ||
event->type == SDL_EVENT_KEY_DOWN ||
event->type == SDL_EVENT_KEY_UP ) {
if ( AKGL_BITMASK_HAS(game.state.flags, AKGLTEST_STATE_WAITFORINPUT) ) {
// get the player's default keyboard or gamepad id from the event
CATCH(errctx, akgltest_controller_get_defaults(appstate, event));
CATCH(errctx, akgltest_set_gamemode_menu(appstate, event));
} else {
CATCH(errctx, akgl_controller_handle_event(appstate, event));
}
}
if (event->type == SDL_EVENT_QUIT) {
return SDL_APP_SUCCESS; /* end the program, reporting success to the OS. */
}
} CLEANUP {
} PROCESS(errctx) {
} FINISH_NORETURN(errctx);
return SDL_APP_CONTINUE; /* carry on with the program! */
}
akerr_ErrorContext AKERR_NOIGNORE *akgltest_iterate_mapmenu(void)
{
akgl_Actor *menupointer = NULL;
PREPARE_ERROR(e);
ATTEMPT {
CATCH(e, renderer.frame_start(&renderer))
SDL_SetRenderDrawColor(renderer.sdl_renderer, 0, 0, 0, 255);
SDL_RenderClear(renderer.sdl_renderer);
PASS(e, akgl_text_rendertextat(
SDL_GetPointerProperty(
AKGL_REGISTRY_FONT,
"C64Pro",
NULL),
"IMAGE MAP DEMO",
(SDL_Color){255, 255, 255, 255},
0,
150,
100)
);
PASS(e, akgl_text_rendertextat(
SDL_GetPointerProperty(
AKGL_REGISTRY_FONT,
"C64Pro",
NULL),
"TILE MAP DEMO",
(SDL_Color){255, 255, 255, 255},
0,
150,
200)
);
PASS(e, akgl_text_rendertextat(
SDL_GetPointerProperty(
AKGL_REGISTRY_FONT,
"C64Pro",
NULL),
"QUIT GAME",
(SDL_Color){255, 255, 255, 255},
0,
150,
300)
);
menupointer = SDL_GetPointerProperty(AKGL_REGISTRY_ACTOR, "menupointer", NULL);
FAIL_ZERO_BREAK(e, menupointer, AKERR_NULLPOINTER, "actor missing from registry");
menupointer->visible = true;
CATCH(e, menupointer->updatefunc(menupointer));
CATCH(e, menupointer->movementlogicfunc(menupointer, 0));
CATCH(e, menupointer->renderfunc(menupointer));
CATCH(e, renderer.frame_end(&renderer))
} CLEANUP {
} PROCESS(e) {
} FINISH(e, true);
SUCCEED_RETURN(e);
}
akerr_ErrorContext AKERR_NOIGNORE *akgltest_iterate_waitforinput(void)
{
PREPARE_ERROR(errctx);
akgl_game_updateFPS();
PASS(errctx, akgl_text_rendertextat(
SDL_GetPointerProperty(
AKGL_REGISTRY_FONT,
"C64Pro",
NULL),
"PRESS ANY KEY OR JOYSTICK BUTTON",
(SDL_Color){255, 255, 255, 255},
0,
40,
120)
);
PASS(errctx, renderer.frame_end(&renderer));
SUCCEED_RETURN(errctx);
}
akerr_ErrorContext AKERR_NOIGNORE *akgltest_iterate_running(void)
{
int i = 0;
akgl_Iterator opflags;
char fpsText[32];
PREPARE_ERROR(errctx);
akgl_game_updateFPS();
AKGL_BITMASK_CLEAR(opflags.flags);
AKGL_BITMASK_ADD(opflags.flags, AKGL_ITERATOR_OP_UPDATE);
AKGL_BITMASK_ADD(opflags.flags, AKGL_ITERATOR_OP_RENDER);
AKGL_BITMASK_ADD(opflags.flags, AKGL_ITERATOR_OP_LAYERMASK);
AKGL_BITMASK_ADD(opflags.flags, AKGL_ITERATOR_OP_TILEMAPSCALE);
for ( i = 0; i < AKGL_TILEMAP_MAX_LAYERS; i++ ) {
opflags.layerid = i;
PASS(errctx, akgl_tilemap_draw((akgl_Tilemap *)&gamemap, &camera, i));
SDL_EnumerateProperties(AKGL_REGISTRY_ACTOR, &akgl_registry_iterate_actor, (void *)&opflags);
}
ATTEMPT {
memset((char *)&fpsText, 0x00, 32);
snprintf((char *)&fpsText, 31, "FPS : %d", game.fps);
PASS(errctx, akgl_text_rendertextat(
SDL_GetPointerProperty(
AKGL_REGISTRY_FONT,
"C64Pro",
NULL),
(char *)&fpsText,
(SDL_Color){255, 255, 255, 255},
0,
450,
10)
);
} CLEANUP {
SDL_RenderPresent(renderer.sdl_renderer);
} PROCESS(errctx) {
} HANDLE_DEFAULT(errctx) {
} FINISH(errctx, true);
SUCCEED_RETURN(errctx);
}
SDL_AppResult SDL_AppIterate(void *appstate) SDL_AppResult SDL_AppIterate(void *appstate)
{ {

24
src/audio.c Normal file
View File

@@ -0,0 +1,24 @@
#include <akgltest.h>
akerr_ErrorContext AKERR_NOIGNORE *music_toggle(akgl_Actor *obj, SDL_Event *event)
{
SDL_PropertiesID bgmprops = 0;
PREPARE_ERROR(e);
if ( MIX_TrackPlaying(akgl_tracks[AKGL_GAME_AUDIO_TRACK_BGM]) ) {
FAIL_ZERO_RETURN(
e,
MIX_StopTrack(akgl_tracks[AKGL_GAME_AUDIO_TRACK_BGM], 0),
AKGL_ERR_SDL,
"%s",
SDL_GetError());
} else {
SDL_SetNumberProperty(bgmprops, MIX_PROP_PLAY_LOOPS_NUMBER, -1);
FAIL_ZERO_RETURN(
e,
MIX_PlayTrack(akgl_tracks[AKGL_GAME_AUDIO_TRACK_BGM], bgmprops),
AKGL_ERR_SDL,
"%s",
SDL_GetError());
}
SUCCEED_RETURN(e);
}

71
src/controllers.c Normal file
View File

@@ -0,0 +1,71 @@
#include <akgltest.h>
akerr_ErrorContext AKERR_NOIGNORE *akgltest_controller_bind_universal(char *actorname, int mapid, int kbid, int jsid)
{
akgl_Control control;
PREPARE_ERROR(e);
PASS(e, akgl_controller_default(mapid, actorname, kbid, jsid));
// set custom control maps */
memset((void *)&control, 0x00, sizeof(akgl_Control));
// Quit
control.key = SDLK_ESCAPE;
control.event_on = SDL_EVENT_KEY_DOWN;
control.handler_on = &akgltest_set_gamemode_menu;
PASS(e, akgl_controller_pushmap(mapid, &control));
// Toggle the music
control.key = SDLK_M;
control.event_on = SDL_EVENT_KEY_DOWN;
control.handler_on = &music_toggle;
PASS(e, akgl_controller_pushmap(mapid, &control));
// Save the game
control.key = SDLK_S;
control.event_on = SDL_EVENT_KEY_DOWN;
control.handler_on = &savegame;
PASS(e, akgl_controller_pushmap(AKGLTEST_CONTROLMAP_INGAMEACTOR, &control));
// Menu selection
control.key = SDLK_RETURN;
control.event_on = SDL_EVENT_KEY_DOWN;
control.handler_on = &akgltest_set_gamemode_running;
PASS(e, akgl_controller_pushmap(AKGLTEST_CONTROLMAP_MENU, &control));
if ( jsid != 0 ) {
// Gamepad Menu selection. Use whatever button they pushed as the action
control.button = SDL_GAMEPAD_BUTTON_START;
control.event_on = SDL_EVENT_GAMEPAD_BUTTON_UP;
control.handler_on = &akgltest_set_gamemode_running;
PASS(e, akgl_controller_pushmap(AKGLTEST_CONTROLMAP_MENU, &control));
// Toggle the music
control.button = SDL_GAMEPAD_BUTTON_SOUTH;
control.event_on = SDL_EVENT_GAMEPAD_BUTTON_UP;
control.handler_on = &music_toggle;
PASS(e, akgl_controller_pushmap(mapid, &control));
// Quit
control.button = SDL_GAMEPAD_BUTTON_EAST;
control.event_on = SDL_EVENT_GAMEPAD_BUTTON_UP;
control.handler_on = &akgltest_set_gamemode_menu;
PASS(e, akgl_controller_pushmap(mapid, &control));
}
SUCCEED_RETURN(e);
}
akerr_ErrorContext AKERR_NOIGNORE *akgltest_controller_get_defaults(void *appstate, SDL_Event *event)
{
akgl_Control control;
PREPARE_ERROR(e);
if (event->type == SDL_EVENT_GAMEPAD_BUTTON_DOWN || event->type == SDL_EVENT_GAMEPAD_BUTTON_UP) {
jsid = event->gbutton.which;
} else if (event->type == SDL_EVENT_KEY_DOWN || event->type == SDL_EVENT_KEY_UP) {
kbid = event->key.which;
}
SUCCEED_RETURN(e);
}

45
src/events.c Normal file
View File

@@ -0,0 +1,45 @@
#include <akgltest.h>
akerr_ErrorContext AKERR_NOIGNORE *savegame(akgl_Actor *obj, SDL_Event *event)
{
return akgl_game_save("assets/savegame.bin");
}
akerr_ErrorContext AKERR_NOIGNORE *quit_game(akgl_Actor *obj, SDL_Event *event)
{
PREPARE_ERROR(e);
AKGL_BITMASK_ADD(game.state.flags, AKGLTEST_STATE_QUIT);
SDL_Log("Quitting game");
SUCCEED_RETURN(e);
}
SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event)
{
PREPARE_ERROR(e);
ATTEMPT {
CATCH(e, akgl_game_state_lock());
FAIL_ZERO_BREAK(e, appstate, AKERR_NULLPOINTER, "NULL appstate pointer");
FAIL_ZERO_BREAK(e, event, AKERR_NULLPOINTER, "NULL event pointer");
if ( AKGL_BITMASK_HAS(game.state.flags, AKGLTEST_STATE_WAITFORINPUT) ) {
if ( event->type == SDL_EVENT_GAMEPAD_BUTTON_DOWN ||
event->type == SDL_EVENT_GAMEPAD_BUTTON_UP ||
event->type == SDL_EVENT_KEY_DOWN ||
event->type == SDL_EVENT_KEY_UP ) {
// get the player's default keyboard or gamepad id from the event
CATCH(e, akgltest_controller_get_defaults(appstate, event));
CATCH(e, akgltest_set_gamemode_menu(appstate, event));
}
} else {
CATCH(e, akgl_controller_handle_event(appstate, event));
}
if (event->type == SDL_EVENT_QUIT) {
return SDL_APP_SUCCESS; /* end the program, reporting success to the OS. */
}
} CLEANUP {
IGNORE(akgl_game_state_unlock());
} PROCESS(e) {
} FINISH_NORETURN(e);
return SDL_APP_CONTINUE; /* carry on with the program! */
}

173
src/gamemodes.c Normal file
View File

@@ -0,0 +1,173 @@
#include <akgltest.h>
akerr_ErrorContext AKERR_NOIGNORE *akgltest_set_gamemode_menu(akgl_Actor *appstate, SDL_Event *event)
{
PREPARE_ERROR(e);
AKGL_BITMASK_DEL(game.state.flags, AKGLTEST_STATE_WAITFORINPUT);
AKGL_BITMASK_DEL(game.state.flags, AKGLTEST_STATE_RUNNING);
PASS(e, akgl_tilemap_release(&gamemap));
PASS(e, akgl_registry_init_actor());
PASS(e, akgl_heap_init_actor());
PASS(e, akgltest_init_menupointer());
akgl_Actor *menupointer = SDL_GetPointerProperty(AKGL_REGISTRY_ACTOR, "menupointer", NULL);
GAME_ControlMaps[AKGLTEST_CONTROLMAP_INGAMEACTOR].target = NULL;
GAME_ControlMaps[AKGLTEST_CONTROLMAP_MENU].target = menupointer;
menupointer->visible = true;
PASS(e, aksl_memset((void *)GAME_ControlMaps, 0x00, (sizeof(akgl_ControlMap) * AKGL_MAX_CONTROL_MAPS)));
PASS(e, akgltest_controller_bind_universal("menupointer", AKGLTEST_CONTROLMAP_MENU, kbid, jsid));
PASS(e, aksl_memset((void *)&gamemap, 0x00, sizeof(akgl_Tilemap)));
AKGL_BITMASK_ADD(game.state.flags, AKGLTEST_STATE_MAPMENU);
SUCCEED_RETURN(e);
}
akerr_ErrorContext AKERR_NOIGNORE *akgltest_set_gamemode_running(akgl_Actor *appstate, SDL_Event *event)
{
PREPARE_ERROR(e);
AKGL_BITMASK_DEL(game.state.flags, AKGLTEST_STATE_WAITFORINPUT);
AKGL_BITMASK_DEL(game.state.flags, AKGLTEST_STATE_MAPMENU);
PASS(e, akgl_registry_init_actor());
PASS(e, akgl_heap_init_actor());
PASS(e, akgltest_init_player());
PASS(e, aksl_memset((void *)GAME_ControlMaps, 0x00, (sizeof(akgl_ControlMap) * AKGL_MAX_CONTROL_MAPS)));
PASS(e, akgltest_controller_bind_universal("player", AKGLTEST_CONTROLMAP_INGAMEACTOR, kbid, jsid));
akgl_Actor *actorptr = SDL_GetPointerProperty(AKGL_REGISTRY_ACTOR, "player", NULL);
GAME_ControlMaps[AKGLTEST_CONTROLMAP_INGAMEACTOR].target = actorptr;
GAME_ControlMaps[AKGLTEST_CONTROLMAP_MENU].target = NULL;
actorptr->visible = true;
if ( menuselection == 0 ) {
strcpy((char *)&dirnamebuf, "assets/imagemap.tmj");
PASS(e, akgl_tilemap_load((char *)&dirnamebuf, (akgl_Tilemap *)&gamemap));
} else if ( menuselection == 1 ) {
strcpy((char *)&dirnamebuf, "assets/tilemap.tmj");
PASS(e, akgl_tilemap_load((char *)&dirnamebuf, (akgl_Tilemap *)&gamemap));
} else if ( menuselection == 2 ) {
strcpy((char *)&dirnamebuf, "assets/sidescroller.tmj");
PASS(e, akgl_tilemap_load((char *)&dirnamebuf, (akgl_Tilemap *)&gamemap));
} else if ( menuselection == 3 ) {
AKGL_BITMASK_DEL(game.state.flags, AKGLTEST_STATE_RUNNING);
AKGL_BITMASK_ADD(game.state.flags, AKGLTEST_STATE_QUIT);
}
AKGL_BITMASK_ADD(game.state.flags, AKGLTEST_STATE_RUNNING);
SUCCEED_RETURN(e);
}
akerr_ErrorContext AKERR_NOIGNORE *akgltest_iterate_mapmenu(void)
{
akgl_Actor *menupointer = NULL;
akgl_Iterator opflags = {
.flags = 0,
.layerid = 0
};
PREPARE_ERROR(e);
ATTEMPT {
CATCH(e, renderer.frame_start(&renderer))
SDL_SetRenderDrawColor(renderer.sdl_renderer, 0, 0, 0, 255);
SDL_RenderClear(renderer.sdl_renderer);
PASS(e, akgl_text_rendertextat(
SDL_GetPointerProperty(
AKGL_REGISTRY_FONT,
"C64Pro",
NULL),
"IMAGE MAP DEMO",
(SDL_Color){255, 255, 255, 255},
0,
150,
100)
);
PASS(e, akgl_text_rendertextat(
SDL_GetPointerProperty(
AKGL_REGISTRY_FONT,
"C64Pro",
NULL),
"TILE MAP DEMO",
(SDL_Color){255, 255, 255, 255},
0,
150,
200)
);
PASS(e, akgl_text_rendertextat(
SDL_GetPointerProperty(
AKGL_REGISTRY_FONT,
"C64Pro",
NULL),
"SIDESCROLLER MAP DEMO",
(SDL_Color){255, 255, 255, 255},
0,
150,
300)
);
PASS(e, akgl_text_rendertextat(
SDL_GetPointerProperty(
AKGL_REGISTRY_FONT,
"C64Pro",
NULL),
"QUIT GAME",
(SDL_Color){255, 255, 255, 255},
0,
150,
400)
);
menupointer = SDL_GetPointerProperty(AKGL_REGISTRY_ACTOR, "menupointer", NULL);
FAIL_ZERO_BREAK(e, menupointer, AKERR_NULLPOINTER, "actor missing from registry");
menupointer->visible = true;
CATCH(e, akgl_game_update(&opflags));
CATCH(e, renderer.frame_end(&renderer))
} CLEANUP {
} PROCESS(e) {
} FINISH(e, true);
SUCCEED_RETURN(e);
}
akerr_ErrorContext AKERR_NOIGNORE *akgltest_iterate_waitforinput(void)
{
PREPARE_ERROR(e);
akgl_game_updateFPS();
PASS(e, akgl_text_rendertextat(
SDL_GetPointerProperty(
AKGL_REGISTRY_FONT,
"C64Pro",
NULL),
"PRESS ANY KEY OR JOYSTICK BUTTON",
(SDL_Color){255, 255, 255, 255},
0,
40,
120)
);
PASS(e, renderer.frame_end(&renderer));
SUCCEED_RETURN(e);
}
akerr_ErrorContext AKERR_NOIGNORE *akgltest_iterate_running(void)
{
int i = 0;
akgl_Iterator opflags;
char fpsText[32];
PREPARE_ERROR(e);
PASS(e, renderer.frame_start(&renderer));
PASS(e, akgl_game_update(NULL));
memset((char *)&fpsText, 0x00, 32);
snprintf((char *)&fpsText, 31, "FPS : %d", game.fps);
PASS(e, akgl_text_rendertextat(
SDL_GetPointerProperty(
AKGL_REGISTRY_FONT,
"C64Pro",
NULL),
(char *)&fpsText,
(SDL_Color){255, 255, 255, 255},
0,
450,
10)
);
PASS(e, renderer.frame_end(&renderer));
SUCCEED_RETURN(e);
}

18
src/init.c Normal file
View File

@@ -0,0 +1,18 @@
#include <akgltest.h>
akerr_ErrorContext AKERR_NOIGNORE *akgltest_load_assets()
{
PREPARE_ERROR(e);
for ( int i = 0; i < numsprites ; i++) {
strcpy((char *)&dirnamebuf, spritepaths[i]);
SDL_Log("Loading sprite %s (%d of %d)....", (char *)&dirnamebuf, i, numsprites);
PASS(e, akgl_sprite_load_json((char *)&dirnamebuf));
}
for ( int i = 0; i < numchars ; i++ ) {
strcpy((char *)&dirnamebuf, characterpaths[i]);
SDL_Log("Loading character %s (%d of %d)....", (char *)&dirnamebuf, i, numchars);
PASS(e, akgl_character_load_json((char *)&dirnamebuf));
}
SUCCEED_RETURN(e);
}

36
src/main.c Normal file
View File

@@ -0,0 +1,36 @@
#define SDL_MAIN_USE_CALLBACKS
#include <akgltest.h>
int menuselection = 0;
int maxmenu = 3;
int kbid = 0;
int jsid = 0;
int numchars = 2;
char *characterpaths[] = {
"assets/characters/littleguy.json",
"assets/characters/menupointer.json"
};
int numsounds = 2;
char *soundfiles[] = {
"assets/vgmenuhighlight.wav",
"assets/vgmenuselect.wav"
};
int numsprites = 9;
char *spritepaths[] = {
"assets/sprites/menupointer.json",
"assets/sprites/little_guy_walking_left.json",
"assets/sprites/little_guy_walking_right.json",
"assets/sprites/little_guy_walking_up.json",
"assets/sprites/little_guy_walking_down.json",
"assets/sprites/little_guy_facing_left.json",
"assets/sprites/little_guy_facing_right.json",
"assets/sprites/little_guy_facing_up.json",
"assets/sprites/little_guy_facing_down.json"
};
char dirnamebuf[1024];