Added faction relationships
parent
cbe8054f45
commit
2c4db4ebc5
|
@ -24,9 +24,15 @@ impl PartialEq for TextureHandle {
|
|||
}
|
||||
|
||||
/// A lightweight representation of a faction
|
||||
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct FactionHandle {
|
||||
/// The index of this faction in content.factions
|
||||
/// TODO: pub in crate, currently for debug.
|
||||
pub index: usize,
|
||||
}
|
||||
|
||||
impl Hash for FactionHandle {
|
||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||
self.index.hash(state)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ use toml;
|
|||
use walkdir::WalkDir;
|
||||
|
||||
pub use handle::{FactionHandle, TextureHandle};
|
||||
pub use part::{Engine, EnginePoint, Faction, Gun, GunPoint, Ship, System, Texture};
|
||||
pub use part::{Engine, EnginePoint, Faction, Gun, GunPoint, Relationship, Ship, System, Texture};
|
||||
|
||||
mod syntax {
|
||||
use anyhow::{bail, Result};
|
||||
|
@ -156,7 +156,7 @@ trait Build {
|
|||
Self: Sized;
|
||||
}
|
||||
|
||||
/// Represents generic game content, not connected to any game objects.
|
||||
/// Represents static game content
|
||||
#[derive(Debug)]
|
||||
pub struct Content {
|
||||
/// Star systems
|
||||
|
|
|
@ -18,16 +18,25 @@ pub(crate) mod syntax {
|
|||
}
|
||||
}
|
||||
|
||||
/// How two factions should interact with each other.
|
||||
/// Relationships are directional: the relationship of
|
||||
/// `a` to `b` may not equal the relationship of `b` to `a`.
|
||||
///
|
||||
/// Relationships dictate how a ship of THIS faction
|
||||
/// will interact with a ship of the OTHER faction.
|
||||
#[derive(Debug, Deserialize, Clone, Copy)]
|
||||
pub enum Relationship {
|
||||
/// Attack this faction
|
||||
#[serde(rename = "hostile")]
|
||||
Hostile,
|
||||
|
||||
/// Ignore this faction
|
||||
#[serde(rename = "neutral")]
|
||||
Neutral,
|
||||
|
||||
#[serde(rename = "enemy")]
|
||||
Enemy,
|
||||
/// Protect this faction
|
||||
#[serde(rename = "friend")]
|
||||
Friend,
|
||||
}
|
||||
|
||||
/// Represents a game faction
|
||||
|
@ -39,6 +48,8 @@ pub struct Faction {
|
|||
/// This faction's handle
|
||||
pub handle: FactionHandle,
|
||||
|
||||
/// Relationships between this faction and other factions
|
||||
/// This is guaranteed to contain an entry for ALL factions.
|
||||
pub relationships: HashMap<FactionHandle, Relationship>,
|
||||
}
|
||||
|
||||
|
@ -50,6 +61,9 @@ impl crate::Build for Faction {
|
|||
// This lets us build FactionHandles before finishing all factions.
|
||||
let faction_names: Vec<String> = factions.keys().map(|x| x.to_owned()).collect();
|
||||
|
||||
// Indexing will break if this is false.
|
||||
assert!(ct.factions.len() == 0);
|
||||
|
||||
for f_idx in 0..faction_names.len() {
|
||||
let faction_name = &faction_names[f_idx];
|
||||
let faction = &factions[faction_name];
|
||||
|
@ -80,12 +94,6 @@ impl crate::Build for Faction {
|
|||
}
|
||||
}
|
||||
|
||||
let relationships = faction
|
||||
.relationship
|
||||
.iter()
|
||||
.map(|x| (h, x.1.clone()))
|
||||
.collect();
|
||||
|
||||
ct.factions.push(Self {
|
||||
name: faction_name.to_owned(),
|
||||
handle: h,
|
||||
|
|
|
@ -8,7 +8,7 @@ pub mod system;
|
|||
pub mod texture;
|
||||
|
||||
pub use engine::Engine;
|
||||
pub use faction::Faction;
|
||||
pub use faction::{Faction, Relationship};
|
||||
pub use gun::{Gun, Projectile};
|
||||
pub use ship::{EnginePoint, GunPoint, Ship};
|
||||
pub use system::{Object, System};
|
||||
|
|
|
@ -24,6 +24,7 @@ pub struct Game {
|
|||
|
||||
physics: Physics,
|
||||
shipbehaviors: Vec<Box<dyn ShipBehavior>>,
|
||||
content: Content,
|
||||
}
|
||||
|
||||
impl Game {
|
||||
|
@ -62,8 +63,8 @@ impl Game {
|
|||
|
||||
let mut shipbehaviors: Vec<Box<dyn ShipBehavior>> = Vec::new();
|
||||
shipbehaviors.push(shipbehavior::Player::new(h1));
|
||||
shipbehaviors.push(shipbehavior::Point::new(h3));
|
||||
shipbehaviors.push(shipbehavior::Dummy::new(h2));
|
||||
shipbehaviors.push(shipbehavior::Point::new(h3));
|
||||
|
||||
Game {
|
||||
last_update: Instant::now(),
|
||||
|
@ -80,6 +81,7 @@ impl Game {
|
|||
time_scale: 1.0,
|
||||
physics,
|
||||
shipbehaviors,
|
||||
content: ct,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -111,12 +113,12 @@ impl Game {
|
|||
if self.physics.get_ship_mut(&b.get_handle()).is_none() {
|
||||
false
|
||||
} else {
|
||||
b.update_controls(&mut self.physics, &self.input, self.player);
|
||||
b.update_controls(&mut self.physics, &self.input, &self.content);
|
||||
true
|
||||
}
|
||||
});
|
||||
|
||||
self.physics.step(t);
|
||||
self.physics.step(t, &self.content);
|
||||
|
||||
if self.input.v_scroll != 0.0 {
|
||||
self.camera.zoom =
|
||||
|
|
|
@ -24,6 +24,8 @@ fn main() -> Result<()> {
|
|||
consts::STARFIELD_TEXTURE_NAME.to_owned(),
|
||||
)?;
|
||||
|
||||
println!("{:?}", content.factions);
|
||||
|
||||
pollster::block_on(run(content))?;
|
||||
return Ok(());
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use cgmath::Point2;
|
||||
use content::FactionHandle;
|
||||
use content::{Content, FactionHandle};
|
||||
use crossbeam::channel::Receiver;
|
||||
use nalgebra::vector;
|
||||
use rapier2d::{
|
||||
|
@ -112,7 +112,7 @@ impl Physics {
|
|||
return h;
|
||||
}
|
||||
|
||||
pub fn step(&mut self, t: f32) {
|
||||
pub fn step(&mut self, t: f32, ct: &Content) {
|
||||
// Run ship updates
|
||||
let mut res = Vec::new();
|
||||
let mut to_remove = Vec::new();
|
||||
|
@ -152,11 +152,16 @@ impl Physics {
|
|||
|
||||
if let Some(p) = self.projectiles.get(a) {
|
||||
if let Some(s) = self.ships.get_mut(b) {
|
||||
// TODO: better rules here
|
||||
if s.faction != p.faction {
|
||||
s.hull -= p.damage;
|
||||
self.remove_projectile(*a);
|
||||
self.remove_projectile(*b);
|
||||
let p_faction = ct.get_faction(p.faction);
|
||||
let r = p_faction.relationships[&s.faction];
|
||||
match r {
|
||||
content::Relationship::Hostile => {
|
||||
// TODO: implement death and spawning, and enable damage
|
||||
//s.hull -= p.damage;
|
||||
self.remove_projectile(*a);
|
||||
self.remove_projectile(*b);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -189,6 +194,15 @@ impl Physics {
|
|||
Some((self.ships.get(&s.1)?, self.wrapper.rigid_body_set.get(s.0)?))
|
||||
}
|
||||
|
||||
pub fn iter_ship_body(&self) -> impl Iterator<Item = (&objects::Ship, &RigidBody)> + '_ {
|
||||
self.ships.values().map(|x| {
|
||||
(
|
||||
x,
|
||||
self.wrapper.rigid_body_set.get(x.physics_handle.0).unwrap(),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get_ship_sprites(&self) -> impl Iterator<Item = Sprite> + '_ {
|
||||
self.ships
|
||||
.values()
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use cgmath::{Deg, InnerSpace};
|
||||
use galactica_content as content;
|
||||
|
||||
use crate::{
|
||||
inputstatus::InputStatus,
|
||||
|
@ -9,7 +10,12 @@ pub trait ShipBehavior
|
|||
where
|
||||
Self: Send,
|
||||
{
|
||||
fn update_controls(&mut self, physics: &mut Physics, input: &InputStatus, player: ShipHandle);
|
||||
fn update_controls(
|
||||
&mut self,
|
||||
physics: &mut Physics,
|
||||
input: &InputStatus,
|
||||
content: &content::Content,
|
||||
);
|
||||
fn get_handle(&self) -> ShipHandle;
|
||||
}
|
||||
|
||||
|
@ -28,7 +34,7 @@ impl ShipBehavior for Dummy {
|
|||
&mut self,
|
||||
_physics: &mut Physics,
|
||||
_input: &InputStatus,
|
||||
_player: ShipHandle,
|
||||
_content: &content::Content,
|
||||
) {
|
||||
}
|
||||
fn get_handle(&self) -> ShipHandle {
|
||||
|
@ -47,7 +53,12 @@ impl Player {
|
|||
}
|
||||
|
||||
impl ShipBehavior for Player {
|
||||
fn update_controls(&mut self, physics: &mut Physics, input: &InputStatus, _player: ShipHandle) {
|
||||
fn update_controls(
|
||||
&mut self,
|
||||
physics: &mut Physics,
|
||||
input: &InputStatus,
|
||||
_content: &content::Content,
|
||||
) {
|
||||
let s = physics.get_ship_mut(&self.handle).unwrap();
|
||||
s.controls.left = input.key_left;
|
||||
s.controls.right = input.key_right;
|
||||
|
@ -71,23 +82,60 @@ impl Point {
|
|||
}
|
||||
|
||||
impl ShipBehavior for Point {
|
||||
fn update_controls(&mut self, physics: &mut Physics, _input: &InputStatus, player: ShipHandle) {
|
||||
let (_, r) = physics.get_ship_body(&player).unwrap();
|
||||
let p = util::rigidbody_position(r);
|
||||
fn update_controls(
|
||||
&mut self,
|
||||
physics: &mut Physics,
|
||||
_input: &InputStatus,
|
||||
content: &content::Content,
|
||||
) {
|
||||
// Turn off all controls
|
||||
let s = physics.get_ship_mut(&self.handle).unwrap();
|
||||
s.controls.left = false;
|
||||
s.controls.right = false;
|
||||
s.controls.guns = false;
|
||||
s.controls.thrust = false;
|
||||
|
||||
let (_, r) = physics.get_ship_body(&self.handle).unwrap();
|
||||
let t = util::rigidbody_position(r);
|
||||
let pa = util::rigidbody_rotation(r);
|
||||
let v = r.angvel();
|
||||
let d: Deg<f32> = (pa).angle(p - t).into();
|
||||
let (my_s, my_r) = physics.get_ship_body(&self.handle).unwrap();
|
||||
let my_position = util::rigidbody_position(my_r);
|
||||
let my_rotation = util::rigidbody_rotation(my_r);
|
||||
let my_angvel = my_r.angvel();
|
||||
let my_faction = content.get_faction(my_s.faction);
|
||||
|
||||
// Iterate all possible targets
|
||||
let mut it = physics
|
||||
.iter_ship_body()
|
||||
.filter(|(s, _)| match my_faction.relationships[&s.faction] {
|
||||
content::Relationship::Hostile => true,
|
||||
_ => false,
|
||||
})
|
||||
.map(|(_, r)| r);
|
||||
|
||||
// Find the closest target
|
||||
let mut closest_enemy_position = match it.next() {
|
||||
Some(c) => util::rigidbody_position(c),
|
||||
None => return, // Do nothing if no targets are available
|
||||
};
|
||||
let mut d = (my_position - closest_enemy_position).magnitude();
|
||||
for r in it {
|
||||
let p = util::rigidbody_position(r);
|
||||
let new_d = (my_position - p).magnitude();
|
||||
if new_d < d {
|
||||
d = new_d;
|
||||
closest_enemy_position = p;
|
||||
}
|
||||
}
|
||||
|
||||
let angle_delta: Deg<f32> = (my_rotation)
|
||||
.angle(closest_enemy_position - my_position)
|
||||
.into();
|
||||
|
||||
let s = physics.get_ship_mut(&self.handle).unwrap();
|
||||
s.controls.left = false;
|
||||
s.controls.right = false;
|
||||
|
||||
if d < Deg(0.0) && v > -0.3 {
|
||||
if angle_delta < Deg(0.0) && my_angvel > -0.3 {
|
||||
s.controls.right = true;
|
||||
} else if d > Deg(0.0) && v < 0.3 {
|
||||
} else if angle_delta > Deg(0.0) && my_angvel < 0.3 {
|
||||
s.controls.left = true;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue