Added basic radar
parent
8fbbf7f110
commit
fa8a0f5761
|
@ -209,6 +209,12 @@ impl Content {
|
|||
}
|
||||
}
|
||||
|
||||
/// Get a texture from a handle
|
||||
pub fn get_texture_handle(&self, name: &str) -> TextureHandle {
|
||||
return *self.texture_index.get(name).unwrap();
|
||||
// TODO: handle errors
|
||||
}
|
||||
|
||||
/// Get a texture from a handle
|
||||
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.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use cgmath::Point2;
|
||||
use cgmath::{Deg, InnerSpace, Point2};
|
||||
use galactica_content::FactionHandle;
|
||||
use std::time::Instant;
|
||||
use winit::event::{ElementState, MouseButton, MouseScrollDelta, TouchPhase, VirtualKeyCode};
|
||||
|
@ -9,10 +9,61 @@ use crate::{
|
|||
content::Content,
|
||||
inputstatus::InputStatus,
|
||||
physics::{util, Physics, ShipHandle},
|
||||
render::Sprite,
|
||||
render::{AnchoredUiPosition, ObjectSprite, UiSprite},
|
||||
shipbehavior::{self, ShipBehavior},
|
||||
};
|
||||
|
||||
struct Ui {}
|
||||
|
||||
impl Ui {
|
||||
fn new() -> Self {
|
||||
Self {}
|
||||
}
|
||||
|
||||
fn build_radar(&self, player: &ShipHandle, physics: &Physics, ct: &Content) -> Vec<UiSprite> {
|
||||
let mut out = Vec::new();
|
||||
|
||||
let radar_range = 2000.0;
|
||||
let radar_size = 300.0;
|
||||
|
||||
out.push(UiSprite {
|
||||
texture: ct.get_texture_handle("ui::radar"),
|
||||
pos: AnchoredUiPosition::NorthWest(Point2 { x: 10.0, y: -10.0 }),
|
||||
dimensions: Point2 {
|
||||
x: radar_size,
|
||||
y: radar_size,
|
||||
},
|
||||
angle: Deg(0.0),
|
||||
});
|
||||
|
||||
let (_, pr) = physics.get_ship_body(player).unwrap();
|
||||
let pr = util::rigidbody_position(pr);
|
||||
for (s, r) in physics.iter_ship_body() {
|
||||
if s.physics_handle == *player {
|
||||
continue;
|
||||
}
|
||||
let r = util::rigidbody_position(r);
|
||||
let d = r - pr;
|
||||
let m = d.magnitude() / radar_range;
|
||||
if m < 0.8 {
|
||||
out.push(UiSprite {
|
||||
texture: ct.get_texture_handle("ui::blip"),
|
||||
pos: AnchoredUiPosition::NorthWest(
|
||||
Point2 {
|
||||
x: radar_size / 2.0 + 10.0,
|
||||
y: radar_size / -2.0 - 10.0,
|
||||
} + (d / radar_range * 150.0),
|
||||
),
|
||||
dimensions: Point2 { x: 1.0, y: 1.0 } * 5.0f32.min((0.8 - m) * 50.0),
|
||||
angle: Deg(0.0),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Game {
|
||||
pub input: InputStatus,
|
||||
pub last_update: Instant,
|
||||
|
@ -22,6 +73,7 @@ pub struct Game {
|
|||
paused: bool,
|
||||
pub time_scale: f32,
|
||||
|
||||
ui: Ui,
|
||||
physics: Physics,
|
||||
shipbehaviors: Vec<Box<dyn ShipBehavior>>,
|
||||
content: Content,
|
||||
|
@ -84,6 +136,7 @@ impl Game {
|
|||
physics,
|
||||
shipbehaviors,
|
||||
content: ct,
|
||||
ui: Ui::new(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -140,8 +193,8 @@ impl Game {
|
|||
self.last_update = Instant::now();
|
||||
}
|
||||
|
||||
pub fn get_sprites(&self) -> Vec<Sprite> {
|
||||
let mut sprites: Vec<Sprite> = Vec::new();
|
||||
pub fn get_object_sprites(&self) -> Vec<ObjectSprite> {
|
||||
let mut sprites: Vec<ObjectSprite> = Vec::new();
|
||||
|
||||
sprites.append(&mut self.system.get_sprites());
|
||||
sprites.extend(self.physics.get_ship_sprites());
|
||||
|
@ -158,4 +211,10 @@ impl Game {
|
|||
|
||||
return sprites;
|
||||
}
|
||||
|
||||
pub fn get_ui_sprites(&self) -> Vec<UiSprite> {
|
||||
return self
|
||||
.ui
|
||||
.build_radar(&self.player, &self.physics, &self.content);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use cgmath::{Deg, Point3};
|
||||
use content::{OutfitSpace, TextureHandle};
|
||||
|
||||
use crate::{content, render::SubSprite};
|
||||
use crate::{content, render::ObjectSubSprite};
|
||||
|
||||
/// Represents a gun attached to a specific ship at a certain gunpoint.
|
||||
#[derive(Debug)]
|
||||
|
@ -77,7 +77,7 @@ pub struct ShipOutfits {
|
|||
|
||||
// Minor performance optimization, since we
|
||||
// rarely need to re-compute these.
|
||||
engine_flare_sprites: Vec<SubSprite>,
|
||||
engine_flare_sprites: Vec<ObjectSubSprite>,
|
||||
}
|
||||
|
||||
impl<'a> ShipOutfits {
|
||||
|
@ -177,7 +177,7 @@ impl<'a> ShipOutfits {
|
|||
self.engine_flare_sprites = self
|
||||
.enginepoints
|
||||
.iter()
|
||||
.map(|p| SubSprite {
|
||||
.map(|p| ObjectSubSprite {
|
||||
pos: Point3 {
|
||||
x: p.pos.x,
|
||||
y: p.pos.y,
|
||||
|
@ -190,7 +190,7 @@ impl<'a> ShipOutfits {
|
|||
.collect();
|
||||
}
|
||||
|
||||
pub fn get_engine_flares(&self) -> Vec<SubSprite> {
|
||||
pub fn get_engine_flares(&self) -> Vec<ObjectSubSprite> {
|
||||
return self.engine_flare_sprites.clone();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ use cgmath::{Point3, Vector2};
|
|||
use rand::{self, Rng};
|
||||
|
||||
use super::SystemObject;
|
||||
use crate::{consts, content, render::Sprite};
|
||||
use crate::{consts, content, render::ObjectSprite};
|
||||
|
||||
pub struct StarfieldStar {
|
||||
/// Star coordinates, in world space.
|
||||
|
@ -59,7 +59,7 @@ impl System {
|
|||
return s;
|
||||
}
|
||||
|
||||
pub fn get_sprites(&self) -> Vec<Sprite> {
|
||||
pub fn get_sprites(&self) -> Vec<ObjectSprite> {
|
||||
return self.bodies.iter().map(|x| x.get_sprite()).collect();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use cgmath::{Deg, Point3};
|
||||
use galactica_content::TextureHandle;
|
||||
|
||||
use crate::render::Sprite;
|
||||
use crate::render::ObjectSprite;
|
||||
|
||||
pub struct SystemObject {
|
||||
pub sprite_texture: TextureHandle,
|
||||
|
@ -11,8 +11,8 @@ pub struct SystemObject {
|
|||
}
|
||||
|
||||
impl SystemObject {
|
||||
pub(super) fn get_sprite(&self) -> Sprite {
|
||||
return Sprite {
|
||||
pub(super) fn get_sprite(&self) -> ObjectSprite {
|
||||
return ObjectSprite {
|
||||
texture: self.sprite_texture,
|
||||
pos: self.pos,
|
||||
angle: self.angle,
|
||||
|
|
|
@ -5,7 +5,7 @@ use rapier2d::{
|
|||
geometry::{ColliderBuilder, ColliderHandle},
|
||||
};
|
||||
|
||||
use crate::{physics::util, render::Sprite};
|
||||
use crate::{physics::util, render::ObjectSprite};
|
||||
|
||||
pub struct ProjectileBuilder {
|
||||
pub rigid_body: RigidBodyBuilder,
|
||||
|
@ -51,14 +51,14 @@ impl Projectile {
|
|||
return self.lifetime < 0.0;
|
||||
}
|
||||
|
||||
pub fn get_sprite(&self, r: &RigidBody) -> Sprite {
|
||||
pub fn get_sprite(&self, r: &RigidBody) -> ObjectSprite {
|
||||
let pos = util::rigidbody_position(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 {
|
||||
ObjectSprite {
|
||||
texture: self.sprite_texture,
|
||||
pos: Point3 {
|
||||
x: pos.x,
|
||||
|
|
|
@ -13,7 +13,7 @@ use crate::{
|
|||
content,
|
||||
game::outfits,
|
||||
physics::{util, ShipHandle},
|
||||
render::Sprite,
|
||||
render::ObjectSprite,
|
||||
};
|
||||
|
||||
pub struct ShipTickResult {
|
||||
|
@ -157,14 +157,14 @@ impl Ship {
|
|||
return ShipTickResult { projectiles: p };
|
||||
}
|
||||
|
||||
pub fn get_sprite(&self, r: &RigidBody) -> Sprite {
|
||||
pub fn get_sprite(&self, r: &RigidBody) -> ObjectSprite {
|
||||
let ship_pos = util::rigidbody_position(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 {
|
||||
ObjectSprite {
|
||||
pos: (ship_pos.x, ship_pos.y, 1.0).into(),
|
||||
texture: self.sprite_texture,
|
||||
angle: -ship_ang,
|
||||
|
|
|
@ -6,5 +6,5 @@ pub use physics::Physics;
|
|||
|
||||
use rapier2d::{dynamics::RigidBodyHandle, geometry::ColliderHandle};
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
pub struct ShipHandle(pub(super) RigidBodyHandle, ColliderHandle);
|
||||
|
|
|
@ -10,7 +10,7 @@ use rapier2d::{
|
|||
use std::{collections::HashMap, f32::consts::PI};
|
||||
|
||||
use super::{wrapper::Wrapper, ShipHandle};
|
||||
use crate::{content, game::outfits, objects, render::Sprite};
|
||||
use crate::{content, game::outfits, objects, render::ObjectSprite};
|
||||
|
||||
/// Keeps track of all objects in the world that we can interact with.
|
||||
/// Also wraps our physics engine
|
||||
|
@ -205,13 +205,13 @@ impl Physics {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn get_ship_sprites(&self) -> impl Iterator<Item = Sprite> + '_ {
|
||||
pub fn get_ship_sprites(&self) -> impl Iterator<Item = ObjectSprite> + '_ {
|
||||
self.ships
|
||||
.values()
|
||||
.map(|x| x.get_sprite(&self.wrapper.rigid_body_set[x.physics_handle.0]))
|
||||
}
|
||||
|
||||
pub fn get_projectile_sprites(&self) -> impl Iterator<Item = Sprite> + '_ {
|
||||
pub fn get_projectile_sprites(&self) -> impl Iterator<Item = ObjectSprite> + '_ {
|
||||
self.projectiles
|
||||
.values()
|
||||
.map(|x| x.get_sprite(&self.wrapper.rigid_body_set[x.rigid_body]))
|
||||
|
|
|
@ -4,20 +4,24 @@ use cgmath::{Deg, EuclideanSpace, Matrix4, Point2, Vector2, Vector3};
|
|||
use galactica_content::Content;
|
||||
use std::{iter, rc::Rc};
|
||||
use wgpu;
|
||||
use winit::{self, dpi::PhysicalSize, window::Window};
|
||||
use winit::{
|
||||
self,
|
||||
dpi::{LogicalSize, PhysicalSize},
|
||||
window::Window,
|
||||
};
|
||||
|
||||
use super::{
|
||||
consts::{OPENGL_TO_WGPU_MATRIX, SPRITE_INSTANCE_LIMIT, STARFIELD_INSTANCE_LIMIT},
|
||||
globaldata::{GlobalData, GlobalDataContent},
|
||||
pipeline::PipelineBuilder,
|
||||
sprite::SubSprite,
|
||||
sprite::ObjectSubSprite,
|
||||
texturearray::TextureArray,
|
||||
vertexbuffer::{
|
||||
consts::{SPRITE_INDICES, SPRITE_VERTICES},
|
||||
types::{SpriteInstance, StarfieldInstance, TexturedVertex},
|
||||
VertexBuffer,
|
||||
},
|
||||
Sprite,
|
||||
ObjectSprite, UiSprite,
|
||||
};
|
||||
use crate::{consts, game::Game};
|
||||
|
||||
|
@ -197,15 +201,15 @@ impl GPUState {
|
|||
self.update_starfield_buffer(game)
|
||||
}
|
||||
|
||||
/// Create a SpriteInstance for s and add it to instances.
|
||||
/// Create a SpriteInstance for an object and add it to `instances`.
|
||||
/// Also handles child sprites.
|
||||
fn push_sprite(
|
||||
fn push_object_sprite(
|
||||
&self,
|
||||
game: &Game,
|
||||
instances: &mut Vec<SpriteInstance>,
|
||||
clip_ne: Point2<f32>,
|
||||
clip_sw: Point2<f32>,
|
||||
s: Sprite,
|
||||
s: ObjectSprite,
|
||||
) {
|
||||
// Position adjusted for parallax
|
||||
// TODO: adjust parallax for zoom?
|
||||
|
@ -284,18 +288,18 @@ impl GPUState {
|
|||
// Add children
|
||||
if let Some(children) = s.children {
|
||||
for c in children {
|
||||
self.push_subsprite(game, instances, c, pos, s.angle);
|
||||
self.push_object_subsprite(game, instances, c, pos, s.angle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Add a sprite's subsprite to instance.
|
||||
/// Only called by push_sprite.
|
||||
fn push_subsprite(
|
||||
/// Add an object sprite's subsprite to `instances`.
|
||||
/// Only called by `self.push_object_sprite`.
|
||||
fn push_object_subsprite(
|
||||
&self,
|
||||
game: &Game,
|
||||
instances: &mut Vec<SpriteInstance>,
|
||||
s: SubSprite,
|
||||
s: ObjectSubSprite,
|
||||
parent_pos: Point2<f32>,
|
||||
parent_angle: Deg<f32>,
|
||||
) {
|
||||
|
@ -332,6 +336,41 @@ impl GPUState {
|
|||
});
|
||||
}
|
||||
|
||||
/// Create a SpriteInstance for a ui sprite and add it to `instances`
|
||||
fn push_ui_sprite(&self, instances: &mut Vec<SpriteInstance>, s: UiSprite) {
|
||||
let logical_size: LogicalSize<f32> =
|
||||
self.window_size.to_logical(self.window.scale_factor());
|
||||
|
||||
let texture = self.texture_array.get_texture(s.texture);
|
||||
let width = s.dimensions.x;
|
||||
let height = s.dimensions.y;
|
||||
|
||||
let scale = Matrix4::from_nonuniform_scale(
|
||||
width / logical_size.width,
|
||||
height / logical_size.height,
|
||||
1.0,
|
||||
);
|
||||
let rotate = Matrix4::from_angle_z(s.angle);
|
||||
let translate = Matrix4::from_translation(match s.pos {
|
||||
super::AnchoredUiPosition::NorthWest(p) => Vector3 {
|
||||
// Note the signs. Positive y points north!
|
||||
x: -1.0 + (width / 2.0 + p.x) / (logical_size.width / 2.0),
|
||||
y: 1.0 - (height / 2.0 - p.y) / (logical_size.height / 2.0),
|
||||
z: 0.0,
|
||||
},
|
||||
_ => Vector3 {
|
||||
x: 0.0,
|
||||
y: 0.0,
|
||||
z: 0.0,
|
||||
},
|
||||
});
|
||||
|
||||
instances.push(SpriteInstance {
|
||||
transform: (OPENGL_TO_WGPU_MATRIX * translate * rotate * scale).into(),
|
||||
texture_index: texture.index,
|
||||
});
|
||||
}
|
||||
|
||||
/// Make a SpriteInstance for each of the game's visible sprites.
|
||||
/// Will panic if SPRITE_INSTANCE_LIMIT is exceeded.
|
||||
///
|
||||
|
@ -344,8 +383,12 @@ impl GPUState {
|
|||
let clip_ne = Point2::from((-self.window_aspect, 1.0)) * game.camera.zoom;
|
||||
let clip_sw = Point2::from((self.window_aspect, -1.0)) * game.camera.zoom;
|
||||
|
||||
for s in game.get_sprites() {
|
||||
self.push_sprite(game, &mut instances, clip_ne, clip_sw, s);
|
||||
for s in game.get_object_sprites() {
|
||||
self.push_object_sprite(game, &mut instances, clip_ne, clip_sw, s);
|
||||
}
|
||||
|
||||
for s in game.get_ui_sprites() {
|
||||
self.push_ui_sprite(&mut instances, s);
|
||||
}
|
||||
|
||||
// Enforce sprite limit
|
||||
|
|
|
@ -7,4 +7,4 @@ mod texturearray;
|
|||
mod vertexbuffer;
|
||||
|
||||
pub use gpustate::GPUState;
|
||||
pub use sprite::{Sprite, SubSprite};
|
||||
pub use sprite::{AnchoredUiPosition, ObjectSprite, ObjectSubSprite, UiSprite};
|
||||
|
|
|
@ -1,12 +1,46 @@
|
|||
use cgmath::{Deg, Point3};
|
||||
use cgmath::{Deg, Point2, Point3};
|
||||
use galactica_content::TextureHandle;
|
||||
|
||||
/// The location of a UI element, in one of a few
|
||||
/// possible coordinate systems.
|
||||
///
|
||||
/// Positive Y always points up,
|
||||
/// positive X always points right.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Sprite {
|
||||
/// The sprite texture to draw
|
||||
pub enum AnchoredUiPosition {
|
||||
/// Position of this sprite's nw corner,
|
||||
/// relative to the nw corner of the window.
|
||||
NorthWest(Point2<f32>),
|
||||
|
||||
/// Position of this sprite's sw corner,
|
||||
/// relative to the sw corner of the window.
|
||||
SouthWest(Point2<f32>),
|
||||
}
|
||||
|
||||
/// A sprite that represents a ui element
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct UiSprite {
|
||||
/// The texture to use for this sprite
|
||||
pub texture: TextureHandle,
|
||||
|
||||
/// This object's position, in world coordinates.
|
||||
/// This object's position, in logical (dpi-adjusted) pixels
|
||||
pub pos: AnchoredUiPosition,
|
||||
|
||||
/// The size of this sprite, in logical (dpi-adjusted) pixels
|
||||
pub dimensions: Point2<f32>,
|
||||
|
||||
/// This sprite's rotation, measured ccw
|
||||
pub angle: Deg<f32>,
|
||||
}
|
||||
|
||||
/// A sprite that represents a world object:
|
||||
/// Ships, planets, debris, etc
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ObjectSprite {
|
||||
/// The texture to use for this sprite
|
||||
pub texture: TextureHandle,
|
||||
|
||||
/// This object's center, in world coordinates.
|
||||
pub pos: Point3<f32>,
|
||||
|
||||
/// The size of this sprite,
|
||||
|
@ -15,14 +49,15 @@ pub struct Sprite {
|
|||
|
||||
/// This sprite's rotation
|
||||
/// (relative to north, measured ccw)
|
||||
/// Note that this is different from the angle used by our physics system.
|
||||
pub angle: Deg<f32>,
|
||||
|
||||
/// Sprites that should be drawn relative to this sprite.
|
||||
pub children: Option<Vec<SubSprite>>,
|
||||
pub children: Option<Vec<ObjectSubSprite>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct SubSprite {
|
||||
pub struct ObjectSubSprite {
|
||||
/// The sprite texture to draw
|
||||
pub texture: TextureHandle,
|
||||
|
||||
|
|
Loading…
Reference in New Issue