Animation means changing a value a little every frame. The catch is that frames aren't always the same length: a 120 Hz screen calls export function update()Screen.OnUpdate()def update() twice as often as a 60 Hz one, and a busy frame can take longer.
deltaTime()Screen.DeltaTimedeltaTime() is the number of seconds since the last frame, usually about 0.016. Multiply speeds by it so they mean "per second" instead of "per frame":
let x: f64 =0const speed: f64 =300// pixels per secondexportfunctionupdate():void{
x +=5// ✗ speed depends on the frame rate
x += speed *deltaTime()// ✓ 300 px/s everywhere}
double x =0;double speed =300;// pixels per second
Screen.OnUpdate(()=>{
x +=5;// ✗ speed depends on the frame rate
x += speed * Screen.DeltaTime;// ✓ 300 px/s everywhere});
x =0.0
speed =300.0# pixels per seconddefupdate():global x
x +=5# ✗ speed depends on the frame rate
x += speed * deltaTime()# ✓ 300 px/s everywhere
The same goes for anything that changes over time: rotation (radians per second), fading (alpha per second) and timers.
Store a velocity, add it to the position each frame, and flip it when you hit a wall:
import{ fill, rect, circle }from"codetoy/canvas"import*as screen from"codetoy/screen"import{ deltaTime }from"codetoy/time"let x: f64 =100, y: f64 =100let vx: f64 =220, vy: f64 =160const r: f64 =20exportfunctionupdate():void{const dt =deltaTime()
x += vx * dt
y += vy * dt
if(x < r || x > screen.width()- r) vx =-vx
if(y < r || y > screen.height()- r) vy =-vy
fill(20,20,30)rect(0,0, screen.width(), screen.height())fill(100,200,255)circle(x, y, r)}
double x =100, y =100;double vx =220, vy =160;constdouble r =20;
Screen.OnUpdate(()=>{double dt = Screen.DeltaTime;
x += vx * dt;
y += vy * dt;if(x < r || x > Screen.Width - r) vx =-vx;if(y < r || y > Screen.Height - r) vy =-vy;
Canvas.Fill(20,20,30);
Canvas.Rect(0,0, Screen.Width, Screen.Height);
Canvas.Fill(100,200,255);
Canvas.Circle(x, y, r);});
from codetoy.canvas import fill, rect, circle
from codetoy.screen import width, height
from codetoy.time import deltaTime
x, y =100.0,100.0
vx, vy =220.0,160.0
r =20defupdate():global x, y, vx, vy
dt = deltaTime()
x += vx * dt
y += vy * dt
if x < r or x > width()- r: vx =-vx
if y < r or y > height()- r: vy =-vy
fill(20,20,30)
rect(0,0, width(), height())
fill(100,200,255)
circle(x, y, r)
Add gravity by increasing vy a little every frame (vy += 900 * dt).
elapsedTime()not in C#elapsedTime() is the total number of seconds since the program started. Feed it to Math.sin()Math.Sin()math.sin() or Math.cos()Math.Cos()math.cos() for smooth back-and-forth motion, pulsing and orbits:
const t =elapsedTime()const pulse =40+ Math.sin(t *3)*15// radius between 25 and 55const orbitX = screen.centerX()+ Math.cos(t)*120const orbitY = screen.centerY()+ Math.sin(t)*120circle(orbitX, orbitY, pulse)
// C# has no ElapsedTime yet, so add up DeltaTime yourself.double t =0;
Screen.OnUpdate(()=>{
t += Screen.DeltaTime;double pulse =40+ Math.Sin(t *3)*15;// radius between 25 and 55double orbitX = Screen.CenterX + Math.Cos(t)*120;double orbitY = Screen.CenterY + Math.Sin(t)*120;
Canvas.Circle(orbitX, orbitY, pulse);});
import math
t = elapsedTime()
pulse =40+ math.sin(t *3)*15# radius between 25 and 55
orbit_x = centerX()+ math.cos(t)*120
orbit_y = centerY()+ math.sin(t)*120
circle(orbit_x, orbit_y, pulse)
To do something every N seconds, count down with delta time:
let spawnTimer: f64 =0exportfunctionupdate():void{
spawnTimer -=deltaTime()if(spawnTimer <=0){
spawnTimer =1.5// seconds until the next spawn// spawn an enemy...}}
double spawnTimer =0;
Screen.OnUpdate(()=>{
spawnTimer -= Screen.DeltaTime;if(spawnTimer <=0){
spawnTimer =1.5;// seconds until the next spawn// spawn an enemy...}});
spawn_timer =0.0defupdate():global spawn_timer
spawn_timer -= deltaTime()if spawn_timer <=0:
spawn_timer =1.5# seconds until the next spawn# spawn an enemy...