0,]']>S}Wup8d%qy)6o;]AsVl33!! !"! 4/O"/" 33343O #?#? ܎̎̈ ݈ ̭ 4C 4C̾̾ <"#"<"#"#" !!,̬̬̚ܬͬ̚əəșɉɉ̙̙̉4433##""ݟM<.-̙̙̙CC33##""".".. ̬̬̬̬̚̚əəɉəɉ̙̉ // ݟ̙̙̙̙̙̙ lflflffffffffffffff f̈̌̈̈Ȉ """""""""" ""̌̌̈ lffffffffffflflfffffffffffffffffffffffffffffffffffffffff̈̈̌̌̌̈̈̈̈̈̈̈""""""""""""""""""""""""""""""""""""""""""""""""̌̌̈̈̌̌̈ȈȈ flfffffffflff ̌̌̈ """""""""""" ̈̌̈̈ """ """"""""  " \UfUUeUUeUUUfUUffUffffffffffffffffeffvuwwg vwvwwwwwwwwwwv\efUefVuffuffVUffUffffffffffofffofvuwwg vgvgwgwwvwwv\ofUmVffmfUf]ffoffmfffffofvuwwg vgowgwwvwwv,"""""""""""""","""""","",,"""", """"""""""",, ffVffvffvffvffvffwfvvvwgwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwvggggggffVffvffvffvffvffwfvvvwgwwwwwwwwwwwwwowwvwwowwwwwwwvggggggfUfffgvfvwvgffwfvvvwgwwwwwwwwwwvwwwwwvgogogo"",",",""",",",,,""""""",""""""",,,"""""""""""""""""""" """"""" " """wwwwwwwwwwvwwggffv wwwwwwwwwwvwwggffv wwwvwwggffv "","","",""""","",,,,",,"""""""""""""",,""""""""""""""  """"0000000  5  ! ! ! ! ! ! ! ! !$%&'() ! !456789 ! !DEFGHI ! !TUVWXY ! !de i !tuy"#0101 q+|       t< \effffvg\effffvg\effffvg\effffvg\effffvg\effffvgUeffffvgUeffffvgUeffffvgUeffffvgUeffffvgUeffffvgD@VuffffwgVuffffwgVuffffwgVuffffwgVuffffwgVuffffwg@DDD@@DfuffoffwwvfuffoffwwvfuffoffwwvfuffoffwwvfuffoffwwvfuffoffwwvD@DDD@fVUfofvwwfVUfofvwwfVUfofvwwfVUfofvwwfVUfofvwwfVUfofvwwD@DffUuwwgvffUuwwgvffUuwwgvffUuwwgvffUuwwgvffUuwwgv@D@@DffVwwwwvffVwwwwvffVwwwwvffVwwwwvffVwwwwvffVwwwwvffvwwwwgffvwwwwgffvwwwwgffvwwwwgffvwwwwgffvwwwwgffvwwwwgffvwwwwgffvwwwwgffvwwwwgffvwwwwgffvwwwwgffvwowwgffvwowwgffvwowwgffvwowwgffvwowwgffvwowwg ffvvwwgffvvwwgffvvwwgffvvwwgffvvwwgffvvwwg ffwowwgffwowwgffwowwgffwowwgffwowwgffwowwg fvvwwgfvvwwgfvvwwgfvvwwgfvvwwgfvvwwg vwgwwwvwgwwwvwgwwwvwgwwwvwgwwwvwgwww wwwvwwgwwwvwwgwwwvwwgwwwvwwgwwwvwwgwwwvwwgwwgffvwwgffvwwgffvwwgffvwwgffvwwgffvwwwwwwwwwwwwwwwwwwwwwwwwwwwwww \effffvg\effffvg\effffvg\effffvg\effffvgUeffffvgUeffffvgUeffffvgUeffffvgUeffffvgVuffffwgVuffffwgVuffffwgVuffffwgVuffffwgfuffoffwwvfuffoffwwvfuffoffwwvfuffoffwwvfuffoffwwvfVUfofvwwfVUfofvwwfVUfofvwwfVUfofvwwfVUfofvwwffUuwwgvffUuwwgvffUuwwgvffUuwwgvffUuwwgvffVwwwwvffVwwwwvffVwwwwvffVwwwwvffVwwwwvffvwwwwgffvwwwwgffvwwwwgffvwwwwgffvwwwwgffvwwwwg?ffvwwwwgffvwwwwgffvwwwwgffvwwwwgffvwowwg3ffvwowwgffvwowwgffvwowwgffvwowwgffvvwwg3ffvvwwgffvvwwgffvvwwgffvvwwgffwowwg3ffwowwgffwowwgffwowwgffwowwgfvvwwg4fvvwwgfvvwwgfvvwwgfvvwwgvwgwwwO3vwgwwwvwgwwwvwgwwwvwgwwwwwwvwwg43wwwvwwgwwwvwwgwwwvwwgwwwvwwgwwgffv/O33wwgffvwwgffvwwgffvwwgffvww"43wwwwwwwwww/Owwwwwwwww"wwww \effffvg\effffvg\effffvg\effffvgUeffffvgUeffffvgUeffffvgUeffffvgVuffffwgVuffffwgVuffffwgVuffffwgfuffoffwwvfuffoffwwvfuffoffwwvfuffoffwwvfVUfofvwwfVUfofvwwfVUfofvwwfVUfofvwwffUuwwgvffUuwwgvffUuwwgvffUuwwgvffVwwwwvffVwwwwvffVwwwwvffVwwwwvffvwwwwgffvwwwwgffvwwwwgffvwwwwgffvwwwwgffvwwwwgffvwwwwgffvwwwwgffvwowwgffvwowwgffvwowwgffvwowwgffvvwwgffvvwwgffvvwwgffvvwwgffwowwgffwowwgffwowwgffwowwgfvvwwgfvvwwgfvvwwgfvvwwgvwgwwwvwgwwwvwgwwwvwgwwwwwwvwwgwwwvwwgwwwvwwgwwwvwwgwwgffvwwgffvwwgffvwwgffvwwwwwwwwwwwwwwwwwwww \effffvg\effffvg\effffvgUeffffvgUeffffvgUeffffvgVuffffwgVuffffwgVuffffwgfuffoffwwvfuffoffwwvfuffoffwwvfVUfofvwwfVUfofvwwfVUfofvwwffUuwwgvffUuwwgvffUuwwgvffVwwwwvffVwwwwvffVwwwwvffvwwwwgffvwwwwgffvwwwwgffvwwwwgffvwwwwgffvwwwwgffvwowwgffvwowwgffvwowwgffvvwwgffvvwwgffvvwwgffwowwgffwowwgffwowwgfvvwwgfvvwwgfvvwwgvwgwwwvwgwwwvwgwwwwwwvwwgwwwvwwgwwwvwwgwwgffvwwgffvwwgffvwwwwwwwwwwwwwww """"""""""   \effffvg\effffvg" "\effffvg\effffvgUeffffvgUeffffvg UeffffvgUeffffvgVuffffwgVuffffwg VuffffwgVuffffwgfuffoffwwvfuffoffwwv fuffoffwwvfuffoffwwvfVUfofvwwfVUfofvww fVUfofvwwfVUfofvwwffUuwwgvffUuwwgv ffUuwwgvffUuwwgvffVwwwwvffVwwwwv ffVwwwwvffVwwwwvffvwwwwgffvwwwwg ffvwwwwgffvwwwwgffvwwwwgffvwwwwg ffvwwwwgffvwwwwgffvwowwgffvwowwg ffvwowwgffvwowwgffvvwwgffvvwwg ffvvwwgffvvwwgffwowwgffwowwg ffwowwgffwowwgfvvwwgfvvwwg fvvwwgfvvwwgvwgwwwvwgwww vwgwwwvwgwwwwwwvwwgwwwvwwg wwwvwwgwwwvwwgwwgffvwwgffv wwgffvwwgffvwwww wwwwwwww wwwwww ww" "   """"""""""D-- title: Memo game -- author: Xevin -- desc: -- script: lua -- asset license: CC BY 4.0 MARGIN = 2 TILE_WIDTH = 24 TILE_HEIGHT = 24 CARD_BACK_TILE = 451 CURSOR_TILE = 448 MENU_CURSOR_START = 496 MENU_CURSOR_END = 501 LOCK_TILE = 502 A_BUTTON_TILE = 271 B_BUTTON_TILE = 287 UP_BUTTON_TILE = 303 LEFT_BUTTON_TILE = 319 RIGHT_BUTTON_TILE = 335 DOWN_BUTTON_TILE = 351 GAME_TYPES = { easy = { cols = 6, rows = 3, chars = { 256, 259, 262, 265, 268, 304, 307, 310, 313 }, x = (TILE_WIDTH + MARGIN) * 2, y = TILE_WIDTH + MARGIN, back = CARD_BACK_TILE, showDelay = 1800 -- cols * rows * 100 }, normal = { cols = 6, rows = 5, chars = { 256, 259, 262, 265, 268, 304, 307, 310, 313, 316, 352, 355, 358, 361, 364 }, x = (TILE_WIDTH + MARGIN) * 2, y = 0, back = CARD_BACK_TILE + 3, showDelay = 3000 }, hard = { cols = 8, rows = 5, chars = { 256, 259, 262, 265, 268, 304, 307, 310, 313, 316, 352, 355, 358, 361, 364, 400, 403, 406, 409, 412 }, x = TILE_WIDTH + MARGIN + 6, y = 0, back = CARD_BACK_TILE + 6, showDelay = 4000 } } -- SWEETIE-16 PALETTE BLACK = 0 MAGENTA = 1 RED = 2 ORANGE = 3 YELLOW = 4 LIME = 5 GREEN = 6 DARKGREEN = 7 DARKBLUE = 8 BLUE = 9 LIGHTBLUE = 10 CIAN = 11 WHITE = 12 LIGHTGRAY = 13 GRAY = 14 DARKGRAY = 15 GAMEPAD_1 = { UP = 0, DOWN = 1, LEFT = 2, RIGHT = 3, A = 4, B = 5, X = 6, Y = 7 } function tableGetFirstItem(tbl) for i,v in pairs(tbl) do return i end end function tableKeys(tbl) t = {} for k,v in pairs(tbl) do table.insert(t, k) end return t end function isTableHasKey(tbl, key) return tbl[key] ~= nil end function isTableHasValue(tbl, value) for k,v in pairs(tbl) do if value == v then return true end end return false end function tableToString(tbl) str = '' for i, j in pairs(tbl) do delimiter = #str > 0 and ',\n' or '' newStr = " " .. i .. '=' .. j str = str .. delimiter .. newStr end return "{\n" .. str .. "\n}" end function cycleIndex(idx, min, max) if idx > max then return min elseif idx < min then return max else return idx end end Timer = { new = function(self) local props = { startTime = time(), func = nil, delay = nil, isEnabled = false } self.__index = self return setmetatable(props, self) end, start = function(self, delay, func) self.isEnabled = true self.startTime = time() self.delay = delay self.func = func end, update = function(self) if self.isEnabled then local nowTime = time() if self.startTime + self.delay < nowTime then self.isEnabled = false self.func() end end end, } function idx2col(idx, colCount) -- convert index to column return ((idx - 1) % colCount) + 1 -- -1 and +1 for index correction end function idx2row(idx, colCount) return ((idx - idx2col(idx, colCount)) / colCount) + 1 -- +1 is lua index correction end function colRow2idx(column, row, columnCount) return ((row - 1) * columnCount) + column end TextureSquare = { new = function(self, x, y, w, h, sprIdx) local props = { x = x, y = y, w = w, h = h, spr = sprIdx, hscale = 1, vscale = 1, tx = x, ty = y, isCentered = true } self.__index = self return setmetatable(props, self) end, flipHorizontal = function(self, delay) if self.tw > 0 then self.tw = self.tw - 1 else self.tw = self.w end end, moveCenter = function(self) self.tx = self.x + (self.w / 2) - (self:getScaledWidth() / 2) self.ty = self.y + (self.h / 2) - (self:getScaledHeight() / 2) end, getScaledWidth = function(self) return self.hscale * self.w end, getScaledHeight = function(self) return self.vscale * self.h end, getSpriteX = function(self) return idx2col(self.spr, 16) * 8 end, getSpriteY = function(self) local idx = idx2row(self.spr+1, 16) - 1 return idx * 8 end, update = function(self) local sx = self:getSpriteX(self.spr) local sy = self:getSpriteY(self.spr) if self.isCentered then self:moveCenter() end textri( self.tx, self.ty, self.tx, self.ty + self:getScaledHeight(), self.tx + self:getScaledWidth(), self.ty, sx, sy, sx, sy + self.h, sx + self.w, sy, false, 0 ) textri( self.tx + self:getScaledWidth(), self.ty, self.tx, self.ty + self:getScaledHeight(), self.tx + self:getScaledWidth(), self.ty + self:getScaledHeight(), sx + self.w, sy, sx, sy + self.h, sx + self.w, sy + self.h, false, 0 ) end, } Card = { new = function(self, x, y, sprIdx, backIdx) local props = { x = x, y = y, spr = sprIdx, openSpeed = 0.2, state = '', stateList = { 'opened', 'closed', 'opening', 'closing' }, back = TextureSquare:new(x, y, TILE_WIDTH, TILE_HEIGHT, backIdx or CARD_BACK_TILE), face = TextureSquare:new(x, y, TILE_WIDTH, TILE_HEIGHT, sprIdx) } props.state = 'closed' props.face.hscale = 0 props.back.hscale = 1 props.cbOnClosed = function() end props.cbOnOpened = function() end self.__index = self return setmetatable(props, self) end, onOpened = function(self, cb) self.cbOnOpened = cb end, onClosed = function(self, cb) self.cbOnClosed = cb end, setState = function(self, state) if isTableHasValue(self.stateList, state) then self.state = state if state == 'closed' then self.face.hscale = 0 self.back.hscale = 1 self.cbOnClosed() elseif state == 'opened' then self.face.hscale = 1 self.back.hscale = 0 self.cbOnOpened() end end end, update = function(self) self.back.x = self.x self.back.y = self.y self.face.x = self.x self.face.y = self.y if self.state == 'opening' then if self.back.hscale > 0 then self.back.hscale = self.back.hscale - self.openSpeed self.back:update() elseif self.face.hscale < 1 then self.face.hscale = self.face.hscale + self.openSpeed self.face:update() else self:setState('opened') end elseif self.state == 'closing' then if self.face.hscale > 0 then self.face.hscale = self.face.hscale - self.openSpeed self.face:update() elseif self.back.hscale < 1 then self.back.hscale = self.back.hscale + self.openSpeed self.back:update() else self:setState('closed') end else self.face:update() self.back:update() end end, } Memo = { new = function(self, x, y, cols, rows, chars, back, showDelay) local props = { x = x, y = y, cols = cols, rows = rows, chars = chars, items = {}, firstItem = { x = -1, y = -1 }, secondItem = { x = -1, y = -1 }, selectedItem = { x = 1, y = 1 }, state = 'locked', back = back, showDelay = showDelay, stateList = { 'idle', -- all cards is closed 'oneOpened', 'twoOpened', 'locked' }, guessed = {}, isGameEnded = false, timer = Timer:new(), cards = {} } props.cardsOpenedCount = 0 self.__index = self local obj = setmetatable(props, self) obj:generateFieldItems() obj:spawnCards() return obj end, generateFieldItems = function(self) local doubledChars = {} for k, v in ipairs(self.chars) do table.insert(doubledChars, v) end for k, v in ipairs(self.chars) do table.insert(doubledChars, v) end self.items = {} for k, v in ipairs(doubledChars) do table.insert(self.items, math.random(1, #self.items + 1), v) table.insert(self.guessed, false) end end, spawnCards = function(self) for k,v in ipairs(self.items) do local col = idx2col(k, self.cols) local row = idx2row(k, self.cols) local x = self.x + ((col - 1) * (TILE_WIDTH + MARGIN)) local y = self.y + ((row - 1) * (TILE_HEIGHT + MARGIN)) local xm = x + MARGIN local ym = y + MARGIN local card = Card:new(xm, ym, v, self.back) card:setState("opened") card:onOpened(function() if self.cardsOpenedCount == 0 then self.firstItem.x = col self.firstItem.y = row self.cardsOpenedCount = 1 self:setState("idle") elseif self.cardsOpenedCount == 1 then self.secondItem.x = col self.secondItem.y = row if self.items[self:getFirstIdx()] == self.items[self:getSecondIdx()] then self:setState("locked") self.timer:start(400, function(obj) self:removeItem(self:getFirstIdx()) self:removeItem(self:getSecondIdx()) self:resetSelection() self:setState("idle") sfx(1) end) else self:setState("locked") self.timer:start(600, function(obj) self:resetSelection() self:setState("idle") end) end self.cardsOpenedCount = 0 end end) card:onClosed(function() if self.cardsOpenedCount > 0 then self.cardsOpenedCount = self.cardsOpenedCount - 1 end self:setState("idle") end) table.insert(self.cards, card) end self.timer:start(self.showDelay, function() self:closeAllCards() end) end, closeAllCards = function(self) for i, card in ipairs(self.cards) do card:setState("closing") end end, setState = function(self, state) if isTableHasValue(self.stateList, state) then self.state = state end end, resetSelection = function(self) local firstIdx = self:itemIndex(self.firstItem) self.cards[firstIdx]:setState('closing') if self.secondItem.x >= 0 then local secondIdx = self:itemIndex(self.secondItem) self.cards[secondIdx]:setState('closing') end self.firstItem.x = -1 self.firstItem.y = -1 self.secondItem.x = -1 self.secondItem.y = -1 end, itemIndex = function(self, item) return colRow2idx(item.x, item.y, self.cols) end, getSelectedIdx = function(self) return self:itemIndex(self.selectedItem) end, getFirstIdx = function(self) return self:itemIndex(self.firstItem) end, getSecondIdx = function(self) return self:itemIndex(self.secondItem) end, removeItem = function(self, idx) self.guessed[idx] = true self:checkGameOver() end, checkGameOver = function(self) for i,v in ipairs(self.guessed) do if not v then self.isGameEnded = false return end end self.isGameEnded = true end, input = function(self) local m_x,m_y,m_left,m_middle,m_right,m_scrollx,m_scrolly=mouse() local field_w = self.cols * (TILE_WIDTH + MARGIN) local field_h = self.rows * (TILE_HEIGHT + MARGIN) -- is mouse cursor inside game field? if m_x > self.x and m_x < field_w + self.x and m_y > self.y and m_y < field_h + self.y then -- draw cursor on card self.selectedItem.x = math.ceil((m_x - self.x) / (TILE_WIDTH + MARGIN)) self.selectedItem.y = math.ceil((m_y - self.y) / (TILE_HEIGHT + MARGIN)) local curCard = self.cards[self:getSelectedIdx()] if m_left and curCard.state ~= "opening" and curCard.state ~= "closing" and self.state ~= "locked" then self:toggleCard(curCard) end end end, toggleCard = function(self, card) self:setState("locked") if card.state == "closing" or card.state == "opening" then trace("card is busy") else if card.state == "closed" then card:setState('opening') else card:setState('closing') end end end, update = function(self) self.timer:update() for i,card in ipairs(self.cards) do if not self.guessed[i] then card:update() end local col = idx2col(i, self.cols) local row = idx2row(i, self.cols) local x = self.x + ((col - 1) * (TILE_WIDTH + MARGIN)) local y = self.y + ((row - 1) * (TILE_HEIGHT + MARGIN)) local xm = x + MARGIN local ym = y + MARGIN if self.selectedItem.x == col and self.selectedItem.y == row then spr(CURSOR_TILE, xm, ym, 0, 1, 0, 0, 3, 3) end end end } MENU_CURSOR_FLIP_DELAY = 70 MENU_CURSOR_SHORT_FLIP_DELAY = 15 Menu = { new = function(self, x, y, items, onSelectItem) local props = { x = x, y = y, items = items, currentItem = 1, onSelectItem = onSelectItem, flipTimer = time(), cursorSpr = MENU_CURSOR_START, timer = Timer:new(), flipDelay = MENU_CURSOR_FLIP_DELAY, is_menu_item_activated = false } self.__index = self return setmetatable(props, self) end, selectItem = function(self, idx) self.currentItem = cycleIndex(idx, 1, #self.items) end, input = function(self) local m_x,m_y,m_left,m_middle,m_right,m_scrollx,m_scrolly = mouse() if m_y + 2 > self.y and m_y - 1 < self.y + (#self.items * 10) then for i, v in ipairs(self.items) do local itemY = ((i -1) * 10) + self.y if m_y > itemY and m_y < itemY + 8 then self:selectItem(i) end end if m_left then if not self.is_menu_item_activated then sfx(3, 'A#5') self.is_menu_item_activated = true end self.flipDelay = MENU_CURSOR_SHORT_FLIP_DELAY self.timer:start(600, function(obj) self.onSelectItem(self.items[self.currentItem]) end) end end end, update = function(self) self.timer:update() local nowTime = time() if self.flipTimer + self.flipDelay < nowTime then self.flipTimer = nowTime self.cursorSpr = cycleIndex(self.cursorSpr + 1, MENU_CURSOR_START, MENU_CURSOR_END) end for i, v in ipairs(self.items) do local y = self.y + ((i - 1) * 10) print(v, self.x, y) if i == self.currentItem then print(v, self.x-1, y-1, LIGHTGRAY) spr(self.cursorSpr, self.x - 12, y - 2, BLACK) end end end, } MENU_X = 100 MENU_Y = 90 MENU_SCENE = { init = function(self, parent) self.parent = parent self.menu = Menu:new( MENU_X, MENU_Y, { 'easy', 'normal', --'hard' }, function(menuItem) self:onSelectMenuItem(menuItem) end ) end, onSelectMenuItem = function(self, menuItem) self.parent:startGame(menuItem) end, update = function(self) cls() local x = 65 local y = 20 print('Memo game', x + 1, y - 1, WHITE, true, 2) print('Memo game', x + 1, y + 1, WHITE, true, 2) print('Memo game', x - 1, y - 1, WHITE, true, 2) print('Memo game', x - 1, y + 1, WHITE, true, 2) print('Memo game', x, y, GREEN, true, 2) self.menu:input() self.menu:update() -- TEMPORARY not working spr(LOCK_TILE, MENU_X - 13, MENU_Y + 18) print('hard (coming soon)', MENU_X, MENU_Y + 19) end, } RUN_SCENE = { init = function(self, parent) self.parent = parent self.startTime = time() self.memo = Memo:new( self.parent.gameType.x, self.parent.gameType.y, self.parent.gameType.cols, self.parent.gameType.rows, self.parent.gameType.chars, self.parent.gameType.back, self.parent.gameType.showDelay ) self.backToMenuY = 119 self.isMenuHighlighted = false end, gameTime = function(self) return self.timer - self.startTime end, input = function(self) local m_x,m_y,m_left,m_middle,m_right,m_scrollx,m_scrolly = mouse() menu_x = 9 menu_w = 24 if m_left and m_x > menu_x - 2 and m_x < menu_x + menu_w + 2 and m_y > self.backToMenuY and m_y < self.backToMenuY + 8 then self.parent:setScene('menu') elseif m_x > menu_x - 2 and m_x < menu_x + menu_w + 2 and m_y > self.backToMenuY and m_y < self.backToMenuY + 8 then self.isMenuHighlighted = true else self.isMenuHighlighted = false end end, drawInputHint = function(self) local x = 0 local cY = 40 local cX = 6 if self.isMenuHighlighted then color = BLUE else color = DARKBLUE end print('Menu', x + 9, self.backToMenuY, color, false, 1) end, update = function(self) cls() self.memo:input() self:input() self.memo:update() self.timer = time() print("time", 5, 6, YELLOW) local timeX = 12 local seconds = self:gameTime()//1000 if seconds < 10 then timeX = 12 elseif seconds < 100 then timeX = 10 else timeX = 8 end print(string.format("%d", seconds), timeX, 14, LIGHTGRAY) if self.memo.isGameEnded then self.parent:setScore(self:gameTime()) self.parent:setScene('result') end self:drawInputHint() end } RESULT_SCENE = { init = function(self, parent) self.parent = parent self.menu = Menu:new( 90, 110, { 'play again', 'main menu' }, function(menuItem) self:onSelectMenuItem(menuItem) end ) end, onSelectMenuItem = function(self, menuItem) if menuItem == 'play again' then self.parent:setScene('run') elseif menuItem == 'main menu' then self.parent:setScene('menu') end end, drawBackground = function(self) map() local x2 = 146 local y2 = 84 line(240, 116, x2, y2, DARKGRAY) line(x2, y2, 0, 136, DARKGRAY) line(x2, y2, x2, 0, DARKGRAY) end, update = function(self) cls() self:drawBackground() self.menu:update() self.menu:input() local msg = string.format('You time: %d seconds', self.parent.score) print('difficult: ' .. self.parent.gameTypeName, 65, 50, GREEN) print(msg, 65, 65, GREEN) end, } local Game = { new = function(self, sceneList) local props = { curSceneName = '', sceneList = sceneList or {}, score = 0 } self.gameTypeName = 'easy' self.gameType = GAME_TYPES[self.gameTypeName] self.__index = self return setmetatable(props, self) end, setScene = function(self, sceneName) if isTableHasKey(self.sceneList, sceneName) then self.curSceneName = sceneName self.sceneList[self.curSceneName]:init(self) end end, setScore = function(self, value) self.score = value // 1000 end, startGame = function(self, type) if isTableHasKey(GAME_TYPES, type) then self.gameTypeName = type self.gameType = GAME_TYPES[self.gameTypeName] self:setScene('run') end end, update = function(self) self.sceneList[self.curSceneName]:update() end } theGame = Game:new({ menu = MENU_SCENE, run = RUN_SCENE, result = RESULT_SCENE }) theGame:setScene('menu') function TIC() theGame:update() end