Input delay experiment

Everything todo with programming goes HERE.
gss
Average Program
Posts: 74
Joined: Wed Jun 08, 2005 2:25 pm

Input delay experiment

Post by gss »

I have a project for which I need to research the effect of input delay. As an experiment, I'd like to add a mechanism into armagetronad whereby I can force a programmable delay (in milliseconds) between when a turn key is pressed and when the screen shows the bike moving in the new direction.

I've pulled and compiled the 0.2.8 branch and will experiment with that. Being a total noob to this code, I was hoping somebody could suggest a way to do this.

- gss
User avatar
Lucifer
Project Developer
Posts: 8641
Joined: Sun Aug 15, 2004 3:32 pm
Location: Republic of Texas
Contact:

Post by Lucifer »

Isn't that what lag is? ;)
Image

Be the devil's own, Lucifer's my name.
- Iron Maiden
gss
Average Program
Posts: 74
Joined: Wed Jun 08, 2005 2:25 pm

Post by gss »

A form of lag, yes. I want to experiment with various amounts of predictable input lag... in a local game.
User avatar
Z-Man
God & Project Admin
Posts: 11589
Joined: Sun Jan 23, 2005 6:01 pm
Location: Cologne
Contact:

Post by Z-Man »

Interesting. A simple, but imperfect, way is to abuse the mechanics of CYCLE_DELAY; where user input is processed, you can make the cycle pretend it has done a turn a short time ago, so the next turn will be delayed. The downside of this is that consecutive turns can't be delayed further, so if the desired input delay shall be larger than CYCLE_DELAY, some turns are executed too early. Anyway, here's the code for that:

Code: Select all

REAL sg_inputDelay = 0;
static tSettingItem<REAL> c_st("CYCLE_INPUT_DELAY",
                               sg_inputDelay);

bool gCycle::Act(uActionPlayer *Act, REAL x){
    // don't accept premature input
    if (se_mainGameTimer && ( se_mainGameTimer->speed <= 0 || se_mainGameTimer->Time() < -1 ) )
        return false;

    // crude input delay
    if ( pendingTurns.size() == 0 )
    {
        REAL lastTurnTime = se_GameTime() - sg_delayCycle + sg_inputDelay;
        if ( lastTurnTimeRight_ < lastTurnTime )
            lastTurnTimeRight_ = lastTurnTime;
        if ( lastTurnTimeLeft_ < lastTurnTime )
            lastTurnTimeLeft_ = lastTurnTime;
    }
It goes into gCycle.cpp, you need to modify the start of gCycle::Act to look like that. You'll get a new configuration variable called CYCLE_INPUT_DELAY that controls the delay.
User avatar
Tank Program
Forum & Project Admin, PhD
Posts: 6711
Joined: Thu Dec 18, 2003 7:03 pm

Post by Tank Program »

I wonder if some sort of temporary turn input queue would be practical. That way when you press a key it's put in the queue, with a marker for the time it was, and it's only read off the queue after your x amount of time has passed.
Image
User avatar
Z-Man
God & Project Admin
Posts: 11589
Joined: Sun Jan 23, 2005 6:01 pm
Location: Cologne
Contact:

Post by Z-Man »

Yeah, the perfect way would be to modify su_GetSDLInput() to keep a queue of input events and delay them. The function already conveniently records the time an event came in, you only need to put them into a std::deque< std::pair< SDL_Event, REAL > > and pull them out as desired.
User avatar
MaZuffeR
Core Dumper
Posts: 121
Joined: Mon Nov 07, 2005 2:28 pm
Location: Finland
Contact:

Post by MaZuffeR »

This might be of some help maybe:

http://www.lfsforum.net/showthread.php? ... post319451


It's about input lag in racing sims
winner of: Spoon, 3rd, 6th, 9th, 11th, 18th, 19th, 33rd, 34th and 48th Ladle.
Retired since 07/2012
User avatar
Z-Man
God & Project Admin
Posts: 11589
Joined: Sun Jan 23, 2005 6:01 pm
Location: Cologne
Contact:

Post by Z-Man »

That's interesting, too, but a different subject :) Gss wants to purposefully introduce additional input lag, and that other guy measures one form of natural input lag.

There were a couple of games I didn't play because they had such big amounts of input lag. Most notably here: Tron 2.0. With my current PC, the lag is gone, but back when it was new and fresh and you actually had a chance to meet other players online, it was unbearable unless I turned down the resolution. The worst one was Aquanox. Upgrading my PC didn't help there. Bummer. In both cases, I'm talking about 0.1 to 0.2 seconds of lag. I tend to blame it on Direct3D's lack of a glFinish like function.
User avatar
MaZuffeR
Core Dumper
Posts: 121
Joined: Mon Nov 07, 2005 2:28 pm
Location: Finland
Contact:

Post by MaZuffeR »

Yeah, I guess I didn't read his first post properly the first time :oops:
winner of: Spoon, 3rd, 6th, 9th, 11th, 18th, 19th, 33rd, 34th and 48th Ladle.
Retired since 07/2012
gss
Average Program
Posts: 74
Joined: Wed Jun 08, 2005 2:25 pm

Post by gss »

z-man wrote:In both cases, I'm talking about 0.1 to 0.2 seconds of lag. I tend to blame it on Direct3D's lack of a glFinish like function.
That's pretty much what I want to drill down on. I'm guessing 100ms is reasonable and 200 ms is unreasonable. The big question is, does everybody feel the same way, or does the line where reasonable and unreasonable meet move around for different observers... and if so, by how much.
Tank wrote:I wonder if some sort of temporary turn input queue would be practical. That way when you press a key it's put in the queue, with a marker for the time it was, and it's only read off the queue after your x amount of time has passed.
z-man wrote:Yeah, the perfect way would be to modify su_GetSDLInput() to keep a queue of input events and delay them. The function already conveniently records the time an event came in, you only need to put them into a std::deque< std::pair< SDL_Event, REAL > > and pull them out as desired..
This is exactly the methodology I want to use. Now that you've mentioned the place to insert the queue, what's alluding me is the best way to service the queue. Ideally I implement some sort of timer that I program to pop every x milliseconds, but this seems a bit complicated. It looks like there is already a timer used to get the SDL inputs. Can you give me some hints on how I can use it to dequeue?

- gss
User avatar
kyle
Reverse Outside Corner Grinder
Posts: 1876
Joined: Thu Jun 08, 2006 3:33 pm
Location: Indiana, USA, Earth, Milky Way Galaxy, Universe, Multiverse
Contact:

Post by kyle »

if you are using windows you can write an autoit script that you set your turn keys to hotkeys.
then use a function with the hot keys to pause the script and then send the key. I'm not 100% sure that it will work but i think it runs over everything else.
User avatar
Tank Program
Forum & Project Admin, PhD
Posts: 6711
Joined: Thu Dec 18, 2003 7:03 pm

Post by Tank Program »

I remember from messing with the chat AI that it can run thru an interation each time step and execute turns accordingly. You could have it do this executing moves from the queue regardless whether or not the chat bot is enabled.
Image
gss
Average Program
Posts: 74
Joined: Wed Jun 08, 2005 2:25 pm

Post by gss »

OK, I think I understand how to do this now. For times when su_GetSDLInput would have returned an event, now it should just Q that event. If ever the function is entered and the Q is non-empty, it should only return the next event from the Q if the event happened more than xmilliseconds previously, where x is the number of milliseconds worth of input lag to model.

Correct?
User avatar
Tank Program
Forum & Project Admin, PhD
Posts: 6711
Joined: Thu Dec 18, 2003 7:03 pm

Post by Tank Program »

I would just queue the events for turning, and keep everything else real time, because I don't know when you could play off the other events.
Image
gss
Average Program
Posts: 74
Joined: Wed Jun 08, 2005 2:25 pm

Post by gss »

ok silly question. In uInputQueue, Time() returns 0 because "timer" is 0. How do i use the timer?
Post Reply