VB/C# Hoe kan je een code max aantal x/sec laten uitvoeren.

Status
Niet open voor verdere reacties.

MatthiWare

Gebruiker
Lid geworden
2 jul 2011
Berichten
282
Hallo iedereen,

Ik ben al een aantal dagen aan het zoeken hoe ik mijn code max aantal x/sec kan laten uitvoeren.
Het probleem is dus, ik heb een loop met daarin 2 calls naar methodes. Methode 1 is zeer snel in uitvoeren maar Methode 2 is zeer traag. En methode 2 vertraagt daardoor methode 1.

Een tweede probleem is mensen met een tragere/snellere processor kunnen dus naargelang sneller of trager het meer of minder x/sec uitvoeren wat dus niet goed is.

Dus wat ik zou willen weten is hoe je voorbeeld Methode2 max 30x/sec kunt laten uitvoeren, en Methode1 max 50x/sec

Opgelet het is niet zo dat hij het 30x snel achter elkaar moet uitvoeren en dan wachten tot de volgende second, nee hij zou het moeten kunnen doen dat er ongeveer evenveel tijd tussen zit.

VB
Code:
While(isRunning)
    Methode1
    Methode2
End While

C#
Code:
While(isRunning)
{
    Methode1;
    Methode2;
}

Ik denk dat het beste is om met 'System.Date.Now.Miliseconds', maar let op tragere pc's hebben meer tijd nodig waardoor de tijd tussen de twee groter is en snellere pc's is de tijd ertussen korter.

Hopelijk kan er mij iemand helpen of tips geven.
 
Laatst bewerkt:
Ik heb het in een aparte thread anders zou men GUI vastlopen, maar jij bedoelt waarschijnlijk elke method in een aparte thread steken?
In dat geval zou ik dat kunnen doen maar hoe zou dit er dan kunnen voor zorgen dat het maar een max aantal x/sec wordt uitgevoerd?

En de beide methodes gebruiken een object dat gelocked word, dus zouden ze nog steeds op elkaar moeten wachten.
 
Dat is een implementatie keuze. Ik ken de opzet van je thread natuurlijk niet, maar als je aparte threads gebruikt kun je prima een master thread hebben met synchronisatie.

Ik begrijp niet helemaal wat de basis van je probleem is, maar je kunt zeer eenvoudig ervoor zorgen dat A nooit vaker wordt uitgevoerd dan B. of in een verhouding 2:1. Tenzij je nog een tweede synchronisatie toevoegt is het echter niet eenvoudig dit goed te synchroniseren tussen computers. Je kunt te snelle computers wel vertragen tot een maximum, maar je kunt langzame computers niet versnellen :)
 
Oke om het probleem te verduidelijken,

Ik ben een spel aan het maken.
Gameloop:
- Update (Methode 1) die de input bewegen enzovoort doet
- Render (Methode 2) deze (her)tekent het scherm

Maar bij snelle computers hebben voorbeeld 60 updates per seconde en 30 frames per seconde.
Maar bij tragere hebben maar 30 updates per seconde en 15 frames per seconde.
Wat dus een groot probleem is als ik multiplayer heb speler 1 gaat dubbel zo snel kunnen lopen als speler 2.

Je voorbeeld van 2:1 verhouding heb ik al uitgeprobeerd maar nog steeds zelfde probleem.
Je mag ook niet vergeten dat als hij de render overslaat de updates per seconde zeer snel stijgt.

Voorbeeld als we de 2:1 verhouding zouden doen dan zou hij gemakkelijk 100 updates p/s doen en 10 frames.
 
Bij multiplayer leg je vaak een effective rate (tick rate) vast en stuur je gewoon niet meer updates per seconde (en verwerk je ook niet meer updates). Proberen de server meer updates toe te laten dan eigenlijk nodig zijn is ook wel bekend als een speedhack.

Bij een goede implementatie maakt het niet uit wat de clients individueel uitspoken, de server is de arbitrator tussen invoer en feedback.

Dit is wel een interessant stukje text:

http://www.moreal.org/articles/fpsund.php

Het onderwerp is niet direct gerelateerd, maar het licht wel de interne werking toe van een grote bekende gameserver. Je ziet ook dat bij geavanceerde servers er enorm veel komt kijken om het spel "eerlijk" te houden.
 
Oke maar als je een effective rate zou vast leggen dan zou het spel opeens vast blijven hangen.

Wat ik daarjuist nog ben vergeten zeggen is dat het ook een singleplayer spel is wat dus ook tot 'oneerlijkheden' zou kunnen lijden,
speler #1 kan veel sneller lopen, vechten, ... terwijl het bij speler #2 dan veel trager zou gaan.
 
Veranderd echter niets aan de client / server verhouding, dat kan namelijk nog steeds.

En ja in de praktijk betekend dat dat als je hardware niet aan minimale eisen voldoet je niet meer eerlijk kan spelen. Daarom hebben alle games een set minimale eisen waarmee de makers een eerlijke game garanderen op de laagste settings.

Als je op een oude computer BF3 op ultra settings zet en je gaat klagen dat je niet kan winnen (single -of multiplayer) neemt echt niemand je serieus hoor.

In het stukje text van mijn vorige post wordt dit ook een beetje uitgelegd. Je kunt ook in singleplayer nooit meer tikken hebben dan de gameserver toelaat. Dat betekend dat bij 60 servertikken iemand met een snelle computer dat iets beter kan benutten dan een langzame, maar het verschil is niet altijd drastisch.

Een goede getrainde gamer heeft een reactietijd van ongeveer 50ms. Dat is 20 beslissingen per seconde. Zolang je daar met je minimum eisen boven blijft is de rest opvulling.
 
Oke maar nu is de vraag hoe kan je de code maar een max aantal x/sec laten uitvoeren en de tijd tussen de uitvoeringen moet ongeveer altijd het zelfde zijn.

Ik heb dus al het een het ander gerpobeerd
  • al eens met wat je zei 3 updates en dan pas 1 frame, maar dat is niet goed.
  • eens met het tijdsverschil van (vorigetijd - nu) / ms op te tellen en als deze > 1 is blijven updates doen tot het lager is dan 1. Ook niet goed want je krijgt haperingen.
  • nu ben ik verder aan het proberen met verschillende tijdseenheden een goede manier te zoeken.
 
Rendersnelheid is eigenlijk niet van belang. Je client kan namelijk alleen renderen wat het weet. Stel je hebt een simpel spel waarbij je elke minuut een zet doet. Het maakt niet uit of je elke seconde een update op je scherm krijgt of elke minuut. Zolang het 1 keer per minuut ververst loop je ongeveer synchroon met de realiteit. Dat levert niet echt een oneerlijke situatie op tussen iemand met 1 keer per seconde verversen en 1 keer per 10 seconden.

De server levert X keer per seconde een scene. Of de client dat 5000 keer tekent of slechts 1 keer maakt niets uit. Zolang het minimum maar rond de 30 FPS blijft ontstaat er geen echt oneerlijk voordeel.
 
Toch wel het renderen op zich maakt niet zoveel uit buiten dat het veel tijd in beslag neemt en zo een groot deel van de updates/sec wegneemt.

Toch eventjes voor de duidelijk ik ben hier nog steeds bezig over singleplayer er is dus geen server.

En stel nu dat per tick je mannetje zijn X coördinaat +1 gaat.

als je 1x/sec het scherm renderd dan krijg je iets van een 100 updates/sec wat dus = je mannetje dat per frame 100px * tegelbreedte naar rechts gaat.
Maar als je nu 10x/sec het scherm renderd dan krijg je iets van een 40 updates/sec wat dus ervoor zorgt dat je mannetjes 4px * tegelbreedte naar rechts gaat per frame en je krijgt dan 10 frames per seconde.

Hopelijk is het probleem nu duidelijker aan het worden :)
 
Je denkt verkeerd :)

je "server" (oftewel game engine) bepaald de feedback.

Stel een speler houd de knop voor "rechts" in. De game verstuurd iedere 1 ms de opdracht "rechts" naar de server (game engine)

De server (game engine) honoreert iedere 10ms een request. na 1 seconde is je poppetje 100 "tikken" naar rechts, ook al zijn er 1000 aanvragen voor rechts verstuurd.

Je renderengine op computer A doet 60 FPS, computer B doet 30 FPS. Computer "A" ziet het poppetje iedere refresh 1.7 posities opschuiven. computer "B" ziet het poppetje iedere refresh 3.3 posities opschuiven.

Voor de gebruiker (die slechts 25 FPS kan zien!) zal het poppetje in beide gevallen 4 posities naar rechts schuiven per "update". Na een sconde is het poppetje even ver en voor het gevoel van de gebruiken is er geen verschil in beleving zolang de refresh maar boven de 24 (met enige marge) blijft.

Je moet af van het idee dat je client thread de snelheid mag bepalen.
 
Wacht kijk eens naar het filmpje in mijn handtekening/signature (Terraria VB version)
Dat is dus het spel waar ik het over heb. Het zou goed zijn om de server de snelheid te laten bepalen als het alleen online te spelen is. Maar het is ook offline te spelen en dan moet de client de snelheid wel bepalen.

Ik had zelf eerst niet door dat het snelheidsprobleem er was buiten dan als je fullscreen en niet fullscreen speelde. Tot dat ik het een aantal vrienden liet testen, en zelf op een andere pc heb getest.
 
Je houdt je teveel vast aan server-client als twee computers. Server en client kunnen ook twee threads zijn binnen 1 programma.

Je client thread mag net zovaak draaien als er resources voor zijn, maar je server thread moet draaien met vaste "ticken". Je server thread ontvangt requests van de client en past de spelwereld aan, je client thread mag onafhankelijk van de server thread zo snel lopen als er resources voor zijn, maar de staat van de client thread kan alleen geupdate worden door de server thread. Of beter: de status van de server mag zoveel opgevraagd worden als mogelijk, maar het antwoord veranderd niet tussen "ticken".

Zolang de server thread "licht" genoeg is om fatsoenlijk te draaien op de meeste hardware zou de beleving nagenoeg hetzelfde moeten zijn.
 
Dat is een beetje afhankelijk van hoe het allemaal is opgezet. Aan de demo te zien ben je al bijna klaar. In dat geval zou ik niet herschrijven naar een basismodel.

Je kunt wel een limiter toevoegen zodat er een maximum ontstaat, maar in je filmpje zie ik 17 FPS. dat houd dan niet echt over.
 
Dan misschien toch overschakelen op het idee waarbij de client de snelheid bepaalt? :D
 
Als je een limiter gaat gebruiken zal dat ook in een andere thread moeten. Die thread dat dan niet de game logic maar alleen de ticken. De "CLIENT" is wat de user ziet en doet, het is normaal NIET je gamelogic

Een game zoals een shooter werkt zo:

Master thread:
- neem invoer
- update game wereld
- AI
- Lines of sight
- bereken richting en spread van kogels (indien van toepassing)
- verander health, update inventory, etc.
- tick
- terug naar begin
> geen grafische berekeningen, geen interactie afhandeling. Deze thread moet zo snel mogelijk lopen

User interface thread
- neem invoer
- update situatie
- muziek, sound effects

render engine
- geef wereld grafisch weer aan de hand van de toestand van de master thread
> mag zo vaak lopen als mogelijk, de wereld veranderd aan de hand van de master thread
 
Oplossing

Ik ben zelf tot een oplossing gekomen.

Waarbij ik zelf de gewenste hoeveelheid frames per seconde kan ingeven. vb 30
dan is de min tijd voor elke frame 1/30 = 0.3333333333..3

Dan starten we een stopwatch

berekenen de frame

kijken hoelang de frame tot hier toe al geduurt heeft

Is de frametijd < de min frame tijd dan laten we thread eventjes wachten tot de frametijd >= de min frame tijd is

en dan starten we de volgende loop.

In code zou dat dan zo iets zijn:

C#
Code:
while(isRunning)
{
   Stopwatch loopTimer = new Stopwatch();
    
   Update();
   Render();
  
   While (loopTimer.Elapsed.TotalSeconds < _MinimumFrameTime)
   {
      Thread.SpinWait(10);
   }

   loopTimer.Stop();
}

VB
Code:
while(isRunning)

  dim loopTimer as new Stopwatch()

  update()
  render()

  while loopTimer.Elapsed.TotalSeconds < _MinimumFrameTime
     Thread.SpinWait(10)
  end while
  looptimer.Stop()
end while
 
Status
Niet open voor verdere reacties.
Terug
Bovenaan Onderaan