diff options
author | Vito Caputo <vcaputo@pengaru.com> | 2022-11-10 09:59:51 -0800 |
---|---|---|
committer | Vito Caputo <vcaputo@pengaru.com> | 2022-11-10 10:03:03 -0800 |
commit | 6bd2dbf11f908abb225fb160c568462e95da2da7 (patch) | |
tree | 04013a01b8f888b77baa972339253b93fde6b888 /src | |
parent | aa20a9ec8697a05d44e949ad6a1f2b2f6a3fe908 (diff) |
bonus-node: add bonus node for bonus quantities
This shows a numeric display with an API for tracking a position
until released. Once released the node self-animates and frees
itself from its own rendering function. Post-release the node
stops accessing the tracking position, intended for allowing the
associated entity to become reused or discarded immediately upon
release. For this to work smoothly the release must be accompanied
by a storing of the last position within the bonus node via the
provided pointer, which the bonus node's render function then uses
as the origin of its self-animating before destruction.
See comment at start of bonus-node.c for more information/issues.
This only adds the node without integrating into the game, a
subsequent commit will integrate into game.c. Initial impetus
for adding this is making teepee quantities visible.
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/bonus-node.c | 180 | ||||
-rw-r--r-- | src/bonus-node.h | 29 |
3 files changed, 211 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 5f55d86..32bfdb0 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -12,6 +12,8 @@ sars_SOURCES = \ baby-node.h \ bb2f.h \ bb3f.h \ + bonus-node.c \ + bonus-node.h \ clear-node.c \ clear-node.h \ cp437.h \ diff --git a/src/bonus-node.c b/src/bonus-node.c new file mode 100644 index 0000000..7eb2c9e --- /dev/null +++ b/src/bonus-node.c @@ -0,0 +1,180 @@ +/* + * Copyright (C) 2022 - Vito Caputo - <vcaputo@pengaru.com> + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +/* Bonus nodes are for showing bonus quantities numerically which move along + * with an entity, and when taken get released from the entity's position and + * float away on their own. + * + * The current way this works is by providing a release counter pointer for + * triggering the release, along with a release position pointer for storing + * the last position when released. So the entity needs some members for saving + * these locations which point at members within the bonus_node_t. + * + * The release gets realised at render time by checking if the release counter + * is non-zero. Upon release, the render func takes over management of the + * position and life-cycle of the node by returning STAGE_RENDER_FUNC_RET_FREE + * when done. + * + * One particularly crufty aspect is the digit nodes are hung off a nested + * stage within the bonus_node_t that's being explicitly rendered and freed, + * rather than existing as direct descendants of the game stage. This results + * in some redundant stage_dirty()/stage_render()/stage_free() rigamarole here, + * and is only being done because I want to vary the alpha in the render func + * for fading the digits out as they decay - and the incoming stage_t on the + * render func is a const so we can't set the alpha directly on the outer bonus + * node before letting render naturally descend down to the children layers with + * the adjusted alpha. + * + * It's no big deal for now, but it illustrates some of the unnecessary + * friction remaining in the libstage API. I'm not convinced constifying these + * things is bringing enough value to justify these kinds of annoyances. FIXME + * + * Another crufty point is for now I threw the release decay duration in + * bonus-node.h so that the caller can accesss it when storing at the release + * pointer, while making it available here for compile-time evaluation of (1.f + * / BONUS_NODE_RELEASE_MS). Also the counter isn't really applied in + * normalized time, but is just a frame counter right now - the name lies. + * TODO FIXME + * + * I'm not too concerned about these things since SARS is such a + * silly thing, but it's a useful exercise to see how (un)usable these + * libraries are. + */ + +#include <assert.h> +#include <stddef.h> +#include <stdlib.h> +#include <stage.h> + +#include "bonus-node.h" +#include "digit-node.h" +#include "m4f.h" +#include "m4f-3dx.h" +#include "v2f.h" + +typedef struct bonus_node_t { + stage_t *stage; + v2f_t *position; + float scale; + unsigned release; + v2f_t release_position; + unsigned n_digits; + m4f_t digits_x[]; +} bonus_node_t; + +static stage_render_func_ret_t bonus_node_render(const stage_t *stage, void *object, float alpha, void *render_ctxt) +{ + bonus_node_t *bonus_node = object; + v3f_t scale; + + assert(stage); + assert(bonus_node); + + scale.x = scale.y = scale.z = bonus_node->scale; + + if (bonus_node->release) { + float t = 1.f - (1.f / BONUS_NODE_RELEASE_MS * (float)bonus_node->release); + + bonus_node->release--; + if (!bonus_node->release) + return STAGE_RENDER_FUNC_RET_FREE; + + for (int i = 0; i < bonus_node->n_digits; i++) { + bonus_node->digits_x[i] = m4f_translate(NULL, &(v3f_t){ + .x = bonus_node->release_position.x + bonus_node->scale*2.f + (float)i * -bonus_node->scale*2.f + (t * sinf((float)bonus_node->release * .1f) * .1f), + .y = bonus_node->release_position.y + bonus_node->scale*2.f + t * .5f, + .z = 0.f + }); + bonus_node->digits_x[i] = m4f_scale(&bonus_node->digits_x[i], &scale); + } + + stage_set_alpha(bonus_node->stage, 1.f - t); + stage_dirty(bonus_node->stage); + stage_render(bonus_node->stage, render_ctxt); + + return STAGE_RENDER_FUNC_RET_CONTINUE; + } + + /* update tranforms for the digits before they render */ + for (int i = 0; i < bonus_node->n_digits; i++) { + bonus_node->digits_x[i] = m4f_translate(NULL, &(v3f_t){ + .x = bonus_node->position->x + bonus_node->scale * 2.f + (float)i * -bonus_node->scale * 2.f, + .y = bonus_node->position->y + bonus_node->scale*2.f, + .z = 0.f + }); + bonus_node->digits_x[i] = m4f_scale(&bonus_node->digits_x[i], &scale); + } + stage_dirty(bonus_node->stage); + stage_render(bonus_node->stage, render_ctxt); + + return STAGE_RENDER_FUNC_RET_CONTINUE; +} + + +static void bonus_node_free(const stage_t *stage, void *object) +{ + bonus_node_t *bonus_node = object; + + assert(stage); + stage_free(bonus_node->stage); + free(bonus_node); +} + + +static const stage_ops_t bonus_node_ops = { + .render_func = bonus_node_render, + .free_func = bonus_node_free, +}; + + +stage_t * bonus_node_new(stage_conf_t *conf, unsigned value, m4f_t *projection_x, v2f_t *position, float scale, unsigned **release, v2f_t **release_position) +{ + unsigned v = value, n_digits = 0, i = 0; + bonus_node_t *bonus_node; + stage_t *s; + + assert(release); + assert(position); + assert(release_position); + assert(projection_x); + + do { + n_digits++; + v /= 10; + } while (v); + + bonus_node = calloc(1, sizeof(bonus_node_t) + n_digits * sizeof(bonus_node->digits_x[0])); + assert(bonus_node); + bonus_node->n_digits = n_digits; + bonus_node->position = position; + bonus_node->scale = scale; + bonus_node->stage = stage_new(&(stage_conf_t){.name = "bonus-container", .active = 1, .alpha = 1.f}, NULL, NULL); /* use a discrete container stage for render_func alpha control */ + *release = &bonus_node->release; + *release_position = &bonus_node->release_position; + + s = stage_new(conf, &bonus_node_ops, bonus_node); + assert(s); + + v = value; + do { + /* TODO: model_x positioning of the digits */ + (void) digit_node_new(&(stage_conf_t){ .parent = bonus_node->stage, .name = "bonus-digit", .active = 1, .alpha = 1.f }, + v % 10, projection_x, &bonus_node->digits_x[i++]); + v /= 10; + } while (v); + + return s; +} diff --git a/src/bonus-node.h b/src/bonus-node.h new file mode 100644 index 0000000..c138589 --- /dev/null +++ b/src/bonus-node.h @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2022 - Vito Caputo - <vcaputo@pengaru.com> + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _BONUS_NODE_H +#define _BONUS_NODE_H + +#define BONUS_NODE_RELEASE_MS 100 /* FIXME: this needs to be actual time units, right now it's frames */ + +typedef struct stage_conf_t stage_conf_t; +typedef struct m4f_t m4f_t; +typedef struct v2f_t v2f_t; + +stage_t * bonus_node_new(stage_conf_t *conf, unsigned value, m4f_t *projection_x, v2f_t *position, float scale, unsigned **release, v2f_t **release_position); + +#endif + |