Improve controller input, console, and UI consistency
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
/* Controller conditioning is independent of drawing and MAVLink transport. */
|
||||
((root)=>{
|
||||
const clamp=value=>Math.max(-1,Math.min(1,Number.isFinite(value)?value:0));
|
||||
function deadZone(value,zone=.08){
|
||||
value=clamp(value);zone=Math.max(0,Math.min(.4,zone));
|
||||
return Math.abs(value)<=zone?0:Math.sign(value)*(Math.abs(value)-zone)/(1-zone);
|
||||
}
|
||||
function defaults(pad){
|
||||
return {turn:0,forward:1,vertical:pad?.axes?.length>=4?3:pad?.axes?.length>=3?2:-1,
|
||||
invertTurn:false,invertForward:true,invertVertical:true,deadZone:.08};
|
||||
}
|
||||
function read(pad,config){
|
||||
if(!pad?.connected||!pad.axes)return null;
|
||||
const axis=(index,invert)=>{
|
||||
if(index===-1)return 0;
|
||||
if(!Number.isInteger(index)||index<0||index>=pad.axes.length||!Number.isFinite(pad.axes[index]))return null;
|
||||
return deadZone(pad.axes[index],config.deadZone)*(invert?-1:1);
|
||||
};
|
||||
let turn=axis(config.turn,config.invertTurn),forward=axis(config.forward,config.invertForward),vertical=axis(config.vertical,config.invertVertical);
|
||||
if(turn===null||forward===null||vertical===null)return null;
|
||||
const length=Math.hypot(turn,forward);if(length>1){turn/=length;forward/=length}
|
||||
return {turn,forward,vertical};
|
||||
}
|
||||
class Smoother{
|
||||
constructor(){this.reset()}
|
||||
reset(){this.value=0;this.last=null;this.release=null}
|
||||
step(target,now){
|
||||
target=clamp(target);
|
||||
const dt=this.last===null?0:Math.max(0,Math.min(.05,(now-this.last)/1000));this.last=now;
|
||||
if(target===0){
|
||||
if(!this.release)this.release={at:now,start:this.value};
|
||||
const t=Math.min(1,Math.max(0,(now-this.release.at)/360)),ease=t*t*(3-2*t);
|
||||
this.value=this.release.start*(1-ease);
|
||||
}else{
|
||||
this.release=null;
|
||||
this.value+=(target-this.value)*(1-Math.exp(-dt/.1));
|
||||
if(Math.abs(target-this.value)<.001)this.value=target;
|
||||
}
|
||||
return this.value;
|
||||
}
|
||||
}
|
||||
class Motion{
|
||||
constructor(){this.axes={turn:new Smoother(),forward:new Smoother(),vertical:new Smoother()}}
|
||||
reset(){Object.values(this.axes).forEach(axis=>axis.reset())}
|
||||
step(target,now){
|
||||
const demand=Object.fromEntries(Object.entries(this.axes).map(([key,axis])=>[key,axis.step(target[key],now)]));
|
||||
const length=Math.hypot(demand.turn,demand.forward);if(length>1){demand.turn/=length;demand.forward/=length}
|
||||
return demand;
|
||||
}
|
||||
}
|
||||
root.ControllerInput={deadZone,defaults,read,Motion};
|
||||
if(typeof module!=='undefined')module.exports=root.ControllerInput;
|
||||
})(typeof window!=='undefined'?window:globalThis);
|
||||
Reference in New Issue
Block a user