Demo: Bounce

\displaystyle \vec{v} = \frac{\Delta \vec{s}}{\Delta t}\Delta \vec{s} = \vec{v}\cdot \Delta t\vec{s}\ += \Delta \vec{s}

1.1

Una pallina al centro e una parete fissa a destra

from vpython import *
    
wall_1 = box(color = color.red, pos = vector(16, 0, 0), size = vector(0.25, 24, 24))
 
ball = sphere(color = color.yellow)

1.2

La posizione della palla dipende dal tempo:

  • ball.speed = vector(8, 0, 0), la palla ha una nuova caratteristica
  • ds = ball.speed*dt, la variazione della posizione nell’intervallo di tempo
  • ball.pos += ds, la posizione viene aggiornata
from vpython import *
     
wall_1 = box(color = color.red, pos = vector(16, 0, 0), size = vector(0.25, 24, 24))
 
ball = sphere(color = color.yellow, speed = vector(8, 0, 0))
 
dt = 0.02
time = 0
 
ds = ball.speed*dt
ball.pos += ds

1.3

Il tempo scorre per alcuni secondi: time = time+dt

from vpython import *
     
wall_1 = box(color = color.red, pos = vector(16, 0, 0), size = vector(0.25, 24, 24))
 
ball = sphere(color = color.yellow, speed = vector(8, 0, 0))

dt = 0.02
time = 0
while(time < 8):
    rate(50)

    ds = ball.speed*dt
    ball.pos += ds
    time += dt

La palla ha attraversato il muro!

1.4

Se la palla rischia di superare il muro a destra allora si rende necessario invertire il segno della sua velocità

from vpython import *
     
wall_1 = box(color = color.red, pos = vector(16, 0, 0), size = vector(0.25, 24, 24))
 
ball = sphere(color = color.yellow, speed = vector(8, 0, 0))

dt = 0.02
time = 0
while(time < 8):
    rate(50)

    if(ball.pos.x > wall_1.pos.x): 
        ball.speed.x *= -1

    ds = ball.speed*dt
    ball.pos += ds
    time += dt

1.5

La palla rimbalza sul lato destro ma si perde sul lato sinistro.
Aggiungi un’altra parete e un’altra condizione per rimbalzare.

from vpython import *
     
wall_1 = box(color = color.red, pos = vector(+16, 0, 0), size = vector(0.25, 24, 24))
wall_2 = box(color = color.red, pos = vector(-16, 0, 0), size = vector(0.25, 24, 24))

ball = sphere(color = color.yellow, speed = vector(8, 0, 0))

dt = 0.02
time = 0
while(time < 8):
    rate(50)

    if(ball.pos.x > wall_1.pos.x): 
        ball.speed.x *= -1
    if(ball.pos.x < wall_2.pos.x): 
        ball.speed.x *= -1

    ds = ball.speed*dt
    ball.pos += ds
    time += dt

Miglioramenti

  1. La palla annega nelle pareti…
  2. Evidenziare gli urti con le pareti
  3. Rendere visibile la direzione della palla
  4. Rendere visibile la traiettoria della palla

2.1

La palla annega parzialmente nelle pareti, è necessario aggiungere una distanza di sicurezza

from vpython import *
     
wall_1 = box(color = color.red, pos = vector(+16, 0, 0), size = vector(0.25, 24, 24))
wall_2 = box(color = color.red, pos = vector(-16, 0, 0), size = vector(0.25, 24, 24))

ball = sphere(color = color.yellow, speed = vector(8, 0, 0))

DIST = ball.radius+wall_1.size.x
dt = 0.02
time = 0
while(time < 8):
    rate(50)

    if(ball.pos.x+DIST > wall_1.pos.x): 
        ball.speed.x *= -1
    if(ball.pos.x-DIST < wall_2.pos.x): 
        ball.speed.x *= -1

    ds = ball.speed*dt
    ball.pos += ds
    time += dt

2.2

La palla e la parete colpita cambiano il proprio attributo emissive

from vpython import *
     
wall_1 = box(color = color.red, pos = vector(+16, 0, 0), size = vector(0.25, 24, 24))
wall_2 = box(color = color.red, pos = vector(-16, 0, 0), size = vector(0.25, 24, 24))

ball = sphere(color = color.yellow, speed = vector(8, 0, 0))

DIST = ball.radius+wall_1.size.x
dt = 0.02
time = 0
while(time < 8):
    rate(50)

    if(ball.pos.x+DIST > wall_1.pos.x): 
        ball.speed.x   *= -1
        ball.emissive   = not ball.emissive
        wall_1.emissive = not wall_1.emissive
    if(ball.pos.x-DIST < wall_2.pos.x): 
        ball.speed.x   *= -1
        ball.emissive   = not ball.emissive
        wall_2.emissive = not wall_2.emissive

    ds = ball.speed*dt
    ball.pos += ds
    time += dt

2.3

Un vettore segue la palla e indica la direzione e il verso del movimento

from vpython import *
     
wall_1 = box(color = color.red, pos = vector(+16, 0, 0), size = vector(0.25, 24, 24))
wall_2 = box(color = color.red, pos = vector(-16, 0, 0), size = vector(0.25, 24, 24))

ball = sphere(color = color.yellow, speed = vector(8, 0, 0))

dir_b  = attach_arrow(ball, "speed", scale = 0.5, shaftwidth = 0.25)

DIST = ball.radius+wall_1.size.x
dt = 0.02
time = 0
while(time < 8):
    rate(50)

    if(ball.pos.x+DIST > wall_1.pos.x): 
        ball.speed.x   *= -1
        ball.emissive   = not ball.emissive
        wall_1.emissive = not wall_1.emissive
    if(ball.pos.x-DIST < wall_2.pos.x): 
        ball.speed.x   *= -1
        ball.emissive   = not ball.emissive
        wall_2.emissive = not wall_2.emissive

    ds = ball.speed*dt
    ball.pos += ds
    time += dt

2.4

Per seguire la traiettoria della palla aggiungi automaticamente una traccia grafica

  • ball.make_trail = True
  • ball.retain = 50, il numero di passi visibili
from vpython import *
     
wall_1 = box(color = color.red, pos = vector(+16, 0, 0), size = vector(0.25, 24, 24))
wall_2 = box(color = color.red, pos = vector(-16, 0, 0), size = vector(0.25, 24, 24))

ball = sphere(color = color.yellow,
              speed = vector(8, 0, 0),
              make_trail = True, retain = 50)

dir_b  = attach_arrow(ball, "speed", scale = 0.5, shaftwidth = 0.25)

DIST = ball.radius+wall_1.size.x
dt = 0.02
time = 0
while(time < 8):
    rate(50)

    if(ball.pos.x+DIST > wall_1.pos.x): 
        ball.speed.x   *= -1
        ball.emissive   = not ball.emissive
        wall_1.emissive = not wall_1.emissive
    if(ball.pos.x-DIST < wall_2.pos.x): 
        ball.speed.x   *= -1
        ball.emissive   = not ball.emissive
        wall_2.emissive = not wall_2.emissive

    ds = ball.speed*dt
    ball.pos += ds
    time += dt

Ulteriori miglioramenti


3.1

  1. Il tempo scorre per sempre: while(True):
  2. Aggiungi le pareti in verticale e in profondità (con delle costanti semplificative)
    • La parete verso l’utente NON è visibile: wall_5.visible = False
  3. Modifica il vettore velocità: ball.speed = vector(9, 8, 7)
from vpython import *

d12 = 16; dd12 = 2*d12; SPES = 0.25
d34 = 12; dd34 = 2*d34
d56 = 12; dd56 = 2*d56
  
wall_1 = box(color=color.red  , pos=vector(+d12,   0,   0), size=vector(SPES, dd34, dd56))
wall_2 = box(color=color.red  , pos=vector(-d12,   0,   0), size=vector(SPES, dd34, dd56))
wall_3 = box(color=color.green, pos=vector(   0,+d34,   0), size=vector(dd12, SPES, dd56))
wall_4 = box(color=color.green, pos=vector(   0,-d34,   0), size=vector(dd12, SPES, dd56))
wall_5 = box(color=color.blue , pos=vector(   0,   0,+d56), size=vector(dd12, dd34, SPES),
             visible = False)
wall_6 = box(color=color.blue , pos=vector(   0,   0,-d56), size=vector(dd12, dd34, SPES))

ball   = sphere(color      = color.yellow,
                speed      = vector(9, 8, 7),
                make_trail = True, retain = 100)

dir_b  = attach_arrow(ball, "speed", scale = 0.5, shaftwidth = 0.25)

dt = 0.02
time = 0
DIST = ball.radius+SPES
while(True):
    rate(50)
   
    if(ball.pos.x+DIST > wall_1.pos.x):
        ball.speed.x   *= -1
        ball.emissive   = not ball.emissive
        wall_1.emissive = not wall_1.emissive
    if(ball.pos.x-DIST < wall_2.pos.x):
        ball.speed.x   *= -1
        ball.emissive   = not ball.emissive
        wall_2.emissive = not wall_2.emissive
    if(ball.pos.y+DIST > wall_3.pos.y):
        ball.speed.y   *= -1
        ball.emissive   = not ball.emissive
        wall_3.emissive = not wall_3.emissive
    if(ball.pos.y-DIST < wall_4.pos.y):
        ball.speed.y   *= -1
        ball.emissive   = not ball.emissive
        wall_4.emissive = not wall_4.emissive
    if(ball.pos.z+DIST > wall_5.pos.z):
        ball.speed.z   *= -1
        ball.emissive   = not ball.emissive
    if(ball.pos.z-DIST < wall_6.pos.z):
        ball.speed.z   *= -1
        ball.emissive   = not ball.emissive
        wall_6.emissive = not wall_6.emissive
    
    ds = ball.speed*dt
    ball.pos += ds      
    time += dt

3.2

Aggiunge etichette con informazioni numeriche su

  1. time, lo scorrere del tempo
  2. ball.pos, la posizione istantanea della pallina
from vpython import *

d12 = 16; dd12 = 2*d12; SPES = 0.25
d34 = 12; dd34 = 2*d34
d56 = 12; dd56 = 2*d56
  
wall_1 = box(color=color.red  , pos=vector(+d12,   0,   0), size=vector(SPES, dd34, dd56))
wall_2 = box(color=color.red  , pos=vector(-d12,   0,   0), size=vector(SPES, dd34, dd56))
wall_3 = box(color=color.green, pos=vector(   0,+d34,   0), size=vector(dd12, SPES, dd56))
wall_4 = box(color=color.green, pos=vector(   0,-d34,   0), size=vector(dd12, SPES, dd56))
wall_5 = box(color=color.blue , pos=vector(   0,   0,+d56), size=vector(dd12, dd34, SPES),
             visible = False)
wall_6 = box(color=color.blue , pos=vector(   0,   0,-d56), size=vector(dd12, dd34, SPES))

ball   = sphere(color      = color.yellow,
                speed      = vector(9, 8, 7),
                make_trail = True, retain = 100)

dir_b  = attach_arrow(ball, "speed", scale = 0.5, shaftwidth = 0.25)

lbl_t = label(box = False, pos = vector(0, +d34+2, d56))
lbl_b = label(box = False, pos = vector(0, -d34-2, d56), color = ball.color)

dt = 0.02
time = 0
DIST = ball.radius+SPES
while(time < 10):
    rate(50)
   
    if(ball.pos.x+DIST > wall_1.pos.x):
        ball.speed.x   *= -1
        ball.emissive   = not ball.emissive
        wall_1.emissive = not wall_1.emissive
    if(ball.pos.x-DIST < wall_2.pos.x):
        ball.speed.x   *= -1
        ball.emissive   = not ball.emissive
        wall_2.emissive = not wall_2.emissive
    if(ball.pos.y+DIST > wall_3.pos.y):
        ball.speed.y   *= -1
        ball.emissive   = not ball.emissive
        wall_3.emissive = not wall_3.emissive
    if(ball.pos.y-DIST < wall_4.pos.y):
        ball.speed.y   *= -1
        ball.emissive   = not ball.emissive
        wall_4.emissive = not wall_4.emissive
    if(ball.pos.z+DIST > wall_5.pos.z):
        ball.speed.z   *= -1
        ball.emissive   = not ball.emissive
    if(ball.pos.z-DIST < wall_6.pos.z):
        ball.speed.z   *= -1
        ball.emissive   = not ball.emissive
        wall_6.emissive = not wall_6.emissive
    
    ds = ball.speed*dt
    ball.pos += ds

    lbl_t.text = "time = {:.2f}".format(time) 
    lbl_b.text = "({:.2f}, {:.2f}, {:.2f})".format(ball.pos.x, ball.pos.y, ball.pos.z)
      
    time += dt

3.3

Una seconda pallina con le stesse caratteristiche / comportamenti eccetto l’evidenza degli urti con le pareti.
Rinomina ball in ball_1 e poi copia e incolla tutto…

from vpython import *

d12 = 16; dd12 = 2*d12; SPES = 0.25
d34 = 12; dd34 = 2*d34
d56 = 12; dd56 = 2*d56
  
wall_1 = box(color=color.red  , pos=vector(+d12,   0,   0), size=vector(SPES, dd34, dd56))
wall_2 = box(color=color.red  , pos=vector(-d12,   0,   0), size=vector(SPES, dd34, dd56))
wall_3 = box(color=color.green, pos=vector(   0,+d34,   0), size=vector(dd12, SPES, dd56))
wall_4 = box(color=color.green, pos=vector(   0,-d34,   0), size=vector(dd12, SPES, dd56))
wall_5 = box(color=color.blue , pos=vector(   0,   0,+d56), size=vector(dd12, dd34, SPES),
             visible = False)
wall_6 = box(color=color.blue , pos=vector(   0,   0,-d56), size=vector(dd12, dd34, SPES))

ball_1 = sphere(color = color.yellow, speed = vector(9, 8, 7), make_trail = True, retain = 100)
ball_2 = sphere(color = color.cyan  , speed = vector(7, 8, 9), make_trail = True, retain = 100)

dir_b1 = attach_arrow(ball_1, "speed", scale = 0.5, shaftwidth = 0.25)
dir_b2 = attach_arrow(ball_2, "speed", scale = 0.5, shaftwidth = 0.25)

lbl_t  = label(box = False, pos = vector(0, +d34+2, d56))
lbl_b1 = label(box = False, pos = vector(-d12, -d34-2, d56), color = ball_1.color)
lbl_b2 = label(box = False, pos = vector(+d12, -d34-2, d56), color = ball_2.color)

dt = 0.02
time = 0
DIST = ball_1.radius+SPES
while(time < 10):
    rate(50)
    lbl_t.text  = "time = {:.2f}".format(time) 
   
    if(ball_1.pos.x+DIST > wall_1.pos.x):
        ball_1.speed.x   *= -1
        ball_1.emissive   = not ball_1.emissive
        wall_1.emissive   = not wall_1.emissive
    if(ball_1.pos.x-DIST < wall_2.pos.x):
        ball_1.speed.x   *= -1
        ball_1.emissive   = not ball_1.emissive
        wall_2.emissive   = not wall_2.emissive
    if(ball_1.pos.y+DIST > wall_3.pos.y):
        ball_1.speed.y   *= -1
        ball_1.emissive   = not ball_1.emissive
        wall_3.emissive   = not wall_3.emissive
    if(ball_1.pos.y-DIST < wall_4.pos.y):
        ball_1.speed.y   *= -1
        ball_1.emissive   = not ball_1.emissive
        wall_4.emissive   = not wall_4.emissive
    if(ball_1.pos.z+DIST > wall_5.pos.z):
        ball_1.speed.z   *= -1
        ball_1.emissive   = not ball_1.emissive
    if(ball_1.pos.z-DIST < wall_6.pos.z):
        ball_1.speed.z   *= -1
        ball_1.emissive   = not ball_1.emissive
        wall_6.emissive   = not wall_6.emissive
    
    ds = ball_1.speed*dt
    ball_1.pos += ds
    lbl_b1.text = "({:.2f}, {:.2f}, {:.2f})".format(ball_1.pos.x, ball_1.pos.y, ball_1.pos.z)

    if(ball_2.pos.x+DIST > wall_1.pos.x):
        ball_2.speed.x   *= -1
    if(ball_2.pos.x-DIST < wall_2.pos.x):
        ball_2.speed.x   *= -1
    if(ball_2.pos.y+DIST > wall_3.pos.y):
        ball_2.speed.y   *= -1
    if(ball_2.pos.y-DIST < wall_4.pos.y):
        ball_2.speed.y   *= -1
    if(ball_2.pos.z+DIST > wall_5.pos.z):
        ball_2.speed.z   *= -1
    if(ball_2.pos.z-DIST < wall_6.pos.z):
        ball_2.speed.z   *= -1
    
    ds = ball_2.speed*dt
    ball_2.pos += ds
    lbl_b2.text = "({:.2f}, {:.2f}, {:.2f})".format(ball_2.pos.x, ball_2.pos.y, ball_2.pos.z)
      
    time += dt

Glowscript

Web VPython 3.2
 
d12 = 16; dd12 = 2*d12; SPES = 0.25
d34 = 12; dd34 = 2*d34
d56 = 12; dd56 = 2*d56
   
wall_1 = box(color=color.red  , pos=vector(+d12,   0,   0), size=vector(SPES, dd34, dd56))
wall_2 = box(color=color.red  , pos=vector(-d12,   0,   0), size=vector(SPES, dd34, dd56))
wall_3 = box(color=color.green, pos=vector(   0,+d34,   0), size=vector(dd12, SPES, dd56))
wall_4 = box(color=color.green, pos=vector(   0,-d34,   0), size=vector(dd12, SPES, dd56))
wall_5 = box(color=color.blue , pos=vector(   0,   0,+d56), size=vector(dd12, dd34, SPES),
             visible = False)
wall_6 = box(color=color.blue , pos=vector(   0,   0,-d56), size=vector(dd12, dd34, SPES))
 
ball_1 = sphere(color = color.yellow, speed = vector(9  , 8  , 7  ), make_trail = True, retain = 100)
ball_2 = sphere(color = color.cyan  , speed = vector(9.1, 8.1, 7.1), make_trail = True, retain = 100)
 
dir_b1 = attach_arrow(ball_1, "speed", scale = 0.5, shaftwidth = 0.25)
dir_b2 = attach_arrow(ball_2, "speed", scale = 0.5, shaftwidth = 0.25)
 
lbl_t  = label(box = False, pos = vector(0, +d34+2, d56))
lbl_b1 = label(box = False, pos = vector(-d12, -d34-2, d56), color = ball_1.color)
lbl_b2 = label(box = False, pos = vector(+d12, -d34-2, d56), color = ball_2.color)
 
dt = 0.02
time = 0
DIST = ball_1.radius+SPES
while(True):
    rate(50)
    lbl_t.text  = "time = {:.2f}".format(time) 
    
    if(ball_1.pos.x+DIST > wall_1.pos.x):
        ball_1.speed.x   *= -1
        ball_1.emissive   = not ball_1.emissive
        wall_1.emissive   = not wall_1.emissive
    if(ball_1.pos.x-DIST < wall_2.pos.x):
        ball_1.speed.x   *= -1
        ball_1.emissive   = not ball_1.emissive
        wall_2.emissive   = not wall_2.emissive
    if(ball_1.pos.y+DIST > wall_3.pos.y):
        ball_1.speed.y   *= -1
        ball_1.emissive   = not ball_1.emissive
        wall_3.emissive   = not wall_3.emissive
    if(ball_1.pos.y-DIST < wall_4.pos.y):
        ball_1.speed.y   *= -1
        ball_1.emissive   = not ball_1.emissive
        wall_4.emissive   = not wall_4.emissive
    if(ball_1.pos.z+DIST > wall_5.pos.z):
        ball_1.speed.z   *= -1
        ball_1.emissive   = not ball_1.emissive
    if(ball_1.pos.z-DIST < wall_6.pos.z):
        ball_1.speed.z   *= -1
        ball_1.emissive   = not ball_1.emissive
        wall_6.emissive   = not wall_6.emissive
     
    ds = ball_1.speed*dt
    ball_1.pos += ds
    lbl_b1.text = "({:.2f}, {:.2f}, {:.2f})".format(ball_1.pos.x, ball_1.pos.y, ball_1.pos.z)
 
    if(ball_2.pos.x+DIST > wall_1.pos.x):
        ball_2.speed.x   *= -1
    if(ball_2.pos.x-DIST < wall_2.pos.x):
        ball_2.speed.x   *= -1
    if(ball_2.pos.y+DIST > wall_3.pos.y):
        ball_2.speed.y   *= -1
    if(ball_2.pos.y-DIST < wall_4.pos.y):
        ball_2.speed.y   *= -1
    if(ball_2.pos.z+DIST > wall_5.pos.z):
        ball_2.speed.z   *= -1
    if(ball_2.pos.z-DIST < wall_6.pos.z):
        ball_2.speed.z   *= -1
     
    ds = ball_2.speed*dt
    ball_2.pos += ds
    lbl_b2.text = "({:.2f}, {:.2f}, {:.2f})".format(ball_2.pos.x, ball_2.pos.y, ball_2.pos.z)
       
    time += dt

Ancora miglioramenti?

  1. Più palline
  2. Velocità variabile (?)
  3. Gestione degli urti tra palline (?)
  4. Pareti mobili (?)
  5. Interattività (start/stop, accelera/decelera, …)
  6. Breakout, Pinball (???)