Game Making Between the PEKs and the PIMPs

If anyone is interested in helping me with coding some of the game, please reach out. It's something I've been working on in between @enginewitty and the PIMP backend work, and my own PeakeCoin Projects. This is the code as far as I have come. It can be a lot of work, but it does come with its perks.
I'll work on getting this uploaded so it's playable as I work on it.
//game.js
// Babylon.js 2D top-down setup
const canvas = document.getElementById("gameCanvas");
const engine = new BABYLON.Engine(canvas, true);
const scene = new BABYLON.Scene(engine);
scene.clearColor = new BABYLON.Color3(0.95, 0.95, 0.95);
// Camera for side-view 2.5D (like Mario)
const camera = new BABYLON.FreeCamera("camera1", new BABYLON.Vector3(0, 50, 150), scene);
camera.setTarget(new BABYLON.Vector3(0, 50, 0));
camera.mode = BABYLON.Camera.ORTHOGRAPHIC_CAMERA;
camera.orthoLeft = -canvas.width / 2;
camera.orthoRight = canvas.width / 2;
camera.orthoTop = canvas.height / 2;
camera.orthoBottom = -canvas.height / 2;
// Add lighting (essential for Babylon.js materials)
const light = new BABYLON.HemisphericLight("light1", new BABYLON.Vector3(0, 1, 0), scene);
light.intensity = 1.0;
// Simple tile map (10x10 for demo)
const TILE_SIZE = 48;
const MAP_W = 10;
const MAP_H = 10;
const map = [
[0,0,0,0,0,0,0,0,0,0],
[0,1,1,0,0,0,1,1,1,0],
[0,0,0,0,1,0,0,0,1,0],
[0,1,0,0,1,0,1,0,0,0],
[0,1,0,0,0,0,1,0,1,0],
[0,0,0,1,1,0,0,0,1,0],
[0,1,0,0,0,0,1,0,0,0],
[0,1,1,1,0,1,1,0,1,0],
[0,0,0,0,0,0,0,0,1,0],
[0,0,1,1,1,0,0,0,0,0],
];
// Create side-view ground platforms (like Mario levels)
for (let x = 0; x < MAP_W * 2; x++) {
// Ground platform
const ground = BABYLON.MeshBuilder.CreateBox(`ground_${x}`, {width: TILE_SIZE, height: TILE_SIZE/2, depth: TILE_SIZE}, scene);
ground.position.x = (x - MAP_W) * TILE_SIZE;
ground.position.y = 0; // Ground level
ground.position.z = 0;
const groundMat = new BABYLON.StandardMaterial(`groundMat_${x}`, scene);
groundMat.diffuseColor = new BABYLON.Color3(0.4, 0.3, 0.2); // Brown ground
ground.material = groundMat;
// Occasional platforms at different heights
if (x % 4 === 0 && x > 2) {
const platform = BABYLON.MeshBuilder.CreateBox(`platform_${x}`, {width: TILE_SIZE * 2, height: TILE_SIZE/3, depth: TILE_SIZE}, scene);
platform.position.x = (x - MAP_W) * TILE_SIZE;
platform.position.y = 60 + Math.sin(x * 0.5) * 30; // Varying platform heights
platform.position.z = 0;
const platMat = new BABYLON.StandardMaterial(`platMat_${x}`, scene);
platMat.diffuseColor = new BABYLON.Color3(0.2, 0.6, 0.2); // Green platforms
platform.material = platMat;
}
}
// Player as a colored circle
// Player as a simple human figure (top-down)
const playerGroup = new BABYLON.TransformNode("playerGroup", scene);
// Create super smooth character with joint hierarchy
const charSize = 20;
// Create materials with bright outline effect
const createOutlineMaterial = (color, outlineColor = new BABYLON.Color3(0, 1, 1)) => {
const mat = new BABYLON.StandardMaterial("material", scene);
mat.diffuseColor = color;
mat.emissiveColor = color.scale(0.1); // Slight glow
// Create outline effect using edge rendering
mat.backFaceCulling = false;
return mat;
};
// Head with smooth sphere
const head = BABYLON.MeshBuilder.CreateSphere("head", {diameter: charSize, segments: 32}, scene);
const headMat = createOutlineMaterial(new BABYLON.Color3(1, 0.85, 0.7));
head.material = headMat;
head.position.y = 55;
head.position.z = 0;
head.parent = playerGroup;
// Neck connector (smooth joint)
const neck = BABYLON.MeshBuilder.CreateCylinder("neck", {height: 8, diameter: 6, tessellation: 16}, scene);
neck.material = headMat;
neck.position.y = 46;
neck.parent = playerGroup;
// Torso (smooth rounded rectangle)
const torso = BABYLON.MeshBuilder.CreateCylinder("torso", {height: charSize * 1.4, diameter: charSize * 0.9, tessellation: 8}, scene);
const torsoMat = createOutlineMaterial(new BABYLON.Color3(0.9, 0.3, 0.3));
torso.material = torsoMat;
torso.position.y = 35;
torso.parent = playerGroup;
// Shoulder joints (smooth connection points)
const leftShoulder = BABYLON.MeshBuilder.CreateSphere("leftShoulder", {diameter: 6, segments: 16}, scene);
leftShoulder.material = headMat;
leftShoulder.position.x = -charSize * 0.4;
leftShoulder.position.y = 42;
leftShoulder.parent = playerGroup;
const rightShoulder = BABYLON.MeshBuilder.CreateSphere("rightShoulder", {diameter: 6, segments: 16}, scene);
rightShoulder.material = headMat;
rightShoulder.position.x = charSize * 0.4;
rightShoulder.position.y = 42;
rightShoulder.parent = playerGroup;
// Upper arms (smooth cylinders)
const leftUpperArm = BABYLON.MeshBuilder.CreateCylinder("leftUpperArm", {height: charSize * 0.7, diameter: 5, tessellation: 12}, scene);
const armMat = createOutlineMaterial(new BABYLON.Color3(1, 0.8, 0.6));
leftUpperArm.material = armMat;
leftUpperArm.position.x = -charSize * 0.4;
leftUpperArm.position.y = 35;
leftUpperArm.parent = playerGroup;
const rightUpperArm = BABYLON.MeshBuilder.CreateCylinder("rightUpperArm", {height: charSize * 0.7, diameter: 5, tessellation: 12}, scene);
rightUpperArm.material = armMat;
rightUpperArm.position.x = charSize * 0.4;
rightUpperArm.position.y = 35;
rightUpperArm.parent = playerGroup;
// Elbow joints
const leftElbow = BABYLON.MeshBuilder.CreateSphere("leftElbow", {diameter: 4, segments: 12}, scene);
leftElbow.material = armMat;
leftElbow.position.x = -charSize * 0.4;
leftElbow.position.y = 28;
leftElbow.parent = playerGroup;
const rightElbow = BABYLON.MeshBuilder.CreateSphere("rightElbow", {diameter: 4, segments: 12}, scene);
rightElbow.material = armMat;
rightElbow.position.x = charSize * 0.4;
rightElbow.position.y = 28;
rightElbow.parent = playerGroup;
// Forearms
const leftForearm = BABYLON.MeshBuilder.CreateCylinder("leftForearm", {height: charSize * 0.6, diameter: 4, tessellation: 12}, scene);
leftForearm.material = armMat;
leftForearm.position.x = -charSize * 0.4;
leftForearm.position.y = 22;
leftForearm.parent = playerGroup;
const rightForearm = BABYLON.MeshBuilder.CreateCylinder("rightForearm", {height: charSize * 0.6, diameter: 4, tessellation: 12}, scene);
rightForearm.material = armMat;
rightForearm.position.x = charSize * 0.4;
rightForearm.position.y = 22;
rightForearm.parent = playerGroup;
// Hip joints
const leftHip = BABYLON.MeshBuilder.CreateSphere("leftHip", {diameter: 6, segments: 16}, scene);
const legMat = createOutlineMaterial(new BABYLON.Color3(0.2, 0.2, 0.9));
leftHip.material = legMat;
leftHip.position.x = -charSize * 0.2;
leftHip.position.y = 25;
leftHip.parent = playerGroup;
const rightHip = BABYLON.MeshBuilder.CreateSphere("rightHip", {diameter: 6, segments: 16}, scene);
rightHip.material = legMat;
rightHip.position.x = charSize * 0.2;
rightHip.position.y = 25;
rightHip.parent = playerGroup;
// Thighs
const leftThigh = BABYLON.MeshBuilder.CreateCylinder("leftThigh", {height: charSize * 0.8, diameter: 6, tessellation: 12}, scene);
leftThigh.material = legMat;
leftThigh.position.x = -charSize * 0.2;
leftThigh.position.y = 18;
leftThigh.parent = playerGroup;
const rightThigh = BABYLON.MeshBuilder.CreateCylinder("rightThigh", {height: charSize * 0.8, diameter: 6, tessellation: 12}, scene);
rightThigh.material = legMat;
rightThigh.position.x = charSize * 0.2;
rightThigh.position.y = 18;
rightThigh.parent = playerGroup;
// Knee joints
const leftKnee = BABYLON.MeshBuilder.CreateSphere("leftKnee", {diameter: 5, segments: 12}, scene);
leftKnee.material = legMat;
leftKnee.position.x = -charSize * 0.2;
leftKnee.position.y = 12;
leftKnee.parent = playerGroup;
const rightKnee = BABYLON.MeshBuilder.CreateSphere("rightKnee", {diameter: 5, segments: 12}, scene);
rightKnee.material = legMat;
rightKnee.position.x = charSize * 0.2;
rightKnee.position.y = 12;
rightKnee.parent = playerGroup;
// Calves
const leftCalf = BABYLON.MeshBuilder.CreateCylinder("leftCalf", {height: charSize * 0.7, diameter: 5, tessellation: 12}, scene);
leftCalf.material = legMat;
leftCalf.position.x = -charSize * 0.2;
leftCalf.position.y = 7;
leftCalf.parent = playerGroup;
const rightCalf = BABYLON.MeshBuilder.CreateCylinder("rightCalf", {height: charSize * 0.7, diameter: 5, tessellation: 12}, scene);
rightCalf.material = legMat;
rightCalf.position.x = charSize * 0.2;
rightCalf.position.y = 7;
rightCalf.parent = playerGroup;
// Feet for complete walking cycle
const leftFoot = BABYLON.MeshBuilder.CreateBox("leftFoot", {width: 8, height: 3, depth: 12}, scene);
const footMat = createOutlineMaterial(new BABYLON.Color3(0.3, 0.2, 0.1));
leftFoot.material = footMat;
leftFoot.position.x = -charSize * 0.2;
leftFoot.position.y = 2;
leftFoot.parent = playerGroup;
const rightFoot = BABYLON.MeshBuilder.CreateBox("rightFoot", {width: 8, height: 3, depth: 12}, scene);
rightFoot.material = footMat;
rightFoot.position.x = charSize * 0.2;
rightFoot.position.y = 2;
rightFoot.parent = playerGroup;
// Add bright outline effect to entire character
playerGroup.getChildMeshes().forEach(mesh => {
if (mesh.material) {
mesh.renderOutline = true;
mesh.outlineWidth = 0.5;
mesh.outlineColor = new BABYLON.Color3(0, 1, 1); // Bright cyan outline
}
});
// Store body parts for smooth animation
const bodyParts = {
head, neck, torso,
leftShoulder, rightShoulder,
leftUpperArm, rightUpperArm,
leftElbow, rightElbow,
leftForearm, rightForearm,
leftHip, rightHip,
leftThigh, rightThigh,
leftKnee, rightKnee,
leftCalf, rightCalf,
leftFoot, rightFoot
};
// Initial position (standing on ground)
playerGroup.position.x = 0;
playerGroup.position.y = 25; // Standing on ground level
playerGroup.position.z = 0;
// Add a simple test box to verify rendering
const testBox = BABYLON.MeshBuilder.CreateBox("testBox", {size: 20}, scene);
const testMat = new BABYLON.StandardMaterial("testMat", scene);
testMat.diffuseColor = new BABYLON.Color3(1, 0, 0); // bright red
testBox.material = testMat;
testBox.position.x = 100;
testBox.position.y = 100;
testBox.position.z = 2;
console.log("Player created at position:", playerGroup.position);
console.log("Camera position:", camera.position);
console.log("Camera ortho bounds:", camera.orthoLeft, camera.orthoRight, camera.orthoTop, camera.orthoBottom);
console.log("Test box created at:", testBox.position);
// Player movement with Mario-style physics
let playerX = 0;
let playerVelocityY = 0; // For jumping/gravity
let isMoving = false;
let walkCycle = 0;
const speed = 3;
const keys = {};
// Super smooth joint animation with fluid movement
function animateWalk() {
if (!isMoving) {
// Smoothly return to neutral pose with interpolation
bodyParts.leftUpperArm.rotation.z = BABYLON.Scalar.Lerp(bodyParts.leftUpperArm.rotation.z, 0, 0.15);
bodyParts.rightUpperArm.rotation.z = BABYLON.Scalar.Lerp(bodyParts.rightUpperArm.rotation.z, 0, 0.15);
bodyParts.leftForearm.rotation.z = BABYLON.Scalar.Lerp(bodyParts.leftForearm.rotation.z, 0, 0.15);
bodyParts.rightForearm.rotation.z = BABYLON.Scalar.Lerp(bodyParts.rightForearm.rotation.z, 0, 0.15);
bodyParts.leftThigh.rotation.z = BABYLON.Scalar.Lerp(bodyParts.leftThigh.rotation.z, 0, 0.15);
bodyParts.rightThigh.rotation.z = BABYLON.Scalar.Lerp(bodyParts.rightThigh.rotation.z, 0, 0.15);
bodyParts.leftCalf.rotation.z = BABYLON.Scalar.Lerp(bodyParts.leftCalf.rotation.z, 0, 0.15);
bodyParts.rightCalf.rotation.z = BABYLON.Scalar.Lerp(bodyParts.rightCalf.rotation.z, 0, 0.15);
bodyParts.torso.position.y = BABYLON.Scalar.Lerp(bodyParts.torso.position.y, 35, 0.15);
bodyParts.head.position.y = BABYLON.Scalar.Lerp(bodyParts.head.position.y, 55, 0.15);
return;
}
walkCycle += 0.2; // Smooth cycle speed
// Calculate fluid movement phases
const armPhase = Math.sin(walkCycle) * 0.5;
const legPhase = Math.sin(walkCycle) * 0.7;
const kneePhase = Math.sin(walkCycle + Math.PI/3) * 0.4;
const elbowPhase = Math.sin(walkCycle + Math.PI/4) * 0.3;
const bounce = Math.abs(Math.sin(walkCycle * 2)) * 2;
const sway = Math.sin(walkCycle * 0.5) * 0.05;
// Super smooth arm movement with natural joint articulation
bodyParts.leftUpperArm.rotation.z = armPhase;
bodyParts.rightUpperArm.rotation.z = -armPhase;
// Forearms follow with natural elbow bend
bodyParts.leftForearm.rotation.z = armPhase * 0.6 + elbowPhase;
bodyParts.rightForearm.rotation.z = -armPhase * 0.6 - elbowPhase;
// Biomechanically correct leg movement
bodyParts.leftThigh.rotation.z = legPhase;
bodyParts.rightThigh.rotation.z = -legPhase;
// Correct knee bending: knees bend when leg swings forward (lifting), straighten when pushing back
const leftKneeBend = legPhase > 0 ? Math.abs(legPhase) * 0.8 : 0; // Bend when swinging forward
const rightKneeBend = -legPhase > 0 ? Math.abs(-legPhase) * 0.8 : 0; // Bend when swinging forward
bodyParts.leftCalf.rotation.z = -leftKneeBend; // Negative rotation bends knee forward
bodyParts.rightCalf.rotation.z = -rightKneeBend;
// Smooth body movement
bodyParts.torso.position.y = 35 + bounce;
bodyParts.head.position.y = 55 + bounce;
bodyParts.neck.position.y = 46 + bounce;
// Natural body sway and rotation
bodyParts.torso.rotation.z = sway;
bodyParts.head.rotation.z = sway * 0.5;
// Shoulder movement follows arm swing
bodyParts.leftShoulder.position.y = 42 + bounce + Math.sin(walkCycle + armPhase) * 0.5;
bodyParts.rightShoulder.position.y = 42 + bounce + Math.sin(walkCycle - armPhase) * 0.5;
// Hip movement follows leg swing
bodyParts.leftHip.rotation.z = legPhase * 0.3;
bodyParts.rightHip.rotation.z = -legPhase * 0.3;
// Joint connections move smoothly
bodyParts.leftElbow.position.y = 28 + bounce + Math.sin(walkCycle + elbowPhase) * 0.3;
bodyParts.rightElbow.position.y = 28 + bounce + Math.sin(walkCycle - elbowPhase) * 0.3;
// Knee position follows thigh movement but also lifts during bending
const leftKneeHeight = 12 + bounce * 0.5 + (leftKneeBend * 2); // Knee lifts when bending
const rightKneeHeight = 12 + bounce * 0.5 + (rightKneeBend * 2);
bodyParts.leftKnee.position.y = leftKneeHeight;
bodyParts.rightKnee.position.y = rightKneeHeight;
// Calf position should follow knee movement
bodyParts.leftCalf.position.y = 7 + bounce * 0.3 + (leftKneeBend * 1.5);
bodyParts.rightCalf.position.y = 7 + bounce * 0.3 + (rightKneeBend * 1.5);
// Feet follow the walking cycle - lift when leg swings forward, plant when stepping
const leftFootLift = leftKneeBend * 3; // Foot lifts more dramatically
const rightFootLift = rightKneeBend * 3;
bodyParts.leftFoot.position.y = 2 + leftFootLift;
bodyParts.rightFoot.position.y = 2 + rightFootLift;
// Foot angle changes during walk cycle
bodyParts.leftFoot.rotation.z = leftKneeBend * 0.3; // Foot tilts up when lifting
bodyParts.rightFoot.rotation.z = rightKneeBend * 0.3;
}
// Handle keyboard input
window.addEventListener("keydown", (e) => {
keys[e.key.toLowerCase()] = true;
});
window.addEventListener("keyup", (e) => {
keys[e.key.toLowerCase()] = false;
});
// Side-scrolling movement (Mario-style)
function updateMovement() {
let moving = false;
let deltaX = 0;
// Horizontal movement only (side-scrolling)
if (keys['d'] || keys['arrowright']) {
deltaX += speed;
moving = true;
// Face right
playerGroup.rotation.y = 0;
}
if (keys['a'] || keys['arrowleft']) {
deltaX -= speed;
moving = true;
// Face left
playerGroup.rotation.y = Math.PI;
}
// Jump (Mario-style)
if (keys['w'] || keys['arrowup'] || keys[' ']) {
if (Math.abs(playerGroup.position.y - 25) < 5) { // Only jump if on ground
playerVelocityY = 8; // Jump force
}
}
// Apply horizontal movement
playerX += deltaX;
playerGroup.position.x = playerX;
// Apply gravity and vertical movement
playerVelocityY -= 0.3; // Gravity
playerGroup.position.y += playerVelocityY;
// Ground collision
if (playerGroup.position.y <= 25) {
playerGroup.position.y = 25;
playerVelocityY = 0;
}
// Update animation state
isMoving = moving;
animateWalk();
}
engine.runRenderLoop(() => {
updateMovement();
scene.render();
});
0
0
0.000
0 comments