-
Notifications
You must be signed in to change notification settings - Fork 4
/
rainbow_v1.lua
245 lines (212 loc) · 10.6 KB
/
rainbow_v1.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
-- Название: Заставка Радуга
-- Автор: @AnatoliyB (телеграм)
-- Описание механики: диагональная радуга
-- Логгер в консоль
-- .print(string) - напечатать строку в консоль разработчика в браузере
local log = require("log")
-- Библиотека github.com/kikito/inspect.lua
-- для человекочитаемого вывода
local inspect = require("inspect")
-- Вспомогательные методы
-- .ShallowCopy(table) - неглубокое копирования таблицы
-- .DeepCopy(table) - глубокое копирования таблицы
local help = require("help")
-- Методы работы с JSON
-- .decode(jsonString) - декодирование строки в объект
-- .encode(jsonObject) - кодирование объекта в строку
local json = require("json")
-- Имплементация некоторых функций работы с временем
-- .unix() - возвращает текущее время в секундах (с дробной частью)
local time = require("time")
-- Методы работы с аудио
-- .PlayRandomBackground() - проигрывает случайную фоновую музыку
-- .PlayBackground(name) - проигрывает фоновую музыку по названию
-- .StopBackground() - останавливает фоновую музыку
-- .PlaySync(name) - проигрывает звук синхронно
-- .PlaySyncFromScratch(name) - проигрывает звук синхронно, очищая существующую очередь звуков
-- .PlaySyncColorSound(color) - проигрывает название цвета по его номеру
-- .PlayLeftAudio(num) - проигрывает голос "остатка" по числу (22, 12, 5 ... 0)
-- .PlayAsync(name) - проигрывает звук асинхронно
-- .PreloadFile(name) - зарянее подгрузить тяжелый файл в память
-- Станданртные звуки: CLICK, MISCLICK, GAME_OVER, GAME_SUCCESS, STAGE_DONE
-- Стандартные голоса: START_GAME, PAUSE, DEFEAT, VICTORY, CHOOSE_COLOR, LEFT_10SEC, LEFT_20SEC, BUTTONS
-- числа: ZERO, ONE, TWO, THREE, FOUR, FIVE
-- цвета: RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE
local audio = require("audio")
-- Константы цветов (0 - 7): NONE, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE
-- Константы яркости (0 - 7): BRIGHT0, BRIGHT15, BRIGHT30, BRIGHT45, BRIGHT60, BRIGHT70, BRIGHT85, BRIGHT100
local colors = require("colors")
-- Полезные стандартные функции
-- math.floor() – отбрасывает дробную часть и переводит значение в целочисленный тип
-- math.random(upper) – генерирует целое число в диапазоне [1..upper]
-- math.random(lower, upper) – генерирует целое число в диапазоне [lower..upper]
-- math.random(lower, upper) – генерирует целое число в диапазоне [lower..upper]
-- Импортированные конфиги (ниже приведен лишь ПРИМЕР структуры,
-- сами объекты будут переопределены в StartGame() при декодировании json)
-- Объект игры, см. файл game.json
local GameObj = {
Cols = 24, -- пикселей по горизонтали (X), обязательные параметр для всех игр
Rows = 15, -- пикселей по вертикали (Y), обязательные параметр для всех игр
Buttons = {2, 6, 10, 14, 18, 22, 26, 30, 34, 42, 46, 50, 54, 58, 62, 65, 69, 73, 77}, -- номера кнопок в комнате
Colors = { -- массив градиента цветов для радуги
{Color=colors.RED,Bright=colors.BRIGHT15},
{Color=colors.RED,Bright=colors.BRIGHT30},
}
}
-- Насторойки, которые может подкручивать админ при запуске игры
-- Объект конфига игры, см. файл config.json
local GameConfigObj = {
Delay = 100, -- задержка отрисовки в мс
}
-- Структура статистики игры (служебная): используется для отображения информации на табло
-- Переодически запрашивается через метод GetStats()
local GameStats = {
StageLeftDuration = 0, -- seconds
StageTotalDuration = 0, -- seconds
CurrentStars = 0,
TotalStars = 0,
CurrentLives = 0,
TotalLives = 0,
Players = { -- максимум 6 игроков
{ Score = 0, Lives = 0, Color = colors.NONE },
{ Score = 0, Lives = 0, Color = colors.NONE },
{ Score = 0, Lives = 0, Color = colors.NONE },
{ Score = 0, Lives = 0, Color = colors.NONE },
{ Score = 0, Lives = 0, Color = colors.NONE },
{ Score = 0, Lives = 0, Color = colors.NONE },
},
TargetScore = 0,
StageNum = 0,
TotalStages = 0,
TargetColor = colors.NONE,
}
-- Структура результата игры (служебная): должна возвращаться в NextTick() в момент завершения игры
-- После этого NextTick(), RangeFloor() и GetStats() больше не вызываются, игра окончена
local GameResults = {
Won = false,
}
-- Локальные переменные для внутриигровой логики
local FloorMatrix = {} -- матрица пола
local ButtonsList = {} -- список кнопок
local Pixel = { -- пиксель тип
Color = colors.NONE,
Bright = colors.BRIGHT0,
}
local GradientLength = 0
local GradientOffset = 0
local LastChangesTimestamp = 0
-- StartGame (служебный): инициализация и старт игры
function StartGame(gameJson, gameConfigJson)
GameObj = json.decode(gameJson)
GameConfigObj = json.decode(gameConfigJson)
for x=1,GameObj.Cols do
FloorMatrix[x] = {} -- новый столбец
for y=1,GameObj.Rows do
FloorMatrix[x][y] = help.ShallowCopy(Pixel) -- заполняем нулевыми пикселями
end
end
for i, num in pairs(GameObj.Buttons) do
ButtonsList[num] = help.ShallowCopy(Pixel) -- тип аналогичен пикселю
end
GradientLength = table.getn(GameObj.Colors)
audio.PlaySyncFromScratch("") -- just reset audio player on start new game
if not GameConfigObj.NoSound then
audio.PlayRandomBackground()
end
end
-- PauseGame (служебный): пауза игры
function PauseGame()
audio.PlaySyncFromScratch(audio.PAUSE)
end
-- ResumeGame (служебный): снятие игры с паузы
function ResumeGame()
end
-- SwitchStage (служебный): может быть использован для принудительного переключению этапа
-- Бывает полезно, чтобы отснять краткое превью игры для каталога
function SwitchStage()
end
-- NextTick (служебный): метод игрового тика
-- Вызывается ПРИМЕРНО каждые ~35мс (28 кадров в секунду)
-- Ориентироваться на время периода нельзя, вместо этого нужно использовать абсолютное время time.unix()
-- Не вызывается, когда игра на паузе или завершена
-- Чтобы нивелировать паузу, нужно запоминать время паузы и делать сдвиг
function NextTick()
local diffMs = (time.unix() - LastChangesTimestamp) * 1000
if diffMs < GameConfigObj.Delay then
return
end
for x=1,GameObj.Cols do
for y=1,GameObj.Rows do
FloorMatrix[x][y]=GameObj.Colors[(x+y+GradientOffset) % GradientLength + 1]
end
end
for num, button in pairs(ButtonsList) do
ButtonsList[num]=GameObj.Colors[(num+GradientOffset) % GradientLength + 1]
end
GradientOffset = GradientOffset + 1
LastChangesTimestamp = time.unix()
-- Эта заставка бесконечная
-- return GameResult
end
-- RangeFloor (служебный): метод для снятия снапшота пола
-- Вызывается в тот же игровой тик следом за методом NextTick()
--
-- Параметры:
-- setPixel = func(x int, y int, color int, bright int)
-- setButton = func(button int, color int, bright int)
function RangeFloor(setPixel, setButton)
for x=1,GameObj.Cols do
for y=1,GameObj.Rows do
setPixel(x,y,FloorMatrix[x][y].Color,FloorMatrix[x][y].Bright)
end
end
for num, button in pairs(ButtonsList) do
setButton(num,button.Color,button.Bright)
end
end
-- GetStats (служебный): отдает текущую статистику игры (время, жизни, очки) для отображения на табло
-- Вызывается в тот же игровой тик следом за методом RangeFloor()
function GetStats()
return GameStats
end
-- PixelClick (служебный): метод нажатия/отпускания пикселя
--
-- Параметры:
-- click = {
-- X: int,
-- Y: int,
-- Click: bool,
-- Weight: int,
-- }
function PixelClick(click)
end
-- ButtonClick (служебный): метод нажатия/отпускания кнопки
--
-- Параметры:
-- click = {
-- Button: int,
-- Click: bool,
-- }
function ButtonClick(click)
end
-- DefectPixel (служебный): метод дефектовки/раздефектовки пикселя
-- Используется для исключения плохих пикселей из игры
--
-- Параметры:
-- defect = {
-- X: int,
-- Y: int,
-- Defect: bool,
-- }
function DefectPixel(defect)
end
-- DefectButton (служебный): метод дефектовки/раздефектовки кнопки
-- Используется для исключения плохих кнопок из игры
--
-- Параметры:
-- defect = {
-- Button: int,
-- Defect: bool,
-- }
function DefectButton(defect)
end