Mudanças entre as edições de "Widget:IbNolandPuzzle"

De Wiki Gla
Ir para navegação Ir para pesquisar
(feat: noland puzzle v1)
 
(refactor: change some tittles to portuguese as default)
 
Linha 1: Linha 1:
<div id="ib-game-container">
<div id="ib-game-container">
   <div id="ib-start-screen">
   <div id="ib-start-screen">
     <button id="ib-play-btn">Play</button>
     <button id="ib-play-btn">Jogar</button>
   </div>
   </div>
   <div id="ib-end-screen">
   <div id="ib-end-screen">
     <p>You Win</p>
     <p>XTRANHO</p>
   </div>
   </div>
   <canvas id="ib-gameCanvas"></canvas>
   <canvas id="ib-gameCanvas"></canvas>

Edição atual tal como às 17h35min de 5 de abril de 2026

   <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>