Widget:IbNolandPuzzle
Revisão de 17h35min de 5 de abril de 2026 por Igor is back (discussão | contribs) (refactor: change some tittles to portuguese as default)
<button id="ib-play-btn">Jogar</button>
XTRANHO
<canvas id="ib-gameCanvas"></canvas>
<style>
#ib-game-container { position: relative; display: inline-block; }
#ib-gameCanvas { display: block; image-rendering: pixelated; }
#ib-start-screen {
position: absolute; inset: 0; display: flex;
justify-content: center; align-items: center;
background: #1a1a2e; z-index: 10;
}
#ib-end-screen {
position: absolute; inset: 0; display: none;
justify-content: center; align-items: center;
background: rgba(0,0,0,0.85); z-index: 10;
color: #e2e2e2; font-size: 64px; letter-spacing: 8px;
}
#ib-play-btn {
padding: 16px 48px; font-size: 24px; cursor: pointer;
background: #16213e; color: #e2e2e2;
border: 2px solid #e2e2e2; letter-spacing: 4px;
}
</style>
<script> (function() {
const COLS = 7, ROWS = 5, TILE_SIZE = 128;
const canvas = document.getElementById('ib-gameCanvas');
const ctx = canvas.getContext('2d');
canvas.width = COLS * TILE_SIZE;
canvas.height = ROWS * TILE_SIZE;
const DIRS = {
ArrowRight: [1, 0, 0],
ArrowLeft: [-1, 0, 1],
ArrowUp: [0, -1, 2],
ArrowDown: [0, 1, 3]
};
const keys = {};
document.addEventListener('keydown', e => {
if (e.key === '1') { player.interact(); return; }
if (!(e.key in DIRS)) return;
e.preventDefault();
if (e.ctrlKey) { player.direction = DIRS[e.key][2]; return; }
keys[e.key] = true;
});
document.addEventListener('keyup', e => { keys[e.key] = false; });
const OBJECT_POS = [[1,0],[3,0],[5,0],[6,2],[5,4],[3,4],[1,4],[0,2]];
const ARTIFACT_COL = 3, ARTIFACT_ROW = 2;
const OBJECT_TILES = new Set([...OBJECT_POS.map(([c,r]) => `${c},${r}`), `${ARTIFACT_COL},${ARTIFACT_ROW}`]);
const mainSprite = new Image(); mainSprite.src = 'https://wiki.gla.com.br/images/3/30/Ib_noland_sprite.png';
const tileImage = new Image(); tileImage.src = 'https://wiki.gla.com.br/images/9/98/Ib_basic_tile.png';
class Character {
constructor(tileX, tileY) {
this.tileX = tileX; this.tileY = tileY;
this.x = tileX * TILE_SIZE; this.y = tileY * TILE_SIZE;
this.direction = 0; this.animFrame = 0;
this.moving = false; this.moveFrame = 0;
this.interactFrame = 0; this.cooldown = 0;
}
_startMove(dx, dy, dir) {
const nx = this.tileX + dx, ny = this.tileY + dy;
if (nx < 0 || nx >= COLS || ny < 0 || ny >= ROWS || OBJECT_TILES.has(`${nx},${ny}`)) return false;
this.direction = dir; this.tileX = nx; this.tileY = ny;
this.startX = this.x; this.startY = this.y;
this.targetX = nx * TILE_SIZE; this.targetY = ny * TILE_SIZE;
this.moving = true; this.moveFrame = 0;
return true;
}
tryMove() {
for (const key in DIRS)
if (keys[key] && this._startMove(...DIRS[key])) break;
}
_finishMove() {
this.x = this.targetX; this.y = this.targetY;
this.moving = false; this.animFrame = 0;
}
interact() {
if (this.cooldown > 0 || this.moving || this.interactFrame > 0) return;
const dx = [1,-1,0,0][this.direction], dy = [0,0,-1,1][this.direction];
const tx = this.tileX + dx, ty = this.tileY + dy;
if (tx === ARTIFACT_COL && ty === ARTIFACT_ROW) { if (artifact.open) endGame(); return; }
this.interactFrame = 1; this.cooldown = 60;
triggerPedestal(tx, ty);
}
_updateMove() {
this.moveFrame++;
this.x = this.startX + (this.targetX - this.startX) * this.moveFrame / 24;
this.y = this.startY + (this.targetY - this.startY) * this.moveFrame / 24;
this.animFrame = (Math.floor(this.moveFrame / 8) % 2) + 1;
if (this.moveFrame >= 24) this._finishMove();
}
update() {
if (this.cooldown > 0) this.cooldown--;
if (this.interactFrame > 0 && ++this.interactFrame > 24) this.interactFrame = 0;
if (this.interactFrame > 0) return;
if (!this.moving) { this.tryMove(); return; }
this._updateMove();
}
draw(ctx) {
const { direction: d, animFrame: f, interactFrame: i, x, y } = this;
const s = TILE_SIZE;
ctx.drawImage(mainSprite, (i > 0 ? 3 : f) * s, d * s, s, s, Math.round(x), Math.round(y), s, s);
}
}
class Artifact {
constructor() { this.tileX = ARTIFACT_COL; this.tileY = ARTIFACT_ROW; this.open = false; }
draw(ctx) {
const s = TILE_SIZE;
ctx.drawImage(mainSprite, (this.open ? s : 0), 4 * s, s, s, this.tileX * s, this.tileY * s, s, s);
}
}
class GameObject {
constructor(tileX, tileY) { this.tileX = tileX; this.tileY = tileY; this.active = false; }
draw(ctx) {
const s = TILE_SIZE;
const col = this.active ? (Math.floor(pedestalTick / 8) % 4 + 1) : 0;
ctx.drawImage(mainSprite, col * s, 5 * s, s, s, this.tileX * s, this.tileY * s, s, s);
}
}
const artifact = new Artifact(); const player = new Character(3, 3); const objects = OBJECT_POS.map(([c,r]) => new GameObject(c, r));
function drawTiles() {
for (let r = 0; r < ROWS; r++)
for (let c = 0; c < COLS; c++)
ctx.drawImage(tileImage, c * TILE_SIZE, r * TILE_SIZE, TILE_SIZE, TILE_SIZE);
}
function render() {
drawTiles();
artifact.draw(ctx);
objects.forEach(o => o.draw(ctx));
player.draw(ctx);
}
const MS_PER_UPDATE = 1000 / 60; let lastTime = 0, lag = 0, pedestalTick = 0;
function gameLoop(timestamp) {
lag += Math.min(timestamp - lastTime, 100);
lastTime = timestamp;
while (lag >= MS_PER_UPDATE) { player.update(); pedestalTick++; lag -= MS_PER_UPDATE; }
render();
requestAnimationFrame(gameLoop);
}
function triggerPedestal(col, row) {
if (artifact.open) return;
const idx = objects.findIndex(o => o.tileX === col && o.tileY === row);
if (idx === -1) return;
const n = objects.length;
[idx, (idx + 1) % n, (idx + n - 1) % n].forEach(i => { objects[i].active = !objects[i].active; });
if (objects.every(o => !o.active)) artifact.open = true;
}
function endGame() {
document.getElementById('ib-end-screen').style.display = 'flex';
setTimeout(() => location.reload(), 2000);
}
function randomizeObjects() {
objects.forEach(o => { o.active = Math.random() < 0.5; });
if (objects.every(o => !o.active)) objects[0].active = true;
}
let started = false, playClicked = false;
function tryStart() {
if (started || !playClicked || !tileImage.complete || !mainSprite.complete) return;
started = true;
lastTime = performance.now();
requestAnimationFrame(gameLoop);
}
tileImage.onload = tryStart; mainSprite.onload = tryStart;
document.getElementById('ib-play-btn').addEventListener('click', () => {
document.getElementById('ib-start-screen').style.display = 'none';
randomizeObjects();
playClicked = true;
tryStart();
});
})(); </script>