Added shields & indicator

master
Mark 2024-01-08 20:43:58 -08:00
parent 861c1ce8e6
commit 10682db347
Signed by: Mark
GPG Key ID: C6D63995FE72FD80
9 changed files with 120 additions and 16 deletions

View File

@ -5,3 +5,12 @@ space.engine = 20
engine.thrust = 100
engine.flare_sprite = "flare::ion"
steering.power = 20
[outfit."shield generator"]
space.outfit = 5
shield.generation = 10
shield.strength = 500
shield.delay = 2.0

View File

@ -2,7 +2,7 @@ use std::collections::HashMap;
use anyhow::{bail, Result};
use crate::{handle::SpriteHandle, Content, ContentBuildContext, OutfitSpace};
use crate::{handle::SpriteHandle, Content, ContentBuildContext, OutfitHandle, OutfitSpace};
pub(crate) mod syntax {
use crate::part::outfitspace;
@ -15,6 +15,15 @@ pub(crate) mod syntax {
pub engine: Option<Engine>,
pub steering: Option<Steering>,
pub space: outfitspace::syntax::OutfitSpace,
pub shield: Option<Shield>,
}
#[derive(Debug, Deserialize)]
pub struct Shield {
pub strength: Option<f32>,
pub generation: Option<f32>,
pub delay: Option<f32>,
// more stats: permiability, shield armor, ramp, etc
}
#[derive(Debug, Deserialize)]
@ -32,6 +41,12 @@ pub(crate) mod syntax {
/// Represents an outfit that may be attached to a ship.
#[derive(Debug, Clone)]
pub struct Outfit {
/// How much space this outfit requires
pub space: OutfitSpace,
/// This outfit's handle
pub handle: OutfitHandle,
/// The name of this outfit
pub name: String,
@ -46,8 +61,14 @@ pub struct Outfit {
/// engine points.
pub engine_flare_sprite: Option<SpriteHandle>,
/// How much space this outfit requires
pub space: OutfitSpace,
/// Shield hit points
pub shield_strength: f32,
/// Shield regeneration rate, per second
pub shield_generation: f32,
/// Wait this many seconds after taking damage before regenerating shields
pub shield_delay: f32,
}
impl crate::Build for Outfit {
@ -59,12 +80,20 @@ impl crate::Build for Outfit {
content: &mut Content,
) -> Result<()> {
for (outfit_name, outfit) in outfits {
let handle = OutfitHandle {
index: content.outfits.len(),
};
let mut o = Self {
handle,
name: outfit_name.clone(),
engine_thrust: 0.0,
steer_power: 0.0,
engine_flare_sprite: None,
space: OutfitSpace::from(outfit.space),
shield_delay: 0.0,
shield_generation: 0.0,
shield_strength: 0.0,
};
// Engine stats
@ -86,6 +115,13 @@ impl crate::Build for Outfit {
o.steer_power = steer.power;
}
// Shield stats
if let Some(shield) = outfit.shield {
o.shield_delay = shield.delay.unwrap_or(0.0);
o.shield_generation = shield.generation.unwrap_or(0.0);
o.shield_strength = shield.strength.unwrap_or(0.0);
}
content.outfits.push(o);
}

View File

@ -38,6 +38,7 @@ impl Game {
let mut o1 = object::OutfitSet::new(ss);
o1.add(&ct, content::OutfitHandle { index: 0 });
o1.add(&ct, content::OutfitHandle { index: 1 });
o1.add_gun(&ct, content::GunHandle { index: 0 });
o1.add_gun(&ct, content::GunHandle { index: 0 });
o1.add_gun(&ct, content::GunHandle { index: 0 });
@ -64,7 +65,7 @@ impl Game {
let mut o1 = object::OutfitSet::new(ss);
o1.add(&ct, content::OutfitHandle { index: 0 });
//o1.add_gun(&ct, content::GunHandle { index: 0 });
o1.add_gun(&ct, content::GunHandle { index: 0 });
let s = object::Ship::new(
&ct,

View File

@ -1,4 +1,4 @@
use content::{EnginePoint, SpriteHandle};
use content::{EnginePoint, OutfitHandle, SpriteHandle};
use galactica_content as content;
/// Represents a gun attached to a specific ship at a certain gunpoint.
@ -33,6 +33,10 @@ pub struct OutfitStatSum {
pub engine_thrust: f32,
pub steer_power: f32,
pub engine_flare_sprites: Vec<content::SpriteHandle>,
pub shield_strength: f32,
// Delay, generation
pub shield_generators: Vec<(OutfitHandle, f32, f32)>,
}
impl OutfitStatSum {
@ -41,6 +45,8 @@ impl OutfitStatSum {
engine_thrust: 0.0,
steer_power: 0.0,
engine_flare_sprites: Vec::new(),
shield_strength: 0.0,
shield_generators: Vec::new(),
}
}
@ -50,6 +56,9 @@ impl OutfitStatSum {
self.engine_flare_sprites.push(t);
};
self.steer_power += o.steer_power;
self.shield_strength += o.shield_strength;
self.shield_generators
.push((o.handle, o.shield_delay, o.shield_generation));
}
pub fn remove(&mut self, o: &content::Outfit) {
@ -63,6 +72,16 @@ impl OutfitStatSum {
);
}
self.steer_power -= o.steer_power;
self.shield_strength -= o.shield_strength;
{
// Assume such an index exists
let index = self
.shield_generators
.iter()
.position(|(h, _, _)| *h == o.handle)
.unwrap();
self.shield_generators.remove(index);
}
}
}

View File

@ -1,4 +1,5 @@
use rand::Rng;
use std::time::Instant;
use crate::{OutfitSet, Projectile};
use galactica_content as content;
@ -8,10 +9,12 @@ pub struct Ship {
pub handle: content::ShipHandle,
pub faction: content::FactionHandle,
pub outfits: OutfitSet,
pub last_hit: Instant,
// TODO: unified ship stats struct, like space
// TODO: unified outfit stats struct: check
pub hull: f32,
pub shields: f32,
}
impl Ship {
@ -22,11 +25,14 @@ impl Ship {
outfits: OutfitSet,
) -> Self {
let s = ct.get_ship(handle);
let shields = outfits.stat_sum().shield_strength;
Ship {
handle: handle,
faction,
outfits,
hull: s.hull,
shields,
last_hit: Instant::now(),
}
}
@ -41,10 +47,19 @@ impl Ship {
let r = f.relationships.get(&p.faction).unwrap();
match r {
content::Relationship::Hostile => {
let mut d = p.content.damage;
if self.is_dead() {
return true;
}
self.hull -= p.content.damage;
if self.shields >= d {
self.shields -= d
} else {
d -= self.shields;
self.shields = 0.0;
self.hull -= d;
}
self.last_hit = Instant::now();
return true;
}
_ => return false,
@ -79,4 +94,19 @@ impl Ship {
})
.collect()
}
pub fn step(&mut self, t: f32) {
let time_since = self.last_hit.elapsed().as_secs_f32();
if self.shields != self.outfits.stat_sum().shield_strength {
for (_, d, g) in &self.outfits.stat_sum().shield_generators {
if time_since >= *d {
self.shields += g * t;
if self.shields > self.outfits.stat_sum().shield_strength {
self.shields = self.outfits.stat_sum().shield_strength;
break;
}
}
}
}
}
}

View File

@ -65,12 +65,12 @@ fn fragment_main(in: VertexOutput) -> @location(0) vec4<f32> {
global_data.window_scale.x
) - in.center;
let bar_width = in.stroke; // Width of filled bar
let bar_radius = in.diameter / 2.0 - bar_width / 2.0; // Middle radius of the bar
let angle = in.angle - floor(in.angle / 6.283) * 6.28318; // Sanely handle large angles (fmod(angle, 2pi))
let zero_vector = vec2(0.0, 1.0); // Draw bar clockwise from this vector
let frag_radius = distance(vec2(0.0, 0.0), p); // Radius of this fragment
let feather = 2.0; // Size of feather, in logical pixels
let bar_width = in.stroke; // Width of filled bar
let bar_radius = in.diameter / 2.0 - bar_width / 2.0; // Middle radius of the bar
let angle = clamp(0.001, 6.28318 + 0.001, in.angle); // Sanely handle extreme angles
let zero_vector = vec2(0.0, 1.0); // Draw bar clockwise from this vector
let frag_radius = distance(vec2(0.0, 0.0), p); // Radius of this fragment
let feather = 2.0; // Size of feather, in logical pixels
// Clockwise angle between zero_vector and fragment location
let frag_angle = atan2(

View File

@ -1,5 +1,7 @@
//! GPUState routines for drawing HUD elements
use std::f32::consts::TAU;
use cgmath::{Deg, InnerSpace, Point2, Rad, Vector2};
use galactica_world::util;
@ -264,6 +266,12 @@ impl GPUState {
panic!("UI limit exceeded!")
}
let (s, _) = state.world.get_ship_body(*state.player).unwrap();
let max_shields = s.ship.outfits.stat_sum().shield_strength;
let current_shields = s.ship.shields;
let current_hull = s.ship.hull;
let max_hull = state.content.get_ship(s.ship.handle).hull;
self.queue.write_buffer(
&self.vertex_buffers.ui.instances,
UiInstance::SIZE * self.vertex_buffers.ui_counter,
@ -286,7 +294,6 @@ impl GPUState {
panic!("Radialbar limit exceeded!")
}
// TODO: counters for each buffer, remove arrays
self.queue.write_buffer(
&self.vertex_buffers.radialbar.instances,
RadialBarInstance::SIZE * self.vertex_buffers.radialbar_counter,
@ -296,7 +303,7 @@ impl GPUState {
diameter: 182.0,
stroke: 5.0,
color: [0.3, 0.6, 0.8, 1.0],
angle: -state.current_time / 2.0,
angle: (current_shields / max_shields) * TAU,
}]),
);
self.vertex_buffers.radialbar_counter += 1;
@ -310,7 +317,7 @@ impl GPUState {
diameter: 166.0,
stroke: 5.0,
color: [0.8, 0.7, 0.5, 1.0],
angle: state.current_time / 5.0,
angle: (current_hull / max_hull) * TAU,
}]),
);
self.vertex_buffers.radialbar_counter += 1;

View File

@ -85,7 +85,7 @@ impl GPUState {
self.vertex_buffers.object_counter += 1;
// Draw engine flares if necessary
if s.controls.thrust {
if s.controls.thrust && !s.ship.is_dead() {
for f in s.ship.outfits.iter_enginepoints() {
let flare = match s.ship.outfits.get_flare_sprite() {
None => continue,

View File

@ -216,6 +216,8 @@ impl ShipWorldObject {
.step(&self.ship, ct, particles, rigid_body, collider, t);
}
self.ship.step(t);
let ship_content = ct.get_ship(self.ship.handle);
let ship_pos = util::rigidbody_position(&rigid_body);
let ship_rot = util::rigidbody_rotation(rigid_body);