4
votes

La balle rebondit le long d'une trajectoire parabolique

La question a été initiée par un sujet

Dans cette question, les rebonds étaient verticaux

<svg id="svg1" version="1.1" xmlns="http://www.w3.org/2000/svg" 
    xmlns:xlink="http://www.w3.org/1999/xlink"
       width="200" height="200" viewBox="0 0 200 200" preserveAspectRatio="xMinYMin meet" style="border:1px solid" >  
 
<image xlink:href="https://i.stack.imgur.com/hXyA5.png" x="82" width="25px" height="25px" >
   <animateTransform id="anT"
     attributeName="transform"
     type="translate"
     dur="3s"
     begin="svg1.click+0.5s;anT.end+1s"
     values="
        0,0;
        0,168;
        0,84;
        0,168;
        0,126;
        0,168;
        0,148;
        0,168;
        0,158;
        0,168;
        0,163;
        0,168;
        0,166;
        0,168;
        "
        keyTimes="0;0.066;0.13;0.198;0.264;0.33;0.396;0.462;0.528;0.594;0.66;0.726;0.792;1"
        repeatCount="1"
        fill="freeze"
        restart="whenNotActive" />
</image>
   <polyline points="5,193 194,193" stroke="silver" stroke-width="4" />
 </svg>  

Cette question concerne les rebonds avec différentes valeurs de décalage en hauteur et en longueur

entrez la description de l'image ici

Mais il est difficile de se rendre compte de l'inégalité du mouvement et de la vitesse.

Comment mettre en œuvre un mouvement de balle parabolique réaliste?

Toute idée et solution serait appréciée.


4 commentaires

Vous n'avez pas posé de question. Pourquoi n'avez-vous pas opté pour l'autre solution? C'est probablement le plus simple à modifier car vous pouvez faire des calculs. Où est le problème?


@Emiel Zuurbier Merci Ajustement de la question


Je ne sais pas non plus quelle est votre question. Cherchez-vous la formule pour calculer la position horizontale?


Dans ma réponse à la question liée, définissez simplement dx sur une valeur non nulle.


3 Réponses :


4
votes

L'animation CSS peut mieux se rapprocher de cela. Tu dois:

  1. trouver la courbe de Bézier appropriée pour la fonction de chronométrage ( https://cubic-bezier.com/#.17,.76,.58,1 )
  2. mettez à jour le facteur de durée comme vous le souhaitez
  3. ajoutez autant d'étapes que vous le souhaitez en ajoutant plus d'animation

Ensuite, vous devez calculer correctement le retard en fonction de la durée ( the previous animation delay + 2*previous aniamation duration ).

L'astuce principale est que l'utilisation d' altenate et l'exécution de chaque animation deux fois vous donnera l'effet miroir et une courbe parabolique parfaite (la moitié définie par la courbe de Bézier)

<div class="box">
  <span><img src="https://i.stack.imgur.com/hXyA5.png"></span>
<div>
.box {
   --d:0.8s; /*duration factor*/
   
  width: 200px;
  height: 190px;
  border: 1px solid;
  display: flex;
  align-items: flex-end;
  overflow:hidden;
}

img {
   width:30px;
   animation-timing-function:cubic-bezier(.17,.76,.58,1); /* control this: https://cubic-bezier.com/#.17,.76,.58,1*/
   animation-iteration-count:2; /* don't change*/
   animation-direction: alternate; /* don't change */
   animation-name:t1,t2,t3,t4,t5; /* don't change unless you need more steps*/

   animation-duration:
     var(--d),
     calc(var(--d)/2),
     calc(var(--d)/3),
     calc(var(--d)/4),
     calc(var(--d)/5);
   animation-delay: 
     calc(var(--d)*-1), 
     calc(var(--d)), 
     calc(var(--d)   + 2*var(--d)/2), 
     calc(var(--d)*2 + 2*var(--d)/3), 
     calc(var(--d)*2 + 2*var(--d)/3 + 2*var(--d)/4); 
}

@keyframes t1{to {transform:translateY(-160px)}}
@keyframes t2{to {transform:translateY(-110px)}}
@keyframes t3{to {transform:translateY(-60px)}}
@keyframes t4{to {transform:translateY(-30px)}}
@keyframes t5{to {transform:translateY(-10px)}}

.box > span {
  animation:m calc(var(--d)*2 + 2*var(--d)/3 + 2*var(--d)/4 + 2*var(--d)/5) linear forwards;
}

@keyframes m{to {transform:translateX(150px)}}

Ajout du mouvement horizontal:

<div class="box">
  <img src="https://i.stack.imgur.com/hXyA5.png">
<div>
.box {
  width: 200px;
  height: 190px;
  border: 1px solid;
  display: flex;
  justify-content: center;
  align-items: flex-end;
}

img {
   --d:0.8s; /*duration factor*/

   width:30px;
   animation-timing-function:cubic-bezier(.17,.76,.58,1); /* control this: https://cubic-bezier.com/#.17,.76,.58,1*/
   animation-iteration-count:2; /* don't change*/
   animation-direction: alternate; /* don't change */
   animation-name:t1,t2,t3,t4,t5; /* don't change unless you need more steps*/

   animation-duration:
     var(--d),
     calc(var(--d)/2),
     calc(var(--d)/3),
     calc(var(--d)/4),
     calc(var(--d)/5);
   animation-delay: 
     calc(var(--d)*-1), 
     calc(var(--d)), 
     calc(var(--d)   + 2*var(--d)/2), 
     calc(var(--d)*2 + 2*var(--d)/3), 
     calc(var(--d)*2 + 2*var(--d)/3 + 2*var(--d)/4); 
}

@keyframes t1{to {transform:translateY(-160px)}}
@keyframes t2{to {transform:translateY(-110px)}}
@keyframes t3{to {transform:translateY(-60px)}}
@keyframes t4{to {transform:translateY(-30px)}}
@keyframes t5{to {transform:translateY(-10px)}}


0 commentaires

2
votes

J'ai autorisé ce comportement dans ma réponse précédente (dans la question liée). dx simplement dx sur une valeur non nulle.

<svg id="svg1" 
     width="200" height="200" viewBox="0 0 200 200" preserveAspectRatio="xMinYMin meet" style="border:1px solid" >  
 
  <image id="ball" xlink:href="https://i.stack.imgur.com/hXyA5.png" x="82" width="25px" height="25px"/>
 
</svg>
  • x et y sont la position de départ de la balle
  • dx et dy sont la vitesse initiale de la balle

let ballElem = document.getElementById("ball");

let GRAVITY = 40;        // Acceleration due to gravity (pixels / sec /sec)
let FLOOR_Y = 200 - 25;  // Y coord of floor. The 25 here is because ball.y is the top of the ball.
let BOUNCINESS = 0.8;    // Velocity retained after a bounce
let LIMIT = 0.1;         // Minimum velocity required to keep animation running
let ball = {};
let lastFrameTime = null;

ballElem.addEventListener("click", startAnim);


function startAnim()
{
  ball = {x: 82, y: 0, dx: 1, dy: 0};
  lastFrameTime = null;
  requestAnimationFrame(animStep);
}


function animStep(timestamp)
{
  if (lastFrameTime === null)
    lastFrameTime = timestamp;
  // Milliseconds elapsed since last step
  const elapsed = timestamp - lastFrameTime;
  lastFrameTime = timestamp;
  
  ball.dy += GRAVITY * elapsed / 1000;
  ball.y += ball.dy;
  ball.x += ball.dx;   // not really used in this example

  if (ball.y > FLOOR_Y) {
    // Step has taken us below the floor, so we need to rebound the ball.
    ball.y -= (ball.y - FLOOR_Y);
    ball.dy = -ball.dy * BOUNCINESS;
  }
  
  // Update the <image> element x and y
  ballElem.x.baseVal.value = ball.x;
  ballElem.y.baseVal.value = ball.y;
  
  // Request another animation step
  if (Math.abs(ball.y - FLOOR_Y) > LIMIT ||  // Not on ground
      Math.abs(ball.dy) > LIMIT ||           // or still moving
      Math.abs(ball.dx) > LIMIT) {
    requestAnimationFrame(animStep);
  }
}
ball = {x: 82, y: 0, dx: 1, dy: 0};


0 commentaires

2
votes

Solution SVG Smil

La trajectoire de la balle a été créée à partir de l'image de la question dans l'éditeur vectoriel Inkscape

entrez la description de l'image ici

Pour l'animation du mouvement le long de la trajectoire que j'ai utilisée - animateMotion

L'application est réactive et semble plus intéressante en plein écran

<div class="container">
<svg id="svg1" version="1.1" xmlns="http://www.w3.org/2000/svg" 
    xmlns:xlink="http://www.w3.org/1999/xlink"
       viewBox="0 0 488 232" preserveAspectRatio="xMinYMin meet" style="border:1px solid" >  
<defs>  
<!--Parabolic trajectory of movement and bounce of the ball -->
 <path id="trace" d="m 25.652812,16.016049 v 181.392771 0 0 l -0.596577,25.31062 c 0,0 12.411076,-62.72171 21.476772,-93.33069 5.109455,-17.25132 11.107049,-34.303277 18.493888,-50.709043 6.68532,-14.84773 11.981393,-31.214941 23.266504,-42.953546 5.128983,-5.335092 11.703068,-10.892125 19.090461,-11.334963 9.33174,-0.559391 18.66956,5.119788 25.65281,11.334963 12.5853,11.201058 18.46109,28.314233 25.65282,43.550123 7.68011,16.270538 13.21524,33.508736 18.49388,50.709046 9.35008,30.46698 17.6561,61.30229 23.26651,92.73411 0,0 7.63247,-46.2686 13.72127,-68.87103 4.15486,-15.42339 7.4192,-31.5679 15.511,-45.33985 5.42122,-9.226722 10.78091,-23.515729 21.47677,-23.863083 11.38465,-0.369722 18.27651,14.296709 24.45966,23.863083 8.5031,13.15573 11.7205,29.10909 16.10758,44.1467 6.69922,22.96293 9.48984,49.49348 15.511,70.06418 5.7106,-34.92901 6.57028,-45.00528 16.10758,-65.29157 5.26265,-11.19392 9.73289,-28.98491 22.07335,-29.82885 11.92521,-0.81554 20.99188,14.41196 25.05624,25.65281 4.04949,11.19974 6.57393,20.61892 9.54523,31.02201 3.6399,12.74398 5.25389,18.16556 10.14181,38.4456 2.98041,-18.27579 1.7071,-16.73913 4.17604,-24.72433 1.6821,-5.44034 3.72502,-10.96841 7.15892,-15.511 3.31674,-4.3876 7.05439,-11.27709 12.52812,-10.73839 7.04712,0.69355 9.92525,10.387 13.12469,16.70416 5.35774,10.57863 5.4736,18.42066 9.54524,34.26956 0.57788,-7.32318 1.59738,-10.47263 1.78973,-13.98594 0.5125,-9.36095 6.36879,-18.32474 10.84695,-17.16023 9.45261,2.45807 13.01612,16.09152 13.01612,16.09152" style="fill:none;stroke-opacity:0.9;stroke-width:2;stroke:#e8204f"/>
</defs>
 
      <!-- Tennis ball -->
<image xlink:href="https://i.stack.imgur.com/hXyA5.png" x="0" y="0" width="25px" height="25px" >
   <animateMotion id="anT"
       dur="1.5s"
     begin="svg1.click+0.5s;anT.end+1s"
        repeatCount="1"
        fill="freeze"
        restart="whenNotActive" > 
        <mpath xlink:href="#trace" />
    </animateMotion>    
</image>
   </svg>
 </div>
.container {
width:60%;
height:60%;
}


0 commentaires