rust/hwphysics/src/collision.rs
changeset 14199 a4c17cfaa4c9
child 14200 abbb74b9cb62
equal deleted inserted replaced
14198:a4dd3d307115 14199:a4c17cfaa4c9
       
     1 use std::{
       
     2     ops::RangeInclusive
       
     3 };
       
     4 
       
     5 use crate::{
       
     6     common::GearId,
       
     7     physics::PhysicsData,
       
     8     grid::Grid
       
     9 };
       
    10 
       
    11 use fpnum::*;
       
    12 use integral_geometry::{
       
    13     Point, Size, GridIndex
       
    14 };
       
    15 use land2d::Land2D;
       
    16 
       
    17 pub fn fppoint_round(point: &FPPoint) -> Point {
       
    18     Point::new(point.x().round() as i32, point.y().round() as i32)
       
    19 }
       
    20 
       
    21 #[derive(PartialEq, Eq, Clone, Copy, Debug)]
       
    22 pub struct CircleBounds {
       
    23     pub center: FPPoint,
       
    24     pub radius: FPNum
       
    25 }
       
    26 
       
    27 impl CircleBounds {
       
    28     pub fn intersects(&self, other: &CircleBounds) -> bool {
       
    29         (other.center - self.center).is_in_range(self.radius + other.radius)
       
    30     }
       
    31 
       
    32     pub fn rows(&self) -> impl Iterator<Item = (usize, RangeInclusive<usize>)> {
       
    33         let radius = self.radius.abs_round() as usize;
       
    34         let center = Point::from_fppoint(&self.center);
       
    35         (center.y as usize - radius..=center.y as usize + radius)
       
    36             .map(move |row| (row, center.x as usize - radius..=center.x as usize + radius))
       
    37     }
       
    38 }
       
    39 
       
    40 #[derive(PartialEq, Eq, Clone, Copy, Debug)]
       
    41 pub struct CollisionData {
       
    42     pub bounds: CircleBounds
       
    43 }
       
    44 
       
    45 #[derive(PartialEq, Eq, Clone, Copy, Debug)]
       
    46 pub struct ContactData {
       
    47     pub elasticity: FPNum,
       
    48     pub friction: FPNum
       
    49 }
       
    50 
       
    51 struct EnabledCollisionsCollection {
       
    52     gear_ids: Vec<GearId>,
       
    53     collisions: Vec<CollisionData>
       
    54 }
       
    55 
       
    56 impl EnabledCollisionsCollection {
       
    57     fn push(&mut self, gear_id: GearId, collision: CollisionData) {
       
    58         self.gear_ids.push(gear_id);
       
    59         self.collisions.push(collision);
       
    60     }
       
    61 
       
    62     fn iter(&self) -> impl Iterator<Item = (GearId, &CollisionData)> {
       
    63         self.gear_ids.iter().cloned().zip(self.collisions.iter())
       
    64     }
       
    65 }
       
    66 
       
    67 pub struct CollisionProcessor {
       
    68     grid: Grid,
       
    69     enabled_collisions: EnabledCollisionsCollection,
       
    70 
       
    71     detected_collisions: DetectedCollisions,
       
    72 }
       
    73 
       
    74 pub struct DetectedCollisions {
       
    75     pub pairs: Vec<(GearId, GearId)>,
       
    76     pub positions: Vec<Point>
       
    77 }
       
    78 
       
    79 impl DetectedCollisions {
       
    80     pub fn new(capacity: usize) -> Self {
       
    81         Self {
       
    82             pairs: Vec::with_capacity(capacity),
       
    83             positions: Vec::with_capacity(capacity),
       
    84         }
       
    85     }
       
    86 
       
    87     pub fn push(&mut self, contact_gear_id1: GearId, contact_gear_id2: GearId, position: &FPPoint) {
       
    88         self.pairs.push((contact_gear_id1, contact_gear_id2));
       
    89         self.positions.push(fppoint_round(position));
       
    90     }
       
    91 }
       
    92 
       
    93 impl CollisionProcessor {
       
    94     pub fn process(&mut self, land: &Land2D<u32>, updates: &crate::physics::PositionUpdate) {
       
    95         self.grid.check_collisions(&mut self.detected_collisions);
       
    96 
       
    97         for (gear_id, collision) in self.enabled_collisions.iter() {
       
    98             if collision.bounds.rows().any(|(y, r)| (&land[y][r]).iter().any(|v| *v != 0)) {
       
    99                 self.detected_collisions.push(0, 0, &collision.bounds.center)
       
   100             }
       
   101         }
       
   102     }
       
   103 
       
   104     pub fn push(&mut self, gear_id: GearId, physics_data: PhysicsData, collision_data: CollisionData) {
       
   105         if physics_data.velocity.is_zero() {
       
   106             self.grid.insert_static(0, &physics_data.position, &collision_data.bounds);
       
   107         } else {
       
   108             self.grid.insert_dynamic(0, &physics_data.position, &collision_data.bounds);
       
   109         }
       
   110     }
       
   111 }