Skip to content

Commit b65fe57

Browse files
committed
fix(core): adjust createAttachFn positional type arguments
1 parent a31153b commit b65fe57

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+26239
-30642
lines changed

Diff for: apps/sandbox/src/app/app.component.ts

+35-166
Original file line numberDiff line numberDiff line change
@@ -1,192 +1,61 @@
1-
import { NgIf } from '@angular/common';
2-
import { CUSTOM_ELEMENTS_SCHEMA, Component, Input, computed, signal } from '@angular/core';
3-
import { Triplet } from '@pmndrs/cannon-worker-api';
4-
import { NgtArgs, NgtCanvas, NgtKey, extend } from 'angular-three';
5-
import { NgtcPhysics } from 'angular-three-cannon';
6-
import { NgtcDebug } from 'angular-three-cannon/debug';
7-
import { injectBox, injectPlane } from 'angular-three-cannon/services';
8-
import { NgtpBloom, NgtpEffectComposer } from 'angular-three-postprocessing';
9-
import { NgtsGrid } from 'angular-three-soba/abstractions';
10-
import { NgtsOrbitControls } from 'angular-three-soba/controls';
11-
import { NgtsLoader, injectNgtsGLTFLoader } from 'angular-three-soba/loaders';
12-
import { injectNgtsAnimations } from 'angular-three-soba/misc';
1+
import { Component, Type, ViewChild, ViewContainerRef, effect, signal } from '@angular/core';
2+
import { NgtCanvas, NgtKey, extend } from 'angular-three';
3+
import { NgtsLoader } from 'angular-three-soba/loaders';
134
import * as THREE from 'three';
14-
import { SkyDivingScene } from './skydiving/scene.component';
15-
import { VaporwareScene } from './vaporware/scene.component';
5+
import { AviatorCanvas } from './aviator/canvas.component';
6+
import { BotCanvas } from './bot/canvas.component';
7+
import { CannonCanvas } from './cannon/canvas.component';
8+
import { SkyDivingCanvas } from './skydiving/canvas.component';
9+
import { VaporwareCanvas } from './vaporware/canvas.component';
1610

1711
extend(THREE);
1812

19-
@Component({
20-
selector: 'app-plane',
21-
standalone: true,
22-
template: `
23-
<ngt-mesh [ref]="planeApi.ref" [receiveShadow]="true">
24-
<ngt-plane-geometry *args="[1000, 1000]" />
25-
<ngt-mesh-standard-material color="#171717" />
26-
</ngt-mesh>
27-
`,
28-
imports: [NgtArgs],
29-
schemas: [CUSTOM_ELEMENTS_SCHEMA],
30-
})
31-
export class Plane {
32-
Math = Math;
33-
@Input() position: Triplet = [0, 0, 0];
34-
35-
planeApi = injectPlane(() => ({ mass: 0, position: this.position, args: [1000, 1000] }));
36-
}
37-
38-
@Component({
39-
selector: 'app-box',
40-
standalone: true,
41-
template: `
42-
<ngt-mesh [ref]="boxApi.ref" [receiveShadow]="true" [castShadow]="true">
43-
<ngt-box-geometry *args="[2, 2, 2]" />
44-
<ngt-mesh-standard-material [roughness]="0.5" color="#575757" />
45-
</ngt-mesh>
46-
`,
47-
imports: [NgtArgs],
48-
schemas: [CUSTOM_ELEMENTS_SCHEMA],
49-
})
50-
export class Box {
51-
@Input() position: Triplet = [0, 0, 0];
52-
53-
boxApi = injectBox(() => ({ mass: 10000, position: this.position, args: [2, 2, 2] }));
54-
}
55-
56-
@Component({
57-
standalone: true,
58-
template: `
59-
<ngt-point-light [position]="[-10, -10, 30]" [intensity]="0.25 * Math.PI" />
60-
<ngt-spot-light
61-
[intensity]="0.3 * Math.PI"
62-
[position]="[30, 30, 50]"
63-
[angle]="0.2"
64-
[penumbra]="1"
65-
[castShadow]="true"
66-
/>
67-
<ngtc-physics [gravity]="[0, 0, -25]" [iterations]="10">
68-
<ngtc-debug color="white" [disabled]="true">
69-
<app-plane [position]="[0, 0, -10]" />
70-
<app-plane *ngIf="showPlane()" />
71-
<app-box [position]="[1, 0, 1]" />
72-
<app-box [position]="[2, 1, 5]" />
73-
<app-box [position]="[0, 0, 6]" />
74-
<app-box [position]="[-1, 1, 8]" />
75-
<app-box [position]="[-2, 2, 13]" />
76-
<app-box [position]="[2, -1, 13]" />
77-
<app-box *ngIf="!showPlane()" [position]="[0.5, 1.0, 20]" />
78-
</ngtc-debug>
79-
</ngtc-physics>
80-
`,
81-
imports: [Box, Plane, NgtcPhysics, NgIf, NgtcDebug],
82-
schemas: [CUSTOM_ELEMENTS_SCHEMA],
83-
})
84-
export class CannonScene {
85-
Math = Math;
86-
showPlane = signal(true);
87-
88-
ngOnInit() {
89-
setTimeout(() => {
90-
this.showPlane.set(false);
91-
}, 5000);
92-
}
93-
}
94-
95-
@Component({
96-
standalone: true,
97-
template: `
98-
<ngt-ambient-light />
99-
<ngt-point-light />
100-
<ngt-primitive *args="[bot()]" [ref]="animations.ref" [position]="[0, -1, 0]" />
101-
<ngts-orbit-controls />
102-
<ngts-grid [position]="[0, -1, 0]" [args]="[10, 10]" />
103-
104-
<ngtp-effect-composer>
105-
<ngtp-bloom [intensity]="1.5" />
106-
</ngtp-effect-composer>
107-
`,
108-
imports: [NgtArgs, NgtsOrbitControls, NgtsGrid, NgtpEffectComposer, NgtpBloom],
109-
schemas: [CUSTOM_ELEMENTS_SCHEMA],
110-
})
111-
export class Scene {
112-
Math = Math;
113-
114-
active = signal(false);
115-
hover = signal(false);
116-
117-
private yBotGltf = injectNgtsGLTFLoader(() => 'assets/ybot.glb');
118-
119-
animations = injectNgtsAnimations(() => this.yBotGltf()?.animations || []);
120-
bot = computed(() => {
121-
const gltf = this.yBotGltf();
122-
if (gltf) {
123-
return gltf.scene;
124-
}
125-
return null;
126-
});
127-
}
128-
129-
const scenes = {
130-
bot: {
131-
scene: Scene,
132-
cameraOptions: {},
133-
glOptions: {},
134-
},
135-
cannon: {
136-
scene: CannonScene,
137-
cameraOptions: { position: [0, 0, 15] },
138-
glOptions: { useLegacyLights: true },
139-
},
140-
skydiving: {
141-
scene: SkyDivingScene,
142-
cameraOptions: { fov: 70, position: [0, 0, 3] },
143-
glOptions: { useLegacyLights: true },
144-
},
145-
vaporware: {
146-
scene: VaporwareScene,
147-
cameraOptions: { near: 0.01, far: 20, position: [0, 0.06, 1.1] },
148-
glOptions: { useLegacyLights: true },
149-
},
13+
const canvases = {
14+
bot: BotCanvas,
15+
skydiving: SkyDivingCanvas,
16+
vaporware: VaporwareCanvas,
17+
aviator: AviatorCanvas,
18+
cannon: CannonCanvas,
15019
} as const;
151-
const availableScenes = Object.keys(scenes) as [keyof typeof scenes];
15220

153-
type AvailableScene = (typeof availableScenes)[number];
21+
const availableCanvases = Object.keys(canvases) as [keyof typeof canvases];
22+
type AvailableCanvas = (typeof availableCanvases)[number];
15423

15524
@Component({
15625
standalone: true,
15726
imports: [NgtCanvas, NgtKey, NgtsLoader],
15827
selector: 'sandbox-root',
15928
template: `
160-
<ngt-canvas
161-
*key="scene"
162-
[sceneGraph]="currentScene.scene"
163-
[camera]="currentScene.cameraOptions"
164-
[gl]="currentScene.glOptions"
165-
[shadows]="true"
166-
/>
29+
<ng-container #anchor />
16730
<ngts-loader />
168-
<button class="cycle" (click)="cycleScene()">Current scene: {{ scene }}</button>
31+
<button class="cycle" (click)="cycleCanvas()">Current canvas: {{ canvas() }}</button>
16932
`,
17033
host: {
17134
'[style.--background]': 'background',
172-
style: 'background-color: var(--background); display: block; height: 100%; width: 100%',
35+
style: 'background: var(--background); display: block; height: 100%; width: 100%',
17336
},
17437
})
17538
export class AppComponent {
176-
scene: AvailableScene = 'vaporware';
39+
canvas = signal<AvailableCanvas>('aviator');
17740

178-
get currentScene() {
179-
return scenes[this.scene];
41+
@ViewChild('anchor', { static: true, read: ViewContainerRef }) vcr!: ViewContainerRef;
42+
43+
constructor() {
44+
effect((onCleanup) => {
45+
const ref = this.vcr.createComponent(canvases[this.canvas()] as Type<unknown>);
46+
onCleanup(ref.destroy.bind(ref));
47+
});
18048
}
18149

182-
get background() {
183-
if (this.scene === 'skydiving') return '#272727';
184-
if (this.scene === 'vaporware') return 'black';
185-
return 'white';
50+
cycleCanvas() {
51+
const index = availableCanvases.indexOf(this.canvas());
52+
this.canvas.set(availableCanvases[(index + 1) % availableCanvases.length]);
18653
}
18754

188-
cycleScene() {
189-
const index = availableScenes.indexOf(this.scene);
190-
this.scene = availableScenes[(index + 1) % availableScenes.length];
55+
get background() {
56+
if (this.canvas() === 'skydiving') return '#272727';
57+
if (this.canvas() === 'vaporware') return 'black';
58+
if (this.canvas() === 'aviator') return 'linear-gradient(#101232, #101560)';
59+
return 'white';
19160
}
19261
}

Diff for: apps/sandbox/src/app/aviator/canvas.component.html

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
<ngt-canvas [sceneGraph]="scene" [camera]="{ fov: 50, near: 0.1, far: 10000 }" [shadows]="true" />
2+
<span style="position: absolute; top: 0; right: 1rem; font-size: xxx-large; color: #ffd700">{{ game.coins }}</span>

Diff for: apps/sandbox/src/app/aviator/canvas.component.ts

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { Component, inject } from '@angular/core';
2+
import { NgtCanvas } from 'angular-three';
3+
import { AviatorScene } from './scene.component';
4+
import { GameService } from './services/game.service';
5+
import { WorldService } from './services/world.service';
6+
7+
@Component({
8+
standalone: true,
9+
templateUrl: './canvas.component.html',
10+
imports: [NgtCanvas],
11+
providers: [WorldService, GameService],
12+
host: { class: 'aviator-canvas' },
13+
})
14+
export class AviatorCanvas {
15+
scene = AviatorScene;
16+
17+
game = inject(GameService);
18+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
<ngt-object3D
2+
[castShadow]="true"
3+
[receiveShadow]="true"
4+
[scale]="0.25"
5+
[position]="[0, world.planeDefaultHeight, 0]"
6+
[ref]="refs.airplaneRef"
7+
(beforeRender)="onAirplaneBeforeRender($event)"
8+
>
9+
<!-- cabin -->
10+
<ngt-mesh [castShadow]="true" [receiveShadow]="true">
11+
<ngt-buffer-geometry>
12+
<ngt-buffer-attribute attach="attributes.position" *args="[cabinVertices, 3]" />
13+
</ngt-buffer-geometry>
14+
<ngt-mesh-phong-material [color]="Colors.red" [flatShading]="true" [side]="DoubleSide" />
15+
</ngt-mesh>
16+
17+
<!-- engine -->
18+
<ngt-mesh [position]="[50, 0, 0]" [castShadow]="true" [receiveShadow]="true">
19+
<ngt-box-geometry *args="[20, 50, 50]" />
20+
<ngt-mesh-phong-material [color]="Colors.white" [flatShading]="true" />
21+
</ngt-mesh>
22+
23+
<!-- tail plane -->
24+
<ngt-mesh [position]="[-40, 20, 0]" [castShadow]="true" [receiveShadow]="true">
25+
<ngt-box-geometry *args="[15, 20, 5]" />
26+
<ngt-mesh-phong-material [color]="Colors.red" [flatShading]="true" />
27+
</ngt-mesh>
28+
29+
<!-- side wing -->
30+
<ngt-mesh [position]="[0, 15, 0]" [castShadow]="true" [receiveShadow]="true">
31+
<ngt-box-geometry *args="[30, 5, 120]" />
32+
<ngt-mesh-phong-material [color]="Colors.red" [flatShading]="true" />
33+
</ngt-mesh>
34+
35+
<!-- windshield -->
36+
<ngt-mesh [position]="[20, 27, 0]" [castShadow]="true" [receiveShadow]="true">
37+
<ngt-box-geometry *args="[3, 15, 20]" />
38+
<ngt-mesh-phong-material [color]="Colors.white" [transparent]="true" [opacity]="0.3" [flatShading]="true" />
39+
</ngt-mesh>
40+
41+
<!-- propeller -->
42+
<app-propeller />
43+
44+
<!-- wheels -->
45+
<app-wheel [position]="[25, -20, 25]" />
46+
<app-tire [position]="[25, -28, 25]" />
47+
<app-wheel [position]="[25, -20, -25]" />
48+
<app-tire [position]="[25, -28, -25]" />
49+
<app-tire [position]="[-35, -5, 0]" [scale]="0.5" />
50+
51+
<!-- suspension -->
52+
<ngt-mesh [position]="[-35, -5, 0]" [rotation]="[0, 0, -0.3]">
53+
<ngt-box-geometry #suspensionGeometry *args="[4, 20, 4]" />
54+
<ngt-mesh-phong-material [color]="Colors.red" [flatShading]="true" />
55+
</ngt-mesh>
56+
57+
<!-- pilot -->
58+
<app-pilot [position]="[5, 27, 0]" />
59+
</ngt-object3D>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
import { CUSTOM_ELEMENTS_SCHEMA, Component, ElementRef, ViewChild, inject } from '@angular/core';
2+
import { NgtArgs, NgtBeforeRenderEvent } from 'angular-three';
3+
import * as THREE from 'three';
4+
import { GameService } from '../../services/game.service';
5+
import { RefsService } from '../../services/refs.service';
6+
import { WorldService } from '../../services/world.service';
7+
import { Colors } from '../../utils/colors';
8+
import { makeTetrahedron } from '../../utils/make-tetrahedron';
9+
import { normalize } from '../../utils/normalize';
10+
import { Pilot } from './pilot/pilot.component';
11+
import { Propeller } from './propeller/propeller.component';
12+
import { Tire } from './tire/tire.component';
13+
import { Wheel } from './wheel/wheel.component';
14+
15+
const frontUR = [40, 25, -25];
16+
const frontUL = [40, 25, 25];
17+
const frontLR = [40, -25, -25];
18+
const frontLL = [40, -25, 25];
19+
const backUR = [-40, 15, -5];
20+
const backUL = [-40, 15, 5];
21+
const backLR = [-40, 5, -5];
22+
const backLL = [-40, 5, 5];
23+
24+
@Component({
25+
selector: 'app-airplane',
26+
standalone: true,
27+
templateUrl: './airplane.component.html',
28+
imports: [NgtArgs, Propeller, Wheel, Tire, Pilot],
29+
schemas: [CUSTOM_ELEMENTS_SCHEMA],
30+
})
31+
export class Airplane {
32+
Colors = Colors;
33+
34+
DoubleSide = THREE.DoubleSide;
35+
36+
cabinVertices = new Float32Array(
37+
makeTetrahedron(frontUL, frontUR, frontLL, frontLR) // front
38+
.concat(makeTetrahedron(backUL, backUR, backLL, backLR)) // back
39+
.concat(makeTetrahedron(backUR, backLR, frontUR, frontLR)) // side
40+
.concat(makeTetrahedron(backUL, backLL, frontUL, frontLL)) // side
41+
.concat(makeTetrahedron(frontUL, backUL, frontUR, backUR)) // top
42+
.concat(makeTetrahedron(frontLL, backLL, frontLR, backLR)), // bottom
43+
);
44+
45+
@ViewChild('suspensionGeometry') set suspensionGeometry({ nativeElement }: ElementRef<THREE.BoxGeometry>) {
46+
nativeElement.applyMatrix4(new THREE.Matrix4().makeTranslation(0, 10, 0));
47+
}
48+
49+
world = inject(WorldService);
50+
game = inject(GameService);
51+
refs = inject(RefsService);
52+
53+
constructor() {
54+
console.log(this.world);
55+
}
56+
57+
onAirplaneBeforeRender({ object, state: { pointer, delta } }: NgtBeforeRenderEvent<THREE.Object3D>) {
58+
if (this.game.status === 'playing') {
59+
this.game.planeSpeed = normalize(pointer.x, -0.5, 0.5, this.world.planeMinSpeed, this.world.planeMaxSpeed);
60+
let targetX = normalize(pointer.x, -1, 1, -this.world.planeAmpWidth * 0.7, -this.world.planeAmpWidth);
61+
let targetY = normalize(
62+
pointer.y,
63+
-0.75,
64+
0.75,
65+
this.world.planeDefaultHeight - this.world.planeAmpHeight,
66+
this.world.planeDefaultHeight + this.world.planeAmpHeight,
67+
);
68+
69+
this.game.planeCollisionDisplacementX += this.game.planeCollisionSpeedX;
70+
targetX += this.game.planeCollisionDisplacementX;
71+
72+
this.game.planeCollisionDisplacementY += this.game.planeCollisionSpeedY;
73+
targetY += this.game.planeCollisionDisplacementY;
74+
75+
object.position.x += (targetX - object.position.x) * delta * 1000 * this.world.planeMoveSensivity;
76+
object.position.y += (targetY - object.position.y) * delta * 1000 * this.world.planeMoveSensivity;
77+
78+
object.rotation.x = (object.position.y - targetY) * delta * 1000 * this.world.planeRotZSensivity;
79+
object.rotation.z = (targetY - object.position.y) * delta * 1000 * this.world.planeRotXSensivity;
80+
}
81+
82+
this.game.planeCollisionSpeedX += (0 - this.game.planeCollisionSpeedX) * delta * 1000 * 0.03;
83+
this.game.planeCollisionDisplacementX += (0 - this.game.planeCollisionDisplacementX) * delta * 1000 * 0.01;
84+
this.game.planeCollisionSpeedY += (0 - this.game.planeCollisionSpeedY) * delta * 1000 * 0.03;
85+
this.game.planeCollisionDisplacementY += (0 - this.game.planeCollisionDisplacementY) * delta * 1000 * 0.01;
86+
}
87+
}

0 commit comments

Comments
 (0)