Compare commits

..

2 Commits

Author SHA1 Message Date
53d2b5b3f5 wip: timelines 2023-09-08 23:20:27 -07:00
c565120ea7 wip: tickless physics 2023-09-08 20:18:31 -07:00
5 changed files with 90 additions and 69 deletions

View File

@@ -1,4 +1,4 @@
use crate::instruction::{InstructionEmitter, InstructionConsumer, TimedInstruction};
use crate::instruction::TimedInstruction;
pub enum PhysicsInstruction {
CollisionStart(RelativeCollision),
@@ -16,10 +16,9 @@ pub enum PhysicsInstruction {
}
pub struct Body {
position: glam::Vec3,//I64 where 2^32 = 1 u
velocity: glam::Vec3,//I64 where 2^32 = 1 u/s
acceleration: glam::Vec3,//I64 where 2^32 = 1 u/s/s
time: TIME,//nanoseconds x xxxxD!
pub position: glam::Vec3,//I64 where 2^32 = 1 u
pub velocity: glam::Vec3,//I64 where 2^32 = 1 u/s
pub time: TIME,//nanoseconds x xxxxD!
}
pub enum MoveRestriction {
@@ -32,9 +31,7 @@ pub enum MoveRestriction {
pub struct PhysicsState {
pub body: Body,
pub contacts: Vec<RelativeCollision>,
//temp
pub models_cringe_clone: Vec<Model>,
pub temp_control_dir: glam::Vec3,
pub time: TIME,
pub strafe_tick_num: TIME,
pub strafe_tick_den: TIME,
@@ -42,7 +39,6 @@ pub struct PhysicsState {
pub mv: f32,
pub walkspeed: f32,
pub friction: f32,
pub walk_target_velocity: glam::Vec3,
pub gravity: glam::Vec3,
pub grounded: bool,
pub jump_trying: bool,
@@ -186,41 +182,28 @@ impl RelativeCollision {
pub type TIME = i64;
impl Body {
pub fn with_position(position:glam::Vec3) -> Self {
Self{
position: position,
velocity: glam::Vec3::ZERO,
acceleration: glam::Vec3::ZERO,
time: 0,
}
}
pub fn extrapolated_position(&self,time: TIME)->glam::Vec3{
let dt=(time-self.time) as f64/1_000_000_000f64;
self.position+self.velocity*(dt as f32)+self.acceleration*((0.5*dt*dt) as f32)
}
pub fn advance_time(&mut self, time: TIME){
self.position=self.extrapolated_position(time);
self.time=time;
}
}
const CONTROL_JUMP:u32 = 0b01000000;//temp DATA NORMALIZATION!@#$
impl PhysicsState {
//tickless gaming
//delete this, we are tickless gamers
pub fn run(&mut self, time: TIME){
//prepare is ommitted - everything is done via instructions.
while let Some(instruction) = self.next_instruction(time) {//collect
while let Some(instruction) = self.next_instruction() {//collect
if time<instruction.time {
break;
}
//advance
//self.advance_time(instruction.time);
self.advance_time(instruction.time);
//process
self.process_instruction(instruction);
//write hash lol
}
}
pub fn advance_time(&mut self, time: TIME){
self.body.advance_time(time);
self.time=time;
//delete this
pub fn extrapolate_position(&self, time: TIME) -> glam::Vec3 {
let dt=(time-self.body.time) as f64/1_000_000_000f64;
self.body.position+self.body.velocity*(dt as f32)+self.gravity*((0.5*dt*dt) as f32)
}
fn next_strafe_instruction(&self) -> Option<TimedInstruction<PhysicsInstruction>> {
@@ -277,9 +260,9 @@ impl PhysicsState {
impl crate::instruction::InstructionEmitter<PhysicsInstruction> for PhysicsState {
//this little next instruction function can cache its return value and invalidate the cached value by watching the State.
fn next_instruction(&self,time_limit:TIME) -> Option<TimedInstruction<PhysicsInstruction>> {
fn next_instruction(&self) -> Option<TimedInstruction<PhysicsInstruction>> {
//JUST POLLING!!! NO MUTATION
let mut collector = crate::instruction::InstructionCollector::new(time_limit);
let mut collector = crate::instruction::InstructionCollector::new();
//autohop (already pressing spacebar; the signal to begin trying to jump is different)
if self.grounded&&self.jump_trying {
//scroll will be implemented with InputInstruction::Jump(true) but it blocks setting self.jump_trying=true
@@ -310,15 +293,15 @@ impl crate::instruction::InstructionEmitter<PhysicsInstruction> for PhysicsState
impl crate::instruction::InstructionConsumer<PhysicsInstruction> for PhysicsState {
fn process_instruction(&mut self, ins:TimedInstruction<PhysicsInstruction>) {
//mutate position and velocity and time
self.advance_time(ins.time);//should this be in run?
self.body.advance_time(ins.time);//should this be in a separate function: self.advance_time?
match ins.instruction {
PhysicsInstruction::CollisionStart(_) => todo!(),
PhysicsInstruction::CollisionEnd(_) => todo!(),
PhysicsInstruction::StrafeTick => {
//let control_dir=self.get_control_dir();//this should respect your mouse interpolation settings
let d=self.body.velocity.dot(self.temp_control_dir);
let control_dir=self.get_control_dir();//this respects your mouse interpolation settings
let d=self.body.velocity.dot(control_dir);
if d<self.mv {
self.body.velocity+=(self.mv-d)*self.temp_control_dir;
self.body.velocity+=(self.mv-d)*control_dir;
}
}
PhysicsInstruction::Jump => {

View File

@@ -4,7 +4,7 @@ pub struct TimedInstruction<I> {
}
pub trait InstructionEmitter<I> {
fn next_instruction(&self, time:crate::body::TIME) -> Option<TimedInstruction<I>>;
fn next_instruction(&self) -> Option<TimedInstruction<I>>;
}
pub trait InstructionConsumer<I> {
fn process_instruction(&mut self, instruction:TimedInstruction<I>);
@@ -12,36 +12,26 @@ pub trait InstructionConsumer<I> {
//PROPER PRIVATE FIELDS!!!
pub struct InstructionCollector<I> {
time: crate::body::TIME,
instruction: Option<I>,
instruction: Option<TimedInstruction<I>>,
}
impl<I> InstructionCollector<I> {
pub fn new(time:crate::body::TIME) -> Self {
Self{
time,
instruction:None
}
pub fn new() -> Self {
Self{instruction:None}
}
pub fn collect(&mut self,instruction:Option<TimedInstruction<I>>){
match instruction {
Some(unwrap_instruction) => {
if unwrap_instruction.time<self.time {
self.time=unwrap_instruction.time;
self.instruction=Some(unwrap_instruction.instruction);
}
match &instruction {
Some(unwrap_instruction) => match &self.instruction {
Some(unwrap_best_instruction) => if unwrap_instruction.time<unwrap_best_instruction.time {
self.instruction=instruction;
},
None => self.instruction=instruction,
},
None => (),
}
}
pub fn instruction(self) -> Option<TimedInstruction<I>> {
//STEAL INSTRUCTION AND DESTROY INSTRUCTIONCOLLECTOR
match self.instruction {
Some(instruction)=>Some(TimedInstruction{
time:self.time,
instruction
}),
None => None,
}
return self.instruction
}
}

View File

@@ -1,3 +1,4 @@
pub mod framework;
pub mod body;
pub mod instruction;
pub mod timelines;

View File

@@ -292,7 +292,11 @@ impl strafe_client::framework::Example for Skybox {
controls:0,
};
let physics = strafe_client::body::PhysicsState {
body: strafe_client::body::Body::with_position(glam::Vec3::new(5.0,5.0,5.0)),
body: strafe_client::body::Body {
position: glam::Vec3::new(5.0,0.0,5.0),
velocity: glam::Vec3::new(0.0,0.0,0.0),
time: 0,
},
time: 0,
tick: 0,
strafe_tick_num: 100,//100t
@@ -300,16 +304,14 @@ impl strafe_client::framework::Example for Skybox {
gravity: glam::Vec3::new(0.0,-100.0,0.0),
friction: 90.0,
mv: 2.7,
grounded: false,
grounded: true,
jump_trying: false,
temp_control_dir: glam::Vec3::ZERO,
walkspeed: 18.0,
contacts: Vec::<strafe_client::body::RelativeCollision>::new(),
models_cringe_clone: modeldatas.iter().map(|m|strafe_client::body::Model::new(m.transform)).collect(),
walk_target_velocity: glam::Vec3::ZERO,
};
let camera_uniforms = camera.to_uniform_data(physics.body.extrapolated_position(0));
let camera_uniforms = camera.to_uniform_data(physics.extrapolate_position(0));
let camera_buf = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some("Camera"),
contents: bytemuck::cast_slice(&camera_uniforms),
@@ -636,15 +638,13 @@ impl strafe_client::framework::Example for Skybox {
let time=self.start_time.elapsed().as_nanos() as i64;
self.physics.temp_control_dir=control_dir;
self.physics.jump_trying=self.camera.controls&CONTROL_JUMP!=0;
self.physics.run(time);
self.physics.run(time,control_dir,self.camera.controls);
let mut encoder =
device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });
// update rotation
let camera_uniforms = self.camera.to_uniform_data(self.physics.body.extrapolated_position(time));
let camera_uniforms = self.camera.to_uniform_data(self.physics.extrapolate_position(time));
self.staging_belt
.write_buffer(
&mut encoder,

47
src/timelines.rs Normal file
View File

@@ -0,0 +1,47 @@
type ORDER = u32;
pub struct Tracker {
order: ORDER,
}
pub struct TimelineInstruction<I>{
pub order: ORDER,//absolute ordering of instructions which can be used for sorting even when there are multiple simultaneous timestamps
pub instruction: crate::instruction::TimedInstruction<I>,
}
pub struct Timeline<I>{
instructions: std::collections::VecDeque<TimelineInstruction<I>>,
trackers: Vec<Tracker>,//wrong
}
impl<I> Timeline<I>{
pub fn new() -> Self {
Self{
instructions:std::collections::VecDeque::<TimelineInstruction<I>>::new(),
trackers:Vec::<Tracker>::new(),
}
}
pub fn len(&self) -> usize {
return self.instructions.len()
}
pub fn first(&self) -> Option<&TimelineInstruction<I>> {
return self.instructions.get(0)
}
pub fn last(&self) -> Option<&TimelineInstruction<I>> {
return self.instructions.get(self.instructions.len()-1)
}
pub fn append(&mut self,instruction:TimelineInstruction<I>){
let i=self.instructions.len();
self.instructions.push_back(instruction);
for tracker in self.trackers.iter() {
tracker.set_active(true);
}
}
pub fn get_index_after_time(&mut self,time:crate::body::TIME) -> usize{
self.instructions.partition_point(|ins|ins.instruction.time<time)
}
pub fn get_index_after_order(&mut self,order:ORDER) -> usize{
self.instructions.partition_point(|ins|ins.order<order)
}
}