Compare commits
2 Commits
876a95e546
...
173263f334
Author | SHA1 | Date |
---|---|---|
Mark | 173263f334 | |
Mark | 083f76332f |
|
@ -644,6 +644,7 @@ dependencies = [
|
||||||
"cgmath",
|
"cgmath",
|
||||||
"galactica-content",
|
"galactica-content",
|
||||||
"galactica-galaxy",
|
"galactica-galaxy",
|
||||||
|
"galactica-playeragent",
|
||||||
"galactica-render",
|
"galactica-render",
|
||||||
"galactica-systemsim",
|
"galactica-systemsim",
|
||||||
"galactica-util",
|
"galactica-util",
|
||||||
|
@ -687,6 +688,20 @@ dependencies = [
|
||||||
"walkdir",
|
"walkdir",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "galactica-playeragent"
|
||||||
|
version = "0.0.0"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"cgmath",
|
||||||
|
"galactica-content",
|
||||||
|
"galactica-galaxy",
|
||||||
|
"galactica-util",
|
||||||
|
"pollster",
|
||||||
|
"wgpu",
|
||||||
|
"winit",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "galactica-render"
|
name = "galactica-render"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
|
@ -714,6 +729,7 @@ dependencies = [
|
||||||
"crossbeam",
|
"crossbeam",
|
||||||
"galactica-content",
|
"galactica-content",
|
||||||
"galactica-galaxy",
|
"galactica-galaxy",
|
||||||
|
"galactica-playeragent",
|
||||||
"galactica-util",
|
"galactica-util",
|
||||||
"nalgebra",
|
"nalgebra",
|
||||||
"rand",
|
"rand",
|
||||||
|
|
|
@ -48,6 +48,7 @@ galactica-render = { path = "crates/render" }
|
||||||
galactica-systemsim = { path = "crates/systemsim" }
|
galactica-systemsim = { path = "crates/systemsim" }
|
||||||
galactica-galaxy = { path = "crates/galaxy" }
|
galactica-galaxy = { path = "crates/galaxy" }
|
||||||
galactica-packer = { path = "crates/packer" }
|
galactica-packer = { path = "crates/packer" }
|
||||||
|
galactica-playeragent = { path = "crates/playeragent" }
|
||||||
galactica = { path = "crates/galactica" }
|
galactica = { path = "crates/galactica" }
|
||||||
|
|
||||||
image = { version = "0.24", features = ["png"] }
|
image = { version = "0.24", features = ["png"] }
|
||||||
|
|
|
@ -26,6 +26,7 @@ galactica-render = { workspace = true }
|
||||||
galactica-util = { workspace = true }
|
galactica-util = { workspace = true }
|
||||||
galactica-systemsim = { workspace = true }
|
galactica-systemsim = { workspace = true }
|
||||||
galactica-galaxy = { workspace = true }
|
galactica-galaxy = { workspace = true }
|
||||||
|
galactica-playeragent = { workspace = true }
|
||||||
|
|
||||||
winit = { workspace = true }
|
winit = { workspace = true }
|
||||||
wgpu = { workspace = true }
|
wgpu = { workspace = true }
|
||||||
|
|
|
@ -1,119 +1,112 @@
|
||||||
use galactica_content::{Content, FactionHandle, OutfitHandle, ShipHandle, SystemHandle};
|
use galactica_content::{Content, FactionHandle, OutfitHandle, ShipHandle, SystemHandle};
|
||||||
use galactica_galaxy::{ship::ShipPersonality, Galaxy, GxShipHandle};
|
use galactica_galaxy::{ship::ShipPersonality, Galaxy, GxShipHandle};
|
||||||
|
use galactica_playeragent::{PlayerAgent, PlayerStatus};
|
||||||
|
use galactica_render::RenderInput;
|
||||||
|
use galactica_systemsim::{util, ParticleBuilder, StepResources, SystemSim, Wrapper};
|
||||||
use galactica_util::timing::Timing;
|
use galactica_util::timing::Timing;
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
use winit::event::{ElementState, MouseButton, MouseScrollDelta, TouchPhase, VirtualKeyCode};
|
|
||||||
|
|
||||||
use crate::camera::Camera;
|
#[derive(Clone)]
|
||||||
use crate::inputstatus::InputStatus;
|
pub struct GameState {
|
||||||
use galactica_render::RenderInput;
|
pub gx: Galaxy,
|
||||||
use galactica_systemsim::{objects::ShipControls, util, ParticleBuilder, StepResources, SystemSim};
|
pub systemsim: SystemSim,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Game {
|
pub struct Game {
|
||||||
input: InputStatus,
|
// Core game data
|
||||||
last_update: Instant,
|
|
||||||
player: GxShipHandle,
|
|
||||||
paused: bool,
|
|
||||||
time_scale: f32,
|
|
||||||
start_instant: Instant,
|
|
||||||
camera: Camera,
|
|
||||||
|
|
||||||
ct: Content,
|
ct: Content,
|
||||||
gx: Galaxy,
|
state_live: GameState,
|
||||||
|
state_static: GameState,
|
||||||
systemsim: SystemSim,
|
|
||||||
|
|
||||||
|
// Metadata
|
||||||
|
wrapper: Wrapper, // Physics computer
|
||||||
|
time_scale: f32,
|
||||||
|
last_update: Instant,
|
||||||
|
start_instant: Instant,
|
||||||
new_particles: Vec<ParticleBuilder>,
|
new_particles: Vec<ParticleBuilder>,
|
||||||
timing: Timing,
|
timing: Timing,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Game {
|
impl Game {
|
||||||
pub fn new(ct: Content) -> Self {
|
pub fn new(ct: Content) -> (Self, GxShipHandle) {
|
||||||
let mut galaxy = Galaxy::new(&ct);
|
let mut gx = Galaxy::new(&ct);
|
||||||
|
|
||||||
let player = galaxy.create_ship(
|
let player = gx.create_ship(
|
||||||
&ct,
|
&ct,
|
||||||
ShipHandle { index: 0 },
|
ShipHandle { index: 0 },
|
||||||
FactionHandle { index: 0 },
|
FactionHandle { index: 0 },
|
||||||
ShipPersonality::Player,
|
ShipPersonality::Player,
|
||||||
&SystemHandle { index: 0 },
|
&SystemHandle { index: 0 },
|
||||||
);
|
);
|
||||||
let s = galaxy.get_ship_mut(player).unwrap();
|
let s = gx.get_ship_mut(player).unwrap();
|
||||||
s.add_outfit(&ct.get_outfit(OutfitHandle { index: 0 }));
|
s.add_outfit(&ct.get_outfit(OutfitHandle { index: 0 }));
|
||||||
s.add_outfit(&ct.get_outfit(OutfitHandle { index: 1 }));
|
s.add_outfit(&ct.get_outfit(OutfitHandle { index: 1 }));
|
||||||
s.add_outfit(&ct.get_outfit(OutfitHandle { index: 2 }));
|
s.add_outfit(&ct.get_outfit(OutfitHandle { index: 2 }));
|
||||||
|
|
||||||
let a = galaxy.create_ship(
|
let a = gx.create_ship(
|
||||||
&ct,
|
&ct,
|
||||||
ShipHandle { index: 0 },
|
ShipHandle { index: 0 },
|
||||||
FactionHandle { index: 1 },
|
FactionHandle { index: 1 },
|
||||||
ShipPersonality::Dummy,
|
ShipPersonality::Dummy,
|
||||||
&SystemHandle { index: 0 },
|
&SystemHandle { index: 0 },
|
||||||
);
|
);
|
||||||
let s = galaxy.get_ship_mut(a).unwrap();
|
let s = gx.get_ship_mut(a).unwrap();
|
||||||
s.add_outfit(&ct.get_outfit(OutfitHandle { index: 0 }));
|
s.add_outfit(&ct.get_outfit(OutfitHandle { index: 0 }));
|
||||||
s.add_outfit(&ct.get_outfit(OutfitHandle { index: 1 }));
|
s.add_outfit(&ct.get_outfit(OutfitHandle { index: 1 }));
|
||||||
s.add_outfit(&ct.get_outfit(OutfitHandle { index: 2 }));
|
s.add_outfit(&ct.get_outfit(OutfitHandle { index: 2 }));
|
||||||
|
|
||||||
let a = galaxy.create_ship(
|
let a = gx.create_ship(
|
||||||
&ct,
|
&ct,
|
||||||
ShipHandle { index: 0 },
|
ShipHandle { index: 0 },
|
||||||
FactionHandle { index: 0 },
|
FactionHandle { index: 0 },
|
||||||
ShipPersonality::Point,
|
ShipPersonality::Point,
|
||||||
&SystemHandle { index: 0 },
|
&SystemHandle { index: 0 },
|
||||||
);
|
);
|
||||||
let s = galaxy.get_ship_mut(a).unwrap();
|
let s = gx.get_ship_mut(a).unwrap();
|
||||||
s.add_outfit(&ct.get_outfit(OutfitHandle { index: 0 }));
|
s.add_outfit(&ct.get_outfit(OutfitHandle { index: 0 }));
|
||||||
s.add_outfit(&ct.get_outfit(OutfitHandle { index: 1 }));
|
s.add_outfit(&ct.get_outfit(OutfitHandle { index: 1 }));
|
||||||
s.add_outfit(&ct.get_outfit(OutfitHandle { index: 2 }));
|
s.add_outfit(&ct.get_outfit(OutfitHandle { index: 2 }));
|
||||||
|
|
||||||
let physics = SystemSim::new(&ct, &galaxy, SystemHandle { index: 0 });
|
let systemsim = SystemSim::new(&ct, &gx, SystemHandle { index: 0 });
|
||||||
|
|
||||||
Game {
|
let state = GameState { gx, systemsim };
|
||||||
last_update: Instant::now(),
|
|
||||||
input: InputStatus::new(),
|
|
||||||
player,
|
|
||||||
start_instant: Instant::now(),
|
|
||||||
|
|
||||||
camera: Camera {
|
(
|
||||||
pos: (0.0, 0.0).into(),
|
Game {
|
||||||
zoom: 500.0,
|
ct,
|
||||||
aspect: 1.0,
|
state_live: state.clone(),
|
||||||
|
state_static: state,
|
||||||
|
|
||||||
|
wrapper: Wrapper::new(),
|
||||||
|
|
||||||
|
last_update: Instant::now(),
|
||||||
|
start_instant: Instant::now(),
|
||||||
|
time_scale: 1.0,
|
||||||
|
new_particles: Vec::new(),
|
||||||
|
timing: Timing::new(),
|
||||||
},
|
},
|
||||||
//system: object::System::new(&ct, SystemHandle { index: 0 }),
|
player,
|
||||||
paused: false,
|
)
|
||||||
time_scale: 1.0,
|
|
||||||
systemsim: physics,
|
|
||||||
gx: galaxy,
|
|
||||||
ct,
|
|
||||||
new_particles: Vec::new(),
|
|
||||||
timing: Timing::new(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_camera_aspect(&mut self, v: f32) {
|
pub fn update_player_controls(&mut self, player: &PlayerAgent) {
|
||||||
self.camera.aspect = v
|
self.state_live.systemsim.update_player_controls(player)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn process_key(&mut self, state: &ElementState, key: &VirtualKeyCode) {
|
pub fn get_player_status(&self, player: &PlayerAgent) -> PlayerStatus {
|
||||||
self.input.process_key(state, key)
|
let o = self
|
||||||
}
|
.state_static
|
||||||
|
.systemsim
|
||||||
|
.get_ship(player.ship.unwrap())
|
||||||
|
.unwrap();
|
||||||
|
let r = self
|
||||||
|
.state_static
|
||||||
|
.systemsim
|
||||||
|
.get_rigid_body(o.rigid_body)
|
||||||
|
.unwrap();
|
||||||
|
let pos = util::rigidbody_position(r);
|
||||||
|
|
||||||
pub fn process_click(&mut self, state: &ElementState, key: &MouseButton) {
|
PlayerStatus { pos }
|
||||||
self.input.process_click(state, key)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn process_scroll(&mut self, delta: &MouseScrollDelta, phase: &TouchPhase) {
|
|
||||||
self.input.process_scroll(delta, phase)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_paused(&mut self, pause: bool) {
|
|
||||||
if pause {
|
|
||||||
self.paused = true;
|
|
||||||
self.input.release_all()
|
|
||||||
} else {
|
|
||||||
self.paused = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update(&mut self) {
|
pub fn update(&mut self) {
|
||||||
|
@ -121,50 +114,33 @@ impl Game {
|
||||||
|
|
||||||
self.timing.start_frame();
|
self.timing.start_frame();
|
||||||
self.timing.start_galaxy();
|
self.timing.start_galaxy();
|
||||||
self.gx.step(t);
|
self.state_live.gx.step(t);
|
||||||
self.timing.mark_galaxy();
|
self.timing.mark_galaxy();
|
||||||
|
|
||||||
self.systemsim.step(StepResources {
|
self.state_live.systemsim.step(StepResources {
|
||||||
player: self.player,
|
|
||||||
player_controls: ShipControls {
|
|
||||||
left: self.input.key_left,
|
|
||||||
right: self.input.key_right,
|
|
||||||
thrust: self.input.key_thrust,
|
|
||||||
guns: self.input.key_guns,
|
|
||||||
},
|
|
||||||
ct: &self.ct,
|
ct: &self.ct,
|
||||||
gx: &mut self.gx,
|
gx: &mut self.state_live.gx,
|
||||||
particles: &mut self.new_particles,
|
particles: &mut self.new_particles,
|
||||||
timing: &mut self.timing,
|
timing: &mut self.timing,
|
||||||
|
wrapper: &mut self.wrapper,
|
||||||
t,
|
t,
|
||||||
});
|
});
|
||||||
|
|
||||||
if self.input.v_scroll != 0.0 {
|
|
||||||
self.camera.zoom = (self.camera.zoom + self.input.v_scroll)
|
|
||||||
.clamp(self.ct.get_config().zoom_min, self.ct.get_config().zoom_max);
|
|
||||||
self.input.v_scroll = 0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.camera.pos = {
|
|
||||||
let o = self.systemsim.get_ship(self.player).unwrap();
|
|
||||||
let r = self.systemsim.get_rigid_body(o.rigid_body).unwrap();
|
|
||||||
util::rigidbody_position(r)
|
|
||||||
};
|
|
||||||
|
|
||||||
self.last_update = Instant::now();
|
self.last_update = Instant::now();
|
||||||
|
self.state_static = self.state_live.clone();
|
||||||
self.timing.mark_frame();
|
self.timing.mark_frame();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_frame_state(&mut self) -> RenderInput {
|
pub fn get_frame_state(&mut self, player: &PlayerAgent) -> RenderInput {
|
||||||
RenderInput {
|
RenderInput {
|
||||||
camera_pos: self.camera.pos,
|
camera_pos: player.camera.pos,
|
||||||
camera_zoom: self.camera.zoom,
|
camera_zoom: player.camera.zoom,
|
||||||
current_time: self.start_instant.elapsed().as_secs_f32(),
|
current_time: self.start_instant.elapsed().as_secs_f32(),
|
||||||
ct: &self.ct,
|
ct: &self.ct,
|
||||||
systemsim: &self.systemsim, // TODO: maybe system should be stored here?
|
systemsim: &self.state_static.systemsim, // TODO: system should be stored here, not in game
|
||||||
particles: &mut self.new_particles,
|
particles: &mut self.new_particles,
|
||||||
player_data: self.player,
|
player_data: player.ship.unwrap(),
|
||||||
gx: &self.gx,
|
gx: &self.state_static.gx,
|
||||||
current_system: SystemHandle { index: 0 },
|
current_system: SystemHandle { index: 0 },
|
||||||
timing: &mut self.timing,
|
timing: &mut self.timing,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
mod camera;
|
|
||||||
mod game;
|
mod game;
|
||||||
mod inputstatus;
|
|
||||||
|
|
||||||
use anyhow::{bail, Result};
|
use anyhow::{bail, Result};
|
||||||
use galactica_content::Content;
|
use galactica_content::Content;
|
||||||
|
use galactica_playeragent::PlayerAgent;
|
||||||
use galactica_util::constants::ASSET_CACHE;
|
use galactica_util::constants::ASSET_CACHE;
|
||||||
use std::{
|
use std::{
|
||||||
fs,
|
fs,
|
||||||
|
@ -37,21 +36,26 @@ fn main() -> Result<()> {
|
||||||
let mut gpu = pollster::block_on(galactica_render::GPUState::new(window, &content))?;
|
let mut gpu = pollster::block_on(galactica_render::GPUState::new(window, &content))?;
|
||||||
gpu.init(&content);
|
gpu.init(&content);
|
||||||
|
|
||||||
let mut game = game::Game::new(content);
|
let (mut game, p) = game::Game::new(content);
|
||||||
game.set_camera_aspect(
|
|
||||||
|
let mut player = PlayerAgent::new(p);
|
||||||
|
|
||||||
|
player.set_camera_aspect(
|
||||||
gpu.window().inner_size().width as f32 / gpu.window().inner_size().height as f32,
|
gpu.window().inner_size().width as f32 / gpu.window().inner_size().height as f32,
|
||||||
);
|
);
|
||||||
|
|
||||||
event_loop.run(move |event, _, control_flow| {
|
event_loop.run(move |event, _, control_flow| {
|
||||||
match event {
|
match event {
|
||||||
Event::RedrawRequested(window_id) if window_id == gpu.window().id() => {
|
Event::RedrawRequested(window_id) if window_id == gpu.window().id() => {
|
||||||
match gpu.render(game.get_frame_state()) {
|
match gpu.render(game.get_frame_state(&player)) {
|
||||||
Ok(_) => {}
|
Ok(_) => {}
|
||||||
Err(wgpu::SurfaceError::Lost) => gpu.resize(game.get_content()),
|
Err(wgpu::SurfaceError::Lost) => gpu.resize(game.get_content()),
|
||||||
Err(wgpu::SurfaceError::OutOfMemory) => *control_flow = ControlFlow::Exit,
|
Err(wgpu::SurfaceError::OutOfMemory) => *control_flow = ControlFlow::Exit,
|
||||||
// All other errors (Outdated, Timeout) should be resolved by the next frame
|
// All other errors (Outdated, Timeout) should be resolved by the next frame
|
||||||
Err(e) => eprintln!("{:?}", e),
|
Err(e) => eprintln!("{:?}", e),
|
||||||
}
|
}
|
||||||
|
let status = game.get_player_status(&player);
|
||||||
|
player.step(game.get_content(), status);
|
||||||
}
|
}
|
||||||
|
|
||||||
Event::MainEventsCleared => {
|
Event::MainEventsCleared => {
|
||||||
|
@ -63,8 +67,8 @@ fn main() -> Result<()> {
|
||||||
ref event,
|
ref event,
|
||||||
window_id,
|
window_id,
|
||||||
} if window_id == gpu.window().id() => match event {
|
} if window_id == gpu.window().id() => match event {
|
||||||
WindowEvent::Focused(state) => {
|
WindowEvent::Focused(_state) => {
|
||||||
game.set_paused(!state);
|
//game.set_paused(!state);
|
||||||
}
|
}
|
||||||
WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit,
|
WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit,
|
||||||
WindowEvent::KeyboardInput {
|
WindowEvent::KeyboardInput {
|
||||||
|
@ -75,23 +79,28 @@ fn main() -> Result<()> {
|
||||||
..
|
..
|
||||||
},
|
},
|
||||||
..
|
..
|
||||||
} => game.process_key(state, key),
|
} => {
|
||||||
|
player.process_key(state, key);
|
||||||
|
game.update_player_controls(&player);
|
||||||
|
}
|
||||||
WindowEvent::MouseInput { state, button, .. } => {
|
WindowEvent::MouseInput { state, button, .. } => {
|
||||||
game.process_click(state, button);
|
player.process_click(state, button);
|
||||||
|
game.update_player_controls(&player);
|
||||||
}
|
}
|
||||||
WindowEvent::MouseWheel { delta, phase, .. } => {
|
WindowEvent::MouseWheel { delta, phase, .. } => {
|
||||||
game.process_scroll(delta, phase);
|
player.process_scroll(delta, phase);
|
||||||
|
game.update_player_controls(&player);
|
||||||
}
|
}
|
||||||
WindowEvent::Resized(_) => {
|
WindowEvent::Resized(_) => {
|
||||||
gpu.resize(game.get_content());
|
gpu.resize(game.get_content());
|
||||||
game.set_camera_aspect(
|
player.set_camera_aspect(
|
||||||
gpu.window().inner_size().width as f32
|
gpu.window().inner_size().width as f32
|
||||||
/ gpu.window().inner_size().height as f32,
|
/ gpu.window().inner_size().height as f32,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
WindowEvent::ScaleFactorChanged { .. } => {
|
WindowEvent::ScaleFactorChanged { .. } => {
|
||||||
gpu.resize(game.get_content());
|
gpu.resize(game.get_content());
|
||||||
game.set_camera_aspect(
|
player.set_camera_aspect(
|
||||||
gpu.window().inner_size().width as f32
|
gpu.window().inner_size().width as f32
|
||||||
/ gpu.window().inner_size().height as f32,
|
/ gpu.window().inner_size().height as f32,
|
||||||
);
|
);
|
||||||
|
|
|
@ -5,7 +5,7 @@ use galactica_content::{Content, FactionHandle, ShipHandle, SystemHandle};
|
||||||
|
|
||||||
/// Keeps track of all objects in the galaxy.
|
/// Keeps track of all objects in the galaxy.
|
||||||
/// This struct does NO physics, it keeps track of data exclusively.
|
/// This struct does NO physics, it keeps track of data exclusively.
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Galaxy {
|
pub struct Galaxy {
|
||||||
/// Universal counter.
|
/// Universal counter.
|
||||||
/// Used to create unique handles for game objects.
|
/// Used to create unique handles for game objects.
|
||||||
|
|
|
@ -6,7 +6,7 @@ use super::{OutfitSet, ShipPersonality};
|
||||||
use galactica_content::{Content, FactionHandle, GunPoint, Outfit, ShipHandle};
|
use galactica_content::{Content, FactionHandle, GunPoint, Outfit, ShipHandle};
|
||||||
use rand::{rngs::ThreadRng, Rng};
|
use rand::{rngs::ThreadRng, Rng};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct GxShip {
|
pub struct GxShip {
|
||||||
// Metadata values
|
// Metadata values
|
||||||
handle: GxShipHandle,
|
handle: GxShipHandle,
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
[package]
|
||||||
|
name = "galactica-playeragent"
|
||||||
|
description = "TODO"
|
||||||
|
categories = { workspace = true }
|
||||||
|
keywords = { workspace = true }
|
||||||
|
version = { workspace = true }
|
||||||
|
rust-version = { workspace = true }
|
||||||
|
authors = { workspace = true }
|
||||||
|
edition = { workspace = true }
|
||||||
|
homepage = { workspace = true }
|
||||||
|
repository = { workspace = true }
|
||||||
|
license = { workspace = true }
|
||||||
|
documentation = { workspace = true }
|
||||||
|
readme = { workspace = true }
|
||||||
|
|
||||||
|
[lints]
|
||||||
|
workspace = true
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
galactica-content = { workspace = true }
|
||||||
|
galactica-util = { workspace = true }
|
||||||
|
galactica-galaxy = { workspace = true }
|
||||||
|
|
||||||
|
winit = { workspace = true }
|
||||||
|
wgpu = { workspace = true }
|
||||||
|
pollster = { workspace = true }
|
||||||
|
anyhow = { workspace = true }
|
||||||
|
cgmath = { workspace = true }
|
|
@ -12,3 +12,13 @@ pub struct Camera {
|
||||||
/// Aspect ratio of viewport (width / height)
|
/// Aspect ratio of viewport (width / height)
|
||||||
pub aspect: f32,
|
pub aspect: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Camera {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
pos: (0.0, 0.0).into(),
|
||||||
|
zoom: 500.0,
|
||||||
|
aspect: 1.0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
mod camera;
|
||||||
|
mod inputstatus;
|
||||||
|
mod playeragent;
|
||||||
|
mod playerstatus;
|
||||||
|
|
||||||
|
pub use camera::Camera;
|
||||||
|
pub use inputstatus::InputStatus;
|
||||||
|
pub use playeragent::PlayerAgent;
|
||||||
|
pub use playerstatus::PlayerStatus;
|
|
@ -0,0 +1,56 @@
|
||||||
|
use galactica_content::Content;
|
||||||
|
use galactica_galaxy::GxShipHandle;
|
||||||
|
use winit::event::{ElementState, MouseButton, MouseScrollDelta, TouchPhase, VirtualKeyCode};
|
||||||
|
|
||||||
|
use crate::{camera::Camera, inputstatus::InputStatus, PlayerStatus};
|
||||||
|
|
||||||
|
pub struct PlayerAgent {
|
||||||
|
/// Which ship this player is controlling
|
||||||
|
pub ship: Option<GxShipHandle>,
|
||||||
|
|
||||||
|
/// This player's camera
|
||||||
|
pub camera: Camera,
|
||||||
|
|
||||||
|
/// What buttons this player is pressing
|
||||||
|
pub input: InputStatus,
|
||||||
|
|
||||||
|
/// What the player currently has selected
|
||||||
|
pub selection: Option<()>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PlayerAgent {
|
||||||
|
pub fn new(ship: GxShipHandle) -> Self {
|
||||||
|
Self {
|
||||||
|
input: InputStatus::new(),
|
||||||
|
camera: Camera::new(),
|
||||||
|
ship: Some(ship),
|
||||||
|
selection: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_camera_aspect(&mut self, v: f32) {
|
||||||
|
self.camera.aspect = v
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn process_key(&mut self, state: &ElementState, key: &VirtualKeyCode) {
|
||||||
|
self.input.process_key(state, key)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn process_click(&mut self, state: &ElementState, key: &MouseButton) {
|
||||||
|
self.input.process_click(state, key)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn process_scroll(&mut self, delta: &MouseScrollDelta, phase: &TouchPhase) {
|
||||||
|
self.input.process_scroll(delta, phase)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn step(&mut self, ct: &Content, status: PlayerStatus) {
|
||||||
|
if self.input.v_scroll != 0.0 {
|
||||||
|
self.camera.zoom = (self.camera.zoom + self.input.v_scroll)
|
||||||
|
.clamp(ct.get_config().zoom_min, ct.get_config().zoom_max);
|
||||||
|
self.input.v_scroll = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.camera.pos = status.pos;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
use cgmath::Point2;
|
||||||
|
|
||||||
|
pub struct PlayerStatus {
|
||||||
|
pub pos: Point2<f32>,
|
||||||
|
}
|
|
@ -20,6 +20,7 @@ workspace = true
|
||||||
galactica-content = { workspace = true }
|
galactica-content = { workspace = true }
|
||||||
galactica-galaxy = { workspace = true }
|
galactica-galaxy = { workspace = true }
|
||||||
galactica-util = { workspace = true }
|
galactica-util = { workspace = true }
|
||||||
|
galactica-playeragent = { workspace = true }
|
||||||
|
|
||||||
rapier2d = { workspace = true }
|
rapier2d = { workspace = true }
|
||||||
nalgebra = { workspace = true }
|
nalgebra = { workspace = true }
|
||||||
|
|
|
@ -3,24 +3,64 @@
|
||||||
mod null;
|
mod null;
|
||||||
mod point;
|
mod point;
|
||||||
|
|
||||||
pub use null::*;
|
use null::*;
|
||||||
pub use point::Point;
|
use point::PointShipController;
|
||||||
|
|
||||||
use galactica_galaxy::GxShipHandle;
|
use galactica_galaxy::GxShipHandle;
|
||||||
use rapier2d::dynamics::{RigidBodyHandle, RigidBodySet};
|
use rapier2d::dynamics::{RigidBodyHandle, RigidBodySet};
|
||||||
use std::collections::HashMap;
|
use std::{collections::HashMap, fmt::Debug};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
objects::{ShipControls, SySimShip},
|
objects::{ShipControls, SySimShip},
|
||||||
StepResources,
|
StepResources,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Represents a ship controller
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum ShipController {
|
||||||
|
/// Null controller
|
||||||
|
Null(NullShipController),
|
||||||
|
|
||||||
|
/// Point controller
|
||||||
|
Point(PointShipController),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ShipController {
|
||||||
|
/// Make a new null controller
|
||||||
|
pub fn new_null() -> Self {
|
||||||
|
Self::Null(NullShipController::new())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Make a new point controller
|
||||||
|
pub fn new_point() -> Self {
|
||||||
|
Self::Point(PointShipController::new())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Compute new ship controls from world state
|
||||||
|
pub fn update_controls(
|
||||||
|
&mut self,
|
||||||
|
res: &StepResources,
|
||||||
|
rigid_bodies: &RigidBodySet,
|
||||||
|
ships: &HashMap<GxShipHandle, SySimShip>,
|
||||||
|
this_ship: RigidBodyHandle,
|
||||||
|
this_data: GxShipHandle,
|
||||||
|
) -> Option<ShipControls> {
|
||||||
|
match self {
|
||||||
|
Self::Null(n) => n.update_controls(res, rigid_bodies, ships, this_ship, this_data),
|
||||||
|
Self::Point(p) => p.update_controls(res, rigid_bodies, ships, this_ship, this_data),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Ship controller trait. Any struct that implements this
|
/// Ship controller trait. Any struct that implements this
|
||||||
/// may be used to control a ship.
|
/// may be used to control a ship.
|
||||||
pub trait ShipController {
|
pub trait ShipControllerStruct
|
||||||
|
where
|
||||||
|
Self: Debug + Clone,
|
||||||
|
{
|
||||||
/// Update a ship's controls based on system state.
|
/// Update a ship's controls based on system state.
|
||||||
/// This method does not return anything, it modifies
|
/// This method returns the ship's new control values,
|
||||||
/// the ship's controls in-place.
|
/// or None if no change is to be made.
|
||||||
fn update_controls(
|
fn update_controls(
|
||||||
&mut self,
|
&mut self,
|
||||||
res: &StepResources,
|
res: &StepResources,
|
||||||
|
@ -28,5 +68,5 @@ pub trait ShipController {
|
||||||
ships: &HashMap<GxShipHandle, SySimShip>,
|
ships: &HashMap<GxShipHandle, SySimShip>,
|
||||||
this_ship: RigidBodyHandle,
|
this_ship: RigidBodyHandle,
|
||||||
this_data: GxShipHandle,
|
this_data: GxShipHandle,
|
||||||
) -> ShipControls;
|
) -> Option<ShipControls>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ use galactica_galaxy::GxShipHandle;
|
||||||
use rapier2d::dynamics::{RigidBodyHandle, RigidBodySet};
|
use rapier2d::dynamics::{RigidBodyHandle, RigidBodySet};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use super::ShipController;
|
use super::ShipControllerStruct;
|
||||||
use crate::{
|
use crate::{
|
||||||
objects::{ShipControls, SySimShip},
|
objects::{ShipControls, SySimShip},
|
||||||
StepResources,
|
StepResources,
|
||||||
|
@ -10,16 +10,17 @@ use crate::{
|
||||||
|
|
||||||
/// The Null controller is assigned to objects that are static or not controlled by the computer.
|
/// The Null controller is assigned to objects that are static or not controlled by the computer.
|
||||||
/// Most notably, the player's ship has a Null controller.
|
/// Most notably, the player's ship has a Null controller.
|
||||||
pub struct Null {}
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct NullShipController {}
|
||||||
|
|
||||||
impl Null {
|
impl NullShipController {
|
||||||
/// Create a new ship controller
|
/// Create a new ship controller
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {}
|
Self {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ShipController for Null {
|
impl ShipControllerStruct for NullShipController {
|
||||||
fn update_controls(
|
fn update_controls(
|
||||||
&mut self,
|
&mut self,
|
||||||
_res: &StepResources,
|
_res: &StepResources,
|
||||||
|
@ -27,7 +28,7 @@ impl ShipController for Null {
|
||||||
_ships: &HashMap<GxShipHandle, SySimShip>,
|
_ships: &HashMap<GxShipHandle, SySimShip>,
|
||||||
_this_ship: RigidBodyHandle,
|
_this_ship: RigidBodyHandle,
|
||||||
_this_data: GxShipHandle,
|
_this_data: GxShipHandle,
|
||||||
) -> ShipControls {
|
) -> Option<ShipControls> {
|
||||||
ShipControls::new()
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ use galactica_galaxy::GxShipHandle;
|
||||||
use rapier2d::dynamics::{RigidBodyHandle, RigidBodySet};
|
use rapier2d::dynamics::{RigidBodyHandle, RigidBodySet};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use super::ShipController;
|
use super::ShipControllerStruct;
|
||||||
use crate::{
|
use crate::{
|
||||||
objects::{ShipControls, SySimShip},
|
objects::{ShipControls, SySimShip},
|
||||||
util, StepResources,
|
util, StepResources,
|
||||||
|
@ -12,16 +12,17 @@ use crate::{
|
||||||
|
|
||||||
/// "Point" ship controller.
|
/// "Point" ship controller.
|
||||||
/// Point and shoot towards the nearest enemy.
|
/// Point and shoot towards the nearest enemy.
|
||||||
pub struct Point {}
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct PointShipController {}
|
||||||
|
|
||||||
impl Point {
|
impl PointShipController {
|
||||||
/// Create a new ship controller
|
/// Create a new ship controller
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {}
|
Self {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ShipController for Point {
|
impl ShipControllerStruct for PointShipController {
|
||||||
fn update_controls(
|
fn update_controls(
|
||||||
&mut self,
|
&mut self,
|
||||||
res: &StepResources,
|
res: &StepResources,
|
||||||
|
@ -29,7 +30,7 @@ impl ShipController for Point {
|
||||||
ships: &HashMap<GxShipHandle, SySimShip>,
|
ships: &HashMap<GxShipHandle, SySimShip>,
|
||||||
this_ship: RigidBodyHandle,
|
this_ship: RigidBodyHandle,
|
||||||
this_data: GxShipHandle,
|
this_data: GxShipHandle,
|
||||||
) -> ShipControls {
|
) -> Option<ShipControls> {
|
||||||
let mut controls = ShipControls::new();
|
let mut controls = ShipControls::new();
|
||||||
|
|
||||||
let this_rigidbody = rigid_bodies.get(this_ship).unwrap();
|
let this_rigidbody = rigid_bodies.get(this_ship).unwrap();
|
||||||
|
@ -60,7 +61,7 @@ impl ShipController for Point {
|
||||||
// Find the closest target
|
// Find the closest target
|
||||||
let mut closest_enemy_position = match hostile_ships.next() {
|
let mut closest_enemy_position = match hostile_ships.next() {
|
||||||
Some(c) => util::rigidbody_position(c),
|
Some(c) => util::rigidbody_position(c),
|
||||||
None => return controls, // Do nothing if no targets are available
|
None => return Some(controls), // Do nothing if no targets are available
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut d = (my_position - closest_enemy_position).magnitude();
|
let mut d = (my_position - closest_enemy_position).magnitude();
|
||||||
|
@ -84,6 +85,6 @@ impl ShipController for Point {
|
||||||
}
|
}
|
||||||
|
|
||||||
controls.guns = true;
|
controls.guns = true;
|
||||||
return controls;
|
return Some(controls);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,3 +13,4 @@ mod wrapper;
|
||||||
pub use particlebuilder::*;
|
pub use particlebuilder::*;
|
||||||
pub use stepresources::*;
|
pub use stepresources::*;
|
||||||
pub use systemsim::SystemSim;
|
pub use systemsim::SystemSim;
|
||||||
|
pub use wrapper::Wrapper;
|
||||||
|
|
|
@ -6,7 +6,7 @@ use rapier2d::{dynamics::RigidBody, geometry::Collider};
|
||||||
|
|
||||||
use crate::{util, ParticleBuilder, StepResources};
|
use crate::{util, ParticleBuilder, StepResources};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub(super) struct ShipCollapseSequence {
|
pub(super) struct ShipCollapseSequence {
|
||||||
total_length: f32,
|
total_length: f32,
|
||||||
time_elapsed: f32,
|
time_elapsed: f32,
|
||||||
|
|
|
@ -3,7 +3,7 @@ use rand::Rng;
|
||||||
use rapier2d::{dynamics::RigidBodyHandle, geometry::ColliderHandle};
|
use rapier2d::{dynamics::RigidBodyHandle, geometry::ColliderHandle};
|
||||||
|
|
||||||
/// A single projectile in this sim
|
/// A single projectile in this sim
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct SySimProjectile {
|
pub struct SySimProjectile {
|
||||||
/// This projectile's game data
|
/// This projectile's game data
|
||||||
pub content: Projectile,
|
pub content: Projectile,
|
||||||
|
|
|
@ -41,7 +41,7 @@ impl ShipControls {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A ship instance in the physics system
|
/// A ship instance in the physics system
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct SySimShip {
|
pub struct SySimShip {
|
||||||
/// This ship's physics handle
|
/// This ship's physics handle
|
||||||
pub rigid_body: RigidBodyHandle,
|
pub rigid_body: RigidBodyHandle,
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
use crate::{objects::ShipControls, ParticleBuilder};
|
use crate::{wrapper::Wrapper, ParticleBuilder};
|
||||||
use galactica_content::Content;
|
use galactica_content::Content;
|
||||||
use galactica_galaxy::{Galaxy, GxShipHandle};
|
use galactica_galaxy::Galaxy;
|
||||||
use galactica_util::timing::Timing;
|
use galactica_util::timing::Timing;
|
||||||
|
|
||||||
/// External resources we need to compute time steps
|
/// External resources we need to compute time steps
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct StepResources<'a> {
|
pub struct StepResources<'a> {
|
||||||
/// Game content
|
/// Game content
|
||||||
pub ct: &'a Content,
|
pub ct: &'a Content,
|
||||||
|
@ -18,12 +17,9 @@ pub struct StepResources<'a> {
|
||||||
/// Particles to create
|
/// Particles to create
|
||||||
pub particles: &'a mut Vec<ParticleBuilder>,
|
pub particles: &'a mut Vec<ParticleBuilder>,
|
||||||
|
|
||||||
/// Player inputs
|
|
||||||
pub player_controls: ShipControls,
|
|
||||||
|
|
||||||
/// The ship that the player controls
|
|
||||||
pub player: GxShipHandle,
|
|
||||||
|
|
||||||
/// Record detailed frame timing breakdown
|
/// Record detailed frame timing breakdown
|
||||||
pub timing: &'a mut Timing,
|
pub timing: &'a mut Timing,
|
||||||
|
|
||||||
|
/// Physics computer
|
||||||
|
pub wrapper: &'a mut Wrapper,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,58 +1,63 @@
|
||||||
use cgmath::{Deg, EuclideanSpace, InnerSpace, Matrix2, Point2, Rad, Vector2, Zero};
|
use cgmath::{Deg, EuclideanSpace, InnerSpace, Matrix2, Point2, Rad, Vector2, Zero};
|
||||||
use crossbeam::channel::Receiver;
|
|
||||||
use galactica_content::{
|
use galactica_content::{
|
||||||
Content, GunPoint, OutfitHandle, ProjectileCollider, Relationship, SystemHandle,
|
Content, GunPoint, OutfitHandle, ProjectileCollider, Relationship, SystemHandle,
|
||||||
};
|
};
|
||||||
use galactica_galaxy::{ship::GxShip, Galaxy, GxShipHandle};
|
use galactica_galaxy::{
|
||||||
|
ship::{GxShip, ShipPersonality},
|
||||||
|
Galaxy, GxShipHandle,
|
||||||
|
};
|
||||||
|
use galactica_playeragent::PlayerAgent;
|
||||||
use nalgebra::{point, vector};
|
use nalgebra::{point, vector};
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
use rapier2d::{
|
use rapier2d::{
|
||||||
dynamics::{RigidBody, RigidBodyBuilder, RigidBodyHandle},
|
dynamics::{RigidBody, RigidBodyBuilder, RigidBodyHandle, RigidBodySet},
|
||||||
geometry::{ColliderBuilder, ColliderHandle, CollisionEvent},
|
geometry::{ColliderBuilder, ColliderHandle, ColliderSet},
|
||||||
pipeline::{ActiveEvents, ChannelEventCollector},
|
pipeline::ActiveEvents,
|
||||||
};
|
};
|
||||||
use std::{collections::HashMap, f32::consts::PI};
|
use std::{collections::HashMap, f32::consts::PI};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
controller::{self, ShipController},
|
controller::ShipController,
|
||||||
objects,
|
|
||||||
objects::{SySimProjectile, SySimShip},
|
objects::{SySimProjectile, SySimShip},
|
||||||
util,
|
util, ParticleBuilder, StepResources,
|
||||||
wrapper::Wrapper,
|
|
||||||
ParticleBuilder, StepResources,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Manages the physics state of one system
|
/// Manages the physics state of one system
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct SystemSim {
|
pub struct SystemSim {
|
||||||
/// The system this sim is attached to
|
/// The system this sim is attached to
|
||||||
_system: SystemHandle,
|
_system: SystemHandle,
|
||||||
|
|
||||||
wrapper: Wrapper,
|
rigid_body_set: RigidBodySet,
|
||||||
projectiles: HashMap<ColliderHandle, objects::SySimProjectile>,
|
collider_set: ColliderSet,
|
||||||
ships: HashMap<GxShipHandle, objects::SySimShip>,
|
|
||||||
ship_behaviors: HashMap<GxShipHandle, Box<dyn ShipController>>,
|
|
||||||
collider_ship_table: HashMap<ColliderHandle, GxShipHandle>,
|
|
||||||
|
|
||||||
collision_handler: ChannelEventCollector,
|
projectiles: HashMap<ColliderHandle, SySimProjectile>,
|
||||||
collision_queue: Receiver<CollisionEvent>,
|
ships: HashMap<GxShipHandle, SySimShip>,
|
||||||
|
|
||||||
|
// TODO: these don't need to be cloned each frame
|
||||||
|
ship_behaviors: HashMap<GxShipHandle, ShipController>,
|
||||||
|
collider_ship_table: HashMap<ColliderHandle, GxShipHandle>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Private methods
|
// Private methods
|
||||||
impl<'a> SystemSim {
|
impl<'a> SystemSim {
|
||||||
fn remove_projectile(&mut self, c: ColliderHandle) -> Option<(RigidBody, SySimProjectile)> {
|
fn remove_projectile(
|
||||||
|
&mut self,
|
||||||
|
res: &mut StepResources,
|
||||||
|
c: ColliderHandle,
|
||||||
|
) -> Option<(RigidBody, SySimProjectile)> {
|
||||||
let p = match self.projectiles.remove(&c) {
|
let p = match self.projectiles.remove(&c) {
|
||||||
Some(p) => p,
|
Some(p) => p,
|
||||||
None => return None,
|
None => return None,
|
||||||
};
|
};
|
||||||
let r = self
|
let r = self
|
||||||
.wrapper
|
|
||||||
.rigid_body_set
|
.rigid_body_set
|
||||||
.remove(
|
.remove(
|
||||||
p.rigid_body,
|
p.rigid_body,
|
||||||
&mut self.wrapper.im,
|
&mut res.wrapper.im,
|
||||||
&mut self.wrapper.collider_set,
|
&mut self.collider_set,
|
||||||
&mut self.wrapper.ij,
|
&mut res.wrapper.ij,
|
||||||
&mut self.wrapper.mj,
|
&mut res.wrapper.mj,
|
||||||
true,
|
true,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -60,7 +65,7 @@ impl<'a> SystemSim {
|
||||||
return Some((r, p));
|
return Some((r, p));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_ship(&mut self, s: ColliderHandle) {
|
fn remove_ship(&mut self, res: &mut StepResources, s: ColliderHandle) {
|
||||||
let s = match self.collider_ship_table.get(&s) {
|
let s = match self.collider_ship_table.get(&s) {
|
||||||
None => return,
|
None => return,
|
||||||
Some(s) => match self.ships.get(s) {
|
Some(s) => match self.ships.get(s) {
|
||||||
|
@ -69,12 +74,12 @@ impl<'a> SystemSim {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
self.wrapper.rigid_body_set.remove(
|
self.rigid_body_set.remove(
|
||||||
s.rigid_body,
|
s.rigid_body,
|
||||||
&mut self.wrapper.im,
|
&mut res.wrapper.im,
|
||||||
&mut self.wrapper.collider_set,
|
&mut self.collider_set,
|
||||||
&mut self.wrapper.ij,
|
&mut res.wrapper.ij,
|
||||||
&mut self.wrapper.mj,
|
&mut res.wrapper.mj,
|
||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
let h = self.collider_ship_table.remove(&s.collider).unwrap();
|
let h = self.collider_ship_table.remove(&s.collider).unwrap();
|
||||||
|
@ -112,28 +117,16 @@ impl<'a> SystemSim {
|
||||||
};
|
};
|
||||||
|
|
||||||
if destory_projectile {
|
if destory_projectile {
|
||||||
let pr = self
|
let pr = self.rigid_body_set.get(projectile.rigid_body).unwrap();
|
||||||
.wrapper
|
|
||||||
.rigid_body_set
|
|
||||||
.get(projectile.rigid_body)
|
|
||||||
.unwrap();
|
|
||||||
let v = util::rigidbody_velocity(pr).normalize() * projectile.content.force;
|
let v = util::rigidbody_velocity(pr).normalize() * projectile.content.force;
|
||||||
let pos = util::rigidbody_position(pr);
|
let pos = util::rigidbody_position(pr);
|
||||||
let _ = pr;
|
let _ = pr;
|
||||||
|
|
||||||
let r = self
|
let r = self.rigid_body_set.get_mut(ship.rigid_body).unwrap();
|
||||||
.wrapper
|
|
||||||
.rigid_body_set
|
|
||||||
.get_mut(ship.rigid_body)
|
|
||||||
.unwrap();
|
|
||||||
r.apply_impulse_at_point(vector![v.x, v.y], point![pos.x, pos.y], true);
|
r.apply_impulse_at_point(vector![v.x, v.y], point![pos.x, pos.y], true);
|
||||||
|
|
||||||
// Borrow again, we can only have one at a time
|
// Borrow again, we can only have one at a time
|
||||||
let pr = self
|
let pr = self.rigid_body_set.get(projectile.rigid_body).unwrap();
|
||||||
.wrapper
|
|
||||||
.rigid_body_set
|
|
||||||
.get(projectile.rigid_body)
|
|
||||||
.unwrap();
|
|
||||||
let pos = util::rigidbody_position(pr);
|
let pos = util::rigidbody_position(pr);
|
||||||
let angle = util::rigidbody_rotation(pr).angle(Vector2 { x: 1.0, y: 0.0 });
|
let angle = util::rigidbody_rotation(pr).angle(Vector2 { x: 1.0, y: 0.0 });
|
||||||
|
|
||||||
|
@ -160,7 +153,7 @@ impl<'a> SystemSim {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
self.remove_projectile(projectile.collider);
|
self.remove_projectile(res, projectile.collider);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -169,18 +162,14 @@ impl<'a> SystemSim {
|
||||||
impl SystemSim {
|
impl SystemSim {
|
||||||
/// Create a new physics system
|
/// Create a new physics system
|
||||||
pub fn new(ct: &Content, gx: &Galaxy, system: SystemHandle) -> Self {
|
pub fn new(ct: &Content, gx: &Galaxy, system: SystemHandle) -> Self {
|
||||||
let (collision_send, collision_queue) = crossbeam::channel::unbounded();
|
|
||||||
let (contact_force_send, _) = crossbeam::channel::unbounded();
|
|
||||||
|
|
||||||
let mut w = Self {
|
let mut w = Self {
|
||||||
_system: system,
|
_system: system,
|
||||||
wrapper: Wrapper::new(),
|
rigid_body_set: RigidBodySet::new(),
|
||||||
|
collider_set: ColliderSet::new(),
|
||||||
projectiles: HashMap::new(),
|
projectiles: HashMap::new(),
|
||||||
ships: HashMap::new(),
|
ships: HashMap::new(),
|
||||||
ship_behaviors: HashMap::new(),
|
ship_behaviors: HashMap::new(),
|
||||||
collider_ship_table: HashMap::new(),
|
collider_ship_table: HashMap::new(),
|
||||||
collision_handler: ChannelEventCollector::new(collision_send, contact_force_send),
|
|
||||||
collision_queue,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: guarantee not touching
|
// TODO: guarantee not touching
|
||||||
|
@ -220,22 +209,36 @@ impl SystemSim {
|
||||||
.translation(vector![position.x, position.y])
|
.translation(vector![position.x, position.y])
|
||||||
.can_sleep(false);
|
.can_sleep(false);
|
||||||
|
|
||||||
let r = self.wrapper.rigid_body_set.insert(rb.build());
|
let r = self.rigid_body_set.insert(rb.build());
|
||||||
let c = self.wrapper.collider_set.insert_with_parent(
|
let c = self
|
||||||
cl.build(),
|
.collider_set
|
||||||
r,
|
.insert_with_parent(cl.build(), r, &mut self.rigid_body_set);
|
||||||
&mut self.wrapper.rigid_body_set,
|
|
||||||
);
|
|
||||||
|
|
||||||
self.collider_ship_table.insert(c, ship.get_handle());
|
self.collider_ship_table.insert(c, ship.get_handle());
|
||||||
self.ship_behaviors
|
|
||||||
.insert(ship.get_handle(), Box::new(controller::Point::new()));
|
self.ship_behaviors.insert(
|
||||||
|
ship.get_handle(),
|
||||||
|
match ship.get_personality() {
|
||||||
|
ShipPersonality::Dummy | ShipPersonality::Player => ShipController::new_null(),
|
||||||
|
ShipPersonality::Point => ShipController::new_point(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
self.ships.insert(
|
self.ships.insert(
|
||||||
ship.get_handle(),
|
ship.get_handle(),
|
||||||
objects::SySimShip::new(ct, ship.get_handle(), ship.get_faction(), r, c),
|
SySimShip::new(ct, ship.get_handle(), ship.get_faction(), r, c),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Update a player ship's controls
|
||||||
|
pub fn update_player_controls(&mut self, player: &PlayerAgent) {
|
||||||
|
let ship_object = self.ships.get_mut(&player.ship.unwrap()).unwrap();
|
||||||
|
ship_object.controls.guns = player.input.key_guns;
|
||||||
|
ship_object.controls.left = player.input.key_left;
|
||||||
|
ship_object.controls.right = player.input.key_right;
|
||||||
|
ship_object.controls.thrust = player.input.key_thrust;
|
||||||
|
}
|
||||||
|
|
||||||
/// Run ship updates:
|
/// Run ship updates:
|
||||||
/// - updates ship controls (runs behaviors)
|
/// - updates ship controls (runs behaviors)
|
||||||
/// - applies ship controls
|
/// - applies ship controls
|
||||||
|
@ -261,34 +264,32 @@ impl SystemSim {
|
||||||
let ship_object = self.ships.get_mut(handle).unwrap();
|
let ship_object = self.ships.get_mut(handle).unwrap();
|
||||||
ship_object.step(
|
ship_object.step(
|
||||||
res,
|
res,
|
||||||
&mut self.wrapper.rigid_body_set[ship_object.rigid_body],
|
&mut self.rigid_body_set[ship_object.rigid_body],
|
||||||
&mut self.wrapper.collider_set[ship_object.collider],
|
&mut self.collider_set[ship_object.collider],
|
||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compute new controls
|
// Compute new controls
|
||||||
let controls;
|
let controls;
|
||||||
if ship_object.data_handle == res.player {
|
let b = self.ship_behaviors.get_mut(handle).unwrap();
|
||||||
controls = res.player_controls.clone();
|
controls = b.update_controls(
|
||||||
} else {
|
&res,
|
||||||
let b = self.ship_behaviors.get_mut(handle).unwrap();
|
&self.rigid_body_set,
|
||||||
controls = b.update_controls(
|
&self.ships,
|
||||||
&res,
|
ship_object.rigid_body,
|
||||||
&self.wrapper.rigid_body_set,
|
*handle,
|
||||||
&self.ships,
|
);
|
||||||
ship_object.rigid_body,
|
|
||||||
*handle,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now re-borrow mutably to apply changes
|
// Now re-borrow mutably to apply changes
|
||||||
let ship_object = self.ships.get_mut(handle).unwrap();
|
let ship_object = self.ships.get_mut(handle).unwrap();
|
||||||
ship_object.controls = controls;
|
if let Some(controls) = controls {
|
||||||
|
ship_object.controls = controls;
|
||||||
|
}
|
||||||
ship_object.step(
|
ship_object.step(
|
||||||
res,
|
res,
|
||||||
&mut self.wrapper.rigid_body_set[ship_object.rigid_body],
|
&mut self.rigid_body_set[ship_object.rigid_body],
|
||||||
&mut self.wrapper.collider_set[ship_object.collider],
|
&mut self.collider_set[ship_object.collider],
|
||||||
);
|
);
|
||||||
|
|
||||||
// If we're firing, try to fire each gun
|
// If we're firing, try to fire each gun
|
||||||
|
@ -318,7 +319,7 @@ impl SystemSim {
|
||||||
|
|
||||||
// Remove ships that don't exist
|
// Remove ships that don't exist
|
||||||
for c in to_remove {
|
for c in to_remove {
|
||||||
self.remove_ship(c);
|
self.remove_ship(res, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create projectiles
|
// Create projectiles
|
||||||
|
@ -364,11 +365,11 @@ impl SystemSim {
|
||||||
.build(),
|
.build(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let rigid_body = self.wrapper.rigid_body_set.insert(rigid_body);
|
let rigid_body = self.rigid_body_set.insert(rigid_body);
|
||||||
let collider = self.wrapper.collider_set.insert_with_parent(
|
let collider = self.collider_set.insert_with_parent(
|
||||||
collider,
|
collider,
|
||||||
rigid_body,
|
rigid_body,
|
||||||
&mut self.wrapper.rigid_body_set,
|
&mut self.rigid_body_set,
|
||||||
);
|
);
|
||||||
|
|
||||||
self.projectiles.insert(
|
self.projectiles.insert(
|
||||||
|
@ -392,10 +393,11 @@ impl SystemSim {
|
||||||
res.timing.start_physics_sim();
|
res.timing.start_physics_sim();
|
||||||
|
|
||||||
// Update physics
|
// Update physics
|
||||||
self.wrapper.step(res.t, &self.collision_handler);
|
res.wrapper
|
||||||
|
.step(res.t, &mut self.rigid_body_set, &mut self.collider_set);
|
||||||
|
|
||||||
// Handle collision events
|
// Handle collision events
|
||||||
while let Ok(event) = &self.collision_queue.try_recv() {
|
while let Ok(event) = &res.wrapper.collision_queue.try_recv() {
|
||||||
if event.started() {
|
if event.started() {
|
||||||
let a = event.collider1();
|
let a = event.collider1();
|
||||||
let b = event.collider2();
|
let b = event.collider2();
|
||||||
|
@ -432,7 +434,7 @@ impl SystemSim {
|
||||||
|
|
||||||
let mut rng = rand::thread_rng();
|
let mut rng = rand::thread_rng();
|
||||||
for c in to_remove {
|
for c in to_remove {
|
||||||
let (pr, p) = self.remove_projectile(c).unwrap();
|
let (pr, p) = self.remove_projectile(&mut res, c).unwrap();
|
||||||
|
|
||||||
match &p.content.expire_effect {
|
match &p.content.expire_effect {
|
||||||
None => {}
|
None => {}
|
||||||
|
@ -475,19 +477,19 @@ impl SystemSim {
|
||||||
|
|
||||||
/// Get a rigid body from a handle
|
/// Get a rigid body from a handle
|
||||||
pub fn get_rigid_body(&self, r: RigidBodyHandle) -> Option<&RigidBody> {
|
pub fn get_rigid_body(&self, r: RigidBodyHandle) -> Option<&RigidBody> {
|
||||||
self.wrapper.rigid_body_set.get(r)
|
self.rigid_body_set.get(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a rigid body from a handle
|
/// Get a rigid body from a handle
|
||||||
pub fn get_rigid_body_mut(&mut self, r: RigidBodyHandle) -> Option<&mut RigidBody> {
|
pub fn get_rigid_body_mut(&mut self, r: RigidBodyHandle) -> Option<&mut RigidBody> {
|
||||||
self.wrapper.rigid_body_set.get_mut(r)
|
self.rigid_body_set.get_mut(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Iterate over all ships in this physics system
|
/// Iterate over all ships in this physics system
|
||||||
pub fn iter_ship_body(&self) -> impl Iterator<Item = (&objects::SySimShip, &RigidBody)> + '_ {
|
pub fn iter_ship_body(&self) -> impl Iterator<Item = (&SySimShip, &RigidBody)> + '_ {
|
||||||
self.ships
|
self.ships
|
||||||
.values()
|
.values()
|
||||||
.map(|x| (x, self.wrapper.rigid_body_set.get(x.rigid_body).unwrap()))
|
.map(|x| (x, self.rigid_body_set.get(x.rigid_body).unwrap()))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Iterate over all ships in this physics system
|
/// Iterate over all ships in this physics system
|
||||||
|
|
|
@ -1,33 +1,39 @@
|
||||||
|
use crossbeam::channel::Receiver;
|
||||||
use rapier2d::{
|
use rapier2d::{
|
||||||
dynamics::{
|
dynamics::{
|
||||||
CCDSolver, ImpulseJointSet, IntegrationParameters, IslandManager, MultibodyJointSet,
|
CCDSolver, ImpulseJointSet, IntegrationParameters, IslandManager, MultibodyJointSet,
|
||||||
RigidBodySet,
|
RigidBodySet,
|
||||||
},
|
},
|
||||||
geometry::{BroadPhase, ColliderSet, NarrowPhase},
|
geometry::{BroadPhase, ColliderSet, CollisionEvent, NarrowPhase},
|
||||||
na::vector,
|
na::vector,
|
||||||
pipeline::{EventHandler, PhysicsPipeline},
|
pipeline::{ChannelEventCollector, PhysicsPipeline},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub(crate) struct Wrapper {
|
/// Wraps Rapier2d physics parameters
|
||||||
pub rigid_body_set: RigidBodySet,
|
pub struct Wrapper {
|
||||||
pub collider_set: ColliderSet,
|
pub(crate) ip: IntegrationParameters,
|
||||||
|
pub(crate) pp: PhysicsPipeline,
|
||||||
|
pub(crate) im: IslandManager,
|
||||||
|
pub(crate) bp: BroadPhase,
|
||||||
|
pub(crate) np: NarrowPhase,
|
||||||
|
pub(crate) ij: ImpulseJointSet,
|
||||||
|
pub(crate) mj: MultibodyJointSet,
|
||||||
|
pub(crate) ccd: CCDSolver,
|
||||||
|
|
||||||
pub ip: IntegrationParameters,
|
collision_handler: ChannelEventCollector,
|
||||||
pub pp: PhysicsPipeline,
|
|
||||||
pub im: IslandManager,
|
/// Collision event queue
|
||||||
pub bp: BroadPhase,
|
/// this should be emptied after every frame.
|
||||||
pub np: NarrowPhase,
|
pub collision_queue: Receiver<CollisionEvent>,
|
||||||
pub ij: ImpulseJointSet,
|
|
||||||
pub mj: MultibodyJointSet,
|
|
||||||
pub ccd: CCDSolver,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Wrapper {
|
impl Wrapper {
|
||||||
|
/// Make a new physics wrapper
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
let (collision_send, collision_queue) = crossbeam::channel::unbounded();
|
||||||
rigid_body_set: RigidBodySet::new(),
|
let (contact_force_send, _) = crossbeam::channel::unbounded();
|
||||||
collider_set: ColliderSet::new(),
|
|
||||||
|
|
||||||
|
Self {
|
||||||
ip: IntegrationParameters::default(),
|
ip: IntegrationParameters::default(),
|
||||||
pp: PhysicsPipeline::new(),
|
pp: PhysicsPipeline::new(),
|
||||||
im: IslandManager::new(),
|
im: IslandManager::new(),
|
||||||
|
@ -36,10 +42,18 @@ impl Wrapper {
|
||||||
ij: ImpulseJointSet::new(),
|
ij: ImpulseJointSet::new(),
|
||||||
mj: MultibodyJointSet::new(),
|
mj: MultibodyJointSet::new(),
|
||||||
ccd: CCDSolver::new(),
|
ccd: CCDSolver::new(),
|
||||||
|
collision_queue,
|
||||||
|
collision_handler: ChannelEventCollector::new(collision_send, contact_force_send),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn step(&mut self, t: f32, handler: &dyn EventHandler) {
|
/// Step physics sim by `t` seconds
|
||||||
|
pub fn step(
|
||||||
|
&mut self,
|
||||||
|
t: f32,
|
||||||
|
rigid_body_set: &mut RigidBodySet,
|
||||||
|
collider_set: &mut ColliderSet,
|
||||||
|
) {
|
||||||
self.ip.dt = t;
|
self.ip.dt = t;
|
||||||
self.pp.step(
|
self.pp.step(
|
||||||
&vector![0.0, 0.0],
|
&vector![0.0, 0.0],
|
||||||
|
@ -47,14 +61,14 @@ impl Wrapper {
|
||||||
&mut self.im,
|
&mut self.im,
|
||||||
&mut self.bp,
|
&mut self.bp,
|
||||||
&mut self.np,
|
&mut self.np,
|
||||||
&mut self.rigid_body_set,
|
rigid_body_set,
|
||||||
&mut self.collider_set,
|
collider_set,
|
||||||
&mut self.ij,
|
&mut self.ij,
|
||||||
&mut self.mj,
|
&mut self.mj,
|
||||||
&mut self.ccd,
|
&mut self.ccd,
|
||||||
None,
|
None,
|
||||||
&(),
|
&(),
|
||||||
handler,
|
&mut self.collision_handler,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue