如何在Rust中消除代码重复,实现处理各类实体的泛型函数
用Rust泛型统一实体碰撞检测实现
核心思路
通过定义一个trait提取所有可碰撞实体的共性,再基于这个trait编写泛型碰撞检测函数,替代多个特定实体的重复函数。
步骤实现
1. 定义可碰撞实体的Trait
先创建Collidable trait,包含碰撞所需的核心方法:获取位置、半径,以及销毁实体的kill方法:
// 假设你已有Position结构体及distance方法 #[derive(Debug, Clone, Copy)] struct Position { x: f32, y: f32, } impl Position { fn distance(&self, other: &Self) -> f32 { ((self.x - other.x).powi(2) + (self.y - other.y).powi(2)).sqrt() } } // 可碰撞实体的统一Trait trait Collidable { fn position(&self) -> &Position; fn radius(&self) -> f32; fn kill(&mut self); }
2. 让所有实体实现Trait
给Asteroid、Player、Laser分别实现Collidable trait,对齐它们的碰撞相关行为:
// 假设你的实体基础结构如下 struct Entity { position: Position, // 其他通用字段... } struct Asteroid { entity: Entity, radius: f32, alive: bool, } struct Player { entity: Entity, radius: f32, alive: bool, } struct Laser { entity: Entity, radius: f32, alive: bool, } // Asteroid实现Collidable impl Collidable for Asteroid { fn position(&self) -> &Position { &self.entity.position } fn radius(&self) -> f32 { self.radius } fn kill(&mut self) { self.alive = false; // 其他销毁逻辑... } } // Player实现Collidable impl Collidable for Player { fn position(&self) -> &Position { &self.entity.position } fn radius(&self) -> f32 { self.radius } fn kill(&mut self) { self.alive = false; // 其他销毁逻辑... } } // Laser实现Collidable impl Collidable for Laser { fn position(&self) -> &Position { &self.entity.position } fn radius(&self) -> f32 { self.radius } fn kill(&mut self) { self.alive = false; // 其他销毁逻辑... } }
3. 编写泛型碰撞检测函数
不同类型实体间的碰撞
处理两个不同实体集合的碰撞逻辑:
pub fn check_collision_between<T: Collidable, U: Collidable>(entities_a: &mut Vec<T>, entities_b: &mut Vec<U>) { for a in entities_a.iter_mut() { for b in entities_b.iter_mut() { let distance = a.position().distance(b.position()); if distance < a.radius() + b.radius() { a.kill(); b.kill(); } } } }
同类型实体间的碰撞
处理同一实体集合内的碰撞,需要跳过自身避免误判:
pub fn check_collision_within<T: Collidable + PartialEq>(entities: &mut Vec<T>) { for i in 0..entities.len() { for j in (i + 1)..entities.len() { let a = &mut entities[i]; let b = &mut entities[j]; let distance = a.position().distance(b.position()); if distance < a.radius() + b.radius() { a.kill(); b.kill(); } } } }
4. 替换原有函数调用
现在可以用这两个泛型函数替代所有特定场景的碰撞检测:
// 替代小行星与玩家的碰撞检测 check_collision_between(asteroids, players); // 替代玩家间的碰撞检测 check_collision_within(players); // 替代激光与玩家的碰撞检测 check_collision_between(lasers, players); // 替代激光与小行星的碰撞检测 check_collision_between(lasers, asteroids);
补充说明
- 泛型方案属于轻量重构,无需引入ECS框架,适合中小规模项目或快速迭代场景。
- 若后续实体复杂度提升、需要更灵活的属性组合,ECS依然是更优选择,它能进一步解耦实体的属性与行为。
内容的提问来源于stack exchange,提问作者user3453345
相关产品推荐
相关产品推荐

