如何让GameState结构体泛型适配Sure/SometimesSure两种可见性类型?
用泛型适配服务器与客户端的游戏状态复用
要复用GameState结构体适配服务器(全可见)和客户端(部分隐藏)两种场景,核心思路是让MapState、PlayerStates以及GameState都接受一个可见性包装器的泛型参数,用Sure和SometimesSure分别填充这个参数来实现不同场景的适配。
步骤1:修正类型定义并添加泛型约束
首先修正SometimesSure的拼写错误(Visibile改为Visible),然后给MapState、PlayerStates和GameState添加泛型参数V,这个参数代表用于包装数据的可见性类型(Sure或SometimesSure):
// 客户端可见性包装:支持隐藏/显示数据 enum SometimesSure<T> { Hidden, Visible(T), } // 服务器可见性包装:确保数据始终可见 struct Sure<T>(T); // 泛型地图状态,V 为可见性包装器 struct MapState<V> { pub tiles: Vec<V<u8>>, } // 泛型玩家状态,V 为可见性包装器 struct PlayerStates<V> { pub points: V<bool>, pub name: V<String>, } // 泛型游戏状态,复用可见性包装器泛型 struct GameState<V> { pub map_state: MapState<V>, pub player_states: PlayerStates<V>, }
步骤2:用Trait增强约束(可选)
如果需要统一处理两种包装类型的行为(比如获取内部值、构造实例),可以定义一个trait并让Sure和SometimesSure实现它,给泛型添加更明确的约束:
trait VisibilityWrapper<T> { // 从原始值构造包装实例 fn wrap(value: T) -> Self; // 获取内部值(Sure 返回 Some,Hidden 返回 None) fn get(&self) -> Option<&T>; } impl<T> VisibilityWrapper<T> for Sure<T> { fn wrap(value: T) -> Self { Sure(value) } fn get(&self) -> Option<&T> { Some(&self.0) } } impl<T> VisibilityWrapper<T> for SometimesSure<T> { fn wrap(value: T) -> Self { SometimesSure::Visible(value) } fn get(&self) -> Option<&T> { match self { SometimesSure::Visible(val) => Some(val), SometimesSure::Hidden => None, } } } // 更新泛型结构体的约束,确保V是合法的可见性包装器 struct MapState<V> where V: for<T> VisibilityWrapper<T>, { pub tiles: Vec<V<u8>>, } struct PlayerStates<V> where V: for<T> VisibilityWrapper<T>, { pub points: V<bool>, pub name: V<String>, } struct GameState<V> where V: for<T> VisibilityWrapper<T>, { pub map_state: MapState<V>, pub player_states: PlayerStates<V>, }
步骤3:实例化不同场景的游戏状态
现在可以分别创建服务器和客户端的游戏状态实例:
服务器端(全可见)
let server_map = MapState { tiles: vec![Sure(1), Sure(2), Sure(3)], }; let server_players = PlayerStates { points: Sure(true), name: Sure("Alice".to_string()), }; let server_game_state = GameState { map_state: server_map, player_states: server_players, };
客户端(部分隐藏)
let client_map = MapState { tiles: vec![ SometimesSure::Visible(1), SometimesSure::Hidden, SometimesSure::Visible(3), ], }; let client_players = PlayerStates { points: SometimesSure::Hidden, // 隐藏玩家分数 name: SometimesSure::Visible("Alice".to_string()), // 显示玩家名字 }; let client_game_state = GameState { map_state: client_map, player_states: client_players, };
额外:从服务器状态生成客户端状态
可以给服务器端的GameState添加方法,根据游戏逻辑生成对应客户端的可见状态:
impl GameState<Sure> { fn to_client_state(&self) -> GameState<SometimesSure> { GameState { map_state: MapState { tiles: self.map_state.tiles.iter() .map(|tile| { // 示例:随机隐藏部分 tiles if rand::random() { SometimesSure::Visible(tile.0) } else { SometimesSure::Hidden } }) .collect(), }, player_states: PlayerStates { points: SometimesSure::Hidden, name: SometimesSure::Visible(self.player_states.name.0.clone()), }, } } }
内容的提问来源于stack exchange,提问作者Tadeo Hepperle
相关产品推荐
相关产品推荐

