根据php项目,协防补位成功次数?

wen PHP项目 1

PHP项目中统计"协防补位成功次数"的实现方案

由于你没有提供具体的项目代码,我给出一个通用的设计思路和实现方案,你可以根据实际项目结构进行调整。

根据php项目,协防补位成功次数?

先明确业务概念

协防补位成功通常指:

  • 玩家 A 的防守位置被攻击时,玩家 B 前往支援
  • B 到达时该位置仍在战斗中
  • 最终防守成功(未被攻破)

不同游戏定义不同,需要先确认清楚。

数据库设计

方案1:日志表 + 聚合统计(推荐)

-- 协防行为记录表
CREATE TABLE `assist_defense_log` (
  `id` BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
  `helper_id` INT UNSIGNED NOT NULL COMMENT '协防者UID',
  `target_id` INT UNSIGNED NOT NULL COMMENT '被协防者UID',
  `battle_id` BIGINT UNSIGNED NOT NULL COMMENT '战斗ID',
  `position_id` INT NOT NULL COMMENT '补位位置',
  `status` TINYINT NOT NULL DEFAULT 0 COMMENT '0进行中 1成功 2失败',
  `created_at` INT UNSIGNED NOT NULL,
  `finished_at` INT UNSIGNED DEFAULT 0,
  KEY `idx_helper_status` (`helper_id`, `status`),
  KEY `idx_battle` (`battle_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

方案2:计数器字段(查询快)

ALTER TABLE `user_stat`
  ADD COLUMN `assist_defense_success` INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '协防补位成功次数',
  ADD COLUMN `assist_defense_total` INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '协防补位总次数';

PHP 代码实现

记录协防行为(战斗开始时)

class AssistDefenseService
{
    private PDO $db;
    public function __construct(PDO $db)
    {
        $this->db = $db;
    }
    /**
     * 记录协防补位(战斗开始时调用)
     */
    public function recordAssist(int $helperId, int $targetId, int $battleId, int $positionId): int
    {
        $sql = "INSERT INTO assist_defense_log 
                (helper_id, target_id, battle_id, position_id, status, created_at)
                VALUES (:helper_id, :target_id, :battle_id, :position_id, 0, :now)";
        $stmt = $this->db->prepare($sql);
        $stmt->execute([
            ':helper_id'   => $helperId,
            ':target_id'   => $targetId,
            ':battle_id'   => $battleId,
            ':position_id' => $positionId,
            ':now'         => time(),
        ]);
        return (int)$this->db->lastInsertId();
    }
    /**
     * 战斗结束时更新结果(协防成功才累计)
     */
    public function finishAssist(int $battleId, bool $defenseSuccess): void
    {
        $this->db->beginTransaction();
        try {
            // 找出这场战斗的所有协防记录
            $stmt = $this->db->prepare(
                "SELECT id, helper_id FROM assist_defense_log 
                 WHERE battle_id = :bid AND status = 0 FOR UPDATE"
            );
            $stmt->execute([':bid' => $battleId]);
            $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
            if (empty($rows)) {
                $this->db->commit();
                return;
            }
            $newStatus = $defenseSuccess ? 1 : 2;
            // 更新日志状态
            $updateStmt = $this->db->prepare(
                "UPDATE assist_defense_log 
                 SET status = :status, finished_at = :now 
                 WHERE id = :id"
            );
            // 成功则累加用户统计
            $incStmt = $this->db->prepare(
                "UPDATE user_stat 
                 SET assist_defense_success = assist_defense_success + 1,
                     assist_defense_total = assist_defense_total + 1
                 WHERE uid = :uid"
            );
            $incTotalStmt = $this->db->prepare(
                "UPDATE user_stat 
                 SET assist_defense_total = assist_defense_total + 1
                 WHERE uid = :uid"
            );
            foreach ($rows as $row) {
                $updateStmt->execute([
                    ':status' => $newStatus,
                    ':now'    => time(),
                    ':id'     => $row['id'],
                ]);
                if ($defenseSuccess) {
                    $incStmt->execute([':uid' => $row['helper_id']]);
                } else {
                    $incTotalStmt->execute([':uid' => $row['helper_id']]);
                }
            }
            $this->db->commit();
        } catch (Throwable $e) {
            $this->db->rollBack();
            throw $e;
        }
    }
}

查询某玩家的协防补位成功次数

/**
 * 从计数器读(推荐,需保证写入时同步)
 */
public function getAssistSuccessCount(int $uid): int
{
    $stmt = $this->db->prepare(
        "SELECT assist_defense_success FROM user_stat WHERE uid = :uid"
    );
    $stmt->execute([':uid' => $uid]);
    return (int)($stmt->fetchColumn() ?: 0);
}
/**
 * 从日志表实时聚合(数据量大时慢,适合对账)
 */
public function getAssistSuccessCountByLog(int $uid): int
{
    $stmt = $this->db->prepare(
        "SELECT COUNT(*) FROM assist_defense_log 
         WHERE helper_id = :uid AND status = 1"
    );
    $stmt->execute([':uid' => $uid]);
    return (int)$stmt->fetchColumn();
}

进阶:Redis 缓存加速

如果是高并发游戏,用 Redis 做实时计数:

class AssistDefenseCounter
{
    private Redis $redis;
    private PDO $db;
    public function __construct(Redis $redis, PDO $db)
    {
        $this->redis = $redis;
        $this->db = $db;
    }
    public function incr(int $uid, int $delta = 1): void
    {
        $key = "assist:success:{$uid}";
        $this->redis->incrBy($key, $delta);
        // 加入待持久化队列
        $this->redis->sAdd('assist:sync:pending', $uid);
    }
    public function get(int $uid): int
    {
        $key = "assist:success:{$uid}";
        if ($this->redis->exists($key)) {
            // 缓存没命中就回源
        }
        $val = $this->redis->get($key);
        if ($val !== false) {
            return (int)$val;
        }
        return $this->getAssistSuccessCount($uid);
    }
    /** 定时任务批量刷回 DB */
    public function flushToDb(): void
    {
        $uids = $this->redis->sMembers('assist:sync:pending');
        foreach ($uids as $uid) {
            $val = (int)$this->redis->get("assist:success:{$uid}");
            // 更新 MySQL...
            $this->redis->sRem('assist:sync:pending', $uid);
        }
    }
}

需要你补充的信息

要给出贴合你项目的代码,请告诉我:

  1. 框架:Laravel / ThinkPHP / 原生 PHP / Hyperf / Swoole?
  2. 业务定义:怎么才算"协防补位成功"?(战斗胜利?补位到位?)
  3. 触发点:哪个接口/事件里触发(战斗结算、定时任务?)
  4. 表结构:现有的用户表、战斗表、日志表字段?
  5. 统计需求:是实时查、定时统计、还是活动期内累计?

把关键代码/表结构贴出来,我可以帮你直接改写成可落地的代码。

抱歉,评论功能暂时关闭!