render.ts
import { Ball, Xy } from "@/lib/canvas/shape/ball"
import { Timer } from "@/lib/control/timer"
import { Clock } from "@/lib/event/clock"
import { Vector2 } from "@/lib/math/vector"
export const onload = () => {
const canvas = <HTMLCanvasElement>document.getElementById("gl-canvas")
const context = canvas.getContext("2d")
if (!context) return
let loopClock: Clock
let timer: Timer
let balls: Ball[] = []
let dt = 0
const setupBackground = () => {
context.beginPath()
context.fillStyle = "#9EA9F0"
context.fillRect(0, 0, canvas.width, canvas.height)
}
const clearCanvas = () => {
context.clearRect(0, 0, canvas.width, canvas.height)
setupBackground()
}
const setupBall = (color: string, position: Xy, velocity: Xy) => {
const ball = new Ball({ radius: 20, color, isGradientOn: true })
ball.position2d = position
ball.velocity2d = velocity
ball.draw(context)
balls.push(ball)
}
const setupScene = () => {
setupBall("#95BDFF", { x: 50, y: 200 }, { x: 30, y: 0 })
setupBall("#F7C8E0", { x: 500, y: 200 }, { x: -20, y: 0 })
setupBall("#C9F4AA", { x: 300, y: 200 }, { x: 10, y: 0 })
}
const moveObject = (ball: Ball) => {
ball.position2d = ball.position2d.addScaled(ball.velocity2d, dt)
ball.draw(context)
}
const checkCollision = () => {
for (let i = 0; i < balls.length; i++) {
const ball_1 = balls[i]
for (let j = i + 1; j < balls.length; j++) {
const ball_2 = balls[j]
const distance = Vector2.distance(ball_1.position2d, ball_2.position2d)
if (distance < ball_1.radius + ball_2.radius) {
;[ball_1.velocity2d, ball_2.velocity2d] = [ball_2.velocity2d, ball_1.velocity2d]
}
}
}
}
const updateScene = () => {
clearCanvas()
checkCollision()
balls.forEach((ball) => moveObject(ball))
}
const animationFrame = () => {
dt = timer.elapsed * 0.001
if (dt > 0.2) dt = 0
timer.reset()
updateScene()
}
const init = () => {
setupBackground()
setupScene()
timer = new Timer()
loopClock = new Clock()
loopClock.on("tick", animationFrame)
}
init()
}