Page 2 sur 10

Publié : dim. 15/mars/2009 19:20
par cha0s
@Ollivier nana le prend pas comme sa ^^'

c'est juste que en général on pense en premier au performance du jeux. Et bon sur les machines récentes on a deux cœurs (voir plus pour ceux plein de sous) alors si on en monopolise un je trouve pas sa très grave ^^'. Après pour un simple pong le "delay(1)" est logique.

Publié : dim. 15/mars/2009 19:59
par Backup
Norswap a écrit :
Dobro a écrit :ps : on dit UN sprite !

la regle en français, c'est de privilégier le masculin, lorsqu'on ne sait pas ..

:)
Ca sonne moins bien pourtant, je pense que je vais persévérer dans mon vice ^^
si tu veux continuer a avoir l'air "out" !! (je suis gentil là)
tiens , une idée , tu pourrai aussi dire:

une cheval , une tabouret , une avion , une homme et meme pourquoi pas , UN femme

bref , ta réponse , m'indique ton grand potentiel , je sens qu'a ce train
on va se marrer dans quelques mois ! :?

tiens pour ta culture :

http://fr.wikipedia.org/wiki/Sprite_(jeu_vid%C3%A9o)

Publié : dim. 15/mars/2009 20:09
par tonton
Heureusement pour Norswap, qu' il na pas dit "Une Dobro!!" :roll:

en parant de vice, j' en connais pas mal qui dise UN vis!!

Publié : dim. 15/mars/2009 20:12
par Backup
tonton a écrit :Heureusement pour Norswap, qu' il na pas dit "Une Dobro!!" :roll:

en parant de vice, j' en connais pas mal qui dise UN vis!!
ben !! c'est clair !!! :lol: meme pas en reve :)

ce qui m'a gonflé c'est surtout le coté obtus de sa réponse

mais bon , il fait comme il veux hein ... :) au fond ; j'men fou

mais je l'épingle sur ma liste noire !! :lol:

Publié : dim. 15/mars/2009 20:22
par Anonyme
Ah ben bien sûr! Et comme par hasard le seul abruti à avoir posté un code d'exemple qui marche complètement, ben c'est moi!!
Ta pas pris tes médocs ? j'ai même pas vu ton code... :?

Publié : dim. 15/mars/2009 21:08
par Ollivier
Cpl.Bator a écrit :Ta pas pris tes médocs ? j'ai même pas vu ton code... Confused
Et la France battait ses records de consommation en anxiolitiques...

Ben... En tout cas, j'ai mis quelque chose de clair avant, et puis surtout après ta remarque. A mon avis, c'est une base essentielle que nous négligeons souvent.

D'ailleurs, si toi, ou un Linuxien pouvait vérifier la véracité du petit code plus bas (celui qui mesure le différentiel minimum entre 2 ElapsedMilliseconds()... ), ça me ferait plaisir de savoir s'il fonctionne pareillement sous µsoft comme sous Linux.

Sous Linux, vous pouvez peut-être même avoir carrément plus efficace que sous Windows en matière de Timer. Une femme nommée Diana Gruber avait fait un ouvrage ("Programmation des jeux d'arcade en C") montrant comment user du Timing matériel sur les jeux sous Dos (mode réel). Alors, si vous pouvez modifier (provisoirement, j'entends) la table des interruptions (comme les virus le font d'ailleurs...) pour y rajouter l'adresse de votre propre procédure principale de jeu et réajuster la pile (Registre ESP) (Cf Code ASM IRET = Interruption RETurn) à chaque retour d'appel. C'est le matériel même qui fait exécuter votre boucle principale.

Une accélération de la fréquence d'appel du Timer en plus de cette modif, et vous (chers Linuxiens!), seriez alors les as du jeu fluide !(hors Windows, cela s'entend...). Dans ce cas (si l'écriture de la table des interruptions ne vous entraîne pas une error d'exception), nul besoin d'utiliser ton modèle de procédure principal. Mais bon... Peut-être que je fantasme... Je vais prendre mes médocs... Norswap! Gerbe mes boules rouge stp! :D

de l'assembleur avec plein de goto, c'est rigolo

Publié : dim. 15/mars/2009 23:06
par beauregard
Dobro a écrit :ben le moniteur CPU fonctionne bien avec japbe et la v 4.30 :)
merci, je viens d'installer la dernière version( parce que la mienne remontais à 2007, c'est peu de dire que je ne l'utilise pas)... et le moniteur est bien là, ouf :)
Norswap a écrit :Le Delay(16) aide effectivement a diminuer l'usage cpu, mais l'image est moins fluide, tandis qu'à 1 l'impact est minimal sur l'usage cpu. En fait 8 est un assez bon compromis je trouve.

Sinon je préfère rester en fenêtré pour le moment, le jeu étant censé être quelque chose d'assez réduit. En plus, c'est plus facile pour tester :)
beauregard a écrit :je n'ai plus accès au moniteur CPU, c'est moi ou spécifique à la version 4.30 ?
Tu peux aussi utiliser le moniteur de performances de Windows (avec ctrl+alt+delete) qui a l'avantage de moins oscillier.
merci, c'est effectivement plus stable comme outil, chuis con des fois moi. Le problème du jour, fait en réalité suite à un éternel débat sur l'utilisation de ce delay. Ma dernière conclusion c'est qu'il ne faut pas l'utiliser. Mais face à tes tests, ben j'ai décider de me remettre en question:

test avec le jeu vers l'infini, temps cpu:
sans delay -> 99% max
avec un delay( 8 ) -> 54% max
avec un delay(10) -> 44% max
avec un delay(12) ->36% max
avec un delay(16), çà rame, chute de fps donc fin de l'exprérience
http://www.purebasic.fr/french/viewtopi ... 4963#94963

Sur ma 2eme machine, bien plus ancienne, çà tourne à 54 i/s de manière fluide avec un delay(12), alors je retiens cette solution :)

Les explications des différents intervenants sont intéressante...

tonton à mis un delay(20) et déconnecté un delay(10), pour son jeu( un jeu complet qui plus est):
http://www.purebasic.fr/french/viewtopi ... sc&start=0
Comme quoi, même les meilleurs peuvent, heu, réfléchir grandement sur cette petite commande. L'avis de tonton sur ce sujet sera des plus précieux...

Publié : lun. 16/mars/2009 0:05
par Norswap
Ollivier a écrit :@ChaOs

Ce que j'ai écrit est donc une connerie?

Ollivier
Pas la peine de s'enflammer (ca vaut pour ton message précédent aussi) , ils essayent juste d'aider.

Publié : lun. 16/mars/2009 6:26
par Ollivier
Norswap a écrit :Pas la peine de s'enflammer etc...


@ Norswap



En conclusion moins hâtive, si tu veux contrôler les ressources CPU compatible, ce que j'ai écrit en page 1 (et première "inflammation" ou "ignition", je ne sais pas exactement comment l'exprimer, mais au moins c'est repérable pas la manière dont j'ai présenté l'explication!) est une méthode qui, à mon avis n'a pas d'égal.

Sous XP (ChaOs, Cpl.Bator ou d'autres personnes possédant aussi Linux pourront te renseigner bien mieux que moi pour Linux), au moins sous XP, l'OS apprécie de convention qu'on lui rende la main de manière amiable grâce à l'instruction Delay(n) avec n en milliseconde(s). L'OS étant le "supérieur", c'est lui qui décide quand est-ce qu'il te rend la main. La seule chose est que si toutes les applications en parallèles fonctionnent dans les normes (ce qui n'est pas toujours le cas), et s'il n'y a pas un nombre trop important d'applications en arrière-plan, l'OS te rend la main à intervalles réguliers.

Sans ton application (ou ton jeu), l'OS a toujours la main (signes "-"), et, parce qu'il est conçu ainsi, il nécessite la main de manière irrégulière (signes "X")

Code : Tout sélectionner

-----------|----XXXXXX|----XXXXXX|---------|---------|----> t
           t0         t1         t2        t3        t4
Chaque intervalle fait environ 15ms. Je vais appeler cet intervalle le différentiel minimum. Si tu as un doute sur sa valeur, teste le code page 1 (à ce propos j'y reviendrai) sur ton PC pour obtenir éventuellement une autre valeur.

Avec ton application légère en ressource, "O" représente ce que ton application consomme ("D" symbolise d'une part ce qu'elle consomme, d'autre part le fait qu'elle rende la main à l'OS avec l'instruction Delay).

Code : Tout sélectionner

Repeat ; Application légère en ressources
Delay(1)
ForEver

Code : Tout sélectionner

-----------|OD--XXXXXX|OD--XXXXXX|OD-------|OD-------|OD--> t
           t0         t1         t2        t3        t4
Entre t0 et t1, ton application va consommer peut-être 1%, sur un CPU à 1GHz, 0.1% sur un double coeur de 2GHz, etc... Mais l'OS ne te rendra pas la main, comme tu l'as précisé (1ms en argument dans le Delay): il maintiendra son rythme et te le rendra environ 15ms plus tard. Résultat :
l'argument de 1ms dans le Delay() est une durée minimum.

Au fur et à mesure que tu rajoutes des instructions de contrôle et de mise à jour, tes ressources consommées vont augmenter.

Code : Tout sélectionner

-----------|OOOOOOD---|OOD-------|OOOOD----|OOOOD----|D---> t
           t0         t1         t2        t3        t4
Maintenant, pour bien comprendre la notion de plantage de jeu (ou d'application), on va garder les proportions (nombres de "O", de "-", etc...) du schéma juste ci-dessus, et on va le mettre dans la plus partageuse des réalités électroniques...
En effet, comme dit ChaOs, ça n'est pas forcément la mer à boire. Ben, il a raison: il ne travaille pas que sous Windows!!

Parce que le Windows qui se chatouille tout seul sans prévenir de temps à autre, ça donne ça:

Code : Tout sélectionner

-----------|OOOOOODXXX|XXX-------|OODXXXXXX|OOOOD-----|D---> t
           t0         t1         t2        t3        t4
Et ça, c'est un idéal, car la réalité, c'est que, malgré ce que l'on pense, XP est désormais un OS expérimenté donc il ne plante que très rarement.

Pourquoi? Parce que ses fabricants ont mis une tolérance très large...

Code : Tout sélectionner

-----------|OOOOOOD---|XXXXXX----|---------|XXXXXX-----|OOD-> t
           t0         t1         t2        t3        t4
...Et donc évidemment très prenante pour ton application si elle ne respecte pas une consommation maximum...

Code : Tout sélectionner

-----------|OOOOOOO---|XXXXXX----|YYY------|XXXXXX-----|OOOO> t
           t0         t1         t2        t3        t4
...Très large donc pour rajouter des protocoles de vérification d'intégrité (signes Y) et parfois...

Code : Tout sélectionner

-----------|OOOOOOD---|XXXXXX----|YYYRR----|YYYRR----|XXXX> t
           t0         t1         t2        t3        t4
...que ce soit dans ton application, ou dans une autre, il n'y a plus d'intégrité! Dans ce cas, il y a réparation (signe R), qui comprend une analyse, un annulation respective jusqu'à un retour d'intégrité avec éventuellement une invite pour signifier qu'une erreur est survenue, dans une autre application, etc...

Si, pendant ce temps-là, tu étais train de défoncer Billy The Skeleton à coup de M79, tu n'apprécies pas trop, que l'explosion fatale reste figée, et que Billy ne se retrouve pas au sol, comme tout le monde à l'écran depuis 10 minutes non-stop. De surcroît, tu vas instinctivement rester appuyé sur la détente de ton arme (touche Espace ou autre) pour lui remettre une deuxième mandalle. Résultat: En plus d'une réparation d'un bug qui n'est pas de ton ressort, Windows risque de te dire "Coco tiens-toi tranquille 100ms stp ou je te colle un plantage du bâton de plusieurs secondes!!". Cela n'a bien entendu pas de frontière de compilateur! Pour éviter cette conflictuelle, en PB, un Delay(1) sans condition est obligatoire. (Information généreusement offerte, page 1 par HuitBit)

Et si tu respectes cette douce règle de t'en tenir à environ 2 cycles de l'OS dans tes jeux, comme dans tes applications, (env. 32ms = 30Hertz), l'OS ne t'appellera jamais (ou très rarement) "Coco". Donc deux instructions Delay(1) sont à placer quelque part dans ta boucle principale...(Ou 1 Delay(16) )

Il n'y a rien besoin d'autre pour qu'un jeu ou une application garde la même vitesse générale sur 36 bécanes diverses à 36 vitesses différentes (au moins sur XP) :

60 Hertz environ pour 1 cycles OS (on ne gère pas grand chose + ralentissement à 30 Hz avec risques "Coco" de temps à autres)
30 Hz~ pour 2 cycles OS(on gère pleins de choses + régularité)
20 Hz~ pour 3 cycles OS(saccades visibles)

Avec
1 cycles OS = 1 instruction Delay(1)
2 cycles OS = 2 instructions Delay(1) ou une instruction Delay(16)
3 cycles OS = 3 instructions Delay(1) ou Delay(1)+Delay(16) ou Delay(33)

Remarques:
Un Delay(2) = Delay(1)
Un Delay(3) = Delay(1)
Etc...
On a :

Code : Tout sélectionner

Delay(F(n) )
Avec :

Code : Tout sélectionner

Procedure.I F(n.I)
   Protected Result.I
   Result = 16 + n - n % 16 
   ; Délai réel = 16 + Délai théorique - (Délai théorique modulo 16)
   ; Résultat précis à + ou - 3%
   ProcedureReturn Result
EndProcedure
Donc, pour info, si Tonton a mis un Delay(10) quelque part (je vois ça en lisant le message de Beauregard...), avec toutes mes plus plates et mes plus profondes excuses, ainsi qu'avec mon plus grand respect envers lui comme envers les autres, il s'est planté...

Il a pris en considération que sa boucle principale tournait dans un de ces trois cas:
soit durant 6ms sur 1 cycle OS de ~16ms à ~40% de conso CPU
soit durant 23ms sur 2 cycles OS de ~33ms à ~68% de conso CPU
soit durant 37ms sur 3 cycles OS de ~47ms à ~78% de conso CPU
(je mets les 3 cas parce que je n'ai pas vu son code)

Or, sur mon PC sans doute plus lent que le sien (on va être gentil, on va inventer, on va dire 2 fois plus lent), je pourrais obtenir quelque choses comme:

12ms sur 2 cycles OS de ~33ms à ~37% de conso CPU ; Incompatibilité
46ms sur 3 cycles OS de ~63ms à ~75% de conso CPU ; Incompatibilité
74ms sur 5 cycles OS de ~94ms à ~80% de conso CPU ; Incompatibilité

Dans le premier cas, mon PC exécute 2 fois plus lentement.
Dans le deuxième cas, mon PC exécute 1.5 fois plus lentement.
Dans le troisième cas, mon PC 1.6 fois plus lentement

Pourtant, s'il avait mis "Delay(1)"
J'obtiendrais sur mon PC deux fois plus lent:
12ms sur 1 cycles OS de ~16ms à ~75% de conso CPU ; Compatible
46ms sur 3 cycles OS de ~47ms à ~98% de conso CPU ; Incompatibilité
74ms sur 4 cycles OS de ~80ms à ~94% de conso CPU ; Incompatibilité

Dans le cas où son jeu ne bouffe qu'un cycle par boucle (on va admettre que c'est ce cas de figure pour comprendre les deux autres : on y reviendra), il est compatible avec mon PC puisque, même 2 fois plus lent, il lui faut le même nombre de cycles OS (1 cycle OS, soit une fréquence de 60 Hertz) que sur le sien. Seul inconvénient, mais lui n'y pourra rien a priori : mon PC va bouffer 75% de ressources contre 40% pour le sien.

Alors Tonton (bon, excuse-moi Tonton, j'invente une fiction romanesque pour me faire comprendre correctement par un large public sur cette subtilité technique...), ébahi à l'idée que je puisse bouffer autant de ressources me dit "Ne t'inquiète pas Ollivier, je suis un malin. Je peux bien enlever 2 ou 3 bricoles pour que tu uses de moins de ressources sur ta grosse dau... ton PC un peu plus ancien!"

Moi, gourdin en main de découvrir un jeu aussi puissant fonctionner soudain sur mon PC, j'exclame ma joie : "Merci Tonton ! Youpi! C'est génial !"

Mais là, c'est Tonton qui fait la gueule: sur son PC, le jeu allégé de quelques détails et le Delay() réglé à 1, il fonce beaucoup trop vite et est injouable...

Alors là, magie de la providence, simple hasard, ou bien illumination shadokienne, je n'en sais rien, je lui porte ce conseil à l'oreille:
"Mais Tonton, tu peux peut-être rajouter un deuxième Delay(1) tous les x boucles, et ce "x", tu le calcules en début de jeu, avant la boucle principale!"

Résultat des courses : Tonton est content sur son 2GHz, et moi je suis content sur ma grosse daube.

Fin de l'histoire.

Petit apparte concernant les critiques susceptibles de naître quand à mon bon conseil de prôner une gestion à 30 Hertz (2 cycles OS) plutôt qu'à 60 Hertz (1 cycle OS), les gens qui, bien évidemment souhaiterait me prouver (par du code, cela va de soi) que j'ai tort peuvent toujours essayer : avant qu'ils perdent du temps à, je le répète essayer de prouver que j'ai tort (de ne jamais travailler à plus de 30 Hertz) (Pour qu'ils m'évitent de perdre moi-même du temps à devoir leur répondre par un code qui leur montre qu'ils ont tort définitivement), qu'ils comprennent juste ma douleur d'être à ce point aveugle :
- Quand je me prends des baffes en pleine tronche à 25 Hertz, je les sens toutes, sans exception, cependant, même les yeux ouverts et le plus sobrement du monde, je n'en vois aucune, ni arriver, ni repartir, et cela, bien évidemment sans exception : Persistence rétinienne oblige, le reste n'est que marketing matériel déviant tranquillement mais bêtement vers les logiciels. J'espère que cette compassion suffira.

Concernant le différentiel minimum, les fameuses 15 (ou 14, ou 16 ms) millisecondes que j'évoque tout au long de ce tutoriel, j'ai fait un code tout bête pour le mesurer donc page 1.
Je peux le remettre là même, ça ressemble à ça:

Code : Tout sélectionner

Depart = ElapsedMilliseconds()
Delay(1)
Fin = ElapsedMilliseconds()
Debug Fin - Depart
Alors, ta réflexion "Ne t'enflamme pas, ils veulent aider, etc..."... Mh... Je la connais quand même la bande à Basile: vu qu'il y en a aucun qui m'a posté "Oh! Beuh... ouais! Sur mon PC j'ai aussi 15ms! Tiens... Donc pas besoin de se souler à faire ci et ça, etc...", voire (là, c'est de l'ordre du fantasme chronico-utopique) "Génial!", ou autre, moi je n'ai aucun doute sur leur plus grande motivation à plutôt vouloir se poiler la gueule, quite à ce que toi, tu n'avances pas de suite sur cette question précise de perf (et donc de compatibilité "multi vitesse"), et juste pour dire qu'ils en ont rien à foutre de casser du processeur depuis des années!!". Ils m'en apprennent tous les jours, je leur en apprends aussi de temps en temps : c'est ça aussi la magie d'un forum. Si on ne peut plus mettre à poil les gens qui te mettent à poil, où serait le plaisir!?! Maintenant, à cause de ce sujet, j'espère bien que 95% des gens qui vont réussir à le lire entièrement vont mettre à jour leur noyau (boucle principale), comme ça je pourrais peut-être enfin exécuter un tout petit peu plus de sources "open" sans en avoir à faire la recherche de la boucle principale, galérer en me disant "encore un punaise de punaise de bourrin..." et puis renoncer.

Alors, je t'explique le mode d'emploi du cas Ollivier.
1) Sélectionner son code publié dans le forum (il n'y a qu'ici) sans en oublier ni la première, ni la dernière ligne
2) Appuyer sur Ctrl-C
3) Retourner dans ton éditeur
4) Cliquer sur "Nouveau" dans l'éditeur, puis cliquez sur la feuille
5) Appuyer sur Ctrl-V
6) Appuyer sur F5

Tu vois, cette règle est valable pour un de mes codes de 4 lignes comme de 40, 400 ou 4000 lignes. Elle est valable, aujourd'hui comme demain, dans un an, dans dix ans, et tout cela si le Ciel le veut. Mais il n'y aura jamais plus compliqué à attraper pour que le fruit s'affiche à ton écran.

Si tu comprends cela, tu as tout compris du cas Ollivier. Simple (là, devant ce mot, tu en as au moins 10 qui se marrent...)

Alors toi, fais-moi plaisir, au lieu de me couler gaiement et surtout, inutilement, teste les codes que je poste: au moins le tout dernier!!! Celui-là, juste ci-dessus ne fait pas 25000 lignes!! C'est un minimum de le tester et de donner un réponse qui puisse être commentée: quel nombre vois-tu s'afficher ?

Publié : lun. 16/mars/2009 10:24
par cha0s
@Olivier
j'ai testé ton code
sous Windows j'ai
Qté de boucles effectuées : 1
Différentiel (en ms) = 15
et sous linux
Qté de boucles effectuées : 1
Différentiel (en ms) = 1
le Windows est un core 2 duo a 2.2ghz et le nux un pentium M(dérivé du P4 pour portable) a 1.7ghz mais il tourne a 700mhz en moyenne (je sait pas si ce genre d'optimisation d'économie d'énergie existe sous Windows)

Je connait pas le noyau de Windows mais sous nux l'OS privilégie les applications possédant une interface quelconque vers l'utilisateur, après c'est une question de priorité et l'ordonnanceur distribue équitablement les temps (quantum) d'exécution c'est le principe d'un système multi-taches . Seul bémol quand on veut accéder a des périphériques partagé (comme par exemple le disque dur) le temps d'exécutions devient aléatoire, je suppose qu'il en est de même pour la carte graphique qui doit être gérée par le serveur X(la sur couche qui gère l'interface graphique sous linux).

Sinon j'ai lue un articles récemment qui parlait du frame rate. http://www.nofrag.com/2003/nov/24/8629/ si vous avez deux seconde je vous conseille d'aller y faire un tour.

Publié : lun. 16/mars/2009 11:20
par Backup
cha0s a écrit : c'est une question de priorité et l'ordonnanceur distribue équitablement les temps (quantum) d'exécution c'est le principe d'un système multi-taches .
celui qui distribut équitablement c'est le system multitache Préamptif !
comme le Multitos , Amos, MagiC ,etc ..
de plus on pouvais détourner les interruptions hard (Hbl,VBL)
pour synchroniser un prg .... ha la belle epoque des hard scroll ;)

le multitache Coopératif , lui attends, que les applications rendent la main !!

c'était le cas de windows 3.11 , et 95,98 (d'ou la presence de la fonction DO EVENT en visual Basic , et de DELAY()en PureBasic
une application qui gardait la main, pouvais bloquer le systeme !!

d'ailleurs a ce propos sur Atari Falcon030 on se foutais de la gueule des windAube de l'époque, parceque si tu mettais une musique d'intro de 5 minutes sur windows, au moment du boot, ben fallait attendre 5 minutes pour voir apparaitre le bureau !!
justement parceque la tache qui s'occupais de jouer la musique gardait la main !! :lol:

Sur Falcon030 , le Hard etait geré de façon parallèle et independant,(DSP) ce qui fait que meme sans le system d'exloitation multitache , tu pouvais mettre un morceau de 5 minutes, au boot, ton bureau apparaissait , tout en continuant d'entrendre ta musique d'intro ! :)


depuis XP , il me semble que le multitache est un compromis entre les 2 system

bref, c'est batard ! :)
d'ou cette imprecision , dans le system
la seul chose sur lequel on puisse compter, c'est peut etre l'horloge !! :lol:
et encore pas sur !!

Deux, c'est mieux qu'une.

Publié : lun. 16/mars/2009 12:01
par beauregard
Ollivier a écrit :Donc, pour info, si Tonton a mis un Delay(10) quelque part (je vois ça en lisant le message de Beauregard...), avec toutes mes plus plates et mes plus profondes excuses, ainsi qu'avec mon plus grand respect envers lui comme envers les autres, il s'est planté...
non, tu as lu trop vite. Je te remet le lien de son code( j'avais précisé qu'il avait déconnecté le delay(10) ):



le code de tonton, ici, là:http://www.purebasic.fr/french/viewtopi ... 14&start=0


Ollivier a écrit : Avec
1 cycles OS = 1 instruction Delay(1)
2 cycles OS = 2 instructions Delay(1) ou une instruction Delay(16)
3 cycles OS = 3 instructions Delay(1) ou Delay(1)+Delay(16) ou Delay(33)

Remarques:
Un Delay(2) = Delay(1)
Un Delay(3) = Delay(1)
Etc...
Heu..., pour résumer tu pense alors qu'il faut 2 delay(1), bon ben c'est cool, hum, grat, grat. Oui, alors où je dois le mettre moi, ce 2eme delay ?

Code : Tout sélectionner

; ******************************************************************************************************
Repeat ; Boucle principale
; ******************************************************************************************************
 Event= WindowEvent ()
 
  If CreateImage(0,26,20)
    StartDrawing(ImageOutput(0))
      Box(0,0,26,20,RGB(255,255,255))
      Circle(13,10,5,RGB(255,0,0))
    StopDrawing()
    SetClipboardImage(0)
  EndIf
   
 ;Event= WaitWindowEvent (100)
 Start3D(); on place cette commande dès le début de la boucle principale. 
 
 ExamineKeyboard ()

; °°°°°°°°°°°°°°°°°°°°°°
;- Commandes: °°°°°°°°°°°° 
If manette=1:ExamineJoystick(0):EndIf
; °°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°
If pause=0:ReleaseMouse(0); on récupère la souris pour le jeu
  ExamineMouse()
EndIf
If pause>0:ReleaseMouse(1):EndIf; on libère la souris
If manette=0
  If KeyboardPushed ( #PB_Key_P ) And pause=0:pause=1:EndIf
  If KeyboardPushed ( #PB_Key_P )=0 And pause=1:pause=2:EndIf
  If KeyboardPushed ( #PB_Key_P ) And pause=2:pause=3:EndIf
  If KeyboardPushed ( #PB_Key_P )=0 And pause=3:pause=0:EndIf
EndIf
If manette=1
  If JoystickButton(0,8) And pause=0:pause=1:EndIf
  If JoystickButton(0,8)=0 And pause=1:pause=2:EndIf
  If JoystickButton(0,8) And pause=2:pause=3:EndIf
  If JoystickButton(0,8)=0 And pause=3:pause=0:EndIf
EndIf
; °°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°
directionX=0:bouton1=0
If manette=0
  If KeyboardPushed ( #PB_Key_Right ):directionX=1:EndIf ; droite.	
  If KeyboardPushed ( #PB_Key_Left ):directionX=-1:EndIf ; gauche.
  If KeyboardPushed ( #PB_Key_X ):bouton1=1:EndIf ; bouton action
EndIf
If manette=1
  If JoystickAxisX(0)=1:directionX=1:EndIf ; droite.	
  If JoystickAxisX(0)=-1:directionX=-1:EndIf ; gauche.
  If JoystickButton(0,1):bouton1=1:EndIf ; bouton action    
EndIf
; °°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°° 
;- étapes: °°°°°°°°°°°°    
If etape=0; *******
  Affichageintro()
EndIf

If etape=1; *******
  Affichagelevel(); dans cette procédure -> fabrication des étoiles et des brutes
EndIf

If etape=10; ******* 

  ;- fond étoilé
  Affichagetoile()
  
  Affichsoucoupe()
 
  If extra=1 Or extra=2:Fsoucoupe(extra):extra=10:EndIf; ordre de Fabrication clone soucoupe volante

  AffichagebruteA() ; ordre d'affichage des clones bruteA.
  AffichagebruteB() ; ordre d'affichage des clones bruteB.
  AffichagebruteC() ; ordre d'affichage des clones bruteC.
  ordretirbrute=0

  Affichagetirbrute() ; ordre d'affichage des clones tirs brute.
  
  Affichageship(); vaisseau du joueur
  Affichagescorep()
  Affichagelifeup()
    
  ;- changement de niveau, explication:
  ; pour le 1er niveau, il y a 16 brutesA à détruire.
  ; pour le 2eme niveau, il y a 8 brutesA et 8 brutesB à détruire.
  ; pour le 3eme niveau, il y a 16 brutesA et 8 brutesB à détruire.
; 4 niveau-> Boss( non effectif)  
  ; pour le 5eme niveau, il y a 16 brutesB à détruire.
  ; pour le 6eme niveau, il y a 8 brutesB et 8 brutesC à détruire.
  ; pour le 7eme niveau, il y a 8 brutesA et 8 brutesB et 8 brutesC à détruire.  
; 8 niveau-> Boss( non effectif)  

  ; ... et provisoire la même chose pour tout les niveau suivant.  
  
  If nextlevel=0  
    If (nbrdetruit>16-1 And level=1) Or (nbrdetruit>16-1 And level=2) Or (nbrdetruit>24-1 And level=3):nextlevel=1:EndIf
  EndIf
  If nextlevel=0
    If level=4:nextlevel=1:EndIf; niveau du 1er Boss( non effectif, alors on zappe).
    If level=8:nextlevel=1:EndIf; niveau du 2eme Boss( non effectif, alors on zappe).
    If level=10:nextlevel=1:level=0:EndIf; niveau 10 terminus, alors on zappe et on propose de recommencer.
  EndIf
  If nextlevel=0  
    If (nbrdetruit>16-1 And level=5) Or (nbrdetruit>16-1 And level=6) Or (nbrdetruit>24-1 And level=7):nextlevel=1:EndIf
  EndIf
  If nextlevel=0  
    If (nbrdetruit>40-1 And level=9):nextlevel=1:EndIf; Or (nbrdetruit>16-1 And level=6) Or (nbrdetruit>24-1 And level=7):nextlevel=1:EndIf
  EndIf
        
  If nextlevel=1:nextlevel=0
    If extra=0:nombrextra=0:topdepartextra=0 
      level+1:etape=1
    
      dirbruteA=0:dirbruteB=0:dirbruteC=0; dans une même direction, pour un même but ;) 
      speedbrut=1:nbrdetruit=0    
    EndIf
  EndIf
;- joueur gagne une vie
  If (score>490 And bonusvie=0) Or (score>990 And bonusvie=1) Or (score>1490 And bonusvie=2) Or (score>1990 And bonusvie=3)
    bonusvie+1:vie+1:Flifeup(Xgentil+11, Ygentil) ; joueur gagne une vie tout les 500 pts
  EndIf
  If (score>2490 And bonusvie=4) Or (score>2990 And bonusvie=5) Or (score>3490 And bonusvie=6) Or (score>3990 And bonusvie=7)
    bonusvie+1:vie+1:Flifeup(Xgentil+11, Ygentil)  ; joueur gagne une vie tout les 500 pts
  EndIf
  If (score>4500-10 And bonusvie=8) Or (score>5000-10 And bonusvie=9) Or (score>5500-10 And bonusvie=10) Or (score>6000-10 And bonusvie=11)
    bonusvie+1:vie+1:Flifeup(Xgentil+11, Ygentil)  ; joueur gagne une vie tout les 500 pts
  EndIf
  If (score>6500-10 And bonusvie=12) Or (score>7000-10 And bonusvie=13) Or (score>7500-10 And bonusvie=14) Or (score>8000-10 And bonusvie=15)
    bonusvie+1:vie+1:Flifeup(Xgentil+11, Ygentil)  ; joueur gagne une vie tout les 500 pts
  EndIf
  If (score>8500-10 And bonusvie=16) Or (score>9000-10 And bonusvie=17) Or (score>9500-10 And bonusvie=18) Or (score>10000-10 And bonusvie=19)
    bonusvie+1:vie+1:Flifeup(Xgentil+11, Ygentil)  ; joueur gagne une vie tout les 500 pts
  EndIf
      
  ClipSprite(#shipb, 0, 208, 64, 48):DisplayTransparentSprite( #shipb , 10, 10)
  StartDrawing ( ScreenOutput ())
    DrawingMode (1)
      FrontColor ( RGB (255,255,255))      

      DrawingFont ( FontID (0)) 
      score$= Str (score) 
      FrontColor ( RGB (154,154,154)) :DrawText (350+1, 5+1, "SCORE " +score$)
      FrontColor ( RGB (234,234,234)) :DrawText (350, 5, "SCORE " +score$)
      
      DrawingFont ( FontID (0))
      hiscore$= Str (hiscore) 

      FrontColor ( RGB (255, 153, 0)) :DrawText (680+1, 5+1, "HI-SCORE ")
      FrontColor ( RGB (255,224,0)) :DrawText (680, 5, "HI-SCORE ") 

      FrontColor ( RGB (255, 153, 0)) :DrawText (680+1,25+1, "" +hiscore$)
      FrontColor ( RGB (255, 224, 0)) :DrawText (680,25, "" +hiscore$) 
            
      DrawingFont ( FontID (1))
      vie$= Str (vie) 
      FrontColor ( RGB (164,21,21)) :DrawText (42+1, 4+1, "  " +vie$)
      FrontColor ( RGB (253,201,255)) :DrawText (42, 4, "  " +vie$)     
  StopDrawing ()
  
  ; Si invuln=100, alors explosion 1.
  ; Si invuln=101, alors explosion 2.  
  If vie<1 And invuln<100:etape=20:EndIf

  If etape=10 And tousensemble=1:tousensemble=0:topdepartextra=1 
    ForEach bruteA()
      bruteA()\y+24
    Next
    ForEach bruteB()
      bruteB()\y+24
    Next
    ForEach bruteC()
      bruteC()\y+24
    Next
  EndIf
  
  If etape=10 ; désigner la brute qui va tirer: il faut utiliser 2 variables globales: choixtirbrute et ordretirbrute 
    If pause=0:tempotirbrute+1:EndIf
      If tempotirbrute>64:tempotirbrute=0:nbrdebrute=0
        ForEach bruteA()
          nbrdebrute+1
        Next
        ForEach bruteB()
          nbrdebrute+1
        Next
        ForEach bruteC()
          nbrdebrute+1
        Next      
        choixtirbrute=Random(nbrdebrute); de 0 à 7... 
        choixtirbrute+1; ...et là +1, donc maintenant de 1 à nombre de brute présent à l'écran.
      EndIf  
  EndIf  
    
EndIf; If etape=10

If etape=20; *******
  Affichagegameover()
EndIf 

 If KeyboardPushed ( #PB_Key_F ) And nbreis=0:nbreis+1:EndIf
 If KeyboardPushed ( #PB_Key_F )=0 And nbreis=1:nbreis+1:EndIf
 If KeyboardPushed ( #PB_Key_F ) And nbreis=2:nbreis+1:EndIf
 If KeyboardPushed ( #PB_Key_F )=0 And nbreis=3:nbreis=0:EndIf

 Gosub fps ; nombre d'image par seconde. 
 
 Stop3D(); on place cette commande à la fin de la boucle principale. 
 FlipBuffers(1) 
;- 
Delay(12) ;- là
;-
 ClearScreen(RGB(0,0,0))
; ******************************************************************************************************   
 If Event= #PB_Event_CloseWindow Or KeyboardPushed ( #PB_Key_Escape ):Fin():EndIf; si clique coin haut droit ou touche Esc, alors ferme fenêtre.
ForEver
Un post spécial Delay() serait le bienvenue pour débattre du truc afin qu'on en finissent une fois pour toute avec cette commande, qu'en pense-tu Dobro ?

Publié : lun. 16/mars/2009 12:13
par djes
Ollivier> 8O Tu es un gros bosseur toi! J'apprécie le travail que tu fais; à titre d'information, tonton, comme moi et d'autres anciens nous basons sur ce que nous connaissons. Nous avons programmé beaucoup d'applis graphiques sur des machines qui étaient synchronisées sur l'affichage, notamment la VBL dont tu as sans doute déjà entendu parler. Nous sommes très habitués à un affichage hyper fluide de ce fait (une synchro constante, jamais un frame drop!). Sur ces machines, il y avait (au moins) une véritable interruption processeur pour la VBL (ça existait sur PC aussi d'ailleurs); donc nous étions sûrs de pouvoir faire nos calculs et notre redraw sans nous faire voler du temps CPU par d'autres tâches.

En programmation système, l'OS nous permettait d'avoir une priorité supérieure afin, de la même façon, de ne pas perdre nos cycles. Cela venait d'un constat simple, mais qui a échappé aux programmeurs de Windows (normal, celui-ci était plutôt fait pour la bureautique), à savoir que l'OS est là pour répondre à l'utilisateur, et ne pas le faire attendre. Avec Windows, l'utilisateur n'est pas prioritaire, souvent lui ou l'application en cours se font voler le focus par une autre appli, c'est exaspérant. Mais ça tient aux fondamentaux de Windows, un programme=une fenêtre, d'où son nom, avec celle au premier plan avec un boost de priorité. Le swap de fenêtres demande à l'OS un jonglage de priorités qui n'améliore pas la réactivité. Windows date, et n'a jamais été le mieux pensé des OS (d'ailleurs ce n'en était pas un!), mais c'est ainsi.

Les anciens sont un peu irrités de devoir utiliser des timers, qui s'ils permettent un affichage et une réaction de l'OS à peu près constants, ne permettent pas une action bien synchronisée sur l'affichage; si en 3d cela ne se voit pas trop, en 2D, quand un vaisseau avance de 5 pixels, de 3, puis de 8, même si la moyenne est constante, à l'oeil c'est horrible, surtout pour les habitués. Moi quand je vois un frame drop j'ai instinctivement un rejet. Je n'y peux rien, j'ai connu trop de bons jeux à 50hz pour supporter ça. C'est pour ça aussi qu'on préfère jouer sur consoles qui ne souffrent pas trop de ces défauts.

Quand j'aurai un peu de temps je testerai ton truc des deux delay(1), ça m'a l'air intéressant. Avec une bonne quantité de sprites 3d de belles dimensions ce serait plus démonstratif.

Publié : lun. 16/mars/2009 12:32
par beauregard
djes a écrit :Quand j'aurai un peu de temps je testerai ton truc des deux delay(1)
j'ai testé avec vers l'infini, ben ça rame( 30fps). dois y avoir une astuce, une technique secrete...

Publié : lun. 16/mars/2009 15:56
par Norswap
Tout d'abord, merci pour toutes ses explications. Quand je disais qu'il ne fallait pas s'enflammer, je parle bien sur de la forme et non du fond.

Ceci étant dit, je trouve tout de même tes explications un brin confuses.
J'ai donc quelques questions :

Tu soulignes l'importance de rendre la main à l'OS, mais est-ce que dans le cas du code de Cpl.Bator, on ne lui rend pas la main ?

D'ailleurs cette histoire de "main" me rend un peu confus l'un dans l'autre. Windows XP est un OS mutlitâches et donc il est supposé divisé le temps d'exécution en petites tranches et faire s'exécuter les programes à tour de rôle (ce qu'on appelle time-slicing). Tu le mentionnes d'ailleurs quand tu parles de tâches en parallèle.

Mais alors, logiquement l'os se trouve à un niveau supérieur comme tu dit, et peut juste décider de suspendre l'exécution pour faire place à la tranche de temps d'un autre programme logiquement. Alors que quand on parle de "rendre la main" on a l'impression que l'OS s'éxecute lui aussi dans une tranche de temps similaire aux autres programmes.

Concernant ceci :

Code : Tout sélectionner

Procedure.I F(n.I)
   Protected Result.I
   Result = 16 + n - n % 16
   ; Délai réel = 16 + Délai théorique - (Délai théorique modulo 16)
   ; Résultat précis à + ou - 3%
   ProcedureReturn Result
EndProcedure 

Code : Tout sélectionner

Depart = ElapsedMilliseconds()
Delay(1)
Fin = ElapsedMilliseconds()
Debug Fin - Depart 
Un Delay(1) me donne 0ms à tous les coups (Windows XP Dual Core 2Ghz), si j'augmente l'argument, j'aurais 16ms ou 0ms (plus j'augmente l'argument, plus le 16 est fréquent, pour couvrir quasi 100% des cas à 14).

Le même phénomène se reproduit pour la suite : un Delay(20) (qui devrait d'après toi me donner 32ms), me donne soit 16ms ou 32ms.

Donc ta formule, même si très liée à la réalité, ne me semble pas fiable à 100%. Elle est même décalée puisque d'après elle un Delay(16) devrait me donner 32ms alors qu'il ne m'en donne que 16 et qu'un Delay(32) devrait me donner 48ms alors qu'il m'en donne que 32.

EDIT :

J'ajouterais en plus que mon problème ne concerne pas de crash comme c'est suggéré à un endroit, mais bien de consommation de cpu trop élévée.

Je viens de tester la méthode Cpl.Bator, elle rend en effet l'impact sur le cpu presque nul. De plus il n'y à priori aucun risque de "désynchronisation" entre différent pc, puisque la boucle vérifie effectivement le temps écoulé. Je ne vois vraiment pas où se situe le problème avec cette méthode.