本文目录导读:

在PHP项目中做“地面对抗”(通常指地面战斗/地面战)的胜负统计,并没有一个固定模板,因为“谁胜出”取决于你的业务逻辑(是PVE打怪、PVP玩家对战,还是模拟战争策略)。
但如果你是想实现一个“统计某一方(如玩家阵营 vs 敌方阵营)在地面战斗中的胜率”的功能,核心在于数据记录和聚合查询。
以下给你提供一套完整的实现思路和代码示例,覆盖从数据库设计到PHP输出统计结果的完整流程。
第一步:数据库设计(假设使用 MySQL)
你至少需要一张战斗记录表,记录每次地面战斗的结果。
CREATE TABLE `ground_battles` ( `id` INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, `battle_time` DATETIME NOT NULL COMMENT '战斗发生时间', `map_name` VARCHAR(50) DEFAULT NULL COMMENT '地图名称(可选)', -- 攻击方 `attacker_type` TINYINT NOT NULL COMMENT '类型:1=玩家, 2=NPC/怪物, 3=联盟A, 4=联盟B', `attacker_id` INT UNSIGNED NOT NULL COMMENT '攻击方ID(玩家ID或军团ID)', `attacker_name` VARCHAR(100) DEFAULT NULL COMMENT '攻击方名称(冗余存储)', -- 防守方 `defender_type` TINYINT NOT NULL, `defender_id` INT UNSIGNED NOT NULL, `defender_name` VARCHAR(100) DEFAULT NULL, -- 结果 `winner` TINYINT NOT NULL COMMENT '胜者:1=攻击方, 2=防守方, 3=平局', `damage_dealt` INT UNSIGNED DEFAULT 0 COMMENT '攻击方输出伤害', `damage_taken` INT UNSIGNED DEFAULT 0 COMMENT '攻击方承受伤害', INDEX idx_attacker (attacker_type, attacker_id), INDEX idx_defender (defender_type, defender_id), INDEX idx_time (battle_time) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
第二步:PHP 统计业务逻辑(核心代码)
假设你需要统计“玩家阵营”作为攻击方时,在地面对抗中的胜率。
<?php
/**
* 统计地面对抗胜负
* 场景:统计指定玩家(或阵营)作为攻击方时的胜率
*
* @param PDO $pdo 数据库连接
* @param int $playerId 玩家ID
* @return array
*/
function getGroundBattleStats(PDO $pdo, int $playerId): array
{
// 1. 基础统计:总场次、胜场、负场、平局
$sql = "
SELECT
COUNT(*) AS total_battles,
SUM(CASE WHEN winner = 1 THEN 1 ELSE 0 END) AS wins,
SUM(CASE WHEN winner = 2 THEN 1 ELSE 0 END) AS losses,
SUM(CASE WHEN winner = 3 THEN 1 ELSE 0 END) AS draws
FROM ground_battles
WHERE attacker_type = 1 -- 1代表玩家
AND attacker_id = :playerId
";
$stmt = $pdo->prepare($sql);
$stmt->execute([':playerId' => $playerId]);
$stats = $stmt->fetch(PDO::FETCH_ASSOC);
// 2. 防止除以零,计算胜率(平局通常不计入胜率,或单独统计)
$totalBattles = (int)($stats['total_battles'] ?? 0);
$wins = (int)($stats['wins'] ?? 0);
$losses = (int)($stats['losses'] ?? 0);
$draws = (int)($stats['draws'] ?? 0);
// 胜率计算方式:胜场 / (胜场+负场) * 100%(平局不算胜率分母)
$decisiveBattles = $wins + $losses;
$winRate = $decisiveBattles > 0
? round(($wins / $decisiveBattles) * 100, 2)
: 0.0;
// 3. 如果你想看“最近7天”的趋势,可以加时间筛选
// WHERE battle_time >= DATE_SUB(NOW(), INTERVAL 7 DAY)
return [
'player_id' => $playerId,
'total_battles' => $totalBattles,
'wins' => $wins,
'losses' => $losses,
'draws' => $draws,
'win_rate' => $winRate, // 百分比,如 66.67
'lose_rate' => $decisiveBattles > 0 ? round(($losses / $decisiveBattles) * 100, 2) : 0.0,
'last_updated' => date('Y-m-d H:i:s'),
];
}
// 使用示例
// $pdo = new PDO(...);
// $result = getGroundBattleStats($pdo, 1001);
// echo json_encode($result);
第三步:进阶场景(联盟/军团之间的对抗)
如果你的项目是联盟战争(联盟A vs 联盟B),你需要统计的是对抗胜率(A赢了B几次,B赢了A几次)。
/**
* 统计两个阵营(联盟)之间的地面对抗胜负
*
* @param PDO $pdo
* @param int $allianceAId
* @param int $allianceBId
* @return array
*/
function getAllianceVsAllianceStats(PDO $pdo, int $allianceAId, int $allianceBId): array
{
// 情况1:A攻击B,且A胜
$a_win = 0;
$b_win = 0;
$sql = "
SELECT
SUM(CASE
WHEN attacker_id = :aId AND defender_id = :bId AND winner = 1 THEN 1
WHEN attacker_id = :bId AND defender_id = :aId AND winner = 2 THEN 1
ELSE 0 END
) AS a_wins,
SUM(CASE
WHEN attacker_id = :bId AND defender_id = :aId AND winner = 1 THEN 1
WHEN attacker_id = :aId AND defender_id = :bId AND winner = 2 THEN 1
ELSE 0 END
) AS b_wins
FROM ground_battles
WHERE (attacker_id = :aId AND defender_id = :bId)
OR (attacker_id = :bId AND defender_id = :aId)
";
$stmt = $pdo->prepare($sql);
$stmt->execute([
':aId' => $allianceAId,
':bId' => $allianceBId,
]);
$result = $stmt->fetch(PDO::FETCH_ASSOC);
$a_wins = (int)$result['a_wins'];
$b_wins = (int)$result['b_wins'];
$total = $a_wins + $b_wins;
return [
'alliance_a_id' => $allianceAId,
'alliance_b_id' => $allianceBId,
'a_wins' => $a_wins,
'b_wins' => $b_wins,
'total_battles' => $total,
'a_win_rate' => $total > 0 ? round(($a_wins / $total) * 100, 2) : 0,
'b_win_rate' => $total > 0 ? round(($b_wins / $total) * 100, 2) : 0,
];
}
第四步:优化与扩展建议
-
缓存(Redis/Memcached):胜率统计如果实时计算且数据量大,会很消耗DB,建议把统计结果缓存起来,比如每5分钟刷新一次。
$cacheKey = "ground_battle_stats:" . $playerId; $stats = $redis->get($cacheKey); if (!$stats) { $stats = getGroundBattleStats($pdo, $playerId); $redis->setex($cacheKey, 300, json_encode($stats)); // 5分钟过期 } -
分页与历史追踪:如果要做“历史战绩”页面,需要分页查询
ground_battles表,并展示时间、对手、胜负图标。 -
存储过程或事件调度:如果项目很大,可以用MySQL的
EVENT每天凌晨跑一次统计,存入player_battle_summary表,避免实时计算。 -
“地面对抗”的判定:如果你的项目有“空中战”和“地面战”之分,记得在查询条件里加上
battle_type = 'ground'字段,否则统计会包含其他类型的战斗。
- 核心表:建一张
ground_battles表,用winner字段(1=攻胜,2=守胜)来判定胜负。 - 核心统计:用
COUNT和SUM(CASE WHEN...)聚合统计,避免使用GROUP BY导致全表扫描。 - 输出:返回JSON给前端,展示胜率、总场次、胜负场数等。
如果你的业务是实时榜单(比如全服对战胜率排名),可以在此基础上用GROUP BY attacker_id ORDER BY win_rate DESC LIMIT 10来实现。
如果你需要更具体的场景(比如按兵种、按地图),告诉我,我再细化!