Files
p5_bounce/src/lib/player.js

112 lines
3.3 KiB
JavaScript
Raw Normal View History

2026-06-30 22:28:37 +03:00
import { WORLD } from "./config.js";
const GRAVITY = 0.32;
const JUMP_VELOCITY = -10.5;
const HORIZONTAL_ACCELERATION = 0.65;
const HORIZONTAL_FRICTION = 0.86;
const MAX_HORIZONTAL_SPEED = 7;
export function createPlayer({ x = 0, y = 0, radius = 18 } = {}) {
return {
position: { x, y },
previousPosition: { x, y },
velocity: { x: 0, y: 0 },
radius,
wasReset: false,
};
}
export function updatePlayer(player, keys, platforms) {
player.wasReset = false;
player.previousPosition.x = player.position.x;
player.previousPosition.y = player.position.y;
const xDirection = Number(keys.has("arrowright") || keys.has("d")) - Number(keys.has("arrowleft") || keys.has("a"));
player.velocity.x += xDirection * HORIZONTAL_ACCELERATION;
player.velocity.x *= HORIZONTAL_FRICTION;
player.velocity.x = Math.max(-MAX_HORIZONTAL_SPEED, Math.min(MAX_HORIZONTAL_SPEED, player.velocity.x));
player.velocity.y += GRAVITY;
player.position.x += player.velocity.x;
player.position.y += player.velocity.y;
wrapPlayerHorizontally(player);
bounceOnPlatforms(player, platforms);
resetIfPlayerFalls(player, platforms);
}
export function placePlayerOnPlatform(player, platform) {
player.position.x = platform.x + platform.width / 2;
player.position.y = platform.y - player.radius;
player.previousPosition.x = player.position.x;
player.previousPosition.y = player.position.y;
player.velocity.x = 0;
player.velocity.y = JUMP_VELOCITY;
}
function wrapPlayerHorizontally(player) {
if (player.position.x < -player.radius) {
player.position.x = WORLD.width + player.radius;
}
if (player.position.x > WORLD.width + player.radius) {
player.position.x = -player.radius;
}
}
function bounceOnPlatforms(player, platforms) {
if (player.velocity.y <= 0) {
return;
}
const previousBottom = player.previousPosition.y + player.radius;
const currentBottom = player.position.y + player.radius;
for (const platform of platforms) {
const isCrossingTop = previousBottom <= platform.y && currentBottom >= platform.y;
const isOverPlatform = player.position.x + player.radius >= platform.x && player.position.x - player.radius <= platform.x + platform.width;
if (isCrossingTop && isOverPlatform) {
player.position.y = platform.y - player.radius;
player.velocity.y = JUMP_VELOCITY;
return;
}
}
}
function resetIfPlayerFalls(player, platforms) {
if (player.position.y - player.radius <= WORLD.height) {
return;
}
placePlayerOnPlatform(player, platforms[0]);
player.wasReset = true;
}
export function drawPlayer(p, player, camera) {
const localX = player.position.x - camera.x;
const localY = player.position.y - camera.y;
p.push();
p.noStroke();
p.fill(52, 152, 219);
p.circle(localX, localY, player.radius * 2);
p.fill(255);
p.circle(localX + player.radius * 0.35, localY - player.radius * 0.25, player.radius * 0.35);
p.pop();
}
export function drawWorldPlayer(p, player, area) {
p.push();
p.noStroke();
p.fill(96, 165, 250);
p.circle(
area.x + player.position.x * area.scale,
area.y + player.position.y * area.scale,
Math.max(5, player.radius * 2 * area.scale),
);
p.pop();
}