微件:GGLScratchGame:修订间差异
来自Limbo Wiki Mirror
无编辑摘要 标签:(旧)WikiEditor |
无编辑摘要 标签:(旧)WikiEditor |
||
| 第11行: | 第11行: | ||
点击灰色区域揭示内容,全部揭示后才能扫描。 | 点击灰色区域揭示内容,全部揭示后才能扫描。 | ||
</div> | </div> | ||
<div class="ggl- | <div class="ggl-remaining"> | ||
剩余彩票:<span id="ggl-ticket- | 剩余彩票:<span id="ggl-ticket-left"></span> | ||
</div> | </div> | ||
</div> | </div> | ||
| 第53行: | 第53行: | ||
/* 顶部 */ | /* 顶部 */ | ||
.ggl-top { | .ggl-top { | ||
position: absolute; | |||
top: 0; | |||
left: 0; | |||
width: 100%; | |||
height: 30%; | |||
padding: 10px; | |||
box-sizing: border-box; | |||
} | } | ||
.ggl-rules { | .ggl-rules { | ||
font-size: | font-size: 14px; | ||
opacity: .8; | opacity: .8; | ||
} | } | ||
.ggl-remaining { | |||
margin-top: 6px; | |||
font-size: 16px; | |||
font-weight: bold; | |||
} | |||
.ggl-tickets-left { | .ggl-tickets-left { | ||
font-size: 14px; | font-size: 14px; | ||
| 第185行: | 第199行: | ||
(function () { | (function () { | ||
/******************** | |||
* 全局状态 | |||
********************/ | |||
const gameState = { | |||
totalTickets: 11, | |||
currentTicket: 1, | |||
totalCells: 30, | |||
revealedCells: 0, | |||
started: false, | |||
data: 0 | |||
}; | |||
/******************** | |||
* DOM | |||
********************/ | |||
const grid = document.querySelector('.ggl-grid'); | const grid = document.querySelector('.ggl-grid'); | ||
const bubble = document.querySelector('.ggl-bubble'); | const bubble = document.querySelector('.ggl-bubble'); | ||
const mascot = document.querySelector('.ggl-mascot'); | const mascot = document.querySelector('.ggl-mascot'); | ||
const scanBtn = document.getElementById('ggl-scan'); | const scanBtn = document.getElementById('ggl-scan'); | ||
const ticketLeftEl = document.getElementById('ggl-ticket-left'); | |||
const startMask = document.getElementById('ggl-start-mask'); | |||
/* | mascot.style.color = '#000'; | ||
const TICKETS = | |||
{ | /******************** | ||
mascot: | * 彩票剧情表(核心) | ||
********************/ | |||
const TICKETS = { | |||
1: { | |||
mascot: '(^▽^)', | |||
text: '欢迎,先来三张试试吧。', | |||
rewards: ['DATA', 'EMPTY', 'EMPTY'] | |||
}, | }, | ||
{ | 2: { | ||
mascot: | mascot: '(ノ◕ヮ◕)ノ', | ||
text: '四个字可以连在一起。', | |||
rewards: ['DATA','DATA','DATA','DATA'] | |||
}, | }, | ||
{ | 3: { | ||
mascot: | mascot: '(・∀・)', | ||
text: '中了刮刮乐!+1 Data', | |||
rewards: ['DATA'] | |||
}, | }, | ||
{ | 4: { | ||
mascot: | mascot: '(・_・)', | ||
text: '什么都没中。', | |||
rewards: [] | |||
}, | }, | ||
{ | 5: { | ||
mascot: | mascot: '(;゚Д゚)', | ||
text: '不对劲……又中了 Data。', | |||
rewards: ['DATA'] | |||
}, | }, | ||
{ | 6: { | ||
mascot: | mascot: '', | ||
text: '什么都没有。', | |||
rewards: [] | |||
}, | }, | ||
{ | 7: { | ||
mascot: | mascot: '...', | ||
text: '▒▓░▒▓░▒▓', | |||
rewards: ['DATA'] | |||
}, | }, | ||
{ | 8: { | ||
mascot: | mascot: '(^▽^)', | ||
text: '中了两张 Data!', | |||
rewards: ['DATA','DATA'] | |||
}, | }, | ||
{ | 9: { | ||
mascot: | mascot: '(・_・)', | ||
text: '……全部都是 Data?', | |||
rewards: Array(30).fill('DATA') | |||
}, | }, | ||
{ | 10: { | ||
mascot: | mascot: '(;゚Д゚)', | ||
text: '停下来。', | |||
rewards: [], | |||
lock: true | lock: true | ||
}, | }, | ||
{ | 11: { | ||
mascot: | mascot: '平安喜乐', | ||
text: '你知道的太多了。', | |||
rewards: [], | |||
end: true | end: true | ||
} | } | ||
]; | }; | ||
/******************** | |||
* 奖项坐标生成 | |||
********************/ | |||
function buildRewardMap(ticket) { | |||
const map = Array(30).fill('EMPTY'); | |||
const rewards = TICKETS[ticket].rewards || []; | |||
rewards.forEach((r, i) => map[i] = r); | |||
return map; | |||
} | |||
/******************** | |||
* UI 刷新 | |||
********************/ | |||
function updateTopUI() { | |||
if (!ticketLeftEl) return; | |||
ticketLeftEl.textContent = | |||
gameState.totalTickets - gameState.currentTicket + 1; | |||
} | |||
function updateMascot(ticket) { | |||
mascot.textContent = TICKETS[ticket].mascot || ''; | |||
bubble.textContent = TICKETS[ticket].text || ''; | |||
} | |||
function | /******************** | ||
grid.innerHTML = | * 构建 30 格 | ||
********************/ | |||
scanBtn.classList.remove( | function buildGrid(ticket) { | ||
grid.innerHTML = ''; | |||
gameState.revealedCells = 0; | |||
scanBtn.classList.remove('active'); | |||
const | const rewardMap = buildRewardMap(ticket); | ||
const locked = TICKETS[ticket].lock; | |||
for (let i = 0; i < 30; i++) { | for (let i = 0; i < 30; i++) { | ||
const cell = document.createElement('div'); | const cell = document.createElement('div'); | ||
cell.className = | cell.className = 'ggl-cell'; | ||
cell.innerHTML = ` | cell.innerHTML = ` | ||
<img | <img src="https://wm.gaoice.run/images/thumb/4/4a/%E5%88%AE%E5%BC%80%E5%90%8E.jpg/180px-%E5%88%AE%E5%BC%80%E5%90%8E.jpg"> | ||
<div class="ggl-reward">${rewardMap[i] === 'DATA' ? 'DATA' : ''}</div> | |||
<div class="ggl- | <div class="ggl-cover"></div> | ||
< | |||
`; | `; | ||
cell.addEventListener('click', () => { | const cover = cell.querySelector('.ggl-cover'); | ||
if (!locked) { | |||
cover.addEventListener('click', () => { | |||
if (cell.dataset.done) return; | |||
cell.dataset.done = '1'; | |||
cover.style.opacity = '0'; | |||
gameState.revealedCells++; | |||
if (rewardMap[i] === 'DATA') { | |||
gameState.data++; | |||
} | |||
if (gameState.revealedCells >= gameState.totalCells) { | |||
scanBtn.classList.add('active'); | |||
bubble.textContent = '可以扫描了。'; | |||
} | } | ||
} | }); | ||
} | |||
grid.appendChild(cell); | grid.appendChild(cell); | ||
| 第300行: | 第356行: | ||
} | } | ||
/******************** | |||
* 下一张彩票 | |||
********************/ | |||
function nextTicket() { | |||
gameState.currentTicket++; | |||
updateTopUI(); | |||
if (gameState.currentTicket > gameState.totalTickets) return; | |||
if (gameState.currentTicket === 11) { | |||
document.body.style.filter = 'invert(1)'; | |||
bubble.style.background = '#000'; | |||
bubble.style.color = 'red'; | |||
} | |||
updateMascot(gameState.currentTicket); | |||
buildGrid(gameState.currentTicket); | |||
} | |||
/******************** | |||
* 扫描按钮 | |||
********************/ | |||
scanBtn.addEventListener('click', () => { | scanBtn.addEventListener('click', () => { | ||
if (!scanBtn.classList.contains( | if (!scanBtn.classList.contains('active')) return; | ||
bubble.textContent = '扫描中……'; | |||
setTimeout(() => { | |||
if (TICKETS[gameState.currentTicket].end) { | |||
location.href = '/index.php?title=六世恶言之一'; | |||
} | } else { | ||
nextTicket(); | |||
} | |||
}, 800); | |||
}); | }); | ||
/******************** | |||
* 初始化遮罩 | |||
********************/ | |||
}); | if (startMask) { | ||
startMask.addEventListener('click', () => { | |||
startMask.remove(); | |||
gameState.started = true; | |||
updateTopUI(); | |||
updateMascot(1); | |||
buildGrid(1); | |||
}); | |||
} else { | |||
updateTopUI(); | |||
updateMascot(1); | |||
buildGrid(1); | |||
} | |||
})(); | })(); | ||
</script> | </script> | ||
2026年2月1日 (日) 19:35的版本
点击灰色区域揭示内容,全部揭示后才能扫描。
剩余彩票:
<img class="ggl-bg"
src="
">
<button id="ggl-scan">扫描结果</button>
<style> .ggl-frame {
max-width: 420px; margin: 20px auto; padding: 10px; border: 2px solid #333; background: #111; color: #eee; font-family: sans-serif;
}
/* 顶部 */ .ggl-top {
position: absolute; top: 0; left: 0; width: 100%; height: 30%; padding: 10px; box-sizing: border-box;
}
.ggl-rules {
font-size: 14px; opacity: .8;
}
.ggl-remaining {
margin-top: 6px; font-size: 16px; font-weight: bold;
}
.ggl-tickets-left {
font-size: 14px; margin-top: 4px;
}
/* 彩票 */ .ggl-root {
position: relative; width: 100%; aspect-ratio: 1075 / 1911;
}
.ggl-bg {
width: 100%; display: block;
}
/* 刮奖区 */ .ggl-scratch-area {
position: absolute; left: 10%; top: 35%; width: 80%; height: 53%;
}
.ggl-grid {
display: grid; grid-template-columns: repeat(5, 1fr); grid-template-rows: repeat(6, 1fr); gap: 4px; width: 100%; height: 100%;
}
/* 单格 */ .ggl-cell {
position: relative; cursor: pointer;
}
.ggl-cover, .ggl-reveal {
position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none;
}
.ggl-cover {
z-index: 3;
} .ggl-reveal {
z-index: 1;
}
/* 奖项层 */ .ggl-prize {
position: absolute; inset: 0; z-index: 2; display: flex; align-items: center; justify-content: center; font-size: 12px; color: #000; text-align: center; pointer-events: none;
}
/* 吉祥物 & 气泡 */ .ggl-mascot {
position: absolute; left: 6%; top: 105%; bottom: 8%; font-size: 20px; color: #000;
}
.ggl-bubble {
position: absolute; left: 6%; bottom: 14%; top: 100%; width: 60%; background: rgba(255,255,255,.9); color: #000; padding: 6px; font-size: 13px;
}
/* 扫描 */ .ggl-controls {
position: absolute; right: 6%; bottom: 8%;
}
- ggl-scan {
opacity: .3;
}
- ggl-scan.active {
opacity: 1;
}
/* 遮罩 */ .ggl-overlay {
position: absolute; inset: 0; background: rgba(0,0,0,.9); z-index: 50; display: flex; align-items: center; justify-content: center;
}
.ggl-start-btn {
padding: 12px 24px; font-size: 16px;
} </style> <script> (function () {
/********************
* 全局状态
********************/
const gameState = {
totalTickets: 11,
currentTicket: 1,
totalCells: 30,
revealedCells: 0,
started: false,
data: 0
};
/********************
* DOM
********************/
const grid = document.querySelector('.ggl-grid');
const bubble = document.querySelector('.ggl-bubble');
const mascot = document.querySelector('.ggl-mascot');
const scanBtn = document.getElementById('ggl-scan');
const ticketLeftEl = document.getElementById('ggl-ticket-left');
const startMask = document.getElementById('ggl-start-mask');
mascot.style.color = '#000';
/********************
* 彩票剧情表(核心)
********************/
const TICKETS = {
1: {
mascot: '(^▽^)',
text: '欢迎,先来三张试试吧。',
rewards: ['DATA', 'EMPTY', 'EMPTY']
},
2: {
mascot: '(ノ◕ヮ◕)ノ',
text: '四个字可以连在一起。',
rewards: ['DATA','DATA','DATA','DATA']
},
3: {
mascot: '(・∀・)',
text: '中了刮刮乐!+1 Data',
rewards: ['DATA']
},
4: {
mascot: '(・_・)',
text: '什么都没中。',
rewards: []
},
5: {
mascot: '(;゚Д゚)',
text: '不对劲……又中了 Data。',
rewards: ['DATA']
},
6: {
mascot: ,
text: '什么都没有。',
rewards: []
},
7: {
mascot: '...',
text: '▒▓░▒▓░▒▓',
rewards: ['DATA']
},
8: {
mascot: '(^▽^)',
text: '中了两张 Data!',
rewards: ['DATA','DATA']
},
9: {
mascot: '(・_・)',
text: '……全部都是 Data?',
rewards: Array(30).fill('DATA')
},
10: {
mascot: '(;゚Д゚)',
text: '停下来。',
rewards: [],
lock: true
},
11: {
mascot: '平安喜乐',
text: '你知道的太多了。',
rewards: [],
end: true
}
};
/********************
* 奖项坐标生成
********************/
function buildRewardMap(ticket) {
const map = Array(30).fill('EMPTY');
const rewards = TICKETS[ticket].rewards || [];
rewards.forEach((r, i) => map[i] = r);
return map;
}
/********************
* UI 刷新
********************/
function updateTopUI() {
if (!ticketLeftEl) return;
ticketLeftEl.textContent =
gameState.totalTickets - gameState.currentTicket + 1;
}
function updateMascot(ticket) {
mascot.textContent = TICKETS[ticket].mascot || ;
bubble.textContent = TICKETS[ticket].text || ;
}
/********************
* 构建 30 格
********************/
function buildGrid(ticket) {
grid.innerHTML = ;
gameState.revealedCells = 0;
scanBtn.classList.remove('active');
const rewardMap = buildRewardMap(ticket); const locked = TICKETS[ticket].lock;
for (let i = 0; i < 30; i++) {
const cell = document.createElement('div');
cell.className = 'ggl-cell';
cell.innerHTML = `
<img src="
">
${rewardMap[i] === 'DATA' ? 'DATA' : }
`;
const cover = cell.querySelector('.ggl-cover');
if (!locked) {
cover.addEventListener('click', () => {
if (cell.dataset.done) return;
cell.dataset.done = '1';
cover.style.opacity = '0';
gameState.revealedCells++;
if (rewardMap[i] === 'DATA') {
gameState.data++;
}
if (gameState.revealedCells >= gameState.totalCells) {
scanBtn.classList.add('active');
bubble.textContent = '可以扫描了。';
}
});
}
grid.appendChild(cell); } }
/********************
* 下一张彩票
********************/
function nextTicket() {
gameState.currentTicket++;
updateTopUI();
if (gameState.currentTicket > gameState.totalTickets) return;
if (gameState.currentTicket === 11) {
document.body.style.filter = 'invert(1)';
bubble.style.background = '#000';
bubble.style.color = 'red';
}
updateMascot(gameState.currentTicket); buildGrid(gameState.currentTicket); }
/********************
* 扫描按钮
********************/
scanBtn.addEventListener('click', () => {
if (!scanBtn.classList.contains('active')) return;
bubble.textContent = '扫描中……';
setTimeout(() => {
if (TICKETS[gameState.currentTicket].end) {
location.href = '/index.php?title=六世恶言之一';
} else {
nextTicket();
}
}, 800);
});
/********************
* 初始化遮罩
********************/
if (startMask) {
startMask.addEventListener('click', () => {
startMask.remove();
gameState.started = true;
updateTopUI();
updateMascot(1);
buildGrid(1);
});
} else {
updateTopUI();
updateMascot(1);
buildGrid(1);
}
})(); </script>
