Kmin/php-raylib排行榜系统:玩家成绩统计与显示
·
Kmin/php-raylib排行榜系统:玩家成绩统计与显示
还在为游戏排行榜功能而烦恼?想要在PHP游戏中实现专业的成绩统计和排名显示?本文将为你展示如何利用php-raylib构建完整的排行榜系统,从数据存储到可视化展示,一站式解决玩家成绩管理难题。
你将获得
- 基于文件存储的成绩持久化方案
- 实时更新的排行榜渲染技术
- 多种排序算法实现
- 美观的UI界面设计
- 完整的代码示例和最佳实践
排行榜系统架构设计
核心组件实现
1. 成绩数据结构定义
<?php
class PlayerScore {
public string $playerName;
public int $score;
public int $timestamp;
public int $level;
public function __construct(string $name, int $score, int $level = 1) {
$this->playerName = $name;
$this->score = $score;
$this->timestamp = time();
$this->level = $level;
}
public function toArray(): array {
return [
'name' => $this->playerName,
'score' => $this->score,
'time' => $this->timestamp,
'level' => $this->level
];
}
public static function fromArray(array $data): PlayerScore {
$score = new PlayerScore($data['name'], $data['score'], $data['level']);
$score->timestamp = $data['time'];
return $score;
}
}
2. 成绩存储管理器
class ScoreManager {
private string $dataFile;
private array $scores = [];
private const MAX_RECORDS = 100;
public function __construct(string $filename = 'scores.json') {
$this->dataFile = $filename;
$this->loadScores();
}
public function addScore(PlayerScore $score): bool {
$this->scores[] = $score;
// 按分数降序排序
usort($this->scores, function($a, $b) {
return $b->score <=> $a->score;
});
// 只保留前MAX_RECORDS条记录
$this->scores = array_slice($this->scores, 0, self::MAX_RECORDS);
return $this->saveScores();
}
public function getTopScores(int $limit = 10): array {
return array_slice($this->scores, 0, $limit);
}
public function getPlayerRank(string $playerName): int {
foreach ($this->scores as $index => $score) {
if ($score->playerName === $playerName) {
return $index + 1;
}
}
return -1;
}
private function loadScores(): void {
if (file_exists($this->dataFile)) {
$data = json_decode(file_get_contents($this->dataFile), true);
foreach ($data as $scoreData) {
$this->scores[] = PlayerScore::fromArray($scoreData);
}
}
}
private function saveScores(): bool {
$data = array_map(function($score) {
return $score->toArray();
}, $this->scores);
return file_put_contents($this->dataFile, json_encode($data, JSON_PRETTY_PRINT)) !== false;
}
}
3. 排行榜渲染器
class LeaderboardRenderer {
use Kingbes\Raylib\Core;
use Kingbes\Raylib\Text;
use Kingbes\Raylib\Shapes;
use Kingbes\Raylib\Utils;
private int $screenWidth;
private int $screenHeight;
private array $colors;
public function __construct(int $width = 800, int $height = 600) {
$this->screenWidth = $width;
$this->screenHeight = $height;
$this->initializeColors();
}
private function initializeColors(): void {
$this->colors = [
'background' => $this->color(40, 40, 40, 255),
'header' => $this->color(70, 130, 180, 255),
'row_even' => $this->color(60, 60, 60, 255),
'row_odd' => $this->color(50, 50, 50, 255),
'text' => $this->color(255, 255, 255, 255),
'highlight' => $this->color(255, 215, 0, 255),
'border' => $this->color(100, 100, 100, 255)
];
}
public function render(array $scores, string $currentPlayer = ''): void {
$this->beginDrawing();
$this->clearBackground($this->colors['background']);
// 绘制标题
$this->drawHeader();
// 绘制表格
$this->drawTable($scores, $currentPlayer);
$this->endDrawing();
}
private function drawHeader(): void {
$headerHeight = 60;
$headerY = 20;
// 绘制标题背景
$this->drawRectangle(50, $headerY, $this->screenWidth - 100, $headerHeight, $this->colors['header']);
// 绘制标题文本
$title = "游戏排行榜";
$titleWidth = $this->measureText($title, 32);
$titleX = ($this->screenWidth - $titleWidth) / 2;
$this->drawText($title, $titleX, $headerY + 15, 32, $this->colors['text']);
}
private function drawTable(array $scores, string $currentPlayer): void {
$tableX = 100;
$tableY = 100;
$tableWidth = $this->screenWidth - 200;
$rowHeight = 40;
// 绘制表头
$this->drawTableHeader($tableX, $tableY, $tableWidth, $rowHeight);
// 绘制数据行
$y = $tableY + $rowHeight;
foreach ($scores as $index => $score) {
$isCurrentPlayer = $score->playerName === $currentPlayer;
$rowColor = $index % 2 === 0 ? $this->colors['row_even'] : $this->colors['row_odd'];
if ($isCurrentPlayer) {
$rowColor = $this->colors['highlight'];
}
$this->drawTableRow($tableX, $y, $tableWidth, $rowHeight, $score, $index + 1, $rowColor, $isCurrentPlayer);
$y += $rowHeight;
}
}
private function drawTableHeader(int $x, int $y, int $width, int $height): void {
$this->drawRectangle($x, $y, $width, $height, $this->colors['header']);
$columnWidth = $width / 4;
$textY = $y + ($height - 20) / 2;
$this->drawText("排名", $x + 10, $textY, 20, $this->colors['text']);
$this->drawText("玩家名称", $x + $columnWidth + 10, $textY, 20, $this->colors['text']);
$this->drawText("分数", $x + $columnWidth * 2 + 10, $textY, 20, $this->colors['text']);
$this->drawText("时间", $x + $columnWidth * 3 + 10, $textY, 20, $this->colors['text']);
}
private function drawTableRow(int $x, int $y, int $width, int $height, PlayerScore $score, int $rank, $color, bool $highlight): void {
$this->drawRectangle($x, $y, $width, $height, $color);
$columnWidth = $width / 4;
$textY = $y + ($height - 20) / 2;
// 排名
$rankText = "#" . $rank;
$this->drawText($rankText, $x + 10, $textY, 20, $this->colors['text']);
// 玩家名称
$nameText = $score->playerName;
if (strlen($nameText) > 15) {
$nameText = substr($nameText, 0, 12) . "...";
}
$this->drawText($nameText, $x + $columnWidth + 10, $textY, 20, $this->colors['text']);
// 分数
$scoreText = number_format($score->score);
$this->drawText($scoreText, $x + $columnWidth * 2 + 10, $textY, 20, $this->colors['text']);
// 时间
$timeText = date('Y-m-d H:i', $score->timestamp);
$this->drawText($timeText, $x + $columnWidth * 3 + 10, $textY, 18, $this->colors['text']);
// 高亮边框
if ($highlight) {
$this->drawRectangleLines($x, $y, $width, $height, $this->colors['highlight']);
}
}
}
完整示例:游戏排行榜系统
<?php
require dirname(__DIR__) . "/vendor/autoload.php";
use Kingbes\Raylib\Core;
use Kingbes\Raylib\Text;
use Kingbes\Raylib\Utils;
class GameLeaderboardDemo {
private ScoreManager $scoreManager;
private LeaderboardRenderer $renderer;
private string $currentPlayer;
public function __construct() {
$this->scoreManager = new ScoreManager();
$this->renderer = new LeaderboardRenderer(800, 600);
$this->currentPlayer = "Player" . rand(1000, 9999);
// 初始化一些测试数据
$this->initializeTestData();
}
private function initializeTestData(): void {
// 添加一些示例分数
$names = ["Alice", "Bob", "Charlie", "David", "Eva", "Frank", "Grace"];
foreach ($names as $name) {
$score = new PlayerScore($name, rand(1000, 50000), rand(1, 10));
$this->scoreManager->addScore($score);
}
// 添加当前玩家分数
$currentScore = new PlayerScore($this->currentPlayer, rand(500, 80000), rand(1, 10));
$this->scoreManager->addScore($currentScore);
}
public function run(): void {
Core::initWindow(800, 600, "游戏排行榜演示");
Core::setTargetFPS(60);
while (!Core::windowShouldClose()) {
$this->handleInput();
$this->update();
$this->render();
}
Core::closeWindow();
}
private function handleInput(): void {
// 模拟游戏结束,添加新分数
if (Core::isKeyPressed(KEY_SPACE)) {
$newScore = new PlayerScore($this->currentPlayer, rand(1000, 100000), rand(1, 10));
$this->scoreManager->addScore($newScore);
}
}
private function update(): void {
// 更新逻辑可以在这里添加
}
private function render(): void {
$topScores = $this->scoreManager->getTopScores(15);
$this->renderer->render($topScores, $this->currentPlayer);
// 显示操作提示
$hintText = "按空格键模拟游戏结束并添加新分数";
Text::drawText($hintText, 50, 550, 20, Utils::color(200, 200, 200, 255));
// 显示当前玩家排名
$playerRank = $this->scoreManager->getPlayerRank($this->currentPlayer);
$rankText = "当前排名: #" . ($playerRank > 0 ? $playerRank : "未上榜");
Text::drawText($rankText, 50, 520, 20, Utils::color(255, 215, 0, 255));
}
}
// 运行演示
$demo = new GameLeaderboardDemo();
$demo->run();
高级功能扩展
1. 多维度排序算法
class AdvancedScoreManager extends ScoreManager {
public function getScoresByLevel(int $level): array {
return array_filter($this->scores, function($score) use ($level) {
return $score->level === $level;
});
}
public function getScoresByTimeRange(int $startTime, int $endTime): array {
return array_filter($this->scores, function($score) use ($startTime, $endTime) {
return $score->timestamp >= $startTime && $score->timestamp <= $endTime;
});
}
public function getPlayerHistory(string $playerName): array {
return array_filter($this->scores, function($score) use ($playerName) {
return $score->playerName === $playerName;
});
}
}
2. 数据统计分析
class ScoreAnalytics {
private array $scores;
public function __construct(array $scores) {
$this->scores = $scores;
}
public function getAverageScore(): float {
$total = array_sum(array_map(function($score) {
return $score->score;
}, $this->scores));
return count($this->scores) > 0 ? $total / count($this->scores) : 0;
}
public function getMedianScore(): float {
$scores = array_map(function($score) {
return $score->score;
}, $this->scores);
sort($scores);
$count = count($scores);
if ($count === 0) return 0;
if ($count % 2 === 0) {
return ($scores[$count/2 - 1] + $scores[$count/2]) / 2;
}
return $scores[floor($count/2)];
}
public function getScoreDistribution(int $buckets = 10): array {
$maxScore = max(array_map(function($score) {
return $score->score;
}, $this->scores));
$bucketSize = ceil($maxScore / $buckets);
$distribution = array_fill(0, $buckets, 0);
foreach ($this->scores as $score) {
$bucket = min((int)($score->score / $bucketSize), $buckets - 1);
$distribution[$bucket]++;
}
return $distribution;
}
}
性能优化建议
内存管理优化
class OptimizedScoreManager extends ScoreManager {
private const CACHE_TTL = 300; // 5分钟缓存
private array $cachedTopScores = [];
private int $lastCacheTime = 0;
public function getTopScores(int $limit = 10): array {
$currentTime = time();
// 使用缓存提高性能
if ($currentTime - $this->lastCacheTime < self::CACHE_TTL &&
isset($this->cachedTopScores[$limit])) {
return $this->cachedTopScores[$limit];
}
$scores = parent::getTopScores($limit);
$this->cachedTopScores[$limit] = $scores;
$this->lastCacheTime = $currentTime;
return $scores;
}
public function addScore(PlayerScore $score): bool {
// 清空缓存
$this->cachedTopScores = [];
return parent::addScore($score);
}
}
数据库集成方案
class DatabaseScoreManager {
private PDO $db;
public function __construct(PDO $db) {
$this->db = $db;
$this->initializeDatabase();
}
private function initializeDatabase(): void {
$this->db->exec("
CREATE TABLE IF NOT EXISTS scores (
id INTEGER PRIMARY KEY AUTOINCREMENT,
player_name TEXT NOT NULL,
score INTEGER NOT NULL,
level INTEGER NOT NULL,
timestamp INTEGER NOT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
)
");
$this->db->exec("CREATE INDEX IF NOT EXISTS idx_score ON scores(score DESC)");
$this->db->exec("CREATE INDEX IF NOT EXISTS idx_player ON scores(player_name)");
}
public function addScore(PlayerScore $score): bool {
$stmt = $this->db->prepare("
INSERT INTO scores (player_name, score, level, timestamp)
VALUES (:name, :score, :level, :timestamp)
");
return $stmt->execute([
':name' => $score->playerName,
':score' => $score->score,
':level' => $score->level,
':timestamp' => $score->timestamp
]);
}
public function getTopScores(int $limit = 10): array {
$stmt = $this->db->prepare("
SELECT player_name, score, level, timestamp
FROM scores
ORDER BY score DESC
LIMIT :limit
");
$stmt->bindValue(':limit', $limit, PDO::PARAM_INT);
$stmt->execute();
$scores = [];
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
$scores[] = new PlayerScore(
$row['player_name'],
$row['score'],
$row['level']
);
}
return $scores;
}
}
总结
通过本文的完整实现,你已经掌握了在php-raylib中构建专业排行榜系统的核心技术。从基础的数据结构设计到高级的统计分析功能,这个系统具备了现代游戏排行榜的所有核心特性。
关键收获:
- 学会了成绩数据的持久化存储方案
- 掌握了基于php-raylib的UI渲染技术
- 理解了多种排序和统计算法的实现
- 获得了性能优化和扩展的最佳实践
这个排行榜系统不仅适用于游戏开发,还可以扩展到任何需要排名和统计功能的PHP应用中。现在就开始在你的项目中实现专业的排行榜功能吧!
更多推荐


所有评论(0)