Skip to content

Latest commit

 

History

History
295 lines (277 loc) · 8.07 KB

File metadata and controls

295 lines (277 loc) · 8.07 KB
layout post
title Gamified Navigation
permalink /index3
sprite
image pixelWidth pixelHeight scale frames
/images/mario_animation.png
256
256
0.25
Rest RestL Walk Tada WalkL TadaL Run1 Run1L Run2 Run2L Puff PuffL Cheer CheerL Flip FlipL
row col frames
0
0
15
row col frames
1
0
15
row col frames
2
0
8
row col frames
2
11
3
row col frames
3
0
8
row col frames
3
11
3
row col frames
4
0
15
row col frames
5
0
15
row col frames
6
0
15
row col frames
7
0
15
row col frames
8
0
15
row col frames
9
0
15
row col frames
10
0
15
row col frames
11
0
15
row col frames
12
0
15
row col frames
13
0
15
sections
id label hotspot detail
hotspot-csse
CSSE
top left
40
40
id top left title content
section-csse
40
200
CSSE Detail
Computer Science and Software Engineering: JavaScript, OOP, algorithmic thinking, game dev projects.
id label hotspot detail
hotspot-csp
CSP
top left
240
40
id top left title content
section-csp
240
200
CSP Detail
Computer Science Principles: Python, algorithms, data, networks, impact of computing.
id label hotspot detail
hotspot-csa
CSA
top left
440
40
id top left title content
section-csa
440
200
CSA Detail
AP Computer Science A: Java, data structures, recursion, team projects, AP prep.

{% for s in page.sections %}

{{s.label}}
{% endfor %}

{% for s in page.sections %}

{{s.detail.title}}

{{s.detail.content}}

{% endfor %}

<style> #game-area { position: relative; width: 400px; height: 700px; margin: 60px auto; background: #55595dff; border-radius: 16px; box-shadow: 0 4px 24px #b6c6e6; } .sprite { width: {{page.sprite.pixelWidth}}px; height: {{page.sprite.pixelHeight}}px; background-image: url('{{page.sprite.image}}'); background-repeat: no-repeat; position: absolute; top: 20px; left: 20px; background-position: 0px 0px; z-index: 3; transform: scale({{page.sprite.scale}}); transform-origin: top left; } .hotspot { position: absolute; width: 120px; height: 48px; font-weight: bold; color: #2563eb; background: #e0e7ff; padding: 8px 16px; border-radius: 8px; z-index: 2; font-size: 1.2em; box-shadow: 0 2px 8px #b6c6e6; text-align: center; display: flex; align-items: center; justify-content: center; } .detail-section { position: absolute; display: none; border: 2px solid #2563eb; padding: 16px; background: #2758dfff; max-width: 160px; min-height: 48px; border-radius: 8px; z-index: 1; } </style> <script> // Sprite data: animation frames, pixel size, scale const sprite_data = {{ page.sprite | jsonify }}; // Hotspots data from frontmatter const hotspots = [ {% for s in page.sections %} {id: '{{s.id}}', section: '{{s.detail.id}}'}, {% endfor %} ]; class Sprite { constructor(sprite_data, hotspots) { this.tID = null; this.positionX = 40; this.positionY = 40; this.currentSpeed = 0; this.spriteElement = document.getElementById("sprite"); this.pixelsWidth = sprite_data.pixelWidth; this.pixelsHeight = sprite_data.pixelHeight; this.scale = sprite_data.scale; this.interval = 100; this.obj = sprite_data.frames; this.spriteElement.style.position = "absolute"; this.moving = false; this.direction = {x: 0, y: 0}; this.hotspots = hotspots; this.activeSection = null; this.currentAnim = 'Rest'; } animate(animName, speed) { let frame = 0; const obj = this.obj[animName]; const row = obj.row * this.pixelsHeight; this.currentAnim = animName; this.currentSpeed = speed; this.stopAnimate(); this.tID = setInterval(() => { const col = (frame + obj.col) * this.pixelsWidth; this.spriteElement.style.backgroundPosition = `-${col}px -${row}px`; this.positionX += speed * this.direction.x; this.positionY += speed * this.direction.y; this.spriteElement.style.left = `${this.positionX}px`; this.spriteElement.style.top = `${this.positionY}px`; frame = (frame + 1) % obj.frames; this.checkHotspots(); }, this.interval); } startWalkingRight() { this.direction = {x: 1, y: 0}; this.animate("Walk", 8); } startWalkingLeft() { this.direction = {x: -1, y: 0}; this.animate("WalkL", 8); } startWalkingDown() { this.direction = {x: 0, y: 1}; this.animate("Walk", 8); } startWalkingUp() { this.direction = {x: 0, y: -1}; this.animate("Walk", 8); } startResting() { this.direction = {x: 0, y: 0}; this.animate("Rest", 0); } stopAnimate() { clearInterval(this.tID); this.tID = null; } checkHotspots() { let collided = false; // Sprite is visually scaled down, so collision box must be scaled too for (const h of this.hotspots) { const el = document.getElementById(h.id); const hx = el.offsetLeft; const hy = el.offsetTop; const hw = el.offsetWidth; const hh = el.offsetHeight; const mx = this.positionX; const my = this.positionY; const mw = this.spriteElement.offsetWidth * this.scale; const mh = this.spriteElement.offsetHeight * this.scale; if ( mx < hx + hw && mx + mw > hx && my < hy + hh && my + mh > hy ) { document.getElementById(h.section).style.display = 'block'; this.activeSection = h.section; collided = true; } else { document.getElementById(h.section).style.display = 'none'; } } if (!collided) { this.activeSection = null; } } reset() { this.stopAnimate(); this.positionX = 40; this.positionY = 40; this.spriteElement.style.left = `40px`; this.spriteElement.style.top = `40px`; for (const h of this.hotspots) { document.getElementById(h.section).style.display = 'none'; } this.activeSection = null; this.startResting(); } } const sprite = new Sprite(sprite_data, hotspots); // Key press/release controls window.addEventListener("keydown", (event) => { if (event.repeat) return; if (event.key === "ArrowRight" || event.key === "d" || event.key === "D") { sprite.startWalkingRight(); } if (event.key === "ArrowLeft" || event.key === "a" || event.key === "A") { sprite.startWalkingLeft(); } if (event.key === "ArrowDown" || event.key === "s" || event.key === "S") { sprite.startWalkingDown(); } if (event.key === "ArrowUp" || event.key === "w" || event.key === "W") { sprite.startWalkingUp(); } if (event.key === "r" || event.key === "R") { sprite.reset(); } }); window.addEventListener("keyup", (event) => { if (["ArrowRight","ArrowLeft","ArrowDown","ArrowUp","d","a","s","w","D","A","S","W"].includes(event.key)) { sprite.stopAnimate(); sprite.startResting(); } }); // On page load, sprite rests window.addEventListener("DOMContentLoaded", () => { sprite.startResting(); }); </script>

Mario Gamified Navigation Example

Use arrow keys to move Mario. When Mario collides with CSSE, CSP, or CSA, the corresponding detail will expand. When Mario leaves the hotspot, the detail collapses. Press 'R' to reset Mario and hide all details.


This example uses your original Mario animation logic, organized layout, and dynamic hotspot reveals. You can further design and expand from here!