Skip to content
This repository has been archived by the owner on Jun 10, 2022. It is now read-only.

Jabenk/pr #541

Merged
merged 6 commits into from
Apr 29, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions packages/functional-tests/src/tests/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ import InputTest from './input-test';
import LibraryFailTest from './library-fail-test';
import LightTest from './light-test';
import LookAtTest from './look-at-test';
import PhysicsBounceTest from './physics-bounce-test';
import PhysicsFrictionTest from './physics-friction-test';
import PhysicsSimTest from './physics-sim-test';
import PrimitivesTest from './primitives-test';
import PromptTest from './prompt-test';
Expand Down Expand Up @@ -74,6 +76,8 @@ export const Factories = {
'library-fail': (...args) => new LibraryFailTest(...args),
'light': (...args) => new LightTest(...args),
'look-at': (...args) => new LookAtTest(...args),
'physics-bounce': (...args) => new PhysicsBounceTest(...args),
'physics-friction': (...args) => new PhysicsFrictionTest(...args),
'physics-sim': (...args) => new PhysicsSimTest(...args),
'primitives': (...args) => new PrimitivesTest(...args),
'prompt': (...args) => new PromptTest(...args),
Expand Down
105 changes: 105 additions & 0 deletions packages/functional-tests/src/tests/physics-bounce-test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
/*!
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/

import * as MRE from '@microsoft/mixed-reality-extension-sdk';

import { Test } from '../test';

const defaultBallColor = MRE.Color3.FromInts(220, 150, 150);

export default class PhysicsBounceTest extends Test {
public expectedResultDescription = "Balls and boxes hit the ground and bounce.";
private assets: MRE.AssetContainer;
private interval: NodeJS.Timeout;
private ballboxMat: MRE.Material;
private bouncePlane: MRE.Actor;

public async run(root: MRE.Actor): Promise<boolean> {
this.assets = new MRE.AssetContainer(this.app.context);

this.ballboxMat = this.assets.createMaterial('ball', {
color: defaultBallColor
});

this.createBouncePlane(root, 2, 1.25);

this.interval = setInterval(() => this.spawnBallOrBox(root, 1.5, 1.5), 1000);

await this.stoppedAsync();
return true;
}

public cleanup() {
clearInterval(this.interval);
this.assets.unload();
}

private createBouncePlane(root: MRE.Actor, width: number, height: number) {
const box = this.assets.createBoxMesh('box', 2.0, 0.05, 2.0).id;
this.bouncePlane = MRE.Actor.Create(this.app.context, {
actor: {
parentId: root.id,
appearance: {
meshId: box,
materialId: this.ballboxMat.id
},
transform: {
app: { position: { x: 0.0, y: 0.0, z: -1.0 } }
},
text: {
contents: `Bouncing balls and boxes`,
anchor: MRE.TextAnchorLocation.MiddleLeft,
height: .2
},
collider: {
geometry: { shape: MRE.ColliderType.Auto },
bounciness: 0.8, dynamicFriction: 0.0, staticFriction: 0.0
}
}
});
}

private spawnBallOrBox(root: MRE.Actor, width: number, height: number, radius = 0.1, killTimeout = 20000) {
const isSphere = (Math.random() > 0.5);
const ballOrBoxID = ((isSphere) ? (this.assets.createSphereMesh('ball', radius).id) :
(this.assets.createBoxMesh('box', 1.5 * radius, 1.8 * radius, 2.1 * radius).id));
// create ball or box
const ballOrBox = MRE.Actor.Create(this.app.context, {
actor: {
parentId: root.id,
appearance: {
meshId: ballOrBoxID,
materialId: this.ballboxMat.id
},
transform: {
local: {
position: {
x: -width / 2 + width * Math.random(),
y: height, z: -(-0.1 + 0.2 * Math.random())
}
}
},
rigidBody: {
mass: 3,
// give the box or spere some initial velocities
angularVelocity: {
x: 10 * Math.random() - 5.0, y: 10.0 * Math.random() - 5.0,
z: 10 * Math.random() - 5.0
},
velocity: { x: 0.0, y: 5 * Math.random() - 2.5, z: -3.0 * Math.random() },
constraints: [MRE.RigidBodyConstraints.None]
},
collider: {
geometry: { shape: MRE.ColliderType.Auto },
bounciness: 0.8, dynamicFriction: 0.0, staticFriction: 0.0
}
}
});

setTimeout(() => {
ballOrBox.destroy();
}, killTimeout);
}
}
107 changes: 107 additions & 0 deletions packages/functional-tests/src/tests/physics-friction-test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
/*!
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/

import * as MRE from '@microsoft/mixed-reality-extension-sdk';

import { Test } from '../test';

const defaultBoxColor = MRE.Color3.FromInts(220, 150, 150);

export default class PhysicsFrictionTest extends Test {
public expectedResultDescription = "Boxes slide with different frictions.";
private assets: MRE.AssetContainer;
private interval: NodeJS.Timeout;
private boxMat: MRE.Material;
private slopePlane: MRE.Actor;

public async run(root: MRE.Actor): Promise<boolean> {
this.assets = new MRE.AssetContainer(this.app.context);

this.boxMat = this.assets.createMaterial('box', {
color: defaultBoxColor
});

this.createSlopePlane(root, 2, 1.25);

this.interval = setInterval(() => this.spawnBox(root, 1.5, 1.5), 500);

await this.stoppedAsync();
return true;
}

public cleanup() {
clearInterval(this.interval);
this.assets.unload();
}

private createSlopePlane(root: MRE.Actor, width: number, height: number) {
// Create a box as a slope for sliding
const box = this.assets.createBoxMesh('box', 2.5, 0.05, 2.5).id;
this.slopePlane = MRE.Actor.Create(this.app.context, {
actor: {
parentId: root.id,
appearance: {
meshId: box,
materialId: this.boxMat.id
},
transform: {
app: {
position: { x: 0.0, y: 0.5, z: -0.8 },
rotation: { x: 0.966, y: 0.0, z: 0.0, w: 0.259 }
} // 30 degree around Y
},
text: {
contents: `Boxes with different frictions`,
anchor: MRE.TextAnchorLocation.MiddleLeft,
height: .2
},
collider: {
geometry: { shape: MRE.ColliderType.Auto },
bounciness: 0.0, dynamicFriction: 0.1, staticFriction: 0.1
}
}
});
}

private spawnBox(root: MRE.Actor, width: number, height: number, radius = 0.1, killTimeout = 5000) {
const boxId = this.assets.createBoxMesh('box', 1.5 * radius, 1.8 * radius, 2.1 * radius).id;
// boxes for the slope and with the same dynamic and static friction
const friction = 0.7 * Math.random();
const box = MRE.Actor.Create(this.app.context, {
actor: {
parentId: root.id,
appearance: {
meshId: boxId,
materialId: this.boxMat.id
},
transform: {
local: {
position: {
x: -width / 2 + width * Math.random(),
y: height, z: -(-0.1 + 0.2 * Math.random())
}
}
},
rigidBody: {
mass: 3,
angularVelocity: {
x: 50 * Math.random() - 25.0, y: 50.0 * Math.random() - 25.0,
z: 50 * Math.random() - 25.0
},
velocity: { x: 0.0, y: 0.0, z: 0.0 },
constraints: [MRE.RigidBodyConstraints.None]
},
collider: {
geometry: { shape: MRE.ColliderType.Auto },
bounciness: 0.0, dynamicFriction: friction, staticFriction: friction
}
}
});

setTimeout(() => {
box.destroy();
}, killTimeout);
}
}
13 changes: 13 additions & 0 deletions packages/sdk/src/actor/physics/collider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ export enum CollisionLayer {
export interface ColliderLike {
enabled: boolean;
isTrigger: boolean;
bounciness: number;
staticFriction: number;
dynamicFriction: number;
layer: CollisionLayer;
geometry: ColliderGeometry;
eventSubscriptions: ColliderEventType[];
Expand All @@ -62,6 +65,9 @@ export class Collider implements ColliderLike {

public enabled = true;
public isTrigger = false;
public bounciness = 0.0;
public staticFriction = 0.0;
public dynamicFriction = 0.0;
public layer = CollisionLayer.Default;
public geometry: Readonly<ColliderGeometry>;

Expand Down Expand Up @@ -92,7 +98,11 @@ export class Collider implements ColliderLike {
if (from.geometry !== undefined) { this.geometry = from.geometry; }
if (from.enabled !== undefined) { this.enabled = from.enabled; }
if (from.isTrigger !== undefined) { this.isTrigger = from.isTrigger; }
if (from.bounciness !== undefined) { this.bounciness = from.bounciness; }
if (from.staticFriction !== undefined) {this.staticFriction = from.staticFriction; }
if (from.dynamicFriction !== undefined) {this.dynamicFriction = from.dynamicFriction; }
if (from.layer !== undefined) { this.layer = from.layer; }

} else {
throw new Error("Must provide a valid collider-like to initialize from.");
}
Expand Down Expand Up @@ -141,6 +151,9 @@ export class Collider implements ColliderLike {
return {
enabled: this.enabled,
isTrigger: this.isTrigger,
bounciness: this.bounciness,
staticFriction: this.staticFriction,
dynamicFriction: this.dynamicFriction,
layer: this.layer,
geometry: this.geometry,
eventSubscriptions: this.eventSubscriptions
Expand Down