CoinFlip - 抛硬币
CoinFlip 是一个基于Canvas的3D硬币抛掷游戏组件,提供真实的硬币翻转动画和统计功能。
📦 导入
import { CoinFlip } from '@randbox/react';
import type { CoinFlipProps, CoinFlipResult, CoinFlipStats } from '@randbox/react';🎯 类型定义
CoinFlipProps
interface CoinFlipProps {
// 可选属性
animationDuration?: number; // 动画时长(毫秒),默认2000
showStats?: boolean; // 是否显示统计,默认true
// 基础属性(继承自BaseGameProps)
className?: string; // CSS类名
style?: React.CSSProperties; // 内联样式
disabled?: boolean; // 是否禁用
// 回调函数
onGameStart?: () => void; // 游戏开始回调
onGameEnd?: (result: CoinFlipResult) => void; // 游戏结束回调
onResult?: (result: CoinFlipResult) => void; // 结果回调
}CoinFlipResult
interface CoinFlipResult {
result: 'heads' | 'tails'; // 硬币结果:正面或反面
round: number; // 回合数
timestamp: number; // 时间戳
}CoinFlipStats
interface CoinFlipStats {
totalFlips: number; // 总抛掷次数
heads: number; // 正面次数
tails: number; // 反面次数
headsRate: string; // 正面概率(百分比)
tailsRate: string; // 反面概率(百分比)
}📋 API参考
CoinFlipProps
| 属性 | 类型 | 默认值 | 描述 |
|---|---|---|---|
animationDuration | number | 2000 | 动画持续时间(毫秒) |
showStats | boolean | true | 是否显示统计信息 |
className | string | '' | CSS类名 |
style | React.CSSProperties | {} | 内联样式 |
disabled | boolean | false | 是否禁用 |
onGameStart | () => void | undefined | 游戏开始回调 |
onGameEnd | (result) => void | undefined | 游戏结束回调 |
onResult | (result) => void | undefined | 结果回调 |
CoinFlipResult 结构
{
result: "heads", // "heads" 或 "tails"
round: 1, // 当前回合数
timestamp: 1234567890 // 时间戳
}CoinFlipStats 结构
{
totalFlips: 10, // 总抛掷次数
heads: 6, // 正面次数
tails: 4, // 反面次数
headsRate: "60.0", // 正面概率(百分比)
tailsRate: "40.0" // 反面概率(百分比)
}🚀 基础用法
import React from 'react';
import { CoinFlip } from '@randbox/react';
function BasicCoinFlip() {
const handleResult = (result) => {
console.log('抛币结果:', result);
alert(`结果是:${result.result === 'heads' ? '正面' : '反面'}`);
};
return (
<CoinFlip onResult={handleResult} />
);
}🎨 高级用法
自定义动画时长
function FastCoinFlip() {
return (
<div>
<h3>快速模式(1秒)</h3>
<CoinFlip animationDuration={1000} />
<h3>慢速模式(3秒)</h3>
<CoinFlip animationDuration={3000} />
</div>
);
}隐藏统计信息
function SimpleCoinFlip() {
return (
<CoinFlip
showStats={false}
animationDuration={1500}
onResult={(result) => {
console.log('结果:', result.result);
}}
/>
);
}完整配置示例
function FullConfigCoinFlip() {
const [isFlipping, setIsFlipping] = useState(false);
const [history, setHistory] = useState<CoinFlipResult[]>([]);
const [stats, setStats] = useState<CoinFlipStats>({
totalFlips: 0,
heads: 0,
tails: 0,
headsRate: '0',
tailsRate: '0'
});
const handleGameStart = () => {
setIsFlipping(true);
console.log('开始抛硬币...');
};
const handleGameEnd = (result: CoinFlipResult) => {
setIsFlipping(false);
setHistory(prev => [result, ...prev.slice(0, 9)]);
// 更新统计
const newStats = {
totalFlips: stats.totalFlips + 1,
heads: stats.heads + (result.result === 'heads' ? 1 : 0),
tails: stats.tails + (result.result === 'tails' ? 1 : 0),
headsRate: '0',
tailsRate: '0'
};
newStats.headsRate = ((newStats.heads / newStats.totalFlips) * 100).toFixed(1);
newStats.tailsRate = ((newStats.tails / newStats.totalFlips) * 100).toFixed(1);
setStats(newStats);
};
return (
<div style={{ padding: '20px' }}>
<CoinFlip
animationDuration={2000}
showStats={true}
className="my-coin-flip"
disabled={isFlipping}
onGameStart={handleGameStart}
onGameEnd={handleGameEnd}
onResult={(result) => {
console.log('实时结果:', result);
}}
/>
{/* 抛币历史 */}
{history.length > 0 && (
<div style={{ marginTop: '20px' }}>
<h3>最近10次记录:</h3>
<div style={{ display: 'flex', gap: '5px', flexWrap: 'wrap' }}>
{history.map((result, index) => (
<span
key={index}
style={{
padding: '5px 10px',
backgroundColor: result.result === 'heads' ? '#2ecc71' : '#e74c3c',
color: 'white',
borderRadius: '5px',
fontSize: '12px'
}}
>
{result.result === 'heads' ? '正面' : '反面'}
</span>
))}
</div>
</div>
)}
{/* 统计汇总 */}
<div style={{ marginTop: '20px', padding: '15px', backgroundColor: '#f5f5f5' }}>
<h3>统计汇总</h3>
<p>总次数:{stats.totalFlips}</p>
<p>正面:{stats.heads} 次 ({stats.headsRate}%)</p>
<p>反面:{stats.tails} 次 ({stats.tailsRate}%)</p>
</div>
</div>
);
}📋 API参考
属性说明
| 属性 | 类型 | 默认值 | 描述 |
|---|---|---|---|
animationDuration | number | 2000 | 动画持续时间(毫秒) |
showStats | boolean | true | 是否显示统计信息 |
className | string | '' | CSS类名 |
style | React.CSSProperties | {} | 内联样式 |
disabled | boolean | false | 是否禁用 |
onGameStart | () => void | undefined | 游戏开始回调 |
onGameEnd | (result) => void | undefined | 游戏结束回调 |
onResult | (result) => void | undefined | 结果回调 |
CoinFlipResult 结构
{
result: "heads", // "heads" 或 "tails"
round: 1, // 当前回合数
timestamp: 1234567890 // 时间戳
}🎨 样式定制
容器样式
.my-coin-flip {
border: 3px solid #f39c12;
border-radius: '20px';
padding: '20px';
box-shadow: 0 10px 30px rgba(0,0,0,0.3);
}🔧 高级功能
猜硬币游戏
function GuessCoinGame() {
const [guess, setGuess] = useState<'heads' | 'tails' | null>(null);
const [score, setScore] = useState({ wins: 0, losses: 0 });
const handleResult = (result: CoinFlipResult) => {
if (guess === result.result) {
setScore(prev => ({ ...prev, wins: prev.wins + 1 }));
alert('猜对了!🎉');
} else {
setScore(prev => ({ ...prev, losses: prev.losses + 1 }));
alert('猜错了!😢');
}
setGuess(null);
};
return (
<div>
<h3>猜硬币游戏</h3>
<p>战绩 - 赢:{score.wins} 输:{score.losses}</p>
<div style={{ marginBottom: '20px' }}>
<button onClick={() => setGuess('heads')} disabled={guess !== null}>
猜正面
</button>
<button onClick={() => setGuess('tails')} disabled={guess !== null}>
猜反面
</button>
</div>
<CoinFlip
disabled={guess === null}
onResult={handleResult}
/>
{guess && <p>你的选择:{guess === 'heads' ? '正面' : '反面'}</p>}
</div>
);
}🎯 最佳实践
1. 概率验证
// 大量实验验证随机性
function ProbabilityTest() {
const [trials, setTrials] = useState(0);
const [heads, setHeads] = useState(0);
const runTrials = (n: number) => {
for (let i = 0; i < n; i++) {
// 模拟抛币...
}
};
return (
<div>
<button onClick={() => runTrials(1000)}>运行1000次</button>
<p>总次数:{trials}</p>
<p>正面率:{(heads / trials * 100).toFixed(2)}%</p>
<p>理论值:50%</p>
</div>
);
}🐛 常见问题
Q: 结果真的是随机的吗?
A: 是的,使用RandBox的Mersenne Twister算法,确保高质量的随机性。
Q: 可以预测结果吗?
A: 不可以,每次抛币都是独立事件,无法预测。
Q: 为什么连续出现多次相同结果?
A: 这是正常的随机现象,类似现实中的连续正面或反面。
🔗 相关链接
最后更新于: