[Résolu] SpriteKit : calculer la distance entre deux texture masks

berfisberfis Membre
janvier 2017 modifié dans API AppKit #1

Bonjour,


 


J'ai deux formes irrégulières dans SpriteKit, et je veux calculer la distance verticale de la base d'un module lunaire et le terrain (irrégulier) juste à  l'aplomb. Le schéma joint aidera peut-être à  la compréhension.


 


J'ai posé la question sur SO, mais la réponse proposée (ajouter un SKPhysicsBody rectangulaire qui passe par le vaisseau et le sol, et calculer la différence entre les deux bodies dans le didBeginContact) ne fonctionne pas.


 


​En effet, soit j'ajoute le rectangle au vaisseau, mais celui-ci se retrouve à  se balancer au bout du rectangle comme une fleur au sommet de sa tige (et plus moyen de le faire bouger), soit je l'ajoute à  la scène, mais dans ce cas il ne suit pas le vaisseau si je le fais bouger latéralement (avec des tuyères directionnelles, vous voyez l'idée...)


 


Je suis obligé de faire ça, entre autres choses, parce que si l'objet est en chute libre (il y a une valeur pour la gravité du monde mis en scène), sa vitesse est de zéro (!). Je dois donc la calculer moi-même (déplacement du node / temps). Or j'aimerais connaà®tre la vitesse verticale avant l'impact.


 


Et de plus, pour savoir si l'engin est posé, je dois me livrer à  d'autres calculs, car la variable "isResting" est calculée tellement finement que l'engin bouge toujours à  la nième décimale, même si visuellement il est au repos... Il me faut donc cette altitude exacte.


 


Y a-t-il un moyen de faire ça?


Réponses

  • DrakenDraken Membre
    janvier 2017 modifié #2

    J'ai vu une copie d'écran de ton jeu dans le topic sur l'utilisation des particules pour donner l'impression d'un fond d'étoiles scintillantes. Je présume que le terrain est une image indépendante collée en bas de l'écran. Tu pourrais réaliser une carte des reliefs de l'image pixel par pixel en analysant sa structure. Il suffit de balayer chaque colonne du haut vers le bas en testant la couleur des pixels. 


     


    Couleur transparente, c'est le vide, on continue la lecture


    Couleur non transparente, c'est le "sol", on stocke l'altitude relative et on passe à  la colonne suivante.


     


    Tu fais ça avec un petit utilitaire spécialisé, générant un fichier de données, chargé ensuite par ton jeu. Cela ne prend pas beaucoup de place et te permet de connaà®tre au pixel prés l'altitude relative du "relief" par rapport au bord de la texture.

  • CéroceCéroce Membre, Modérateur
    J'avoue que je n'ai pas compris vraiment le problème. Alors désolé si je vais un peu vite en besogne, mais j'ai l'impression que tu te bas contre le moteur mécanique (les américains disent "physique") plutôt que l'utiliser.

    J'ai deux formes irrégulières dans SpriteKit, et je veux calculer la distance verticale de la base d'un module lunaire et le terrain (irrégulier) juste à  l'aplomb.

    Pourquoi? Ce n'est pas simple. Essaie de trouver une autre solution.

    Je suis obligé de faire ça, entre autres choses, parce que si l'objet est en chute libre (il y a une valeur pour la gravité du monde mis en scène), sa vitesse est de zéro (!).

    Un objet en chute libre qui a une vitesse nulle ???
     

    Et de plus, pour savoir si l'engin est posé, je dois me livrer à  d'autres calculs, car la variable "isResting" est calculée tellement finement que l'engin bouge toujours à  la nième décimale, même si visuellement il est au repos... Il me faut donc cette altitude exacte.
    Y a-t-il un moyen de faire ça?

    ça remonte à  loin, mais ce problème de précision est classique dans un moteur physique, et je crois me rappeler que Sprite Kit permet de spécifier un seuil.
  • Une question pour mieux comprendre ton problème : est-ce que tu utilises le moteur physique de SpriteKit pour gérer automatiquement les déplacements et les collisions des objets ou fais-tu les calculs "à  l'ancienne", avec tes propres formules ?

  • berfisberfis Membre
    janvier 2017 modifié #5


    Un objet en chute libre qui a une vitesse nulle ???




     


    Bah oui. Mon LEM tombe en chute libre et le physicalBody.velocity.dy donne une valeur de 0.00000000...


     


    Dès que le LEM percute, d'un coup il me donne la vitesse... mais c'est un peu tard pour corriger...


     


    Je suppose que pour que l'objet ait une vélocité, il faut lui appliquer une force "manuellement"...


     


    Il y a pas mal de choses qui me sont encore obscures dans SpriteKit. Mais bon, dès que je vois un cercle débuter à  droite et des angles qui se mesurent en radians dans le sens contraire des aiguilles de la montre, je me dis que je joue dans la cour des grands...


     


    @Draken: je laisse faire le moteur de Spritekit. Je suis vacciné contre le virus du NIH.


  • CéroceCéroce Membre, Modérateur

    Bah oui. Mon LEM tombe en chute libre et le physicalBody.velocity.dy donne une valeur de 0.00000000...
     Dès que le LEM percute, d'un coup il me donne la vitesse... mais c'est un peu tard pour corriger...

    D'accord, c'est sans doute parce que velocity tient uniquement compte des forces appliquées directement à  la fusée, mais pas l'attraction lunaire. Malheureusement, SK n'a pas l'air de proposer de propriété pour connaà®tre la vitesse. Une méthode possible est de noter la position à  la frame n-1, prendre celle à  la frame n, et faire la différence. ça donne une vitesse en points CG...
  • Merci Céroce, c'est bien ce que j'ai dû faire, dans le update:(CFTimeInterval)currentTime, je prends la dernière position stockée dans une propriété et je la soustrais à  la nouvelle. J'ai une distance en points, ce qui, en divisant par l'intervalle écoulé, me donne une vitesse...


     


    Il y a d'autres choses que SK ne permet pas, comme fixer un seuil à  ce "resting". C'est un peu agaçant ce "clé en main" sans même la possibilité d'aller bidouiller derrière...


     


    J'ai un autre problème mais je vais en faire au autre sujet.


  • Bonjour,


     


    Finalement, j'ai utilisé la suggestion de Draken, mais plutôt que de construire un utilitaire et de stocker les données à  charger dans le jeu, j'ai décidé d'analyser la texture directement dans le jeu: cela permet d'économiser du temps, surtout si je décide de changer les images par la suite. J'ai procédé comme ceci:



    CFDataRef imageData = CGDataProviderCopyData(CGImageGetDataProvider(terrain.texture.CGImage));
    const UInt32 *pixels = (const UInt32*)CFDataGetBytePtr(imageData);

    NSMutableArray *mut = [NSMutableArray new];
    for (long col = 0; col < terrain.size.width; col++)
    [mut addObject:@(0)];

    for (long ind = 0; ind < (terrain.size.height * terrain.size.width); ind++)
    {
    if (pixels[ind] & 0xff000000) // non-transparent pixel
    {
    long line = ind/terrain.size.width;
    long col = ind - (line*terrain.size.width);
    if ([mut[col]integerValue] <terrain.size.height-line) mut[col] = @(terrain.size.height-line);
    }

    Ce n'est pas très optimisé puisque je parcours l'ensemble des pixels, mais l'optimisation prématurée est la source des tous les maux, j'ai lu ça je ne sais plus trop où.


     


    Sur l'image jointe, on a de haut en bas l'image d'origine, sa "traduction" en pixels opaques et transparents, et la surface (en blanc) détectée par le "radar" du vaisseau.


     


    Merci de vos réponses, toujours instructives et stimulantes !


Connectez-vous ou Inscrivez-vous pour répondre.