街機清版遊戲場景動畫
動畫模擬街機清版遊戲:主角從左端持劍往右端前進,沿途打倒六個彩色反派,抵達 GOAL 旗幟。
遊戲開發街機遊戲SVG動畫角色動畫
提示詞(可直接修改內容)
import React from "react";
import {
AbsoluteFill,
useCurrentFrame,
useVideoConfig,
interpolate,
spring,
} from "remotion";
const colors = {
background: "#0A0E14",
backgroundGradient: "linear-gradient(135deg, #0A0E14 0%, #131A24 100%)",
accent: "#00D4AA",
accentSecondary: "#4DA3FF",
warning: "#FFB547",
danger: "#FF6B6B",
dimmed: "rgba(255, 255, 255, 0.6)",
};
const fonts = { main: "'Inter', 'Noto Sans TC', sans-serif" };
const ENEMIES = [
{ x: 380, color: "#E74C3C", size: 28, delay: 60 },
{ x: 520, color: "#C0392B", size: 32, delay: 90 },
{ x: 600, color: "#E67E22", size: 26, delay: 100 },
{ x: 740, color: "#E74C3C", size: 30, delay: 130 },
{ x: 830, color: "#9B59B6", size: 36, delay: 150 },
{ x: 950, color: "#C0392B", size: 28, delay: 165 },
];
export const Scene33-ArcadeBeatEmUp: React.FC = () => {
const frame = useCurrentFrame();
const { fps } = useVideoConfig();
const titleSpring = spring({ frame: Math.max(0, frame - 5), fps, config: { damping: 10, mass: 0.5, stiffness: 120 } });
const titleScale = interpolate(titleSpring, [0, 1], [0.3, 1]);
const titleOpacity = interpolate(frame, [5, 25], [0, 1], { extrapolateLeft: "clamp", extrapolateRight: "clamp" });
const titleFade = interpolate(frame, [40, 55], [1, 0], { extrapolateLeft: "clamp", extrapolateRight: "clamp" });
const stageOpacity = interpolate(frame, [30, 50], [0, 1], { extrapolateLeft: "clamp", extrapolateRight: "clamp" });
const heroProgress = interpolate(frame, [50, 220], [0, 1], { extrapolateLeft: "clamp", extrapolateRight: "clamp" });
const heroX = interpolate(heroProgress, [0, 1], [80, 1020]);
const heroOpacity = interpolate(frame, [45, 55], [0, 1], { extrapolateLeft: "clamp", extrapolateRight: "clamp" });
const heroBob = frame >= 50 && frame < 220 ? Math.sin(frame * 0.3) * 4 : 0;
const getHitFlash = (enemyDelay: number) => {
const hitFrame = enemyDelay + 15;
return interpolate(frame, [hitFrame, hitFrame + 4, hitFrame + 8], [0, 1, 0], { extrapolateLeft: "clamp", extrapolateRight: "clamp" });
};
const fadeOut = interpolate(frame, [240, 270], [1, 0], { extrapolateLeft: "clamp", extrapolateRight: "clamp" });
const glowPulse = interpolate(Math.sin(frame * 0.04), [-1, 1], [0.03, 0.08]);
const stageW = 1100;
const stageH = 400;
const groundY = 280;
return (
<AbsoluteFill style={{ background: colors.backgroundGradient }}>
<div style={{ position: "absolute", top: "50%", left: "50%", width: 900, height: 900, borderRadius: "50%", background: `radial-gradient(circle, ${colors.accent}08 0%, transparent 60%)`, transform: "translate(-50%, -50%)", opacity: glowPulse * fadeOut }} />
<AbsoluteFill style={{ display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", opacity: fadeOut }}>
<div style={{ position: "absolute", top: 120, fontSize: 78, fontWeight: 800, fontFamily: fonts.main, letterSpacing: 6, opacity: titleOpacity * titleFade, transform: `scale(${titleScale})` }}>
<span style={{ background: `linear-gradient(90deg, ${colors.accent}, ${colors.warning})`, WebkitBackgroundClip: "text", WebkitTextFillColor: "transparent" }}>街機遊戲</span>
</div>
<svg width={stageW * 1.5} height={stageH * 1.5} viewBox={`0 0 ${stageW} ${stageH}`} style={{ opacity: stageOpacity }}>
<rect x="60" y="120" width="80" height="160" rx="4" fill="#FFFFFF08" />
<rect x="160" y="80" width="60" height="200" rx="4" fill="#FFFFFF06" />
<rect x="250" y="140" width="90" height="140" rx="4" fill="#FFFFFF05" />
<rect x="380" y="100" width="70" height="180" rx="4" fill="#FFFFFF07" />
<rect x="500" y="130" width="100" height="150" rx="4" fill="#FFFFFF05" />
<rect x="640" y="90" width="60" height="190" rx="4" fill="#FFFFFF06" />
<rect x="730" y="150" width="80" height="130" rx="4" fill="#FFFFFF04" />
<rect x="860" y="110" width="70" height="170" rx="4" fill="#FFFFFF07" />
<rect x="960" y="140" width="90" height="140" rx="4" fill="#FFFFFF05" />
<rect x="20" y={groundY} width={stageW - 40} height="8" rx="4" fill="#FFFFFF20" />
{[0, 1, 2, 3, 4, 5, 6, 7, 8].map((i) => (
<rect key={i} x={60 + i * 120} y={groundY + 15} width={60} height="3" rx="1.5" fill="#FFFFFF0a" />
))}
<g opacity={interpolate(frame, [55, 70], [0, 0.4], { extrapolateLeft: "clamp", extrapolateRight: "clamp" })}>
<line x1="80" y1={groundY + 35} x2="1020" y2={groundY + 35} stroke="#FFFFFF" strokeWidth="2" strokeDasharray="8 6" opacity={0.15} />
<polygon points="1025,35 1010,28 1010,42" fill="#FFFFFF" opacity={0.15} transform={`translate(0, ${groundY})`} />
</g>
{ENEMIES.map((enemy, i) => {
const eSpring = spring({ frame: Math.max(0, frame - enemy.delay), fps, config: { damping: 10, mass: 0.5, stiffness: 130 } });
const eScale = interpolate(eSpring, [0, 1], [0, 1]);
const eOp = interpolate(eSpring, [0, 0.2], [0, 1], { extrapolateRight: "clamp" });
const defeated = heroX > enemy.x - 20;
const hitFlash = getHitFlash(enemy.delay);
const defeatOp = defeated ? interpolate(frame, [enemy.delay + 15, enemy.delay + 25], [1, 0], { extrapolateLeft: "clamp", extrapolateRight: "clamp" }) : 1;
const enemyBob = !defeated ? Math.sin(frame * 0.15 + i * 3) * 3 : 0;
const r = enemy.size;
return (
<g key={i} transform={`translate(${enemy.x}, ${groundY - r - 8 + enemyBob}) scale(${eScale})`} opacity={eOp * defeatOp}>
<rect x={-r * 0.6} y={-r * 0.4} width={r * 1.2} height={r * 1.4} rx={6} fill={enemy.color} opacity={0.8} />
<circle cx={0} cy={-r * 0.7} r={r * 0.45} fill={enemy.color} opacity={0.9} />
<circle cx={-r * 0.15} cy={-r * 0.75} r={3} fill="#FFFFFF" />
<circle cx={r * 0.15} cy={-r * 0.75} r={3} fill="#FFFFFF" />
{hitFlash > 0 && <circle cx={0} cy={-r * 0.3} r={r * 1.2} fill={colors.warning} opacity={hitFlash * 0.5} />}
</g>
);
})}
<g transform={`translate(${heroX}, ${groundY - 38 + heroBob})`} opacity={heroOpacity}>
<rect x={-16} y={-10} width={32} height={40} rx={8} fill={colors.accent} opacity={0.9} />
<circle cx={0} cy={-22} r={14} fill={colors.accent} />
<circle cx={-5} cy={-24} r={2.5} fill="#FFFFFF" />
<circle cx={5} cy={-24} r={2.5} fill="#FFFFFF" />
{frame >= 50 && (
<g>
<line x1={18} y1={-5} x2={42} y2={-15} stroke={colors.warning} strokeWidth={4} strokeLinecap="round" />
<circle cx={44} cy={-16} r={3} fill={colors.warning} opacity={0.8} />
</g>
)}
<circle cx={0} cy={0} r={35} fill="none" stroke={colors.accent} strokeWidth="1.5" opacity={0.2 + Math.sin(frame * 0.08) * 0.1} />
</g>
<text x={80} y={groundY + 50} textAnchor="middle" fontSize="18" fontWeight="700" fontFamily={fonts.main} fill="#FFFFFF50" opacity={stageOpacity}>START</text>
<g opacity={interpolate(frame, [180, 200], [0, 1], { extrapolateLeft: "clamp", extrapolateRight: "clamp" })}>
<line x1={1020} y1={groundY - 60} x2={1020} y2={groundY} stroke="#FFFFFFaa" strokeWidth="2" />
<polygon points={`1022,${groundY - 58} 1055,${groundY - 48} 1022,${groundY - 38}`} fill={colors.warning} opacity={0.8} />
<text x={1020} y={groundY + 50} textAnchor="middle" fontSize="18" fontWeight="700" fontFamily={fonts.main} fill={`${colors.warning}90`}>GOAL</text>
</g>
</svg>
</AbsoluteFill>
</AbsoluteFill>
);
};登入後查看完整程式碼