Add frame tick system for continuous animation
- Added INPUT_FRAME_TICK event type to input_event.h - Added wants_frame_updates() virtual method to Game base class - Implemented frame tick logic in main loop (basic1.cpp and emulator/main.cpp) - Added Lua bindings: game.set_frame_updates(bool) and INPUT.FRAME_TICK - Updated LuaGame to support frame updates via registry flag - Updated ball.lua to use continuous frame updates for smooth animation - Both hardware and emulator now support continuous animation for physics/games
This commit is contained in:
@@ -520,6 +520,14 @@ int main()
|
|||||||
}
|
}
|
||||||
needs_refresh = true;
|
needs_refresh = true;
|
||||||
}
|
}
|
||||||
|
} else if (launcher.is_game_selected()) {
|
||||||
|
// No input, but check if game wants continuous updates
|
||||||
|
current_game = launcher.get_selected_game();
|
||||||
|
if (current_game->wants_frame_updates()) {
|
||||||
|
// Send frame tick event for animation/physics updates
|
||||||
|
InputEvent frame_tick = {INPUT_FRAME_TICK, 0, 0, 0, 0, 0, true};
|
||||||
|
needs_refresh = current_game->update(frame_tick);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4. Redraw and queue async refresh on Core 1
|
// 4. Redraw and queue async refresh on Core 1
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ public:
|
|||||||
virtual bool update(const InputEvent& event) = 0;
|
virtual bool update(const InputEvent& event) = 0;
|
||||||
virtual void draw() = 0;
|
virtual void draw() = 0;
|
||||||
virtual bool wants_to_exit() const { return false; }
|
virtual bool wants_to_exit() const { return false; }
|
||||||
|
virtual bool wants_frame_updates() const { return false; }
|
||||||
|
|
||||||
// Public members for Lua bindings access
|
// Public members for Lua bindings access
|
||||||
uint16_t width;
|
uint16_t width;
|
||||||
|
|||||||
@@ -171,7 +171,17 @@ bool LuaGame::wants_to_exit() const {
|
|||||||
|
|
||||||
return exit;
|
return exit;
|
||||||
}
|
}
|
||||||
|
bool LuaGame::wants_frame_updates() const {
|
||||||
|
if (!L) return false;
|
||||||
|
|
||||||
|
// Check registry for frame updates flag
|
||||||
|
lua_pushstring(L, "__wants_frame_updates");
|
||||||
|
lua_gettable(L, LUA_REGISTRYINDEX);
|
||||||
|
bool wants_updates = lua_toboolean(L, -1);
|
||||||
|
lua_pop(L, 1);
|
||||||
|
|
||||||
|
return wants_updates;
|
||||||
|
}
|
||||||
bool LuaGame::call_lua_function(const char* func_name, int nargs, int nresults) {
|
bool LuaGame::call_lua_function(const char* func_name, int nargs, int nresults) {
|
||||||
int result = lua_pcall(L, nargs, nresults, 0);
|
int result = lua_pcall(L, nargs, nresults, 0);
|
||||||
if (result != LUA_OK) {
|
if (result != LUA_OK) {
|
||||||
|
|||||||
@@ -107,6 +107,17 @@ int main() {
|
|||||||
needs_redraw = true;
|
needs_redraw = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if (launcher.is_game_selected()) {
|
||||||
|
// No user input, but check if game wants frame tick updates
|
||||||
|
current_game = launcher.get_selected_game();
|
||||||
|
if (current_game->wants_frame_updates()) {
|
||||||
|
InputEvent frame_event = {INPUT_FRAME_TICK, 0, 0, 0, 0, 0, true};
|
||||||
|
needs_redraw = current_game->update(frame_event) || needs_redraw;
|
||||||
|
if (current_game->wants_to_exit()) {
|
||||||
|
launcher.reset();
|
||||||
|
needs_redraw = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Always redraw every frame for emulator
|
// Always redraw every frame for emulator
|
||||||
|
|||||||
@@ -186,6 +186,21 @@ static int lua_game_exit(lua_State* L) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// game.set_frame_updates(enabled) - enable/disable continuous frame tick events
|
||||||
|
static int lua_game_set_frame_updates(lua_State* L) {
|
||||||
|
LuaGame* game = get_game(L);
|
||||||
|
if (!game) return 0;
|
||||||
|
|
||||||
|
bool enabled = lua_toboolean(L, 1);
|
||||||
|
|
||||||
|
// Set frame updates flag (will be checked in wants_frame_updates())
|
||||||
|
lua_pushstring(L, "__wants_frame_updates");
|
||||||
|
lua_pushboolean(L, enabled);
|
||||||
|
lua_settable(L, LUA_REGISTRYINDEX);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// INPUT TYPE CONSTANTS
|
// INPUT TYPE CONSTANTS
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
@@ -283,6 +298,10 @@ void lua_bindings_register(lua_State* L, LuaGame* game) {
|
|||||||
lua_pushcfunction(L, lua_game_exit);
|
lua_pushcfunction(L, lua_game_exit);
|
||||||
lua_settable(L, -3);
|
lua_settable(L, -3);
|
||||||
|
|
||||||
|
lua_pushstring(L, "set_frame_updates");
|
||||||
|
lua_pushcfunction(L, lua_game_set_frame_updates);
|
||||||
|
lua_settable(L, -3);
|
||||||
|
|
||||||
// Create empty vars table for persistent state
|
// Create empty vars table for persistent state
|
||||||
lua_pushstring(L, "vars");
|
lua_pushstring(L, "vars");
|
||||||
lua_newtable(L);
|
lua_newtable(L);
|
||||||
|
|||||||
@@ -14,6 +14,9 @@ function init()
|
|||||||
game.vars.radius = 10
|
game.vars.radius = 10
|
||||||
game.vars.frame_count = 0
|
game.vars.frame_count = 0
|
||||||
|
|
||||||
|
-- Enable continuous frame updates for smooth animation
|
||||||
|
game.set_frame_updates(true)
|
||||||
|
|
||||||
print("Bouncing Ball initialized")
|
print("Bouncing Ball initialized")
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -28,8 +31,8 @@ function update(event)
|
|||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Update physics if running
|
-- Update physics if running (on any frame tick)
|
||||||
if game.vars.state == STATE_RUNNING then
|
if event.type == INPUT.FRAME_TICK and game.vars.state == STATE_RUNNING then
|
||||||
-- Move ball
|
-- Move ball
|
||||||
game.vars.ball_x = game.vars.ball_x + game.vars.vel_x
|
game.vars.ball_x = game.vars.ball_x + game.vars.vel_x
|
||||||
game.vars.ball_y = game.vars.ball_y + game.vars.vel_y
|
game.vars.ball_y = game.vars.ball_y + game.vars.vel_y
|
||||||
|
|||||||
@@ -193,6 +193,18 @@ bool LuaGame::wants_to_exit() const {
|
|||||||
return exit;
|
return exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool LuaGame::wants_frame_updates() const {
|
||||||
|
if (!L) return false;
|
||||||
|
|
||||||
|
// Check if Lua script wants continuous frame updates
|
||||||
|
lua_pushstring(L, "__wants_frame_updates");
|
||||||
|
lua_gettable(L, LUA_REGISTRYINDEX);
|
||||||
|
bool wants_updates = lua_toboolean(L, -1);
|
||||||
|
lua_pop(L, 1);
|
||||||
|
|
||||||
|
return wants_updates;
|
||||||
|
}
|
||||||
|
|
||||||
bool LuaGame::call_lua_function(const char* func_name, int nargs, int nresults) {
|
bool LuaGame::call_lua_function(const char* func_name, int nargs, int nresults) {
|
||||||
int result = lua_pcall(L, nargs, nresults, 0);
|
int result = lua_pcall(L, nargs, nresults, 0);
|
||||||
if (result != LUA_OK) {
|
if (result != LUA_OK) {
|
||||||
|
|||||||
@@ -64,6 +64,12 @@ public:
|
|||||||
*/
|
*/
|
||||||
bool wants_to_exit() const override;
|
bool wants_to_exit() const override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Check if game wants continuous frame updates
|
||||||
|
* @return true if Lua script set __wants_frame_updates flag
|
||||||
|
*/
|
||||||
|
bool wants_frame_updates() const override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get Lua state for bindings access
|
* @brief Get Lua state for bindings access
|
||||||
*/
|
*/
|
||||||
|
|||||||
11
lib/game.h
11
lib/game.h
@@ -94,6 +94,17 @@ public:
|
|||||||
*/
|
*/
|
||||||
virtual bool wants_to_exit() const { return false; }
|
virtual bool wants_to_exit() const { return false; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Check if game wants continuous frame updates
|
||||||
|
*
|
||||||
|
* Games that need animation or continuous updates (like physics simulations)
|
||||||
|
* can override this to return true. They will receive INPUT_FRAME_TICK events
|
||||||
|
* every frame, even without user input.
|
||||||
|
*
|
||||||
|
* @return true if game needs frame updates, false for event-driven only
|
||||||
|
*/
|
||||||
|
virtual bool wants_frame_updates() const { return false; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get the type of game for safe downcasting without RTTI
|
* @brief Get the type of game for safe downcasting without RTTI
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -17,7 +17,8 @@ enum InputType {
|
|||||||
INPUT_TOUCH_UP,
|
INPUT_TOUCH_UP,
|
||||||
INPUT_BUTTON_0,
|
INPUT_BUTTON_0,
|
||||||
INPUT_BUTTON_1,
|
INPUT_BUTTON_1,
|
||||||
INPUT_GESTURE
|
INPUT_GESTURE,
|
||||||
|
INPUT_FRAME_TICK // Sent every frame for animation/continuous updates
|
||||||
};
|
};
|
||||||
|
|
||||||
// Unified input event structure
|
// Unified input event structure
|
||||||
|
|||||||
Reference in New Issue
Block a user