0

I have two types of structs:

  1. Ships have a 2D position and a speed
  2. Targets are standing

I have a vector with all the Ships and another with all the Targets. I want to know then a Ship collides with another Ship or with a Target, so I will go through all the ships and check for collisions.

I know this is a bunch of code, but I did want to provide a full example.

use std::any::Any;


trait AsAny {
    fn as_any(&self) -> &Any;
}

impl<T: Any> AsAny for T {
    fn as_any(&self) -> &Any {
        self
    }
}

trait AsPoint {
    fn as_point(&self) -> &Point;
}

impl<T: Point> AsPoint for T {
    fn as_point(&self) -> &Point {
        self
    }
}

trait Point: AsPoint {
    fn x(&self) -> i32;
    fn y(&self) -> i32;


    fn distance(&self, rhs: &Point) -> i32 {
        (( ((self.x() - rhs.x()) as f64).powi(2) +
            ((self.y() - rhs.y()) as f64).powi(2)
        )as f64).sqrt().round() as i32
    }
}

struct Ship {
    x: i32,
    y: i32,
    radius: i32,
    vx: i32,
    vy: i32,
}

struct Target {
    x: i32,
    y: i32,
    radius: i32,
}

struct Collision<'a> {
    pub a: &'a mut (Element + 'a),
    pub b: &'a mut (Element + 'a),
}

trait Element: Point + AsAny {
    fn radius(&self) -> i32;
    fn apply_collision(&mut self, rhs: &mut Element);
}

impl Point for Target {
    fn x(&self) -> i32 {
        self.x
    }

    fn y(&self) -> i32 {
        self.y
    }
}

impl Point for Ship {
    fn x(&self) -> i32 {
        self.x
    }

    fn y(&self) -> i32 {
        self.y
    }
}
impl Element for Ship {
    fn apply_collision(&mut self, rhs: &mut Element) {

        if let Some(ref mut as_target) = rhs.as_any().downcast_ref::<Target>() {
            self.collision_with_target(as_target);
        } else if let Some(ref mut as_ship) = rhs.as_any().downcast_ref::<Ship>() {
            self.collision_with_ship(as_ship);
        }
    }
    fn radius(&self) -> i32 {
        self.radius
    }
}

impl Element for Target {
    fn radius(&self) -> i32 {
        self.radius
    }

    fn apply_collision(&mut self, rhs: &mut Element) {
        match  rhs.as_any().downcast_ref::<Ship>() {
            Some(ref mut as_ship ) => {
                as_ship.vx = -as_ship.vx;
                as_ship.vy = -as_ship.vy;
            },
            None => panic!(), // should never happen
        }
    }
}

impl Ship {
    fn collision_with_target(&mut self, target: &Target) {
        self.vx = -self.vx;
        self.vy = -self.vy;
    }

    fn collision_with_ship(&mut self, ship: &mut Ship) {
        let vx = self.vx;
        let vy = self.vy;

        self.vx = ship.vx;
        self.vy = ship.vy;

        ship.vx = vx;
        ship.vy = vy;
    }
}

fn collide<'a>(u1: &'a mut Element, u2: &'a mut Element) -> Option<Collision<'a>> {

    if u1.as_point().distance(u2.as_point()) < u1.radius() + u2.radius() {
        Some(Collision { a: u1, b: u2 })
    } else {None}

}

fn handle_collisions(ships : &mut Vec<Ship>, targets: &mut Vec<Target>) {

    for ship in ships.iter_mut() {
        for other_ship in &mut ships[1..] {
            let collision = collide(ship, other_ship);

            if let Some(col) = collision {
                col.a.apply_collision(col.b);
            }
        }

        for target in targets.iter_mut() {
            let collision = collide(ship,target);

            if let Some(col) = collision {
                col.a.apply_collision(col.b);
            }
        }
    }
}
fn main() {
    let ships: Vec<Ship> = vec![Ship {
        x: 10,
        y: 10,
        radius: 20,
        vx: 5,
        vy: 5,
    }, Ship {
        x: 20,
        y: 20,
        radius: 10,
        vx: 100,
        vy: 100,
    }];

    let targets = vec![ Target{
        x: 15,
        y: 15,
        radius: 10,
    }];


    handle_collisions(&mut ships, &mut targets);
}

Here is a playground link to the code.

Compiler output:

Compiling playground v0.0.1 (file:///playground)
error[E0477]: the type `&mut Element` does not fulfill the required lifetime
  --> src/main.rs:84:51
   |
84 |         } else if let Some(ref mut as_ship) = rhs.as_any().downcast_ref::<Ship>() {
   |                                                   ^^^^^^
   |
   = note: type must satisfy the static lifetime

error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
  --> src/main.rs:82:46
   |
82 |         if let Some(ref mut as_target) = rhs.as_any().downcast_ref::<Target>() {
   |                                              ^^^^^^
   |
note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the method body at 80:5...
  --> src/main.rs:80:5
   |
80 | /     fn apply_collision(&mut self, rhs: &mut Element) {
81 | |
82 | |         if let Some(ref mut as_target) = rhs.as_any().downcast_ref::<Target>() {
83 | |             self.collision_with_target(as_target);
...  |
86 | |         }
87 | |     }
   | |_____^
note: ...so that the reference type `&mut Element` does not outlive the data it points at
  --> src/main.rs:82:42
   |
82 |         if let Some(ref mut as_target) = rhs.as_any().downcast_ref::<Target>() {
   |                                          ^^^^^^^^^^^^
   = note: but, the lifetime must be valid for the static lifetime...
note: ...so that the type `&mut Element` will meet its required lifetime bounds
  --> src/main.rs:82:46
   |
82 |         if let Some(ref mut as_target) = rhs.as_any().downcast_ref::<Target>() {
   |                                              ^^^^^^

error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
  --> src/main.rs:84:51
   |
84 |         } else if let Some(ref mut as_ship) = rhs.as_any().downcast_ref::<Ship>() {
   |                                                   ^^^^^^
   |
note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the method body at 80:5...
  --> src/main.rs:80:5
   |
80 | /     fn apply_collision(&mut self, rhs: &mut Element) {
81 | |
82 | |         if let Some(ref mut as_target) = rhs.as_any().downcast_ref::<Target>() {
83 | |             self.collision_with_target(as_target);
...  |
86 | |         }
87 | |     }
   | |_____^
note: ...so that the reference type `&mut Element` does not outlive the data it points at
  --> src/main.rs:84:47
   |
84 |         } else if let Some(ref mut as_ship) = rhs.as_any().downcast_ref::<Ship>() {
   |                                               ^^^^^^^^^^^^
   = note: but, the lifetime must be valid for the static lifetime...
note: ...so that the type `&mut Element` will meet its required lifetime bounds
  --> src/main.rs:84:51
   |
84 |         } else if let Some(ref mut as_ship) = rhs.as_any().downcast_ref::<Ship>() {
   |                                                   ^^^^^^

error[E0477]: the type `&mut Element` does not fulfill the required lifetime
  --> src/main.rs:99:20
   |
99 |         match  rhs.as_any().downcast_ref::<Ship>() {
   |                    ^^^^^^
   |
   = note: type must satisfy the static lifetime

error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
  --> src/main.rs:99:20
   |
99 |         match  rhs.as_any().downcast_ref::<Ship>() {
   |                    ^^^^^^
   |
note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the method body at 98:5...
  --> src/main.rs:98:5
   |
98 | /     fn apply_collision(&mut self, rhs: &mut Element) {
99 | |         match  rhs.as_any().downcast_ref::<Ship>() {
100| |             Some(ref mut as_ship ) => {
101| |                 as_ship.vx = -as_ship.vx;
...  |
105| |         }
106| |     }
   | |_____^
note: ...so that the reference type `&mut Element` does not outlive the data it points at
  --> src/main.rs:99:16
   |
99 |         match  rhs.as_any().downcast_ref::<Ship>() {
   |                ^^^^^^^^^^^^
   = note: but, the lifetime must be valid for the static lifetime...
note: ...so that the type `&mut Element` will meet its required lifetime bounds
  --> src/main.rs:99:20
   |
99 |         match  rhs.as_any().downcast_ref::<Ship>() {
   |                    ^^^^^^
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
thamurath
  • 765
  • 8
  • 24
  • You can only use `downcast` with `'static` lifetimes. Duplicate of https://stackoverflow.com/q/27892375/155423 – Shepmaster Aug 02 '17 at 15:22
  • 1
    I'm not an expert at Rust (yet) but FYI you might consider using generics more rather than trait objects. Your usage of trait objects is what is adding to a lot of the complexity here. You could consider something like https://play.rust-lang.org/?gist=73d9693dfdf3857f7fb14a561f4ce302&version=stable – loganfsmyth Aug 02 '17 at 21:34
  • Thanks for the comment @loganfsmyth ... The only problem is that I found myself trying to store direferent types inside a container ... You know ... like a vector of "things that can collide " but It seems that is not possible in Rust ( at least as far as I know right now ). Rust is not an OO language, I know ... but I find the traits a little bit limiting ... too many years with c++ I fear... – thamurath Aug 03 '17 at 12:01
  • 1
    If you've got an explicit finite set of things, you'd make an enum with an entry for each type, then make the array a list of enum values. – loganfsmyth Aug 03 '17 at 17:40

0 Answers0