ÎÌÌÌ̈ˆˆ¬ªªª¬ˆˆˆ¬ÌÌ̬ÌÀ̬ÌÀ̬ÌÀÌÌÌìÌÀÀî̬ÀÌÀ¬ÀÀÀ¬ÀÀÀ¬ÀÀÎÌÌÌ̈ˆˆ¬ªªª¬ˆˆˆ¬ÌÌ̬ÌÌ̬ÌÀ̬ÌÀÌÌÌìÌÀÀî̬ÀÌ̬ÀÀÀ¬ÀÀÀ¬ÀÀ¬ÌÌ̬ªªª¬ª¬ª¬ªÊ̬ªªªŒˆˆˆÌÀÌÎÌÌÎ̬̪ªÀ쬪ÀÀÀÌîÀìîÌÌîî¬ÌÌ̬ªªª¬ª¬ª¬ªÊ̬ªªªŒˆˆˆÌÀÌÎÌÌÎ̬̪ªÀ쬪ÀÀÀÌîÀìîÌÌîî z è°© ª°:Ð I à ¹·ÆÐ°Ð 2BbctuU÷èéëìì ÝÝÛ‰™™ºËðAÌ "7<âý>ðÿÿÿÿðÿÿðÿðÿÿðÿÿÿðÿÀÌÀÌÌ ÌÌÀÌ Ì À ÀÌ Ì ÀÌ Ì ÿÿÿððÿÿÿÿÿÿðÿððÌ Ì Ì À À ÀÀ ÀÀ À ÀÀ ÀÌÌ ÿÿÿÿÿÿÿÿðÿðÿððÿÌÌ ÌÌ À À ÀÀ ÀÀ ÀÌ À ÀÌÌÌ ÿÿÿððÿÿÿÿÿÿÿððððÌ Ì ÌÀ À ÀÌ À ÀÀ À ÀÀ ÀÌÌ ðÿÿððÿÿÿÿÿÿÿÿÿðÿÀÌÀÌÌ À À ÀÌ ÀÌÌÀÌ Ì ÌÌ ÀÀÀÀÌ Ì ÀÀÀÌ ° °± ° °° °° UUUUUUUUUUUUUUUUUPUPUUUU UUUUÐ UUUU ÐÑ ÐÐÐ ÐÐ UUUUUUUUUUUUUUUUUPUPUUUUUÕÝÝÝ  ªªª ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆUÕÝÝÝ�ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆ¨ªªªŠˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆÐÝÝÝ  ªªª ÐÝÝÝ  ªªª ÐÝÝÝ  ªªª ÐÝÝÝ  ªªª ÐÝÝÝ  ªªª ÐÝÝÝ  ªªª ° °° ° °° °° ° °° ° °° °°° » ° °@DDD Ð @DDD °@DDD° @DDD»@D°@DDD@DDD@DDDÐÐUUUUÝÝUUUUÐ Ð UUUU Ра UUUU ð ð °UPUP Ð ° UUUUРн °UUUU »»»» °» °°» °» ° °» ݰ UUUU» ° ° °° °°°°° °°Û°° ° °Ð ° °° ° °° °°»»° °° °° ° °° ° ° °°» °»»° °°» ° ° ° »» ° » ° ° »» ° °°»»°» ™™�™™™�™ �™™� �™™™™™™™�™ ™ � ™™ ™™ ™ ™ ™™ ™™™ � ™™ ™™ ™™ ™ ™ ™™ �™ ™ � ™™ ™™ ™ ™™™™ ™ ™™�™� ™�™ ™� �™™ ™™ ™™ø$-- title: Dual Being -- author: kolonochkaa -- desc: Play for both two characters and collect gems! -- script: lua -- input: gamepad -- palette: modern -- ============================================ -- Ð�Ð�СТРОЙКИ И ГЛОБÐ�ЛЬÐ�ЫЕ ПЕРЕМЕÐ�Ð�ЫЕ -- ============================================ -- Игроки (две Ñ�ущноÑ�ти) players = { { x = 100, y = 68, -- позициÑ� (верхний мир) color = 12, -- Ñ�иний active = true, width = 6, height = 6 }, { x = 140, y = 68, -- позициÑ� (нижний мир) color = 9, -- краÑ�ный active = true, width = 6, height = 6 } } -- КриÑ�таллы (цели) crystals = {} for i = 1, 8 do crystals[i] = { x = math.random(20, 220), y = math.random(20, 116), world = math.random(1, 2), -- 1 = верхний, 2 = нижний collected = false } end -- Враги (движутÑ�Ñ� в противоположном мире) enemies = {} for i = 1, 4 do enemies[i] = { x = math.random(20, 220), y = math.random(20, 116), world = math.random(1, 2), dx = (math.random() * 2 - 1) * 0.8, dy = (math.random() * 2 - 1) * 0.8, size = 8 } end -- Счет score = 0 gameOver = false win = false -- Таймер анимации animTimer = 0 -- ============================================ -- ВСПОМОГÐ�ТЕЛЬÐ�ЫЕ ФУÐ�КЦИИ -- ============================================ function clamp(value, min, max) return math.max(min, math.min(max, value)) end function distance(x1, y1, x2, y2) local dx = x1 - x2 local dy = y1 - y2 return math.sqrt(dx*dx + dy*dy) end -- ============================================ -- ЗÐ�ГРУЗКÐ� -- ============================================ function BOOT() -- Ð’ TIC-80 math.random уже инициализирован, -- дополнительный seed не требуетÑ�Ñ�. -- ЕÑ�ли нужно, можно иÑ�пользовать time() вмеÑ�то os.time() -- math.randomseed(time()) end -- ============================================ -- ГЛÐ�Ð’Ð�ЫЙ ЦИКЛ -- ============================================ function TIC() if gameOver then showGameOver() return end if win then showWin() return end handleInput() updateEnemies() checkCollisions() draw() drawUI() animTimer = (animTimer + 1) % 60 end -- ============================================ -- УПРÐ�ВЛЕÐ�ИЕ (зеркальное движение) -- ============================================ function handleInput() local dx = 0 local dy = 0 if btn(0) then dx = -2 end -- влево if btn(1) then dx = 2 end -- вправо if btn(2) then dy = -2 end -- вверх if btn(3) then dy = 2 end -- вниз -- Перемещаем обоих игроков зеркально players[1].x = players[1].x + dx players[1].y = players[1].y + dy players[2].x = players[2].x - dx -- зеркально по X players[2].y = players[2].y - dy -- зеркально по Y -- ОграничениÑ� длÑ� первого игрока (верхний мир) players[1].x = clamp(players[1].x, 2, 238 - players[1].width) players[1].y = clamp(players[1].y, 2, 134 - players[1].height) -- ОграничениÑ� длÑ� второго игрока (нижний мир) players[2].x = clamp(players[2].x, 2, 238 - players[2].width) players[2].y = clamp(players[2].y, 2, 134 - players[2].height) end -- ============================================ -- ДВИЖЕÐ�ИЕ ВРÐ�ГОВ -- ============================================ function updateEnemies() for i, e in ipairs(enemies) do e.x = e.x + e.dx e.y = e.y + e.dy -- ОтÑ�кок от границ if e.x < 4 then e.x = 4; e.dx = -e.dx end if e.x > 236 then e.x = 236; e.dx = -e.dx end if e.y < 4 then e.y = 4; e.dy = -e.dy end if e.y > 132 then e.y = 132; e.dy = -e.dy end end end -- ============================================ -- ПРОВЕРКÐ� СТОЛКÐ�ОВЕÐ�ИЙ -- ============================================ function checkCollisions() -- Проверка Ñ�бора криÑ�таллов for i, c in ipairs(crystals) do if not c.collected then local player = players[c.world] if distance(player.x + player.width/2, player.y + player.height/2, c.x + 4, c.y + 4) < 10 then c.collected = true score = score + 1 -- Звук (еÑ�ли наÑ�троить sfx) end end end -- Проверка Ñ�толкновениÑ� Ñ� врагами (игра заканчиваетÑ�Ñ�) for _, e in ipairs(enemies) do local player = players[e.world] if distance(player.x + player.width/2, player.y + player.height/2, e.x + e.size/2, e.y + e.size/2) < 12 then gameOver = true end end -- Проверка победы (вÑ�е криÑ�таллы Ñ�обраны) local allCollected = true for _, c in ipairs(crystals) do if not c.collected then allCollected = false break end end if allCollected then win = true end end -- ============================================ -- ОТРИСОВКÐ� -- ============================================ function draw() cls(0) -- черный фон -- РазделительнаÑ� линиÑ� между мирами line(0, 68, 240, 68, 8) -- Верхний мир (голубоватый оттенок) for y = 0, 68, 8 do for x = 0, 240, 8 do if (x+y)%16 == 0 then pix(x, y, 1) -- Ñ�лабые точки фона end end end -- Ð�ижний мир (краÑ�новатый оттенок) for y = 68, 136, 8 do for x = 0, 240, 8 do if (x+y)%16 == 0 then pix(x, y, 2) end end end -- КриÑ�таллы for _, c in ipairs(crystals) do if not c.collected then local color = (c.world == 1) and 11 or 13 -- РиÑ�уем ромб (криÑ�талл) local cx, cy = c.x + 4, c.y + 4 line(cx, cy-4, cx+3, cy, color) line(cx+3, cy, cx, cy+4, color) line(cx, cy+4, cx-3, cy, color) line(cx-3, cy, cx, cy-4, color) pix(cx, cy, color+2) end end -- Враги (вращающиеÑ�Ñ� квадраты) for _, e in ipairs(enemies) do local color = (e.world == 1) and 4 or 5 rect(e.x, e.y, e.size, e.size, color) -- Глазки local eyeX = e.x + e.size/2 local eyeY = e.y + e.size/2 pix(eyeX-2, eyeY, 0) pix(eyeX+2, eyeY, 0) end -- Игроки for _, p in ipairs(players) do -- Тело rect(p.x, p.y, p.width, p.height, p.color) -- Глаза local eyeX = p.x + p.width/2 local eyeY = p.y + p.height/2 pix(eyeX-1, eyeY, 0) pix(eyeX+1, eyeY, 0) -- Ð�нимациÑ� пульÑ�ации (каждый 30-й кадр) if animTimer % 30 < 15 then rect(p.x-1, p.y-1, p.width+2, p.height+2, p.color+1) end end end function drawUI() -- Счет print("CRYSTALS: " .. score .. "/" .. #crystals, 10, 5, 15) -- ПодÑ�казка print("CONTROL BOTH", 160, 5, 12) print(" < > ^ v", 160, 13, 12) -- Иконки миров print("â–² TOP WORLD", 10, 120, 11) print("â–¼ BOTTOM WORLD", 10, 128, 9) end -- ============================================ -- ЭКРÐ�Ð�Ы КОÐ�ЦÐ� ИГРЫ -- ============================================ function showGameOver() cls(0) print("GAME OVER", 90, 60, 14) print("SCORE: " .. score, 100, 70, 15) print("PRESS Z TO RESTART", 60, 90, 12) if btn(4) then restartGame() end end function showWin() cls(0) print("VICTORY!", 100, 60, 14) print("YOU MASTERED DUALITY", 60, 70, 11) print("SCORE: " .. score, 100, 80, 15) print("PRESS Z TO PLAY AGAIN", 50, 100, 12) if btn(4) then restartGame() end end function restartGame() -- СброÑ� переменных score = 0 gameOver = false win = false -- СброÑ� позиций игроков players[1].x, players[1].y = 100, 68 players[2].x, players[2].y = 140, 68 -- Ð�овые криÑ�таллы crystals = {} for i = 1, 8 do crystals[i] = { x = math.random(20, 220), y = math.random(20, 116), world = math.random(1, 2), collected = false } end -- Ð�овые враги enemies = {} for i = 1, 4 do enemies[i] = { x = math.random(20, 220), y = math.random(20, 116), world = math.random(1, 2), dx = (math.random() * 2 - 1) * 0.8, dy = (math.random() * 2 - 1) * 0.8, size = 8 } end end