Кроме шуток, подскажите где можно наколупать математику инерции.
Пишу кукурузник для unreal engine 1, сейчас работает втупую (абсолютным переназначением координат вектора location).
Переписывал под накопление длины вектора velocity установив физику PHYS_Falling (самая тщательно рассчитываемая и реплицируемая по сети физика) - вроде подход правильный, но на выходе получается кал гавна.
Сейчас имею на выходе нечто типа VTOL как у Шварценеггера в фильме “Правдивая ложь” (горизонтально взлетает на скорости больше 150 uu, вертикальная/горизонтальная автопосадка на скорости меньше 90. чтобы имитировать потерю подъёмной силы, недостаток скорости вносит немного “проваливания”, то есть уменьшения location.z)
Есьчо подсказать?
class asw extends asmd;
#exec texture import file="textures\ttagbarhl.png" name="ttagbarhl" package="aerscope" group="None" mips=1 flags=0 btc=-2
#exec texture import file="textures\ttagbarhs.png" name="ttagbarhs" package="aerscope" group="None" mips=1 flags=0 btc=-2
#exec texture import file="textures\ttagbarvl.png" name="ttagbarvl" package="aerscope" group="None" mips=1 flags=0 btc=-2
#exec texture import file="textures\ttagbarvs.png" name="ttagbarvs" package="aerscope" group="None" mips=1 flags=0 btc=-2
#exec texture import file="textures\ttagpixel.png" name="ttagpixel" package="aerscope" group="None" mips=1 flags=0 btc=-2
#exec audio import file="sounds\ttagengend3.wav" name="ttagengend" package="aerscope" group="Sound"
#exec audio import file="sounds\ttagengloop3.wav" name="ttagengloop" package="aerscope" group="Sound"
#exec audio import file="sounds\ttagengsta3.wav" name="ttagengsta" package="aerscope" group="Sound"
var aswcam fpv;
var bool deployed;
var rotator freeze_rot;
var vector freeze_loc;
var float movespeed, actualspeed, movespeedtimer, movemeasspeedtimer, movesndstarttimer, altitude;
var float scale1, scale128, clipxdiv2, clipydiv2;
var bool canvas_set,ok_land,ok_takeoff;
function fire(float f){}
function altfire(float f){}
function calccoords(canvas c, playerpawn p){
if(canvas_set) return;
scale1 = c.clipx / 640;
scale128 = scale1 * 128;
clipxdiv2 = c.clipx / 2;
clipydiv2 = c.clipy / 2;
canvas_set = true;
}
function postrender(canvas c){
local playerpawn p;
local pawn t;
local int i,j,k,l,m,xp,yp;
local vector dist,dist_c,dir,x,y,z,dir_bounds[8];
local float d,ms_s,bearing,bear_s,alt_s,dirdotx,fovscale;
local string s;
if(!deployed || fpv == none) return;
p = playerpawn(owner);
if(p == none) return;
calccoords(c,p);
dist = fpv.location - p.location;
dist_c = dist;
alt_s = altitude;
alt_s = alt_s % 80;
ms_s = movespeed;
ms_s = ms_s % 80;
bearing = fpv.rotation.yaw;
bearing = bearing % 65536;
bearing /= 182.0;
if(bearing < 0) bearing += 360;
bear_s = bearing % 80;
c.drawcolor = makecolor(255,255,255);
// ====== ABR ==========================================================================================================
if(p.bIsCrouching){ c.setpos(250,c.clipy-40); c.drawtext("[ABR]"); }
// ====== RSSI =========================================================================================================
s="";
j=clamp(int(vsize(dist)/256),0,10);
for(i=1;i<10-j;i++) s $= "|";
c.setpos(50,c.clipy-40); c.drawtext("RSSI: "$s);
// ====== altimeter ====================================================================================================
yp = 0 - int(alt_s);
c.setpos(40,clipydiv2-5); c.drawtext(int(altitude * 2.125));
for(i=0;i<115;i++){
if(i%10 == 0){ c.setpos(100,yp); if(yp > 60 && yp < c.clipy-60) c.drawicon(texture'ttagbarhl', 1);
}else{ c.setpos(108,yp); if(yp > 60 && yp < c.clipy-60) c.drawicon(texture'ttagbarhs', 1); }
yp += 8;
}
// ====== speedmeter ===================================================================================================
yp = 0 - int(ms_s);
c.setpos(c.clipx-70,clipydiv2-5); c.drawtext(int(movespeed * 1.619));
for(i=0;i<115;i++){
if(i%10 == 0){ c.setpos(c.clipx-100,yp); if(yp > 60 && yp < c.clipy-60) c.drawicon(texture'ttagbarhl', 1);
}else{ c.setpos(c.clipx-100,yp); if(yp > 60 && yp < c.clipy-60) c.drawicon(texture'ttagbarhs', 1); }
yp += 8;
}
// ====== compass ======================================================================================================
xp = 0 - int(bear_s);
c.setpos(clipxdiv2-20,30); c.drawtext(int(bearing));
for(i=0;i<115;i++){
c.setpos(xp,54); if(xp > 140 && xp < c.clipx-124) c.drawicon(texture'ttagbarvs', 1);
xp += 16;
}
// ====== targets display ==============================================================================================
getaxes(fpv.rotation,x,y,z);
FovScale = 1 / Tan(FClamp(p.DesiredFOV, 1, 170) / 360 * Pi);
c.style = ERenderStyle.STY_Translucent;
foreach RadiusActors(class'pawn', t, 12000, fpv.location){
if(!validate_target(t)) continue;
Dir = fpv.location - t.location;
if(VSize(Dir) > 2000 && t.group != 'AERtarget') continue;
if ( ((Dir / VSize(Dir)) Dot X) > 0.7 * FovScale) continue;
for(i=0;i<8;i++) dir_bounds[i] = dir;
d = t.collisionheight/2;
for(i=0;i<4;i++) dir_bounds[i].z -= d;
for(i=4;i<8;i++) dir_bounds[i].z += d;
d = t.collisionradius/2;
dir_bounds[0].y -= d; dir_bounds[1].y -= d; dir_bounds[4].y -= d; dir_bounds[5].y -= d;
dir_bounds[2].y += d; dir_bounds[3].y += d; dir_bounds[6].y += d; dir_bounds[7].y += d;
dir_bounds[0].x -= d; dir_bounds[3].x -= d; dir_bounds[4].x -= d; dir_bounds[7].x -= d;
dir_bounds[1].x += d; dir_bounds[2].x += d; dir_bounds[5].x += d; dir_bounds[6].x += d;
dirdotx = dir dot x;
c.drawcolor = t.group == 'AERtarget' ? makecolor(200,200,255) : makecolor(32,32,32);
for(i=0;i<8;i++){
dir_bounds[i] /= dirdotx;
XP = 0.5 * (c.SizeX + c.SizeX * (dir_bounds[i] Dot Y) * FovScale);
YP = 0.5 * (c.SizeY - c.SizeX * (dir_bounds[i] Dot Z) * FovScale);
c.SetPos(XP - 0.5 * 4 * scale1, YP - 0.5 * 4 * scale1);
c.DrawIcon(texture'ttagpixel', scale1/4);
}
}
c.Reset();
c.drawcolor = makecolor(255,255,255);
}
function tick(float f){
local playerpawn p;
local vector l,x,y,z,hl,hn;
local actor atarg;
local pawn ptarg;
p = playerpawn(owner);
if(p == none) return;
if(p.weapon != self) return;
if(deployed && fpv != none){
l = fpv.location;
getaxes(fpv.rotation,x,y,z);
atarg = trace(hl,hn,l + 2000*x,l,true);
}
if(atarg != none && atarg.bIsPawn) ptarg = pawn(atarg);
if(ptarg != none) attempt_tag_target(ptarg);
if(p.bFire != 0 && !deployed) deploy_fpv(p);
if(p.bAltFire != 0 && deployed) collapse_fpv();
if(!deployed || fpv == none) return;
rotate_fpv(p);
thrust_fpv(p,f);
move_fpv(p,f);
fpv_speed(f);
move_sound(f);
}
function bool validate_target(pawn targ){
if(targ.group == 'AERtarget') return true;
if(targ==owner) return false;
if(targ.health <= 0){
targ.group = '';
return false;
}
if(bool(flockpawn(targ)) || bool(flockmasterpawn(targ)) || bool(nali(targ)) || bool(cow(targ))) return false;
if(targ.isa('stationarypawn') || targ.isa('cspawn') || targ.isa('upakintermissioncam')) return false;
return true;
}
function attempt_tag_target(pawn targ){
if(validate_target(targ) && targ.AttitudeToPlayer<ATTITUDE_IGNORE) targ.group = 'AERtarget';
}
function rotate_fpv(playerpawn p){
fpv.setrotation(p.viewrotation);
p.setrotation(freeze_rot);
}
function bool thrust_val(){
local vector l,x,y,z,hl,hn;
local bool ok_fwd,ok_top,ok_bot,ok_l,ok_r;
l = fpv.location;
getaxes(fpv.rotation,x,y,z);
trace(hl,hn,l + 64*x,l,true); ok_fwd = vsize(hl-l) > 40;
// trace(hl,hn,l - 64*x,l,true); ok_bak = vsize(hl-l) > 8; // never used
trace(hl,hn,l + 64*y,l,true); ok_r = vsize(hl-l) > 8;
trace(hl,hn,l - 64*y,l,true); ok_l = vsize(hl-l) > 8;
trace(hl,hn,l + 64*z,l,true); ok_top = vsize(hl-l) > 8;
trace(hl,hn,l - 64*z,l,true); ok_bot = vsize(hl-l) > 8;
trace(hl,hn,l - vect(0,0,10000),l,true); altitude = vsize(hl-l);
return (ok_fwd && ok_r && ok_l && ok_top && ok_top);
}
function thrust_fpv(playerpawn p,float f){
local bool tval,ok_autobrk;
local int shm;
local float min_thr;
tval = thrust_val();
shm = !p.bIsCrouching ? 1 : 5;
if(!ok_land && movespeed<160 && altitude<32) ok_land = true;
if(ok_land && movespeed>160) ok_land = false;
min_thr = ok_land ? 0 : 30; //was 186,180,230
if(movesndstarttimer>0.1 && movespeed<170) movespeed += 1; // auto launch thrust
movespeedtimer -= f;
if(movespeedtimer > 0) return;
movespeedtimer = !p.bIsCrouching ? 0.1 : 0.02;
if(ok_land) movespeedtimer = 0.02;
if(movespeed <= 2 && ok_land && !ok_takeoff){
p.clientmessage("ok_takeoff.",'pickup');
fpv.setphysics(PHYS_Falling);
movespeed = 0;
ok_takeoff = true;
fpv.ambientsound = none;
fpv.playsound(sound'ttagengend', SLOT_None, 16);
// spawn pickup here
// collapse_fpv();
return;
}
ok_autobrk = ok_land && movespeed<150 && p.bIsCrouching;
if(!p.bWasForward || !tval){
if(!p.bWasBack && p.bIsCrouching) shm = 1;
if(ok_autobrk && movespeed > min_thr) movespeed -= 1*shm; // auto fly/landing brake
if(p.bWasBack && movespeed > min_thr) movespeed -= 2*shm;
if(movespeed < 0) movespeed = 0;
return;
}
if(tval && movespeed < 900) movespeed += 1*shm;
}
function move_fpv(playerpawn p,float f){
local vector l,x,y,z;
local int lackspeed;
p.setlocation(freeze_loc);
if(!thrust_val()) return;
l = fpv.location;
getaxes(fpv.rotation,x,y,z);
if(movespeed > 0) l += movespeed*x*f;
if(movesndstarttimer<=0 && altitude>12 && movespeed<150){
lackspeed = 150 - movespeed;
if(lackspeed>100) lackspeed -= 100;
if(movespeed < 50) lackspeed += lackspeed;
if(movespeed < 25) lackspeed *= 4;
l.z -= lackspeed*1.2*f;
}
fpv.setlocation(l);
}
function fpv_speed(float f){
movemeasspeedtimer -= f;
if(movemeasspeedtimer > 0) return;
movemeasspeedtimer = 0.4;
actualspeed = int(vsize(fpv.spd_oldloc-fpv.location));
fpv.spd_oldloc = fpv.location;
}
function move_sound(float f){
if(movesndstarttimer > 0){
movesndstarttimer -= f;
return;
}
if(movespeed >= 50) fpv.soundpitch = 64 + int(movespeed/100);
fpv.ambientsound = sound'ttagengloop';
}
function deploy_fpv(playerpawn p){
local vector x,y,z;
if(deployed) return;
getaxes(p.viewrotation,x,y,z);
movespeed = 50;
fpv = spawn(class'aswcam',,,p.location + 40*x + 10*z,p.viewrotation);
if(fpv==none) return;
deployed = true;
fpv.w = self;
freeze_rot = p.viewrotation;
freeze_loc = p.location;
movesndstarttimer = 1.02;
p.viewtarget = fpv;
fpv.playsound(sound'ttagengsta', SLOT_None, 16);
p.dodgeclicktime = 0;
}
function collapse_fpv(){
local playerpawn p;
if(!deployed || fpv == none) return;
p = playerpawn(owner);
if(p == none) return;
if(p.viewtarget == fpv) p.viewtarget = none;
p.viewrotation = freeze_rot;
p.dodgeclicktime = p.default.dodgeclicktime;
// fpv.destroy(); //todo settimeout
fpv.mesh = lodmesh'unrealshare.rabbit';
fpv.drawtype = dt_mesh;
fpv.bhidden = false;
fpv = none;
deployed = false;
}
function tweendown(){
local playerpawn p;
p = playerpawn(owner);
if(p == none) return;
super.tweendown();
if(!deployed) return;
bringup();
p.weapon = self;
}
function timer(){
local playerpawn p;
p = playerpawn(owner);
if(p == None){
GotoState('Pickup');
return;
}
if(!isinstate('Idle')) GotoState('Idle');
if(p.weapon != self) return;
settimer(0.05, true);
}
defaultproperties{
movespeed=50
ok_takeoff=false
ok_land=false
fpv=none
deployed=false
canvas_set=false
}
Самое интересное с точки зрения движения живёт в функциях tick(), move_fpv()
Текущий вариант использует физику PHYS_None