[jasper/world] Get animations working
All checks were successful
Build / build (push) Successful in 3m43s

This commit is contained in:
2025-01-12 22:50:44 -06:00
parent 21f7ce7885
commit fd5a82689c
7 changed files with 62 additions and 33 deletions

View File

@ -14,13 +14,16 @@ namespace ncore = nostalgia::core;
class World { class World {
private: private:
struct ObjState {
uint16_t objIdx{};
uint16_t frame{};
turbine::TimeMs nextUpdateTime{};
};
ncore::Context &m_nctx; ncore::Context &m_nctx;
WorldStatic const&m_worldStatic; WorldStatic const&m_worldStatic;
ox::Vector<keel::AssetRef<ncore::CompactTileSheet>, 32> m_tilesheets; ox::Vector<keel::AssetRef<ncore::CompactTileSheet>, 32> m_tilesheets;
#ifndef OX_OS_BareMetal ox::Vector<ObjState, 128> m_objStates;
//turbine::TimeMs m_prevUpdateTime{}; turbine::TimeMs m_currentTicks{};
turbine::TimeMs m_nextUpdateTime{};
#endif
public: public:
explicit World(ncore::Context &nctx, WorldStatic const&worldStatic) noexcept; explicit World(ncore::Context &nctx, WorldStatic const&worldStatic) noexcept;
@ -29,16 +32,14 @@ class World {
ox::Result<int> update() noexcept; ox::Result<int> update() noexcept;
#ifndef OX_OS_BareMetal
ox::Result<int> editorModeUpdate() noexcept;
#endif
void setupTiles() noexcept; void setupTiles() noexcept;
void setupTile(uint32_t lyr, uint32_t x, uint32_t y) const noexcept; void setupTile(uint32_t lyr, uint32_t x, uint32_t y) noexcept;
private: private:
void setupLayer(uint_t lyr, uint_t cbb) const noexcept; turbine::TimeMs updateObj(ObjState &state) noexcept;
void setupLayer(uint_t lyr, uint_t cbb) noexcept;
}; };

View File

@ -91,6 +91,7 @@ struct ObjTileRefSet {
uint8_t tileCnt{}; uint8_t tileCnt{};
// each successive frame will use tileIdx[i] + tileCnt * frameNo for the tileIdx // each successive frame will use tileIdx[i] + tileCnt * frameNo for the tileIdx
uint8_t frames{}; uint8_t frames{};
uint16_t intervalMs{};
}; };
OX_MODEL_BEGIN(ObjTileRefSet) OX_MODEL_BEGIN(ObjTileRefSet)
@ -101,6 +102,7 @@ OX_MODEL_BEGIN(ObjTileRefSet)
OX_MODEL_FIELD(tilesheetId) OX_MODEL_FIELD(tilesheetId)
OX_MODEL_FIELD(tileCnt) OX_MODEL_FIELD(tileCnt)
OX_MODEL_FIELD(frames) OX_MODEL_FIELD(frames)
OX_MODEL_FIELD(intervalMs)
OX_MODEL_END() OX_MODEL_END()
[[nodiscard]] [[nodiscard]]

View File

@ -17,7 +17,7 @@ WorldEditorView::WorldEditorView(studio::StudioContext &sctx, WorldStatic const&
ox::Error WorldEditorView::setupTile( ox::Error WorldEditorView::setupTile(
uint32_t const lyr, uint32_t const lyr,
uint32_t const x, uint32_t const x,
uint32_t const y) const noexcept { uint32_t const y) noexcept {
m_world.setupTile(lyr, x, y); m_world.setupTile(lyr, x, y);
return {}; return {};
} }
@ -46,7 +46,7 @@ void WorldEditorView::draw(ox::Size const&targetSz) noexcept {
} }
glutils::FrameBufferBind const frameBufferBind(m_frameBuffer); glutils::FrameBufferBind const frameBufferBind(m_frameBuffer);
if (m_animateWorld) { if (m_animateWorld) {
auto const wakeUp = m_world.editorModeUpdate(); auto const wakeUp = m_world.update();
if (wakeUp.ok()) { if (wakeUp.ok()) {
turbine::setRefreshWithin(m_sctx.tctx, wakeUp.value); turbine::setRefreshWithin(m_sctx.tctx, wakeUp.value);
} }

View File

@ -37,7 +37,7 @@ class WorldEditorView: public ox::SignalHandler {
public: public:
WorldEditorView(studio::StudioContext &ctx, WorldStatic const&worldStatic); WorldEditorView(studio::StudioContext &ctx, WorldStatic const&worldStatic);
ox::Error setupTile(uint32_t lyr, uint32_t x, uint32_t y) const noexcept; ox::Error setupTile(uint32_t lyr, uint32_t x, uint32_t y) noexcept;
void setupTiles() noexcept; void setupTiles() noexcept;

View File

@ -10,6 +10,11 @@
namespace jasper::world { namespace jasper::world {
[[nodiscard]]
static bool isUpdatingObj(ObjTileRefSet const&obj) noexcept {
return obj.frames > 1;
}
World::World(ncore::Context &nctx, WorldStatic const&worldStatic) noexcept: World::World(ncore::Context &nctx, WorldStatic const&worldStatic) noexcept:
m_nctx(nctx), m_nctx(nctx),
m_worldStatic(worldStatic) {} m_worldStatic(worldStatic) {}
@ -46,7 +51,17 @@ ox::Error World::setupDisplay() noexcept {
return {}; return {};
} }
ox::Result<int> World::update() noexcept {
turbine::TimeMs nextUpdateTime = ox::MaxValue<turbine::TimeMs>;
m_currentTicks = ticksMs(turbineCtx(m_nctx));
for (auto &state : m_objStates) {
nextUpdateTime = ox::min(nextUpdateTime, updateObj(state));
}
return static_cast<int>(nextUpdateTime - m_currentTicks);
}
void World::setupTiles() noexcept { void World::setupTiles() noexcept {
m_currentTicks = ticksMs(turbineCtx(m_nctx));
ncore::setBgStatus(m_nctx, 0); // disable all backgrounds ncore::setBgStatus(m_nctx, 0); // disable all backgrounds
for (auto layerNo = 0u; auto const&layer : m_worldStatic.map) { for (auto layerNo = 0u; auto const&layer : m_worldStatic.map) {
setupLayer(layerNo, layer.cbb); setupLayer(layerNo, layer.cbb);
@ -57,7 +72,7 @@ void World::setupTiles() noexcept {
void World::setupTile( void World::setupTile(
uint32_t const lyr, uint32_t const lyr,
uint32_t const x, uint32_t const x,
uint32_t const y) const noexcept { uint32_t const y) noexcept {
auto &t = tile(m_worldStatic, lyr, x, y); auto &t = tile(m_worldStatic, lyr, x, y);
auto const tx = static_cast<int>(x) * 2; auto const tx = static_cast<int>(x) * 2;
auto const ty = static_cast<int>(y) * 2; auto const ty = static_cast<int>(y) * 2;
@ -78,11 +93,37 @@ void World::setupTile(
.tileIdx = static_cast<uint_t>(obj.cbbIdx + 3), .tileIdx = static_cast<uint_t>(obj.cbbIdx + 3),
.palBank = obj.palBank, .palBank = obj.palBank,
}); });
if (isUpdatingObj(obj)) {
m_objStates.emplace_back(ObjState{
.objIdx = t.objIdxRefSet,
.frame = 0,
.nextUpdateTime = m_currentTicks + obj.intervalMs,
});
}
}
turbine::TimeMs World::updateObj(ObjState &state) noexcept {
if (state.nextUpdateTime <= m_currentTicks) {
auto &obj = m_worldStatic.objTileRefSets[state.objIdx];
++state.frame;
if (state.frame >= obj.frames) {
state.frame = 0;
}
std::ignore = ncore::loadBgTileSheet(
m_nctx,
obj.cbb,
*m_tilesheets[obj.tilesheetId],
obj.cbbIdx,
static_cast<size_t>(obj.tilesheetIdx + state.frame * static_cast<uint16_t>(obj.tileCnt)),
obj.tileCnt);
state.nextUpdateTime = m_currentTicks + obj.intervalMs;
}
return state.nextUpdateTime;
} }
void World::setupLayer( void World::setupLayer(
uint_t const lyr, uint_t const lyr,
uint_t const cbb) const noexcept { uint_t const cbb) noexcept {
ncore::clearBg(m_nctx, lyr); ncore::clearBg(m_nctx, lyr);
ncore::setBgStatus(m_nctx, lyr, true); ncore::setBgStatus(m_nctx, lyr, true);
ncore::setBgCbb(m_nctx, lyr, cbb); ncore::setBgCbb(m_nctx, lyr, cbb);
@ -95,20 +136,4 @@ void World::setupLayer(
} }
} }
ox::Result<int> World::update() noexcept {
int expiresIn = 60'000;
return expiresIn;
}
#ifndef OX_OS_BareMetal
ox::Result<int> World::editorModeUpdate() noexcept {
auto const time = ticksMs(turbineCtx(m_nctx));
if (time >= m_nextUpdateTime) {
turbine::TimeMs expiresIn = 60'000;
m_nextUpdateTime = time + expiresIn;
}
return static_cast<int>(m_nextUpdateTime - time);
}
#endif
} }

View File

@ -167,6 +167,7 @@ ox::Result<uint8_t> WorldStaticLoader::setupTileResrc(DocObjRef const&docObjRef)
.tilesheetId = tsIdx, .tilesheetId = tsIdx,
.tileCnt = subsheetTileCnt(*subsheet), .tileCnt = subsheetTileCnt(*subsheet),
.frames = obj->frames, .frames = obj->frames,
.intervalMs = obj->intervalMs,
}); });
m_cbbIt += refSet.tileCnt; m_cbbIt += refSet.tileCnt;
m_resourcesChanged = true; m_resourcesChanged = true;

View File

@ -43,11 +43,11 @@ ox::Error run(
} }
setUpdateHandler(*tctx, [](turbine::Context &tctx) -> int { setUpdateHandler(*tctx, [](turbine::Context &tctx) -> int {
auto &world = *applicationData<world::World>(tctx); auto &world = *applicationData<world::World>(tctx);
auto [sleepTime, err] = world.update(); auto const [sleepTime, err] = world.update();
if (err) { if (err) {
oxLogError(err); oxLogError(err);
} }
return 0; return sleepTime;
}); });
OX_RETURN_ERROR(turbine::run(*tctx)); OX_RETURN_ERROR(turbine::run(*tctx));
oxOut("Exiting...\n"); oxOut("Exiting...\n");