Decently small and minimalistic working base.
This commit is contained in:
commit
f3f6677386
|
@ -0,0 +1,19 @@
|
|||
# Build files
|
||||
/build-fx
|
||||
/build-cg
|
||||
/*.g1a
|
||||
/*.g3a
|
||||
|
||||
# Python bytecode
|
||||
__pycache__/
|
||||
|
||||
# Common IDE files
|
||||
*.sublime-project
|
||||
*.sublime-workspace
|
||||
.vscode
|
||||
|
||||
# KBLE backup files
|
||||
backup_*.kble
|
||||
|
||||
# Generated C files.
|
||||
gen_*.c
|
|
@ -0,0 +1,48 @@
|
|||
# Configure with [fxsdk build-fx] or [fxsdk build-cg], which provide the
|
||||
# toolchain file and module path of the fxSDK
|
||||
|
||||
cmake_minimum_required(VERSION 3.18)
|
||||
project(MyAddin)
|
||||
|
||||
execute_process(COMMAND python3 kble.py
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR})
|
||||
|
||||
include(GenerateG1A)
|
||||
include(GenerateG3A)
|
||||
include(Fxconv)
|
||||
include_directories(include)
|
||||
find_package(Gint 2.1 REQUIRED)
|
||||
|
||||
set(SOURCES
|
||||
src/main.c
|
||||
src/player.c
|
||||
src/input.c
|
||||
src/gen_levels.c
|
||||
# ...
|
||||
)
|
||||
# Shared assets, fx-9860G-only assets and fx-CG-50-only assets
|
||||
set(ASSETS
|
||||
# ...
|
||||
)
|
||||
#set(ASSETS_fx
|
||||
# assets-fx/example.png
|
||||
# # ...
|
||||
#)
|
||||
#set(ASSETS_cg
|
||||
# assets-cg/example.png
|
||||
# # ...
|
||||
#)
|
||||
|
||||
fxconv_declare_assets(${ASSETS} ${ASSETS_fx} ${ASSETS_cg} WITH_METADATA)
|
||||
|
||||
add_executable(myaddin ${SOURCES} ${ASSETS} ${ASSETS_${FXSDK_PLATFORM}})
|
||||
target_compile_options(myaddin PRIVATE -Wall -Wextra -Os)
|
||||
target_link_libraries(myaddin Gint::Gint)
|
||||
|
||||
#if("${FXSDK_PLATFORM_LONG}" STREQUAL fx9860G)
|
||||
# generate_g1a(TARGET myaddin OUTPUT "MyAddin.g1a"
|
||||
# NAME "Painful" ICON assets-fx/icon.png)
|
||||
if("${FXSDK_PLATFORM_LONG}" STREQUAL fxCG50)
|
||||
generate_g3a(TARGET myaddin OUTPUT "Painfull.g3a"
|
||||
NAME "Painful" ICONS assets-cg/icon-uns.png assets-cg/icon-sel.png)
|
||||
endif()
|
|
@ -0,0 +1 @@
|
|||
|
Binary file not shown.
After Width: | Height: | Size: 8.2 KiB |
Binary file not shown.
After Width: | Height: | Size: 4.5 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#define TARGET_UPS 60
|
||||
#define TARGET_FPS 30
|
||||
#define TILE_SIZE 16
|
||||
#define LEVEL_WIDTH 16
|
||||
#define LEVEL_HEIGHT 16
|
||||
#define LEVEL_SIZE (LEVEL_WIDTH * LEVEL_HEIGHT)
|
|
@ -0,0 +1,35 @@
|
|||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define KEYS_COUNT 6
|
||||
enum {
|
||||
K_LEFT,
|
||||
K_RIGHT,
|
||||
K_DOWN,
|
||||
K_JUMP,
|
||||
K_RESTART,
|
||||
K_EXIT
|
||||
};
|
||||
|
||||
#define S_PRESSED 0
|
||||
#define S_DOWN 1
|
||||
#define S_RELEASED 2
|
||||
#define S_UP 3
|
||||
|
||||
typedef struct Input {
|
||||
uint8_t keys[KEYS_COUNT];
|
||||
uint8_t states[KEYS_COUNT];
|
||||
} Input;
|
||||
|
||||
/* Check for new key inputs and update accordingly. */
|
||||
void input_update(Input *input);
|
||||
|
||||
/* Initialize values. */
|
||||
void input_init(Input *input);
|
||||
|
||||
/* Get state of keys. */
|
||||
bool input_is_pressed(Input *input, uint8_t key);
|
||||
bool input_is_down(Input *input, uint8_t key);
|
||||
bool input_is_released(Input *input, uint8_t key);
|
||||
bool input_is_up(Input *input, uint8_t key);
|
|
@ -0,0 +1,10 @@
|
|||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include "conf.h"
|
||||
#include "vec2.h"
|
||||
|
||||
typedef uint8_t tile_t;
|
||||
typedef struct Level{
|
||||
tile_t content[LEVEL_WIDTH * LEVEL_HEIGHT];
|
||||
Vec2 start_pos;
|
||||
} Level;
|
|
@ -0,0 +1,16 @@
|
|||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include "vec2.h"
|
||||
|
||||
typedef struct Player{
|
||||
Vec2 pos;
|
||||
Vec2 spd;
|
||||
int8_t facing;
|
||||
bool stun;
|
||||
bool knocked;
|
||||
uint8_t keys_left;
|
||||
uint8_t jump_buffer;
|
||||
uint8_t coyot;
|
||||
} Player;
|
||||
|
||||
Player player_init();
|
|
@ -0,0 +1,13 @@
|
|||
#pragma once
|
||||
|
||||
enum {
|
||||
AIR_TILE,
|
||||
SOLID_TILE,
|
||||
PAIN_TILE,
|
||||
SPAWN_TILE,
|
||||
EXIT_TILE,
|
||||
KEY_TILE,
|
||||
SEMI_SOLID,
|
||||
CHECKY_TILE,
|
||||
};
|
||||
#define OUT_OF_BOUNDS AIR_TILE
|
|
@ -0,0 +1,8 @@
|
|||
#pragma once
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef int16_t vec2_int_t;
|
||||
typedef struct Vec2{
|
||||
vec2_int_t x;
|
||||
vec2_int_t y;
|
||||
} Vec2;
|
|
@ -0,0 +1,109 @@
|
|||
"""
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright © 2021 KikooDX
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the
|
||||
“Software”), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included
|
||||
in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
"""
|
||||
|
||||
def info(*args) -> None:
|
||||
#print("info:", *args)
|
||||
pass
|
||||
|
||||
def merge_bytes(_bytes: bytes) -> int:
|
||||
"""
|
||||
Get a bytes slice and merge them into an integer.
|
||||
"""
|
||||
mul = 256 ** len(_bytes)
|
||||
sum = 0
|
||||
for byte in _bytes:
|
||||
mul //= 256
|
||||
sum += byte * mul
|
||||
return sum
|
||||
|
||||
def kble_parse(_bytes: bytes) -> list:
|
||||
"""
|
||||
Read content of binary file using the KBLE format and output a two
|
||||
dimensional int grid.
|
||||
"""
|
||||
# Read whole file at once.
|
||||
# Check version byte.
|
||||
assert(_bytes[0] == 0)
|
||||
# Get byte length of cells.
|
||||
cell_size: int = _bytes[1]
|
||||
info("Cell size:", cell_size)
|
||||
# Get level dimensions.
|
||||
width = merge_bytes(_bytes[2:4])
|
||||
height = merge_bytes(_bytes[4:6])
|
||||
info("Level width:", width)
|
||||
info("Level height:", height)
|
||||
# Check than the number of bytes matches the obtained informations.
|
||||
assert(len(_bytes) == width * height * cell_size + 6)
|
||||
info("Correct format.")
|
||||
# Process remaining bytes and add them to a list.
|
||||
grid: list = [[0 for _ in range(width)] for _ in range(height)]
|
||||
i: int = 6
|
||||
x: int = 0
|
||||
y: int = 0
|
||||
while (i < len(_bytes)):
|
||||
SLICE = _bytes[i:i + cell_size]
|
||||
grid[y][x] = merge_bytes(SLICE)
|
||||
i += cell_size
|
||||
x += 1
|
||||
if x == width:
|
||||
x = 0
|
||||
y += 1
|
||||
info("Parsing ended successfully.")
|
||||
return grid
|
||||
|
||||
if __name__ == "__main__":
|
||||
LEVELS_PATHS = (
|
||||
"assets/levels/hello_world.kble",
|
||||
"assets/levels/damage_boosting_101.kble",
|
||||
"assets/levels/chaos.kble",
|
||||
"assets/levels/so_far_but_so_close.kble",
|
||||
"assets/levels/key_101.kble",
|
||||
"assets/levels/two_for_one.kble",
|
||||
"assets/levels/up_and_down.kble",
|
||||
"assets/levels/dome.kble",
|
||||
"assets/levels/die_and_retry.kble",
|
||||
"assets/levels/end.kble")
|
||||
with open("src/gen_levels.c", "w") as c_file:
|
||||
c_file.write("#include \"level.h\"\n#include \"vec2.h\"\n")
|
||||
c_file.write("const Level levels[] = {\n")
|
||||
for level_path in LEVELS_PATHS:
|
||||
c_file.write("\t{\n\t\t.content = {")
|
||||
with open(level_path, "rb") as file:
|
||||
BYTES = file.read()
|
||||
data = kble_parse(BYTES)
|
||||
start_x = 0
|
||||
start_y = 0
|
||||
for y, line in enumerate(data):
|
||||
for x, tile in enumerate(line):
|
||||
c_file.write(str(tile))
|
||||
c_file.write(", ")
|
||||
if tile == 3: # spawn tile
|
||||
start_x, start_y = x, y
|
||||
c_file.write("},\n")
|
||||
c_file.write("\t\t.start_pos = (Vec2){")
|
||||
c_file.write(f"{start_x}, {start_y}")
|
||||
c_file.write("}\n\t},\n")
|
||||
c_file.write("};")
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
#include <gint/keyboard.h>
|
||||
#include "input.h"
|
||||
|
||||
void input_update(Input *input) {
|
||||
/* Read full input stream. */
|
||||
clearevents();
|
||||
/* For each key, update state. */
|
||||
for (int i = 0; i < KEYS_COUNT; ++i) {
|
||||
uint8_t *state = &input->states[i];
|
||||
const uint8_t key = input->keys[i];
|
||||
/* See if the key is pressed. */
|
||||
const bool pressed = keydown(key);
|
||||
/* Update input status. */
|
||||
if (pressed) {
|
||||
if (*state == S_RELEASED || *state == S_UP)
|
||||
*state = S_PRESSED;
|
||||
else
|
||||
*state = S_DOWN;
|
||||
}
|
||||
else {
|
||||
if (*state == S_PRESSED || *state == S_DOWN)
|
||||
*state = S_RELEASED;
|
||||
else
|
||||
*state = S_UP;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void input_init(Input *input) {
|
||||
/* initialize all values to S_UP, avoid random bugs */
|
||||
input->keys[K_LEFT] = KEY_LEFT;
|
||||
input->keys[K_RIGHT] = KEY_RIGHT;
|
||||
input->keys[K_DOWN] = KEY_DOWN;
|
||||
input->keys[K_JUMP] = KEY_SHIFT;
|
||||
input->keys[K_RESTART] = KEY_6;
|
||||
input->keys[K_EXIT] = KEY_EXIT;
|
||||
for (int i = 0; i < KEYS_COUNT; ++i)
|
||||
input->states[i] = S_UP;
|
||||
}
|
||||
|
||||
bool input_is_pressed(Input *input, uint8_t key) {
|
||||
return input->states[key] == S_PRESSED;
|
||||
}
|
||||
|
||||
bool input_is_down(Input *input, uint8_t key) {
|
||||
return (input->states[key] == S_DOWN) || (input->states[key] == S_PRESSED);
|
||||
}
|
||||
|
||||
bool input_is_released(Input *input, uint8_t key) {
|
||||
return input->states[key] == S_RELEASED;
|
||||
}
|
||||
|
||||
bool input_is_up(Input *input, uint8_t key) {
|
||||
return (input->states[key] == S_UP) || (input->states[key] == S_RELEASED);
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
#include <gint/display.h>
|
||||
#include <gint/timer.h>
|
||||
#include <gint/clock.h>
|
||||
#include <gint/std/string.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "conf.h"
|
||||
#include "input.h"
|
||||
#include "level.h"
|
||||
#include "player.h"
|
||||
|
||||
void load_level(Level *level, Player *player, uint8_t id) {
|
||||
extern Level levels[LEVEL_SIZE];
|
||||
memcpy(level->content, levels[id].content, LEVEL_SIZE);
|
||||
level->start_pos = levels[id].start_pos;
|
||||
player->pos = levels[id].start_pos;
|
||||
}
|
||||
|
||||
int callback(volatile void *arg) {
|
||||
volatile bool *has_ticked = arg;
|
||||
*has_ticked = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
/* Initialize player. */
|
||||
Player player = player_init();
|
||||
/* Initialize level. */
|
||||
Level level = (Level){};
|
||||
uint8_t level_id = 0;
|
||||
load_level(&level, &player, level_id);
|
||||
/* Initialize input. */
|
||||
Input input = (Input){};
|
||||
input_init(&input);
|
||||
|
||||
/* UPS control. */
|
||||
volatile bool has_ticked = true;
|
||||
int timer = timer_setup(TIMER_ANY, 1000000/TARGET_UPS, callback, &has_ticked);
|
||||
timer_start(timer);
|
||||
|
||||
/* Core loop. */
|
||||
while (!input_is_down(&input, K_EXIT)) {
|
||||
/* Repeat step event so the UPS is constant. */
|
||||
for (uint8_t i = 0; i < TARGET_UPS / TARGET_FPS; i += 1) {
|
||||
/* UPS control. */
|
||||
while (!has_ticked) sleep();
|
||||
has_ticked = false;
|
||||
/* Update. */
|
||||
input_update(&input);
|
||||
/* player_update(&player, &level, &level_id); */
|
||||
}
|
||||
/* Draw. */
|
||||
dclear(C_BLACK);
|
||||
/* player_draw(player); */
|
||||
dupdate();
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
#include "player.h"
|
||||
#include "vec2.h"
|
||||
|
||||
Player player_init() {
|
||||
return (Player){
|
||||
.pos = (Vec2){},
|
||||
.spd = (Vec2){},
|
||||
.facing = 1,
|
||||
.stun = false,
|
||||
.knocked = false,
|
||||
.keys_left = 0,
|
||||
.jump_buffer = 0,
|
||||
.coyot = 0,
|
||||
};
|
||||
}
|
Loading…
Reference in New Issue