首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

手機網遊服務端數據處理:遊戲狀態管理與邏輯引擎設計

     編輯:Java 相關知識

遊戲服務端核心在於數據處理:用戶狀態、房間管理、地圖實體、實時同步。本文深入剖析《瘋狂的炸彈》數據模型、移動驗證、炸彈邏輯與狀態持久化。

核心數據模型

房間/遊戲數據聚合根


public class GameRoom {
    private final long roomId;
    private final long user1, user2;
    private final GameMap map;
    private final Map players = new ConcurrentHashMap<>();
    private final List bombs = new CopyOnWriteArrayList<>();
    private volatile RoomState state = RoomState.WAITING;
    private long lastFrameTime = System.currentTimeMillis();
    
    // 狀態機
    enum RoomState { WAITING, PLAYING, FINISHED }
    
    // 地圖分層數據 (11行 x 10列)
    static class GameMap {
        final byte[][] boxLayer = new byte[11][10];      // 箱子層
        final byte[][] treeLayer = new byte[11][10];     // 樹木層
        final byte[][] houseLayer = new byte[11][10];    // 房子層
        final byte[][] brushLayer = new byte[11][10];    // 草叢層
        final byte[][] bombLayer = new byte[11][10];     // 炸彈層
        
        // 初始化地圖
        void initialize() { /* 從配置加載或程序生成 */ }
    }
}

玩家實體


public class Player {
    private final long userId;
    private int row, col;           // 格子坐標 (0-10, 0-9)
    private byte direction;         // 0上 1下 2左 3右
    private byte hp = 3;            // 生命值
    private boolean alive = true;
    private int score = 0;
    
    // 移動驗證
    boolean canMove(int newRow, int newCol, GameMap map) {
        if (newRow < 0 || newRow >= 11 || newCol < 0 || newCol >= 10) return false;
        // 檢查阻擋層:箱子/樹木/房子/炸彈
        return map.boxLayer[newRow][newCol] == 0 
            && map.treeLayer[newRow][newCol] == 0
            && map.houseLayer[newRow][newCol] == 0
            && map.bombLayer[newRow][newCol] == 0;
    }
}

移動邏輯處理


public class LogicEngine {
    
    public static MoveResult processMove(GameRoom room, long userId, byte direction) {
        Player player = room.getPlayers().get(userId);
        if (player == null || !player.isAlive()) return MoveResult.DEAD;
        
        // 1. 計算目標位置
        int newRow = player.getRow();
        int newCol = player.getCol();
        switch (direction) {
            case 0: newRow--; break;  // 上
            case 1: newRow++; break;  // 下
            case 2: newCol--; break;  // 左
            case 3: newCol++; break;  // 右
        }
        
        // 2. 邊界檢查
        if (newRow < 0 || newRow >= 11 || newCol < 0 || newCol >= 10) {
            return MoveResult.OUT_OF_BOUNDS;
        }
        
        // 3. 碰撞檢查
        GameMap map = room.getMap();
        byte targetCell = map.boxLayer[newRow][newCol];
        
        if (targetCell == 0) { // 空地,直接移動
            player.setRow(newRow);
            player.setCol(newCol);
            player.setDirection(direction);
            return MoveResult.SUCCESS;
        }
        
        // 4. 推箱子邏輯
        if (isBox(targetCell)) {
            int boxNewRow = newRow + (newRow - player.getRow());
            int boxNewCol = newCol + (newCol - player.getCol());
            
            if (isValidPush(boxNewRow, boxNewCol, map)) {
                // 移動箱子
                map.boxLayer[boxNewRow][boxNewCol] = targetCell;
                map.boxLayer[newRow][newCol] = 0;
                
                // 玩家移動
                player.setRow(newRow);
                player.setCol(newCol);
                player.setDirection(direction);
                return MoveResult.BOX_PUSHED;
            }
            return MoveResult.BLOCKED;
        }
        
        return MoveResult.BLOCKED; // 其他阻擋物
    }
    
    private static boolean isValidPush(int r, int c, GameMap map) {
        if (r < 0 || r >= 11 || c < 0 || c >= 10) return false;
        return map.boxLayer[r][c] == 0 
            && map.treeLayer[r][c] == 0
            && map.houseLayer[r][c] == 0
            && map.bombLayer[r][c] == 0;
    }
}

炸彈生命週期管理


public class Bomb {
    private final int row, col;
    private final long ownerId;
    private final long placeTime;
    private final int power = 3; // 爆炸範圍
    private volatile BombState state = BombState.TICKING;
    
    enum BombState { TICKING, EXPLODED, REMOVED }
    
    // 爆炸判定
    public ExplosionResult explode(GameMap map, Map players) {
        if (state != BombState.TICKING) return ExplosionResult.NONE;
        state = BombState.EXPLODED;
        
        List cells = new ArrayList<>();
        cells.add(new ExplosionCell(row, col, ExplosionType.CENTER));
        
        // 四方向擴散
        for (Direction dir : Direction.values()) {
            for (int i = 1; i <= power; i++) {
                int r = row + dir.dr * i;
                int c = col + dir.dc * i;
                if (r < 0 || r >= 11 || c < 0 || c >= 10) break;
                
                byte cell = map.boxLayer[r][c];
                if (cell != 0) { // 遇到箱子停止並炸毀
                    cells.add(new ExplosionCell(r, c, ExplosionType.DESTROY_BOX));
                    map.boxLayer[r][c] = 0;
                    break;
                }
                cells.add(new ExplosionCell(r, c, ExplosionType.FLAME));
                // 檢查玩家傷害
                for (Player p : players.values()) {
                    if (p.getRow() == r && p.getCol() == c && p.isAlive()) {
                        p.hurt(1);
                    }
                }
            }
        }
        map.bombLayer[row][col] = 0;
        state = BombState.REMOVED;
        return new ExplosionResult(cells);
    }
}

幀同步與狀態持久化

增量幀編碼


public class FrameEncoder {
    public static byte[] encodeDelta(GameRoom room, long lastAckFrame) {
        ByteBuffer buf = ByteBuffer.allocate(1024);
        buf.putInt(room.getCurrentFrameId());
        
        // 只編碼變更的實體
        List changes = room.getChangesSince(lastAckFrame);
        buf.putShort((short) changes.size());
        for (EntityChange change : changes) {
            change.encode(buf);
        }
        return Arrays.copyOf(buf.array(), buf.position());
    }
}

異步持久化策略


@Repository
public class GameRepository {
    private final RedisTemplate redis;
    private final JdbcTemplate jdbc;
    
    // 實時寫入Redis(高頻)
    public void saveRoomState(GameRoom room) {
        String key = "room:" + room.getRoomId();
        redis.opsForValue().set(key, JsonUtils.toJson(room), 1, TimeUnit.HOURS);
    }
    
    // 定時落地MySQL(低頻)
    @Scheduled(fixedRate = 30000) // 30秒
    public void persistToDb() {
        List dirtyRooms = getDirtyRooms();
        for (GameRoom room : dirtyRooms) {
            jdbc.update("UPDATE rooms SET state=?, data=? WHERE id=?",
                room.getState(), JsonUtils.toJson(room), room.getRoomId());
            room.markClean();
        }
    }
}

數據一致性保障

場景風險對策
併發移動位置競態房間級鎖/單線程邏輯循環
炸彈爆炸傷害重複/遺漏狀態機+原子狀態變更
斷線重連狀態不同步全量同步+增量補全
服務器重啟數據丟失WAL日誌/定時快照

核心原則:邏輯單線程化(避免鎖競爭)、狀態機驅動(明確狀態流轉)、增量同步(降低帶寬)、異步持久化(不阻塞主循環)。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved