rust/hwphysics/src/collision.rs
branchui-scaling
changeset 15288 c4fd2813b127
parent 15279 42b710b0f883
child 15287 478d5372eb4a
equal deleted inserted replaced
13395:0135e64c6c66 15288:c4fd2813b127
       
     1 use std::ops::RangeInclusive;
       
     2 
       
     3 use crate::{
       
     4     common::{GearData, GearDataProcessor, GearId},
       
     5     grid::Grid,
       
     6     physics::PhysicsData,
       
     7 };
       
     8 
       
     9 use fpnum::*;
       
    10 use integral_geometry::{GridIndex, Point, Size};
       
    11 use land2d::Land2D;
       
    12 
       
    13 pub fn fppoint_round(point: &FPPoint) -> Point {
       
    14     Point::new(point.x().round(), point.y().round())
       
    15 }
       
    16 
       
    17 #[derive(PartialEq, Eq, Clone, Copy, Debug)]
       
    18 pub struct CircleBounds {
       
    19     pub center: FPPoint,
       
    20     pub radius: FPNum,
       
    21 }
       
    22 
       
    23 impl CircleBounds {
       
    24     pub fn intersects(&self, other: &CircleBounds) -> bool {
       
    25         (other.center - self.center).is_in_range(self.radius + other.radius)
       
    26     }
       
    27 
       
    28     pub fn rows(&self) -> impl Iterator<Item = (usize, RangeInclusive<usize>)> {
       
    29         let radius = self.radius.abs_round() as usize;
       
    30         let center = Point::from_fppoint(&self.center);
       
    31         (center.y as usize - radius..=center.y as usize + radius)
       
    32             .map(move |row| (row, center.x as usize - radius..=center.x as usize + radius))
       
    33     }
       
    34 }
       
    35 
       
    36 #[derive(PartialEq, Eq, Clone, Copy, Debug)]
       
    37 pub struct CollisionData {
       
    38     pub bounds: CircleBounds,
       
    39 }
       
    40 
       
    41 impl GearData for CollisionData {}
       
    42 
       
    43 #[derive(PartialEq, Eq, Clone, Copy, Debug)]
       
    44 pub struct ContactData {
       
    45     pub elasticity: FPNum,
       
    46     pub friction: FPNum,
       
    47 }
       
    48 
       
    49 impl GearData for ContactData {}
       
    50 
       
    51 struct EnabledCollisionsCollection {
       
    52     gear_ids: Vec<GearId>,
       
    53     collisions: Vec<CollisionData>,
       
    54 }
       
    55 
       
    56 impl EnabledCollisionsCollection {
       
    57     fn new() -> Self {
       
    58         Self {
       
    59             gear_ids: Vec::new(),
       
    60             collisions: Vec::new(),
       
    61         }
       
    62     }
       
    63 
       
    64     fn push(&mut self, gear_id: GearId, collision: CollisionData) {
       
    65         self.gear_ids.push(gear_id);
       
    66         self.collisions.push(collision);
       
    67     }
       
    68 
       
    69     fn iter(&self) -> impl Iterator<Item = (GearId, &CollisionData)> {
       
    70         self.gear_ids.iter().cloned().zip(self.collisions.iter())
       
    71     }
       
    72 }
       
    73 
       
    74 pub struct CollisionProcessor {
       
    75     grid: Grid,
       
    76     enabled_collisions: EnabledCollisionsCollection,
       
    77 
       
    78     detected_collisions: DetectedCollisions,
       
    79 }
       
    80 
       
    81 pub struct DetectedCollisions {
       
    82     pub pairs: Vec<(GearId, Option<GearId>)>,
       
    83     pub positions: Vec<Point>,
       
    84 }
       
    85 
       
    86 impl DetectedCollisions {
       
    87     pub fn new(capacity: usize) -> Self {
       
    88         Self {
       
    89             pairs: Vec::with_capacity(capacity),
       
    90             positions: Vec::with_capacity(capacity),
       
    91         }
       
    92     }
       
    93 
       
    94     pub fn push(
       
    95         &mut self,
       
    96         contact_gear_id1: GearId,
       
    97         contact_gear_id2: Option<GearId>,
       
    98         position: &FPPoint,
       
    99     ) {
       
   100         self.pairs.push((contact_gear_id1, contact_gear_id2));
       
   101         self.positions.push(fppoint_round(&position));
       
   102     }
       
   103 
       
   104     pub fn clear(&mut self) {
       
   105         self.pairs.clear();
       
   106         self.positions.clear()
       
   107     }
       
   108 }
       
   109 
       
   110 impl CollisionProcessor {
       
   111     pub fn new(size: Size) -> Self {
       
   112         Self {
       
   113             grid: Grid::new(size),
       
   114             enabled_collisions: EnabledCollisionsCollection::new(),
       
   115             detected_collisions: DetectedCollisions::new(0),
       
   116         }
       
   117     }
       
   118 
       
   119     pub fn process(
       
   120         &mut self,
       
   121         land: &Land2D<u32>,
       
   122         updates: &crate::physics::PositionUpdates,
       
   123     ) -> &DetectedCollisions {
       
   124         self.detected_collisions.clear();
       
   125         for (id, old_position, new_position) in updates.iter() {
       
   126             self.grid.update_position(id, old_position, new_position)
       
   127         }
       
   128 
       
   129         self.grid.check_collisions(&mut self.detected_collisions);
       
   130 
       
   131         for (gear_id, collision) in self.enabled_collisions.iter() {
       
   132             if collision
       
   133                 .bounds
       
   134                 .rows()
       
   135                 .any(|(y, r)| (&land[y][r]).iter().any(|v| *v != 0))
       
   136             {
       
   137                 self.detected_collisions
       
   138                     .push(gear_id, None, &collision.bounds.center)
       
   139             }
       
   140         }
       
   141 
       
   142         &self.detected_collisions
       
   143     }
       
   144 }
       
   145 
       
   146 impl GearDataProcessor<CollisionData> for CollisionProcessor {
       
   147     fn add(&mut self, gear_id: GearId, gear_data: CollisionData) {
       
   148         self.grid.insert_static(gear_id, &gear_data.bounds);
       
   149     }
       
   150 
       
   151     fn remove(&mut self, gear_id: GearId) {
       
   152         self.grid.remove(gear_id);
       
   153     }
       
   154 }