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