キーダウンイベントに対応した、流れ星のアニメーションを適切に制御する。

js

1let canvas, ctx, w, h, moon, stars = [], meteors = [];2let isMeteorAnimationEnabled = false; 3function init() {4 canvas = document.querySelector("#canvas");5 ctx = canvas.getContext("2d");6 resizeReset();7 moon = new Moon();8 for (let a = 0; a < w * h * 0.0001; a++) {9 stars.push(new Star());10 }11 12 animationLoop();13}14 15function keydown() {16 if (isMeteorAnimationEnabled) {17 isMeteorAnimationEnabled = false;18 } else {19 for (let b = 0; meteors.length < 2; b++) {20 meteors.push(new Meteor());21 }22 isMeteorAnimationEnabled = true;23 }24}25function resizeReset() {26 w = canvas.width = window.innerWidth;27 h = canvas.height = window.innerHeight;28}29 30function animationLoop() {31 ctx.clearRect(0, 0, w, h);32 drawScene();33 requestAnimationFrame(animationLoop);34}35 36function drawScene() {37 moon.draw();38 stars.map((star) => {39 star.update();40 star.draw();41 });42 meteors.map((meteor) => {43 meteor.update();44 meteor.draw();45 });46}47 48class Moon {49 constructor() {50 this.x = 150;51 this.y = 150;52 this.size = 100;53 }54 draw() {55 ctx.save();56 ctx.beginPath();57 ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);58 ctx.shadowColor = "rgba(254, 247, 144, .7)";59 ctx.shadowBlur = 70;60 ctx.fillStyle = "rgba(254, 247, 144, 1)";61 ctx.fill();62 ctx.closePath();63 ctx.restore();64 }65}66 67class Star {68 constructor() {69 this.x = Math.random() * w;70 this.y = Math.random() * h;71 this.size = Math.random() + 0.5;72 this.blinkChance = 0.005;73 this.alpha = 1;74 this.alphaChange = 0;75 }76 draw() {77 ctx.beginPath();78 ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);79 ctx.fillStyle = `rgba(255, 255, 255, ${this.alpha})`;80 ctx.fill();81 ctx.closePath();82 }83 update() {84 if (this.alphaChange === 0 && Math.random() < this.blinkChance) {85 this.alphaChange = -1;86 } else if (this.alphaChange !== 0) {87 this.alpha += this.alphaChange * 0.05;88 if (this.alpha <= 0) {89 this.alphaChange = 1;90 } else if (this.alpha >= 1) {91 this.alphaChange = 0;92 }93 }94 }95}96 97class Meteor {98 constructor() {99 this.reset();100 }101 reset() {102 this.x = Math.random() * w + 300; 103 this.y = -100;104 this.size = Math.random() * 2 + 0.5;105 this.speed = (Math.random() + 0.5) * 15;106 }107 draw() {108 ctx.save();109 ctx.strokeStyle = "rgba(255, 255, 255, .1)";110 ctx.lineCap = "round";111 ctx.shadowColor = "rgba(255, 255, 255, 1)";112 ctx.shadowBlur = 10;113 for (let i = 0; i < 10; i++) {114 ctx.beginPath();115 ctx.moveTo(this.x, this.y);116 ctx.lineWidth = this.size;117 ctx.lineTo(this.x + 10 * (i + 1), this.y - 10 * (i + 1));118 ctx.stroke();119 ctx.closePath();120 }121 ctx.restore();122 }123 update() {124 if (this.y < h + 100) {125 this.x -= this.speed;126 this.y += this.speed;127 } else if (isMeteorAnimationEnabled) {128 this.reset();129 }130 }131}132 133window.addEventListener("DOMContentLoaded", init);134window.addEventListener("keydown", keydown);135window.addEventListener("resize", resizeReset);

コメントを投稿

0 コメント