package game import ( "sync" "time" "github.com/wonderivan/logger" ) //房间 type Room struct { Lock sync.Mutex ID int //玩家列表 PlayerList []*Player //游戏开始时,会给房间中的各个玩家定义一个ID PlayerIds map[*Player]int //玩家上传的帧数据,发送出去后需要清空 Frames []interface{} //是否有效,设置为false后,会被协程销毁 IsValid bool //是否处于匹配阶段 Matching bool //最多容纳几个玩家 MaxPlayerCount int } var roomListLock sync.Mutex var roomList []*Room //玩家匹配并进入一个房间 func MatchAndEnterRoom(player *Player) { roomListLock.Lock() defer roomListLock.Unlock() //看能否进入已有的房间 for _, v := range roomList { if v.enter(player, true) { return } } //不能就进入新建的房间 addNewRoom(false).enter(player, true) } //新增一个房间(创建房间) func addNewRoom(lock bool) *Room { if lock { roomListLock.Lock() defer roomListLock.Unlock() } room := &Room{ID: GetUuidInt("Room"), IsValid: true, Matching: true, MaxPlayerCount: 4} roomList = append(roomList, room) logger.Info("Room ID", room.ID, "Created") go room.autoCheckCompleteMatchingAndStartGame() return room } //移除一个房间(销毁房间) func removeRoom(room *Room) { roomListLock.Lock() defer roomListLock.Unlock() for k, v := range roomList { if v == room { roomList = append(roomList[:k], roomList[k+1:]...) logger.Info("Room ID", room.ID, "Removed") break } } } //让玩家进入 func (room *Room) enter(player *Player, onlyEnterWhenMatching bool) bool { room.Lock.Lock() defer room.Lock.Unlock() if onlyEnterWhenMatching && !room.Matching { return false } if len(room.PlayerList) < room.MaxPlayerCount { room.PlayerList = append(room.PlayerList, player) player.Room = room logger.Info("Room ID", room.ID, "A Player Enter, Total Member Count", len(room.PlayerList)) if room.Matching && len(room.PlayerList) == room.MaxPlayerCount { room.Matching = false } return true } return false } //让玩家离开 func (room *Room) Leave(player *Player) { room.Lock.Lock() defer room.Lock.Unlock() for k, v := range room.PlayerList { if v == player { room.PlayerList = append(room.PlayerList[:k], room.PlayerList[k+1:]...) player.Room = nil if room.PlayerIds != nil { playerId := room.PlayerIds[player] delete(room.PlayerIds, player) room.Frames = append(room.Frames, NewSyncFrame_PlayerLeave(playerId)) } logger.Info("Room ID", room.ID, "A Player Leave, Total Member Count", len(room.PlayerList)) break } } if len(room.PlayerList) == 0 { room.IsValid = false removeRoom(room) } } //自动结束匹配(需要协程开启) func (room *Room) autoCheckCompleteMatchingAndStartGame() { //循环等待匹配结束 checkStartTime := time.Now().UnixMilli() checkInterval := time.Duration(100) * time.Millisecond for room.Matching { time.Sleep(checkInterval) //房间最多匹配几秒 if time.Now().UnixMilli()-checkStartTime >= 6000 { room.Lock.Lock() room.Matching = false room.Lock.Unlock() } } //结束匹配 room.completeMatching() //延迟2秒 time.Sleep(time.Duration(2) * time.Second) //通知玩家开始游戏 room.startGame() //开启自动帧同步 go room.autoFrameSync() } //完成匹配 func (room *Room) completeMatching() { room.Lock.Lock() defer room.Lock.Unlock() //记录玩家数据 playerInfos := make(map[int]interface{}) room.PlayerIds = make(map[*Player]int) for k, v := range room.PlayerList { room.PlayerIds[v] = k playerInfos[k] = v.userInfo } uuid := NewUUID() timestamp := time.Now().UnixMilli() for k, v := range room.PlayerList { v.Notify_onMatchComplete(k, playerInfos, uuid, timestamp) } logger.Info("Room ID", room.ID, "Matching Completed") } //开始游戏 func (room *Room) startGame() { room.Lock.Lock() defer room.Lock.Unlock() for _, v := range room.PlayerList { v.Notify_onGameStart() } logger.Info("Room ID", room.ID, "Game Start") } //自动帧同步(需要协程开启) func (room *Room) autoFrameSync() { loopInterval := time.Duration(33) * time.Millisecond logger.Info("Room ID", room.ID, "Frame Sync Start") lastHandleTime := time.Now().UnixMilli() currentHandleTime := lastHandleTime for room.IsValid { time.Sleep(loopInterval) currentHandleTime = time.Now().UnixMilli() room.Frames = append(room.Frames, NewSyncFrame_DeltaTime(currentHandleTime-lastHandleTime)) lastHandleTime = currentHandleTime room.sendFrames() } logger.Info("Room ID", room.ID, "Frame Sync Stop") } //向房间内所有玩家发送同步帧 func (room *Room) sendFrames() { room.Lock.Lock() defer room.Lock.Unlock() if len(room.Frames) > 0 { for _, v := range room.PlayerList { v.Notify_onFrameSync(room.Frames) } room.Frames = nil } } //缓存玩家上传的帧数据 func (room *Room) CacheFrames(frames []interface{}) { room.Lock.Lock() defer room.Lock.Unlock() room.Frames = append(room.Frames, frames...) }