Compare commits
No commits in common. "ece82a8c1b0d86e3caede0f5314999d77718012e" and "389803eae9254d8c29b1cad8208fcceabb83c9e7" have entirely different histories.
ece82a8c1b
...
389803eae9
|
@ -1,4 +0,0 @@
|
|||
[engine."plasma"]
|
||||
|
||||
thrust = 50
|
||||
flare.sprite = "flare::ion"
|
|
@ -1,22 +1,5 @@
|
|||
[gun."blaster"]
|
||||
|
||||
# Angle of fire cone
|
||||
# Smaller angle = more accurate
|
||||
spread = 2
|
||||
|
||||
# Average delay between shots
|
||||
rate = 0.2
|
||||
# Random rate variation (+- this in both directions)
|
||||
rate_rng = 0.1
|
||||
|
||||
|
||||
projectile.sprite = "projectile::blaster"
|
||||
# Height of projectile in game units
|
||||
projectile.size = 10
|
||||
projectile.size_rng = 0.0
|
||||
# Speed of projectile, in game units/second
|
||||
projectile.size = 100
|
||||
projectile.speed = 300
|
||||
projectile.speed_rng = 10.0
|
||||
# Lifetime of projectile, in seconds
|
||||
projectile.lifetime = 2.0
|
||||
projectile.lifetime_rng = 0.2
|
||||
|
|
|
@ -3,4 +3,4 @@ sprite = "ship::gypsum"
|
|||
size = 100
|
||||
|
||||
engines = [{ x = 0.0, y = -105, size = 50.0 }]
|
||||
guns = [{ x = 0.0, y = 100 }, { x = 10.0, y = 80 }, { x = -10.0, y = 80 }]
|
||||
guns = [{ x = 0.0, y = 100 }]
|
||||
|
|
|
@ -1,46 +0,0 @@
|
|||
use anyhow::Result;
|
||||
|
||||
pub(super) mod syntax {
|
||||
use serde::Deserialize;
|
||||
// Raw serde syntax structs.
|
||||
// These are never seen by code outside this crate.
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct Engine {
|
||||
pub thrust: f32,
|
||||
pub flare: Flare,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct Flare {
|
||||
pub sprite: String,
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Engine {
|
||||
pub name: String,
|
||||
pub thrust: f32,
|
||||
pub flare_sprite: String,
|
||||
}
|
||||
|
||||
impl super::Build for Engine {
|
||||
fn build(root: &super::syntax::Root) -> Result<Vec<Self>> {
|
||||
let engine = if let Some(engine) = &root.engine {
|
||||
engine
|
||||
} else {
|
||||
return Ok(vec![]);
|
||||
};
|
||||
|
||||
let mut out = Vec::new();
|
||||
for (engine_name, engine) in engine {
|
||||
out.push(Self {
|
||||
name: engine_name.to_owned(),
|
||||
thrust: engine.thrust,
|
||||
flare_sprite: engine.flare.sprite.clone(),
|
||||
});
|
||||
}
|
||||
|
||||
return Ok(out);
|
||||
}
|
||||
}
|
|
@ -1,5 +1,4 @@
|
|||
use anyhow::Result;
|
||||
use cgmath::Deg;
|
||||
|
||||
pub(super) mod syntax {
|
||||
use serde::Deserialize;
|
||||
|
@ -9,20 +8,14 @@ pub(super) mod syntax {
|
|||
#[derive(Debug, Deserialize)]
|
||||
pub struct Gun {
|
||||
pub projectile: Projectile,
|
||||
pub spread: f32,
|
||||
pub rate: f32,
|
||||
pub rate_rng: f32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct Projectile {
|
||||
pub sprite: String,
|
||||
pub size: f32,
|
||||
pub size_rng: f32,
|
||||
pub speed: f32,
|
||||
pub speed_rng: f32,
|
||||
pub lifetime: f32,
|
||||
pub lifetime_rng: f32,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -30,20 +23,14 @@ pub(super) mod syntax {
|
|||
pub struct Gun {
|
||||
pub name: String,
|
||||
pub projectile: Projectile,
|
||||
pub spread: Deg<f32>,
|
||||
pub rate: f32,
|
||||
pub rate_rng: f32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Projectile {
|
||||
pub sprite: String,
|
||||
pub size: f32,
|
||||
pub size_rng: f32,
|
||||
pub speed: f32,
|
||||
pub speed_rng: f32,
|
||||
pub lifetime: f32,
|
||||
pub lifetime_rng: f32,
|
||||
}
|
||||
|
||||
impl super::Build for Gun {
|
||||
|
@ -58,17 +45,11 @@ impl super::Build for Gun {
|
|||
for (gun_name, gun) in gun {
|
||||
out.push(Self {
|
||||
name: gun_name.to_owned(),
|
||||
spread: Deg(gun.spread),
|
||||
rate: gun.rate,
|
||||
rate_rng: gun.rate_rng,
|
||||
projectile: Projectile {
|
||||
sprite: gun.projectile.sprite.to_owned(),
|
||||
size: gun.projectile.size,
|
||||
size_rng: gun.projectile.size_rng,
|
||||
speed: gun.projectile.speed,
|
||||
speed_rng: gun.projectile.speed_rng,
|
||||
lifetime: gun.projectile.lifetime,
|
||||
lifetime_rng: gun.projectile.lifetime_rng,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
#![allow(dead_code)]
|
||||
mod engine;
|
||||
mod gun;
|
||||
mod ship;
|
||||
mod system;
|
||||
|
||||
pub use engine::Engine;
|
||||
pub use gun::{Gun, Projectile};
|
||||
pub use ship::{EnginePoint, GunPoint, Ship};
|
||||
pub use ship::{Engine, Ship, ShipGun};
|
||||
pub use system::{Object, System};
|
||||
|
||||
use anyhow::{bail, Context, Result};
|
||||
|
@ -17,7 +15,7 @@ use walkdir::WalkDir;
|
|||
|
||||
mod syntax {
|
||||
use super::HashMap;
|
||||
use super::{engine, gun, ship, system};
|
||||
use super::{gun, ship, system};
|
||||
use serde::Deserialize;
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
|
@ -25,7 +23,6 @@ mod syntax {
|
|||
pub gun: Option<HashMap<String, gun::syntax::Gun>>,
|
||||
pub ship: Option<HashMap<String, ship::syntax::Ship>>,
|
||||
pub system: Option<HashMap<String, system::syntax::System>>,
|
||||
pub engine: Option<HashMap<String, engine::syntax::Engine>>,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -36,13 +33,11 @@ trait Build {
|
|||
Self: Sized;
|
||||
}
|
||||
|
||||
/// Represents generic game content, not connected to any game objects.
|
||||
#[derive(Debug)]
|
||||
pub struct Content {
|
||||
pub systems: Vec<system::System>,
|
||||
pub ships: Vec<ship::Ship>,
|
||||
pub guns: Vec<gun::Gun>,
|
||||
pub engines: Vec<engine::Engine>,
|
||||
}
|
||||
|
||||
macro_rules! quick_name_dup_check {
|
||||
|
@ -75,7 +70,6 @@ impl Content {
|
|||
quick_name_dup_check!(self.systems, root, system::System::build);
|
||||
quick_name_dup_check!(self.guns, root, gun::Gun::build);
|
||||
quick_name_dup_check!(self.ships, root, ship::Ship::build);
|
||||
quick_name_dup_check!(self.engines, root, engine::Engine::build);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
|
@ -84,7 +78,6 @@ impl Content {
|
|||
systems: Vec::new(),
|
||||
ships: Vec::new(),
|
||||
guns: Vec::new(),
|
||||
engines: Vec::new(),
|
||||
};
|
||||
|
||||
for e in WalkDir::new(path).into_iter().filter_map(|e| e.ok()) {
|
||||
|
|
|
@ -36,19 +36,21 @@ pub struct Ship {
|
|||
pub name: String,
|
||||
pub sprite: String,
|
||||
pub size: f32,
|
||||
pub engines: Vec<EnginePoint>,
|
||||
pub guns: Vec<GunPoint>,
|
||||
pub engines: Vec<Engine>,
|
||||
pub guns: Vec<ShipGun>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct EnginePoint {
|
||||
pub struct Engine {
|
||||
pub pos: Point2<f32>,
|
||||
pub size: f32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct GunPoint {
|
||||
pub struct ShipGun {
|
||||
pub pos: Point2<f32>,
|
||||
pub cooldown: f32,
|
||||
pub active_cooldown: f32,
|
||||
}
|
||||
|
||||
impl super::Build for Ship {
|
||||
|
@ -68,7 +70,7 @@ impl super::Build for Ship {
|
|||
engines: ship
|
||||
.engines
|
||||
.iter()
|
||||
.map(|e| EnginePoint {
|
||||
.map(|e| Engine {
|
||||
pos: Point2 { x: e.x, y: e.y },
|
||||
size: e.size,
|
||||
})
|
||||
|
@ -76,8 +78,10 @@ impl super::Build for Ship {
|
|||
guns: ship
|
||||
.guns
|
||||
.iter()
|
||||
.map(|e| GunPoint {
|
||||
.map(|e| ShipGun {
|
||||
pos: Point2 { x: e.x, y: e.y },
|
||||
cooldown: 0.2,
|
||||
active_cooldown: 0.0,
|
||||
})
|
||||
.collect(),
|
||||
});
|
||||
|
|
|
@ -2,7 +2,7 @@ use cgmath::{Deg, Point2, Point3, Vector2};
|
|||
use std::time::Instant;
|
||||
use winit::event::{ElementState, MouseButton, MouseScrollDelta, TouchPhase, VirtualKeyCode};
|
||||
|
||||
use super::{ship, Camera, InputStatus, System};
|
||||
use super::{Camera, InputStatus, Ship, System};
|
||||
use crate::{
|
||||
consts,
|
||||
content::Content,
|
||||
|
@ -16,7 +16,6 @@ pub struct Projectile {
|
|||
pub sprite: SpriteTexture,
|
||||
pub angle: Deg<f32>,
|
||||
pub lifetime: f32,
|
||||
pub size: f32,
|
||||
}
|
||||
|
||||
impl Projectile {
|
||||
|
@ -33,8 +32,8 @@ impl Projectile {
|
|||
pub struct Game {
|
||||
pub input: InputStatus,
|
||||
pub last_update: Instant,
|
||||
pub player: ship::Ship,
|
||||
pub test: ship::Ship,
|
||||
pub player: Ship,
|
||||
pub test: Ship,
|
||||
pub system: System,
|
||||
pub camera: Camera,
|
||||
paused: bool,
|
||||
|
@ -48,15 +47,7 @@ impl Game {
|
|||
last_update: Instant::now(),
|
||||
input: InputStatus::new(),
|
||||
projectiles: Vec::new(),
|
||||
player: ship::Ship::new(
|
||||
&ct.ships[0],
|
||||
vec![
|
||||
ship::ShipOutfit::Gun(ship::ShipGun::new(ct.guns[0].clone(), 1)),
|
||||
ship::ShipOutfit::Gun(ship::ShipGun::new(ct.guns[0].clone(), 2)),
|
||||
ship::ShipOutfit::Engine(ct.engines[0].clone()),
|
||||
],
|
||||
(0.0, 0.0).into(),
|
||||
),
|
||||
player: Ship::new(&ct.ships[0], (0.0, 0.0).into()),
|
||||
camera: Camera {
|
||||
pos: (0.0, 0.0).into(),
|
||||
zoom: 500.0,
|
||||
|
@ -65,7 +56,7 @@ impl Game {
|
|||
|
||||
paused: false,
|
||||
time_scale: 1.0,
|
||||
test: ship::Ship::new(&ct.ships[0], vec![], (100.0, 100.0).into()),
|
||||
test: Ship::new(&ct.ships[0], (100.0, 100.0).into()),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -139,7 +130,7 @@ impl Game {
|
|||
y: p.position.y,
|
||||
z: 1.0,
|
||||
},
|
||||
size: p.size,
|
||||
size: 10.0,
|
||||
angle: p.angle,
|
||||
children: None,
|
||||
})
|
||||
|
|
|
@ -8,5 +8,6 @@ mod systemobject;
|
|||
pub use camera::Camera;
|
||||
pub use game::Game;
|
||||
pub use inputstatus::InputStatus;
|
||||
pub use ship::Ship;
|
||||
pub use system::System;
|
||||
pub use systemobject::SystemObject;
|
||||
|
|
|
@ -0,0 +1,143 @@
|
|||
use cgmath::{Deg, EuclideanSpace, Matrix2, Point2, Point3, Vector2};
|
||||
|
||||
use crate::{
|
||||
content,
|
||||
physics::PhysicsBody,
|
||||
render::{Sprite, SpriteTexture, Spriteable, SubSprite},
|
||||
};
|
||||
|
||||
use super::{game::Projectile, InputStatus};
|
||||
|
||||
pub struct ShipControls {
|
||||
pub left: bool,
|
||||
pub right: bool,
|
||||
pub thrust: bool,
|
||||
pub guns: bool,
|
||||
}
|
||||
|
||||
impl ShipControls {
|
||||
pub fn new() -> Self {
|
||||
ShipControls {
|
||||
left: false,
|
||||
right: false,
|
||||
thrust: false,
|
||||
guns: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ShipTickResult {
|
||||
pub projectiles: Vec<Projectile>,
|
||||
}
|
||||
|
||||
pub struct Ship {
|
||||
pub physicsbody: PhysicsBody,
|
||||
pub controls: ShipControls,
|
||||
|
||||
sprite: SpriteTexture,
|
||||
size: f32,
|
||||
engines: Vec<content::Engine>,
|
||||
guns: Vec<content::ShipGun>,
|
||||
}
|
||||
|
||||
impl Ship {
|
||||
pub fn new(ct: &content::Ship, pos: Point2<f32>) -> Self {
|
||||
Ship {
|
||||
physicsbody: PhysicsBody::new(pos),
|
||||
sprite: SpriteTexture(ct.sprite.clone()),
|
||||
size: ct.size,
|
||||
engines: ct.engines.clone(),
|
||||
guns: ct.guns.clone(),
|
||||
controls: ShipControls::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_controls(&mut self, input: &InputStatus) {
|
||||
self.controls.thrust = input.key_thrust;
|
||||
self.controls.right = input.key_right;
|
||||
self.controls.left = input.key_left;
|
||||
self.controls.guns = input.key_guns;
|
||||
}
|
||||
|
||||
pub fn fire_guns(&mut self) -> Vec<Projectile> {
|
||||
let mut out = Vec::new();
|
||||
for i in &mut self.guns {
|
||||
if i.active_cooldown > 0.0 {
|
||||
continue;
|
||||
}
|
||||
i.active_cooldown = i.cooldown;
|
||||
|
||||
let p = self.physicsbody.pos
|
||||
+ (Matrix2::from_angle(self.physicsbody.angle) * i.pos.to_vec());
|
||||
|
||||
out.push(Projectile {
|
||||
position: p,
|
||||
velocity: self.physicsbody.vel
|
||||
+ (Matrix2::from_angle(self.physicsbody.angle) * Vector2 { x: 0.0, y: 400.0 }),
|
||||
angle: self.physicsbody.angle,
|
||||
sprite: SpriteTexture("projectile::blaster".into()),
|
||||
lifetime: 5.0,
|
||||
})
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
pub fn tick(&mut self, t: f32) -> ShipTickResult {
|
||||
if self.controls.thrust {
|
||||
self.physicsbody.thrust(50.0 * t);
|
||||
}
|
||||
|
||||
if self.controls.right {
|
||||
self.physicsbody.rot(Deg(35.0) * t);
|
||||
}
|
||||
|
||||
if self.controls.left {
|
||||
self.physicsbody.rot(Deg(-35.0) * t);
|
||||
}
|
||||
|
||||
let p = if self.controls.guns {
|
||||
self.fire_guns()
|
||||
} else {
|
||||
Vec::new()
|
||||
};
|
||||
|
||||
self.physicsbody.tick(t);
|
||||
for i in &mut self.guns {
|
||||
i.active_cooldown -= t;
|
||||
}
|
||||
|
||||
return ShipTickResult { projectiles: p };
|
||||
}
|
||||
}
|
||||
|
||||
impl Spriteable for Ship {
|
||||
fn get_sprite(&self) -> Sprite {
|
||||
let engines = if self.controls.thrust {
|
||||
Some(
|
||||
self.engines
|
||||
.iter()
|
||||
.map(|e| SubSprite {
|
||||
pos: Point3 {
|
||||
x: e.pos.x,
|
||||
y: e.pos.y,
|
||||
z: 1.0,
|
||||
},
|
||||
texture: SpriteTexture("flare::ion".to_owned()),
|
||||
angle: Deg(0.0),
|
||||
size: e.size,
|
||||
})
|
||||
.collect(),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
Sprite {
|
||||
pos: (self.physicsbody.pos.x, self.physicsbody.pos.y, 1.0).into(),
|
||||
texture: self.sprite.clone(), // TODO: sprite texture should be easy to clone
|
||||
angle: self.physicsbody.angle,
|
||||
size: self.size,
|
||||
children: engines,
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
mod outfits;
|
||||
mod ship;
|
||||
|
||||
pub use outfits::{ShipGun, ShipOutfit, ShipOutfits};
|
||||
pub use ship::Ship;
|
||||
|
||||
use super::{game::Projectile, InputStatus};
|
||||
|
||||
pub struct ShipControls {
|
||||
pub left: bool,
|
||||
pub right: bool,
|
||||
pub thrust: bool,
|
||||
pub guns: bool,
|
||||
}
|
||||
|
||||
impl ShipControls {
|
||||
pub fn new() -> Self {
|
||||
ShipControls {
|
||||
left: false,
|
||||
right: false,
|
||||
thrust: false,
|
||||
guns: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ShipTickResult {
|
||||
pub projectiles: Vec<Projectile>,
|
||||
}
|
|
@ -1,129 +0,0 @@
|
|||
use cgmath::{Deg, Point3};
|
||||
|
||||
use crate::{
|
||||
content::{self, EnginePoint, GunPoint},
|
||||
render::{SpriteTexture, SubSprite},
|
||||
};
|
||||
|
||||
/// Represents a gun attached to a specific ship at a certain gunpoint.
|
||||
pub struct ShipGun {
|
||||
pub kind: content::Gun,
|
||||
pub cooldown: f32,
|
||||
pub point: usize,
|
||||
}
|
||||
|
||||
impl ShipGun {
|
||||
pub fn new(kind: content::Gun, point: usize) -> Self {
|
||||
Self {
|
||||
kind,
|
||||
point,
|
||||
cooldown: 0.0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents a specific outfit attached to a specific ship
|
||||
pub enum ShipOutfit {
|
||||
Gun(ShipGun),
|
||||
Engine(content::Engine),
|
||||
}
|
||||
|
||||
impl ShipOutfit {
|
||||
pub fn gun(&mut self) -> Option<&mut ShipGun> {
|
||||
match self {
|
||||
Self::Gun(g) => Some(g),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn engine(&self) -> Option<&content::Engine> {
|
||||
match self {
|
||||
Self::Engine(e) => Some(e),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ShipOutfits {
|
||||
outfits: Vec<ShipOutfit>,
|
||||
enginepoints: Vec<content::EnginePoint>,
|
||||
gunpoints: Vec<content::GunPoint>,
|
||||
|
||||
// Minor performance optimization, since we
|
||||
// rarely need to re-compute these.
|
||||
engine_flare_sprites: Vec<SubSprite>,
|
||||
}
|
||||
|
||||
impl<'a> ShipOutfits {
|
||||
pub fn new(enginepoints: Vec<content::EnginePoint>, gunpoints: Vec<content::GunPoint>) -> Self {
|
||||
Self {
|
||||
outfits: Vec::new(),
|
||||
enginepoints,
|
||||
gunpoints,
|
||||
engine_flare_sprites: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add(&mut self, o: ShipOutfit) {
|
||||
self.outfits.push(o);
|
||||
self.update_engine_flares();
|
||||
}
|
||||
|
||||
pub fn iter_guns(&mut self) -> impl Iterator<Item = &mut ShipGun> {
|
||||
self.outfits
|
||||
.iter_mut()
|
||||
.map(|x| x.gun())
|
||||
.filter(|x| x.is_some())
|
||||
.map(|x| x.unwrap())
|
||||
}
|
||||
|
||||
pub fn iter_guns_points(&mut self) -> impl Iterator<Item = (&mut ShipGun, &GunPoint)> {
|
||||
self.outfits
|
||||
.iter_mut()
|
||||
.map(|x| x.gun())
|
||||
.filter(|x| x.is_some())
|
||||
.map(|x| x.unwrap())
|
||||
.map(|x| (&self.gunpoints[x.point], x))
|
||||
.map(|(a, b)| (b, a))
|
||||
}
|
||||
|
||||
pub fn iter_engines(&self) -> impl Iterator<Item = &content::Engine> {
|
||||
self.outfits
|
||||
.iter()
|
||||
.map(|x| x.engine())
|
||||
.filter(|x| x.is_some())
|
||||
.map(|x| x.unwrap())
|
||||
}
|
||||
|
||||
pub fn iter_enginepoints(&self) -> impl Iterator<Item = &EnginePoint> {
|
||||
self.enginepoints.iter()
|
||||
}
|
||||
|
||||
pub fn update_engine_flares(&mut self) {
|
||||
// TODO: better way to pick flare texture
|
||||
self.engine_flare_sprites.clear();
|
||||
let t = if let Some(e) = self.iter_engines().next() {
|
||||
SpriteTexture(e.flare_sprite.clone())
|
||||
} else {
|
||||
return;
|
||||
};
|
||||
|
||||
self.engine_flare_sprites = self
|
||||
.iter_enginepoints()
|
||||
.map(|p| SubSprite {
|
||||
pos: Point3 {
|
||||
x: p.pos.x,
|
||||
y: p.pos.y,
|
||||
z: 1.0,
|
||||
},
|
||||
texture: t.clone(),
|
||||
angle: Deg(0.0),
|
||||
size: p.size,
|
||||
})
|
||||
.collect();
|
||||
}
|
||||
|
||||
pub fn get_engine_flares(&self) -> Vec<SubSprite> {
|
||||
return self.engine_flare_sprites.clone();
|
||||
}
|
||||
}
|
|
@ -1,132 +0,0 @@
|
|||
use cgmath::{Deg, EuclideanSpace, Matrix2, Point2, Vector2};
|
||||
use rand::Rng;
|
||||
|
||||
use super::super::game::Projectile;
|
||||
use super::ShipOutfit;
|
||||
use super::{outfits::ShipOutfits, InputStatus, ShipControls, ShipTickResult};
|
||||
use crate::{
|
||||
content,
|
||||
physics::PhysicsBody,
|
||||
render::{Sprite, SpriteTexture, Spriteable},
|
||||
};
|
||||
|
||||
pub struct Ship {
|
||||
pub physicsbody: PhysicsBody,
|
||||
pub controls: ShipControls,
|
||||
outfits: ShipOutfits,
|
||||
|
||||
sprite: SpriteTexture,
|
||||
size: f32,
|
||||
}
|
||||
|
||||
impl Ship {
|
||||
pub fn new(ct: &content::Ship, outfits: Vec<ShipOutfit>, pos: Point2<f32>) -> Self {
|
||||
let mut o = ShipOutfits::new(ct.engines.clone(), ct.guns.clone());
|
||||
for x in outfits.into_iter() {
|
||||
o.add(x)
|
||||
}
|
||||
|
||||
Ship {
|
||||
physicsbody: PhysicsBody::new(pos),
|
||||
controls: ShipControls::new(),
|
||||
|
||||
outfits: o,
|
||||
sprite: SpriteTexture(ct.sprite.clone()),
|
||||
size: ct.size,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_controls(&mut self, input: &InputStatus) {
|
||||
self.controls.thrust = input.key_thrust;
|
||||
self.controls.right = input.key_right;
|
||||
self.controls.left = input.key_left;
|
||||
self.controls.guns = input.key_guns;
|
||||
}
|
||||
|
||||
pub fn fire_guns(&mut self) -> Vec<Projectile> {
|
||||
let mut rng = rand::thread_rng();
|
||||
|
||||
let mut out = Vec::new();
|
||||
|
||||
for (g, p) in self.outfits.iter_guns_points() {
|
||||
if g.cooldown > 0.0 {
|
||||
continue;
|
||||
}
|
||||
|
||||
g.cooldown = g.kind.rate + rng.gen_range(-g.kind.rate_rng..=g.kind.rate_rng);
|
||||
|
||||
let pos = self.physicsbody.pos
|
||||
+ (Matrix2::from_angle(self.physicsbody.angle) * p.pos.to_vec());
|
||||
|
||||
let vel = self.physicsbody.vel
|
||||
+ (Matrix2::from_angle(
|
||||
self.physicsbody.angle
|
||||
+ Deg(rng.gen_range(-(g.kind.spread.0 / 2.0)..=g.kind.spread.0 / 2.0)),
|
||||
) * Vector2 {
|
||||
x: 0.0,
|
||||
y: g.kind.projectile.speed
|
||||
+ rng.gen_range(-g.kind.projectile.speed_rng..=g.kind.projectile.speed_rng),
|
||||
});
|
||||
|
||||
out.push(Projectile {
|
||||
position: pos,
|
||||
velocity: vel,
|
||||
angle: self.physicsbody.angle,
|
||||
sprite: SpriteTexture(g.kind.projectile.sprite.clone()),
|
||||
lifetime: g.kind.projectile.lifetime
|
||||
+ rng.gen_range(
|
||||
-g.kind.projectile.lifetime_rng..=g.kind.projectile.lifetime_rng,
|
||||
),
|
||||
size: g.kind.projectile.size
|
||||
+ rng.gen_range(-g.kind.projectile.size_rng..=g.kind.projectile.size_rng),
|
||||
})
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
pub fn tick(&mut self, t: f32) -> ShipTickResult {
|
||||
if self.controls.thrust {
|
||||
for e in self.outfits.iter_engines() {
|
||||
self.physicsbody.thrust(e.thrust * t);
|
||||
}
|
||||
}
|
||||
|
||||
if self.controls.right {
|
||||
self.physicsbody.rot(Deg(35.0) * t);
|
||||
}
|
||||
|
||||
if self.controls.left {
|
||||
self.physicsbody.rot(Deg(-35.0) * t);
|
||||
}
|
||||
|
||||
let p = if self.controls.guns {
|
||||
self.fire_guns()
|
||||
} else {
|
||||
Vec::new()
|
||||
};
|
||||
|
||||
self.physicsbody.tick(t);
|
||||
for i in self.outfits.iter_guns() {
|
||||
i.cooldown -= t;
|
||||
}
|
||||
|
||||
return ShipTickResult { projectiles: p };
|
||||
}
|
||||
}
|
||||
|
||||
impl Spriteable for Ship {
|
||||
fn get_sprite(&self) -> Sprite {
|
||||
Sprite {
|
||||
pos: (self.physicsbody.pos.x, self.physicsbody.pos.y, 1.0).into(),
|
||||
texture: self.sprite.clone(), // TODO: sprite texture should be easy to clone
|
||||
angle: self.physicsbody.angle,
|
||||
size: self.size,
|
||||
|
||||
children: if self.controls.thrust {
|
||||
Some(self.outfits.get_engine_flares())
|
||||
} else {
|
||||
None
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,7 +2,6 @@ use cgmath::{Deg, Point3};
|
|||
|
||||
use super::SpriteTexture;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Sprite {
|
||||
/// The sprite texture to draw
|
||||
pub texture: SpriteTexture,
|
||||
|
@ -22,7 +21,6 @@ pub struct Sprite {
|
|||
pub children: Option<Vec<SubSprite>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct SubSprite {
|
||||
/// The sprite texture to draw
|
||||
pub texture: SpriteTexture,
|
||||
|
|
Loading…
Reference in New Issue