Les membres ayant 30 points peuvent parler sur les canaux annonces, projets et hs du chat.
La shoutbox n'est pas chargée par défaut pour des raisons de performances. Cliquez pour charger.

Forum Casio - Autres questions


Index du Forum » Autres questions » Physique d'un grappin
Massena Hors ligne Ancien rédacteur Points: 2244 Défis: 11 Message

Physique d'un grappin

Posté le 09/01/2022 10:59

yow

En ce moment pour un petit projet d'add-in, j'ai besoin de développer un grappin.
Il pourra s'accrocher à des points fixes définis et permettra au joueur de s'élancer et/ou de prendre de la hauteur. N'ayant pas fait spécialité physique/chimie, je me retrouve dans le flou total quand il s'agit de programmer ce truc.

Cette mécanique est directement volée d'un demake PICO-8 de A Hat in Time (la mécanique rend très très bien). J'ai essayé de reprendre le code écrit en Lua afin de l'appliquer sur mon jeu, mais que ce soit sur un proto avec LÖVE ou bien en C sur mon jeu, ça donne un résultat catastrophique (en C, le personnage part même de manière incontrôlée par moment).

Voici le bout de code en question :

function move_hook(v)
-- Note : v représente le hook, p1 le joueur
-- p1.dx et p1.dy contiennent la vitesse du joueur
-- measure hyp between hook and
-- hat kid
        i = abs(v.x-p1.x)
        j = abs(v.y-p1.y)
        k = sqrt(i*i + j*j) -- calcul de la distance
        v.k = k
        if k < 40 and
                    v.y-p1.y < 0 then
            v.range = true
        else
            v.range = false  
        end
-- if hyp is short enough, set
-- latched to true
    if btn(5) and
                v.range == true then
        v.latch = true
    else
        v.latch = false
    end  

-- latch behavior
    if v.latch == true then
-- pull hat kid toward latch
-- distance sur les axes x et y entre le joueur et le crochet
            i = v.x-p1.x
            j = v.y-p1.y
-- ramène le joueur vers le crochet
         if abs(p1.dy)<5 then
             p1.dy += j*(1.2/k)
         end
         if abs(p1.dx)<5 then
                p1.dx += i*(.5/k)
            end
    end
end

Comme j'ai du mal à l'expliquer, voici un schéma :


Le grappin doit être en mesure de propulser le joueur lorsqu'il est au sol , mais aussi le balancer lorsqu'il est dans les airs. Je me demande si les deux comportements sont compatibles d'un point de vue physique, étant donné qu'il y en a qui demande le rétrecissement de la corde et l'autre de conserver une longueur égale x)

Quelqu'un aurait-il des pistes ou formules pour m'éclairer ?
Merci beaucoup

Fichier joint


Lephenixnoir En ligne Administrateur Points: 24670 Défis: 170 Message

Citer : Posté le 09/01/2022 11:10 | #


Je m'attends à ce que Kouhai ou quelqu'un d'autre donne plein de détails, alors juste une remarque rapide :

Le fait que le grappin puisse te tirer est indépendant du fait que tu puisses te balancer avec.

Quand il te tire, tu peux gérer le mouvement en ajoutant une force qui s'applique à ton personnage et qui t'envoie le long de la corde (ie. dans la direction du point d'accroche). Note que comme la gravité est toujours là tu vas automatiquement tourner (et si tu fais rien tu finiras à la verticale), ce qui est généralement normal.

Qu'il te tire ou pas, quand le grappin est accroché tu es contraint de te déplacer sur un disque autour du point d'accroche (tu ne peux pas t'éloigner plus du point d'accroche que la longueur du grappin à ce moment-là), ce que tu peux probablement modéliser par (1) calcul normal des forces, puis (2) si tu es sorti du cercle, tu te téléportes au point le plus proche du cercle (ie. tu ramènes le grappin à sa longueur normale mais sans changer l'angle que tu fais avec le point d'accroche).
Mon graphe (11 Avril): ((Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; passe gint 3 ; ...) || (shoutbox v5 ; v5)
Shadow15510 Hors ligne Administrateur Points: 5504 Défis: 18 Message

Citer : Posté le 09/01/2022 11:11 | #


C'est de la mécanique toute bête C'est des équations de paraboles.

Pour certains il faudrait que je fasse des calculs en prenant une masse pour le joueur, pour le cas en bas à droite, l'angle θ est une fonction du temps et vérifie l'équa diff :
d²θ/dt² + g/l sin θ = 0 (avec l la longeur de la corde)
Je t'épargne les détails, mais si je me souviens bien, θ(t) = v / sqrt(g / l) × sin(sqrt(g/l) t) avec l la longueur de ta corde. (Lephe ou Alice pour confirmer, je suis pas contre xD)
"Ce n'est pas parce que les chose sont dures que nous ne les faisons pas, c'est parce que nous ne les faisons pas qu'elles sont dures." Sénèque

Lephenixnoir En ligne Administrateur Points: 24670 Défis: 170 Message

Citer : Posté le 09/01/2022 11:14 | #


Je suis à peu près sûr que si tu t'accroches à un moment où ta vitesse est tangente tu fais un arc de cercle... à vérifier du coup, tu me mets le doute.
Mon graphe (11 Avril): ((Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; passe gint 3 ; ...) || (shoutbox v5 ; v5)
Shadow15510 Hors ligne Administrateur Points: 5504 Défis: 18 Message

Citer : Posté le 09/01/2022 11:23 | #


Ce serait juste un sinus du temps alors ?

Pour le cas en bas à gauche, c'est assez simple, tant que ton personnage monte tu peux juste augmenter sa vitesse de déplacement vers le haut selon une exponentielle (c'est pas de la méca là) genre x_max (1 - exp(-t/X)) avec X une constante positive. Tu peux prendre une loi linéaire aussi.
Si ton personnage à une masse m, on a
sa vitesse : v = -mg⋅t + v0 où v0 est la vitesse au moment du lâcher
sa position : x = -mg⋅t² + v0⋅t + x0 où x0 est la position au moment du lâcher
"Ce n'est pas parce que les chose sont dures que nous ne les faisons pas, c'est parce que nous ne les faisons pas qu'elles sont dures." Sénèque

Gladosse Hors ligne Membre Points: 229 Défis: 2 Message

Citer : Posté le 09/01/2022 11:24 | #


je crois ca a quelque chose a voir avec le momentum, je ne connais que le mot et vaguement le concept, je t'invite a continuer ta recherche par toi meme (la force de gravite est limitee par le fil et donc toute cette force devient une force sur l'axe x et non y je crois)

apres le cours de physique le plus avance que j'ai fait c'est un cours sur le mouvement, donc je ne suis pas une source vraiment credible
Shadow15510 Hors ligne Administrateur Points: 5504 Défis: 18 Message

Citer : Posté le 09/01/2022 11:30 | #


Lephé : pour le grappin et le personnage qui tourne autour du point d'accorche, ça peut pas être juste un arc de cercle, la gravité va tendre à faire osciller le personnage autour de la seule position d'équilibre stable, donc c'est bien une équa diff (sans doute d'ordre 1 car on va dire que les frottements, osef ). Ceci dit, celle que j'ai balancée tout à l'heure, je l'ai fait de tête, donc c'est largement possible qu'elle soit fausse x)
"Ce n'est pas parce que les chose sont dures que nous ne les faisons pas, c'est parce que nous ne les faisons pas qu'elles sont dures." Sénèque

Lephenixnoir En ligne Administrateur Points: 24670 Défis: 170 Message

Citer : Posté le 09/01/2022 11:32 | #


On oscille oui... sur un arc de cercle. Je vois pas trop comment ça pourrait être une parabole vu que la corde est toujours tendue ; la distance entre le point d'accroche et la position du joueur est donc forcément une constante.

Je suis d'accord cela dit qu'une formulation en équa diffs est supérieure, comme ça t'as juste à intégrer par simulation et en termes de code c'est trivial. C'est un peu ce qui se passe dans le code Lua d'ailleurs, si mes yeux ne me trompent pas.
Mon graphe (11 Avril): ((Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; passe gint 3 ; ...) || (shoutbox v5 ; v5)
Shadow15510 Hors ligne Administrateur Points: 5504 Défis: 18 Message

Citer : Posté le 09/01/2022 11:34 | #


Ah si la longueur est constante, oui ça doit faire un arc de cercle
"Ce n'est pas parce que les chose sont dures que nous ne les faisons pas, c'est parce que nous ne les faisons pas qu'elles sont dures." Sénèque

Gladosse Hors ligne Membre Points: 229 Défis: 2 Message

Citer : Posté le 09/01/2022 11:38 | #


quand le joueur est au dessus du sommet du fil c'est une droite qui va vers le bas non?
Shadow15510 Hors ligne Administrateur Points: 5504 Défis: 18 Message

Citer : Posté le 09/01/2022 11:50 | #


@Gladosse : j'ai pas tout compris… le joueur ne peut pas rester au dessus de son point d'accroche, la gravité va tendre à le ramener vers le bas. Note que si le fil avait été une tige, ça aurait été possible, mais c'est une position d'équilibre instable (un toute petite variation suffit à faire repartir le pendule vers une position d'équilibre stable)

Pour le cas du grappin qui tire le joueur selon une ligne oblique, si je me suis pas planté, on a :
sa vitesse selon l'axe des x : -gt + v0x sin α
sa vitesse selon l'axe des y : v0y⋅cos α

sa position selon l'axe des x : -gt²/2 + v0⋅t⋅sin α + x0x
sa position selon l'axe des y : v0⋅t⋅cos α + x0y

En notant :
α l'angle entre l'axe des y et le segment qui représente le fil du grappin
v0x, v0y les composantes selon x et y du vecteur vitesse à l'instant initial (au moment où le joueur relâche le grappin)
x0x, x0y idem mais pour la position

Ajouté le 09/01/2022 à 11:57 :
Pour le cas en haut à droite, c'est un mélange entre les cas précédents :
- La petite parabole que tu as dessiné, correspond à une équation du second degré (cf. mon message précédent)
- L'arc de cercle parcouru par le joueur est donné par une équation différentielle, d²θ/dt² + g/l sinθ = 0 avec θ l'angle que le fil forme avec l'axe des x. J'essaye de la résoudre, mais je suis pas trop familier avec les équa diff du second ordre à coefficients non constants ^^' ça va faire un truc de la forme θ(t) = A cos(sqrt(g/l)⋅t) + B sin(sqrt(g/l)⋅t) mais

Ajouté le 09/01/2022 à 12:07 :
Bon, je crois que j'ai trouvé, c'est pas très joli comme expression, mais si je me suis pas planté,
la vitesse angulaire dθ/dt a pour expression :
dθ/dt (t) = -θ0⋅w0⋅sin(w0⋅t) + v0⋅cos(w0⋅t)

et l'angle θ a pour expression :
θ(t) = θ0⋅cos(w0⋅t) + (v0 / w0)⋅sin(w0⋅t)

Avec v0 la vitesse au moment où le grappin s'accroche
θ0 l'angle entre l'axe des x et le fil du grappin au moment où le grappin s'accroche
w0, (la pulsation caractéristique) qui a pour expression : sqtr(g / l) avec g la gravité, et l la longueur du fil

Je suis contre une vérification, mais je crois que c'est correct
"Ce n'est pas parce que les chose sont dures que nous ne les faisons pas, c'est parce que nous ne les faisons pas qu'elles sont dures." Sénèque

Massena Hors ligne Ancien rédacteur Points: 2244 Défis: 11 Message

Citer : Posté le 09/01/2022 13:04 | #


Je vais être franc : J'ai pas réussir à suivre tes explications Shadow

Du coup il faudrait avoir deux comportements différents, un pour le propulsage et l'autre pour le balancement ?
Et les ⋅ c'est une multiplication ou un produit scalaire ?
Ninestars Hors ligne Membre Points: 2462 Défis: 24 Message

Citer : Posté le 09/01/2022 13:09 | #


Salut Massena,

Les équations de Shadows sont sans doute correctes, mais tu ne pourras pas les exploiter pour ton jeu.
L'approche par équation exact ne me semble pas la bonne approche.

Après avoir joué au jeu quelques minutes, pense que la mécanique est très simple

Vecteur2D player_hook = (hook.position - player.position) / distance_sqrt(hook.position - player.position) // vecteur normalisé
player.acceleration += player_hook * coef // on modifie l'acceleration du joueur
si (player.acceleration > acceleration_max) player.acceleration = acceleration_max // on bride l'acceleration
Shadow15510 Hors ligne Administrateur Points: 5504 Défis: 18 Message

Citer : Posté le 09/01/2022 13:21 | #


Du coup il faudrait avoir deux comportements différents, un pour le propulsage et l'autre pour le balancement ?

Je pense que oui ^^' Après l'idée de Ninestars me paraît bien, tu n'as peut-être pas besoin des équations du mouvements exacte.

Et les ⋅ c'est une multiplication ou un produit scalaire

Désolé pour la notation foireuse ^^' c'est bien une multiplication (note que la multiplication usuelle est un produit scalaire, donc l'un dans l'autre… bon voila xD)


Les équations de Shadows sont sans doute correctes, mais tu ne pourras pas les exploiter pour ton jeu.

Ces équations permettent de trouver les vecteurs vitesse et la position du joueur à tout instant, je pense que ça peut être implémenter et même plutôt bien fonctionner Après c'est pas forcément le plus simple à mettre en place, je suis d'accord.
"Ce n'est pas parce que les chose sont dures que nous ne les faisons pas, c'est parce que nous ne les faisons pas qu'elles sont dures." Sénèque

Shadow15510 Hors ligne Administrateur Points: 5504 Défis: 18 Message

Citer : Posté le 09/01/2022 14:25 | # | Fichier joint


Je met en fichier joint un doc avec les équations de la position et de la vitesse du joueur dans les différents cas de figure.
"Ce n'est pas parce que les chose sont dures que nous ne les faisons pas, c'est parce que nous ne les faisons pas qu'elles sont dures." Sénèque

Massena Hors ligne Ancien rédacteur Points: 2244 Défis: 11 Message

Citer : Posté le 09/01/2022 15:15 | #


Merci beaucoup, ça marche beaucoup mieux ! Désolé Shadow si tu t'es embêté à faire un PDF pour rien, mais la méthode de Ninestars était beaucoup plus simple et accessible à mon niveau

Voici le code pour les interessés :

void
player_hook(void)
{
    struct Vec2 player_middle = {player.pos.x + PLAYER_S / 2,
                                 player.pos.y + PLAYER_S / 2};

    /* get the nearest hook */
    if (!player.locked) {
        player.hook_pos = hook_closest(&player_middle);
    }

    const float dist = length(player_middle.x, player_middle.y,
                              player.hook_pos.x, player.hook_pos.y);

    /* if the nearest hook is in range */
    if (dist < 100 && player_middle.y > player.hook_pos.y) {
        player.hooking = 1;
        player.locked = 1;
        player.jumping = 1;
    }

    if (player.hooking && dist) {
        /* determining hook force */
        float dist_x = player.hook_pos.x - player_middle.x;
        float dist_y = player.hook_pos.y - player_middle.y;

        struct FVec2 force = {};
        if (dist_x) {
            force.x = dist_x / dist;
        }
        if (dist_y) {
            force.y = dist_y / dist;
        }

        /* apply hook force */
        player.spd.x += force.x;
        player.spd.y += force.y;

        /* cap speed */
        if (abs(player.spd.x) > 16) {
            player.spd.x = 8 * sign(player.spd.x);
        }
        if (abs(player.spd.y) > 8) {
            player.spd.y = 8 * sign(player.spd.y);
        }
    }
}
Shadow15510 Hors ligne Administrateur Points: 5504 Défis: 18 Message

Citer : Posté le 09/01/2022 15:16 | #


Y a aucun problème, ça m'a fait réviser ma méca.
"Ce n'est pas parce que les chose sont dures que nous ne les faisons pas, c'est parce que nous ne les faisons pas qu'elles sont dures." Sénèque

Ninestars Hors ligne Membre Points: 2462 Défis: 24 Message

Citer : Posté le 09/01/2022 16:25 | #


Avec plaisir

Au passage, dans ton code tu peux retirer les conditions pour éviter les divisions:
if (dist_x) et if (dist_y)
car 99 fois sur 100 ta force sera sur deux dimensions.

T'as peut être une erreur sur le player.spd.x = 8 * sign(player.spd.x); ? Ce ne serait pas un 16 plutôt ?
Massena Hors ligne Ancien rédacteur Points: 2244 Défis: 11 Message

Citer : Posté le 09/01/2022 16:30 | #


Bien vu pour les deux, c'est corrigé. Merci

LienAjouter une imageAjouter une vidéoAjouter un lien vers un profilAjouter du codeCiterAjouter un spoiler(texte affichable/masquable par un clic)Ajouter une barre de progressionItaliqueGrasSoulignéAfficher du texte barréCentréJustifiéPlus petitPlus grandPlus de smileys !
Cliquez pour épingler Cliquez pour détacher Cliquez pour fermer
Alignement de l'image: Redimensionnement de l'image (en pixel):
Afficher la liste des membres
:bow: :cool: :good: :love: ^^
:omg: :fusil: :aie: :argh: :mdr:
:boulet2: :thx: :champ: :whistle: :bounce:
valider
 :)  ;)  :D  :p
 :lol:  8)  :(  :@
 0_0  :oops:  :grr:  :E
 :O  :sry:  :mmm:  :waza:
 :'(  :here:  ^^  >:)

Σ π θ ± α β γ δ Δ σ λ
Veuillez donner la réponse en chiffre
Vous devez activer le Javascript dans votre navigateur pour pouvoir valider ce formulaire.

Si vous n'avez pas volontairement désactivé cette fonctionnalité de votre navigateur, il s'agit probablement d'un bug : contactez l'équipe de Planète Casio.

Planète Casio v4.3 © créé par Neuronix et Muelsaco 2004 - 2024 | Il y a 202 connectés | Nous contacter | Qui sommes-nous ? | Licences et remerciements

Planète Casio est un site communautaire non affilié à Casio. Toute reproduction de Planète Casio, même partielle, est interdite.
Les programmes et autres publications présentes sur Planète Casio restent la propriété de leurs auteurs et peuvent être soumis à des licences ou copyrights.
CASIO est une marque déposée par CASIO Computer Co., Ltd