Skip to content

Commit

Permalink
lib: add image flipping
Browse files Browse the repository at this point in the history
lib: fix Doom tempo
  • Loading branch information
and3rson committed Mar 4, 2024
1 parent e627694 commit 9f287a1
Show file tree
Hide file tree
Showing 6 changed files with 158 additions and 21 deletions.
75 changes: 56 additions & 19 deletions firmware/main/sdcard/runner/runner.lua
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,47 @@ BLACK = display.color565(0, 0, 0)

ROOT = 'runner/'

PlayerState = {
STAND = "stand",
RUN = "run",
JUMP = "jump",
STAND_SPRITE = resources.load_image(ROOT .. "boy_stand.bmp", BLACK)
RUN_SPRITES = {
resources.load_image(ROOT .. "boy_run_1.bmp", BLACK),
resources.load_image(ROOT .. "boy_run_2.bmp", BLACK),
resources.load_image(ROOT .. "boy_run_3.bmp", BLACK),
}
JUMP_SPRITE = resources.load_image(ROOT .. "boy_jump.bmp", BLACK)

Player = {
x = 32,
y = 128,
width = 32, -- Розмір спрайту - 32x32
height = 32,
sprites = {
stand = { resources.load_image(ROOT .. "boy_stand.bmp") },
run = {
resources.load_image(ROOT .. "boy_run_1.bmp", BLACK),
resources.load_image(ROOT .. "boy_run_2.bmp", BLACK),
resources.load_image(ROOT .. "boy_run_3.bmp", BLACK),
left = {
stand = resources.flip_image_x(STAND_SPRITE),
run = {
resources.flip_image_x(RUN_SPRITES[1]),
resources.flip_image_x(RUN_SPRITES[2]),
resources.flip_image_x(RUN_SPRITES[3]),
resources.flip_image_x(RUN_SPRITES[2]),
},
jump = resources.flip_image_x(JUMP_SPRITE),
},
right = {
stand = STAND_SPRITE,
run = {
RUN_SPRITES[1],
RUN_SPRITES[2],
RUN_SPRITES[3],
RUN_SPRITES[2],
},
jump = JUMP_SPRITE,
},
jump = { resources.load_image(ROOT .. "boy_jump.bmp", BLACK) },
},
state = PlayerState.RUN,
speed_x = 0,
speed_y = 0,
look_direction = 1,

is_airborne = true,
gravity = 200,
}

function Player:new(o)
Expand All @@ -36,18 +56,30 @@ function Player:new(o)
end

function Player:update(delta)
self.x = self.x + 50 * delta
-- self.x = self.x + 50 * delta
self.speed_y = self.speed_y + self.gravity * delta

self.x = self.x + self.speed_x * delta
self.y = self.y + self.speed_y * delta

-- TODO: Calculcate look direction based on speed_x and/or inputs
end

function Player:draw()
local image
if self.state == PlayerState.STAND then
image = self.sprites.stand[1]
elseif self.state == PlayerState.RUN then
-- Перемикаємо спрайти бігу кожні 0.25 секунди
image = self.sprites.run[math.floor(util.time() * 4) % #self.sprites.run + 1]
elseif self.state == PlayerState.JUMP then
image = self.sprites.jump[1]
local sprites
if self.look_direction == 1 then
sprites = self.sprites.right
else
sprites = self.sprites.left
end

if self.is_airborne then
image = sprites.jump
elseif math.abs(self.speed_x) < 1 then
image = sprites.stand[1]
else
image = sprites.run[math.floor(util.time() * 15) % #sprites.run + 1]
end
-- Малюємо гравця на екрані так, щоб середина нижнього краю спрайту була в координатах (x, y)
display.draw_image(image, self.x - self.width / 2, self.y - self.height)
Expand All @@ -60,8 +92,13 @@ display.render()

function lilka.update(delta)
player:update(delta)
local state = controller.get_state()
if state.start.pressed then
util.exit()
end
end

function lilka.draw()
display.fill_screen(BLACK)
player:draw()
end
10 changes: 10 additions & 0 deletions sdk/addons/lualilka/library/resources.lua
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,16 @@ function resources.load_image(filename, transparent_color) end
---@param blank_color integer колір для пікселів, які залишаться незаповненими
function resources.rotate_image(image, angle, blank_color) end

---Відображає зображення горизонтально. Зручно використовувати для платформерів, де герой може рухатись вліво та вправо.
---
---@param image table ідентифікатор зображення
function resources.flip_image_x(image) end

---Відображає зображення вертикально.
---
---@param image table ідентифікатор зображення
function resources.flip_image_y(image) end

---Читає вміст файлу і повертає його як текст.
---@param filename string шлях до файлу (відносно місця знаходження скрипта, що виконується)
---@return string
Expand Down
2 changes: 1 addition & 1 deletion sdk/lib/lilka/src/lilka/buzzer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ void Buzzer::playDoom() {
{NOTE_F3, -16}, {NOTE_D3, -16}, {NOTE_E2, 8}, {NOTE_E2, 8}, {NOTE_E3, 8}, {NOTE_E2, 8}, {NOTE_E2, 8}, {NOTE_D3, 8}, {NOTE_E2, 8}, {NOTE_E2, 8}, {NOTE_C3, 8}, {NOTE_E2, 8}, {NOTE_E2, 8}, {NOTE_AS2, 8}, {NOTE_E2, 8}, {NOTE_E2, 8}, {NOTE_B2, 8}, {NOTE_C3, 8}, {NOTE_E2, 8}, {NOTE_E2, 8}, {NOTE_E3, 8}, {NOTE_E2, 8}, {NOTE_E2, 8}, {NOTE_D3, 8}, {NOTE_E2, 8}, {NOTE_E2, 8}, {NOTE_C3, 8}, {NOTE_E2, 8}, {NOTE_E2, 8}, {NOTE_AS2, -2}, {NOTE_E2, 8}, {NOTE_E2, 8}, {NOTE_E3, 8}, {NOTE_E2, 8}, {NOTE_E2, 8}, {NOTE_D3, 8}, {NOTE_E2, 8}, {NOTE_E2, 8}, {NOTE_C3, 8}, {NOTE_E2, 8}, {NOTE_E2, 8}, {NOTE_AS2, 8}, {NOTE_E2, 8}, {NOTE_E2, 8}, {NOTE_B2, 8}, {NOTE_C3, 8}, {NOTE_E2, 8}, {NOTE_E2, 8}, {NOTE_E3, 8}, {NOTE_E2, 8}, {NOTE_E2, 8}, {NOTE_D3, 8}, {NOTE_E2, 8}, {NOTE_E2, 8}, {NOTE_C3, 8}, {NOTE_E2, 8}, {NOTE_E2, 8}, {NOTE_AS2, -2}, {NOTE_E2, 8}, {NOTE_E2, 8}, {NOTE_E3, 8}, {NOTE_E2, 8},
{NOTE_E2, 8}, {NOTE_D3, 8}, {NOTE_E2, 8}, {NOTE_E2, 8}, {NOTE_C3, 8}, {NOTE_E2, 8}, {NOTE_E2, 8}, {NOTE_AS2, 8}, {NOTE_E2, 8}, {NOTE_E2, 8}, {NOTE_B2, 8}, {NOTE_C3, 8}, {NOTE_E2, 8}, {NOTE_E2, 8}, {NOTE_E3, 8}, {NOTE_E2, 8}, {NOTE_E2, 8}, {NOTE_D3, 8}, {NOTE_E2, 8}, {NOTE_E2, 8}, {NOTE_C3, 8}, {NOTE_E2, 8}, {NOTE_E2, 8}, {NOTE_AS2, -2}, {NOTE_E2, 8}, {NOTE_E2, 8}, {NOTE_E3, 8}, {NOTE_E2, 8}, {NOTE_E2, 8}, {NOTE_D3, 8}, {NOTE_E2, 8}, {NOTE_E2, 8}, {NOTE_C3, 8}, {NOTE_E2, 8}, {NOTE_E2, 8}, {NOTE_AS2, 8}, {NOTE_E2, 8}, {NOTE_E2, 8}, {NOTE_B2, 8}, {NOTE_C3, 8}, {NOTE_E2, 8}, {NOTE_E2, 8}, {NOTE_E3, 8}, {NOTE_E2, 8}, {NOTE_E2, 8}, {NOTE_D3, 8}, {NOTE_E2, 8}, {NOTE_E2, 8}, {NOTE_B3, -16}, {NOTE_G3, -16}, {NOTE_E3, -16}, {NOTE_B2, -16}, {NOTE_E3, -16}, {NOTE_G3, -16}, {NOTE_C4, -16}, {NOTE_B3, -16}, {NOTE_G3, -16}, {NOTE_B3, -16}, {NOTE_G3, -16}, {NOTE_E3, -16},
};
playMelody(doom_e1m1, sizeof(doom_e1m1) / sizeof(doom_e1m1[0]), 160);
playMelody(doom_e1m1, sizeof(doom_e1m1) / sizeof(doom_e1m1[0]), 60); // TODO - Should be 160... But note durations seem to be off
}

Buzzer buzzer;
Expand Down
16 changes: 16 additions & 0 deletions sdk/lib/lilka/src/lilka/display.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,22 @@ void Image::rotate(int16_t angle, Image *dest, int32_t blankColor) {
}
}

void Image::flipX(Image *dest) {
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
dest->pixels[x + y * width] = pixels[(width - 1 - x) + y * width];
}
}
}

void Image::flipY(Image *dest) {
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
dest->pixels[x + y * width] = pixels[x + (height - 1 - y) * width];
}
}
}

Display display;

} // namespace lilka
6 changes: 5 additions & 1 deletion sdk/lib/lilka/src/lilka/display.h
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ class Image {
public:
Image(uint32_t width, uint32_t height, int32_t transparentColor = -1);
~Image();
/// Повертає зображення, яке отримане обертанням поточного зображення на заданий кут (в градусах), і записує його в `dest`.
/// Обернути зображення на заданий кут (в градусах) і записати результат в `dest`.
///
/// @param angle Кут обертання в градусах.
/// @param dest Вказівник на Image, в яке буде записано обернуте зображення.
Expand All @@ -307,6 +307,10 @@ class Image {
/// delete rotatedImage;
/// @endcode
void rotate(int16_t angle, Image *dest, int32_t blankColor);
/// Віддзеркалити зображення по горизонталі і записати результат в `dest`.
void flipX(Image *dest);
/// Віддзеркалити зображення по вертикалі і записати результат в `dest`.
void flipY(Image *dest);
uint32_t width;
uint32_t height;
/// 16-бітний колір (5-6-5), який буде прозорим. За замовчуванням -1 (прозорість відсутня).
Expand Down
70 changes: 70 additions & 0 deletions sdk/lib/lilka/src/lua/lualilka_resources.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,74 @@ int lualilka_resources_rotateImage(lua_State* L) {
return 1;
}

int lualilka_resources_flipImageX(lua_State* L) {
// Arg is image table
// First argument is table that contains image width, height and pointer. We need all of them.
lua_getfield(L, 1, "pointer");
// Check if value is a valid pointer
if (!lua_islightuserdata(L, -1)) {
return luaL_error(L, "Невірне зображення");
}
Image* image = (Image*)lua_touserdata(L, -1);
lua_pop(L, 1);

// Instantiate a new image
lilka::Image* flippedImage = new lilka::Image(image->width, image->height, image->transparentColor);
// Rotate the image
image->flipX(flippedImage);

// Append rotatedImage to images table in registry
lua_getfield(L, LUA_REGISTRYINDEX, "images");
lua_pushlightuserdata(L, flippedImage);
lua_setfield(L, -2, (String("xFlippedImage-") + random(100000)).c_str());
lua_pop(L, 1);

// Create and return table that contains image width, height and pointer
lua_newtable(L);
lua_pushinteger(L, flippedImage->width);
lua_setfield(L, -2, "width");
lua_pushinteger(L, flippedImage->height);
lua_setfield(L, -2, "height");
lua_pushlightuserdata(L, flippedImage);
lua_setfield(L, -2, "pointer");

return 1;
}

int lualilka_resources_flipImageY(lua_State* L) {
// Arg is image table
// First argument is table that contains image width, height and pointer. We need all of them.
lua_getfield(L, 1, "pointer");
// Check if value is a valid pointer
if (!lua_islightuserdata(L, -1)) {
return luaL_error(L, "Невірне зображення");
}
Image* image = (Image*)lua_touserdata(L, -1);
lua_pop(L, 1);

// Instantiate a new image
lilka::Image* flippedImage = new lilka::Image(image->width, image->height, image->transparentColor);
// Rotate the image
image->flipY(flippedImage);

// Append rotatedImage to images table in registry
lua_getfield(L, LUA_REGISTRYINDEX, "images");
lua_pushlightuserdata(L, flippedImage);
lua_setfield(L, -2, (String("yFlippedImage-") + random(100000)).c_str());
lua_pop(L, 1);

// Create and return table that contains image width, height and pointer
lua_newtable(L);
lua_pushinteger(L, flippedImage->width);
lua_setfield(L, -2, "width");
lua_pushinteger(L, flippedImage->height);
lua_setfield(L, -2, "height");
lua_pushlightuserdata(L, flippedImage);
lua_setfield(L, -2, "pointer");

return 1;
}

int lualilka_resources_readFile(lua_State* L) {
const char* path = luaL_checkstring(L, 1);
// Get dir from registry
Expand Down Expand Up @@ -120,6 +188,8 @@ int lualilka_resources_writeFile(lua_State* L) {
static const luaL_Reg lualilka_resources[] = {
{"load_image", lualilka_resources_loadImage},
{"rotate_image", lualilka_resources_rotateImage},
{"flip_image_x", lualilka_resources_flipImageX},
{"flip_image_y", lualilka_resources_flipImageY},
{"read_file", lualilka_resources_readFile},
{"write_file", lualilka_resources_writeFile},
{NULL, NULL},
Expand Down

0 comments on commit 9f287a1

Please sign in to comment.