
はじめに
こんにちは。株式会社エーピーコミュニケーションズクラウド事業部の丸山です。
少し前にリリースされたChatGPTの新モデルo3-mini-highが非常に賢いと話題になっていたため、本来はそちらを記事にする予定でした。
テスト実行自体はしたものの、記事化するべく整理している間にClaudeからも3.7 Sonnetがリリースされ、これがまたとてつもなくすごいとの噂。
個人的にはGPTよりもSonnetの方が好みのため、早速試してみました。
結論
天才
予想を遥かに超える賢さのため、手戻りもなく記事としては非常に内容が薄くなってしまいました。
意図を組んでの一発生成が可能のため、有用すぎて再課金を検討してます。
プロンプトの作成と生成
かなりの読解力があるとの評判を聞いていたため、プロンプトとしてはたったのこれだけ。
グラディウスのようなシューティングゲームを作成して。 ただし条件としてはChromeのコンソールに貼り付けることで実行ができるものとしてください。
プロンプト実行後、しばらくするといきなりArtifacts上でゲーム画面が登場します。
しばらくClaudeからの利用はしていなかっため、こんな便利機能があることを失念していました。
軽微なバグは見受けられましたが、きちんと動作もします。
唯一残念なことは要件としてつけた条件の、Chromeのコンソールから貼り付けて動作させることができませんでした。
しかしながら予想を遥かに凌駕する結果となったためとても大満足です。
コンソール実行については無料プランのリミットにて修正を断念しましたが、あと1,2回程度で基本的な要件は満たしたものを作成してくれるでしょう。(個人的にCursor利用がメインでClaude自体の課金はやめてしまったため)
<!DOCTYPE html>
<html>
<head>
<style>
body {
margin: 0;
overflow: hidden;
background-color: #000;
color: white;
font-family: Arial, sans-serif;
}
#game-container {
position: relative;
width: 800px;
height: 600px;
margin: 0 auto;
border: 1px solid #333;
overflow: hidden;
}
.player, .enemy, .bullet, .powerup {
position: absolute;
background-size: contain;
background-repeat: no-repeat;
}
.player {
width: 50px;
height: 20px;
background-color: #0af;
border-radius: 5px;
}
.enemy {
width: 40px;
height: 40px;
background-color: #f66;
border-radius: 50%;
}
.bullet {
width: 10px;
height: 5px;
background-color: #ff0;
border-radius: 5px;
}
.powerup {
width: 20px;
height: 20px;
background-color: #0f0;
border-radius: 5px;
}
.explosion {
position: absolute;
width: 40px;
height: 40px;
background-color: #f90;
border-radius: 50%;
animation: explode 0.5s forwards;
}
@keyframes explode {
0% { transform: scale(0.5); opacity: 1; }
100% { transform: scale(2); opacity: 0; }
}
#score, #lives {
position: absolute;
top: 10px;
color: white;
font-weight: bold;
}
#score {
left: 10px;
}
#lives {
right: 10px;
}
#game-over, #start-screen {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
background-color: rgba(0, 0, 0, 0.7);
color: white;
font-size: 32px;
}
button {
margin-top: 20px;
padding: 10px 20px;
font-size: 18px;
background-color: #0af;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
}
button:hover {
background-color: #08f;
}
</style>
</head>
<body>
<div id="game-container">
<div id="score">スコア: 0</div>
<div id="lives">ライフ: 3</div>
<div id="start-screen">
<h1>グラディウス風ゲーム</h1>
<p>矢印キーで移動、スペースキーで発射</p>
<button id="start-btn">ゲームスタート</button>
</div>
<div id="game-over" style="display: none;">
<h1>ゲームオーバー</h1>
<p id="final-score">最終スコア: 0</p>
<button id="restart-btn">リスタート</button>
</div>
</div>
<script>
// ゲームの設定
const gameWidth = 800;
const gameHeight = 600;
let gameRunning = false;
let gameLoop;
let score = 0;
let lives = 3;
let level = 1;
let enemySpeed = 2;
let enemySpawnRate = 100;
let powerUpChance = 0.1;
// プレイヤーの設定
let player = {
x: 50,
y: gameHeight / 2,
width: 50,
height: 20,
speed: 5,
shootCooldown: 0,
power: 1
};
// ゲームオブジェクト
let bullets = [];
let enemies = [];
let powerups = [];
let explosions = [];
// キー入力の状態
let keys = {
ArrowUp: false,
ArrowDown: false,
ArrowLeft: false,
ArrowRight: false,
Space: false
};
// ゲームコンテナの取得
const container = document.getElementById('game-container');
const scoreEl = document.getElementById('score');
const livesEl = document.getElementById('lives');
const gameOverEl = document.getElementById('game-over');
const startScreenEl = document.getElementById('start-screen');
const finalScoreEl = document.getElementById('final-score');
const startBtn = document.getElementById('start-btn');
const restartBtn = document.getElementById('restart-btn');
// イベントリスナー
document.addEventListener('keydown', keyDownHandler);
document.addEventListener('keyup', keyUpHandler);
startBtn.addEventListener('click', startGame);
restartBtn.addEventListener('click', startGame);
// キー入力ハンドラ
function keyDownHandler(e) {
if (e.code === 'ArrowUp' || e.code === 'ArrowDown' ||
e.code === 'ArrowLeft' || e.code === 'ArrowRight' ||
e.code === 'Space') {
keys[e.code] = true;
e.preventDefault();
}
}
function keyUpHandler(e) {
if (e.code === 'ArrowUp' || e.code === 'ArrowDown' ||
e.code === 'ArrowLeft' || e.code === 'ArrowRight' ||
e.code === 'Space') {
keys[e.code] = false;
e.preventDefault();
}
}
// ゲーム開始
function startGame() {
// ゲームをリセット
player = {
x: 50,
y: gameHeight / 2,
width: 50,
height: 20,
speed: 5,
shootCooldown: 0,
power: 1
};
bullets = [];
enemies = [];
powerups = [];
explosions = [];
score = 0;
lives = 3;
level = 1;
enemySpeed = 2;
enemySpawnRate = 100;
// UI要素を更新
updateScore();
updateLives();
// プレイヤー要素を作成
createPlayerElement();
// スタート画面とゲームオーバー画面を非表示
startScreenEl.style.display = 'none';
gameOverEl.style.display = 'none';
// ゲームループを開始
gameRunning = true;
if (gameLoop) clearInterval(gameLoop);
gameLoop = setInterval(update, 16); // 約60FPS
}
// プレイヤー要素の作成
function createPlayerElement() {
// 既存のプレイヤー要素を削除
const oldPlayer = container.querySelector('.player');
if (oldPlayer) oldPlayer.remove();
// 新しいプレイヤー要素を作成
const playerEl = document.createElement('div');
playerEl.className = 'player';
playerEl.style.left = player.x + 'px';
playerEl.style.top = player.y + 'px';
container.appendChild(playerEl);
}
// ゲームの更新
function update() {
if (!gameRunning) return;
// プレイヤーの移動
movePlayer();
// 弾の発射
if (keys.Space && player.shootCooldown <= 0) {
shoot();
player.shootCooldown = 15 - player.power * 2; // パワーアップで発射速度が上がる
}
if (player.shootCooldown > 0) player.shootCooldown--;
// 弾の移動と衝突判定
updateBullets();
// 敵の生成
if (Math.random() * enemySpawnRate < level) {
createEnemy();
}
// 敵の移動と衝突判定
updateEnemies();
// パワーアップの移動と衝突判定
updatePowerUps();
// アニメーションの更新
updateExplosions();
// レベルアップ
if (score > level * 1000) {
level++;
enemySpeed += 0.2;
enemySpawnRate -= 5;
if (enemySpawnRate < 20) enemySpawnRate = 20;
}
}
// プレイヤーの移動
function movePlayer() {
// 移動の計算
if (keys.ArrowUp) player.y -= player.speed;
if (keys.ArrowDown) player.y += player.speed;
if (keys.ArrowLeft) player.x -= player.speed;
if (keys.ArrowRight) player.x += player.speed;
// 画面内に留める
if (player.x < 0) player.x = 0;
if (player.x > gameWidth - player.width) player.x = gameWidth - player.width;
if (player.y < 0) player.y = 0;
if (player.y > gameHeight - player.height) player.y = gameHeight - player.height;
// プレイヤー位置の更新
const playerEl = container.querySelector('.player');
if (playerEl) {
playerEl.style.left = player.x + 'px';
playerEl.style.top = player.y + 'px';
}
}
// 弾の発射
function shoot() {
// 通常の弾
createBullet(player.x + player.width, player.y + player.height / 2 - 2.5);
// パワーアップによる追加の弾
if (player.power >= 2) {
createBullet(player.x + player.width, player.y + 5);
createBullet(player.x + player.width, player.y + player.height - 5);
}
if (player.power >= 3) {
createBullet(player.x + player.width, player.y);
createBullet(player.x + player.width, player.y + player.height);
}
}
// 弾の作成
function createBullet(x, y) {
const bullet = {
x: x,
y: y,
width: 10,
height: 5,
speed: 10
};
bullets.push(bullet);
const bulletEl = document.createElement('div');
bulletEl.className = 'bullet';
bulletEl.style.left = bullet.x + 'px';
bulletEl.style.top = bullet.y + 'px';
container.appendChild(bulletEl);
}
// 弾の更新
function updateBullets() {
const bulletElements = container.querySelectorAll('.bullet');
bullets = bullets.filter((bullet, index) => {
// 弾の移動
bullet.x += bullet.speed;
// 画面外に出た弾を削除
if (bullet.x > gameWidth) {
if (bulletElements[index]) bulletElements[index].remove();
return false;
}
// 弾の位置を更新
if (bulletElements[index]) {
bulletElements[index].style.left = bullet.x + 'px';
bulletElements[index].style.top = bullet.y + 'px';
}
return true;
});
}
// 敵の作成
function createEnemy() {
const enemy = {
x: gameWidth,
y: Math.random() * (gameHeight - 40),
width: 40,
height: 40,
speed: enemySpeed + Math.random() * 1
};
enemies.push(enemy);
const enemyEl = document.createElement('div');
enemyEl.className = 'enemy';
enemyEl.style.left = enemy.x + 'px';
enemyEl.style.top = enemy.y + 'px';
container.appendChild(enemyEl);
}
// 敵の更新
function updateEnemies() {
const enemyElements = container.querySelectorAll('.enemy');
enemies = enemies.filter((enemy, index) => {
// 敵の移動
enemy.x -= enemy.speed;
// 画面外に出た敵を削除
if (enemy.x + enemy.width < 0) {
if (enemyElements[index]) enemyElements[index].remove();
return false;
}
// プレイヤーとの衝突判定
if (checkCollision(player, enemy)) {
// 衝突時の処理
createExplosion(player.x, player.y);
lives--;
updateLives();
if (lives <= 0) {
gameOver();
} else {
// プレイヤーを初期位置に戻す
player.x = 50;
player.y = gameHeight / 2;
}
if (enemyElements[index]) enemyElements[index].remove();
return false;
}
// 弾との衝突判定
let hit = false;
bullets = bullets.filter((bullet, bulletIndex) => {
if (checkCollision(bullet, enemy)) {
// 弾が当たった場合
hit = true;
const bulletElements = container.querySelectorAll('.bullet');
if (bulletElements[bulletIndex]) bulletElements[bulletIndex].remove();
return false;
}
return true;
});
if (hit) {
// 敵が倒された場合
createExplosion(enemy.x, enemy.y);
score += 100;
updateScore();
// パワーアップアイテムをドロップするかどうか
if (Math.random() < powerUpChance) {
createPowerUp(enemy.x, enemy.y);
}
if (enemyElements[index]) enemyElements[index].remove();
return false;
}
// 敵の位置を更新
if (enemyElements[index]) {
enemyElements[index].style.left = enemy.x + 'px';
enemyElements[index].style.top = enemy.y + 'px';
}
return true;
});
}
// パワーアップの作成
function createPowerUp(x, y) {
const powerup = {
x: x,
y: y,
width: 20,
height: 20,
speed: 1
};
powerups.push(powerup);
const powerupEl = document.createElement('div');
powerupEl.className = 'powerup';
powerupEl.style.left = powerup.x + 'px';
powerupEl.style.top = powerup.y + 'px';
container.appendChild(powerupEl);
}
// パワーアップの更新
function updatePowerUps() {
const powerupElements = container.querySelectorAll('.powerup');
powerups = powerups.filter((powerup, index) => {
// パワーアップの移動
powerup.x -= powerup.speed;
// 画面外に出たパワーアップを削除
if (powerup.x + powerup.width < 0) {
if (powerupElements[index]) powerupElements[index].remove();
return false;
}
// プレイヤーとの衝突判定
if (checkCollision(player, powerup)) {
// パワーアップの効果
if (player.power < 3) player.power++;
score += 200;
updateScore();
if (powerupElements[index]) powerupElements[index].remove();
return false;
}
// パワーアップの位置を更新
if (powerupElements[index]) {
powerupElements[index].style.left = powerup.x + 'px';
powerupElements[index].style.top = powerup.y + 'px';
}
return true;
});
}
// 爆発エフェクトの作成
function createExplosion(x, y) {
const explosion = document.createElement('div');
explosion.className = 'explosion';
explosion.style.left = x + 'px';
explosion.style.top = y + 'px';
container.appendChild(explosion);
// 爆発エフェクトを一定時間後に削除
setTimeout(() => {
explosion.remove();
}, 500);
}
// 爆発エフェクトの更新
function updateExplosions() {
// アニメーションはCSSで処理されるので何もしない
}
// 衝突判定
function checkCollision(obj1, obj2) {
return (
obj1.x < obj2.x + obj2.width &&
obj1.x + obj1.width > obj2.x &&
obj1.y < obj2.y + obj2.height &&
obj1.y + obj1.height > obj2.y
);
}
// スコアの更新
function updateScore() {
scoreEl.textContent = 'スコア: ' + score;
}
// ライフの更新
function updateLives() {
livesEl.textContent = 'ライフ: ' + lives;
}
// ゲームオーバー
function gameOver() {
gameRunning = false;
clearInterval(gameLoop);
finalScoreEl.textContent = '最終スコア: ' + score;
gameOverEl.style.display = 'flex';
}
// HTMLの描画が完了したら
window.onload = function() {
// ゲーム要素をクリア
clearElements();
};
// 全てのゲーム要素をクリア
function clearElements() {
const elements = container.querySelectorAll('.player, .enemy, .bullet, .powerup, .explosion');
elements.forEach(el => el.remove());
}
</script>
</body>
</html>
利用した感想
巷ではflutterアプリを一発生成できたような話も見かけましたが、実際にClaudeのチャット窓からの利用でこれだけのものを一発生成してくれることからどれだけ強力なモデルなのかが想像できます。
Cursor開発にてこれまでは3.5 Sonnetがメインで活躍していましたが、Cursorのフォーラムを読むに3.7の威力は絶大とのこと。
残念ながら現在有料プランでも人為的に制限が掛けられている状況のため試せていません。(機械翻訳)

これからも発展が楽しみな分野ですのでまた機会があれば、Cursorでの利用感などもレビューしてみようと思います。
おわりに
私達クラウド事業部はクラウド技術を活用したSI/SESのご支援をしております。
また、一緒に働いていただける仲間も募集中です! ご興味持っていただけましたらぜひお声がけください。