|
56 | 56 | font-size: 40px; |
57 | 57 | content: counter(item-counter); |
58 | 58 | } |
| 59 | + |
| 60 | + #special-effects { |
| 61 | + width: 100%; |
| 62 | + height: 100%; |
| 63 | + position: absolute; |
| 64 | + z-index: 10; |
| 65 | + } |
| 66 | + |
| 67 | + |
| 68 | + .text-effects { |
| 69 | + position: absolute; |
| 70 | + display: flex; |
| 71 | + flex-direction: column; |
| 72 | + width: 6em; |
| 73 | + bottom: 20px; |
| 74 | + z-index: 15; |
| 75 | + right: 0; |
| 76 | + opacity: 0; |
| 77 | + } |
| 78 | + |
| 79 | + .text-effects.show { |
| 80 | + right: 20px; |
| 81 | + opacity: 1; |
| 82 | + transition: all .5s ease-out; |
| 83 | + } |
| 84 | + |
| 85 | + .text-effects-title { |
| 86 | + color: rgba(255, 50, 50, 1); |
| 87 | + text-shadow: 1px 1px rgba(200, 200, 200, 1); |
| 88 | + font-size: 30px; |
| 89 | + text-align: right; |
| 90 | + } |
| 91 | + |
| 92 | + .text-effects-subtitle { |
| 93 | + color: rgba(255, 50, 50, 1); |
| 94 | + text-shadow: 1px 1px rgba(200, 200, 200, 1); |
| 95 | + font-size: 20px; |
| 96 | + text-align: right; |
| 97 | + } |
59 | 98 | </style> |
60 | 99 | </head> |
61 | 100 |
|
|
66 | 105 | 共有10种颜色的乌龟,出现概率均等(各占总数的1/10),每次完全随机抽取,“买家”可以“许愿”一种幸运颜色,初始指定乌龟总数,依次放入1-9号格,放满后开始结算。 |
67 | 106 | 触发幸运色:每拆出1只幸运色乌龟,立刻加赠1只; |
68 | 107 | 对对碰:2个同色格,一起拿走,加赠1只; ✔ |
69 | | - 三连位:同一直线上(横、竖、对角线)3个同色格,一起拿走,加赠5只; ✔ |
70 | | - 全不同:9个格子颜色全不同,一起拿走,加赠10只。 |
| 108 | + 三连位:同一直线上(横、竖、对角线)3个同色格,一起拿走,加赠3只; ✔ |
71 | 109 | 清台: +5 |
72 | 110 | --> |
73 | 111 |
|
|
85 | 123 | </div> |
86 | 124 |
|
87 | 125 | <!-- 连线特效 Canvas --> |
| 126 | + <canvas id="special-effects"></canvas> |
| 127 | + |
88 | 128 | <!-- 文字特效 Css --> |
89 | 129 |
|
| 130 | + <div class="text-effects"> |
| 131 | + <div class="text-effects-title">三连位</div> |
| 132 | + <div class="text-effects-subtitle">加赠3只</div> |
| 133 | + </div> |
| 134 | + |
| 135 | + |
90 | 136 | <!-- 开始面板 --> |
91 | 137 | <div class="start-panel"> |
92 | 138 | <!-- 选择颜色 --> |
|
108 | 154 |
|
109 | 155 | import { Randoms } from "https://gcore.jsdelivr.net/npm/@3r/tool/lib/randoms.js"; |
110 | 156 |
|
| 157 | + /** |
| 158 | + * 等待时间 |
| 159 | + * @author linyisonger |
| 160 | + * @date 2025-01-22 |
| 161 | + */ |
| 162 | + function waitTime(time) { |
| 163 | + return { |
| 164 | + then: function (resolve) { |
| 165 | + setTimeout(resolve, time) |
| 166 | + } |
| 167 | + } |
| 168 | + } |
111 | 169 |
|
112 | 170 | /** |
113 | 171 | * 初始化平面数组 |
|
186 | 244 | * @date 2025-01-16 |
187 | 245 | */ |
188 | 246 | function same(self, target) { |
189 | | - return map[self.y][self.x].color == map[target.y][target.x].color |
| 247 | + return map[self.y][self.x].color == map[target.y][target.x].color && map[self.y][self.x].color != TURTLE_COLOR.NONE; |
190 | 248 | } |
191 | 249 |
|
192 | 250 | /** |
193 | | - * 二连判断 |
| 251 | + * 二联判断 |
194 | 252 | * @author linyisonger |
195 | 253 | * @date 2025-01-16 |
196 | 254 | */ |
197 | | - function isTwin() { |
198 | | - let sameList = [] |
199 | | - // 横向 |
200 | | - for (let x = 0; x < 2; x++) { |
201 | | - for (let y = 0; y < 3; y++) { |
202 | | - let sameArray = isSameMatch({ x, y }, { x: 1, y: 0 }, 1) |
203 | | - sameArray.length && sameList.push(sameArray) |
| 255 | + async function isTwin() { |
| 256 | + // 循环 |
| 257 | + for (let i = 0; i < turtles.length - 1; i++) { |
| 258 | + const cur = turtles[i]; |
| 259 | + if (cur.color === TURTLE_COLOR.NONE) continue; |
| 260 | + for (let j = i + 1; j < turtles.length; j++) { |
| 261 | + const nex = turtles[j] |
| 262 | + if (same(cur, nex)) { |
| 263 | + await eliminate([cur, nex]) |
| 264 | + await isTwin() |
| 265 | + } |
204 | 266 | } |
205 | 267 | } |
206 | | - // 纵向 |
207 | | - for (let y = 0; y < 2; y++) { |
208 | | - for (let x = 0; x < 3; x++) { |
209 | | - let sameArray = isSameMatch({ x, y }, { x: 0, y: 1 }, 1) |
210 | | - sameArray.length && sameList.push(sameArray) |
211 | | - } |
212 | | - } |
213 | | - return sameList; |
214 | 268 | } |
215 | 269 |
|
216 | 270 | /** |
217 | 271 | * 三连判断 |
218 | 272 | * @author linyisonger |
219 | 273 | * @date 2025-01-16 |
220 | 274 | */ |
221 | | - function isTriplet() { |
222 | | - let sameList = [] |
| 275 | + async function isTriplet() { |
| 276 | + // let sameList = [] |
223 | 277 | // 横向 |
224 | 278 | for (let i = 0; i < 3; i++) { |
225 | 279 | let sameArray = isSameMatch({ x: 0, y: i }, { x: 1, y: 0 }) |
226 | | - sameArray.length && sameList.push(sameArray) |
| 280 | + sameArray.length && await eliminate(sameArray) // sameList.push(sameArray) |
227 | 281 | } |
228 | 282 | // 纵向 |
229 | 283 | for (let i = 0; i < 3; i++) { |
230 | 284 | let sameArray = isSameMatch({ x: i, y: 0 }, { x: 0, y: 1 }) |
231 | | - sameArray.length && sameList.push(sameArray) |
| 285 | + sameArray.length && await eliminate(sameArray) // sameList.push(sameArray) |
232 | 286 | } |
233 | 287 | // 对角线 - 左上 右下 |
234 | 288 | { |
235 | 289 | let sameArray = isSameMatch({ x: 0, y: 0 }, { x: 1, y: 1 }) |
236 | | - sameArray.length && sameList.push(sameArray) |
| 290 | + sameArray.length && await eliminate(sameArray) // sameList.push(sameArray) |
237 | 291 | } |
238 | 292 | // 对角线 - 右上 左下 |
239 | 293 | { |
240 | 294 | let sameArray = isSameMatch({ x: 2, y: 0 }, { x: -1, y: 1 }) |
241 | | - sameArray.length && sameList.push(sameArray) |
| 295 | + sameArray.length && await eliminate(sameArray) // sameList.push(sameArray) |
242 | 296 | } |
243 | | - return sameList; |
| 297 | + // return sameList; |
244 | 298 | } |
245 | 299 |
|
| 300 | + |
| 301 | + /** |
| 302 | + * 清台 |
| 303 | + * @author linyisonger |
| 304 | + * @date 2025-01-23 |
| 305 | + */ |
| 306 | + async function isCleanUp() { |
| 307 | + let isClean = turtles.every(t => t.color === TURTLE_COLOR.NONE) |
| 308 | + if (isClean) await eliminate([]) |
| 309 | + } |
| 310 | + |
| 311 | + |
| 312 | + /** |
| 313 | + * 幸运色 |
| 314 | + * @author linyisonger |
| 315 | + * @date 2025-01-23 |
| 316 | + * |
| 317 | + * @param {Turtle} turtle |
| 318 | + */ |
| 319 | + async function isLuckyColor(turtle) { |
| 320 | + if (turtle.color === luckyColor) { |
| 321 | + specialEffects([turtle]) |
| 322 | + textEffects([turtle]) |
| 323 | + await waitTime(3000); |
| 324 | + } |
| 325 | + } |
| 326 | + |
| 327 | + |
246 | 328 | /** |
247 | 329 | * 是否相同位置匹配 |
248 | 330 | * @author linyisonger |
|
260 | 342 | } |
261 | 343 |
|
262 | 344 |
|
| 345 | + |
263 | 346 | /** |
264 | 347 | * 拆盲盒 |
265 | 348 | * @author linyisonger |
266 | 349 | * @date 2025-01-16 |
267 | 350 | */ |
268 | | - function unpack() { |
| 351 | + async function unpack() { |
269 | 352 | // 颜色 |
270 | 353 | let color = colors[Randoms.int(0, colors.length)] |
271 | | - // 幸运色 |
272 | | - |
273 | 354 | // 第一 |
274 | 355 | let turtleIndex = turtles.findIndex(t => t.color == TURTLE_COLOR.NONE); |
275 | | - // 结束 |
276 | | - if (buyCount == unpackCount) { |
277 | 356 |
|
278 | | - } |
| 357 | + |
| 358 | + console.log(buyCount, unpackCount); |
| 359 | + |
279 | 360 | // 摆放 |
280 | | - else if (turtleIndex > -1) { |
| 361 | + if (turtleIndex > -1 && buyCount != unpackCount) { |
| 362 | + |
281 | 363 | turtles[turtleIndex].color = color; |
282 | 364 | // 新建IMG |
283 | 365 | let imgDom = document.createElement('img') |
284 | 366 | imgDom.src = assetConfig[color] |
285 | 367 | turtlesDom.item(turtleIndex).appendChild(imgDom) |
| 368 | + await isLuckyColor(turtles[turtleIndex]) |
286 | 369 | unpackCount++; |
287 | | - unpack(); |
288 | | - |
| 370 | + await unpack(); |
289 | 371 | } |
290 | 372 | // 结算 |
291 | 373 | else { |
| 374 | + await waitTime(1000); |
| 375 | + |
| 376 | + console.log('结算'); |
| 377 | + // 三联 |
| 378 | + await isTriplet(); |
| 379 | + // 二联 |
| 380 | + await isTwin(); |
| 381 | + // 清台 |
| 382 | + await isCleanUp() |
| 383 | + |
| 384 | + // 结束 |
| 385 | + if (buyCount == unpackCount) { |
| 386 | + console.log('结束'); |
| 387 | + } |
| 388 | + else { |
| 389 | + await unpack(); |
| 390 | + } |
| 391 | + } |
292 | 392 |
|
293 | | - // 九不同 |
| 393 | + } |
294 | 394 |
|
295 | | - // 三连 |
296 | | - isTriplet(); |
297 | | - // 二连 |
298 | | - isTwin(); |
299 | 395 |
|
| 396 | + /** |
| 397 | + * 消除 |
| 398 | + * @author linyisonger |
| 399 | + * @date 2025-01-22 |
| 400 | + * |
| 401 | + * @param {Turtle[]} link |
| 402 | + */ |
| 403 | + async function eliminate(link) { |
| 404 | + link.forEach(item => map[item.y][item.x].color = TURTLE_COLOR.NONE) |
| 405 | + specialEffects(link) |
| 406 | + textEffects(link) |
| 407 | + await waitTime(3000); |
| 408 | + } |
300 | 409 |
|
301 | | - // 清台 |
| 410 | + /** |
| 411 | + * 特效 |
| 412 | + * @author linyisonger |
| 413 | + * @date 2025-01-22 |
| 414 | + * |
| 415 | + * @param {Turtle[]} link |
| 416 | + */ |
| 417 | + function specialEffects(link) { |
| 418 | + if (!link.length) return; |
| 419 | + /** @type {HTMLCanvasElement} */ |
| 420 | + let canvas = document.querySelector("#special-effects") |
| 421 | + let ctx = canvas.getContext('2d') |
| 422 | + let width = canvas.clientWidth; |
| 423 | + let height = canvas.clientHeight; |
| 424 | + canvas.width = width; |
| 425 | + canvas.height = height; |
| 426 | + let gw = width / 3; |
| 427 | + let gh = height / 3; |
| 428 | + let lw = 4; |
| 429 | + ctx.clearRect(0, 0, width, height) |
| 430 | + ctx.strokeStyle = '#ff2222' |
| 431 | + ctx.lineWidth = lw; |
| 432 | + for (let i = 0; i < link.length; i++) { |
| 433 | + const item = link[i]; |
| 434 | + ctx.rect(item.x * gw + lw / 2 + 1, item.y * gh + lw / 2 + 1, gw - lw, gh - lw) |
302 | 435 | } |
| 436 | + ctx.stroke() |
| 437 | + |
| 438 | + setTimeout(() => { |
| 439 | + if (link.length > 1) { // 非幸运色 |
| 440 | + let doms = document.querySelectorAll('.turtle-grid-item') |
| 441 | + link.forEach(item => doms[item.x + item.y * 3].innerHTML = '') |
| 442 | + } |
| 443 | + ctx.clearRect(0, 0, width, height) |
| 444 | + }, 1500); |
303 | 445 | } |
304 | 446 |
|
305 | 447 |
|
306 | | - unpack() |
| 448 | + /** |
| 449 | + * 文字特效 |
| 450 | + * @author linyisonger |
| 451 | + * @date 2025-01-22 |
| 452 | + * |
| 453 | + * @param {Turtle[]} link |
| 454 | + */ |
| 455 | + function textEffects(link) { |
| 456 | + let dom = document.querySelector('.text-effects'); |
| 457 | + let titleDom = dom.querySelector('.text-effects-title') |
| 458 | + let subtitleDom = dom.querySelector('.text-effects-subtitle') |
| 459 | + |
| 460 | + // 对对碰:2个同色格,一起拿走,加赠1只; ✔ |
| 461 | + // 三连:同一直线上(横、竖、对角线)3个同色格,一起拿走,加赠3只; ✔ |
| 462 | + // 清台: +5 |
| 463 | + if (link.length === 3) { |
| 464 | + titleDom.textContent = '三连位' |
| 465 | + subtitleDom.textContent = '加赠3只' |
| 466 | + buyCount += 3; |
| 467 | + } |
| 468 | + else if (link.length === 2) { |
| 469 | + titleDom.textContent = '对对碰' |
| 470 | + subtitleDom.textContent = '加赠1只' |
| 471 | + buyCount += 1; |
| 472 | + } |
| 473 | + else if (link.length === 0) { |
| 474 | + titleDom.textContent = '清台' |
| 475 | + subtitleDom.textContent = '加赠5只' |
| 476 | + buyCount += 5; |
| 477 | + } |
| 478 | + else if (link.length === 1) { |
| 479 | + titleDom.textContent = '幸运色' |
| 480 | + subtitleDom.textContent = '加赠1只' |
| 481 | + buyCount += 1; |
| 482 | + } |
| 483 | + dom.classList.add('show') |
307 | 484 |
|
| 485 | + setTimeout(() => { |
| 486 | + dom.classList.remove('show') |
| 487 | + }, 1500) |
| 488 | + } |
| 489 | + unpack() |
308 | 490 |
|
309 | | - console.log(isTwin()); |
310 | 491 |
|
311 | 492 | </script> |
312 | 493 |
|
|
0 commit comments