{"id":26298,"date":"2026-04-24T21:05:10","date_gmt":"2026-04-24T12:05:10","guid":{"rendered":"http:\/\/www.tyosuke20xx.com\/blog\/?p=26298"},"modified":"2026-04-24T21:05:13","modified_gmt":"2026-04-24T12:05:13","slug":"stggame-html","status":"publish","type":"post","link":"http:\/\/www.tyosuke20xx.com\/blog\/?p=26298","title":{"rendered":"STGGAME.html"},"content":{"rendered":"\n<pre class=\"wp-block-code\"><code>&lt;!DOCTYPE html>\n&lt;html lang=\"ja\">\n&lt;head>\n  &lt;meta charset=\"UTF-8\" \/>\n  &lt;meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" \/>\n  &lt;title>Bullet Hell STG Game&lt;\/title>\n  &lt;style>\n    * { box-sizing: border-box; }\n\n    body {\n      margin: 0;\n      min-height: 100vh;\n      background: radial-gradient(circle at top, #1f2b5c, #070915 70%);\n      display: flex;\n      align-items: center;\n      justify-content: center;\n      font-family: system-ui, sans-serif;\n      color: white;\n      overflow: hidden;\n    }\n\n    .wrap { text-align: center; }\n\n    h1 {\n      margin: 0 0 10px;\n      font-size: 28px;\n      letter-spacing: 0.08em;\n    }\n\n    canvas {\n      background: #050816;\n      border: 3px solid #ffffff33;\n      border-radius: 16px;\n      box-shadow: 0 20px 80px #000a;\n      display: block;\n    }\n\n    .info {\n      margin-top: 10px;\n      color: #dce6ff;\n      font-size: 14px;\n    }\n\n    .panel {\n      position: fixed;\n      top: 16px;\n      left: 50%;\n      transform: translateX(-50%);\n      display: flex;\n      gap: 20px;\n      background: #0008;\n      border: 1px solid #fff2;\n      padding: 8px 16px;\n      border-radius: 999px;\n      backdrop-filter: blur(8px);\n      font-weight: 700;\n    }\n  &lt;\/style>\n&lt;\/head>\n&lt;body>\n  &lt;div class=\"panel\">\n    &lt;div>Score: &lt;span id=\"score\">0&lt;\/span>&lt;\/div>\n    &lt;div>HP: &lt;span id=\"hp\">5&lt;\/span>&lt;\/div>\n    &lt;div>Power: &lt;span id=\"power\">1&lt;\/span>&lt;\/div>\n  &lt;\/div>\n\n  &lt;div class=\"wrap\">\n    &lt;h1>BULLET STORM&lt;\/h1>\n    &lt;canvas id=\"game\" width=\"480\" height=\"640\">&lt;\/canvas>\n    &lt;div class=\"info\">\u79fb\u52d5: WASD \/ \u65b9\u5411\u30ad\u30fc\u3000\u30b7\u30e7\u30c3\u30c8: Space\u3000\u30d1\u30ef\u30fc\u30a2\u30c3\u30d7\u3092\u53d6\u308b\u3068\u5f3e\u304c\u5f37\u5316\u3000\u30ea\u30b9\u30bf\u30fc\u30c8: Enter&lt;\/div>\n  &lt;\/div>\n\n  &lt;script>\n    const canvas = document.getElementById(\"game\");\n    const ctx = canvas.getContext(\"2d\");\n    const scoreEl = document.getElementById(\"score\");\n    const hpEl = document.getElementById(\"hp\");\n    const powerEl = document.getElementById(\"power\");\n\n    const keys = {};\n\n    const player = {\n      x: canvas.width \/ 2,\n      y: canvas.height - 70,\n      w: 34,\n      h: 42,\n      speed: 5,\n      hp: 5,\n      power: 1,\n      shotCooldown: 0,\n      invincible: 0\n    };\n\n    let bullets = &#91;];\n    let enemyBullets = &#91;];\n    let enemies = &#91;];\n    let items = &#91;];\n    let particles = &#91;];\n    let stars = &#91;];\n    let score = 0;\n    let enemyTimer = 0;\n    let itemTimer = 0;\n    let gameOver = false;\n    let boss = null;\n    let bossTimer = 0;\n    let frame = 0;\n\n    for (let i = 0; i &lt; 100; i++) {\n      stars.push({\n        x: Math.random() * canvas.width,\n        y: Math.random() * canvas.height,\n        r: Math.random() * 2 + 0.5,\n        speed: Math.random() * 2 + 1\n      });\n    }\n\n    window.addEventListener(\"keydown\", (e) => {\n      keys&#91;e.key.toLowerCase()] = true;\n      if (gameOver &amp;&amp; e.key === \"Enter\") restart();\n    });\n\n    window.addEventListener(\"keyup\", (e) => {\n      keys&#91;e.key.toLowerCase()] = false;\n    });\n\n    function restart() {\n      player.x = canvas.width \/ 2;\n      player.y = canvas.height - 70;\n      player.hp = 5;\n      player.power = 1;\n      player.shotCooldown = 0;\n      player.invincible = 0;\n      bullets = &#91;];\n      enemyBullets = &#91;];\n      enemies = &#91;];\n      items = &#91;];\n      particles = &#91;];\n      score = 0;\n      enemyTimer = 0;\n      itemTimer = 0;\n      frame = 0;\n      gameOver = false;\n      updateUI();\n    }\n\n    function updateUI() {\n      scoreEl.textContent = score;\n      hpEl.textContent = player.hp;\n      powerEl.textContent = player.power;\n    }\n\n    function addPlayerBullet(x, y, vx, vy, power = 1) {\n      bullets.push({ x, y, w: 6, h: 16, vx, vy, power });\n    }\n\n    function shoot() {\n      if (player.power === 1) {\n        addPlayerBullet(player.x, player.y - 25, 0, -10);\n      } else if (player.power === 2) {\n        addPlayerBullet(player.x - 9, player.y - 25, 0, -10);\n        addPlayerBullet(player.x + 9, player.y - 25, 0, -10);\n      } else if (player.power === 3) {\n        addPlayerBullet(player.x, player.y - 28, 0, -11);\n        addPlayerBullet(player.x - 16, player.y - 20, -1.2, -10);\n        addPlayerBullet(player.x + 16, player.y - 20, 1.2, -10);\n      } else {\n        addPlayerBullet(player.x, player.y - 30, 0, -12, 2);\n        addPlayerBullet(player.x - 14, player.y - 24, -0.8, -11);\n        addPlayerBullet(player.x + 14, player.y - 24, 0.8, -11);\n        addPlayerBullet(player.x - 24, player.y - 10, -1.7, -10);\n        addPlayerBullet(player.x + 24, player.y - 10, 1.7, -10);\n      }\n\n      player.shotCooldown = Math.max(4, 10 - player.power);\n    }\n\n    function spawnEnemy() {\n      if (boss) return;\n      const size = Math.random() * 16 + 28;\n      enemies.push({\n        x: Math.random() * (canvas.width - size) + size \/ 2,\n        y: -size,\n        w: size,\n        h: size,\n        speed: Math.random() * 1.4 + 1.4,\n        hp: size > 38 ? 4 : 2,\n        shotTimer: Math.floor(Math.random() * 50),\n        type: Math.random() &lt; 0.35 ? \"spread\" : \"normal\"\n      });\n    }\n\n    function spawnPowerItem(x = Math.random() * (canvas.width - 40) + 20, y = -20) {\n      items.push({\n        x,\n        y,\n        w: 24,\n        h: 24,\n        speed: 2.2,\n        type: \"power\"\n      });\n    }\n\n    function enemyShoot(enemy) {\n      if (enemy.type === \"spread\") {\n        for (let i = -2; i &lt;= 2; i++) {\n          enemyBullets.push({\n            x: enemy.x,\n            y: enemy.y + enemy.h \/ 2,\n            w: 8,\n            h: 8,\n            vx: i * 1.1,\n            vy: 3.2\n          });\n        }\n      } else {\n        const dx = player.x - enemy.x;\n        const dy = player.y - enemy.y;\n        const len = Math.hypot(dx, dy) || 1;\n        enemyBullets.push({\n          x: enemy.x,\n          y: enemy.y + enemy.h \/ 2,\n          w: 8,\n          h: 8,\n          vx: dx \/ len * 3.2,\n          vy: dy \/ len * 3.2\n        });\n      }\n    }\n\n    function createExplosion(x, y) {\n      for (let i = 0; i &lt; 16; i++) {\n        particles.push({\n          x,\n          y,\n          vx: (Math.random() - 0.5) * 7,\n          vy: (Math.random() - 0.5) * 7,\n          life: 24,\n          r: Math.random() * 4 + 2\n        });\n      }\n    }\n\n    function isHit(a, b) {\n      return (\n        a.x - a.w \/ 2 &lt; b.x + b.w \/ 2 &amp;&amp;\n        a.x + a.w \/ 2 > b.x - b.w \/ 2 &amp;&amp;\n        a.y - a.h \/ 2 &lt; b.y + b.h \/ 2 &amp;&amp;\n        a.y + a.h \/ 2 > b.y - b.h \/ 2\n      );\n    }\n\n    function damagePlayer() {\n      if (player.invincible > 0) return;\n      player.hp--;\n      player.power = Math.max(1, player.power - 1);\n      player.invincible = 80;\n      createExplosion(player.x, player.y);\n      updateUI();\n      if (player.hp &lt;= 0) gameOver = true;\n    }\n\n    function update() {\n      if (gameOver) return;\n      frame++;\n\n      \/\/ boss spawn\n      bossTimer++;\n      if (!boss &amp;&amp; bossTimer > 2000) {\n        boss = {\n          x: canvas.width \/ 2,\n          y: 120,\n          w: 120,\n          h: 120,\n          hp: 200,\n          maxHp: 200,\n          shotTimer: 0\n        };\n      }\n\n      if (keys&#91;\"arrowleft\"] || keys&#91;\"a\"]) player.x -= player.speed;\n      if (keys&#91;\"arrowright\"] || keys&#91;\"d\"]) player.x += player.speed;\n      if (keys&#91;\"arrowup\"] || keys&#91;\"w\"]) player.y -= player.speed;\n      if (keys&#91;\"arrowdown\"] || keys&#91;\"s\"]) player.y += player.speed;\n\n      player.x = Math.max(player.w \/ 2, Math.min(canvas.width - player.w \/ 2, player.x));\n      player.y = Math.max(player.h \/ 2, Math.min(canvas.height - player.h \/ 2, player.y));\n\n      if (player.invincible > 0) player.invincible--;\n      if (player.shotCooldown > 0) player.shotCooldown--;\n      if ((keys&#91;\" \"] || keys&#91;\"space\"]) &amp;&amp; player.shotCooldown &lt;= 0) shoot();\n\n      bullets.forEach((b) => {\n        b.x += b.vx;\n        b.y += b.vy;\n      });\n      bullets = bullets.filter((b) => b.y > -30 &amp;&amp; b.x > -30 &amp;&amp; b.x &lt; canvas.width + 30);\n\n      enemyBullets.forEach((b) => {\n        b.x += b.vx;\n        b.y += b.vy;\n      });\n      enemyBullets = enemyBullets.filter((b) => b.y &lt; canvas.height + 30 &amp;&amp; b.x > -30 &amp;&amp; b.x &lt; canvas.width + 30);\n\n      enemyTimer++;\n      if (enemyTimer > Math.max(20, 40 - Math.floor(score \/ 1000))) {\n        spawnEnemy();\n        enemyTimer = 0;\n      }\n\n      itemTimer++;\n      if (itemTimer > 520) {\n        spawnPowerItem();\n        itemTimer = 0;\n      }\n\n      enemies.forEach((e) => {\n        e.y += e.speed;\n        e.shotTimer++;\n        if (e.shotTimer > 70) {\n          enemyShoot(e);\n          e.shotTimer = 0;\n        }\n      });\n\n      \/\/ boss behavior\n      if (boss) {\n        boss.shotTimer++;\n        if (boss.shotTimer % 40 === 0) {\n          for (let i = 0; i &lt; 20; i++) {\n            const angle = (Math.PI * 2 \/ 20) * i + frame * 0.02;\n            enemyBullets.push({\n              x: boss.x,\n              y: boss.y,\n              w: 10,\n              h: 10,\n              vx: Math.cos(angle) * 3,\n              vy: Math.sin(angle) * 3\n            });\n          }\n        }\n      }\n\n      items.forEach((item) => {\n        item.y += item.speed;\n        item.x += Math.sin((frame + item.y) * 0.04) * 0.8;\n      });\n      items = items.filter((item) => item.y &lt; canvas.height + 40);\n\n      for (let i = items.length - 1; i >= 0; i--) {\n        if (isHit(player, items&#91;i])) {\n          player.power = Math.min(4, player.power + 1);\n          score += 300;\n          createExplosion(items&#91;i].x, items&#91;i].y);\n          items.splice(i, 1);\n          updateUI();\n        }\n      }\n\n      for (let i = enemies.length - 1; i >= 0; i--) {\n        const e = enemies&#91;i];\n        if (isHit(player, e)) {\n          createExplosion(e.x, e.y);\n          enemies.splice(i, 1);\n          damagePlayer();\n          continue;\n        }\n\n        if (e.y > canvas.height + 50) {\n          enemies.splice(i, 1);\n          damagePlayer();\n        }\n      }\n\n      for (let i = enemyBullets.length - 1; i >= 0; i--) {\n        if (isHit(player, enemyBullets&#91;i])) {\n          enemyBullets.splice(i, 1);\n          damagePlayer();\n        }\n      }\n\n      for (let i = enemies.length - 1; i >= 0; i--) {\n        for (let j = bullets.length - 1; j >= 0; j--) {\n          if (isHit(enemies&#91;i], bullets&#91;j])) {\n            enemies&#91;i].hp -= bullets&#91;j].power;\n            bullets.splice(j, 1);\n\n            if (enemies&#91;i].hp &lt;= 0) {\n              const drop = Math.random() &lt; 0.18;\n              if (drop) spawnPowerItem(enemies&#91;i].x, enemies&#91;i].y);\n              createExplosion(enemies&#91;i].x, enemies&#91;i].y);\n              enemies.splice(i, 1);\n              score += 100;\n              updateUI();\n            }\n            break;\n          }\n        }\n      }\n\n      particles.forEach((p) => {\n        p.x += p.vx;\n        p.y += p.vy;\n        p.life--;\n      });\n      particles = particles.filter((p) => p.life > 0);\n\n      stars.forEach((s) => {\n        s.y += s.speed;\n        if (s.y > canvas.height) {\n          s.y = 0;\n          s.x = Math.random() * canvas.width;\n        }\n      });\n    }\n\n    function drawPlayer() {\n      if (player.invincible > 0 &amp;&amp; Math.floor(frame \/ 5) % 2 === 0) return;\n\n      ctx.save();\n      ctx.translate(player.x, player.y);\n\n      \/\/ body\n      const grad = ctx.createLinearGradient(0, -20, 0, 30);\n      grad.addColorStop(0, \"#7df9ff\");\n      grad.addColorStop(1, \"#0077ff\");\n      ctx.fillStyle = grad;\n      ctx.beginPath();\n      ctx.moveTo(0, -26);\n      ctx.lineTo(20, 22);\n      ctx.lineTo(0, 12);\n      ctx.lineTo(-20, 22);\n      ctx.closePath();\n      ctx.fill();\n\n      \/\/ cockpit\n      ctx.fillStyle = \"#ffffff\";\n      ctx.beginPath();\n      ctx.arc(0, -6, 6, 0, Math.PI * 2);\n      ctx.fill();\n\n      \/\/ wings glow\n      ctx.fillStyle = \"#00eaff\";\n      ctx.globalAlpha = 0.5;\n      ctx.fillRect(-24, 0, 8, 10);\n      ctx.fillRect(16, 0, 8, 10);\n      ctx.globalAlpha = 1;\n\n      \/\/ engine flame\n      ctx.fillStyle = \"#ffcf5a\";\n      ctx.beginPath();\n      ctx.moveTo(-8, 24);\n      ctx.lineTo(0, 40 + Math.random() * 6);\n      ctx.lineTo(8, 24);\n      ctx.closePath();\n      ctx.fill();\n\n      ctx.restore();\n    }\n\n    function drawEnemy(e) {\n      ctx.save();\n      ctx.translate(e.x, e.y);\n\n      \/\/ core\n      const grad = ctx.createRadialGradient(0, 0, 4, 0, 0, e.w \/ 2);\n      grad.addColorStop(0, \"#fff\");\n      grad.addColorStop(1, e.type === \"spread\" ? \"#ff00cc\" : \"#ff0000\");\n      ctx.fillStyle = grad;\n      ctx.beginPath();\n      ctx.arc(0, 0, e.w \/ 2, 0, Math.PI * 2);\n      ctx.fill();\n\n      \/\/ spikes\n      ctx.strokeStyle = \"#fff\";\n      ctx.lineWidth = 2;\n      for (let i = 0; i &lt; 6; i++) {\n        const angle = (Math.PI * 2 \/ 6) * i + frame * 0.01;\n        ctx.beginPath();\n        ctx.moveTo(Math.cos(angle) * 6, Math.sin(angle) * 6);\n        ctx.lineTo(Math.cos(angle) * (e.w \/ 2 + 8), Math.sin(angle) * (e.w \/ 2 + 8));\n        ctx.stroke();\n      }\n\n      ctx.restore();\n    }\n\n    function drawPowerItem(item) {\n      ctx.save();\n      ctx.translate(item.x, item.y);\n      ctx.rotate(frame * 0.05);\n      ctx.fillStyle = \"#68ff7a\";\n      ctx.fillRect(-12, -12, 24, 24);\n      ctx.fillStyle = \"#052\";\n      ctx.font = \"bold 18px system-ui\";\n      ctx.textAlign = \"center\";\n      ctx.textBaseline = \"middle\";\n      ctx.fillText(\"P\", 0, 1);\n      ctx.restore();\n    }\n\n    function draw() {\n      ctx.clearRect(0, 0, canvas.width, canvas.height);\n      ctx.fillStyle = \"#050816\";\n      ctx.fillRect(0, 0, canvas.width, canvas.height);\n\n      ctx.fillStyle = \"#ffffff\";\n      stars.forEach((s) => {\n        ctx.globalAlpha = 0.4 + Math.random() * 0.5;\n        ctx.beginPath();\n        ctx.arc(s.x, s.y, s.r, 0, Math.PI * 2);\n        ctx.fill();\n      });\n      ctx.globalAlpha = 1;\n\n      bullets.forEach((b) => {\n        ctx.fillStyle = b.power >= 2 ? \"#fff36a\" : \"#8ffcff\";\n        ctx.fillRect(b.x - b.w \/ 2, b.y - b.h \/ 2, b.w, b.h);\n      });\n\n      enemyBullets.forEach((b) => {\n        ctx.fillStyle = \"#ff9a3b\";\n        ctx.beginPath();\n        ctx.arc(b.x, b.y, b.w \/ 2, 0, Math.PI * 2);\n        ctx.fill();\n      });\n\n      items.forEach(drawPowerItem);\n      enemies.forEach(drawEnemy);\n      \/\/ draw boss\n      if (boss) {\n        ctx.save();\n        ctx.translate(boss.x, boss.y);\n\n        const grad = ctx.createRadialGradient(0, 0, 10, 0, 0, boss.w \/ 2);\n        grad.addColorStop(0, \"#fff\");\n        grad.addColorStop(1, \"#ff00aa\");\n        ctx.fillStyle = grad;\n        ctx.beginPath();\n        ctx.arc(0, 0, boss.w \/ 2, 0, Math.PI * 2);\n        ctx.fill();\n        ctx.restore();\n\n        \/\/ HP bar\n        ctx.fillStyle = \"#000\";\n        ctx.fillRect(80, 20, 320, 16);\n        ctx.fillStyle = \"#ff0066\";\n        ctx.fillRect(80, 20, 320 * (boss.hp \/ boss.maxHp), 16);\n      }\n\n      drawPlayer();\n\n      particles.forEach((p) => {\n        ctx.globalAlpha = p.life \/ 24;\n        ctx.fillStyle = \"#ffd35a\";\n        ctx.beginPath();\n        ctx.arc(p.x, p.y, p.r, 0, Math.PI * 2);\n        ctx.fill();\n      });\n      ctx.globalAlpha = 1;\n\n      if (gameOver) {\n        ctx.fillStyle = \"#000b\";\n        ctx.fillRect(0, 0, canvas.width, canvas.height);\n        ctx.fillStyle = \"white\";\n        ctx.textAlign = \"center\";\n        ctx.font = \"bold 42px system-ui\";\n        ctx.fillText(\"GAME OVER\", canvas.width \/ 2, canvas.height \/ 2 - 30);\n        ctx.font = \"20px system-ui\";\n        ctx.fillText(\"Score: \" + score, canvas.width \/ 2, canvas.height \/ 2 + 10);\n        ctx.fillText(\"Enter\u3067\u30ea\u30b9\u30bf\u30fc\u30c8\", canvas.width \/ 2, canvas.height \/ 2 + 48);\n      }\n    }\n\n    function loop() {\n      update();\n      draw();\n      requestAnimationFrame(loop);\n    }\n\n    updateUI();\n    loop();\n  &lt;\/script>\n&lt;\/body>\n&lt;\/html>\n<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"_uf_show_specific_survey":0,"_uf_disable_surveys":false,"footnotes":""},"categories":[44],"tags":[3],"class_list":["post-26298","post","type-post","status-publish","format-standard","hentry","category-44","tag-programming"],"aioseo_notices":[],"jetpack_featured_media_url":"","_links":{"self":[{"href":"http:\/\/www.tyosuke20xx.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/26298","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/www.tyosuke20xx.com\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.tyosuke20xx.com\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.tyosuke20xx.com\/blog\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.tyosuke20xx.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=26298"}],"version-history":[{"count":1,"href":"http:\/\/www.tyosuke20xx.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/26298\/revisions"}],"predecessor-version":[{"id":26299,"href":"http:\/\/www.tyosuke20xx.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/26298\/revisions\/26299"}],"wp:attachment":[{"href":"http:\/\/www.tyosuke20xx.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=26298"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.tyosuke20xx.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=26298"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.tyosuke20xx.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=26298"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}