Compare commits
2 Commits
99f198c9d6
...
2c4db4ebc5
Author | SHA1 | Date |
---|---|---|
Mark | 2c4db4ebc5 | |
Mark | cbe8054f45 |
|
@ -0,0 +1,7 @@
|
||||||
|
[faction."player"]
|
||||||
|
display_name = "Player"
|
||||||
|
relationship.enemy = "hostile"
|
||||||
|
|
||||||
|
[faction."enemy"]
|
||||||
|
display_name = "Enemy"
|
||||||
|
relationship.player = "hostile"
|
|
@ -1,13 +1,12 @@
|
||||||
[ship."Gypsum"]
|
[ship."Gypsum"]
|
||||||
sprite_texture = "ship::gypsum"
|
sprite_texture = "ship::gypsum"
|
||||||
size = 100
|
size = 100
|
||||||
mass = 10
|
mass = 1
|
||||||
hull = 200
|
hull = 200
|
||||||
|
|
||||||
engines = [{ x = 0.0, y = -1.05, size = 50.0 }]
|
engines = [{ x = 0.0, y = -1.05, size = 50.0 }]
|
||||||
guns = [{ x = 0.0, y = 1 }, { x = 0.1, y = 0.80 }, { x = -0.1, y = 0.80 }]
|
guns = [{ x = 0.0, y = 1 }, { x = 0.1, y = 0.80 }, { x = -0.1, y = 0.80 }]
|
||||||
|
|
||||||
|
|
||||||
collision.points = [
|
collision.points = [
|
||||||
#[rustfmt:skip],
|
#[rustfmt:skip],
|
||||||
[0.53921, 1.0000],
|
[0.53921, 1.0000],
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
use std::{cmp::Eq, hash::Hash};
|
||||||
|
|
||||||
|
/// Represents a specific texture defined in the content dir.
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub struct TextureHandle {
|
||||||
|
/// The index of this texture in content.textures
|
||||||
|
pub(crate) index: usize,
|
||||||
|
|
||||||
|
/// The aspect ratio of this texture (width / height)
|
||||||
|
pub aspect: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Hash for TextureHandle {
|
||||||
|
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||||
|
self.index.hash(state)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Eq for TextureHandle {}
|
||||||
|
impl PartialEq for TextureHandle {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.index.eq(&other.index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A lightweight representation of a faction
|
||||||
|
#[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)
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,35 +3,29 @@
|
||||||
//! This subcrate is responsible for loading, parsing, validating game content,
|
//! This subcrate is responsible for loading, parsing, validating game content,
|
||||||
//! which is usually stored in `./content`.
|
//! which is usually stored in `./content`.
|
||||||
|
|
||||||
mod engine;
|
mod handle;
|
||||||
mod gun;
|
mod part;
|
||||||
mod ship;
|
|
||||||
mod system;
|
|
||||||
mod texture;
|
|
||||||
mod util;
|
mod util;
|
||||||
|
|
||||||
pub use engine::Engine;
|
use anyhow::{Context, Result};
|
||||||
pub use gun::{Gun, Projectile};
|
|
||||||
pub use ship::{EnginePoint, GunPoint, Ship};
|
|
||||||
pub use system::{Object, System};
|
|
||||||
pub use texture::Texture;
|
|
||||||
|
|
||||||
use anyhow::{bail, Context, Result};
|
|
||||||
use std::{
|
use std::{
|
||||||
cmp::Eq,
|
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
fs::File,
|
fs::File,
|
||||||
hash::Hash,
|
|
||||||
io::Read,
|
io::Read,
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
};
|
};
|
||||||
use toml;
|
use toml;
|
||||||
use walkdir::WalkDir;
|
use walkdir::WalkDir;
|
||||||
|
|
||||||
|
pub use handle::{FactionHandle, TextureHandle};
|
||||||
|
pub use part::{Engine, EnginePoint, Faction, Gun, GunPoint, Relationship, Ship, System, Texture};
|
||||||
|
|
||||||
mod syntax {
|
mod syntax {
|
||||||
use super::{bail, HashMap, Result};
|
use anyhow::{bail, Result};
|
||||||
use super::{engine, gun, ship, system, texture};
|
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use crate::part::{engine, faction, gun, ship, system, texture};
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
pub struct Root {
|
pub struct Root {
|
||||||
|
@ -40,6 +34,7 @@ mod syntax {
|
||||||
pub system: Option<HashMap<String, system::syntax::System>>,
|
pub system: Option<HashMap<String, system::syntax::System>>,
|
||||||
pub engine: Option<HashMap<String, engine::syntax::Engine>>,
|
pub engine: Option<HashMap<String, engine::syntax::Engine>>,
|
||||||
pub texture: Option<HashMap<String, texture::syntax::Texture>>,
|
pub texture: Option<HashMap<String, texture::syntax::Texture>>,
|
||||||
|
pub faction: Option<HashMap<String, faction::syntax::Faction>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Root {
|
impl Root {
|
||||||
|
@ -50,6 +45,7 @@ mod syntax {
|
||||||
system: None,
|
system: None,
|
||||||
engine: None,
|
engine: None,
|
||||||
texture: None,
|
texture: None,
|
||||||
|
faction: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,6 +127,21 @@ mod syntax {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(a) = other.faction {
|
||||||
|
if self.faction.is_none() {
|
||||||
|
self.faction = Some(a);
|
||||||
|
} else {
|
||||||
|
let sg = self.faction.as_mut().unwrap();
|
||||||
|
for (k, v) in a {
|
||||||
|
if sg.contains_key(&k) {
|
||||||
|
bail!("Repeated faction name {k}");
|
||||||
|
} else {
|
||||||
|
sg.insert(k, v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -145,53 +156,33 @@ trait Build {
|
||||||
Self: Sized;
|
Self: Sized;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represents a specific texture defined in the content dir.
|
/// Represents static game content
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
pub struct TextureHandle {
|
|
||||||
/// The index of this texture in content.textures
|
|
||||||
pub index: usize,
|
|
||||||
|
|
||||||
/// The aspect ratio of this texture (width / height)
|
|
||||||
pub aspect: f32,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Hash for TextureHandle {
|
|
||||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
|
||||||
self.index.hash(state)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Eq for TextureHandle {}
|
|
||||||
impl PartialEq for TextureHandle {
|
|
||||||
fn eq(&self, other: &Self) -> bool {
|
|
||||||
self.index.eq(&other.index)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Represents generic game content, not connected to any game objects.
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Content {
|
pub struct Content {
|
||||||
/// Star systems
|
/// Star systems
|
||||||
pub systems: Vec<system::System>,
|
pub systems: Vec<part::system::System>,
|
||||||
|
|
||||||
/// Ship bodies
|
/// Ship bodies
|
||||||
pub ships: Vec<ship::Ship>,
|
pub ships: Vec<part::ship::Ship>,
|
||||||
|
|
||||||
/// Gun outfits
|
/// Gun outfits
|
||||||
pub guns: Vec<gun::Gun>,
|
pub guns: Vec<part::gun::Gun>,
|
||||||
|
|
||||||
/// Engine outfits
|
/// Engine outfits
|
||||||
pub engines: Vec<engine::Engine>,
|
pub engines: Vec<part::engine::Engine>,
|
||||||
|
|
||||||
/// Textures
|
/// Textures
|
||||||
pub textures: Vec<texture::Texture>,
|
pub textures: Vec<part::texture::Texture>,
|
||||||
|
|
||||||
|
/// Factions
|
||||||
|
pub factions: Vec<part::faction::Faction>,
|
||||||
|
|
||||||
/// Map strings to texture handles
|
/// Map strings to texture handles
|
||||||
/// This is never used outside this crate.
|
/// This is never used outside this crate.
|
||||||
texture_index: HashMap<String, TextureHandle>,
|
texture_index: HashMap<String, handle::TextureHandle>,
|
||||||
|
|
||||||
/// The texture to use for starfield stars
|
/// The texture to use for starfield stars
|
||||||
starfield_handle: Option<TextureHandle>,
|
starfield_handle: Option<handle::TextureHandle>,
|
||||||
|
|
||||||
/// Root directory for textures
|
/// Root directory for textures
|
||||||
texture_root: PathBuf,
|
texture_root: PathBuf,
|
||||||
|
@ -217,12 +208,17 @@ impl Content {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a texture from a handle
|
/// Get a texture from a handle
|
||||||
pub fn get_texture(&self, h: TextureHandle) -> &texture::Texture {
|
pub fn get_texture(&self, h: TextureHandle) -> &Texture {
|
||||||
// In theory, this could fail if h has a bad index, but that shouldn't ever happen.
|
// In theory, this could fail if h has a bad index, but that shouldn't ever happen.
|
||||||
// The only TextureHandles that exist should be created by this crate.
|
// The only TextureHandles that exist should be created by this crate.
|
||||||
return &self.textures[h.index];
|
return &self.textures[h.index];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get a faction from a handle
|
||||||
|
pub fn get_faction(&self, h: FactionHandle) -> &Faction {
|
||||||
|
return &self.factions[h.index];
|
||||||
|
}
|
||||||
|
|
||||||
/// Load content from a directory.
|
/// Load content from a directory.
|
||||||
pub fn load_dir(
|
pub fn load_dir(
|
||||||
path: PathBuf,
|
path: PathBuf,
|
||||||
|
@ -262,6 +258,7 @@ impl Content {
|
||||||
guns: Vec::new(),
|
guns: Vec::new(),
|
||||||
engines: Vec::new(),
|
engines: Vec::new(),
|
||||||
textures: Vec::new(),
|
textures: Vec::new(),
|
||||||
|
factions: Vec::new(),
|
||||||
texture_index: HashMap::new(),
|
texture_index: HashMap::new(),
|
||||||
starfield_handle: None,
|
starfield_handle: None,
|
||||||
texture_root,
|
texture_root,
|
||||||
|
@ -270,19 +267,22 @@ impl Content {
|
||||||
|
|
||||||
// Order here matters, usually
|
// Order here matters, usually
|
||||||
if root.texture.is_some() {
|
if root.texture.is_some() {
|
||||||
texture::Texture::build(root.texture.take().unwrap(), &mut content)?;
|
part::texture::Texture::build(root.texture.take().unwrap(), &mut content)?;
|
||||||
}
|
}
|
||||||
if root.ship.is_some() {
|
if root.ship.is_some() {
|
||||||
ship::Ship::build(root.ship.take().unwrap(), &mut content)?;
|
part::ship::Ship::build(root.ship.take().unwrap(), &mut content)?;
|
||||||
}
|
}
|
||||||
if root.gun.is_some() {
|
if root.gun.is_some() {
|
||||||
gun::Gun::build(root.gun.take().unwrap(), &mut content)?;
|
part::gun::Gun::build(root.gun.take().unwrap(), &mut content)?;
|
||||||
}
|
}
|
||||||
if root.engine.is_some() {
|
if root.engine.is_some() {
|
||||||
engine::Engine::build(root.engine.take().unwrap(), &mut content)?;
|
part::engine::Engine::build(root.engine.take().unwrap(), &mut content)?;
|
||||||
}
|
}
|
||||||
if root.system.is_some() {
|
if root.system.is_some() {
|
||||||
system::System::build(root.system.take().unwrap(), &mut content)?;
|
part::system::System::build(root.system.take().unwrap(), &mut content)?;
|
||||||
|
}
|
||||||
|
if root.faction.is_some() {
|
||||||
|
part::faction::Faction::build(root.faction.take().unwrap(), &mut content)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Ok(content);
|
return Ok(content);
|
||||||
|
|
|
@ -2,9 +2,9 @@ use std::collections::HashMap;
|
||||||
|
|
||||||
use anyhow::{bail, Result};
|
use anyhow::{bail, Result};
|
||||||
|
|
||||||
use crate::{Content, TextureHandle};
|
use crate::{handle::TextureHandle, Content};
|
||||||
|
|
||||||
pub(super) mod syntax {
|
pub(crate) mod syntax {
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
// Raw serde syntax structs.
|
// Raw serde syntax structs.
|
||||||
// These are never seen by code outside this crate.
|
// These are never seen by code outside this crate.
|
||||||
|
@ -36,7 +36,7 @@ pub struct Engine {
|
||||||
pub flare_sprite_texture: TextureHandle,
|
pub flare_sprite_texture: TextureHandle,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl super::Build for Engine {
|
impl crate::Build for Engine {
|
||||||
type InputSyntax = HashMap<String, syntax::Engine>;
|
type InputSyntax = HashMap<String, syntax::Engine>;
|
||||||
|
|
||||||
fn build(engine: Self::InputSyntax, ct: &mut Content) -> Result<()> {
|
fn build(engine: Self::InputSyntax, ct: &mut Content) -> Result<()> {
|
|
@ -0,0 +1,106 @@
|
||||||
|
use anyhow::Result;
|
||||||
|
use serde::Deserialize;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use crate::{handle::FactionHandle, Content};
|
||||||
|
|
||||||
|
pub(crate) mod syntax {
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use serde::Deserialize;
|
||||||
|
// Raw serde syntax structs.
|
||||||
|
// These are never seen by code outside this crate.
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
pub struct Faction {
|
||||||
|
pub display_name: String,
|
||||||
|
pub relationship: HashMap<String, super::Relationship>,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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,
|
||||||
|
|
||||||
|
/// Protect this faction
|
||||||
|
#[serde(rename = "friend")]
|
||||||
|
Friend,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Represents a game faction
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Faction {
|
||||||
|
/// The name of this faction
|
||||||
|
pub name: String,
|
||||||
|
|
||||||
|
/// 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>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl crate::Build for Faction {
|
||||||
|
type InputSyntax = HashMap<String, syntax::Faction>;
|
||||||
|
|
||||||
|
fn build(factions: Self::InputSyntax, ct: &mut Content) -> Result<()> {
|
||||||
|
// Keeps track of position in faction array.
|
||||||
|
// 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];
|
||||||
|
|
||||||
|
// Handle for this faction
|
||||||
|
let h = FactionHandle { index: f_idx };
|
||||||
|
|
||||||
|
// Compute relationships
|
||||||
|
let mut relationships = HashMap::new();
|
||||||
|
for i in 0..faction_names.len() {
|
||||||
|
let f_other = &faction_names[i];
|
||||||
|
let h_other = FactionHandle { index: i };
|
||||||
|
if let Some(r) = faction.relationship.get(f_other) {
|
||||||
|
relationships.insert(h_other, *r);
|
||||||
|
} else {
|
||||||
|
// Default relationship, if not specified
|
||||||
|
|
||||||
|
// Look at reverse direction...
|
||||||
|
let other = factions[f_other].relationship.get(faction_name);
|
||||||
|
relationships.insert(
|
||||||
|
h_other,
|
||||||
|
// ... and pick a relationship based on that.
|
||||||
|
match other {
|
||||||
|
Some(Relationship::Hostile) => Relationship::Hostile {},
|
||||||
|
_ => Relationship::Neutral {},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ct.factions.push(Self {
|
||||||
|
name: faction_name.to_owned(),
|
||||||
|
handle: h,
|
||||||
|
relationships,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,9 +3,9 @@ use std::collections::HashMap;
|
||||||
use anyhow::{bail, Result};
|
use anyhow::{bail, Result};
|
||||||
use cgmath::Deg;
|
use cgmath::Deg;
|
||||||
|
|
||||||
use crate::{Content, TextureHandle};
|
use crate::{handle::TextureHandle, Content};
|
||||||
|
|
||||||
pub(super) mod syntax {
|
pub(crate) mod syntax {
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
// Raw serde syntax structs.
|
// Raw serde syntax structs.
|
||||||
// These are never seen by code outside this crate.
|
// These are never seen by code outside this crate.
|
||||||
|
@ -82,7 +82,7 @@ pub struct Projectile {
|
||||||
pub damage: f32,
|
pub damage: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl super::Build for Gun {
|
impl crate::Build for Gun {
|
||||||
type InputSyntax = HashMap<String, syntax::Gun>;
|
type InputSyntax = HashMap<String, syntax::Gun>;
|
||||||
|
|
||||||
fn build(gun: Self::InputSyntax, ct: &mut Content) -> Result<()> {
|
fn build(gun: Self::InputSyntax, ct: &mut Content) -> Result<()> {
|
|
@ -0,0 +1,15 @@
|
||||||
|
//! Content parts
|
||||||
|
|
||||||
|
pub mod engine;
|
||||||
|
pub mod faction;
|
||||||
|
pub mod gun;
|
||||||
|
pub mod ship;
|
||||||
|
pub mod system;
|
||||||
|
pub mod texture;
|
||||||
|
|
||||||
|
pub use engine::Engine;
|
||||||
|
pub use faction::{Faction, Relationship};
|
||||||
|
pub use gun::{Gun, Projectile};
|
||||||
|
pub use ship::{EnginePoint, GunPoint, Ship};
|
||||||
|
pub use system::{Object, System};
|
||||||
|
pub use texture::Texture;
|
|
@ -4,9 +4,9 @@ use anyhow::{bail, Result};
|
||||||
use cgmath::Point2;
|
use cgmath::Point2;
|
||||||
use nalgebra::{point, Point};
|
use nalgebra::{point, Point};
|
||||||
|
|
||||||
use crate::{Content, TextureHandle};
|
use crate::{handle::TextureHandle, Content};
|
||||||
|
|
||||||
pub(super) mod syntax {
|
pub(crate) mod syntax {
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
// Raw serde syntax structs.
|
// Raw serde syntax structs.
|
||||||
// These are never seen by code outside this crate.
|
// These are never seen by code outside this crate.
|
||||||
|
@ -108,7 +108,7 @@ pub struct GunPoint {
|
||||||
pub pos: Point2<f32>,
|
pub pos: Point2<f32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl super::Build for Ship {
|
impl crate::Build for Ship {
|
||||||
type InputSyntax = HashMap<String, syntax::Ship>;
|
type InputSyntax = HashMap<String, syntax::Ship>;
|
||||||
|
|
||||||
fn build(ship: Self::InputSyntax, ct: &mut Content) -> Result<()> {
|
fn build(ship: Self::InputSyntax, ct: &mut Content) -> Result<()> {
|
||||||
|
@ -154,7 +154,7 @@ impl super::Build for Ship {
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
collision: Collision {
|
collision: Collision {
|
||||||
indices: ship.collision.indices.clone(),
|
indices: ship.collision.indices,
|
||||||
points: ship
|
points: ship
|
||||||
.collision
|
.collision
|
||||||
.points
|
.points
|
|
@ -2,9 +2,9 @@ use anyhow::{bail, Context, Result};
|
||||||
use cgmath::{Deg, Point3};
|
use cgmath::{Deg, Point3};
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
|
|
||||||
use crate::{util::Polar, Content, TextureHandle};
|
use crate::{handle::TextureHandle, util::Polar, Content};
|
||||||
|
|
||||||
pub(super) mod syntax {
|
pub(crate) mod syntax {
|
||||||
use super::HashMap;
|
use super::HashMap;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
// Raw serde syntax structs.
|
// Raw serde syntax structs.
|
||||||
|
@ -174,7 +174,7 @@ fn resolve_position(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl super::Build for System {
|
impl crate::Build for System {
|
||||||
type InputSyntax = HashMap<String, syntax::System>;
|
type InputSyntax = HashMap<String, syntax::System>;
|
||||||
|
|
||||||
fn build(system: Self::InputSyntax, ct: &mut Content) -> Result<()> {
|
fn build(system: Self::InputSyntax, ct: &mut Content) -> Result<()> {
|
|
@ -3,9 +3,9 @@ use std::{collections::HashMap, path::PathBuf};
|
||||||
use anyhow::{bail, Context, Result};
|
use anyhow::{bail, Context, Result};
|
||||||
use image::io::Reader;
|
use image::io::Reader;
|
||||||
|
|
||||||
use crate::{Content, TextureHandle};
|
use crate::{handle::TextureHandle, Content};
|
||||||
|
|
||||||
pub(super) mod syntax {
|
pub(crate) mod syntax {
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
@ -31,7 +31,7 @@ pub struct Texture {
|
||||||
pub path: PathBuf,
|
pub path: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl super::Build for Texture {
|
impl crate::Build for Texture {
|
||||||
type InputSyntax = HashMap<String, syntax::Texture>;
|
type InputSyntax = HashMap<String, syntax::Texture>;
|
||||||
|
|
||||||
fn build(texture: Self::InputSyntax, ct: &mut Content) -> Result<()> {
|
fn build(texture: Self::InputSyntax, ct: &mut Content) -> Result<()> {
|
|
@ -1,4 +1,5 @@
|
||||||
use cgmath::Point2;
|
use cgmath::Point2;
|
||||||
|
use galactica_content::FactionHandle;
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
use winit::event::{ElementState, MouseButton, MouseScrollDelta, TouchPhase, VirtualKeyCode};
|
use winit::event::{ElementState, MouseButton, MouseScrollDelta, TouchPhase, VirtualKeyCode};
|
||||||
|
|
||||||
|
@ -23,6 +24,7 @@ pub struct Game {
|
||||||
|
|
||||||
physics: Physics,
|
physics: Physics,
|
||||||
shipbehaviors: Vec<Box<dyn ShipBehavior>>,
|
shipbehaviors: Vec<Box<dyn ShipBehavior>>,
|
||||||
|
content: Content,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Game {
|
impl Game {
|
||||||
|
@ -32,30 +34,37 @@ impl Game {
|
||||||
let h1 = physics.add_ship(
|
let h1 = physics.add_ship(
|
||||||
&ct.ships[0],
|
&ct.ships[0],
|
||||||
vec![
|
vec![
|
||||||
outfits::ShipOutfit::Gun(outfits::ShipGun::new(ct.guns[0].clone(), 1)),
|
outfits::ShipOutfit::Gun(outfits::ShipGun::new(&ct.guns[0], 1)),
|
||||||
outfits::ShipOutfit::Gun(outfits::ShipGun::new(ct.guns[0].clone(), 2)),
|
outfits::ShipOutfit::Gun(outfits::ShipGun::new(&ct.guns[0], 2)),
|
||||||
outfits::ShipOutfit::Engine(ct.engines[0].clone()),
|
outfits::ShipOutfit::Engine(ct.engines[0].clone()),
|
||||||
],
|
],
|
||||||
Point2 { x: 0.0, y: 0.0 },
|
Point2 { x: 0.0, y: 0.0 },
|
||||||
|
FactionHandle { index: 0 },
|
||||||
);
|
);
|
||||||
|
|
||||||
let h2 = physics.add_ship(&ct.ships[0], vec![], Point2 { x: 300.0, y: 300.0 });
|
let h2 = physics.add_ship(
|
||||||
let _h3 = physics.add_ship(
|
&ct.ships[0],
|
||||||
|
vec![],
|
||||||
|
Point2 { x: 300.0, y: 300.0 },
|
||||||
|
FactionHandle { index: 0 },
|
||||||
|
);
|
||||||
|
let h3 = physics.add_ship(
|
||||||
&ct.ships[0],
|
&ct.ships[0],
|
||||||
vec![outfits::ShipOutfit::Gun(outfits::ShipGun::new(
|
vec![outfits::ShipOutfit::Gun(outfits::ShipGun::new(
|
||||||
ct.guns[0].clone(),
|
&ct.guns[0],
|
||||||
0,
|
0,
|
||||||
))],
|
))],
|
||||||
Point2 {
|
Point2 {
|
||||||
x: -300.0,
|
x: -300.0,
|
||||||
y: 300.0,
|
y: 300.0,
|
||||||
},
|
},
|
||||||
|
FactionHandle { index: 1 },
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut shipbehaviors: Vec<Box<dyn ShipBehavior>> = Vec::new();
|
let mut shipbehaviors: Vec<Box<dyn ShipBehavior>> = Vec::new();
|
||||||
shipbehaviors.push(shipbehavior::Player::new(h1));
|
shipbehaviors.push(shipbehavior::Player::new(h1));
|
||||||
//shipbehaviors.push(shipbehavior::Point::new(h3));
|
|
||||||
shipbehaviors.push(shipbehavior::Dummy::new(h2));
|
shipbehaviors.push(shipbehavior::Dummy::new(h2));
|
||||||
|
shipbehaviors.push(shipbehavior::Point::new(h3));
|
||||||
|
|
||||||
Game {
|
Game {
|
||||||
last_update: Instant::now(),
|
last_update: Instant::now(),
|
||||||
|
@ -72,6 +81,7 @@ impl Game {
|
||||||
time_scale: 1.0,
|
time_scale: 1.0,
|
||||||
physics,
|
physics,
|
||||||
shipbehaviors,
|
shipbehaviors,
|
||||||
|
content: ct,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,11 +109,16 @@ impl Game {
|
||||||
pub fn update(&mut self) {
|
pub fn update(&mut self) {
|
||||||
let t: f32 = self.last_update.elapsed().as_secs_f32() * self.time_scale;
|
let t: f32 = self.last_update.elapsed().as_secs_f32() * self.time_scale;
|
||||||
|
|
||||||
for b in &mut self.shipbehaviors {
|
self.shipbehaviors.retain_mut(|b| {
|
||||||
b.update_controls(&mut self.physics, &self.input, self.player);
|
if self.physics.get_ship_mut(&b.get_handle()).is_none() {
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
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 {
|
if self.input.v_scroll != 0.0 {
|
||||||
self.camera.zoom =
|
self.camera.zoom =
|
||||||
|
@ -112,7 +127,11 @@ impl Game {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Camera physics
|
// TODO: Camera physics
|
||||||
let r = self.physics.get_ship_mut(&self.player).physics_handle;
|
let r = self
|
||||||
|
.physics
|
||||||
|
.get_ship_mut(&self.player)
|
||||||
|
.unwrap()
|
||||||
|
.physics_handle;
|
||||||
let r = self.physics.get_rigid_body(r.0); // TODO: r.0 shouldn't be public
|
let r = self.physics.get_rigid_body(r.0); // TODO: r.0 shouldn't be public
|
||||||
let ship_pos = util::rigidbody_position(r);
|
let ship_pos = util::rigidbody_position(r);
|
||||||
self.camera.pos = ship_pos;
|
self.camera.pos = ship_pos;
|
||||||
|
|
|
@ -1,9 +1,6 @@
|
||||||
use cgmath::{Deg, Point3};
|
use cgmath::{Deg, Point3};
|
||||||
|
|
||||||
use crate::{
|
use crate::{content, render::SubSprite};
|
||||||
content::{self, EnginePoint, GunPoint},
|
|
||||||
render::SubSprite,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Represents a gun attached to a specific ship at a certain gunpoint.
|
/// Represents a gun attached to a specific ship at a certain gunpoint.
|
||||||
pub struct ShipGun {
|
pub struct ShipGun {
|
||||||
|
@ -13,9 +10,9 @@ pub struct ShipGun {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ShipGun {
|
impl ShipGun {
|
||||||
pub fn new(kind: content::Gun, point: usize) -> Self {
|
pub fn new(kind: &content::Gun, point: usize) -> Self {
|
||||||
Self {
|
Self {
|
||||||
kind,
|
kind: kind.clone(),
|
||||||
point,
|
point,
|
||||||
cooldown: 0.0,
|
cooldown: 0.0,
|
||||||
}
|
}
|
||||||
|
@ -77,7 +74,7 @@ impl<'a> ShipOutfits {
|
||||||
.map(|x| x.unwrap())
|
.map(|x| x.unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn iter_guns_points(&mut self) -> impl Iterator<Item = (&mut ShipGun, &GunPoint)> {
|
pub fn iter_guns_points(&mut self) -> impl Iterator<Item = (&mut ShipGun, &content::GunPoint)> {
|
||||||
self.outfits
|
self.outfits
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
.map(|x| x.gun())
|
.map(|x| x.gun())
|
||||||
|
@ -95,7 +92,7 @@ impl<'a> ShipOutfits {
|
||||||
.map(|x| x.unwrap())
|
.map(|x| x.unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn iter_enginepoints(&self) -> impl Iterator<Item = &EnginePoint> {
|
pub fn iter_enginepoints(&self) -> impl Iterator<Item = &content::EnginePoint> {
|
||||||
self.enginepoints.iter()
|
self.enginepoints.iter()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,8 @@ fn main() -> Result<()> {
|
||||||
consts::STARFIELD_TEXTURE_NAME.to_owned(),
|
consts::STARFIELD_TEXTURE_NAME.to_owned(),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
println!("{:?}", content.factions);
|
||||||
|
|
||||||
pollster::block_on(run(content))?;
|
pollster::block_on(run(content))?;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use cgmath::Point3;
|
use cgmath::{Deg, InnerSpace, Point3, Vector2};
|
||||||
use galactica_content::TextureHandle;
|
use galactica_content::{FactionHandle, TextureHandle};
|
||||||
use rapier2d::{
|
use rapier2d::{
|
||||||
dynamics::{RigidBody, RigidBodyBuilder, RigidBodyHandle},
|
dynamics::{RigidBody, RigidBodyBuilder, RigidBodyHandle},
|
||||||
geometry::{ColliderBuilder, ColliderHandle},
|
geometry::{ColliderBuilder, ColliderHandle},
|
||||||
|
@ -14,6 +14,7 @@ pub struct ProjectileBuilder {
|
||||||
pub lifetime: f32,
|
pub lifetime: f32,
|
||||||
pub size: f32,
|
pub size: f32,
|
||||||
pub damage: f32,
|
pub damage: f32,
|
||||||
|
pub faction: FactionHandle,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ProjectileBuilder {
|
impl ProjectileBuilder {
|
||||||
|
@ -25,6 +26,7 @@ impl ProjectileBuilder {
|
||||||
lifetime: self.lifetime,
|
lifetime: self.lifetime,
|
||||||
size: self.size,
|
size: self.size,
|
||||||
damage: self.damage,
|
damage: self.damage,
|
||||||
|
faction: self.faction,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,6 +39,7 @@ pub struct Projectile {
|
||||||
pub lifetime: f32,
|
pub lifetime: f32,
|
||||||
pub size: f32,
|
pub size: f32,
|
||||||
pub damage: f32,
|
pub damage: f32,
|
||||||
|
pub faction: FactionHandle,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Projectile {
|
impl Projectile {
|
||||||
|
@ -50,7 +53,11 @@ impl Projectile {
|
||||||
|
|
||||||
pub fn get_sprite(&self, r: &RigidBody) -> Sprite {
|
pub fn get_sprite(&self, r: &RigidBody) -> Sprite {
|
||||||
let pos = util::rigidbody_position(r);
|
let pos = util::rigidbody_position(r);
|
||||||
let ang = util::rigidbody_angle(r);
|
let rot = util::rigidbody_rotation(r);
|
||||||
|
|
||||||
|
// Sprites point north at 0 degrees
|
||||||
|
let ang: Deg<f32> = rot.angle(Vector2 { x: 1.0, y: 0.0 }).into();
|
||||||
|
|
||||||
Sprite {
|
Sprite {
|
||||||
texture: self.sprite_texture,
|
texture: self.sprite_texture,
|
||||||
pos: Point3 {
|
pos: Point3 {
|
||||||
|
@ -59,7 +66,7 @@ impl Projectile {
|
||||||
z: 1.0,
|
z: 1.0,
|
||||||
},
|
},
|
||||||
size: self.size,
|
size: self.size,
|
||||||
angle: ang,
|
angle: -ang,
|
||||||
children: None,
|
children: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use cgmath::{Deg, EuclideanSpace, Matrix2, Rad, Vector2};
|
use cgmath::{Deg, EuclideanSpace, InnerSpace, Matrix2, Rad, Vector2};
|
||||||
use content::TextureHandle;
|
use content::{FactionHandle, TextureHandle};
|
||||||
use nalgebra::vector;
|
use nalgebra::vector;
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
use rapier2d::{
|
use rapier2d::{
|
||||||
|
@ -40,12 +40,13 @@ impl ShipControls {
|
||||||
|
|
||||||
pub struct Ship {
|
pub struct Ship {
|
||||||
pub physics_handle: ShipHandle,
|
pub physics_handle: ShipHandle,
|
||||||
outfits: outfits::ShipOutfits,
|
pub faction: FactionHandle,
|
||||||
|
|
||||||
sprite_texture: TextureHandle,
|
|
||||||
size: f32,
|
|
||||||
pub hull: f32,
|
pub hull: f32,
|
||||||
pub controls: ShipControls,
|
pub controls: ShipControls,
|
||||||
|
|
||||||
|
outfits: outfits::ShipOutfits,
|
||||||
|
sprite_texture: TextureHandle,
|
||||||
|
size: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Ship {
|
impl Ship {
|
||||||
|
@ -53,6 +54,7 @@ impl Ship {
|
||||||
c: &content::Ship,
|
c: &content::Ship,
|
||||||
outfits: Vec<outfits::ShipOutfit>,
|
outfits: Vec<outfits::ShipOutfit>,
|
||||||
physics_handle: ShipHandle,
|
physics_handle: ShipHandle,
|
||||||
|
faction: FactionHandle,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let mut o = outfits::ShipOutfits::new(c);
|
let mut o = outfits::ShipOutfits::new(c);
|
||||||
for x in outfits.into_iter() {
|
for x in outfits.into_iter() {
|
||||||
|
@ -66,6 +68,7 @@ impl Ship {
|
||||||
size: c.size,
|
size: c.size,
|
||||||
hull: c.hull,
|
hull: c.hull,
|
||||||
controls: ShipControls::new(),
|
controls: ShipControls::new(),
|
||||||
|
faction,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,24 +84,28 @@ impl Ship {
|
||||||
g.cooldown = g.kind.rate + rng.gen_range(-g.kind.rate_rng..=g.kind.rate_rng);
|
g.cooldown = g.kind.rate + rng.gen_range(-g.kind.rate_rng..=g.kind.rate_rng);
|
||||||
|
|
||||||
let ship_pos = util::rigidbody_position(r);
|
let ship_pos = util::rigidbody_position(r);
|
||||||
let ship_ang: Deg<f32> = util::rigidbody_angle(r);
|
let ship_rot = util::rigidbody_rotation(r);
|
||||||
let ship_ang_rad: Rad<f32> = ship_ang.into();
|
|
||||||
let ship_vel = util::rigidbody_velocity(r);
|
let ship_vel = util::rigidbody_velocity(r);
|
||||||
|
let ship_ang = ship_rot.angle(Vector2 { x: 0.0, y: 1.0 });
|
||||||
|
|
||||||
let pos = ship_pos + (Matrix2::from_angle(ship_ang) * p.pos.to_vec());
|
let pos = ship_pos + (Matrix2::from_angle(-ship_ang) * p.pos.to_vec());
|
||||||
|
|
||||||
|
let spread: Rad<f32> =
|
||||||
|
Deg(rng.gen_range(-(g.kind.spread.0 / 2.0)..=g.kind.spread.0 / 2.0)).into();
|
||||||
|
|
||||||
let vel = ship_vel
|
let vel = ship_vel
|
||||||
+ (Matrix2::from_angle(
|
+ (Matrix2::from_angle(-ship_ang + spread)
|
||||||
ship_ang + Deg(rng.gen_range(-(g.kind.spread.0 / 2.0)..=g.kind.spread.0 / 2.0)),
|
* Vector2 {
|
||||||
) * Vector2 {
|
|
||||||
x: 0.0,
|
x: 0.0,
|
||||||
y: g.kind.projectile.speed
|
y: g.kind.projectile.speed
|
||||||
+ rng.gen_range(-g.kind.projectile.speed_rng..=g.kind.projectile.speed_rng),
|
+ rng.gen_range(
|
||||||
|
-g.kind.projectile.speed_rng..=g.kind.projectile.speed_rng,
|
||||||
|
),
|
||||||
});
|
});
|
||||||
|
|
||||||
let p_r = RigidBodyBuilder::kinematic_velocity_based()
|
let p_r = RigidBodyBuilder::kinematic_velocity_based()
|
||||||
.translation(vector![pos.x, pos.y])
|
.translation(vector![pos.x, pos.y])
|
||||||
.rotation(-ship_ang_rad.0)
|
.rotation(-ship_ang.0)
|
||||||
.linvel(vector![vel.x, vel.y]);
|
.linvel(vector![vel.x, vel.y]);
|
||||||
|
|
||||||
let p_c = ColliderBuilder::ball(5.0)
|
let p_c = ColliderBuilder::ball(5.0)
|
||||||
|
@ -116,6 +123,7 @@ impl Ship {
|
||||||
size: g.kind.projectile.size
|
size: g.kind.projectile.size
|
||||||
+ rng.gen_range(-g.kind.projectile.size_rng..=g.kind.projectile.size_rng),
|
+ rng.gen_range(-g.kind.projectile.size_rng..=g.kind.projectile.size_rng),
|
||||||
damage: g.kind.projectile.damage, // TODO: kind as param to builder
|
damage: g.kind.projectile.damage, // TODO: kind as param to builder
|
||||||
|
faction: self.faction,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return out;
|
return out;
|
||||||
|
@ -123,8 +131,8 @@ impl Ship {
|
||||||
|
|
||||||
/// Apply the effects of all active controls
|
/// Apply the effects of all active controls
|
||||||
pub fn apply_controls(&mut self, r: &mut RigidBody, t: f32) -> ShipTickResult {
|
pub fn apply_controls(&mut self, r: &mut RigidBody, t: f32) -> ShipTickResult {
|
||||||
let ship_ang = util::rigidbody_angle(r);
|
let ship_rot = util::rigidbody_rotation(r);
|
||||||
let engine_force = Matrix2::from_angle(ship_ang) * Vector2 { x: 0.0, y: 1.0 } * t;
|
let engine_force = ship_rot * t;
|
||||||
|
|
||||||
if self.controls.thrust {
|
if self.controls.thrust {
|
||||||
for e in self.outfits.iter_engines() {
|
for e in self.outfits.iter_engines() {
|
||||||
|
@ -155,12 +163,15 @@ impl Ship {
|
||||||
|
|
||||||
pub fn get_sprite(&self, r: &RigidBody) -> Sprite {
|
pub fn get_sprite(&self, r: &RigidBody) -> Sprite {
|
||||||
let ship_pos = util::rigidbody_position(r);
|
let ship_pos = util::rigidbody_position(r);
|
||||||
let ship_ang = util::rigidbody_angle(r);
|
let ship_rot = util::rigidbody_rotation(r);
|
||||||
|
|
||||||
|
// Sprites point north at 0 degrees
|
||||||
|
let ship_ang: Deg<f32> = ship_rot.angle(Vector2 { x: 0.0, y: 1.0 }).into();
|
||||||
|
|
||||||
Sprite {
|
Sprite {
|
||||||
pos: (ship_pos.x, ship_pos.y, 1.0).into(),
|
pos: (ship_pos.x, ship_pos.y, 1.0).into(),
|
||||||
texture: self.sprite_texture.clone(), // TODO: sprite texture should be easy to clone
|
texture: self.sprite_texture,
|
||||||
angle: ship_ang,
|
angle: -ship_ang,
|
||||||
size: self.size,
|
size: self.size,
|
||||||
|
|
||||||
children: if self.controls.thrust {
|
children: if self.controls.thrust {
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use cgmath::Point2;
|
use cgmath::Point2;
|
||||||
|
use content::{Content, FactionHandle};
|
||||||
use crossbeam::channel::Receiver;
|
use crossbeam::channel::Receiver;
|
||||||
use nalgebra::vector;
|
use nalgebra::vector;
|
||||||
use rapier2d::{
|
use rapier2d::{
|
||||||
|
@ -6,7 +7,7 @@ use rapier2d::{
|
||||||
geometry::{ColliderBuilder, ColliderHandle, CollisionEvent},
|
geometry::{ColliderBuilder, ColliderHandle, CollisionEvent},
|
||||||
pipeline::ChannelEventCollector,
|
pipeline::ChannelEventCollector,
|
||||||
};
|
};
|
||||||
use std::collections::HashMap;
|
use std::{collections::HashMap, f32::consts::PI};
|
||||||
|
|
||||||
use super::{wrapper::Wrapper, ShipHandle};
|
use super::{wrapper::Wrapper, ShipHandle};
|
||||||
use crate::{content, game::outfits, objects, render::Sprite};
|
use crate::{content, game::outfits, objects, render::Sprite};
|
||||||
|
@ -83,11 +84,15 @@ impl Physics {
|
||||||
ct: &content::Ship,
|
ct: &content::Ship,
|
||||||
outfits: Vec<outfits::ShipOutfit>,
|
outfits: Vec<outfits::ShipOutfit>,
|
||||||
position: Point2<f32>,
|
position: Point2<f32>,
|
||||||
|
faction: FactionHandle,
|
||||||
) -> ShipHandle {
|
) -> ShipHandle {
|
||||||
let cl = ColliderBuilder::convex_decomposition(
|
let cl = ColliderBuilder::convex_decomposition(
|
||||||
&ct.collision.points[..],
|
&ct.collision.points[..],
|
||||||
&ct.collision.indices[..],
|
&ct.collision.indices[..],
|
||||||
)
|
)
|
||||||
|
// Rotate collider to match sprite
|
||||||
|
// (Collider starts pointing east, sprite starts pointing north.)
|
||||||
|
.rotation(PI / -2.0)
|
||||||
.mass(ct.mass);
|
.mass(ct.mass);
|
||||||
|
|
||||||
let rb = RigidBodyBuilder::dynamic()
|
let rb = RigidBodyBuilder::dynamic()
|
||||||
|
@ -102,11 +107,12 @@ impl Physics {
|
||||||
);
|
);
|
||||||
|
|
||||||
let h = ShipHandle(r, c);
|
let h = ShipHandle(r, c);
|
||||||
self.ships.insert(c, objects::Ship::new(ct, outfits, h));
|
self.ships
|
||||||
|
.insert(c, objects::Ship::new(ct, outfits, h, faction));
|
||||||
return h;
|
return h;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn step(&mut self, t: f32) {
|
pub fn step(&mut self, t: f32, ct: &Content) {
|
||||||
// Run ship updates
|
// Run ship updates
|
||||||
let mut res = Vec::new();
|
let mut res = Vec::new();
|
||||||
let mut to_remove = Vec::new();
|
let mut to_remove = Vec::new();
|
||||||
|
@ -136,8 +142,8 @@ impl Physics {
|
||||||
let a = &event.collider1();
|
let a = &event.collider1();
|
||||||
let b = &event.collider2();
|
let b = &event.collider2();
|
||||||
|
|
||||||
// If a projectile is part of the collision, make sure
|
// If projectiles are a part of this collision, make sure
|
||||||
// a is a projectile.
|
// `a` is one of them.
|
||||||
let (a, b) = if self.projectiles.contains_key(b) {
|
let (a, b) = if self.projectiles.contains_key(b) {
|
||||||
(b, a)
|
(b, a)
|
||||||
} else {
|
} else {
|
||||||
|
@ -146,11 +152,19 @@ impl Physics {
|
||||||
|
|
||||||
if let Some(p) = self.projectiles.get(a) {
|
if let Some(p) = self.projectiles.get(a) {
|
||||||
if let Some(s) = self.ships.get_mut(b) {
|
if let Some(s) = self.ships.get_mut(b) {
|
||||||
s.hull -= p.damage;
|
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(*a);
|
||||||
self.remove_projectile(*b);
|
self.remove_projectile(*b);
|
||||||
}
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,16 +185,22 @@ impl Physics {
|
||||||
&self.wrapper.rigid_body_set[r]
|
&self.wrapper.rigid_body_set[r]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_ship_mut(&mut self, s: &ShipHandle) -> &mut objects::Ship {
|
pub fn get_ship_mut(&mut self, s: &ShipHandle) -> Option<&mut objects::Ship> {
|
||||||
self.ships.get_mut(&s.1).unwrap()
|
self.ships.get_mut(&s.1)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_ship_body(&self, s: &ShipHandle) -> (&objects::Ship, &RigidBody) {
|
pub fn get_ship_body(&self, s: &ShipHandle) -> Option<(&objects::Ship, &RigidBody)> {
|
||||||
// TODO: handle dead handles
|
// TODO: handle dead handles
|
||||||
|
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| {
|
||||||
(
|
(
|
||||||
self.ships.get(&s.1).unwrap(),
|
x,
|
||||||
self.wrapper.rigid_body_set.get(s.0).unwrap(),
|
self.wrapper.rigid_body_set.get(x.physics_handle.0).unwrap(),
|
||||||
)
|
)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_ship_sprites(&self) -> impl Iterator<Item = Sprite> + '_ {
|
pub fn get_ship_sprites(&self) -> impl Iterator<Item = Sprite> + '_ {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use cgmath::{Deg, InnerSpace, Point2, Vector2};
|
use cgmath::{Point2, Vector2};
|
||||||
use nalgebra;
|
use nalgebra;
|
||||||
use rapier2d::dynamics::RigidBody;
|
use rapier2d::dynamics::RigidBody;
|
||||||
|
|
||||||
|
@ -9,19 +9,10 @@ pub fn rigidbody_position(r: &RigidBody) -> cgmath::Point2<f32> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn rigidbody_angle(r: &RigidBody) -> Deg<f32> {
|
|
||||||
Vector2 {
|
|
||||||
x: r.rotation().im,
|
|
||||||
y: r.rotation().re,
|
|
||||||
}
|
|
||||||
.angle(Vector2 { x: 0.0, y: 1.0 })
|
|
||||||
.into()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn rigidbody_rotation(r: &RigidBody) -> Vector2<f32> {
|
pub fn rigidbody_rotation(r: &RigidBody) -> Vector2<f32> {
|
||||||
Vector2 {
|
Vector2 {
|
||||||
x: r.rotation().im,
|
x: r.rotation().re,
|
||||||
y: r.rotation().re,
|
y: r.rotation().im,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use cgmath::{Deg, InnerSpace};
|
use cgmath::{Deg, InnerSpace};
|
||||||
|
use galactica_content as content;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
inputstatus::InputStatus,
|
inputstatus::InputStatus,
|
||||||
|
@ -9,7 +10,13 @@ pub trait ShipBehavior
|
||||||
where
|
where
|
||||||
Self: Send,
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Dummy {
|
pub struct Dummy {
|
||||||
|
@ -27,9 +34,12 @@ impl ShipBehavior for Dummy {
|
||||||
&mut self,
|
&mut self,
|
||||||
_physics: &mut Physics,
|
_physics: &mut Physics,
|
||||||
_input: &InputStatus,
|
_input: &InputStatus,
|
||||||
_player: ShipHandle,
|
_content: &content::Content,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
fn get_handle(&self) -> ShipHandle {
|
||||||
|
return self._handle;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Player {
|
pub struct Player {
|
||||||
|
@ -43,13 +53,22 @@ impl Player {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ShipBehavior for Player {
|
impl ShipBehavior for Player {
|
||||||
fn update_controls(&mut self, physics: &mut Physics, input: &InputStatus, _player: ShipHandle) {
|
fn update_controls(
|
||||||
let s = physics.get_ship_mut(&self.handle);
|
&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.left = input.key_left;
|
||||||
s.controls.right = input.key_right;
|
s.controls.right = input.key_right;
|
||||||
s.controls.guns = input.key_guns;
|
s.controls.guns = input.key_guns;
|
||||||
s.controls.thrust = input.key_thrust;
|
s.controls.thrust = input.key_thrust;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_handle(&self) -> ShipHandle {
|
||||||
|
return self.handle;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Point {
|
pub struct Point {
|
||||||
|
@ -63,34 +82,68 @@ impl Point {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ShipBehavior for Point {
|
impl ShipBehavior for Point {
|
||||||
fn update_controls(&mut self, physics: &mut Physics, _input: &InputStatus, player: ShipHandle) {
|
fn update_controls(
|
||||||
let (_, r) = physics.get_ship_body(&player);
|
&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 (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 p = util::rigidbody_position(r);
|
||||||
|
let new_d = (my_position - p).magnitude();
|
||||||
|
if new_d < d {
|
||||||
|
d = new_d;
|
||||||
|
closest_enemy_position = p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let (_, r) = physics.get_ship_body(&self.handle);
|
let angle_delta: Deg<f32> = (my_rotation)
|
||||||
let t = util::rigidbody_position(r);
|
.angle(closest_enemy_position - my_position)
|
||||||
let pa = util::rigidbody_rotation(r);
|
.into();
|
||||||
let v = r.angvel();
|
|
||||||
|
|
||||||
let d: Deg<f32> = (t - p).angle(pa).into();
|
|
||||||
println!("{:?}", d);
|
|
||||||
|
|
||||||
let s = physics.get_ship_mut(&self.handle);
|
|
||||||
|
|
||||||
|
let s = physics.get_ship_mut(&self.handle).unwrap();
|
||||||
s.controls.left = false;
|
s.controls.left = false;
|
||||||
s.controls.right = false;
|
s.controls.right = false;
|
||||||
|
|
||||||
if d < Deg(0.0) && v < 0.1 {
|
if angle_delta < Deg(0.0) && my_angvel > -0.3 {
|
||||||
s.controls.left = false;
|
|
||||||
s.controls.right = true;
|
s.controls.right = true;
|
||||||
println!("r")
|
} else if angle_delta > Deg(0.0) && my_angvel < 0.3 {
|
||||||
} else if d > Deg(0.0) && v > -0.1 {
|
|
||||||
println!("l");
|
|
||||||
s.controls.left = true;
|
s.controls.left = true;
|
||||||
s.controls.right = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
s.controls.guns = true;
|
s.controls.guns = true;
|
||||||
s.controls.thrust = false;
|
s.controls.thrust = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_handle(&self) -> ShipHandle {
|
||||||
|
return self.handle;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue