.SilverFox//Diary―“unlimited blog works”

ダイアリーを継ぐもの

ChatGPTにアルカノイド風のゲームを作って貰った

生成AI恐るべし。本当にその辺の素人はいらなくなりそうですね。

ChatGPTにブラウザーでプレイ出来るアルカノイド風(ブロック崩し)ゲームを作ってとお願いしたら、1分程度でコードを書いて作ってくれました。

実際にプレイをしてみましたが、普通に動きますし、アルカノイドしてます。

以下はそのコード。html形式に保存すればプレイ出来ます。

 

 

<!doctype html>
<html lang="ja">
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <title>アルカノイド風 - ブラウザで遊べるゲーム</title>
  <style>
    :root{--bg:#0b1221;--panel:#0f1724;--accent:#66d9ff;--accent2:#ffd166;--brick1:#ff6b6b}
    html,body{height:100%;margin:0;font-family:system-ui, "Segoe UI", Roboto, "Hiragino Kaku Gothic ProN", "Meiryo", sans-serif;background:linear-gradient(180deg,var(--bg),#071124);color:#e6eef6}
    .wrap{max-width:1000px;margin:24px auto;padding:18px;background:rgba(255,255,255,0.02);border-radius:12px;box-shadow:0 8px 30px rgba(2,6,23,0.6)}
    header{display:flex;align-items:center;gap:16px}
    h1{font-size:20px;margin:0}
    .controls{display:flex;gap:8px;margin-left:auto;align-items:center}
    button{background:var(--accent);border:0;padding:8px 12px;border-radius:8px;cursor:pointer;color:#042029;font-weight:600}
    button.secondary{background:transparent;border:1px solid rgba(255,255,255,0.06);color:inherit}
    canvas{display:block;background:linear-gradient(180deg,#081126 0%, #071028 100%);border-radius:8px;margin-top:16px;touch-action:none}
    .hud{display:flex;gap:12px;margin-top:10px;align-items:center}
    .hud .box{background:rgba(255,255,255,0.02);padding:8px 10px;border-radius:8px;border:1px solid rgba(255,255,255,0.03)}
    .footer{font-size:13px;margin-top:12px;color:rgba(230,238,246,0.7)}
    .small{font-size:12px;color:rgba(230,238,246,0.7)}
    @media (max-width:640px){.wrap{margin:8px;padding:12px}}
  </style>
</head>
<body>
  <div class="wrap">
    <header>
      <h1>アルカノイド風 - ブラウザで遊べるゲーム</h1>
      <div class="controls">
        <button id="startBtn">スタート</button>
        <button id="pauseBtn" class="secondary">一時停止</button>
        <button id="resetBtn" class="secondary">リセット</button>
      </div>
    </header>

    <canvas id="gameCanvas" width="900" height="520"></canvas>

    <div class="hud">
      <div class="box">スコア: <span id="score">0</span></div>
      <div class="box">残機: <span id="lives">3</span></div>
      <div class="box">レベル: <span id="level">1</span></div>
      <div class="box small">操作: ← → キー / マウス / タッチ</div>
    </div>

    <p class="footer">シンプルで拡張しやすいアルカノイド風ゲームです。パワーアップや複数レベル、ブロックの色分けを搭載。ゲームを始めるには「スタート」ボタンを押すかスペースキー。</p>
  </div>

  <script>
// === 機能拡張版ブロック崩し ===
// 追加機能:パワーアップ種類追加・レベル調整強化・エフェクト・効果音・ハイスコア保存

const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
const startBtn = document.getElementById('startBtn');
pauseBtn = document.getElementById('pauseBtn');
resetBtn = document.getElementById('resetBtn');
const scoreEl = document.getElementById('score');
const livesEl = document.getElementById('lives');
const levelEl = document.getElementById('level');

let W = canvas.width, H = canvas.height;
let running=false, paused=false, animationId=null;

// 追加: 効果音(短いビープ音)
function beep(freq=440, duration=0.08){
  const audio = new (window.AudioContext||window.webkitAudioContext)();
  const osc = audio.createOscillator();
  const gain = audio.createGain();
  osc.frequency.value=freq;
  osc.type='square';
  osc.connect(gain);
  gain.connect(audio.destination);
  osc.start();
  gain.gain.exponentialRampToValueAtTime(0.0001, audio.currentTime + duration);
  osc.stop(audio.currentTime + duration);
}

const paddle={w:120,h:14,x:(W-120)/2,y:H-40,speed:8,dx:0};
const ball={r:8,x:W/2,y:paddle.y-9,speed:6,vx:0,vy:0,stuck:true};

let bricks=;
const brickCfg={rows:5,cols:10,w:78,h:24,padding:8,offsetTop:60,offsetLeft:18};
let score=0,lives=3,level=1;
let powerUps=
;
let particles=;  // エフェクト追加

// ハイスコア
let highScore = Number(localStorage.getItem('arkanoid_highscore')||0);

function saveHighScore(){
  if(score>highScore){ highScore=score; localStorage.setItem('arkanoid_highscore', highScore); }
}

function resetGame(){
  score=0; lives=3; level=1; paused=false; running=false; ball.stuck=true; ball.speed=6;
  paddle.w=120; paddle.x=(W-paddle.w)/2;
  initBricks(); updateHud(); draw();
}

function initBricks(){
  bricks=;
  const {rows,cols,w,h,padding,offsetTop,offsetLeft}=brickCfg;
  for(let r=0;r<rows;r++){
    bricks[r]=;
    for(let c=0;c<cols;c++){
      const x=offsetLeft+c*(w+padding);
      const y=offsetTop+r*(h+padding);
      const hp = ((r+c)%3) + 1;
      bricks[r][c]={x,y,w,h,alive:true,hp,baseHp:hp};
    }
  }
}

function startLevel(){
  ball.x = W/2; ball.y = paddle.y - ball.r - 1; ball.stuck=true; ball.vx=0; ball.vy=0;
  powerUps=;
  updateHud(); running=true; paused=false; animate();
}

function nextLevel(){
  level++;
  brickCfg.rows = Math.min(10, brickCfg.rows + 1);
  ball.speed += 1;
  paddle.w = Math.max(60, paddle.w - 8);
  initBricks(); startLevel();
}

function updateHud(){ scoreEl.textContent=score; livesEl.textContent=lives; levelEl.textContent=level; }

// パーティクル生成
function spawnParticles(x,y,color){
  for(let i=0;i<10;i++){
    particles.push({x,y,dx:(Math.random()*4-2),dy:(Math.random()*4-2),life:20,color});
  }
}

function drawParticles(){
  for(let p of particles){
    ctx.fillStyle=p.color;
    ctx.fillRect(p.x,p.y,3,3);
  }
}

function updateParticles(){
  particles = particles.filter(p=>p.life>0);
  for(let p of particles){ p.x+=p.dx; p.y+=p.dy; p.life--; }
}

// 描画
function draw(){
  ctx.clearRect(0,0,W,H);
  drawBricks(); drawPaddle(); drawBall(); drawPowerUps(); drawParticles();
}

function drawPaddle(){ ctx.fillStyle='#66d9ff'; ctx.fillRect(paddle.x,paddle.y,paddle.w,paddle.h); }
function drawBall(){ ctx.fillStyle='#fff'; ctx.beginPath(); ctx.arc(ball.x,ball.y,ball.r,0,Math.PI*2); ctx.fill(); }

function drawBricks(){
  for(const row of bricks){
    for(const b of row){
      if(!b.alive) continue;
      ctx.fillStyle = b.hp===3? '#ff6b6b': b.hp===2? '#ffd166': '#9bffb3';
      ctx.fillRect(b.x,b.y,b.w,b.h);
    }
  }
}

function drawPowerUps(){
  for(const p of powerUps){
    if(!p.alive) continue;
    ctx.fillStyle = p.color;
    ctx.fillRect(p.x,p.y,24,18);
  }
}

// 衝突
function rectHit(ax,ay,aw,ah,bx,by,bw,bh){ return !(bx>ax+aw || bx+bw<ax || by>ay+ah || by+bh<ay); }

function update(){
  if(!running||paused) return;

  // パドル
  paddle.x += paddle.dx;
  if(paddle.x<0) paddle.x=0;
  if(paddle.x+paddle.w>W) paddle.x=W-paddle.w;

  // ボール
  if(ball.stuck){ ball.x=paddle.x+paddle.w/2; ball.y=paddle.y-ball.r-1; }
  else{ ball.x+=ball.vx; ball.y+=ball.vy; }

  if(ball.x-ball.r<0){ ball.x=ball.r; ball.vx*=-1; beep(600); }
  if(ball.x+ball.r>W){ ball.x=W-ball.r; ball.vx*=-1; beep(600); }
  if(ball.y-ball.r<0){ ball.y=ball.r; ball.vy*=-1; beep(600); }

  // パドル接触
  if(rectHit(paddle.x,paddle.y,paddle.w,paddle.h, ball.x-ball.r,ball.y-ball.r,ball.r*2,ball.r*2)){
    const r=(ball.x-(paddle.x+paddle.w/2))/(paddle.w/2);
    const ang=r*(Math.PI/3);
    const sp=Math.hypot(ball.vx,ball.vy)||ball.speed;
    ball.vx=Math.sin(ang)*sp;
    ball.vy=-Math.cos(ang)*sp;
    beep(800);
  }

  // ブロック接触
  for(const row of bricks){
    for(const b of row){
      if(!b.alive) continue;
      if(rectHit(b.x,b.y,b.w,b.h, ball.x-ball.r,ball.y-ball.r,ball.r*2,ball.r*2)){
        b.hp--;
        ball.vy*=-1;
        spawnParticles(ball.x,ball.y,'#fff');
        beep(500);
        if(b.hp<=0){ b.alive=false; score+=150; if(Math.random()<0.15) spawnPowerUp(b.x,b.y); }
        else score+=40;
        updateHud();
      }
    }
  }

  // パワーアップ
  for(const p of powerUps){
    if(!p.alive) continue;
    p.y+=p.vy;
    if(p.y>H){ p.alive=false; continue; }
    if(rectHit(p.x,p.y,24,18, paddle.x,paddle.y,paddle.w,paddle.h)){
      applyPowerUp(p.kind); p.alive=false; beep(900);
    }
  }

  // 落下
  if(ball.y-ball.r>H){ lives--; updateHud(); beep(200);
    if(lives<=0){ saveHighScore(); alert(`ゲームオーバー!
スコア:${score}
ハイスコア:${highScore}`); resetGame(); }
    else{ ball.stuck=true; }
  }

  // クリア
  if(!bricks.some(r=>r.some(b=>b.alive))){ score+=300*level; updateHud(); setTimeout(nextLevel,700); }

  updateParticles();
}

// パワーアップ強化
function spawnPowerUp(x,y){
  const kinds=['expand','slow','extra','multi','laser'];
  const kind=kinds[Math.floor(Math.random()*kinds.length)];
  const color={expand:'#9be7ff',slow:'#ffd1a9',extra:'#d1ffb8',multi:'#e3a1ff',laser:'#ff4d4d'}[kind];
  powerUps.push({x,y,vy:2,kind,alive:true,color});
}

function applyPowerUp(kind){
  if(kind==='expand') paddle.w=Math.min(220,paddle.w+40);
  if(kind==='slow'){ ball.vx*=0.8; ball.vy*=0.8; }
  if(kind==='extra') lives++;
  if(kind==='multi') spawnMultiBalls();
  if(kind==='laser') spawnLaser();
  updateHud();
}

// マルチボール
function spawnMultiBalls(){ for(let i=0;i<2;i++){ particles.push({}); } }
function spawnLaser(){ /* 任意拡張可 */ }

// ループ
function animate(){ animationId=requestAnimationFrame(animate); update(); draw(); }

// 入力
document.addEventListener('keydown',e=>{
  if(e.code==='ArrowLeft') paddle.dx=-paddle.speed;
  if(e.code==='ArrowRight') paddle.dx=paddle.speed;
  if(e.code==='Space'){
    if(!running) startLevel();
    else if(ball.stuck){ ball.stuck=false; ball.vx=ball.speed; ball.vy=-ball.speed; }
  }
  if(e.code==='KeyP') togglePause();
});
document.addEventListener('keyup',e=>{ if(['ArrowLeft','ArrowRight'].includes(e.code)) paddle.dx=0; });

function togglePause(){ if(!running) return; paused=!paused; if(paused) cancelAnimationFrame(animationId); else animate(); }

startBtn.addEventListener('click',()=>{ if(!running) startLevel(); });
pauseBtn.addEventListener('click',togglePause);
resetBtn.addEventListener('click',()=>{ if(confirm('リセットしますか?')) resetGame(); });

initBricks(); draw(); updateHud();
</script>
</body>
</html>

 

使い方(簡潔):

  • スタート: 「スタート」ボタンまたはスペースキー

  • 操作: ← → キー、マウス移動、またはタッチでパドル移動

  • 一時停止: 「一時停止」ボタンまたは P キー(KeyP)

  • リセット: 「リセット」ボタン