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=525">
<title>π¦ Fox Ache</title>
<div id='instructions'>You are π, stop π¦ from eating πππππ¦π¦. Press an arrow to start</div>
<div id='time_left' style='display:inline-block;background:#6688aa;'>Time Left</div><br>
<div id="field" style='background:#338833;display:inline-block;padding:0px;font-size:0px;'>
<canvas id='canvas' width=500 height=500
style='border:9px dashed brown;border-radius:50px;'></canvas>
</div>
<canvas id='sprite_canvas' style='display:none;' width=1760 height=80></canvas>
<div id='arrows' style='width:516px;border:2px outset;'></div>
<style>*, html{-webkit-user-select:none;touch-action:none;user-select:none;</style>
<script>
var livestock = [..."πππππ¦π¦"], plants = [..."πππ»π»πΌπΌπΎπΎπ΅π³π΄π²"];
var dog = {symbol: "π", x: 200, y: 300, radius: 25, speed_x:0, speed_y: 0};
var items = [dog], keys={}, start_time = false, last_time = false, game_started = false;
var drawing = canvas.getContext("2d"),
sprite_drawing = sprite_canvas.getContext("2d");
Object.assign(sprite_drawing, {textAlign:"center", textBaseline:"middle", font:"60px serif"});
var press = onkeydown =(e)=>{
keys[e.key] = true;
if (e.key.startsWith("Arrow") && e.preventDefault) e.preventDefault();
if (!game_started) game_started = e.key.startsWith("Arrow");
};
onkeyup = (e) =>{ keys[e.key] = false };
arrows.innerHTML = [["Up","β"], ["Left","β"], ["Down","β"], ["Right","β"]].map((key,index)=>{
var style=`height:60px; width:60px; margin:5px ${index==0 ? '220px;':'52px;'};`;
return `<button style='${style}' name='Arrow${key[0]}'>${key[1]}</button> `;
}).join("");
arrows.addEventListener("touchstart", (e)=>{
if (e.target.name) press({key:e.target.name});
e.preventDefault();
});
arrows.addEventListener("touchend", (e)=>{if (e.target.name) keys[e.target.name] =false});
arrows.addEventListener("touchcancel", (e)=>{if (e.target.name) keys[e.target.name] =false});
var sprite_indexes = {};
[..."ππ¦πππππππππππ¦π¦π²π³π΄π΅πΎπ»πΌπ"].forEach((symbol,index)=>{
sprite_drawing.fillText(symbol, index * 80 + 40, 40);
sprite_indexes[symbol] = index;
});
var hit=(a,b)=>Math.hypot(a.x - b.x, a.y - b.y) < a.radius + b.radius;
var box_collision=(a,b)=>{
if (a.x < b.right && b.x < a.right && a.y < b.bottom && b.y < a.bottom) {
if ((a.x < b.x && a.right - b.x < 20 && a.speed_x > 0) ||
(a.right > b.right && b.right - a.x < 20 && a.speed_x < 0)) return "x";
if ((a.y < b.y && a.bottom - b.y < 20 && a.speed_y > 0) ||
(a.bottom > b.bottom && b.bottom - a.y < 20 && a.speed_y < 0)) return "y";
}
}
var up_to=(max)=>Math.random()*max;
for (var i = 0; i < 6; i++)
items.unshift({
type:"livestock", symbol: livestock[i], radius: 15 + (i*2),
x: 150 + up_to(100), y: 150 + up_to(100),
speed_x: 5 - up_to(10), speed_y: 5 - up_to(10),
});
var foxes = [];
for (var fox = 0; fox < 50; fox++){
var x = (Math.random() > 0.5) ? canvas.width + 10 : -50;
var speed_x = x > 0 ? -(60 +fox): 60+fox;
var y = up_to(canvas.height);
var speed_y = y > canvas.height / 2 ? - (up_to(40 +fox)) : up_to(40+fox);
var delay = fox * (3000 - (fox*30));
foxes.push({symbol:"π¦", radius: 18, x, y, speed_x, speed_y, delay, fox:true});
}
plants.forEach((p,i)=>items.unshift({plant:p, x: up_to(500), y: up_to(500), radius: 12+i}));
var time_limit = foxes[foxes.length-1].delay + 5000;
requestAnimationFrame(function create_one_frame(now){
var interval = game_started ? Math.min(0.2, (now - last_time)/1000) : 0;
last_time = now;
start_time = game_started ? start_time || now : now;
if (interval > 0.1 && foxes.length) start_time = now - foxes[0]?.delay;
if (now - start_time > foxes[0]?.delay) items.push(foxes.shift());
time_left.style.width = Math.max(0, ((1 - (now - start_time) / time_limit) * 518)) + "px";
dog.speed_x += keys.ArrowRight? 1000 * interval : keys.ArrowLeft ? -1000 * interval: 0;
dog.speed_y += keys.ArrowDown? 1000 * interval : keys.ArrowUp ? -1000 * interval: 0;
["speed_x", "speed_y"].forEach(speed => dog[speed] -= dog[speed] * interval * 2);
drawing.clearRect(0,0, canvas.width, canvas.height);
items.forEach(i=>{
i.right = (i.x = i.x + (i.speed_x|0) * interval) + (i.radius*2);
i.bottom = (i.y = i.y + (i.speed_y|0) * interval) + (i.radius*2);
if (i.symbol || i.plant) {
drawing.globalAlpha = (i.plant) ? 0.5 : 1;
drawing.drawImage(sprite_canvas, (sprite_indexes[i.symbol || i.plant] * 80), 0,
80, 80, i.x, i.y, i.radius*2.2, i.radius*2.2);
}
if (i.fox) items.forEach(i2=>{if(i2.type=="livestock" && hit(i, i2)) i2.dead=true});
if (i != dog && box_collision(i,dog)) i["speed_"+box_collision(i,dog)] *= -1;
if (i.speed_x > 0 && i.right > canvas.width && !i.fox) i.speed_x *= -1;
if (i.speed_x < 0 && i.x < 0 && !i.fox) i.speed_x *= -1;
if (i.speed_y > 0 && i.bottom > canvas.height && !i.fox) i.speed_y *= -1;
if (i.speed_y < 0 && i.y < 0 && !i.fox) i.speed_y *= -1;
});
if (!items.some(i=>i.type=="livestock")) instructions.textContent= "Bad Dog. Game over";
else if (now > start_time + time_limit) instructions.textContent = "Good Dog. Relax";
requestAnimationFrame(create_one_frame);
items = items.filter(i=>(!i.dead && i.x > -1000 && i.x < 1000));
});
</script>