Random "pas si random que ça"

vico92vico92 Membre
16:41 modifié dans API UIKit #1
Bonjour,
(je ne sais pas trop dans quel topic poster ce message, désolé...)

En cherchant sur le forum j'ai trouvé comment générer un nombre pseudo-aleatoire entre deux valeurs données, mais ce n'est pas exactement ce dont j'ai besoin.
Je voudrais faire varier une valeur, disons entre 0.4 et 1.5 "progressivement". Pour être plus clair, je ne veux pas passer directement de 0.5 à  1.2, mais que la valeur augmente ou diminue petit à  petit vers des valeurs cibles aléatoires.

J'imagine donc qu'il me faut une fonction utilisant la valeur générée par sRandom, c ça ?

Merci ^^
Vico
«1

Réponses

  • AliGatorAliGator Membre, Modérateur
    16:41 modifié #2
    Heu tu mélanges un peu 2 choses là  j'ai l'impression.
    Il y a un aspect random (aléatoire) pour tes valeurs cibles à  atteindre, mais il y a un aspect "transition progressive" pour atteindre ces valeurs. Ce sont 2 problématiques bien différentes.

    A partir d'une valeur donnée de départ v0 (qui peut être random d'ailleurs), il faut que tu :
    - tires (avec random()) une valeur cible aléatoire v1 pour la prochaine cible
    - fasse évoluer ta valeur de v0 vers v1 de façon progressive
    - une fois arrivé à  v1, que tu tires au hasard une nouvelle valeur cible v2
    - fasse évoluer ta valeur de v1 vers v2 de façon progressive
    - une fois arrivé à  v2, que tu tires au hasard une nouvelle valeur cible v3
    ...


    Comment et pour quel usage sont utilisées ces valeurs ? Comment comptais-tu faire l'animation de ta valeur progressivement ? Avec un timer ?
    Si c'est pour se faire déplacer des éléments de ton interface (par exemple des boules d'un jeu apparaissant à  l'écran) de façon progressive d'un endroit à  un autre de ton écran, le plus simple est encore d'utiliser CoreAnimation pour ça. Tu choisis une valeur cible (CGPoint) random, tu demandes d'y aller avec un effet de transition avec genre [tt]maboule.layer.position = positionCible[/tt] et dans le delegate de l'animation ainsi déclenchée tu détectes quand l'animation est terminée et tu choisis alors une nouvelle cible et lance une autre animation, pour aller à  cette nouvelle position... etc...
  • AdauAdau Membre
    juin 2009 modifié #3
    Je pense qu'un simple petit algorithme comme celui-là  peut suffire:
    <br />N = 0.4<br />Tant que N&lt;1.5 :<br />N = random entre N-0.1 et N+0.2<br />
    

    Le principe de la marche aléatoire s'occupe du reste.

    Sinon, autrement, et encore plus simple:
    <br />N = 0.4<br />i = 0<br />tant que i &lt; 1.5-0.4<br />N = N + random(entre -0.01 et +0.01)<br />i = i + 0.01<br />
    


    Dans les deux cas, il faut ajuster certaines constantes pour obtenir l'effet voulu.
    Personnellement, je choisirai la première solution, elle est plus jolie.


    Edit:// Sinon, quand je vois le message d'Alligator, j'ai peut-être pas bien cerné le problème. Si c'est le cas, désolé.
  • DrakenDraken Membre
    juin 2009 modifié #4
    Tu veux faire varier progressivement une valeur entre deux chiffres aléatoires ? Ce n'est pas bien compliqué. Il te suffit de diviser la "distance" entre les deux valeurs par le nombre d'étapes intermédiaires.

    Exemple: ma valeur actuelle est de 2, et le générateur aléatoire viens de me donner la valeur 7. La "distance numérique" entre les deux valeurs est de 5 (7-2=5). Pour avoir 100 étapes de progression entre les valeurs, tu divise 5 par 100, soit 0,05.

    <br />valeurOrigine = tirageAleatoire(Espace de valeurs possibles)<br />valeurFinale = tirageAleatoire(Espace de valeurs possibles)<br />nombreEtapes = 100<br />valeurDeTransition = (valeurFinale-valeurOrigine)/nombreEtapes<br />// ..<br />maValeur = valeurOrigine<br />// ..<br />Boucle allant de 1 à  nombreEtapes<br />&nbsp;  // Progression d&#39;une étape <br />&nbsp;  maValeur = maValeur + valeurDeTransition<br />&nbsp;  // Traitements<br />&nbsp;  // ...<br />
    


    Ceci dis, en relisant ton message, je me demande si j'ai bien compris.

    J'ai compris que tu voulais aller progressivement d'une valeur aléatoire vers une autre valeur aléatoire. Mais est-ce cette progression doit se faire de manière continue, ou plus ou moins aléatoire ?

  • vico92vico92 Membre
    16:41 modifié #5
    Merci pour vos réponses,

    Draken -> Mais est-ce cette progression doit se faire de manière continue, ou plus ou moins aléatoire ?


    De manière continue, et idéalement pas de manière linéaire mais lissée (easeIn et easeOut seraient les bienvenus^^).

    Adau, tu as dû comprendre que je voulais aller de la valeur V1 à  la valeur V2 de manière aléatoire, ce qui n'est pas le cas, j'ai dû mal m'exprimer, merci qd-même pour ta réponse.

    AliGator-> Comment et pour quel usage sont utilisées ces valeurs ? Comment comptais-tu faire l'animation de ta valeur progressivement ? Avec un timer ?
    Si c'est pour se faire déplacer des éléments de ton interface (par exemple des boules d'un jeu apparaissant à  l'écran) de façon progressive d'un endroit à  un autre de ton écran, le plus simple est encore d'utiliser CoreAnimation pour ça.


    AliGator, le processus que tu as décrit est effectivement le bon (ma réflexion en est arrivée là  ce midi pendant le déj, heureux que tu confirmes^^).
    Reste à  savoir comment aller de V0 à  V1 de façon progressive,
    sachant que dans mon cas, la valeur obtenue est une simple float utilisée dans d'autres fonctions comme facteur (de vitesse).
    J'ai bien pensé à  CoreAnimation mais je me demande s'il fera l'interpolation entre une CGFloat A et une CGFloat B. J'ai peur qu'il n'interpole que les propriétés animables (position echelle etc.) d'un objet (juste une supposition, pas encore testé).

    (au passage c koi la difference entre float et CGFloat ?)


  • AliGatorAliGator Membre, Modérateur
    16:41 modifié #6
    dans 1245417854:
    J'ai bien pensé à  CoreAnimation mais je me demande s'il fera l'interpolation entre une CGFloat A et une CGFloat B. J'ai peur qu'il n'interpole que les propriétés animables (position echelle etc.) d'un objet (juste une supposition, pas encore testé).

    (au passage c koi la difference entre float et CGFloat ?)
    CoreAnimation est fait pour animer des propriétées des CALayers, donc des layers (calques) utilisés pour le rendu à  l'écran (donc position, orientation, taille, tout ça). Je doute donc que ça convienne pour faire une transition entre tes floats. Je te parlais de ça uniquement si tes CGFloats étaient utilisés pour l'animation d'un objet graphique à  l'écran, dans ce cas autant laisser CoreAnimation faire l'interpolation, mais vu que ça n'a pas l'air d'être le cas, il va falloir faire à  la main.

    Pour aller de V0 à  V1 c'est simple, une petite équation mathématique. Il suffit de faire varier t de 0 à  1 par un pas donné (par exemple pas de 0.1 si tu veux 10 étapes intermédiaires), t représentant alors le pourcentage d'avancement de ton animation entre V0 et V1 (t=0 : tu es en V0 ; t=1 tu es en V1 ; t=0.5 tu es à  mi-parcours entre V0 et V1 ; ...).

    Si c'est une progression linéaire que tu veux, l'équation est simple : [tt]v = v0*(1-t) + v1*t[/tt]. Ce qui correspond bien à  une équation linéaire (que l'on peut aussi écrire [tt]v = (v1-v0)*t+v0[/tt] où t est la variable, donc c'est bien de la forme ax+b).
    Si tu veux un effet de "easeIn" / "easeOn", va falloir trouver les équations paramétriques adéquates (google doit les connaà®tre :p)

    Sinon CGFloat c'est en fait un double et pas un float (donc plus de précision qu'un float) : [tt]typedef double CGFloat[/tt] (défini dans CoreGraphics.framework/headers/CGBase.h)
  • vico92vico92 Membre
    16:41 modifié #7
    Très clair, merci bien à  vous 3  , je teste ça dès ce soir.

    (Mine de rien, il commence à  avoir de la gueule, mon jeu. J'ai hâte de vous le faire essayer ^^)
  • Philippe49Philippe49 Membre
    16:41 modifié #8
    La formule des courbes de Bezier (polynômes de Bernoulli en fait) par exemple
    M(t)=M(0)*(1-t)^3+...
    et il suffit de prendre M(t) à  une seule dimension.
  • vico92vico92 Membre
    16:41 modifié #9
    Bonjour :)

    J'essaye de faire une transition linéaire pour commencer, mais quelque-chose cloche dans mon code car ça ne fonctionne pas comme attendu  :-\\

    Voici le code:
    <br />/* la transition de WindForce (V0) vers windForceTarget (V1) est écrite <br />dans la fonction accelerometer pour que windForce s&#39;actualise 80 fois <br />par seconde*/<br />//n.b. windForce est préalablement initialisé à  1.<br /><br />- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration {<br />	if (windForce != windForceTarget) {<br />		<br />		if(windForce &lt; windForceTarget) {<br />			windForce = windForce + 0.01;	<br />		}<br />		<br />		if(windForce &gt; windForceTarget) {<br />			windForce = windForce - 0.01;	<br />		}<br /><br />		else {<br /><br />/* Quand windForce==windForceTarget, j&#39;utilise un timer pour appeler <br />la fonction random (un boléen serait peut-être plus adapté mais je ne <br />sais pas trop comment l&#39;utiliser, alors...)*/<br /><br />			timerWind = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(randomWind) userInfo:nil repeats:NO] ;<br /><br />}<br /><br /><br />//fonction calculant une valeur random CGFloat &quot;WindForceTarget&quot; entre 0.7 et 1.2<br /><br />-(void)randomWind {<br />	// fonction de generation d un nombre aleatoire compris entre les bornes NOMBREMAX et NOMBREMIN<br />	int NOMBREMIN = 700;<br />	int NOMBREMAX = 1200;<br />	<br />	srand(time(NULL));<br />	randomValue = (rand() % (NOMBREMAX - NOMBREMIN + 1)) + NOMBREMIN;<br />	<br />	windForceTarget = randomValue/1000;<br />	<br />	NSLog(@&quot;windForce = %f&quot;, windForce);	<br />	NSLog(@&quot;windForceTarget = %f&quot;, windForceTarget);<br />}<br /><br />
    


    Peut-être est-ce un boléen qui conviendrait pour appeler à  nouveau la fonction randomWind, mais je sais pas trop l'utiliser.
    J'ai également essayé de remplacer le timer par [self randomWind];
    Soit la valeur courrante windForce stagne quand elle atteint windForceTarget, soit windForceTarget change de valeur avant que windForce ne l'ai atteint...je m'y paume un peu là  ^^



  • Philippe49Philippe49 Membre
    16:41 modifié #10

    srand(time(NULL));

    Avec cette instruction, tu réinitialises à  chaque appel le générateur aléatoire, et comme time(NULL) ne change qu'une fois par seconde, tu obtiens toujours les mêmes valeurs.

    Mets donc cet instruction dans une méthode d'initialisation.

    rq: L'habitude est d'utiliser random() plutôt que rand() (voir la page man)

  • vico92vico92 Membre
    juin 2009 modifié #11
    Bingo !  <3 <br />
    Merci pour votre aide les gars, ça fonctionne maintenant, ça fait un tout petit peu lagger l'affichage mais je suis content du résultat ^^

    (Philippe, pour le srand(time(NULL));, j'ai beau le mettre dans le awakeFromNib, c'est toujours la même suite qui revient après chaque reboot du jeu??)

    Pour ceux que ça intéresse, voici le code qui fonctionne bien pour ce que je voulais:
    <br /><br />//tirage d&#39;une valeur random<br /><br />-(void)randomWind {<br />	<br />	int NOMBREMIN = 700;<br />	int NOMBREMAX = 1200;<br />	srand(time(NULL));<br />	randomValue = (random() % (NOMBREMAX - NOMBREMIN + 1)) + NOMBREMIN;<br />	<br />	windForceTarget = randomValue/1000;<br />	NSLog(@&quot;windForceTarget = %f&quot;, windForceTarget);<br />	<br />}<br /><br />-(void)timeLapse {<br />	<br />	// When WindForce reach windForceTarget value, <br />	// we ask randomWind to give another random value<br />	<br />	if (windForce &lt;= windForceTarget+0.05 &amp;&amp; windForce &gt;= windForceTarget-0.05 ) {<br />		<br />		[self randomWind];<br />	}<br />	<br />	else {<br />		// WindForce increase itself to reach windForceTarget<br />		if (windForce &lt; windForceTarget) {<br />			windForce = windForce + 0.01;	<br />		}<br />		// WindForce decrease itself to reach windForceTarget<br />		if(windForce &gt; windForceTarget) {<br />			windForce = windForce - 0.01;	<br />		}<br />	}<br />	NSLog(@&quot;windForce = %f&quot;, windForce);	<br />}<br /><br /><br />// n&#39;importe où dans le code, on check 5 fois par seconde la situation de windForce par rapport à  sa windForceTarget en appelant timeLapse:<br /><br />	timerWind = [NSTimer scheduledTimerWithTimeInterval:.2 target:self selector:@selector(timeLapse) userInfo:nil repeats:YES] ;<br /><br /><br />
    


  • BaardeBaarde Membre
    juin 2009 modifié #12
    Normal : rand() et random() sont deux générateurs de nombres pseudo-aléatoires différents avec chacun son propre initialisateur, respectivement srand() et srandom().

    Donc, si tu utilises random(), il faut initialiser avec srandom(time(NULL)) ou, mieux encore, avec sranddev().

    EDIT : srandomdev(), pas sranddev()
  • vico92vico92 Membre
    16:41 modifié #13
    ah ok, merci Baarde :)

    et pkoi c mieux avec sranddev() ?
  • BaardeBaarde Membre
    16:41 modifié #14
    srandomdev() et sranddev() initialisent le générateur de nombres pseudo-aléatoires en utilisant /dev/random (un pseudo-device qui est lui même un générateur de nombres pseudo-aléatoires) ce qui garantie un tirage différent même si tu exécutes le programme au même instant (alors que time(NULL) renverra la même chose).
  • vico92vico92 Membre
    16:41 modifié #15
    Merci pour cette précision.

    Bon, en fait je suis pas tout à  fait content du résultat obtenu car l'animation saccade parceque le timer n'actualise que 5 fois/sec la valeur de windForce (qui elle-même influence la vitesse de déplacement de mon cerf-volant, et aussi le défilement du décors.)
    Mais si j'augmente la fréquence de repeat du timer, ça se met à  ramer par manque réel de puissance de l'iphone (l'image se freeze pendant 1 à  2 secondes parfois).

    Beaucoup de jeux sont pourtant bien plus riches graphiquement et plus complexes que le mien, c'est que j'utilise pas la bonne méthode, je pense...

    Une idée à  ce sujet les amis ?

    (c'est un simulateur de cerf-volant. le decors de fond est une image de 1400 pixels de coté. le cerf-volant rotationne via l'accelerometre, sa position est calculée en fonction des cos/sin de l'angle. L'image de fond se déplace en direction inverse de celle du cerf-volant.
    La vitesse du cerf-volant décroit en partant du centre de l'écran et elle varie en fontion de la force du vent "windForce".) Tout ça est implementé dans la fonction UIAccelerometer

    Voilà  vous savez tout, si quelque-chose vous semble mal pensé...^^
  • DrakenDraken Membre
    juin 2009 modifié #16
    dans 1245928065:


    Beaucoup de jeux sont pourtant bien plus riches graphiquement et plus complexes que le mien, c'est que j'utilise pas la bonne méthode, je pense...

    Une idée à  ce sujet les amis ?


    Je dirais que ce sont des jeux OpenGL, selon toute vraisemblance..

    Tu dis que ton image de fond fait 1400 pixels de long, mais combien en largeur ? La taille de l'écran ?




  • Philippe49Philippe49 Membre
    16:41 modifié #17
    dans 1245749909:

    srandomdev() et sranddev() initialisent le générateur de nombres pseudo-aléatoires en utilisant /dev/random (un pseudo-device qui est lui même un générateur de nombres pseudo-aléatoires) ce qui garantie un tirage différent même si tu exécutes le programme au même instant (alors que time(NULL) renverra la même chose).

    Ces affirmations et celles que l'on trouve sur ce sujet n'ont rien de scientifiques. rand() et random() a été analysée scientifiquement, avec des résultats que tout le monde peut consulter, et vérifier si il a envie. L'utilisation de /dev/random, de par sa conception même, est un hasard ... à  pile ou face. Il est invérifiable de savoir si cela marche !

    A voir les travaux récents sur la simulation du hasard et les contraintes qui s'y affairent, c'est beaucoup moins simple que voir une liste de nombres. C'est un travail de spécialiste.
  • Philippe49Philippe49 Membre
    16:41 modifié #18
    dans 1245929004:

    Je dirais que ce sont des jeux OpenGL, selon toute vraisemblance..

    Non OpenGL n'accélère pas l'iPhone. Pour une bonne raison, c'est que OpenGL ES est un client de CoreAnimation. (reference)
    Cela sans retirer à  openGL ce qui lui appartient.
  • AliGatorAliGator Membre, Modérateur
    16:41 modifié #19
    Heu ton image de fond de 1400px de côtés... c'est énorme ça, voir même pas conseillé du tout.
    L'iPhone ne supporte "nativement" pour le rendu à  l'écran que les images de 1000x1000 maximum, la doc mentionne que si tu travailles avec des images plus grandes faut les sous-découper pour que l'affichage se passe bien.
    D'ailleurs y'a pas trop d'intérêt d'avoir d'avoir plus grand que l'écran de l'iphone (320x480) sauf cas particulier, mais pour ton paysage avoir un truc 4x plus grand que l'écran me parait injustifié, non ?

    Sinon avoir mis la totalité des calculs dans la méthode de delegate de UIAccelerometer n'est peut-être pas la meilleure des solutions, d'autant qu'elle risque d'être appelée assez souvent...
    ...y'a peut-être aussi des calculs mathématiques à  optimiser, des choses à  ne calculer qu'une fois pour toute plutôt qu'à  chaque boucle de rendu ?
  • DrakenDraken Membre
    juin 2009 modifié #20
    Effectivement Philippe, au final toutes les opérations graphiques se terminent par des appels à  OpenGL, en passant par une ou plusieurs couches intermédiaires.

    L'ennui c'est que ces couches sont conçues pour répondre aux attentes des développeurs d'applications standards, leurs offrant souplesse et polyvalence, ce qui se paye par une diminution des performances, plus ou moins importante.

    De plus les fonctionnalités de ces couches hauts niveaux ne se prêtent pas forcément aux besoin spécifiques de l'écriture des jeux vidéo. L'exemple le plus flagrant est l'absence d'une méthode Core Graphics pour afficher sur l'écran une portion d'image au lieu de l'image entière.

    C'est une fonction très pratique pour les jeux vidéo, et très utilisé. J'en ai déjà  parlé dans un autre post, et cela me reste encore en travers de la gorge. Alors oui, on peut bricoler pour refaire le même effet en Core Graphics, mais au prix d'une dégradation des performances. Et quand tu veux faire un jeu vidéo, et tout particulièrement un beau scrolling la dégradation des performances, c'est le Mal absolu.

    OpenGL est complexe d'emploi, mais permet un contrôle plus fin de la machinerie graphique, et donc une meilleure utilisation de la puissance de l'iPhone.

  • DrakenDraken Membre
    16:41 modifié #21

    Il est rare que les jeux fassent un scrolling sur des images de grandes tailles. Généralement le scrolling se fait sur un "fond virtuel" composé d'un assemblage de tuiles graphiques.

    J'ai joint à  ce post l'image du jeu de rôle Inotia utilisant ce principe. On vois bien que le décor est formé d'un assemblage de "briques" de base. Les arbres, les fleurs, les touffes d'herbes, et les rochers sont tous les mêmes.

    Cette technique est économique en mémoire, permettant de créer de vastes décors, avec peu de graphismes. Il faut juste une image contenant les éléments graphiques, et un tableau à  2 dimensions pour le stockage du terrain.

  • vico92vico92 Membre
    juin 2009 modifié #22
    Mon image de fond fait 1400x1400, bcp plus grande que l'écran dans le but de la scroller pendant le jeu.
    (Tandis que le cerf-volant se deplace à  l'écran, le decors de fond bouge en direction opposée à  celle du cerf-volant, ce qui augmente le dynamisme du jeu  et l'impression de vitesse).

    J'avais lu que Apple recommandait de ne pas depasser 1000x1000 px mais comme ça semblait très bien fonctionner et avec fluidité jusqu'à  maintenant, je faisais comme ça... Mais du coup je devrais peut-être réduire sa taille pour voir si le probleme persiste.
    par-contre j'ai un peu peur que l'image pixellise, ce qui n'est pas beau du tout  :'( (crénelage des contours)

    -Sinon, tu dis qu'apple preconise d'utiliser plusieurs images accolées pour créer une grande mosaique ? Pourquoi pas, si ça reste joli quand c'est animé.
    Et en même temps je vois pas comment ça peut améliorer la fluidité puisque plusieurs images à  calculer (leur position, leur taille etc.) ça ralentirait plutôt les performances, je trouve ?

    -C'est de cette methode dont tu parles Draken ? Effectivement pour un jeu comme celui de ton screenshot, avec un fond et des objets graphiques répétitifs, c'est pratique, mais moi j'ai des décors comme celui en piece jointe, alors je vois pas trop comment faire.

    -Sinon, peut-être qu'une image de 1000 px seulement, mais avec une résolution superieure à  72 dpi ça pourrait éviter de pixeliser (gros pixels visibles) tout en restant sous la barre des 1000 pixels ?

    EDIT: Je viens de lire que le fait de supprimer la couche alpha du png pouvait alleger le fichier et ameliorer sa gestion.

    -Le jpg est-il moins bien géré que le png ? Quelqu'un dans un post précédent m'a répondu oui.

    AliGator-> "Sinon avoir mis la totalité des calculs dans la méthode de delegate de UIAccelerometer n'est peut-être pas la meilleure des solutions, d'autant qu'elle risque d'être appelée assez souvent..."

    T'as surement raison, mais si je met mon code ailleurs que dans le delegate de l'accelerometre, j'ai plus de loop dans mon jeu. Je veux dire que le cerf volant reste figé puisque sa position est lue par le programme 1 seule fois, alors que le delegate reactualise la position du cerf-volant jusqu'à  100fois/sec, ce qui fait que le jeu est "vivant". Quelles sont les autres possibilité pour avoir une loop de jeu ? Tout mettre dans un Timer avec un repeat de 0.01 ?
  • DrakenDraken Membre
    juin 2009 modifié #23
    dans 1245945167:

    si je met mon code ailleurs que dans le delegate de l'accelerometre, j'ai plus de loop dans mon jeu. Je veux dire que le cerf volant reste figé puisque sa position est lue par le programme 1 seule fois, alors que le delegate reactualise la position du cerf-volant jusqu'à  100fois/sec, ce qui fait que le jeu est "vivant". Quelles sont les autres possibilité pour avoir une loop de jeu ? Tout mettre dans un Timer avec un repeat de 0.01 ?


    Pas besoin d'avoir un timer cadencé à  0.01, ce qui correspondrait à  une vitesse de 100 images/s, alors que l'iPhone ne rafraà®chit son écran qu'à  60 images/s.

    Utilise plutôt un timer avec une cadence de 1.0/60.0, comme le fait Apple dans son exemple GLSprite:

    animationInterval = 1.0 / 60.0;<br />animationTimer = [NSTimer scheduledTimerWithTimeInterval:animationInterval target:self selector:@selector(drawView) userInfo:nil repeats:YES];<br />
    


  • Philippe49Philippe49 Membre
    juin 2009 modifié #24
    dans 1245939142:

    Effectivement Philippe, au final toutes les opérations graphiques se terminent par des appels à  OpenGL, en passant par une ou plusieurs couches intermédiaires.

    L'ennui c'est que ces couches sont conçues pour répondre aux attentes des développeurs d'applications standards, leurs offrant souplesse et polyvalence, ce qui se paye par une diminution des performances, plus ou moins importante.

    De plus les fonctionnalités de ces couches hauts niveaux ne se prêtent pas forcément aux besoin spécifiques de l'écriture des jeux vidéo.

    Disons que quelqu'un qui a déjà  écrit son code en opengl, ou qui en a l'habitude, répugne à  le réécrire avec CoreAnimation.
    Ce que j'ai compris, c'est la chaà®ne suivante :
    OpenGL ES ==> CoreAnimation ==> "style OpenGL"
    Cela veut dire que OpenGL ES ne shunte pas CoreAnimation, et qu'en optimisant du code C pour utiliser ensuite des méthodes CocoaTouch/CoreAnimation, on obtient à  priori au moins aussi bien que par OpenGL ES qui va faire appel à  des méthodes CoreAnimation et son OpenGL propre après.

    Maintenant si tu as d'autres sources qui dise le contraire, fais nous en profiter.


    dans 1245939142:

    L'exemple le plus flagrant est l'absence d'une méthode Core Graphics pour afficher sur l'écran une portion d'image au lieu de l'image entière.

    Borpf, en cherchant un peu CGImageCreateWithImageInRect
    et sans avoir vérifié, la méthode colorWithPatternImage associée à  la redéfinition du bounds de la view est sans doute (si elle marche) le plus simple.

    dans 1245939142:

    veux faire un jeu vidéo, et tout particulièrement un beau scrolling la dégradation des performances, c'est le Mal absolu.

    Tu veux dire que le scrolling des view apple n'est pas au point ?

  • Philippe49Philippe49 Membre
    juin 2009 modifié #25
    Bon voilà  un essai de scrolling sur une image 2048*1536 vue à  travers une fenêtre de taille 100*100 (c'est pareil sur l'écran complet). C'est fait avec CGImageCreateWithImageInRect et ni le simulateur ni le device ne rament.
  • vico92vico92 Membre
    16:41 modifié #26
    Bon, je viens de comprendre pourquoi l'appli ramait comme ça.
    Rien à  voir avec la taille des images, c'est parce que je demandais trop de calculs au proc. apparemment.

    En gros, je faisais windForce+0.1 ou windForce - 0.1, et ce 100 fois/sec, maintenant, je fais windForce+10 ou windForce - 10 toutes les 5 secondes, et là  c'est redevenu fluide.
    (Ce ne sont pas mes vraies valeurs, mais le principe est là ).

    Alors je ne sais pas ce que c'est comme proc mais faut pas trop lui en demander, on dirait ^^

    Merci à  tous pour vos réponses et pour ton essai de scroll, Philippe.
  • Philippe49Philippe49 Membre
    16:41 modifié #27
    dans 1246138190:

    En gros, je faisais windForce+0.1 ou windForce - 0.1, et ce 100 fois/sec, maintenant, je fais windForce+10 ou windForce - 10 toutes les 5 secondes, et là  c'est redevenu fluide.

    Oui enfin tu devais entraà®ner bien plus de calcul que cette addition pour empêcher la fluidité.
    Dans une appli Cocoa, la boucle d'événements , le "run loop" principal , cadence cette application, et elle est prioritairement dédié à  l'interaction entre l'appli et l'utilisateur. On doit s'insérer dans cette logique , sans essayer de forcer le rythme. Mais rassurons-nous, il est prévu de pouvoir s'en abstraire en créant ses propres run loop comme le fait CoreAnimation,
    ou en créant des threads. 

    - Si tu as des calculs lourds, fais un thread ( éventuellement optimisé par exemple par OpenGL ou autre utilisation directe du C) 
    - Si tu as des animations indépendantes de l'intervention de l'utilisateur, utilise les CAAnimation, ou la méthode beginAnimations: context: de UIView.
  • DrakenDraken Membre
    16:41 modifié #28
    Voici un lien traitant des liens entre Open GL ES et CoreGraphic:

    [url=http://:http://www.mti.epita.fr/blogs/apple/2008/09/02/introduction-iphone-sdk-opengl-es/]:http://www.mti.epita.fr/blogs/apple/2008/09/02/introduction-iphone-sdk-opengl-es/[/url]

    Il y est notamment dis qu'OpenGL ES est la couche graphique de base du système. Petite citation extraite de l'article:

    Les frameworks
    Pour afficher, iPhoneOS, comme son grand frère MacOS X, repose sur OpenGL. Là -dessus reposent plusieurs couches logiciels, du plus bas au plus haut niveau, nous avons (je n'ai pas tout mis !) :

    OpenGL [ES] : bah on ne le présente plus...
    CoreGraphics : l'API C sur laquelle repose à  peu près tout ce qui se fait sur Mac et iPhone. Elle s'occupe de lier ce qu'il y a au-dessus avec OpenGL en tirant parti au mieux du matériel et des OS.
    Quartz2D : l'API C basé sur PDF et Postscript pour faire la 2D sur Mac et iPhone. Lorsque l'on ne fait pas de 3D, c'est ça qu'il faut utiliser.
    CoreAnimation : le framework Objective-C le plus haut niveau pour faire de la (fausse) 3D et animée sur Mac et iPhone. Il est organisé en couche, fait appelle à  tout ce qu'il a au-dessous de lui pour produire facilement des animations et effets kikoolol optimisés.
    UIKit : bah c'est ici que vous avez toutes les fenêtres, boutons, etc. Il n'y a rien à  faire niveau programmation graphique " sauf si vous voulez modifer l'aspect de vos éléments de l'application...


    Il serait d'ailleurs étonnant qu'OpenGL ES soit basé sur CoreGraphic, vu que Sony l'utilise dans la PS3 !

    Philippe, la fonction CGImageCreateWithImageInRect que tu utilises dans ta démo fonctionne parfaitement dans le cadre d'un scrolling sur une image fixe. Mais elle as le défaut d'allouer de la mémoire et de faire une copie des données graphiques à  chaque utilisation.

    Dans le cadre d'un jeu 2D comme inotia dont j'ai parlé plus haut, l'image de jeu est fabriquée par assemblage de centaines de petits éléments. En utilisant CGImageCreateWithImageInRect pour faire mes transferts d'images, je forcerais l'OS à  faire des centaines d'allocations mémoires/copie des données graphiques/affichages/désallocations mémoire pour chaque étape d'affichage. Avec une vitesse de 30 images/s comme le recommande Apple, ce serait des milliers de fois par seconde ! Je n'ai pas essayé, mais je doute que cela soit follement performant.

    Bon d'accord, il y a des tas d'optimisations possibles, comme utiliser un tampon pour stocker les blocs d'images les plus utilisées et ne pas les recalculer à  chaque fois. Ou découper les planches à  l'avance en .. STOP !

    Je me rend compte que je suis en train de m'étaler sur les techniques graphiques dans un topic pas conçu pour ça. J'était chaud pour parler de l'avantage d'utiliser OpenGL pour transférer des sprites d'une planche d'images vers l'écran, pour "teinter" la couleur d'un sprite et de l'utilisation des textures compressées pour économiser de la place. Et de mes démêles avec les scrollings quand je bossais chez Ubi Soft, il y a 20 ans, sur les premiers PC (processeur à  8 Mhz, 512 Ko de mémoire et carte vidéo CGA 320x200 en 4 couleurs!) et les Atari ST.

    Dis, monsieur le propriétaire des lieux, tu ne peut pas nous créer une section "Création des jeux vidéos sur iPhone/iTouch ?". Il me semble que c'est suffisamment spécifique pour être isolé du reste. Et en plus * voix racoleuse * ça devrait attirer le chaland !

    Pour finir, je joint à  ce post des exemples de planches d'éléments 2D utilisés pour faire des jeux style Inotia.

  • Philippe49Philippe49 Membre
    16:41 modifié #29
    dans 1246149689:

    Voici un lien traitant des liens entre Open GL ES et CoreGraphic:

    [url=http://:http://www.mti.epita.fr/blogs/apple/2008/09/02/introduction-iphone-sdk-opengl-es/]:http://www.mti.epita.fr/blogs/apple/2008/09/02/introduction-iphone-sdk-opengl-es/[/url]

    Il y est notamment dis qu'OpenGL ES est la couche graphique de base du système. Petite citation extraite de l'article:

    Les frameworks
    Pour afficher, iPhoneOS, comme son grand frère MacOS X, repose sur OpenGL. Là -dessus reposent plusieurs couches logiciels, du plus bas au plus haut niveau, nous avons (je n'ai pas tout mis !) :


    Tu extrapoles ce que dit ce texte. Voici la présentation des couches graphiques dans Quartz 2D Programming Guide .
    Rien ne dit que quand on utilise de l'openGL dans un programme, ce soit en prise directe avec la couche basse d'OpenGL, et connaissant Apple cela m'étonnerait fort. Voilà  la confusion.

    openGL ES ==> CoreAnimation  ==> OpenGL à  la sauce Apple
  • Philippe49Philippe49 Membre
    juin 2009 modifié #30
    dans 1246149689:

    Il serait d'ailleurs étonnant qu'OpenGL ES soit basé sur CoreGraphic, vu que Sony l'utilise dans la PS3 !

    Evidemment, je débute en OpenGL ES, mais à  ce que j'ai vu jusqu'à  maintenant c'est de la construction de buffers graphiques, en gros d'images. Ce que je pense c'est que ces buffers sont transmis à  la carte graphique sous le contrôle du système graphique Apple.

    dans 1246149689:

    Philippe, la fonction CGImageCreateWithImageInRect que tu utilises dans ta démo fonctionne parfaitement dans le cadre d'un scrolling sur une image fixe. Mais elle as le défaut d'allouer de la mémoire et de faire une copie des données graphiques à  chaque utilisation.

    Mais que fait OpenGL d'autre que d'allouer des tampons graphiques ?


    dans 1246149689:

    Dans le cadre d'un jeu 2D comme inotia dont j'ai parlé plus haut, l'image de jeu est fabriquée par assemblage de centaines de petits éléments.

    Certes tu gagnes en temps de création des images élémentaires, par contre en empreinte mémoire tu dois y perdre.
    Un principe de base de la programmation sur Mac/iPhone c'est le "lazy calcul" : Tant que tu n'as pas besoin d'une image, d'un xib, ... ne le charge pas

    dans 1246149689:

    En utilisant CGImageCreateWithImageInRect pour faire mes transferts d'images, je forcerais l'OS à  faire des centaines d'allocations mémoires/copie des données graphiques/affichages/désallocations mémoire pour chaque étape d'affichage. Avec une vitesse de 30 images/s comme le recommande Apple, ce serait des milliers de fois par seconde ! Je n'ai pas essayé, mais je doute que cela soit follement performant.

    Pour donner une idée, dans Count It Right, les calculs des solutions sont faits par écriture dynamique de toutes les solutions. Cela peut représenter jusqu'à  20 Mo de zone mémoire allouée (j'ai mesuré, cela m'inquiétait quand même un peu). Temps d'exécution moyen ? moins d'un centième de seconde (pour 2Mo). Et pendant ce temps les animations graphiques ne sont pas ralenties.
    Combien de mémoire utilise une image 100x100 ou même 480x320 ? On n'est à  peine au Mo !

    dans 1246149689:

    Bon d'accord, il y a des tas d'optimisations possibles, comme utiliser un tampon pour stocker les blocs d'images les plus utilisées et ne pas les recalculer à  chaque fois.

    Ton programme tient à  jour automatiquement les images en cache, du moins celles appelées par imageNamed par exemple.
  • vico92vico92 Membre
    juin 2009 modifié #31

    Philippe-> Si tu as des calculs lourds, fais un thread


    et c'est quoi, au juste, un thread ?

    Sympathique cette planche, Draken. J'adore entrer dans les entrailles d'un jeu, et j'ai toujours aimé le texturing 3D low poly qui donne ce genre de planche aussi ^^
Connectez-vous ou Inscrivez-vous pour répondre.