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">
<title>π₯
Trampoline Goals</title>
Don't drop any items, and bounce them into the goal <br>
<canvas style='background:linear-gradient(blue, white);border-radius:3px;'
id='canvas' height=500 width=500></canvas> <br>
<button id="ArrowLeft">←</button><button id="ArrowRight">→</button>
<style> button {width:240px;margin:5px; height:130px;font-size:70px;} </style>
<script>
var people = [..."πΊπ€Ύπ§π§βπ€ΈπππβΉβ·πΆπ«"], fruits = [..."πππππ"], drinks = [..."π·πΈπΉπΊ"],
animals = [..."ππ
πππ"], vehicles = [..."ππππππ"];
var levels = [vehicles, animals, drinks, fruits, people];
var item_positions = [ {y: 100, speed_y: 100}, {y: 410, speed_y: -200}, {y: 10, speed_y: -20},
{y: 25, speed_y: 40}, {y: 200, speed_y: -140}, {y: 70, speed_y: -80} ];
var game = {level:0, over: false};
var drawing = canvas.getContext("2d");
Object.assign(drawing, {textAlign: "center", textBaseline: "middle", font: "30px serif"});
var gravity = 50,
deceleration = 2,
bat = {x: 10, y: 480, width: 130, height: 10, speed_y: 0, speed_x: 0},
balls = [],
goal = {x: canvas.width-50, y: 400, symbol: "π₯
", height:30, width: 30};
keys_down = {}, frame = {};
onkeydown = (e) => {keys_down[e.key] = true;}
onkeyup = (e) => {keys_down[e.key]= false;}
[ArrowLeft, ArrowRight].forEach(button=>{
button.addEventListener("pointerdown", () => {keys_down[button.id] = true});
button.addEventListener("pointerup", ()=>{keys_down[button.id] = false});
button.addEventListener("pointerleave", ()=>{keys_down[button.id] = false});
});
function text(string,x,y,size=30){
drawing.font = size+"px sans-serif";
drawing.fillText(string,x,y);
}
var next_level = (level)=>{
if (level > levels.length) return game.over = "You won!";
var positions = item_positions.slice(0,game.level+1).sort((a,b)=>b.speed_y-a.speed_y);
for (var i = 0; i < positions.length; i++){
var ball = {width: 30, height:30, speed_x: 0, symbol: levels[game.level-1][i]};
balls.push({x: 10+ i *80, ...positions[i], ...ball});
};
bat.x = bat.speed_x = 3;
game.time_left = balls.length * 40;
}
var rectangle_hit=(a,b)=> (a.x < b.right && b.x< a.right && a.y < b.bottom && b.y < a.bottom);
var hits_bat = (item) => {
if (rectangle_hit(item, bat)){
var y_overlap = bat.y - item.y;
var x_overlap = Math.max(bat.x - item.x, (item.x + item.width) - (bat.x + bat.width));
if (y_overlap > x_overlap) return "top";
else return "side";
}
}
function round_rectangle(x,y,width,height, corner_radius, stroke_colour, fill_colour){
drawing.beginPath();
drawing.lineWidth = 3;
if (stroke_colour) drawing.strokeStyle = stroke_colour;
if (fill_colour) drawing.fillStyle = fill_colour;
drawing.roundRect(x, y, width, height, [corner_radius]);
if (fill_colour) drawing.fill();
if (stroke_colour) drawing.stroke();
}
requestAnimationFrame(function do_one_frame(now) {
drawing.clearRect(0,0, canvas.width, canvas.height);
frame.interval = frame.last_time ? (now - frame.last_time) / 1000 : 0.016;
frame.last_time = now;
if (keys_down.ArrowLeft) bat.speed_x -= 800 * frame.interval;
else if (keys_down.ArrowRight) bat.speed_x += 800 * frame.interval;
else bat.speed_x -= (bat.speed_x * deceleration * frame.interval);
[bat, goal, ...balls].forEach(i => {
if (i !== bat && i !== goal) i.speed_y += gravity * frame.interval;
if (i.y > canvas.height) game.over = "Dropped item";
if (i.x < 0 && i.speed_x < 0) i.speed_x *= -1;
else if (i.x + i.width > canvas.width && i.speed_x > 0) i.speed_x *= -1;
if (i.speed_x) i.x += i.speed_x * frame.interval;
if (i.speed_y) i.y += i.speed_y * frame.interval;
i.right = i.x + i.width;
i.bottom = i.y + i.height;
if (i !== bat && i.speed_y > 0 && hits_bat(i)) {
if (hits_bat(i) == "top") {
i.speed_y = -210;
i.speed_x += (bat.speed_x - i.speed_x) * 0.5;
}
else i.speed_x = bat.speed_x;
}
if (i !== goal && rectangle_hit(i, goal)) i.deleted = true;
if (i == bat) round_rectangle(i.x, i.y, i.width, i.height, 10, "green", "black");
else text(i.symbol, i.x + i.width/2, i.y + i.height/2, 30);
if (i == goal) round_rectangle(i.x-10, i.y-10, i.width+20, i.height+20, 15, "green");
});
balls = balls.filter(b=>!b.deleted);
if (balls.length == 0) next_level(++game.level);
if ((game.time_left -= frame.interval) <= 0) game.over = "Out of time";
if (game.over) text("Game Over: "+game.over, 250, 250, 40);
else requestAnimationFrame(do_one_frame);
text("Time Left", 35, 20, 16);
round_rectangle(80, 10, Math.ceil(game.time_left*1.5), 20, 5, null, "green");
});
</script>