112 lines
3.3 KiB
JavaScript
112 lines
3.3 KiB
JavaScript
|
|
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();
|
||
|
|
}
|