Mercurial > molko
diff examples/example-states/state-play.c @ 645:83781cc87fca
core: rework game stack state mechanism
The current model was fundamentally broken as the state could continue its
execution when calling mlk_game_pop from itself (e.g. in update).
The current model uses a sjlj mechanism with mlk_game_push/pop being disallowed
in special state function like end, finish, suspend.
author | David Demelier <markand@malikania.fr> |
---|---|
date | Sun, 04 Feb 2024 15:24:00 +0100 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/example-states/state-play.c Sun Feb 04 15:24:00 2024 +0100 @@ -0,0 +1,179 @@ +/* + * state-play.c -- very funny game + * + * Copyright (c) 2020-2023 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <mlk/core/alloc.h> +#include <mlk/core/event.h> +#include <mlk/core/game.h> +#include <mlk/core/image.h> +#include <mlk/core/painter.h> +#include <mlk/core/panic.h> +#include <mlk/core/state.h> +#include <mlk/core/texture.h> +#include <mlk/core/util.h> + +#include <mlk/ui/align.h> +#include <mlk/ui/button.h> + +#include <assets/images/dvd.h> + +#include "state-menu.h" +#include "state-play.h" + +#define BG 0x99c2dbff +#define BUTTON_H (mlk_window.h / 20) +#define BUTTON_W (mlk_window.w / 10) +#define LOGO assets_images_dvd +#define LOGO_SPEED 100 + +#define PLAY(self) MLK_CONTAINER_OF(self, struct play, state) + +struct play { + struct mlk_button button_leave; + struct mlk_texture logo; + int x; + int y; + int dx; + int dy; + struct mlk_state state; +}; + +static void +state_play__start(struct mlk_state *self) +{ + struct play *play = PLAY(self); + + if (mlk_image_openmem(&play->logo, LOGO, sizeof (LOGO)) < 0) + mlk_panic(); + + mlk_align(MLK_ALIGN_CENTER, + &play->x, + &play->y, + play->logo.w, + play->logo.h, + 0, + 0, + mlk_window.w, + mlk_window.h + ); + + play->button_leave.text = "menu"; + play->button_leave.w = BUTTON_W; + play->button_leave.h = BUTTON_H; + + mlk_align(MLK_ALIGN_BOTTOM, + &play->button_leave.x, + &play->button_leave.y, + play->button_leave.w, + play->button_leave.h, + 0, + 0, + mlk_window.w, + mlk_window.h - 20 + ); + + play->dx = play->dy = 1; +} + +static void +state_play__handle(struct mlk_state *self, const union mlk_event *event) +{ + struct play *play = PLAY(self); + + if (mlk_button_handle(&play->button_leave, event)) + mlk_game_pop(); + + switch (event->type) { + case MLK_EVENT_QUIT: + mlk_game_quit(); + break; + case MLK_EVENT_KEYUP: + switch (event->key.key) { + case MLK_KEY_ESCAPE: + mlk_game_pop(); + break; + default: + break; + } + break; + default: + break; + } +} + +static void +state_play__update(struct mlk_state *self, unsigned int ticks) +{ + struct play *play = PLAY(self); + + play->x += play->dx * (LOGO_SPEED * ticks / 1000); + play->y += play->dy * (LOGO_SPEED * ticks / 1000); + + if (play->x < 0) { + play->dx = 1; + play->x = 0; + } else if (play->x + play->logo.w >= mlk_window.w) { + play->dx = -1; + play->x = mlk_window.w - play->logo.w; + } + + if (play->y < 0) { + play->dy = 1; + play->y = 0; + } else if (play->y + play->logo.h >= mlk_window.h) { + play->dy = -1; + play->y = mlk_window.h - play->logo.h; + } + + mlk_button_update(&play->button_leave, ticks); +} + +static void +state_play__draw(struct mlk_state *self) +{ + struct play *play = PLAY(self); + + mlk_painter_set_color(BG); + mlk_painter_clear(); + mlk_texture_draw(&play->logo, play->x, play->y); + mlk_button_draw(&play->button_leave); + mlk_painter_present(); +} + +static void +state_play__finish(struct mlk_state *self) +{ + struct play *play = PLAY(self); + + mlk_texture_finish(&play->logo); +} + +struct mlk_state * +state_play_new(void) +{ + struct play *play; + + play = mlk_alloc_new0(1, sizeof (*play)); + play->state.name = "play"; + play->state.start = state_play__start; + play->state.handle = state_play__handle; + play->state.update = state_play__update; + play->state.draw = state_play__draw; + play->state.finish = state_play__finish; + + return &play->state; +}