1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
<!doctype html>
<meta charset='utf-8'>
<meta name="viewport" content="width=520, user-scalable=no">
<title>🦟 Mozzie Mayhem</title>
<div id='info'>Move with arrows, shoot with WASD. Don't die. Shoot to start</div>
<canvas id='canvas' style='border:1px outset;background:radial-gradient(#889944 80%, green 90%, black);'
width=500 height=500></canvas>
<div id='buttons' style="width:500px;border:1px outset;touch-action:none;user-select:none;"></div>
<style> button{width:60px;height:60px;user-select:none;-webkit-user-select:none;}</style>
<script>
var drawing = canvas.getContext("2d");
Object.assign(drawing, {textAlign: "center", textBaseline: "middle", font: "40px serif"});
var player = {faces:"up", health:100, score:0, x:400, y:400, speed_x:0, speed_y:0, radius:20};
var items=[player], keys = {}, frame = {};
var acceleration_per_second = 800, friction = 2;
onkeydown=(e)=>{
keys[e.key.length == 1 ? e.key.toLowerCase() : e.key] = true;
if (e.key.startsWith("Arrow")) e.preventDefault();
}
onkeyup=(e)=>{ keys[e.key.length == 1 ? e.key.toLowerCase() : e.key] = false; }
["w",["↑","Up"],"a","s","d",["←","Left"],["↓","Down"],["→","Right"]].forEach((key,index)=>{
var button = buttons.appendChild(document.createElement("button"));
button.textContent = key[0].toUpperCase();
var event_key = key[1] ? "Arrow"+key[1] : key[0];
button.addEventListener("pointerdown", (e) => {keys[event_key]=true} );
button.onpointerup = button.onpointerleave=() => {keys[event_key]=false};
button.style.margin = (index < 2) ? "5px 90px" : "3px 10px";
});
function circle(x, y, radius, colour) {
drawing.fillStyle = colour;
drawing.beginPath();
drawing.arc(x, y, radius, 0, 2*Math.PI);
drawing.fill();
}
function shoot(direction, speed_x, speed_y, now=performance.now()) {
player.faces = direction;
var bullet = {...player, radius: 8, colour:"#ffcc00", created: now, type: "bullet"};
bullet.x += (direction == "down") ? -22 : (direction == "up") ? 22 : 0;
bullet.y += (direction == "right") ? 22 : (direction == "left") ? -22 : 0;
if ((items[0].created|0) < (now - 500)) items.unshift({...bullet, speed_x, speed_y});
if (!frame.started) frame.started = true;
};
function collides(a,b){ return Math.hypot(a.x-b.x, a.y-b.y) < a.radius + b.radius; }
function player_circle(x,y,radius,colour){circle(player.x +x, player.y +y, radius, colour);}
function draw_player(){
var circles = [ [12, 10, 6, "#662266"], [12, -10, 6, "#662266"],
[4, 20, 8, "#880000"], [4, -20, 8, "#880000"],
[0, 15, 10, "#225588"], [0 , -15, 10, "#225588"],
[0,0,15,"#000044"], [14,0, 3, "#000044"]];
if (player.faces == "left") circles.forEach(c=>c[0] *= -1);
else if (player.faces == "down") circles.forEach(c=>{ [c[0], c[1]] = [c[1], c[0]]; });
else if (player.faces == "up") circles.forEach(c=>{ [c[0], c[1]] = [c[1], -c[0]]; });
circles.forEach(c=>player_circle(...c));
}
var bug = {symbol:"🦟", x: -50, damage: 18, y: 0, speed_x: 0, speed_y: 0, radius: 20};
function add_bug(){ items.push({...bug, y: 800 - Math.random() * 1100, count:++bugs});}
var bugs = 0;
function in_range(item){return Math.hypot(item.x - player.x, item.y - player.y) < 1000}
(function do_frame(now=performance.now()) {
var interval = frame.started ? (now - frame.last_time)/1000 : 0;
frame.last_time = now;
if (!bugs || (frame.started && Math.random() < interval && bugs < 100)) add_bug();
var acceleration = acceleration_per_second * interval;
player.speed_x += keys.ArrowRight ? acceleration : keys.ArrowLeft ? -acceleration : 0;
player.speed_y += keys.ArrowDown ? acceleration : keys.ArrowUp ? -acceleration : 0;
if (keys.w) shoot("up", player.speed_x, player.speed_y -800);
if (keys.a) shoot("left", player.speed_x -800, player.speed_y);
if (keys.s) shoot("down", player.speed_x, player.speed_y + 800);
if (keys.d) shoot("right", player.speed_x + 800, player.speed_y);
drawing.clearRect(0,0,canvas.width, canvas.height);
draw_player();
items.forEach(i => {
if (i.symbol == "🦟") i.speed_x += (i.x < player.x ? 500*interval : -500*interval);
if (i.symbol == "🦟") i.speed_y += (i.y < player.y ? 500*interval : -500*interval);
i.x += i.speed_x * interval;
i.y += i.speed_y * interval;
if (i.type !== "bullet") i.speed_x -= i.speed_x * friction * interval;
if (i.type !== "bullet") i.speed_y -= i.speed_y * friction * interval;
items.filter(i2=>(i !== i2 && !i2.deleted && collides(i, i2))).forEach(i2=>{
if (i == player || i2 == player)
player.health -= ((i.damage|0+i2.damage|0)*interval);
else if ((i.damage && i2.type=="bullet") || (i2.damage && i.type=="bullet"))
i.deleted = i2.deleted = (player.score += 1);
});
if (i.symbol && !i.deleted) drawing.fillText(i.symbol, i.x, i.y);
else if (i !== player) circle(i.x, i.y, i.radius, i.colour || "red");
});
items = items.filter(item=>( (in_range(item) || item.symbol == "🦟") && !item.deleted) );
if (player.x > canvas.width && player.speed_x > 0) player.speed_x *= -0.5;
if (player.x < 0 && player.speed_x < 0) player.speed_x *= -0.5;
if (player.y > canvas.height && player.speed_y > 0) player.speed_y *= -0.5;
if (player.y < 0 && player.speed_y < 0) player.speed_y *= -0.5;
if (player.score < 100 && player.health > 0) requestAnimationFrame(do_frame);
if (!frame.started) return;
if (player.score >= 100) info.style.color = "green";
else info.style.color = (player.health < player.previous_health) ? "red" : "black";
player.previous_health = player.health = Math.max(0, player.health);
info.textContent = "Health: "+Math.ceil(player.health)+", Score: "+player.score + "/100";
})();
</script>