1
Fork 0

define mortality

This commit is contained in:
Andy Killorin 2026-11-09 15:50:07 -05:00
parent 3d9f957c4f
commit 596db89430
Signed by: ank
GPG key ID: 23F9463ECB67FE8C

View file

@ -2,6 +2,8 @@ use std::cmp::min;
use std::collections::HashMap; use std::collections::HashMap;
use std::f32::consts::TAU; use std::f32::consts::TAU;
use std::ptr; use std::ptr;
use std::sync::atomic::AtomicBool;
use std::sync::atomic::Ordering;
use macroquad::prelude::*; use macroquad::prelude::*;
use parry2d::math::Pose; use parry2d::math::Pose;
@ -16,19 +18,48 @@ use parry2d::shape::Shape;
const VIEW_DIST: f32 = 180.0; const VIEW_DIST: f32 = 180.0;
const BOT_RADIUS: f32 = 16.0; const BOT_RADIUS: f32 = 16.0;
trait Mortal {
fn collider(&self) -> (&Pose, &dyn Shape);
fn kill(&self);
fn living(&self) -> bool;
fn draw(&self);
}
struct Robot { struct Robot {
pose: Pose, pose: Pose,
alive: bool, alive: AtomicBool,
collider: Ball, collider: Ball,
sensor: Sensor, sensor: Sensor,
team: Color, team: Color,
} }
impl Mortal for Robot {
fn draw(&self) {
let tl = self.pose.translation;
let tl2 = self.view_end();
draw_circle(tl.x, tl.y, BOT_RADIUS, BLACK);
draw_line(tl.x, tl.y, tl2.x, tl2.y, 2.0, BLUE);
draw_circle(tl.x, tl.y, BOT_RADIUS-1.0, self.team);
}
fn collider(&self) -> (&Pose, &dyn Shape) {
(&self.pose, &self.collider)
}
fn kill (&self) {
self.alive.store(false, Ordering::Relaxed);
}
fn living(&self) -> bool {
self.alive.load(Ordering::Relaxed)
}
}
impl Robot { impl Robot {
fn new(position: Vec2, team: Color) -> Self { fn new(position: Vec2, team: Color) -> Self {
let rand_angle = rand::gen_range(0, 1000) as f32 * TAU / 1000.0; let rand_angle = rand::gen_range(0, 1000) as f32 * TAU / 1000.0;
let pose:Pose = Pose::from_parts(position.to_array().into(), Rot2::from_angle(rand_angle)); let pose:Pose = Pose::from_parts(position.to_array().into(), Rot2::from_angle(rand_angle));
Self { pose, alive: true, collider: Ball::new(BOT_RADIUS), sensor: Sensor::None, team} Self { pose, alive: AtomicBool::new(true), collider: Ball::new(BOT_RADIUS), sensor: Sensor::None, team}
} }
fn move_step(&mut self, forward: f32, right: f32) { fn move_step(&mut self, forward: f32, right: f32) {
@ -40,21 +71,10 @@ impl Robot {
Vec2::new(self.pose.rotation.re, self.pose.rotation.im) Vec2::new(self.pose.rotation.re, self.pose.rotation.im)
} }
pub fn draw(&self) {
let tl = self.pose.translation;
let tl2 = self.view_end();
draw_circle(tl.x, tl.y, BOT_RADIUS, BLACK);
draw_line(tl.x, tl.y, tl2.x, tl2.y, 2.0, BLUE);
draw_circle(tl.x, tl.y, BOT_RADIUS-1.0, self.team);
}
fn view_end(&self) -> Vec2 { fn view_end(&self) -> Vec2 {
self.pose.translation + self.ahead() * VIEW_DIST self.pose.translation + self.ahead() * VIEW_DIST
} }
pub fn collider(&self) -> (&Pose, &dyn Shape) {
(&self.pose, &self.collider)
}
fn detect<'a>(&self, things: impl Iterator<Item = (&'a Pose, &'a dyn Shape)>) -> Option<f32> { fn detect<'a>(&self, things: impl Iterator<Item = (&'a Pose, &'a dyn Shape)>) -> Option<f32> {
let collider = Segment::new(self.pose.translation, self.view_end()); let collider = Segment::new(self.pose.translation, self.view_end());
@ -76,7 +96,7 @@ impl Robot {
struct Food { struct Food {
pose: Pose, pose: Pose,
collider: Ball, collider: Ball,
alive: bool, alive: AtomicBool,
} }
enum Sensor { enum Sensor {
@ -86,22 +106,33 @@ enum Sensor {
None None
} }
impl Food { impl Mortal for Food {
fn new(position: Vec2) -> Self { fn draw(&self) {
let pose:Pose = Pose::from_translation(position.to_array().into());
Self { pose, alive: true, collider: Ball::new(BOT_RADIUS) }
}
pub fn draw(&self) {
let tl = self.pose.translation; let tl = self.pose.translation;
draw_circle(tl.x, tl.y, BOT_RADIUS, BLACK); draw_circle(tl.x, tl.y, BOT_RADIUS, BLACK);
draw_circle(tl.x, tl.y, BOT_RADIUS-1.0, GREEN); draw_circle(tl.x, tl.y, BOT_RADIUS-1.0, GREEN);
} }
pub fn collider(&self) -> (&Pose, &dyn Shape) { fn collider(&self) -> (&Pose, &dyn Shape) {
(&self.pose, &self.collider) (&self.pose, &self.collider)
} }
fn kill (&self) {
self.alive.store(false, Ordering::Relaxed);
}
fn living(&self) -> bool {
self.alive.load(Ordering::Relaxed)
}
}
impl Food {
fn new(position: Vec2) -> Self {
let pose:Pose = Pose::from_translation(position.to_array().into());
Self { pose, alive: AtomicBool::new(true), collider: Ball::new(BOT_RADIUS) }
}
fn detect<'a>(&self, things: impl Iterator<Item = &'a Robot>) -> Option<Color> { fn detect<'a>(&self, things: impl Iterator<Item = &'a Robot>) -> Option<Color> {
things things
.map(|robot| contact(&self.pose, &self.collider, &robot.pose, &robot.collider, 0.0).unwrap().map(|a| (a,robot.team))).flatten() .map(|robot| contact(&self.pose, &self.collider, &robot.pose, &robot.collider, 0.0).unwrap().map(|a| (a,robot.team))).flatten()
@ -140,21 +171,21 @@ async fn run_simulation() -> (i32, i32) {
let mut loo = 0; let mut loo = 0;
loop { loop {
let rendered = loo %30 == 0; let rendered = loo %100 == 0;
clear_background(LIGHTGRAY); clear_background(LIGHTGRAY);
for food in &mut food{ for food in &mut food{
if let Some(team) = food.detect(robots.iter()) { if let Some(team) = food.detect(robots.iter()) {
if food.alive { if food.living() {
score.entry(color_hash(team)).and_modify(|s| *s +=1 ).or_insert(1); score.entry(color_hash(team)).and_modify(|s| *s +=1 ).or_insert(1);
food.alive = false; food.kill();
} }
} }
if rendered { food.draw(); } if rendered { food.draw(); }
// TODO: die upon collision with robot // TODO: die upon collision with robot
} }
food = food.into_iter().filter(|f| f.alive).collect(); // remove dead food food = food.into_iter().filter(Mortal::living).collect(); // remove dead food
let mut sensors = Vec::new(); let mut sensors = Vec::new();
for robot in &*robots { for robot in &*robots {