-
Notifications
You must be signed in to change notification settings - Fork 2.4k
Open
Description
<title>Super Mini Mario Engine</title>
<style>
body { margin:0; background:#5c94fc; overflow:hidden; }
canvas { background:#87ceeb; display:block; margin:auto; }
.controls {
position:fixed; bottom:10px; width:100%;
display:flex; justify-content:space-between;
}
button { font-size:24px; padding:15px; opacity:0.7; }
</style>
⬅️
⤴️
➡️
<script>
// ================= BASIS =================
const canvas = document.getElementById("game");
const ctx = canvas.getContext("2d");
const gravity = 0.6;
let cameraX = 0;
// ================= SPIELSTATUS =================
let score = Number(localStorage.getItem("score")) || 0;
let lives = 3;
let gameOver = false;
let win = false;
// ================= SOUND =================
const audioCtx = new (window.AudioContext||window.webkitAudioContext)();
function sound(f){ const o=audioCtx.createOscillator();
o.frequency.value=f; o.connect(audioCtx.destination);
o.start(); o.stop(audioCtx.currentTime+0.1); }
// ================= SPIELER =================
const player = {
x:50,y:300,w:30,h:40,
dx:0,dy:0,
speed:4,jump:12,
grounded:false,
big:false, star:false
};
// ================= LEVEL =================
const level = {
width:4000,
platforms:[
{x:0,y:360,w:4000,h:60},
{x:300,y:280,w:120,h:20},
{x:700,y:240,w:120,h:20},
{x:1100,y:280,w:120,h:20}
],
blocks:[
{x:500,y:260,type:"coin",used:false},
{x:900,y:260,type:"mushroom",used:false},
{x:1300,y:260,type:"star",used:false}
],
coins:[
{x:320,y:250,c:false},
{x:720,y:210,c:false}
],
enemies:[
{x:600,y:330,w:30,h:30,dir:1,alive:true},
{x:1400,y:330,w:30,h:30,dir:-1,alive:true}
],
boss:{x:3500,y:300,w:60,h:60,hp:3}
};
// ================= INPUT =================
const keys={};
document.addEventListener("keydown",e=>{
if(e.code==="ArrowLeft")keys.left=true;
if(e.code==="ArrowRight")keys.right=true;
if(e.code==="Space")jump();
});
document.addEventListener("keyup",e=>{
if(e.code==="ArrowLeft")keys.left=false;
if(e.code==="ArrowRight")keys.right=false;
});
function jump(){
if(player.grounded){
player.dy=-player.jump;
player.grounded=false;
sound(600);
}
}
// ================= UPDATE =================
function update(){
if(gameOver||win) return;
player.dx = keys.left?-player.speed:keys.right?player.speed:0;
player.dy += gravity;
player.x += player.dx;
player.y += player.dy;
cameraX = Math.max(0,player.x-200);
player.grounded=false;
level.platforms.forEach(p=>{
if(player.x+player.w>p.x &&
player.x=p.y){
player.y=p.y-player.h;
player.dy=0;
player.grounded=true;
}
});
// Gegner
level.enemies.forEach(e=>{
if(!e.alive) return;
e.x+=e.dir*1.5;
if(e.x<0||e.x>level.width) e.dir*=-1;
if(collide(player,e)){
if(player.dy>0){
e.alive=false;
player.dy=-8;
score+=200;
sound(300);
}else if(!player.star){
hitPlayer();
}
}
});
// Boss
const b=level.boss;
if(b.hp>0 && collide(player,b)){
if(player.dy>0){
b.hp--; player.dy=-10; sound(200);
}else hitPlayer();
if(b.hp<=0){ win=true; sound(900); }
}
// Münzen
level.coins.forEach(c=>{
if(!c.c && pointHit(c.x,c.y)){
c.c=true; score+=50; sound(800);
}
});
// Blöcke
level.blocks.forEach(b=>{
if(!b.used &&
player.dy<0 &&
player.x+player.w>b.x &&
player.xb.y){
b.used=true;
activateBlock(b.type);
}
});
if(player.y>500) hitPlayer();
draw();
requestAnimationFrame(update);
}
function activateBlock(type){
if(type==="coin"){ score+=100; sound(700); }
if(type==="mushroom"){ player.big=true; player.h=60; sound(300); }
if(type==="star"){ player.star=true; setTimeout(()=>player.star=false,5000); sound(1000); }
}
function hitPlayer(){
lives--; sound(100);
player.x=50; player.y=300; player.dy=0;
if(lives<=0){ gameOver=true; localStorage.setItem("score",score); }
}
function collide(a,b){
return a.xb.x &&
a.yb.y;
}
function pointHit(x,y){
return player.xx &&
player.yy;
}
// ================= DRAW =================
function draw(){
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.save();
ctx.translate(-cameraX,0);
ctx.fillStyle="#228B22";
level.platforms.forEach(p=>ctx.fillRect(p.x,p.y,p.w,p.h));
ctx.fillStyle="gold";
level.coins.forEach(c=>!c.c&&(
ctx.beginPath(),ctx.arc(c.x,c.y,8,0,Math.PI*2),ctx.fill()
));
ctx.fillStyle="brown";
level.enemies.forEach(e=>e.alive&&ctx.fillRect(e.x,e.y,e.w,e.h));
ctx.fillStyle="purple";
if(level.boss.hp>0)
ctx.fillRect(level.boss.x,level.boss.y,level.boss.w,level.boss.h);
ctx.fillStyle="orange";
level.blocks.forEach(b=>ctx.fillRect(b.x,b.y,30,30));
ctx.fillStyle=player.star?"yellow":"red";
ctx.fillRect(player.x,player.y,player.w,player.h);
ctx.restore();
ctx.fillStyle="black";
ctx.fillText("Score: "+score,10,20);
ctx.fillText("Leben: "+lives,10,40);
if(gameOver) ctx.fillText("GAME OVER",420,200);
if(win) ctx.fillText("YOU WIN 👑",420,200);
}
update();
</script>
Metadata
Metadata
Assignees
Labels
No labels