Comment faire bouger des formes (cercles, carrés, triangles, ...) aléatoirement

2

Réponses

  • CeetixCeetix Membre
    mars 2009 modifié #32
    Dsl erreur de manip,

    sinon je viens de piger pourquoi c'est plus dur, ta balle est mouvement.
    Au pire ralenti de vitesse ce sera plus simple.

    edit: tes commentaires de code sont en anglais. Essai de faire par toi même pour bien comprendre commen ca marche. Copier/coller n'est pas la bonne solution. Meme si tu n'arrives pas tout de suite à  ce que tu veux tu auras les bases pour aller plus loin.
  • AliGatorAliGator Membre, Modérateur
    10:47 modifié #33
    Je parierai pour un oubli de travailler dans le même repère donc un oubli de demander par exemple "locationInView:" sur le touch (ou de passer la mauvaise view en paramètre) ?
  • apocaalypsoapocaalypso Membre
    10:47 modifié #34
    dans 1236719452:

    Dsl erreur de manip,

    sinon je viens de piger pourquoi c'est plus dur, ta balle est mouvement.
    Au pire ralenti de vitesse ce sera plus simple.

    edit: tes commentaires de code sont en anglais. Essai de faire par toi même pour bien comprendre commen ca marche. Copier/coller n'est pas la bonne solution. Meme si tu n'arrives pas tout de suite à  ce que tu veux tu auras les bases pour aller plus loin.


    Je mets moi-même mes commentaires en anglais, pour que ce soit lu par tout le monde sur les forums. C'est moi qui ai fait mon code de a à  z.

    Sinon je pense maintenant que le problème se situe là  :
    UITouch *touch = [touches anyObject];<br />	CGPoint location = [touch locationInView:[touch view]];<br />
    
  • CeetixCeetix Membre
    mars 2009 modifié #35
    Mille excuses alors o:)
    Si tu mets :

    <br />	UITouch *touch = [[event allTouches] anyObject];<br />	CGPoint location = [touch locationInView:touch.view];<br />
    


    ca donne quoi?
  • apocaalypsoapocaalypso Membre
    10:47 modifié #36
    Une erreur.

    Mais je viens de m'apercevoir de quelque chose, dans ma console, à  chaque clique j'ai :
    X =-10.000000 | Y =-22.000000  ||  DoigtX =166.000000 | DoigtY =84.953613

    mais pour chaque clic le X et le Y restent pareils et ne changent pas. L'erreur doit venir d'ici, les coordonnées ne sont pas mises à  jour non ?
  • CeetixCeetix Membre
    10:47 modifié #37
    Bah je sais pas trop. Par contre c'est bizar, ta balle sort de l'écran. C'est normal?

    Je regarde ton code, pourquoi tu n'utilises pas cercle.center.x etc ... ? C'est bien les coordonnées de ton cercle que tu veux. non?
  • apocaalypsoapocaalypso Membre
    10:47 modifié #38
    Oui ce sont les coordonnées du cercles que je veux.

    Par contre ma balle ne sort pas de l'écran, elle rebondit bien contre les bords.
  • CeetixCeetix Membre
    10:47 modifié #39
    A la place de coordonnee.x et y dans le if de toucheBegan, met circle.center.x  vu que c'est ton objet que tu veux toucher...
  • apocaalypsoapocaalypso Membre
    mars 2009 modifié #40
    Je l'ai fait et ça marche niquel.

    Voici mon if :
    if(location.x &lt;= (circle.center.x+CIRCLE_RAYON) &amp;&amp; location.y &lt;= (circle.center.y+CIRCLE_RAYON))<br />
    


    Lorsque mon if est vérifié, j'exécute la fonction suivante qui me permet de changer la trajectoire de la nouvelle boule :
    // Function which display another shape randomly<br />-(void)randomAddShape<br />{<br />	[self addSubview:circle];<br />	<br />	coordonnees = CGPointMake(0,0);<br />	<br />	NSInteger nwx =&nbsp; 1 + arc4random() % 20;<br />	NSInteger nwy =&nbsp; 1 + arc4random() % 30;<br />	<br />	coordonnees = CGPointMake(nwx,nwy);<br />	[NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(randomMove) userInfo:nil repeats:YES];<br />}<br />
    


    Sauf que l'on peut quand même cliquer dans des parties de l'écran comme si l'on le faisait sur la boule.
  • CeetixCeetix Membre
    10:47 modifié #41
    Eu là  j'ai le cerveau en miette. Dodo et demain, si personne n'a répondu je reviens (vers 20h).
    Bonne nuit
  • AliGatorAliGator Membre, Modérateur
    10:47 modifié #42
    C'est pas touch.view qu'il faut utiliser, mais la vue qui te sert de "plateau de jeu", la vue dans laquelle sont placées tes balles.
    Il faut que tu utilises le même système de coordonnées dans les 2 cas, quand tu places tes balles dans ta vue principale (à  priori la view gérée par ton viewController j'imagine, en tout cas la superview de tes balles donc) et celui où dans lequel tu récupères les coordonnées du Touch.

    Là  tu as les coordonnées de tes balles dans leur superview (donc dans la vue qui te sert de "plateau de jeu" je dirais) mais tu demandes les coordonnées de ta vue dans touch.view qui est la vue qui se trouve sous ton toucher... qui est donc à  priori ta balle... Donc tu obtiendras à  priori par [locationInView:touch.view] toujours des coordonnées de ton "touch" dans... la vue de ta balle (donc les coordonnées seront toujours très petites et leur valeur max sera le rayon de ta balle...)

    Il suffit de remplacer par [locationInView:self] ou [locationInView:self.view], (selon si tu mets ce code dans la vue ou le viewController). Ceci dit puisque tu sembles avoir choisi comme solution de représenter chacune de tes balles par une UIView que tu mets en tant que subView dans ta UIView "plateau de jeu", tu devrais pouvoir directement récupérer la UIView et donc la balle qui était sous ton doigt via touch.view justement !! Bon après c'est pas très MVC et ça a les inconvénients qu'on évoquait dans les autres threads récents sur la gestion de vues pour les jeux du genre...
  • apocaalypsoapocaalypso Membre
    10:47 modifié #43
    Ca marche, il y a juste une petit partie de l'écran quand la balle est dans une position particulière que l'écran est actif comme la balle, je pense pouvoir régler ça tout seul.

    Par contre j'ai quelques petites questions.
    La première est que je voudrais savoir comment je peux charger un .png dans une UIImageView en gérant sa transparence de celui-ci. Comme dans cet exemple où je souhaite enlever le fond noir :
    Image+1.png

    La deuxième est que dans le code de la page que je vous ai donné, je charge le début de l'action de la balle avec awakeFromNib, donc, quand je charge mon jeu, même dans mon écran d'accueil le jeu est lancé en arrière tache (même sans le voir). J'ai donc essayer de le remplacer par loadView mais le fond d'écran que je charge à  l'aide de
    [self setBackgroundColor:[UIColor colorWithPatternImage:squared]];
    
    ne se met pas alors que dans awakeFromNib il s'affiche.

    Merci d'avance pour votre aide !

  • AliGatorAliGator Membre, Modérateur
    10:47 modifié #44
    Oulà  je crois qu'il y a certaines bases à  reprendre...

    Il faut que tu fasses une vue dédiée pour chaque partie de ton jeu (menu d'accueil, plateau de jeu avec les balles, tableau de high scores, etc etc), avec un ViewController dédié pour chacune, le mieux étant de les mettre dans un XIB séparé chacune, et demander par code au ViewController adéquat de se "pusher" quand tu souhaites afficher la vue.
    Ca c'est un grand classique dont tu trouveras pas mal d'exemples dans les templates Xcode. Lis la doc sur les ViewControllers & co dans la doc Apple aussi, c'est assez bien foutu ça devrait t'expliquer comment tout ça fonctionne.

    Une fois les NIB séparés faits, déjà  tu n'auras plus ce problème.

    Ensuite pour ton PNG, bah il suffit d'avoir un PNG avec un canal alpha (canal de transparence) qui fait que seule la balle est opaque et le reste est transparent (avec un dégradé de transparence sur les bords de la balle pourquoi pas pour faire une transition de opaque à  transparent entre la balle et son fond). A partir du moment où l'image PNG est bien faite avec son canal alpha, t'as rien à  faire en Cocoa pour gérer le reste, Cocoa sait prendre en compte la transparence du PNG et t'affichera la balle comme il faut sans le fond si ce dernier est bien transparent dans le PNG.

    Enfin pour tes calculs de clics, je ne vois pas en quoi il y aurait des cas particuliers, sauf si tu as utilisé touch.view pour savoir quelle vue était sous ton doigt et que tu n'as pas pris en compte le cas où la vue sous ton doigt était le plateau car aucune balle n'était par dessus à  cet endroit.

    Et enfin pour des questions d'optimisation déjà  discutées dans d'autres threads, utiliser une UIView pour chaque balle n'est pas la meilleure façon de procéder, une solution alternative aurait été de dessiner tes images (ou tes CGPath) toi-même dans la vue de plateau plutôt que d'utiliser des subViews... mais bon tu vas p'tet pas tout refaire now, ça dépend jusqu'où tu veux aller, ça t'obligerait à  refaire ton algo de détection de clic (que j'ai donné dans l'autre thread à  GreenSource pour la solution que j'évoque) donc à  toi de voir.
    Une autre solution vu que tu as bcp de rendu et de mouvement à  gérer serait de passer par OpenGL ES, mais je crois que c'est encore un peu tôt pour partir là -dessus et peut-être un peu machine à  gaz pour un premier projet... d'autant que même si tu y gagnerais en performances et donc en nombre de frames/seconde, c'est quand même un peu plus dur encore à  se plonger dedans (moi-même j'ai parfois du mal avec, c'est pas trivial)...


    Le mieux est peut-être de commencer par quelques tutos de montrant comment manipuler des ViewControllers différents, et comment personnaliser une UIView aussi, avec un exemple type comme il en existe dans la doc ou sur le net, pour revenir à  ton jeu ensuite avec une vision plus claire de tout ça. Rien ne sert de vouloir aller trop vite en besogne.
  • apocaalypsoapocaalypso Membre
    10:47 modifié #45
    Merci beaucoup pour ta réponse détaillé Ali !
    Oui, je suis encore débutant. Et c'est pour ça que je vais plutôt utiliser Quartz 2D pour créer mes cercles. Je pense que ça sera plus facile de les gérer.

    J'utilise ceci pour bouger mon cercle mais ça ne marche pas :
    myOval.origin = CGPointMake(myOval.origin.x+20, myOval.origin.y+100);<br />
    
    où myOval est de type CGRect.

    -(void)drawRect:(CGRect)rect<br />{<br />	CGPoint center = {30, 30};<br />	<br />	float radius = CIRCLE_DIAM * 0.5;<br />	<br />	CGRect myOval = {center.x - radius, center.y - radius, CIRCLE_DIAM, CIRCLE_DIAM};<br />	CGContextRef context = UIGraphicsGetCurrentContext();<br />	CGContextSetRGBFillColor(context, 106.0, 6.0, 0.0, 1.0);<br />	<br />	// Settings for the glow effect<br />	float glowWidth = 15.0;<br />	float colorValues&#91;] = { 1, 0, 1, 1.0 };<br />	CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();<br />	CGColorRef glowColor = CGColorCreate(colorSpace, colorValues);<br /><br />	CGContextSetShadowWithColor(context, CGSizeMake( 0.0, 0.0 ), glowWidth, glowColor);<br />	CGContextAddEllipseInRect(context, myOval);<br />	CGContextFillPath(context);<br />}
    


  • CeetixCeetix Membre
    10:47 modifié #46
    Il faut que tu refraichisses ta méthode drawRect. Tu vas donc faire un [self setNeedsDisplay] qui va rappelé ton drawRect et tout bien redessiner avec les nouvelles coordonnées.
  • apocaalypsoapocaalypso Membre
    10:47 modifié #47
    Il faut que je le mette dans le drawRect: ?
  • CeetixCeetix Membre
    10:47 modifié #48
    Non, à  chaque fois que tu modifies tes coordonnées dans une méthode autre, tu utilises setNeedsDisplay
  • apocaalypsoapocaalypso Membre
    10:47 modifié #49
    Je fais ça :
    blushBall.origin = CGPointMake(blushBall.origin.x+coordonnees.x, blushBall.origin.y+coordonnees.y);<br />
    
    et j'insère le [self setNeedsDisplay]; dans la fonction qui appelle mon drawRect: mais mon cercle ne bouge pas, il n'y a pas grand chose sur internet la dessus.
  • CeetixCeetix Membre
    10:47 modifié #50
    dans la fonction qui appelle mon drawRect

    Je comprends pas trop ta phrase.

    En gros :

    drawRect() {

    tu dessinnes ton cercle



    }

    uneFonction(){

    blushBall.origin = CGPointMake(blushBall.origin.x+coordonnees.x, blushBall.origin.y+coordonnees.y);

    et a la fin de cette fonction,
    [self setNeedsDisplay];

    }
  • apocaalypsoapocaalypso Membre
    10:47 modifié #51
    Voici mon nouveau drawRect:
    blushBall est initialisé CGRect blushBall;

    -(void)drawRect:(CGRect)rect<br />{	<br />	float diameter = 40.0;<br />	CGPoint center = {30,30};<br />	float radius = diameter * 0.5;<br />	<br />	CGRect blushBall = {center.x - radius, center.y - radius, diameter, diameter};<br />	<br />	CGContextRef context = UIGraphicsGetCurrentContext();<br />	CGContextSetRGBFillColor(context, 1.0, 0.0, 0.0, 1.0);<br />	//CGContextAddEllipseInRect(context, blushBall);<br />	CGContextFillEllipseInRect(context, blushBall);<br />	CGContextFillPath(context);<br />}<br />
    


    Fonction qui fait bouger le cercle
    -(void)randomMove<br />{	<br />	// Initalizing the circle<br /><br />	blushBall.origin = CGPointMake(blushBall.origin.x+coordonnees.x, blushBall.origin.y+coordonnees.y);<br /><br />	[self setNeedsDisplay];<br />}<br />
    


    et voici comment je met à  jour dans le awakeFromNib :
    NSInteger wx =&nbsp; 1 + arc4random() % 20;<br />	NSInteger wy =&nbsp; 1 + arc4random() % 30;<br />	<br />	coordonnees = CGPointMake(wx,wy);<br />	[NSTimer scheduledTimerWithTimeInterval:0.05 target:self selector:@selector(randomMove) userInfo:nil repeats:YES];
    

  • apocaalypsoapocaalypso Membre
    10:47 modifié #52
    J'avoue que là  je suis vraiment perdu.
    Autant il est simple de faire rebondir une UIImageView, autant il est compliqué de le faire avec un CGRect !
  • schlumschlum Membre
    10:47 modifié #53
    Non, c'est plus simple de faire bouger un dessin qu'une vue.

    Sauf que là  je vois pas ce que t'essaies de changer avec ton "blushBall.origin = ..."  ???
    Tous tes paramètres de dessin sont définies dans le "drawRect", donc je vois pas trop ce qui risque de bouger.
  • AliGatorAliGator Membre, Modérateur
    10:47 modifié #54
    Je vois deux incohérences dans ton code :

    1) Tu modifies "blushBall.origin" dans ton randomMove, mais qu'est-ce que blushBall ? Une variable d'instance de ta classe apparemment ? puisque tu ne la déclares pas dans ta fonction randomMove c'est qu'elle est déclarée en variable d'instance dans ton .h, non ? (et quel type au fait ?)
    Mais dans drawRect, tu déclares un CGRect du nom de blushBall... donc une variable de même nom, qui va venir masquer la déclaration de ta variable d'instance (si c'en est bien une) que tu utilises dans randomMove ! D'ailleurs tu as dû avoir un warning à  ce propos genre "declaration of blushBall shadows instance variable" ou un truc du genre qui te prévient du problème quand tu compiles...

    2) Tu modifies blushBall.origin dans randomMove... mais tu ne t'en sers jamais, puisque dans drawRect tu redéfinis blushBall, mais en plus sans te servir de ce blushBall.origin précédemment modifié ! Au lieu de ça tu redéfinis un CGRect toujours positionné au centre de ta vue (center.x & center.y c'est le center de l'objet dans lequel tu as mis ton code drawRect, j'imagine ta vue qui te sert de "plateau de jeu")... donc forcément il ne va pas bouger bien loin !
  • apocaalypsoapocaalypso Membre
    10:47 modifié #55
    Dans mon .h, blushBall est de type CGRect.
  • CeetixCeetix Membre
    10:47 modifié #56
    Alors tu n'as pas besoin de le redéclarer dans ton drawRect().
    Et oui, en fait tu fait bien bouger ta balle mais tu l'écrases dans drawRect().
  • apocaalypsoapocaalypso Membre
    10:47 modifié #57
    J'ai réussi a faire bouger mon cercle.
    Maintenant je veux lui associer une action lorsque l'utilisateur tappe dessus.

    J'ai repris l'idée de Ali mais le problème c'est que la zone active du cercle est seulement le quart en haut à  gauche, ce qui est logique d'après mon code :
    float droite = blushBall.origin.x-CIRCLE_RAYON;<br />	float haut = blushBall.origin.y+CIRCLE_RAYON;<br />	<br />		<br />	if(CGRectContainsPoint(CGRectMake(droite, haut, CIRCLE_DIAM, CIRCLE_DIAM), location))<br />	{<br />			blushBall = CGRectMake(0, 0, 0, 0);<br />	}<br />
    


    Mais je n'arrive pas à  créer le rectangle pour contenir la totalité de mon cercle, et pourtant j'ai fait des tonnes de dessins sur papier pour m'aider mais à  chaque fois une seule zone est couverte.

    Quelqu'un pourrait-il m'aider ?

    Merci d'avance !
  • AliGatorAliGator Membre, Modérateur
    10:47 modifié #58
    Heu c'est pas parce que droite et haut ne sont pas bons ?
    Déjà  tu appelles ta variable "droite" alors qu'en fait j'imagine que c'est plutôt le bord gauche de ta balle que tu voulais désigner...
    Ensuite du prends l'origine et tu enlèves le rayon... Mais l'origine de ta blushBall, ne serait-ce pas l'origine du CGRect qui encapsule ta balle ? Et donc déjà  son coin haut/gauche ! Tu dois confondre avec blushBall.center qui lui est le centre de ta balle !

    D'ailleurs je me demande si blushBall, si c'est un CGRect... n'est pas déjà  le rectangle qu'il te faut pour tester CGRectContainsPoint ! Si c'est pas déjà  le rectangle englobant de ta balle... du coup bas besoin de faire CGRectMake pour recréer un rectangle si tu as déjà  le bon...
  • schlumschlum Membre
    10:47 modifié #59
    Vous essayez tous de faire la même application là  ?  :P
    Vous pourriez vous organiser dans un seul sujet, ça serait plus pratique !  :)
  • apocaalypsoapocaalypso Membre
    10:47 modifié #60
    Oui j'avoue que c'est un peu désordonné... Désolé  ::)

    En remplaçant par blushBall ça marche, ça valait pas le coup que je me torture le cerveau... Effectivement blushBall est bien de type CGRect.
    Mais dans la fonction - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event, une fois que j'ai vérifier que le tap de l'utilisateur est bien sur la balle, il n'y a aucun moyen de modifier le l'apparence du cercle établit dans drawRect: ? Par exemple changer sa couleur et le faire disparaà®tre.

    Merci !

  • apocaalypsoapocaalypso Membre
    10:47 modifié #61
    Ce n'est pas possible ?
    Dans ce cas là , il faudrait que je fasse apparaà®tre un nouveau cercle aux même coordonnées que celui de départ.
Connectez-vous ou Inscrivez-vous pour répondre.