All files / src/physics arena.ts

100% Statements 40/40
100% Branches 2/2
100% Functions 2/2
100% Lines 40/40

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 631x                   1x 1x 1x 1x 1x 1x 1x   1x 338x 338x   338x 338x 338x 338x 338x     338x 338x 338x 338x 338x 338x       338x 338x 338x 338x     338x 338x 338x 338x     338x 338x 338x 338x     338x 338x 338x 338x 338x 338x  
import RAPIER from '@dimforge/rapier3d-compat';
 
export interface ArenaConfig {
  lengthMeters: number; // Table length (X or Z axis): standard FLL is 93 inches = 2.362m
  widthMeters: number;  // Table width: standard FLL is 45 inches = 1.143m
  wallHeightMeters: number; // 77mm = ~3 inches
  wallThicknessMeters: number;
  matFriction: number;
}
 
export const DEFAULT_FLL_ARENA_CONFIG: ArenaConfig = {
  lengthMeters: 2.45,  // Table length accommodating 2.40m mat with walls spaced away from field
  widthMeters: 1.45,   // Table width accommodating 1.40m mat with walls spaced away from field
  wallHeightMeters: 0.077,
  wallThicknessMeters: 0.025,
  matFriction: 0.75, // Standard competition vinyl mat friction
};
 
export class FllArenaPhysics {
  public floorBody: RAPIER.RigidBody;
  public wallBodies: RAPIER.RigidBody[] = [];
 
  constructor(world: RAPIER.World, config: ArenaConfig = DEFAULT_FLL_ARENA_CONFIG) {
    const halfL = config.lengthMeters / 2;
    const halfW = config.widthMeters / 2;
    const halfH = config.wallHeightMeters / 2;
    const thick = config.wallThicknessMeters;
 
    // 1. Vinyl Mat Floor Collider (At Y = 0)
    const floorBodyDesc = RAPIER.RigidBodyDesc.fixed().setTranslation(0, -0.05, 0);
    this.floorBody = world.createRigidBody(floorBodyDesc);
    const floorColliderDesc = RAPIER.ColliderDesc.cuboid(halfL + 0.1, 0.05, halfW + 0.1)
      .setFriction(config.matFriction)
      .setRestitution(0.0);
    world.createCollider(floorColliderDesc, this.floorBody);
 
    // 2. Perimeter Boundary Walls (North, South, East, West)
    // North wall (+Z)
    const northDesc = RAPIER.RigidBodyDesc.fixed().setTranslation(0, halfH, halfW + thick / 2);
    const northBody = world.createRigidBody(northDesc);
    world.createCollider(RAPIER.ColliderDesc.cuboid(halfL + thick, halfH, thick / 2).setFriction(0.3), northBody);
    this.wallBodies.push(northBody);
 
    // South wall (-Z)
    const southDesc = RAPIER.RigidBodyDesc.fixed().setTranslation(0, halfH, -halfW - thick / 2);
    const southBody = world.createRigidBody(southDesc);
    world.createCollider(RAPIER.ColliderDesc.cuboid(halfL + thick, halfH, thick / 2).setFriction(0.3), southBody);
    this.wallBodies.push(southBody);
 
    // East wall (+X)
    const eastDesc = RAPIER.RigidBodyDesc.fixed().setTranslation(halfL + thick / 2, halfH, 0);
    const eastBody = world.createRigidBody(eastDesc);
    world.createCollider(RAPIER.ColliderDesc.cuboid(thick / 2, halfH, halfW).setFriction(0.3), eastBody);
    this.wallBodies.push(eastBody);
 
    // West wall (-X)
    const westDesc = RAPIER.RigidBodyDesc.fixed().setTranslation(-halfL - thick / 2, halfH, 0);
    const westBody = world.createRigidBody(westDesc);
    world.createCollider(RAPIER.ColliderDesc.cuboid(thick / 2, halfH, halfW).setFriction(0.3), westBody);
    this.wallBodies.push(westBody);
  }
}