[C#] Gameloop : Is dit normaal?

Pagina: 1
Acties:
  • 168 views sinds 30-01-2008
  • Reageer

  • Mischa_NL
  • Registratie: Mei 2004
  • Laatst online: 01-02-2023
Ik ben sinds kort bezig in C#.
Leuke taal, iets toegankelijker dan c++ maar ook wel langzamer.

Maar zo langzaam als ik het nu heb lijkt me wel heel sterk!

Ik ben met een loopje bezig die de framerate constant moet proberen te houden op 100 fps.
Hij komt echter niet boven de 64 uit!

Hier de code:

C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
using System;

class testloop
{
    
    private static int intFramesPerSecond   = 100; // framerate in fps

    
    public static void Main() // Entry point
    {
        MainGameLoop();
    }

    private static int GetTickCount()
    {
        return System.Environment.TickCount;
    }
        
    public static void MainGameLoop()
    {

    
        //init some vars :)
        int intCurrentTickCount = GetTickCount();
        bool m_blnSurfacesInitialised = true;
        int framerate=0;
        int i=0;
        int lastsecond = GetTickCount();
        
        //main loop (always true atm)
        while ( m_blnSurfacesInitialised == true )
        {
            //if the number of miliseconds have passed then do all the stuff!
            if (GetTickCount() - (1000/intFramesPerSecond) >= intCurrentTickCount)
            {
                //als seconde voorbij show framerate van de laatste seconde.
                if (GetTickCount() - 1000 >= lastsecond)
                {
                    lastsecond = GetTickCount();
                    framerate = i;
                    i=0;
                    Console.WriteLine("Framerate : {0}",framerate);
                }
                
                //zet framerate van deze seconde op + 1
                i++;
                    
                //get current tick count
                intCurrentTickCount = GetTickCount();
            }
        }
    }
        
}       


Wat maakt deze code zo langzaam? als ik namelijk een writeline buiten de if in de while zet gaat hij als een speer! Zou er een tijdsverschilletje zitten bij de gettickcount ofzo?

Eigenlijk weet ik niet eens of dit wel de manier is om zo een loop te maken. Maar dit leek mij redelijk logisch. Of kan ik het beter anders doen?

Alvast erg bedankt!

Verwijderd

Well, een paar (minimale) optimalisaties die ik zou voorstellen is:

• Niet elke keer GetTickCount() aanroepen, maar voor elke omloop de waarde opslaan in een variabele (scheelt je in elk geval 2 functieaanroepen per omwenteling, en eens per seconde 3).
• 1000/intFramesPerSecond verandert nooit. Je hoeft deze dus niet elke omloop opnieuw te evalueren. Sterker nog, je kunt het als constante meelinken in je executable.
• Slapen als het nog geen tijd is om te ticken! Je sleurt nu 100% CPU vanwege je busy-wait loop en hoewel dat misschien niet erg is als het om een spelletje gaat (want spelletjes ga je toch niet multitasken), vind ik het toch wel zo netjes om een beetje aardig tegen de CPU en andere processen te zijn. Op zijn minst een Sleep(0) om je timeslice op te geven scheelt al een boel in CPU gebruik.

Voor de rest weet ik niet precies wat er mis is met je code. Het lijkt me best okee zo. En het lijkt me logisch dat de framerate als een speer gaat als je hem buiten je if zet: je krijgt dan namelijk een writeln elke tick, in plaats van elke seconde.

  • MrSleeves
  • Registratie: Februari 2004
  • Laatst online: 10-04 19:23

MrSleeves

You'll thank me later.

Heb je het ook al geprobeerd zonder te debuggen (buiten de VS-environment). Scheelt ook behoorlijk wat.

Enne, wat is precies de bedoeling:
Je gaat nu namelijk nooit de 100 ms. halen.
Dat kan nu alleen als alles wat je doet geen tijd kost. Helemaal niets.
Dat doet het natuurlijk wel; de Console.WriteLine kost tijd en de GetTickCount.

Want je gaat nu elke 10 ms i met één verhogen. En dan kijk je na een seconde hoeveel hij geteld hebt.
Als je straks bij de i++ het beeld gaat renderen moet je ook rekening gaan houden met vertraging (die rendering is ook niet gratis) en zal dan aanpassingen moeten doen in intFramesPerSecond.

Op zich is 64 van de 100 een slechte score. Maar de Console.WriteLine i.c.m. debug-mode, zorgen daar o.a. voor.

[ Voor 76% gewijzigd door MrSleeves op 03-02-2005 08:42 ]

30Drie Web Design & IT Consultancy | Raven Consultancy Services


  • Semyon
  • Registratie: April 2001
  • Laatst online: 05:27
Verwijderd schreef op donderdag 03 februari 2005 @ 00:03:
• 1000/intFramesPerSecond verandert nooit. Je hoeft deze dus niet elke omloop opnieuw te evalueren. Sterker nog, je kunt het als constante meelinken in je executable.
Een beetje compiler doet dit zelf al wel hoor tegenwoordig. Als je een constante op een constante deelt moet de compiler toch wel zien dat hij dat al kan uitrekenen. Heb geen ervaring met C#, maar vermoed dat die wel slim is.

En ja, kijk eens wat je framerate is als je niet elke seconde een writeline doet.

Only when it is dark enough, can you see the stars


  • MrSleeves
  • Registratie: Februari 2004
  • Laatst online: 10-04 19:23

MrSleeves

You'll thank me later.

Hmm, vreemd.. debuggen of niet, en dat GettickCount maakt ook niet.

Vaag dit...
Het zit 'm in de eerste If-regel (na de While).. Da's logisch, maaarrr:
Visual Basic .NET:
1
If GetTickCount() > intCurrentTickCount Then

of
Visual Basic .NET:
1
If GetTickCount() >= intCurrentTickCount Then

maakt een wereld van verschil.
Ergens klopt er dus iets niet.

[ Voor 69% gewijzigd door MrSleeves op 03-02-2005 09:13 ]

30Drie Web Design & IT Consultancy | Raven Consultancy Services


  • farlane
  • Registratie: Maart 2000
  • Laatst online: 12-05 20:13
Chief.NET schreef op donderdag 03 februari 2005 @ 08:57:
...en dat GettickCount maakt ook niet...
Niet zo vreemd, dat zijn microseconden waar je over praat. Als jij zegt dat het in de Console zit, dan zal daar iets gebeuren wat die tijd opslurpt. Maw, je moet die framerate op een andere manier laten zien.

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


  • MrSleeves
  • Registratie: Februari 2004
  • Laatst online: 10-04 19:23

MrSleeves

You'll thank me later.

farlane schreef op donderdag 03 februari 2005 @ 09:15:
[...]

Niet zo vreemd, dat zijn microseconden waar je over praat. Als jij zegt dat het in de Console zit, dan zal daar iets gebeuren wat die tijd opslurpt. Maw, je moet die framerate op een andere manier laten zien.
Nope,je bent in de war met DateTime. Daar zijn ticks 100-nanoseconde. (nog steeds geen microseconde).
Maar bij Environment.TickCount staat in de MSDN:
The resolution of the TickCount property cannot be less than 500 milliseconds.

The TickCount property handles an overflow condition by resetting its value to zero. The minimum value returned by TickCount is 0.

TickCount is different from the Ticks property, which is the number of 100-nanosecond intervals that have elapsed since 1/1/0001, 12:00am.

Use the DateTime.Now property to obtain the current local date and time on this computer.
Gaat even om de eerste regel. Dus ik zou zeggen probeer eens DateTime.Ticks. Maakt ook niet uit.

Maar het zit dus niet in de Console en ook niet in het debuggen.

(offtopic: kan er echt niet tegen als ik niet weet waar het zit... B) )

30Drie Web Design & IT Consultancy | Raven Consultancy Services


  • MrSleeves
  • Registratie: Februari 2004
  • Laatst online: 10-04 19:23

MrSleeves

You'll thank me later.

Als je de eerste If verwijdert en aan het eind
code:
1
Threading.Thread.CurrentThread.Sleep(10)

kom je hoger (93 ofzo). Geen idee verder.

30Drie Web Design & IT Consultancy | Raven Consultancy Services


  • farlane
  • Registratie: Maart 2000
  • Laatst online: 12-05 20:13
Chief.NET schreef op donderdag 03 februari 2005 @ 09:23:
[...]
Nope,je bent in de war met DateTime. Daar zijn ticks 100-nanoseconde. (nog steeds geen microseconde).
[...]
Daar doelde ik niet op. Ik bedoelde dat het eenmaal aanroepen van GetTickCount of driemaal niet zon invloed kan hebben op de framerate.

Haal die hele lus voor het showen van de fr eens buiten de lus voor het berekenen van de fr.

[ Voor 12% gewijzigd door farlane op 03-02-2005 09:52 ]

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


Verwijderd

Een aantal tips bij het bouwen van een engine.

Zorg er voor dat er in je mainloop zo minmogelijk staat! (geen berekeningen geen andere onzin en vooral geen console tekst laten printen!)

Als je iets wilt afdrukken doe je dat doormiddel van het laten lopen van een andere thread en daarin de gegevens op het beeld laten afdrukken

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
boolean run = true;

//mainlus
while(run){
    Systemtimepakken1
    Gamecheck();  //voor later
    GameLogica()  //voor later
    GameDraw();
    Systemtimepakken2
    if( Systemtimepakken2 - Systemtimepakken1 < 
                    De tijd die er besteed moet worden){
        Sleep(resterende deel);
    }
}

Als je wilt cappen op een bepaalde framerate kun je in deze lus een 
sleep inbouwen die er dan voor zorgt dat je engine niet sneller kan gaan.


GameDraw(){

Maak in dit stukje code een nieuwe thread aan die er voor zorgt dat er iets 
is het console word afgedrukt of een thread die al draait en waar dan elke 
keer een nieuwe value mee komt vanuit de mainthread. Op deze wijze heeft 
je mainthread geen last van het in het console afdrukken van de gegevens.

}

  • Sjaaky
  • Registratie: Oktober 2000
  • Laatst online: 22-04 07:04
Even een disclaimer, ik heb hier weinig ervaring mee. De code is slechts symptoombestrijding, maar werkt wel.
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
        public static void MainGameLoop()
        {
            //init some vars :)
            bool m_blnSurfacesInitialised = true;
            int framerate=0;
            int i=0;
            int TickCount = GetTickCount();
            int nextFrame = TickCount + 1000/framesPerSecond;
            int nextSecond = TickCount + 1000;
            //main loop (always true atm)
            while (m_blnSurfacesInitialised == true)
            {
                TickCount = GetTickCount();
                if (TickCount >= nextSecond)
                {
                    nextSecond += 1000;
                    framerate = i;
                    i = 0;
                    Console.WriteLine("Framerate : {0}", framerate);
                }
                if (TickCount >= nextFrame)
                {
                    nextFrame += 1000/framesPerSecond;
                    //zet framerate van deze seconde op + 1
                    i++;
                }
            }
        }

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 15-05 03:15

.oisyn

Moderator Devschuur®

Demotivational Speaker

Console output is idd langzaam, update eens wat minder vaak en je zult zien dat het meteen sneller gaat. Daarnaast is GetTickCount is veel te onnauwkeurig voor dit soort doeleinden. Ja, het resultaat is in milliseconden maar dat wil niet zeggen dat ie ook zo nauwkeurig is. Geen idee hoe het zit met de .Net api maar de win32 functie QueryPerformanceCounter is wel een geschikte kandidaat. Daarnaast moet je in je loop steeds maar 1 meting doen van de counter; je werkt in discrete tijd en je bent niet geïnteresseerd in het verschil tussen 2 opéénvolgende aanroepen van GetTickCounts

[ Voor 21% gewijzigd door .oisyn op 03-02-2005 11:11 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 15-05 03:15

.oisyn

Moderator Devschuur®

Demotivational Speaker

Verwijderd schreef op donderdag 03 februari 2005 @ 10:31:
Als je iets wilt afdrukken doe je dat doormiddel van het laten lopen van een andere thread en daarin de gegevens op het beeld laten afdrukken
Uitvoeren naar de console kan prima in de gameloop, het is namelijk niet de aanroep zelf die traag is maar het daadwerkelijk tekenen op het scherm dat wat system-wide lag met zich meebrengt. Het onderbrengen in een andere thread heeft dus niet veel nut, je gameloop thread moet dan nog altijd tijd afstaan om die console-uitvoer-thread z'n werk te laten doen. Daarnaast is het iirc niet eens die thread zelf die er lang over doet; dat wordt namelijk gedelegeerd naar de GDI.

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Verwijderd

Zeker moet er tijd worden afgestaan. Alleen loopt je loop wel door en kan de thread netje de rest van de gevens verwerken. Vooral in een verder stadium van je game kan dit een enorm voordeel opleveren. Nu misschien nog niet maar later zeker wel. Aangezien ik er vanuit ga dat hij een volledige game wil gaan maken is het misschien wel slim om daar nu vast rekening mee te houden.

Het is zo dat binnen het proces (GAME) meerder threads kunnen draaien. Deze threads delen wel de resources van het proces maar kunnen wel naast elkaar bestaan zonder op elkaar te hoeven wachten (of je moet het specifiek zo programmeren). Dat is het mooie van de threads. Op deze wijze kun je de mainthread maximaal de gameloop laten doorlopen!

Voor een eventueel voorbeeld
http://www.dotsphinx.com/software/demo3d/source/
Source code van een 3d spel te downloaden. Wel in C geschreven maar geeft een idee van hoe het kan.

[ Voor 42% gewijzigd door Verwijderd op 03-02-2005 13:31 . Reden: Toevoeging ]


  • Mischa_NL
  • Registratie: Mei 2004
  • Laatst online: 01-02-2023
Sjaaky schreef op donderdag 03 februari 2005 @ 10:55:
Even een disclaimer, ik heb hier weinig ervaring mee. De code is slechts symptoombestrijding, maar werkt wel.
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
        public static void MainGameLoop()
        {
            //init some vars :)
            bool m_blnSurfacesInitialised = true;
            int framerate=0;
            int i=0;
            int TickCount = GetTickCount();
            int nextFrame = TickCount + 1000/framesPerSecond;
            int nextSecond = TickCount + 1000;
            //main loop (always true atm)
            while (m_blnSurfacesInitialised == true)
            {
                TickCount = GetTickCount();
                if (TickCount >= nextSecond)
                {
                    nextSecond += 1000;
                    framerate = i;
                    i = 0;
                    Console.WriteLine("Framerate : {0}", framerate);
                }
                if (TickCount >= nextFrame)
                {
                    nextFrame += 1000/framesPerSecond;
                    //zet framerate van deze seconde op + 1
                    i++;
                }
            }
        }
Perfect!
Hij haalt nu gewoon de 500!
Heel erg bedankt.
Opzich was het best logisch eigenlijk :) .

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 15-05 03:15

.oisyn

Moderator Devschuur®

Demotivational Speaker

CounterForce: Als z'n game in een verder stadium is hoop ik voor hem dat ie een andere manier heeft uitgevonden om dingen duidelijk te maken, aangezien de console daar maar weinig geschikt voor is als alle subsystems vrolijk daarnaartoe aan het schrijven zijn en elk overzicht compleet weg is :)

Daarnaast blijft het debug output, het lijkt me niet dat je die calls in een master build wilt hebben.

[ Voor 3% gewijzigd door .oisyn op 03-02-2005 13:30 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • curry684
  • Registratie: Juni 2000
  • Laatst online: 12-05 22:23

curry684

left part of the evil twins

.oisyn schreef op donderdag 03 februari 2005 @ 11:10:
Geen idee hoe het zit met de .Net api maar de win32 functie QueryPerformanceCounter is wel een geschikte kandidaat.
System.Diagnostics.PerformanceCounter? ;)

Professionele website nodig?


Verwijderd

Voor de liefhebber:

ftp://ftp.idsoftware.com/idstuff/source/quake2.zip

Source code van Q2 engine

Verwijderd

.oisyn schreef op donderdag 03 februari 2005 @ 13:29:
CounterForce: Als z'n game in een verder stadium is hoop ik voor hem dat ie een andere manier heeft uitgevonden om dingen duidelijk te maken, aangezien de console daar maar weinig geschikt voor is als alle subsystems vrolijk daarnaartoe aan het schrijven zijn en elk overzicht compleet weg is :)

Daarnaast blijft het debug output, het lijkt me niet dat je die calls in een master build wilt hebben.
Eens! Ga misschien een beetje teveel op wat er nog allemaal gebeuren moet :) Heb al de Source code van Q2 gepost dat is pas een echte lange en goede leerweg B)

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 15-05 03:15

.oisyn

Moderator Devschuur®

Demotivational Speaker

Carmack & co staan nou niet bepaald bekend om hun softwaredesign skills ;)

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Verwijderd

Oh geloof wel dat ze de beste gameinnovaties hebben verzorgt in de afgelopen jaren....
(Wolvenstein, Doom, q1 , q2 , q3 doom3) op FPS gebied dan.
En vertel mij dan eens dan wat een goede manier is van software ontwerpen?

Wanneer het in de kast ligt? of als het verkocht word en redelijk stabiel is? ID engines worden in meerdere spellen gebruikt (COD, MOH, Jedi Knights, Q4). Dus snap niet helemaal wat je bedoelt met ze staan niet bekent als softwaredesigners.. Als dat namelijk zo is snap ik niet waarom zoveel bedrijven hun engine's gebruiken...

Zag net ook dat je zelf wel eens een spelletje speelt: Snowblind (is dat spel een beetje te pruimen?)

Dus kom even met wat harde argumenten!

Dat zijn goede argumenten! misschien kan .oisyn ons dan nog wat leren van het vak!

[ Voor 16% gewijzigd door Verwijderd op 03-02-2005 14:40 ]


  • curry684
  • Registratie: Juni 2000
  • Laatst online: 12-05 22:23

curry684

left part of the evil twins

Dat de auto hard kan rijden en er mooi uitziet betekent nog niet dat de motor een toonbeeld is van goede werktuigbouwkunde of dat mindere goden onderhoud op het ding kunnen plegen.
Verwijderd schreef op donderdag 03 februari 2005 @ 14:27:
Zag net ook dat je zelf wel eens een spelletje speelt: Snowblind (is dat spel een beetje te pruimen?)
psst, die regel in z'n sig is het project waar ie op dit moment de 3D-engine van aan het ontwikkelen is voor z'n werk ;)

[ Voor 50% gewijzigd door curry684 op 03-02-2005 14:32 ]

Professionele website nodig?


  • Sjaaky
  • Registratie: Oktober 2000
  • Laatst online: 22-04 07:04
Mischa_NL schreef op donderdag 03 februari 2005 @ 13:28:
Perfect!
Hij haalt nu gewoon de 500!
Heel erg bedankt.
Opzich was het best logisch eigenlijk :) .
De anderen hebben trouwens ook een punt over de precisie van GetTickCount. Als ik een loopje maak en daarin GetTickCount uitprint krijg ik 50 regels met hetzelfde getal, daarna verspringt het getal met ongeveer 10. Daarom gaat het fout als je in de loop 4x GetTickCount aanroept. Als je iedere keer dezelfde waarde terug krijgt is er niets aan de hand, maar soms zit er dus een sprong van 10 tussen.

Bij mij was de max framerate 100 (=1000/ sprongetje van 10)

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 15-05 03:15

.oisyn

Moderator Devschuur®

Demotivational Speaker

Verwijderd schreef op donderdag 03 februari 2005 @ 14:27:
Oh geloof wel dat ze de beste gameinnovaties hebben verzorgt in de afgelopen jaren....
(Wolvenstein, Doom, q1 , q2 , q3 doom3) op FPS gebied dan.
Hey, de engines van id zijn idd stuk voor stuk juweeltjes als het gaat om kwaliteit en optimalisaties. Software design, dus hoe de code eruit ziet, welke functies en classes gebruikt worden, hoe modulair het is, etc., zijn echter hele andere dingen. Uit mijn ervaring met de Q1 en Q2 sourcecode weet ik dat Carmack nou niet bepaald duidelijk en eenzijdige code schrijft. Het is snel en geeft goede resultaten, en dat is waar het voornamelijk om gaat in de gamedevelopment wereld, maar dat maakt het niet meteen geschikt voor een nog niet gevorderde programmeur om van te leren. Als je iets wilt weten over low-level optimalisaties en 3D engines zijn ze zeker de moeite waard om naar te kijken, maar (low-level) optimaliseren is over het algemeen de laatste stap in development. Iets met "premature optimizations are the root of all evil" ;)
Zag net ook dat je zelf wel eens een spelletje speelt: Snowblind (is dat spel een beetje te pruimen?)
Spelen doe ik het ook weleens ja, m'n code moet ook getest worden :P
curry684 schreef op donderdag 03 februari 2005 @ 14:31:
psst, die regel in z'n sig is het project waar ie op dit moment de 3D-engine van aan het ontwikkelen is voor z'n werk ;)
Niet helemaal, voor snowblind ben ik nog een manusje-van-alles omdat ik er rijkelijk laat bij ben gekomen, ik heb wel wat aan de engine gesleuteld maar 't mag geen naam hebben ;). Als snowblind af is word ik wel full-time op de next-gen engine gezet

[ Voor 17% gewijzigd door .oisyn op 03-02-2005 15:03 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Verwijderd

.oisyn schreef op donderdag 03 februari 2005 @ 14:57:
[...]

Spelen doe ik het ook weleens ja, m'n code moet ook getest worden :P
Ik wil ook wel testen :P
Zat net al op je site te kijken en zag dat je een aardig druk bestaan hebt.

Helaas heb alleen nog maar mogen genieten van het maken van spellen met generieke componenten. Een aardig onderzoek waarbij ik het moest stellen met J2ME. Nu helaas geen tijd meer om zelf engines te schrijven. Misschien ooit nog :)
Veel suc6 met de engine trouwens!
Pagina: 1