[jasper/world] Get animations working
All checks were successful
Build / build (push) Successful in 3m43s
All checks were successful
Build / build (push) Successful in 3m43s
This commit is contained in:
@ -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;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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]]
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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");
|
||||||
|
Reference in New Issue
Block a user