|
| 1 | +import { NgtCannonDebugModule, NgtPhysicBody, NgtPhysicsModule } from '@angular-three/cannon'; |
| 2 | +import { NgtCanvasModule, NgtRadianPipeModule, NgtTriple, UnknownRecord } from '@angular-three/core'; |
| 3 | +import { |
| 4 | + NgtColorAttributeModule, |
| 5 | + NgtFogAttributeModule, |
| 6 | + NgtValueAttributeModule, |
| 7 | +} from '@angular-three/core/attributes'; |
| 8 | +import { NgtCylinderGeometryModule, NgtPlaneGeometryModule } from '@angular-three/core/geometries'; |
| 9 | +import { NgtGroupModule } from '@angular-three/core/group'; |
| 10 | +import { NgtAmbientLightModule, NgtSpotLightModule } from '@angular-three/core/lights'; |
| 11 | +import { NgtMeshNormalMaterialModule, NgtMeshStandardMaterialModule } from '@angular-three/core/materials'; |
| 12 | +import { NgtMeshModule } from '@angular-three/core/meshes'; |
| 13 | +import { NgtSobaEnvironmentModule } from '@angular-three/soba/staging'; |
| 14 | +import { CommonModule } from '@angular/common'; |
| 15 | +import { ChangeDetectionStrategy, Component, HostListener, Input, NgModule } from '@angular/core'; |
| 16 | +import { RouterModule } from '@angular/router'; |
| 17 | +import { CylinderArgs } from '@pmndrs/cannon-worker-api'; |
| 18 | +import * as THREE from 'three'; |
| 19 | +import { Chassis, Vehicle, Wheel } from './vehicle.component'; |
| 20 | + |
| 21 | +@Component({ |
| 22 | + selector: 'sandbox-raycast-vehicle', |
| 23 | + template: ` |
| 24 | + <ngt-canvas initialLog shadows [camera]="{ fov: 50, position: [0, 5, 15] }"> |
| 25 | + <ngt-fog attach="fog" [fog]="['#171720', 10, 50]"></ngt-fog> |
| 26 | + <ngt-color attach="background" color="#171720"></ngt-color> |
| 27 | +
|
| 28 | + <ngt-ambient-light intensity="0.1"></ngt-ambient-light> |
| 29 | + <ngt-spot-light castShadow [position]="[10, 10, 10]" angle="0.5" intensity="1" penumbra="1"></ngt-spot-light> |
| 30 | +
|
| 31 | + <ngt-physics |
| 32 | + broadphase="SAP" |
| 33 | + [defaultContactMaterial]="{ contactEquationRelaxation: 4, friction: 1e-3 }" |
| 34 | + allowSleep |
| 35 | + > |
| 36 | + <sandbox-world *ngIf="isDebugDisabled; else debugEnabled"></sandbox-world> |
| 37 | + <ng-template #debugEnabled> |
| 38 | + <ngt-cannon-debug> |
| 39 | + <sandbox-world></sandbox-world> |
| 40 | + </ngt-cannon-debug> |
| 41 | + </ng-template> |
| 42 | + </ngt-physics> |
| 43 | +
|
| 44 | + <ngt-soba-environment preset="night"></ngt-soba-environment> |
| 45 | + </ngt-canvas> |
| 46 | + <div class="instruction"> |
| 47 | + <pre>* ↑←↓→ to drive, space to brake |
| 48 | + <br />r to reset |
| 49 | + <br />? to debug |
| 50 | + </pre> |
| 51 | + </div> |
| 52 | + `, |
| 53 | + styles: [ |
| 54 | + ` |
| 55 | + .instruction { |
| 56 | + color: white; |
| 57 | + font-size: 1.2em; |
| 58 | + left: 50px; |
| 59 | + position: absolute; |
| 60 | + top: 20px; |
| 61 | + } |
| 62 | + `, |
| 63 | + ], |
| 64 | + changeDetection: ChangeDetectionStrategy.OnPush, |
| 65 | +}) |
| 66 | +export class RaycastVehicleComponent { |
| 67 | + isDebugDisabled = true; |
| 68 | + |
| 69 | + @HostListener('window:keyup', ['$event']) |
| 70 | + private onKeyDown(event: KeyboardEvent) { |
| 71 | + if (event.key === '?') { |
| 72 | + this.isDebugDisabled = !this.isDebugDisabled; |
| 73 | + } |
| 74 | + } |
| 75 | +} |
| 76 | + |
| 77 | +@Component({ |
| 78 | + selector: 'sandbox-world', |
| 79 | + template: ` |
| 80 | + <sandbox-plane [rotation]="[-90 | radian, 0, 0]" [userData]="{ id: 'floor' }"></sandbox-plane> |
| 81 | +
|
| 82 | + <sandbox-vehicle |
| 83 | + [position]="[0, 2, 0]" |
| 84 | + [rotation]="[0, -45 | radian, 0]" |
| 85 | + [angularVelocity]="[0, 0.5, 0]" |
| 86 | + ></sandbox-vehicle> |
| 87 | +
|
| 88 | + <sandbox-pillar [position]="[-5, 2.5, -5]" [userData]="{ id: 'pillar-1' }"></sandbox-pillar> |
| 89 | + <sandbox-pillar [position]="[0, 2.5, -5]" [userData]="{ id: 'pillar-2' }"></sandbox-pillar> |
| 90 | + <sandbox-pillar [position]="[5, 2.5, -5]" [userData]="{ id: 'pillar-3' }"></sandbox-pillar> |
| 91 | + `, |
| 92 | + changeDetection: ChangeDetectionStrategy.OnPush, |
| 93 | +}) |
| 94 | +export class World {} |
| 95 | + |
| 96 | +@Component({ |
| 97 | + selector: 'sandbox-plane', |
| 98 | + template: ` |
| 99 | + <ngt-group [ref]="planeRef.ref" [rotation]="rotation" [userData]="userData"> |
| 100 | + <ngt-mesh receiveShadow> |
| 101 | + <ngt-plane-geometry [args]="[100, 100]"></ngt-plane-geometry> |
| 102 | + <ngt-mesh-standard-material color="#303030"></ngt-mesh-standard-material> |
| 103 | + </ngt-mesh> |
| 104 | + </ngt-group> |
| 105 | + `, |
| 106 | + changeDetection: ChangeDetectionStrategy.OnPush, |
| 107 | + providers: [NgtPhysicBody], |
| 108 | +}) |
| 109 | +export class Plane { |
| 110 | + @Input() rotation?: NgtTriple; |
| 111 | + @Input() userData: UnknownRecord = {}; |
| 112 | + |
| 113 | + readonly planeRef = this.physicBody.usePlane<THREE.Group>(() => ({ |
| 114 | + material: 'ground', |
| 115 | + rotation: this.rotation, |
| 116 | + type: 'Static', |
| 117 | + userData: this.userData, |
| 118 | + args: [100, 100], |
| 119 | + })); |
| 120 | + |
| 121 | + constructor(private physicBody: NgtPhysicBody) {} |
| 122 | +} |
| 123 | + |
| 124 | +@Component({ |
| 125 | + selector: 'sandbox-pillar', |
| 126 | + template: ` |
| 127 | + <ngt-mesh [ref]="pillarRef.ref" [position]="position" [userData]="userData"> |
| 128 | + <ngt-cylinder-geometry [args]="args"></ngt-cylinder-geometry> |
| 129 | + <ngt-mesh-normal-material></ngt-mesh-normal-material> |
| 130 | + </ngt-mesh> |
| 131 | + `, |
| 132 | + changeDetection: ChangeDetectionStrategy.OnPush, |
| 133 | + providers: [NgtPhysicBody], |
| 134 | +}) |
| 135 | +export class Pillar { |
| 136 | + @Input() position?: NgtTriple; |
| 137 | + @Input() userData: UnknownRecord = {}; |
| 138 | + |
| 139 | + readonly args: CylinderArgs = [0.7, 0.7, 5, 16]; |
| 140 | + |
| 141 | + readonly pillarRef = this.physicBody.useCylinder<THREE.Mesh>(() => ({ |
| 142 | + args: this.args, |
| 143 | + mass: 10, |
| 144 | + position: this.position, |
| 145 | + userData: this.userData, |
| 146 | + })); |
| 147 | + |
| 148 | + constructor(private physicBody: NgtPhysicBody) {} |
| 149 | +} |
| 150 | + |
| 151 | +@NgModule({ |
| 152 | + declarations: [RaycastVehicleComponent, Plane, Pillar, Vehicle, Chassis, Wheel, World], |
| 153 | + imports: [ |
| 154 | + RouterModule.forChild([ |
| 155 | + { |
| 156 | + path: '', |
| 157 | + component: RaycastVehicleComponent, |
| 158 | + }, |
| 159 | + ]), |
| 160 | + CommonModule, |
| 161 | + NgtCanvasModule, |
| 162 | + NgtFogAttributeModule, |
| 163 | + NgtColorAttributeModule, |
| 164 | + NgtAmbientLightModule, |
| 165 | + NgtSpotLightModule, |
| 166 | + NgtPhysicsModule, |
| 167 | + NgtCannonDebugModule, |
| 168 | + NgtGroupModule, |
| 169 | + NgtMeshModule, |
| 170 | + NgtPlaneGeometryModule, |
| 171 | + NgtMeshStandardMaterialModule, |
| 172 | + NgtRadianPipeModule, |
| 173 | + NgtCylinderGeometryModule, |
| 174 | + NgtMeshNormalMaterialModule, |
| 175 | + NgtSobaEnvironmentModule, |
| 176 | + NgtValueAttributeModule, |
| 177 | + ], |
| 178 | +}) |
| 179 | +export class RaycastVehicleComponentModule {} |
0 commit comments