重力フラックス:物理ベースの飛行回避ゲーム
フリーのプロンプト百科事典 Wikiprompt より
重力フラックス:物理ベースの飛行回避ゲーム 物理ベースのゲームプレイ、手続き型ベジェ障害物、Web Audio合成、禅のようなパステル調の美学を備えた単一ファイルHTMLゲームを生成するための詳細なプロンプト。
プロンプト内容保存
🌐
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Gravity Flux</title>
<style>
body {
margin: 0;
overflow: hidden;
background: #1a1a2e;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
canvas {
display: block;
cursor: none;
}
#ui {
position: fixed;
top: 20px;
left: 20px;
color: #e0e0e0;
font-size: 14px;
letter-spacing: 2px;
text-transform: uppercase;
opacity: 0.8;
pointer-events: none;
z-index: 10;
}
#ui h1 {
font-size: 18px;
margin: 0 0 10px 0;
font-weight: 300;
color: #c0c0c0;
}
#ui p {
margin: 5px 0;
font-size: 12px;
color: #a0a0a0;
}
#score {
font-size: 24px;
font-weight: 700;
color: #ffffff;
text-shadow: 0 0 20px rgba(255,255,255,0.3);
}
#gameOver {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
text-align: center;
color: #e0e0e0;
display: none;
z-index: 20;
background: rgba(26,26,46,0.9);
padding: 40px 60px;
border-radius: 10px;
border: 1px solid rgba(255,255,255,0.1);
backdrop-filter: blur(10px);
}
#gameOver h2 {
font-size: 36px;
margin: 0 0 20px 0;
font-weight: 300;
letter-spacing: 4px;
}
#gameOver button {
background: transparent;
border: 1px solid #e0e0e0;
color: #e0e0e0;
padding: 12px 30px;
font-size: 14px;
letter-spacing: 2px;
cursor: pointer;
transition: all 0.3s;
text-transform: uppercase;
}
#gameOver button:hover {
background: #e0e0e0;
color: #1a1a2e;
}
#controls {
position: fixed;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
color: #a0a0a0;
font-size: 12px;
letter-spacing: 1px;
text-align: center;
opacity: 0.6;
pointer-events: none;
z-index: 10;
}
</style>
</head>
<body>
<div id="ui">
<h1>Gravity Flux</h1>
<p>Score: <span id="score">0</span></p>
<p>Altitude: <span id="altitude">0</span></p>
</div>
<div id="gameOver">
<h2>Flux Collapse</h2>
<p style="margin-bottom: 20px; color: #a0a0a0;">The sphere has been crushed</p>
<button onclick="restartGame()">Re-enter Flux</button>
</div>
<div id="controls">
MOUSE MOVE - Navigate | CLICK - Boost | SPACE - Pause
</div>
<canvas id="gameCanvas"></canvas>
<script>
// ============================================
// GRAVITY FLUX - Physics-based flight evasion
// ============================================
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
const scoreEl = document.getElementById('score');
const altitudeEl = document.getElementById('altitude');
const gameOverEl = document.getElementById('gameOver');
// Canvas sizing
function resizeCanvas() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
}
resizeCanvas();
window.addEventListener('resize', resizeCanvas);
// ============================================
// AUDIO SYSTEM - Web Audio API
// ============================================
let audioCtx = null;
let masterGain = null;
let pulseOsc = null;
let pulseGain = null;
let ambientGain = null;
function initAudio() {
if (audioCtx) return;
audioCtx = new (window.AudioContext || window.webkitAudioContext)();
masterGain = audioCtx.createGain();
masterGain.gain.value = 0.3;
masterGain.connect(audioCtx.destination);
// Ambient drone
ambientGain = audioCtx.createGain();
ambientGain.gain.value = 0.15;
ambientGain.connect(masterGain);
const osc1 = audioCtx.createOscillator();
osc1.type = 'sine';
osc1.frequency.value = 55;
const osc2 = audioCtx.createOscillator();
osc2.type = 'sine';
osc2.frequency.value = 55.5;
const osc3 = audioCtx.createOscillator();
osc3.type = 'sine';
osc3.frequency.value = 110;
const g1 = audioCtx.createGain();
g1.gain.value = 0.5;
const g2 = audioCtx.createGain();
g2.gain.value = 0.3;
const g3 = audioCtx.createGain();
g3.gain.value = 0.2;
osc1.connect(g1);
osc2.connect(g2);
osc3.connect(g3);
g1.connect(ambientGain);
g2.connect(ambientGain);
g3.connect(ambientGain);
osc1.start();
osc2.start();
osc3.start();
// Pulse oscillator
pulseOsc = audioCtx.createOscillator();
pulseOsc.type = 'sine';
pulseOsc.frequency.value = 220;
pulseGain = audioCtx.createGain();
pulseGain.gain.value = 0;
pulseOsc.connect(pulseGain);
pulseGain.connect(masterGain);
pulseOsc.start();
}
function playPulse(freq = 220, duration = 0.3, volume = 0.2) {
if (!audioCtx) return;
const osc = audioCtx.createOscillator();
osc.type = 'sine';
osc.frequency.setValueAtTime(freq, audioCtx.currentTime);
osc.frequency.exponentialRampToValueAtTime(freq * 0.5, audioCtx.currentTime + duration);
const gain = audioCtx.createGain();
gain.gain.setValueAtTime(volume, audioCtx.currentTime);
gain.gain.exponentialRampToValueAtTime(0.001, audioCtx.currentTime + duration);
osc.connect(gain);
gain.connect(masterGain);
osc.start();
osc.stop(audioCtx.currentTime + duration);
}
function playGateSweep() {
if (!audioCtx) return;
const osc = audioCtx.createOscillator();
osc.type = 'sine';
osc.frequency.setValueAtTime(400, audioCtx.currentTime);
osc.frequency.exponentialRampToValueAtTime(1200, audioCtx.currentTime + 0.4);
const gain = audioCtx.createGain();
gain.gain.setValueAtTime(0.3, audioCtx.currentTime);
gain.gain.exponentialRampToValueAtTime(0.001, audioCtx.currentTime + 0.4);
osc.connect(gain);
gain.connect(masterGain);
osc.start();
osc.stop(audioCtx.currentTime + 0.4);
}
// ============================================
// GAME STATE
// ============================================
let gameRunning = true;
let paused = false;
let score = 0;
let gameOver = false;
let lastTime = 0;
let time = 0;
// Player sphere
const player = {
x: 0,
y: 0,
vx: 0,
vy: 0,
radius: 18,
targetRadius: 18,
baseRadius: 18,
inflation: 0,
targetX: 0,
targetY: 0,
boost: false,
boostCooldown: 0
};
// Camera / world scroll
let worldY = 0;
let worldSpeed = 80; // pixels per second
// Obstacles
let obstacles = [];
let nextObstacleY = 0;
const OBSTACLE_SPACING = 300;
// ============================================
// PROCEDURAL OBSTACLE GENERATION
// ============================================
class Obstacle {
constructor(y) {
this.y = y;
this.gateSize = 120 + Math.random() * 80;
this.centerX = canvas.width / 2 + (Math.random() - 0.5) * 200;
this.phase = Math.random() * Math.PI * 2;
this.speed = 0.5 + Math.random() * 1.5;
this.amplitude = 20 + Math.random() * 30;
this.thickness = 15 + Math.random() * 10;
this.passed = false;
this.points = [];
this.generatePoints();
}
generatePoints() {
this.points = [];
const segments = 8;
for (let i = 0; i <= segments; i++) {
const t = i / segments;
const x = this.centerX + (t - 0.5) * this.gateSize * 2;
const y = this.y + Math.sin(t * Math.PI * 2 + this.phase) * this.amplitude;
this.points.push({x, y});
}
}
update(dt) {
this.phase += this.speed * dt;
this.gateSize += Math.sin(this.phase * 0.5) * 20 * dt;
this.gateSize = Math.max(60, Math.min(250, this.gateSize));
this.generatePoints();
}
draw() {
// Draw the gate as two bezier curves (top and bottom)
const topPoints = this.points.map(p => ({x: p.x, y: p.y - this.gateSize / 2}));
const bottomPoints = this.points.map(p => ({x: p.x, y: p.y + this.gateSize / 2}));
ctx.strokeStyle = '#c0c0c0';
ctx.lineWidth = this.thickness;
ctx.shadowColor = '#c0c0c0';
ctx.shadowBlur = 20;
ctx.lineCap = 'round';
ctx.lineJoin = 'round';
// Draw top curve
ctx.beginPath();
ctx.moveTo(topPoints[0].x, topPoints[0].y);
for (let i = 1; i < topPoints.length; i++) {
const prev = topPoints[i-1];
const curr = topPoints[i];
const midX = (prev.x + curr.x) / 2;
const midY = (prev.y + curr.y) / 2;
ctx.quadraticCurveTo(prev.x, prev.y, midX, midY);
}
ctx.stroke();
// Draw bottom curve
ctx.beginPath();
ctx.moveTo(bottomPoints[0].x, bottomPoints[0].y);
for (let i = 1; i < bottomPoints.length; i++) {
const prev = bottomPoints[i-1];
const curr = bottomPoints[i];
const midX = (prev.x + curr.x) / 2;
const midY = (prev.y + curr.y) / 2;
ctx.quadraticCurveTo(prev.x, prev.y, midX, midY);
}
ctx.stroke();
// Draw connecting lines at edges
ctx.beginPath();
ctx.moveTo(topPoints[0].x, topPoints[0].y);
ctx.lineTo(bottomPoints[0].x, bottomPoints[0].y);
ctx.moveTo(topPoints[topPoints.length-1].x, topPoints[topPoints.length-1].y);
ctx.lineTo(bottomPoints[bottomPoints.length-1].x, bottomPoints[bottomPoints.length-1].y);
ctx.stroke();
ctx.shadowBlur = 0;
}
checkCollision(px, py, pr) {
// Check collision with top and bottom curves
for (let i = 0; i < this.points.length - 1; i++) {
const p1 = this.points[i];
const p2 = this.points[i+1];
// Top curve
const topY1 = p1.y - this.gateSize / 2;
const topY2 = p2.y - this.gateSize / 2;
if (this.lineCircleCollision(p1.x, topY1, p2.x, topY2, px, py, pr)) return true;
// Bottom curve
const botY1 = p1.y + this.gateSize / 2;
const botY2 = p2.y + this.gateSize / 2;
if (this.lineCircleCollision(p1.x, botY1, p2.x, botY2, px, py, pr)) return true;
}
// Check side walls
const leftX = this.points[0].x;
const rightX = this.points[this.points.length-1].x;
if (px - pr < leftX && px + pr > leftX) {
const topY = this.points[0].y - this.gateSize / 2;
const botY = this.points[0].y + this.gateSize / 2;
if (py > topY && py < botY) return true;
}
if (px - pr < rightX && px + pr > rightX) {
const topY = this.points[this.points.length-1].y - this.gateSize / 2;
const botY = this.points[this.points.length-1].y + this.gateSize / 2;
if (py > topY && py < botY) return true;
}
return false;
}
lineCircleCollision(x1, y1, x2, y2, cx, cy, r) {
const dx = x2 - x1;
const dy = y2 - y1;
const fx = x1 - cx;
const fy = y1 - cy;
const a = dx * dx + dy * dy;
const b = 2 * (fx * dx + fy * dy);
const c = fx * fx + fy * fy - r * r;
let discriminant = b * b - 4 * a * c;
if (discriminant < 0) return false;
discriminant = Math.sqrt(discriminant);
const t1 = (-b - discriminant) / (2 * a);
const t2 = (-b + discriminant) / (2 * a);
if (t1 >= 0 && t1 <= 1) return true;
if (t2 >= 0 && t2 <= 1) return true;
return false;
}
}
// ============================================
// INITIALIZATION
// ============================================
function init() {
player.x = canvas.width / 2;
player.y = canvas.height * 0.7;
player.targetX = player.x;
player.targetY = player.y;
player.radius = player.baseRadius;
player.inflation = 0;
player.boost = false;
player.boostCooldown = 0;
worldY = 0;
worldSpeed = 80;
score = 0;
gameOver = false;
gameOverEl.style.display = 'none';
obstacles = [];
nextObstacleY = -200;
// Generate initial obstacles
for (let i = 0; i < 5; i++) {
const obs = new Obstacle(nextObstacleY);
obstacles.push(obs);
nextObstacleY -= OBSTACLE_SPACING;
}
// Reset audio
if (audioCtx) {
audioCtx.resume();
}
}
// ============================================
// GAME LOOP
// ============================================
function update(dt) {
if (paused || gameOver) return;
time += dt;
worldSpeed = 80 + score * 0.5;
// Player physics
const mouseX = player.targetX;
const mouseY = player.targetY;
// Spring physics for smooth movement
const springForce = 8;
const damping = 0.85;
player.vx += (mouseX - player.x) * springForce * dt;
player.vy += (mouseY - player.y) * springForce * dt;
player.vx *= damping;
player.vy *= damping;
// Boost
if (player.boost && player.boostCooldown <= 0) {
player.vy -= 300 * dt;
player.boostCooldown = 0.5;
playPulse(440, 0.2, 0.1);
}
player.boostCooldown -= dt;
player.x += player.vx * dt;
player.y += player.vy * dt;
// Keep in bounds
player.x = Math.max(player.radius, Math.min(canvas.width - player.radius, player.x));
player.y = Math.max(player.radius, Math.min(canvas.height - player.radius, player.y));
// Inflation/deflation based on altitude
const altitude = canvas.height - player.y;
const targetInflation = Math.max(0, (altitude - 100) / 500);
player.inflation += (targetInflation - player.inflation) * dt * 2;
player.radius = player.baseRadius + player.inflation * 10;
// World scroll
worldY += worldSpeed * dt;
// Update obstacles
for (let i = obstacles.length - 1; i >= 0; i--) {
const obs = obstacles[i];
obs.y += worldSpeed * dt;
obs.update(dt);
// Check collision
if (obs.checkCollision(player.x, player.y, player.radius)) {
endGame();
return;
}
// Check if passed
if (!obs.passed && obs.y > player.y + player.radius) {
obs.passed = true;
score++;
scoreEl.textContent = score;
playGateSweep();
}
// Remove if off screen
if (obs.y > canvas.height + 100) {
obstacles.splice(i, 1);
}
}
// Generate new obstacles
if (obstacles.length < 5) {
const lastY = obstacles.length > 0 ? Math.min(...obstacles.map(o => o.y)) : 0;
const newObs = new Obstacle(lastY - OBSTACLE_SPACING);
obstacles.push(newObs);
}
// Update altitude display
altitudeEl.textContent = Math.max(0, Math.floor(altitude));
// Ambient pulse
if (audioCtx && Math.random() < dt * 0.5) {
playPulse(110 + Math.random() * 110, 0.5, 0.05);
}
}
function draw() {
// Clear with gradient background
const gradient = ctx.createLinearGradient(0, 0, 0, canvas.height);
gradient.addColorStop(0, '#1a1a2e');
gradient.addColorStop(0.5, '#16213e');
gradient.addColorStop(1, '#0f3460');
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Draw subtle grid lines
ctx.strokeStyle = 'rgba(255,255,255,0.03)';
ctx.lineWidth = 1;
for (let y = 0; y < canvas.height; y += 50) {
ctx.beginPath();
ctx.moveTo(0, y);
ctx.lineTo(canvas.width, y);
ctx.stroke();
}
for (let x = 0; x < canvas.width; x += 50) {
ctx.beginPath();
ctx.moveTo(x, 0);
ctx.lineTo(x, canvas.height);
ctx.stroke();
}
// Draw obstacles
for (const obs of obstacles) {
obs.draw();
}
// Draw player sphere
ctx.save();
ctx.shadowColor = '#e0e0e0';
ctx.shadowBlur = 30;
// Outer glow
const glowGradient = ctx.createRadialGradient(
player.x, player.y, 0,
player.x, player.y, player.radius * 2
);
glowGradient.addColorStop(0, 'rgba(255,255,255,0.3)');
glowGradient.addColorStop(1, 'rgba(255,255,255,0)');
ctx.fillStyle = glowGradient;
ctx.beginPath();
ctx.arc(player.x, player.y, player.radius * 2, 0, Math.PI * 2);
ctx.fill();
// Main sphere
const sphereGradient = ctx.createRadialGradient(
player.x - player.radius * 0.3, player.y - player.radius * 0.3, 0,
player.x, player.y, player.radius
);
sphereGradient.addColorStop(0, '#ffffff');
sphereGradient.addColorStop(0.7, '#e0e0e0');
sphereGradient.addColorStop(1, '#a0a0a0');
ctx.fillStyle = sphereGradient;
ctx.beginPath();
ctx.arc(player.x, player.y, player.radius, 0, Math.PI * 2);
ctx.fill();
// Inner detail
ctx.shadowBlur = 0;
ctx.strokeStyle = 'rgba(255,255,255,0.3)';
ctx.lineWidth = 1;
ctx.beginPath();
ctx.arc(player.x, player.y, player.radius * 0.6, 0, Math.PI * 2);
ctx.stroke();
ctx.restore();
// Draw boost indicator
if (player.boostCooldown > 0) {
ctx.fillStyle = 'rgba(255,255,255,0.2)';
ctx.beginPath();
ctx.arc(player.x, player.y, player.radius + 10, 0, Math.PI * 2);
ctx.fill();
}
}
function endGame() {
gameOver = true;
gameOverEl.style.display = 'block';
playPulse(80, 1, 0.3);
}
function restartGame() {
init();
}
// ============================================
// MAIN LOOP
// ============================================
let lastFrameTime = performance.now();
function gameLoop(timestamp) {
const dt = Math.min((timestamp - lastFrameTime) / 1000, 0.05);
lastFrameTime = timestamp;
update(dt);
draw();
requestAnimationFrame(gameLoop);
}
// ============================================
// EVENT LISTENERS
// ============================================
canvas.addEventListener('mousemove', (e) => {
player.targetX = e.clientX;
player.targetY = e.clientY;
});
canvas.addEventListener('click', () => {
initAudio();
player.boost = true;
setTimeout(() => player.boost = false, 100);
});
canvas.addEventListener('contextmenu', (e) => {
e.preventDefault();
player.boost = true;
setTimeout(() => player.boost = false, 100);
});
window.addEventListener('keydown', (e) => {
if (e.code === 'Space') {
e.preventDefault();
paused = !paused;
}
});
// Initialize
init();
requestAnimationFrame(gameLoop);
// Start audio on first interaction
document.addEventListener('click', initAudio, { once: true });
</script>
</body>
</html>
ログインして完全なプロンプトを表示
次で続行:
ログインすると、次に同意したことになります: 利用規約 と プライバシーポリシー
使い方
このプロンプトは coding 向けに設計されています。上の内容をコピーして、お好みの AI ツールに貼り付けてください。
最良の結果を得るには、プレースホルダー(角括弧や大文字で示された部分)を具体的な要件に置き換えてください。
ノート
0 件のコメント