conseil pour afficher des images en mouvement
macounette
Membre
Bonjour,
je débute dans mon application iPhone. J'ai de bonnes bases en développement, mais je suis une newbie en objective-C...
J'aimerais pour l'instant que mon appli affiche un nombre N d'images qui flotte en gravité sur l'écran avec gestion des collisions. Pour le moment si j'arrive à afficher N-images qui bougent je m'en contenterais ! :P
Je suis partie de ces tutos :
http://www.bit-101.com/blog/?p=1784
et aussi ici :
http://cedsoft.blogspot.com/2007/11/dveloppement-iphone-utilisation-de.html
Pour l'instant avec mon code j'arrive bien à afficher une balle en mouvement sur l'écran.
GTViewController.h // Ma vue principale
GTViewController.m
Ball.h // Ma balle avec ces coordonnées
Ball.m
Le problème c'est que si je veux en afficher 2, je suis obliger de créer 2 instances pour Ball et pour ma UIImageView :
Ce n'est pas du tout pratique si j'ai N images à afficher (N étant un nombre aléatoire...)
Avant de continuer plus loin dans mon développement, j'aimerais d'abord savoir si je suis bien partie (histoire de pas tout recommencer à la fin). Et surtout j'aimerais avoir quelques pistes pour afficher mes N-images sans trop problèmes pour la suite (l'ajout de la gravité et la gestion des collisions). Je m'embrouille assez vite avec les view, les NSobject... Je pensais à utiliser un tableau de Ball ? Je pars mal ?
Merci de vos conseils avisés !
Macounette
je débute dans mon application iPhone. J'ai de bonnes bases en développement, mais je suis une newbie en objective-C...
J'aimerais pour l'instant que mon appli affiche un nombre N d'images qui flotte en gravité sur l'écran avec gestion des collisions. Pour le moment si j'arrive à afficher N-images qui bougent je m'en contenterais ! :P
Je suis partie de ces tutos :
http://www.bit-101.com/blog/?p=1784
et aussi ici :
http://cedsoft.blogspot.com/2007/11/dveloppement-iphone-utilisation-de.html
Pour l'instant avec mon code j'arrive bien à afficher une balle en mouvement sur l'écran.
GTViewController.h // Ma vue principale
@interface GTViewController : UIViewController {<br /> Ball *ball;<br /> UIImageView* fireBall;<br /><br />}<br /><br />- (void)onTimer;
GTViewController.m
- (void)viewDidLoad {<br />void)viewDidLoad {<br /> [super viewDidLoad];<br /> <br /> ball = [Ball alloc];<br /> ball.position = CGPointMake(100, 100);<br /> ball.velocity = CGPointMake(4.0, 3.0);<br /> ball.radius = 25.0; <br /> fireBall = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"fireball.png"]];<br /> [NSTimer scheduledTimerWithTimeInterval:1.0 / 30.0 target:self selector:@selector(onTimer) userInfo:nil repeats:YES];<br />}<br /><br />-(void) onTimer {<br /> [ball update];<br /> fireBall.center = CGPointMake(ball.position.x, ball.position.y);<br /> [self.view addSubview:fireBall];<br />}
Ball.h // Ma balle avec ces coordonnées
@interface Ball : NSObject {<br /> CGPoint position;<br /> CGPoint velocity;<br /> CGFloat radius;<br />}<br /><br />@property CGPoint position;<br />@property CGPoint velocity;<br />@property CGFloat radius;<br />@property CGColorRef color;<br /><br />- (void)update;
Ball.m
- (void)update {<br /><br /> position.x += velocity.x;<br /> position.y += velocity.y;<br /> <br /> if(position.x + radius> 320.0) {<br /> position.x = 320.0 - radius;<br /> velocity.x *= -1.0;<br /> }<br /> else if(position.x - radius <0.0) {<br /> position.x = radius;<br /> velocity.x *= -1.0;<br /> }<br /> <br /> if(position.y + radius> 460.0) {<br /> position.y = 460.0 - radius;<br /> velocity.y *= -1.0;<br /> }<br /> else if(position.y - radius <0.0) {<br /> position.y = radius;<br /> velocity.y *= -1.0;<br /> }<br />}
Le problème c'est que si je veux en afficher 2, je suis obliger de créer 2 instances pour Ball et pour ma UIImageView :
@interface GTViewController : UIViewController {<br /> Ball *ball;<br /> UIImageView* fireBall;<br /> Ball *ball2;<br /> UIImageView* fireBall2;<br /><br />}
Ce n'est pas du tout pratique si j'ai N images à afficher (N étant un nombre aléatoire...)
Avant de continuer plus loin dans mon développement, j'aimerais d'abord savoir si je suis bien partie (histoire de pas tout recommencer à la fin). Et surtout j'aimerais avoir quelques pistes pour afficher mes N-images sans trop problèmes pour la suite (l'ajout de la gravité et la gestion des collisions). Je m'embrouille assez vite avec les view, les NSobject... Je pensais à utiliser un tableau de Ball ? Je pars mal ?
Merci de vos conseils avisés !
Macounette
Connectez-vous ou Inscrivez-vous pour répondre.
Réponses
Une balle soumise à la gravité fait des paraboles, elle ne va pas tout droit...
Voilà une petite video de démo. Si c'est un truc dans le genre que tu veux, dis moi j'essaierai de t'expliquer
Eu sinon Shlum, en admettant que la gravité "ancrée" dans le sol (la bas de son iPhone) il n'y aura pas de parabole(enfin très très très peu visible). Par contre si sa gravité s'effectue sur un point beaucoup plus petit, là il y a bien paralabole. No?
Normal ! Pour l'instant je ne gère pas du tout la gravité. Je souhaite juste afficher de manière intelligente 2 balles qui rebondissent sur les bords de l'écran. La trajectoire est rectiligne et différente pour chaque balle. Après je rajouterais des choses plus complexes...
Là j'arrive bien à avoir mes balles, elles rebondissent bien sur les bords, mais je ne peux pas utiliser mon code pour n-balles.
Je voudrais juste qu'on m'éclaire un peu sur la façon de gérer mes objets et mes vues de manière à ce que je puisse utiliser N-balles. Parce que je sais pas comment m'en sortir.
Ta classe Ball ne possède pas de méthode d'init: c'est mal.
Ne pas oublier la méthode -dealloc:
Quand ton timer est déclenché:
(d'ailleurs, ce serait plutôt la méthode -[display] que -[update]).
Une fois que t'as ta classe balle qui bouge, tu en fais plusieurs instances (en attribuant à chacune un point de départ et une vitesse initiale), puis tu les mets toutes à jours à la fois dans le timer.
Gérer l'interactivité c'est beaucoup plus complexe là par contre !
Au moment où tu fais la mise à jour, il faut récupérer les coordonnées de toutes les autres balles pour détecter les collisions (et avoir un algo efficace pour écarter très vite des calculs les balles suffisamment loin).
Ma balle ball.h est maintenant définit comme suit :
GTViewController.m :
GTViewController.h :
Ca marche bien, mais je voudrais éviter d'utiliser dans mon timer : [ballArray objectAtIndex:0];
Là tout va bien car je n'ai qu'une balle, mais si j'en ai plusieurs je fais comment ?
Il y a un moyen d'utiliser autre chose qu'un objectAtIndex et une boucle ?
aSelector
The message to send to target when the timer fires.
The selector must have the following signature:
- (void)timerFireMethod:(NSTimer*)theTimer
The timer passes itself as the argument to this method.
Pour la balle, tu passes son numéro dans le champ userInfo, il est là pour cela.
[EDIT] mais bon as-tu besoin de faire cela ?
[self.view addSubview:ball.imageBall];
Ce n'est pas ta méthode display qui s'en occupe ?
Et en fait cette méthode n'apparaà®t pas dans ton ball.h ? ou alors tu ne l'as pas recopiée ici ?!
Et puis pourquoi tu ajoutes ta balle en tant que subview... dans ta méthode de timer ?! Tu veux ajouter une balle toutes les N secondes ? Bizarre ça
Et enfin, tu appelles la méthode... display des tes balles/NSViews ?! Il ne faut jamais appeller display directement, ni drawRect d'ailleurs, seulement mettre le code du dessin dans drawRect et appeler setNeedsDisplay pour forcer le réaffichage...
Oui là Ceroce n'a pas fait attention en te conseillant ce nom (le matin c'est moi qui :fouf): mais le soir on me remplace ;D ), quoique display n'apparaà®t pas dans le SDK iphone (sauf pour CALayer) contrairement au mécanisme dans NSView. Donc c'est moins grave.
On est aux p'tits soins !
Au fait bienvenue sur le forum, et il faudrait voir à payer son coup !!
La méthode appelée par ton timer doit
1) régler le problème des collisions
2) demander la mise à jour de l'interface
Pour le 1) c'est ce que dis Schlum, et cela c'est pas simple à optimiser si le nombre de balles est grand. Si tu envisages 3, 5 boules une simple double boucle suffit, sinon on pourrait penser à utiliser une triangulation (découpage de l'écran en triangles ) ou peut-être à la mise à jour à chaque temps d'horloge d'un polygone des voisins de chaque balle. Ce dernier cas signifiant que l'on charge la classe Ball d'une variable d'instance désignant le polygone des balles autour de cette balle, cosntamment mis à jour. Il faut voir dans les problèmes d'algorithmique géométrique si il n'y a pas autre chose.
Le 2) c'est ce que tu fais dans [ballArray makeObjectsPerformSelector:@selector(update)]; les caluls des nouvelles positions étant faites au point 1.
[/quote]
Ouep ben c'est pas gagné. J'envisage beaucoup plus de boules... Rien que le mot triangulation me fait peur. :-\\
Bon première étape , je remet mon code au propre en fonction de vos remarques. Et on attaque les collisions après ! On y croit !
Faut chercher sur Google, y a sans doute des infos.
http://fr.wikipedia.org/wiki/Détection_de_collision
Bon je suis désolée, il y a un truc que j'ai pas compris
Alors j'ai :
- GTViewController.h qui crée mes balles dans viewDidLoad et qui lance le timer.
- un NSObject Ball.h qui contient une méthode update qui met à jour les coordonnées de la balle.
Est-ce que c'est dans Ball.h que je dois définir mon drawRect pour dessiner mon image ?
Est-ce que setNeedsDisplay doit être appeler dans mon timer ou dans ma méthode update ?
Parce que setNeedsDisplay rafraà®chit une UIView du coup elle ne peut pas être dans mon update d'un NSObject...
Alors est-ce que ma balle est bien un NSObject ? Est-ce que je n'aurais pas besoin d'une UIView supplémentaire ou je peux m'en sortir sans ?
Je crois que je me suis embrouillée aujourd'hui. J'aurais peut-être les idées plus claires demain
- GTViewController.h qui crée mes balles dans viewDidLoad et qui lance le timer.
- un NSObject Ball.h qui contient une méthode update qui met à jour les coordonnées de la balle.
- une UIView BallView qui contient mon drawrect et qui utilise le setNeedsDisplay
dans GTViewController.m
dans BallView.m
Bon voilà c'est mieux ? J'avance ?
Par contre gros problème je pense que mon [(BallView *)self.view refresh:rect]; n'est pas au bon endroit. Car du coup même si je créé plusieurs instance de balles, je n'en aurais qu'une qui s'affiche.
Ca donnerais ça avec plusieurs balles (c'est pour l'exemple car c'est pas très propre...) :
Je chiante hein ? Milles merci de m'aider, je cherches beaucoup d'exemple sur le net mais je trouve tout et n'importe quoi. Alors pour savoir ce qui est bien ou pas...
ça dépend, c'est une question d'architecture. On pourrait imaginer que la vue récupère les coordonnées de toutes les balles et les dessine. Cependant, il paraà®t plus commode (dans la logique "objet", s'entend) qu'un balle sache se dessiner elle-même. Dans ce cas, elle comporterait une méthode -draw " et non pas -drawRect:, puisque la balle connaà®t ses coordonnées.
Dans ce cas, la vue n'a plus besoin d'appeler une méthode -[Ball update], puisque la mise à jour des coordonnées se ferait juste avant le dessin de la balle.
Certains y ont vu de la fumette :fouf):, mais il y avait bien une intention dans ce que j'avais écris la première fois ! (Comment ça je suis de mauvaise fois ? >:D)
Dans ton timer, d'ailleurs, c'est la seule chose que tu aies à y mettre. Comprends que quand tu appelles -setNeedsUpdate:YES, le dessin n'est pas immédiat. Dans la prochaine boucle du runtime objC, ta view va regarder si elle a besoin d'être rafraà®chie (= needs update), et si c'est le cas, elle appellera sa méthode -drawRect:. Là , tu pourras appeler la méthode -draw de toutes tes balles.
Oui, une balle hérite de NSObject.
Tu pourrais imaginer créer une UIView pour représenter chaque balle et l'insérer dans la vue parente, mais ce n'est pas du tout la bonne approche, aussi bien en termes de performances que de complexité.
Sauf que dans le cas de GreenSource ce n'était pas animé, mais le principe est le même, une classe "modèle" pour gérer tes balles, leur position, etc... et une classe Vue qui, dans son drawRect, demande à chaque balle de se dessiner elle-même (mettant à jour ses coordonnées auparavant)
exemple dans CGPathFunHouse
Je publie mon code ici pour aider comme moi les gens qui galère
Ma UIView BallView :
Mon Objet Ball :
J'avais réussi à afficher dans 1 vue BallView, des balles en mouvement. C'était l'étape 1.
L'étape 2 consiste à avoir sur l'écran, 2 zones distinctes, dans lesquelles des balles vont se déplacer.
Imaginons que l'on coupe l'écran en 2. Dans ma "zone" supérieure j'aurais par exemple 3 balles en mouvement qui ne se déplaceront que dans cette zone (en rebondissant sur les bords de la zone). Dans ma "zone" inférieure, j'aurais 1 balle en mouvement.
La problématique est donc d'afficher 2 zone distinctes indépendantes contenant des balles qui rebondissent. Je n'y arrive pas.
J'ai un TestViewController.m qui me permettrait d'afficher mes 2 vues
Mon UIView BallView.m permet de créer un tableau de NSObject Ball et de les mouvoir
Avec ça, le résultat est horrible :-\\ Je n'ai même pas 2 vues qui s'affiche.
Je soupçonne que mon TestViewController.m n'est pas comme il faut.
Un coup de main ne serait pas de refus, ça fait des jours que je cherche en vain...