Add move example

This commit is contained in:
Thibaud Gasser 2025-01-30 23:06:31 +01:00
parent 9c61718274
commit 412bd60c8c
3 changed files with 136 additions and 0 deletions

View File

@ -19,6 +19,7 @@
<li><a href="/bezier-2.html">Bezier demo #2</a></li> <li><a href="/bezier-2.html">Bezier demo #2</a></li>
<li><a href="/spline.html">Bezier spline demo</a></li> <li><a href="/spline.html">Bezier spline demo</a></li>
<li><a href="/image.html">Image demo</a></li> <li><a href="/image.html">Image demo</a></li>
<li><a href="/move.html">Move demo</a></li>
</ul> </ul>
</body> </body>
</html> </html>

12
move.html Normal file
View File

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Hello typescript</title>
</head>
<body style="margin: 0; padding 0; overflow: hidden; background-color: #000000">
<canvas id="canvas" tabindex="0"></canvas>
<script type="module" src="./move.js"></script>
</body>
</html>

123
move.ts Normal file
View File

@ -0,0 +1,123 @@
class Vec2d {
x: number;
y: number;
constructor(x: number, y: number) {
this.x = x;
this.y = y;
}
toString() {
return `[${this.x}, ${this.y}]`;
}
scale(scalar: number): Vec2d {
return new Vec2d(this.x * scalar, this.y * scalar);
}
add(other: Vec2d): Vec2d {
return new Vec2d(this.x + other.x, this.y + other.y)
}
lerp(other: Vec2d, t: number): Vec2d {
// (1-t)*A + B*t
return this.scale(1-t).add(other.scale(t));
}
}
// state
let target: Vec2d | undefined = undefined;
let pos = new Vec2d(200, 200);
let velocity = new Vec2d(500, 500);
let pause = false;
let mode: "follow" | "bounce" = "bounce";
let start: number | undefined = undefined;
function drawCircle(ctx: CanvasRenderingContext2D, center: Vec2d, radius: number, color: number) {
ctx.save();
ctx.beginPath();
ctx.arc(center.x, center.y, radius, 0, 2*Math.PI);
ctx.strokeStyle = `#${color.toString(16)}`
ctx.lineWidth = 5;
ctx.stroke();
ctx.restore();
}
function resizeCanvas(ctx: CanvasRenderingContext2D) {
ctx.canvas.width = window.innerWidth;
ctx.canvas.height = window.innerHeight;
ctx.clearRect(0, 0, ctx.canvas.height, ctx. canvas.width);
}
function update(ctx: CanvasRenderingContext2D, timestamp: number) {
switch (mode) {
case "bounce":
updateBounce(ctx, timestamp);
break;
case "follow":
updateFollow(ctx);
break;
default:
throw new Error(`Unknown mode: ${mode}`);
}
if (!pause) window.requestAnimationFrame(t => update(ctx, t));
}
function updateFollow(ctx: CanvasRenderingContext2D) {
if (target) pos = pos.lerp(target, 0.01);
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
drawCircle(ctx, pos, 100, 0xFF00FF);
}
function updateBounce(ctx: CanvasRenderingContext2D, timestamp: number) {
if (!start) start = timestamp;
const dt = timestamp - start;
// P_t+1 = P_t + V * t
const newPos = pos.add(velocity.scale(0.001*dt));
if (newPos.x > ctx.canvas.width - 100) { velocity.x *= -1; newPos.x = ctx.canvas.width - 100; }
if (newPos.y > ctx.canvas.height - 100) { velocity.y *= -1; newPos.y = ctx.canvas.height - 100; }
if (newPos.x < 100) { velocity.x *= -1; newPos.x = 100; }
if (newPos.y < 100) { velocity.y *= -1; newPos.y = 100; }
//console.log(velocity);
pos = newPos;
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
drawCircle(ctx, pos, 100, 0xFF00FF);
start = timestamp;
}
function init() {
const canvas = document.getElementById("canvas") as HTMLCanvasElement | null;
if (!canvas) throw new Error("unable to get canvas HTML element");
const ctx = canvas.getContext("2d") as CanvasRenderingContext2D | null;
if (!ctx) throw new Error("unable to get canvas 2D context");
ctx.canvas.width = window.innerWidth;
ctx.canvas.height = window.innerHeight;
canvas.onmousemove = (evt) => {
const {clientX, clientY} = evt;
target = new Vec2d(clientX, clientY);
}
canvas.onclick = () => {
if (pause) {
window.requestAnimationFrame(t => update(ctx, t));
}
pause = !pause;
}
window.onkeydown = (evt) => {
console.log("key down", evt);
if (mode === "follow") mode = "bounce";
else mode = "follow"
console.log("mode", mode);
}
window.addEventListener('resize', () => resizeCanvas(ctx));
window.requestAnimationFrame(t => update(ctx, t));
}
init();