Kmin/php-raylib排行榜系统:玩家成绩统计与显示

【免费下载链接】php-raylib 🔥 PHP-FFI 绑 定 raylib,实 现 享 受 视 频 游 戏 编 程。 【免费下载链接】php-raylib 项目地址: https://gitcode.com/Kmin/php-raylib

还在为游戏排行榜功能而烦恼?想要在PHP游戏中实现专业的成绩统计和排名显示?本文将为你展示如何利用php-raylib构建完整的排行榜系统,从数据存储到可视化展示,一站式解决玩家成绩管理难题。

你将获得

  • 基于文件存储的成绩持久化方案
  • 实时更新的排行榜渲染技术
  • 多种排序算法实现
  • 美观的UI界面设计
  • 完整的代码示例和最佳实践

排行榜系统架构设计

mermaid

核心组件实现

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应用中。现在就开始在你的项目中实现专业的排行榜功能吧!

【免费下载链接】php-raylib 🔥 PHP-FFI 绑 定 raylib,实 现 享 受 视 频 游 戏 编 程。 【免费下载链接】php-raylib 项目地址: https://gitcode.com/Kmin/php-raylib

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐