static void paintWrapper() { // clear the palette newCubes.clear(); lostCubes.clear(); reconnectedCubes.clear(); dirtyCubes.clear(); // fire events System::paint(); // dynamically load assets just-in-time if (!(newCubes | reconnectedCubes).empty()) { loader.start(config); while(!loader.isComplete()) { for(CubeID cid : (newCubes | reconnectedCubes)) { vbuf[cid].bg0rom.hBargraph( vec(0, 4), loader.cubeProgress(cid, 128), BG0ROMDrawable::ORANGE, 8 ); } // fire events while we wait System::paint(); } loader.finish(); } // repaint cubes for(CubeID cid : dirtyCubes) { activateCube(cid, taskCubes[cid].task); } // also, handle lost cubes, if you so desire :) }
void main() { blicketCubes.mark(blicket1); blicketCubes.mark(blicket2); nonBlicketCubes.mark(nonBlicket1); nonBlicketCubes.mark(nonBlicket2); // Initialize asset configuration and loader config.append(gMainSlot, BootstrapAssets); loader.init(); // Subscribe to events (See pubsub design pattern) Events::cubeConnect.set(onCubeConnect); Events::cubeDisconnect.set(onCubeDisconnect); Events::cubeRefresh.set(onCubeRefresh); Events::neighborAdd.set(onNeighborAdd); Events::neighborRemove.set(onNeighborRemove); // Events::cubeTouch.set(onCubeTouch); Events::cubeTouch.set(onTouch); // Initialize cubes for(CubeID cid : CubeSet::connected()) { vbuf[cid].attach(cid); activateCube(cid); } // Run loop for(;;) { paintWrapper(); } }
static void onCubeDisconnect(void* ctxt, unsigned cid) { // mark as lost and clear from other cube sets lostCubes.mark(cid); newCubes.clear(cid); reconnectedCubes.clear(cid); dirtyCubes.clear(cid); activeCubes.clear(cid); }
static void onNeighborAdd(void* ctxt, unsigned cube0, unsigned side0, unsigned cube1, unsigned side1) { // Update art on active cubes (not loading cubes or base) bool sfx = false; if (isActive(cube0) && cube0 == blicketDetector && blicketCubes.test(cube1)) { sfx |= showSideBar(cube1, Side(side1)); sfx |= showSideBar(cube0, Side(side0)); } if (isActive(cube1) && cube1 == blicketDetector && blicketCubes.test(cube0)) { sfx |= showSideBar(cube0, Side(side0)); sfx |= showSideBar(cube1, Side(side1)); } if (sfx) { playSfx(SfxSong); } }
static bool showSideBar(CubeID cid, CubeID nb, Side s) { // if cid is not showing a bar on side s, show it int stat1 = taskCubes[cid].status; int stat2 = taskCubes[nb].status; //To-Do: add logic for different colored bars based on the statuses of the cubes. ASSERT(activeCubes.test(cid)); if (vbuf[cid].sprites[s].isHidden()) { switch (stat1 + stat2) { case 0: vbuf[cid].sprites[s].setImage(RedBars[s]); break; //2 red -> red case 1: vbuf[cid].sprites[s].setImage(OrangeBars[s]); break; //1 red, 1 yellow -> orange case 2: if (stat1 == 0 || stat1 == 2) { //1 red, 1 blue -> purple vbuf[cid].sprites[s].setImage(PurpleBars[s]); break; } else { vbuf[cid].sprites[s].setImage(YellowBars[s]); //2 yellow -> yellow break; } case 3: vbuf[cid].sprites[s].setImage(GreenBars[s]); break; //1 yellow, 1 blue -> green case 4: vbuf[cid].sprites[s].setImage(BlueBars[s]); break; //2 blue -> blue } vbuf[cid].sprites[s].move(getRestPosition(s)); return true; } else { return false; } }
static bool hideSideBar(CubeID cid, Side s) { // if cid is showing a bar on side s, hide it ASSERT(activeCubes.test(cid)); if (!vbuf[cid].sprites[s].isHidden()) { vbuf[cid].sprites[s].hide(); return true; } else { return false; } }
static void onCubeConnect(void* ctxt, unsigned cid) { // this cube is either new or reconnected if (lostCubes.test(cid)) { // this is a reconnected cube since it was already lost this paint() lostCubes.clear(cid); reconnectedCubes.mark(cid); } else { // this is a brand-spanking new cube newCubes.mark(cid); } // begin showing some loading art (have to use BG0ROM since we don't have assets) dirtyCubes.mark(cid); auto& g = vbuf[cid]; g.attach(cid); g.initMode(BG0_ROM); g.bg0rom.fill(vec(0,0), vec(16,16), BG0ROMDrawable::SOLID_BG); g.bg0rom.text(vec(1,1), "Hold on!", BG0ROMDrawable::BLUE); g.bg0rom.text(vec(1,14), "Adding Cube...", BG0ROMDrawable::BLUE); }
static int barSpriteCount(CubeID cid) { // how many bars are showing on this cube? ASSERT(activeCubes.test(cid)); int result = 0; for(int i=0; i<4; ++i) { if (!vbuf[cid].sprites[i].isHidden()) { result++; } } return result; }
static void activateCube(CubeID cid) { // mark cube as active and render its canvas activeCubes.mark(cid); String<128> str; if (inRunMode) { str << "I am cube #" << cid << "\n"; drawText(cid, str, 1, 1); } else { str << "In set mode...\n"; drawText(cid, str, 1, 1); } }
static bool hideSideBar(CubeID cid, Side s) { // If cid is showing a bar on side s, hide it and check if the // blicket detector should turn off. ASSERT(activeCubes.test(cid)); if (!vbuf[cid].sprites[s].isHidden()) { vbuf[cid].sprites[s].hide(); if (barSpriteCount(cid) == 0 && cid == 0) { vbuf[cid].bg0.image(vec(0,0), Backgrounds, 0); } else { vbuf[cid].bg0.image(vec(0,0), cond.get_condition(), cid - 1); } return true; } else { return false; } }
static void activateCube(CubeID cid) { // mark cube as active and render its canvas activeCubes.mark(cid); vbuf[cid].initMode(BG0_SPR_BG1); vbuf[cid].bg0.image(vec(0,0), Backgrounds, currentBackgrounds[(int)cid]); //Old sidebar code //auto neighbors = vbuf[cid].physicalNeighbors(); // for(int side=0; side<4; ++side) { // if (neighbors.hasNeighborAt(Side(side))) { // showSideBar(cid, Side(side)); // } else { // hideSideBar(cid, Side(side)); // } // } }
static void activateCube(CubeID cid, int task) { // mark cube as active and render its canvas activeCubes.mark(cid); vbuf[cid].initMode(BG0_SPR_BG1); //this is where the starting image is set (after a task is set and we exit the menu) vbuf[cid].bg0.image(vec(0,0), TaskReds, task); auto neighbors = vbuf[cid].physicalNeighbors(); for(int side=0; side<4; ++side) { if (neighbors.hasNeighborAt(Side(side))) { //showSideBar(cid, Side(side)); } else { hideSideBar(cid, Side(side)); } } }
static bool showSideBar(CubeID cid, Side s) { // If cid is not showing a bar on side s, show it and check if the // blicket detector shold go off. ASSERT(activeCubes.test(cid)); if (vbuf[cid].sprites[s].isHidden()) { vbuf[cid].sprites[s].setImage(Bars[s]); vbuf[cid].sprites[s].move(getRestPosition(s)); if (barSpriteCount(cid) == 1 && cid == 0) { vbuf[cid].bg0.image(vec(0,0), Backgrounds, 1); } else { vbuf[cid].bg0.image(vec(0,0), cond.get_condition(), cid - 1); } return true; } else { return false; } }
static void activateCube(CubeID cid) { // Mark cube as active and render its canvas // activeCubes.mark(cid); vbuf[cid].initMode(BG0_SPR_BG1); if (cid == 0) { vbuf[cid].bg0.image(vec(0,0), Backgrounds, 0); } else { vbuf[cid].bg0.image(vec(0,0), cond.get_condition(), cid - 1); } auto neighbors = vbuf[cid].physicalNeighbors(); for(int side=0; side<4; ++side) { if (neighbors.hasNeighborAt(Side(side))) { showSideBar(cid, Side(side)); } else { hideSideBar(cid, Side(side)); } } }
void MainMenu::updateConnecting() { /* * Cubes are in the 'connectingCubes' set between when they first connect * and when they become usable for the menu. They go through three states: * * 1. Displaying the Sifteo logo. This starts in cubeConnect(), and runs on a timer. * * 2. Loading assets. We start the load itself in cubeConnect(). After the logo * finishes, we switch to displaying a progress animation. * * 3. When loading finishes, we draw an idle screen on the cube and remove it * form connectingCubes. */ SystemTime now = SystemTime::now(); /* * Look for state transitions from (1) to (2) */ CubeSet beginLoadingAnim; beginLoadingAnim.clear(); for (CubeID cube : connectingCubes & ~loadingCubes) { if ((now - Shared::connectTime[cube]).milliseconds() >= kDisplayBlueLogoTimeMS) { loadingCubes.mark(cube); beginLoadingAnim.mark(cube); } } if (!beginLoadingAnim.empty()) { loadingAnimation.begin(beginLoadingAnim); } /* * Let cubes participate in the loading animation until the whole load is done */ if (loadingCubes.empty()) { // nothing to do return; } if (!loader.isComplete()) { // Still loading, update progress loadingAnimation.paint(loadingCubes, loader.averageProgress(100)); return; } // Loading is done! loadingAnimation.end(loadingCubes); // Draw an idle screen on each cube, and remove it from connectingCubes for (CubeID cube : loadingCubes) { auto& vid = Shared::video[cube]; vid.initMode(BG0); vid.bg0.erase(Menu_StripeTile); vid.bg0.image(vec(0,0), Menu_IdleCube); connectingCubes.clear(cube); // Dispatch connected event to current applet now that the cube is ready if (itemIndexCurrent >= 0) { ASSERT(itemIndexCurrent < items.count()); MainMenuItem *item = items[itemIndexCurrent]; item->onCubeConnect(cube); // If a game was waiting on a cube to launch, try again. if (cubeRangeSavedIcon && areEnoughCubesConnected(itemIndexCurrent)) { itemIndexChoice = itemIndexCurrent; toggleCubeRangeAlert(); // remove the warning asking for more cubes } } updateCubeRangeAlert(); } loadingCubes.clear(); }
static bool isActive(NeighborID nid) { // Does this nid indicate an active cube? return nid.isCube() && activeCubes.test(nid); }
static void onCubeRefresh(void* ctxt, unsigned cid) { // mark this cube for a future repaint dirtyCubes.mark(cid); }
void main() { // subscribe to events Events::neighborAdd.set(onNeighborAdd); Events::neighborRemove.set(onNeighborRemove); Events::cubeTouch.set(onTouch); Events::cubeAccelChange.set(onAccelChange); for(CubeID cid : CubeSet::connected()) { vbuf[cid].attach(cid); motion[cid].attach(cid); activateCube(cid); } AudioTracker::setVolume(0.2f * AudioChannel::MAX_VOLUME); //if (inRunMode) LOG("run mode\n"); //else LOG("set mode\n"); // run loop while(1) { System::paint(); if (count > 1800 /*&& countDown*/) { LOG("in count conditional \n"); SystemTime curTime = SystemTime::now(); TimeDelta timePast = curTime - startTime; if (timePast > totalTime) { if (!musicInitialized) { musicInitialized = true; AudioTracker::play(Music); alarm = true; //countDown = false; } } convertedSec = timePast.seconds(); convertedMin = convertedSec / 60; displayHour = convertedMin / 60; displayMin = (int)convertedMin % (int)60; displaySec = convertedSec - (convertedMin * 60); count = 0; } //LOG_FLOAT(displaySec); count++; //if (inRunMode) LOG("run mode\n"); //else LOG("set mode\n"); for(CubeID cid : CubeSet::connected()) { activeCubes.mark(cid); String<128> str; if (inRunMode) { if (alarm) { if (cid == 0) str << "0:\n"; else if (cid == 1) str << ":00\n"; drawText(cid, str, 1, 1); } else { if (cid == 0) str << Fixed(hours-displayHour, 3) << ":\n"; else if (cid == 1) str << ":" << Fixed(minutes-displayMin, 3) << "\n"; drawText(cid, str, 1, 1) ; } } else { if (cid == 0) str << "Hours: " << Fixed(hours, 3) << "\n"; else if (cid == 1) str << "Minutes: " << Fixed(minutes, 3) << "\n"; drawText(cid, str, 1, 1) ; } } } }
static void paintWrapper() { // clear the palette newCubes.clear(); lostCubes.clear(); reconnectedCubes.clear(); dirtyCubes.clear(); if(previousLearningTask != currentLearningTask){ previousLearningTask++; } // fire events System::paint(); // dynamically load assets just-in-time if (!(newCubes | reconnectedCubes).empty()) { AudioTracker::pause(); playSfx(SfxConnect); loader.start(config); while(!loader.isComplete()) { for(CubeID cid : (newCubes | reconnectedCubes)) { vbuf[cid].bg0rom.hBargraph( vec(0, 4), loader.cubeProgress(cid, 128), BG0ROMDrawable::ORANGE, 8 ); } // fire events while we wait System::paint(); } loader.finish(); AudioTracker::resume(); } // // repaint cubes (will this paint right? If not, try repainting all of them) // for(CubeID cid : dirtyCubes) { // activateCube(cid); // } //If the shaken timer flag is too old, turn it off again here. if(distractTime.isValid() && (currentLearningTask==2)) { TimeDelta timeSinceShook = SystemTime::now() - distractTime; double duration = timeSinceShook.milliseconds() / 1000; if((duration > 11) && isDistracted) { currentBackgrounds[2] = 3; currentBackgrounds[1] = 1; isDistracted = false; } } //update art to new task int j = 0; for(CubeID cid : CubeSet::connected()) { vbuf[cid].attach(cid); activateCube(cid); cbs [j] = cid; j++; } // also, handle lost cubes, if you so desire :) }
void MainMenu::eventLoop() { while (1) { // Need to bind the menu to a new cube? if (!mainCube.isDefined()) { /* * Make sure we have at least one cube. Until we do, there's nothing * we can do, so just play our "cube missing" sound periodically. * * This exits as soon as at least one cube is in CubeSet::connected(), * but that cube may still be busy loading assets or showing the logo. */ waitForACube(); /* * Wait until we have a cube that's usable for our menu */ while (1) { CubeSet usable = CubeSet::connected() & ~connectingCubes; if (usable.empty()) { System::paint(); updateMusic(); updateConnecting(); System::yield(); continue; } else { mainCube = *usable.begin(); break; } } // try and avoid some of the garbage we often see :P System::finish(); if (itemIndexCurrent >= 0) { if (itemIndexCurrent > 0 && items[itemIndexCurrent]->isFirstRun()) { initMenu(itemIndexCurrent, true, 0); } else { initMenu(itemIndexCurrent, true); } } else { initMenu(0, false); } } MenuEvent e; itemIndexChoice = -1; // Keep running until a choice is made or the menu cube disconnects while (mainCube.isDefined() && menu.pollEvent(&e)) { updateConnecting(); updateSound(); updateMusic(); updateAlerts(); handleEvent(e); } if (itemIndexChoice >= 0) { ASSERT(itemIndexChoice < items.count()); return execItem(items[itemIndexChoice]); } } }