Random "pas si random que ça"
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
(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
Connectez-vous ou Inscrivez-vous pour répondre.
Réponses
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...
Le principe de la marche aléatoire s'occupe du reste.
Sinon, autrement, et encore plus simple:
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é.
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.
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 ?
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, 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 ?)
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 )
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)
(Mine de rien, il commence à avoir de la gueule, mon jeu. J'ai hâte de vous le faire essayer ^^)
M(t)=M(0)*(1-t)^3+...
et il suffit de prendre M(t) à une seule dimension.
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:
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à ^^
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)
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:
Donc, si tu utilises random(), il faut initialiser avec srandom(time(NULL)) ou, mieux encore, avec sranddev().
EDIT : srandomdev(), pas sranddev()
et pkoi c mieux avec sranddev() ?
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é...^^
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 ?
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.
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.
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 ?
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.
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.
(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 ?
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:
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.
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.
Tu veux dire que le scrolling des view apple n'est pas au point ?
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.
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.
[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:
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.
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
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.
Mais que fait OpenGL d'autre que d'allouer des tampons graphiques ?
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
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 !
Ton programme tient à jour automatiquement les images en cache, du moins celles appelées par imageNamed par exemple.
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 ^^