Compare commits
4 Commits
master
...
tickless-p
Author | SHA1 | Date | |
---|---|---|---|
f60a370228 | |||
79053420cd | |||
ea9ac948f8 | |||
7f841427dd |
124
src/body.rs
124
src/body.rs
@ -1,10 +1,12 @@
|
|||||||
use crate::instruction::TimedInstruction;
|
use crate::instruction::{InstructionEmitter, InstructionConsumer, TimedInstruction};
|
||||||
|
|
||||||
pub enum PhysicsInstruction {
|
pub enum PhysicsInstruction {
|
||||||
CollisionStart(RelativeCollision),
|
CollisionStart(RelativeCollision),
|
||||||
CollisionEnd(RelativeCollision),
|
CollisionEnd(RelativeCollision),
|
||||||
StrafeTick,
|
StrafeTick,
|
||||||
Jump,
|
Jump,
|
||||||
|
SetWalkTargetVelocity(glam::Vec3),
|
||||||
|
ReachWalkTargetVelocity,
|
||||||
// Water,
|
// Water,
|
||||||
// Spawn(
|
// Spawn(
|
||||||
// Option<SpawnId>,
|
// Option<SpawnId>,
|
||||||
@ -14,15 +16,25 @@ pub enum PhysicsInstruction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct Body {
|
pub struct Body {
|
||||||
pub position: glam::Vec3,//I64 where 2^32 = 1 u
|
position: glam::Vec3,//I64 where 2^32 = 1 u
|
||||||
pub velocity: glam::Vec3,//I64 where 2^32 = 1 u/s
|
velocity: glam::Vec3,//I64 where 2^32 = 1 u/s
|
||||||
pub time: TIME,//nanoseconds x xxxxD!
|
acceleration: glam::Vec3,//I64 where 2^32 = 1 u/s/s
|
||||||
|
time: TIME,//nanoseconds x xxxxD!
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum MoveRestriction {
|
||||||
|
Air,
|
||||||
|
Water,
|
||||||
|
Ground,
|
||||||
|
Ladder,//multiple ladders how
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct PhysicsState {
|
pub struct PhysicsState {
|
||||||
pub body: Body,
|
pub body: Body,
|
||||||
pub contacts: Vec<RelativeCollision>,
|
pub contacts: Vec<RelativeCollision>,
|
||||||
|
//temp
|
||||||
pub models_cringe_clone: Vec<Model>,
|
pub models_cringe_clone: Vec<Model>,
|
||||||
|
pub temp_control_dir: glam::Vec3,
|
||||||
pub time: TIME,
|
pub time: TIME,
|
||||||
pub strafe_tick_num: TIME,
|
pub strafe_tick_num: TIME,
|
||||||
pub strafe_tick_den: TIME,
|
pub strafe_tick_den: TIME,
|
||||||
@ -30,6 +42,7 @@ pub struct PhysicsState {
|
|||||||
pub mv: f32,
|
pub mv: f32,
|
||||||
pub walkspeed: f32,
|
pub walkspeed: f32,
|
||||||
pub friction: f32,
|
pub friction: f32,
|
||||||
|
pub walk_target_velocity: glam::Vec3,
|
||||||
pub gravity: glam::Vec3,
|
pub gravity: glam::Vec3,
|
||||||
pub grounded: bool,
|
pub grounded: bool,
|
||||||
pub jump_trying: bool,
|
pub jump_trying: bool,
|
||||||
@ -173,50 +186,41 @@ impl RelativeCollision {
|
|||||||
|
|
||||||
pub type TIME = i64;
|
pub type TIME = i64;
|
||||||
|
|
||||||
const CONTROL_JUMP:u32 = 0b01000000;//temp DATA NORMALIZATION!@#$
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl PhysicsState {
|
impl PhysicsState {
|
||||||
//delete this, we are tickless gamers
|
//tickless gaming
|
||||||
pub fn run(&mut self, time: TIME, control_dir: glam::Vec3, controls: u32){
|
pub fn run(&mut self, time: TIME){
|
||||||
let target_tick = (time*self.strafe_tick_num/self.strafe_tick_den) as u32;
|
//prepare is ommitted - everything is done via instructions.
|
||||||
//the game code can run for 1 month before running out of ticks
|
while let Some(instruction) = self.next_instruction(time) {//collect
|
||||||
while self.tick<target_tick {
|
//advance
|
||||||
self.tick += 1;
|
//self.advance_time(instruction.time);
|
||||||
let dt=0.01;
|
//process
|
||||||
let d=self.body.velocity.dot(control_dir);
|
self.process_instruction(instruction);
|
||||||
if d<self.mv {
|
//write hash lol
|
||||||
self.body.velocity+=(self.mv-d)*control_dir;
|
|
||||||
}
|
|
||||||
self.body.velocity+=self.gravity*dt;
|
|
||||||
self.body.position+=self.body.velocity*dt;
|
|
||||||
if self.body.position.y<0.0{
|
|
||||||
self.body.position.y=0.0;
|
|
||||||
self.body.velocity.y=0.0;
|
|
||||||
self.grounded=true;
|
|
||||||
}
|
|
||||||
if self.grounded&&(controls&CONTROL_JUMP)!=0 {
|
|
||||||
self.grounded=false;
|
|
||||||
self.body.velocity+=glam::Vec3::new(0.0,0.715588/2.0*100.0,0.0);
|
|
||||||
}
|
|
||||||
if self.grounded {
|
|
||||||
let applied_friction=self.friction*dt;
|
|
||||||
let targetv=control_dir*self.walkspeed;
|
|
||||||
let diffv=targetv-self.body.velocity;
|
|
||||||
if applied_friction*applied_friction<diffv.length_squared() {
|
|
||||||
self.body.velocity+=applied_friction*diffv.normalize();
|
|
||||||
} else {
|
|
||||||
//PhysicsInstruction::WalkTargetReached
|
|
||||||
self.body.velocity=targetv;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.body.time=target_tick as TIME*self.strafe_tick_den/self.strafe_tick_num;
|
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>> {
|
fn next_strafe_instruction(&self) -> Option<TimedInstruction<PhysicsInstruction>> {
|
||||||
@ -273,9 +277,9 @@ impl PhysicsState {
|
|||||||
|
|
||||||
impl crate::instruction::InstructionEmitter<PhysicsInstruction> for 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.
|
//this little next instruction function can cache its return value and invalidate the cached value by watching the State.
|
||||||
fn next_instruction(&self) -> Option<TimedInstruction<PhysicsInstruction>> {
|
fn next_instruction(&self,time_limit:TIME) -> Option<TimedInstruction<PhysicsInstruction>> {
|
||||||
//JUST POLLING!!! NO MUTATION
|
//JUST POLLING!!! NO MUTATION
|
||||||
let mut collector = crate::instruction::InstructionCollector::new();
|
let mut collector = crate::instruction::InstructionCollector::new(time_limit);
|
||||||
//autohop (already pressing spacebar; the signal to begin trying to jump is different)
|
//autohop (already pressing spacebar; the signal to begin trying to jump is different)
|
||||||
if self.grounded&&self.jump_trying {
|
if self.grounded&&self.jump_trying {
|
||||||
//scroll will be implemented with InputInstruction::Jump(true) but it blocks setting self.jump_trying=true
|
//scroll will be implemented with InputInstruction::Jump(true) but it blocks setting self.jump_trying=true
|
||||||
@ -304,7 +308,31 @@ impl crate::instruction::InstructionEmitter<PhysicsInstruction> for PhysicsState
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl crate::instruction::InstructionConsumer<PhysicsInstruction> for PhysicsState {
|
impl crate::instruction::InstructionConsumer<PhysicsInstruction> for PhysicsState {
|
||||||
fn process_instruction(&mut self, instruction:TimedInstruction<PhysicsInstruction>) {
|
fn process_instruction(&mut self, ins:TimedInstruction<PhysicsInstruction>) {
|
||||||
//
|
//mutate position and velocity and time
|
||||||
|
self.advance_time(ins.time);//should this be in run?
|
||||||
|
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);
|
||||||
|
if d<self.mv {
|
||||||
|
self.body.velocity+=(self.mv-d)*self.temp_control_dir;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PhysicsInstruction::Jump => {
|
||||||
|
self.grounded=false;//do I need this?
|
||||||
|
self.body.velocity+=glam::Vec3::new(0.0,0.715588/2.0*100.0,0.0);
|
||||||
|
}
|
||||||
|
PhysicsInstruction::ReachWalkTargetVelocity => {
|
||||||
|
//precisely set velocity
|
||||||
|
self.body.velocity=self.walk_target_velocity;
|
||||||
|
}
|
||||||
|
PhysicsInstruction::SetWalkTargetVelocity(v) => {
|
||||||
|
self.walk_target_velocity=v;
|
||||||
|
//calculate acceleration yada yada
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -4,7 +4,7 @@ pub struct TimedInstruction<I> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub trait InstructionEmitter<I> {
|
pub trait InstructionEmitter<I> {
|
||||||
fn next_instruction(&self) -> Option<TimedInstruction<I>>;
|
fn next_instruction(&self, time:crate::body::TIME) -> Option<TimedInstruction<I>>;
|
||||||
}
|
}
|
||||||
pub trait InstructionConsumer<I> {
|
pub trait InstructionConsumer<I> {
|
||||||
fn process_instruction(&mut self, instruction:TimedInstruction<I>);
|
fn process_instruction(&mut self, instruction:TimedInstruction<I>);
|
||||||
@ -12,26 +12,36 @@ pub trait InstructionConsumer<I> {
|
|||||||
|
|
||||||
//PROPER PRIVATE FIELDS!!!
|
//PROPER PRIVATE FIELDS!!!
|
||||||
pub struct InstructionCollector<I> {
|
pub struct InstructionCollector<I> {
|
||||||
instruction: Option<TimedInstruction<I>>,
|
time: crate::body::TIME,
|
||||||
|
instruction: Option<I>,
|
||||||
}
|
}
|
||||||
impl<I> InstructionCollector<I> {
|
impl<I> InstructionCollector<I> {
|
||||||
pub fn new() -> Self {
|
pub fn new(time:crate::body::TIME) -> Self {
|
||||||
Self{instruction:None}
|
Self{
|
||||||
|
time,
|
||||||
|
instruction:None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn collect(&mut self,instruction:Option<TimedInstruction<I>>){
|
pub fn collect(&mut self,instruction:Option<TimedInstruction<I>>){
|
||||||
match &instruction {
|
match instruction {
|
||||||
Some(unwrap_instruction) => match &self.instruction {
|
Some(unwrap_instruction) => {
|
||||||
Some(unwrap_best_instruction) => if unwrap_instruction.time<unwrap_best_instruction.time {
|
if unwrap_instruction.time<self.time {
|
||||||
self.instruction=instruction;
|
self.time=unwrap_instruction.time;
|
||||||
},
|
self.instruction=Some(unwrap_instruction.instruction);
|
||||||
None => self.instruction=instruction,
|
}
|
||||||
},
|
},
|
||||||
None => (),
|
None => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn instruction(self) -> Option<TimedInstruction<I>> {
|
pub fn instruction(self) -> Option<TimedInstruction<I>> {
|
||||||
//STEAL INSTRUCTION AND DESTROY INSTRUCTIONCOLLECTOR
|
//STEAL INSTRUCTION AND DESTROY INSTRUCTIONCOLLECTOR
|
||||||
return self.instruction
|
match self.instruction {
|
||||||
|
Some(instruction)=>Some(TimedInstruction{
|
||||||
|
time:self.time,
|
||||||
|
instruction
|
||||||
|
}),
|
||||||
|
None => None,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
18
src/main.rs
18
src/main.rs
@ -292,11 +292,7 @@ impl strafe_client::framework::Example for Skybox {
|
|||||||
controls:0,
|
controls:0,
|
||||||
};
|
};
|
||||||
let physics = strafe_client::body::PhysicsState {
|
let physics = strafe_client::body::PhysicsState {
|
||||||
body: strafe_client::body::Body {
|
body: strafe_client::body::Body::with_position(glam::Vec3::new(5.0,5.0,5.0)),
|
||||||
position: glam::Vec3::new(5.0,0.0,5.0),
|
|
||||||
velocity: glam::Vec3::new(0.0,0.0,0.0),
|
|
||||||
time: 0,
|
|
||||||
},
|
|
||||||
time: 0,
|
time: 0,
|
||||||
tick: 0,
|
tick: 0,
|
||||||
strafe_tick_num: 100,//100t
|
strafe_tick_num: 100,//100t
|
||||||
@ -304,14 +300,16 @@ impl strafe_client::framework::Example for Skybox {
|
|||||||
gravity: glam::Vec3::new(0.0,-100.0,0.0),
|
gravity: glam::Vec3::new(0.0,-100.0,0.0),
|
||||||
friction: 90.0,
|
friction: 90.0,
|
||||||
mv: 2.7,
|
mv: 2.7,
|
||||||
grounded: true,
|
grounded: false,
|
||||||
jump_trying: false,
|
jump_trying: false,
|
||||||
|
temp_control_dir: glam::Vec3::ZERO,
|
||||||
walkspeed: 18.0,
|
walkspeed: 18.0,
|
||||||
contacts: Vec::<strafe_client::body::RelativeCollision>::new(),
|
contacts: Vec::<strafe_client::body::RelativeCollision>::new(),
|
||||||
models_cringe_clone: modeldatas.iter().map(|m|strafe_client::body::Model::new(m.transform)).collect(),
|
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.extrapolate_position(0));
|
let camera_uniforms = camera.to_uniform_data(physics.body.extrapolated_position(0));
|
||||||
let camera_buf = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
let camera_buf = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
||||||
label: Some("Camera"),
|
label: Some("Camera"),
|
||||||
contents: bytemuck::cast_slice(&camera_uniforms),
|
contents: bytemuck::cast_slice(&camera_uniforms),
|
||||||
@ -638,13 +636,15 @@ impl strafe_client::framework::Example for Skybox {
|
|||||||
|
|
||||||
let time=self.start_time.elapsed().as_nanos() as i64;
|
let time=self.start_time.elapsed().as_nanos() as i64;
|
||||||
|
|
||||||
self.physics.run(time,control_dir,self.camera.controls);
|
self.physics.temp_control_dir=control_dir;
|
||||||
|
self.physics.jump_trying=self.camera.controls&CONTROL_JUMP!=0;
|
||||||
|
self.physics.run(time);
|
||||||
|
|
||||||
let mut encoder =
|
let mut encoder =
|
||||||
device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });
|
device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });
|
||||||
|
|
||||||
// update rotation
|
// update rotation
|
||||||
let camera_uniforms = self.camera.to_uniform_data(self.physics.extrapolate_position(time));
|
let camera_uniforms = self.camera.to_uniform_data(self.physics.body.extrapolated_position(time));
|
||||||
self.staging_belt
|
self.staging_belt
|
||||||
.write_buffer(
|
.write_buffer(
|
||||||
&mut encoder,
|
&mut encoder,
|
||||||
|
Loading…
Reference in New Issue
Block a user