#2569 posted by Spike on 2018/07/07 13:34:19
use dotproducts:
upspeed = self.velocity * v_up;
fwdspeed = self.velocity * v_forward;
rightspeed = self.velocity * v_right;
(vec*vec is a dotproduct).
You can then get back to the original velocity vector with:
self.velocity = v_up*upspeed + v_forward*fwdspeed + v_right*rightspeed;
Of course, if you change some fraction of the force exerted on the underside of your glider before reforming the velocity then you'll reduce the effects of gravity while horizontal, and return to normal when facing vertically down.
Of course, that energy should normally go somewhere - if you add to fwdspeed anything you subtract from upspeed then you should get something a bit glidery.
you'll also need to include some friction somewhere, in order to get some terminal velocity. and yeah, the conversion should probably also not be 100% efficient either, nor should it convert ALL the energy.
but yeah, dotproducts are great if you want to compare two directions. trying to do stuff like this without using them is just going to leave it feeling really hacky.
Unfortunately there's no real way to control the camera from ssqc, but csqc can override the camera angles without changing the client's 'desired' angles. you should be able to implement roll that way, somehow.
Notes After Testing The Suggested Code
#2570 posted by Preach on 2018/07/09 00:20:50
Had a go with the code from my post on Saturday, it worked pretty well for a first attempt. I did find that it wasn't responsive enough until I doubled frametime everywhere it appeared. One big tip for testing it - use e1m8. Firstly because its one of the few ID maps with enough vertical and horizontal space to glide in properly, secondly because it's low gravity so it's much more fun!
It's got most of the effects you'd want to see in glider physics - you can dive down to gain speed then level off and carry the momentum forward, and if you look up you'll gain height but bleed forward speed. You can look straight up, and you'll quickly stall then crash to the ground. Also if you collide with walls etc your speed is lost which tends to end the flight pretty quick.
One advanced trick: you can accelerate in Quake while in the air. If you're gliding, strafe left while turning in an anticlockwise circle and you'll gain speed (same principle as bunnyhopping works on). You can use this to offset the loss of speed while climbing, and gain height by moving in a big spiral.
Preach’s Code Test
#2571 posted by Reyond on 2018/07/09 08:29:44
Hi Preach, yesterday I arrived to my PC and I got an error after compiling your code. May be I have done something wrong. Could you please post a full file with your code so I could test it out? I think that would be useful for all the community.
#2572 posted by c0burn on 2018/07/09 18:21:41
Maybe if you post the error you're getting we can help you out ...
Skeleton Code
#2573 posted by Preach on 2018/07/09 20:54:12
I tried to post it as skeleton code so that you'd get some practice hooking it up. One thing I did unintentionally was to misspell (well, anglicize) a built-in function name, so make sure you change the spelling to normalize. If that wasn't the error that's stopped you, post it like c0burn says and we can suggest fixes.
#2574 posted by Reyond on 2018/07/10 12:21:21
Still no result. I try to use this code if no flag on_ground is false but nothing works.
New Issue
#2575 posted by Preach on 2018/07/10 23:34:43
Hi Reyond. It sounds like it's a bit further on if the compiler error has gone away. What function are you running the code in? I ran it in PlayerPreThink so that it would happen every frame. You're right to disable the code when the player is on the ground, but from your description I don't know whether the code you have is right.
I used: if(self.flags & FL_ONGROUND) to see if the player was on the ground. I also turned the code off while the player was in water using the check if(self.waterlevel) (although that's a detail to add once the basics work.
If that doesn't help, post the whole text of the code you're using and maybe we can spot what else it could be...
Tut From InsideQc
#2576 posted by madfox on 2018/07/11 14:37:59
Found an old tutorial from Legion with an Xman version of a FlySimulator. Maybe helpfull as a guide.
#2577 posted by Reyond on 2018/07/12 01:26:51
Allright, I found an error. Here is how I use the code:
else // airborn
{
vector fly_direction; vector new_dir; float fly_speed;
float fly_velocity; '
float koef;
/*
if (wishspeed < 30)
f = wishspeed - (self.velocity * wishdir);
else
f = 30 - (self.velocity * wishdir);
if (f > 0)
self.velocity - self.velocity + wishdir * (min(f, sv_accelerate) * wishspeed * frametime);
*/
fly_speed = vlen(self.velocity);
fly_direction = normalize(self.velocity);
makevectors(self.v_angle);
new_dir = normalize(v_forward*frametime +fly_direction*(1-frametime)); self.velocity = new_dir * speed;
}
#2578 posted by Reyond on 2018/07/12 01:32:54
Yes, actually it looks a little bit like gliding but I can’t understand how the code works. Why do I use frametime if this function works every frame? How this code affects the gravity (in-game gravity is 100 now). And how can I improve this code to make it work better?
Also, I would like to make it works without changing the standart “800” value of the sv_gravity variable. Is that possible?
Also, thanks to Preach and to everyone who helps me in making player gliding in quake.
Try It Out
#2579 posted by Preach on 2018/07/12 22:56:06
Have a go with the second-to-last line changed to
new_dir = v_forward;
This leaves out the bits with frametime. What you should notice is that while gliding, you instantly start moving in exactly the direction you are facing. It's very easy to control, but it's not very realistic for a glider - you can 180 turn instantly at any time.
The idea behind the frametime code is to add the v_forward part more slowly, so that your direction of travel doesn't change instantly. Instead we add the v_forward in a bit at a time. Because the function runs every frame, we need the pieces we add to be smaller when the framerate is higher, otherwise people with higher framerates could execute tighter turns, which would be unfair.
I found that in practice the rate of change was too slow, and that it was better to change that line to:
new_dir = normalize(v_forward*2*frametime +fly_direction*(1-2*frametime));
By making the piece we add each frame twice as large, we get a better trade-off between smooth turning and reaction time.
In terms of making the glider float, I noticed that you don't have the last line from the code I posted:
self.gravity = 0.1 + 0.9*abs(v_forward*'0 0 1');
I expect you were getting a compiler error from this line that you didn't know how to fix. The secret is to add the following to the bottom of defs.qc:
.float gravity;
This warns the compiler that you'd like to be able to store a float called "gravity" on all the entities. The engine uses this to change the gravity just for that entity. So if you are flying in normal 800 strength gravity, but the player has self.gravity = 0.1, for that player gravity will be 80 instead (because 800 * 0.1 = 80). All other entities are unaffected, try firing a grenade while gliding and notice that it falls normally.
Give it a go, see what comes of it! Any more questions, just ask...
#2580 posted by Reyond on 2018/07/12 23:08:01
Error: unknown value “abs”.
To Reyond
its fabs i think
Yup
#2582 posted by Preach on 2018/07/13 00:13:06
Teach me to copy-paste from the sketchy untested post rather than the working code, use fabs and it'll work.
#2583 posted by Reyond on 2018/07/13 18:15:40
Finally, we have a nice result!
Watch this:
https://youtu.be/vuXm64C_xso
Thanks to Preach for the code and to st1x51, Baker, madfox, metlslime, Qmaster, Spike, mankrip, c0burn and to all who helped me with this.
Here you can get progs.dat file to check it out:
https://drive.google.com/open?id=1U1Qb6nN3nTc9zwpRYZotGen_weFsBjIQ
And here is the source code (use dpextensions.qc or fteextensions.qc to compile it and add .float gravity in to the defs.qc):
https://drive.google.com/open?id=1Mck52dhvC7KKKOkC2N3QzGcgiBqQJtQU
Reyond
#2584 posted by Baker on 2018/07/13 18:59:17
Tried in on E1M7 in FTE and it works nice.
Congrats!
Improving The Code
#2585 posted by Reyond on 2018/07/14 13:49:43
Is there any way to slow down flight? I have to make huge maps to make flight works properly.
And is there any way to change the value of horizontal speed loss?
Is there any way to make this work in standard quake without ising fork engines extensions?
Improving The Code
#2586 posted by Reyond on 2018/07/14 13:49:53
Is there any way to slow down flight? I have to make huge maps to make flight works properly.
And is there any way to change the value of horizontal speed loss?
Is there any way to make this work in standard quake without ising fork engines extensions?
Generic Engines
#2587 posted by Spike on 2018/07/14 15:39:49
In theory, if you set the player's movetype to movetype_none in PlayerPostThink, and back to movetype_walk in PlayerPreThink, then you can insert a call to your (renamed) SV_PlayerPhysics at the start of PlayerPreThink and get a similar result.
In practice, doing so would leave you with no way to determine the user's intents (read: the .movement extension). You can work around this by using movetype_noclip instead of the movetype_none above, and to then try to guess the intents according to how the player's velocity accelerated between postthink->prethink (hint: dotproducts, see my earlier post). You'll also need to unwind those noclip-based velocity changes which will require some kind of shadow field, and clearing the velocity field in playerpostthink will make your .movement guessing logic more reliable.
Either way, it'll screw over prediction and get confused by knockbacks.
.gravity exists in all quake engines since hipnotic. You should be able to knock up a min/max function easily enough. I don't think there's anything else in there that's a problem.
Engine Neutral
#2588 posted by Preach on 2018/07/15 21:26:41
My code runs fine in standard quake engines (once you define the .gravity field to enable that feature). You just run it in playerprethink, it uses standard player physics but then just rewrites the velocity each frame.
To slow it down, I guess you could do a number of things. One thing would be to reduce gravity further, even while facing down, so that you can't build up speed so well. Another would be to add a cap to fly_velocity after you calculate it:
if(fly_velocity > MAX_FLY_VELOCITY)
fly_velocity = MAX_FLY_VELOCITY;
Without this, the player can achieve speeds up to the global maximum speed an entity can reach, which defaults to 2000!
Quake1_test
#2589 posted by madfox on 2018/07/17 22:50:04
On Quake Wiki I read the Trivial of the HellKnight.
The intention was to let Rangers spawn when the Hellknight is hit.
The same applies to the Axe_Ogre, which I managed to give some extra postures.
In this case, the Ogre should laugh when someone dies.
A more peculiar fact was pissing on the player's body.
If I were to start coding ... where should I start?
Something like pissing on the player would mean something to the player.qc and ai.qc.
Laughing when someone dies is a more general topic.
Take A Leak
#2590 posted by Qmaster on 2018/07/18 03:23:38
PlayerDeathThink in client.qc, add a while loop that use
spot = find (world,classname,"monster_ogreaxe");
if ( spot ) {
spot.think = ai_leak1;
spot.leakentity = self;
}
Then set goalentity to the leakentity in ai_leak1 and self.enemy to self.leakentity. Do some ai_run()s inside your ai_leak1, 2, 3, etc. check for distance using vlen and start ai_leaking1 when close to player. In ai_leaking1, 2, 3 do your leak anim frames and play a sound effect maybe.
Of Course
#2591 posted by Qmaster on 2018/07/18 03:26:04
You may need to add a .float to act as a bool so that you only check for axeogres in PlayerDeathThink once, something like
if(!foundleakers) {
foundkeakers = 1;
//while loop in here
}
And then in respawn() maybe add a foundleakers = 0; call. You might need to get fancy with coop though.
I...
#2592 posted by Kinn on 2018/07/18 09:13:59
...assumed the idea was that if the ogre killed the player then just that particular ogre would piss on the player, however...
Qmaster is making me think that if the player dies then all the ogres in the map would start making their way over to the player's corpse for a great big ogre gang-corpse-piss-party, and if I'm being totally honest with myself, that idea is too compelling to just pass up.
Laughing Is A More General Topic.
#2593 posted by madfox on 2018/07/18 15:22:38
Let's assume the idea that if the ogre killed the player then all ogres would laugh.
The same a strange way when they're fighting between themselves and all start laughing when the player dies..
So these extra poses would concern the player only.
If I take PlayerDeathThink, and start adding code exact above respawn();
and under the self.button2 = 0;
the new code looks like:
self.button2 = 0;
}
spot = find (world,classname,"monster_ogreaxe");
if ( spot ) {
spot.think = ai_leak1;
spot.leakentity = self;
}
respawn();
};
client.qc:805: error: unknown value "spot".
I know I'm a geek what coding concerns,
no idea how to make a spot statement.
laughing Axe_Ogre
lapaz Axe_Ogre
|