Compare commits

...

78 Commits

Author SHA1 Message Date
Davy Hélard
e2c5c1be74 Fix velocity setters. 2024-12-12 18:37:46 +01:00
Davy Hélard
e53d1d830e Remove unused function. 2024-12-12 17:32:36 +01:00
Davy Hélard
f7625194f5 Fix the character rotation on moving platforms. 2024-12-11 22:37:39 +01:00
Davy Hélard
da2de649ab Fix angular velocity. 2024-12-11 20:57:37 +01:00
Davy Hélard
be6e05bfad Forgot to save a file. 2024-12-11 20:51:48 +01:00
Davy Hélard
ad6ee2342c Review changes. 2024-12-11 18:29:10 +01:00
Davy Hélard
8c840480b0 Keep the same alert identifier as Physics2. 2024-12-11 16:29:35 +01:00
Davy Hélard
92c1bc9199 Add some comments. 2024-12-11 15:26:00 +01:00
Davy Hélard
aaab5f5ae1 Make some attributes private. 2024-12-11 14:02:07 +01:00
Davy Hélard
dafa56d2f2 Format 2024-12-11 13:44:26 +01:00
Davy Hélard
a92a7ee3ce Fix the character position for Box3D. 2024-12-11 13:43:35 +01:00
Davy Hélard
2629755290 Add a property to bind object and forward angle. 2024-12-11 12:57:43 +01:00
Davy Hélard
ec6470bd72 Factorize the acceleration handling. 2024-12-10 17:19:17 +01:00
Davy Hélard
4615a6456a Fix controls handling. 2024-12-10 14:34:52 +01:00
Davy Hélard
1b1ea873ae Ass instructions for angular velocity. 2024-12-05 23:05:50 +01:00
Davy Hélard
81b3c69618 Fix multiplayer sync. 2024-12-05 15:25:37 +01:00
Davy Hélard
c2eb58360c Fix the character position after a size change. 2024-12-05 14:53:16 +01:00
Davy Hélard
e1159b3748 Remove the offset properties. 2024-12-05 11:16:14 +01:00
Davy Hélard
2022af743b Use a dedicated angle for the character direction instead of using the object angle directly. 2024-12-04 16:46:55 +01:00
Davy Hélard
7828970797 Offset the character according to the physics shape instead of the object dimensions. 2024-12-03 19:40:26 +01:00
Davy Hélard
289b001584 Use the object custom center. 2024-12-03 18:33:00 +01:00
Davy Hélard
b35f427451 Fix capsule size and size/mass update. 2024-12-03 13:27:01 +01:00
Davy Hélard
6edb7aaec9 Fix the floor following. 2024-12-03 11:20:31 +01:00
Davy Hélard
e8a4be338c Failed attempt to fit maxSlopeAngle. 2024-12-02 21:56:18 +01:00
Davy Hélard
1ebab8ba95 Fix the floor following. 2024-12-02 18:45:26 +01:00
Davy Hélard
ec37b03548 Clean up character code. 2024-12-02 16:03:00 +01:00
Davy Hélard
6c3ff254db Extract a BodyUpdater. 2024-12-02 16:03:00 +01:00
Davy Hélard
b3675cd3c6 Temporary fix character position synchronization. 2024-12-02 16:02:59 +01:00
Davy Hélard
76f70dfc36 Improve multiplayer sync 2024-12-02 16:02:59 +01:00
Davy Hélard
5ce9ec2283 Remove dead code. 2024-12-02 16:02:59 +01:00
Davy Hélard
32d70ff5b7 Add an icon for the character. 2024-12-02 16:02:59 +01:00
Davy Hélard
58fa20591c Move the icon. 2024-12-02 16:02:58 +01:00
Davy Hélard
df54f30221 Fix jump state. 2024-12-02 16:02:58 +01:00
Davy Hélard
6a109a7e44 Handle hot-reload. 2024-12-02 16:02:57 +01:00
Davy Hélard
ac4172ec33 Declare some instructions. 2024-12-02 16:02:57 +01:00
Davy Hélard
c15aeb6a82 Handle stick. 2024-12-02 16:02:57 +01:00
Davy Hélard
ccf5859596 Handle sideways speed. 2024-12-02 16:02:56 +01:00
Davy Hélard
b5f5bfa1c0 Fix jump sustain time. 2024-12-02 16:02:56 +01:00
Davy Hélard
bd473029e0 Declare character properties. 2024-12-02 16:02:55 +01:00
Davy Hélard
c77ac93c0b Fix bunny jumping. 2024-12-02 16:02:55 +01:00
Davy Hélard
72cb5a7f2c Add some getters and setters. 2024-12-02 16:02:54 +01:00
Davy Hélard
772a6980e1 Try to follow platforms that moves outside of the physics engine. 2024-12-02 16:02:54 +01:00
Davy Hélard
63f637c44f Clean up layer setup. 2024-12-02 16:02:54 +01:00
Davy Hélard
18c7eef5b2 Add a condition to check the current floor. 2024-12-02 16:02:53 +01:00
Davy Hélard
79b331d009 Fix collision. 2024-12-02 16:02:52 +01:00
Davy Hélard
06776447f2 Fix floor following 2024-12-02 16:02:52 +01:00
Davy Hélard
c1fe0a4e61 Fix position round trip. 2024-12-02 16:02:52 +01:00
Davy Hélard
d68920e84d Fix zone that can land. 2024-12-02 16:02:51 +01:00
Davy Hélard
79e868f1fe Fix character up axis. 2024-12-02 16:02:51 +01:00
Davy Hélard
2a556c9e4e WIP Jump 2024-12-02 16:02:50 +01:00
Davy Hélard
dfb98df8fb WIP walk 2024-12-02 16:02:49 +01:00
Davy Hélard
8bff97c586 WIP character 2024-12-02 16:02:49 +01:00
Davy Hélard
af0779d902 Fix velocity setters and thin shapes. 2024-12-02 16:02:49 +01:00
Davy Hélard
cdc9e0b85a Fix description. 2024-12-02 16:02:48 +01:00
Davy Hélard
ae32d09a09 Add a property for the shape orientation. 2024-12-02 16:02:48 +01:00
Davy Hélard
a8ed839003 Use a new icon. 2024-12-02 16:02:47 +01:00
Davy Hélard
bdbf6a1a3b Add getters and setters. 2024-12-02 16:02:47 +01:00
Davy Hélard
9a301b4737 Handle hot-reload. 2024-12-02 16:02:46 +01:00
Davy Hélard
6113769520 Forbid to use the behavior with 2D objects. 2024-12-02 16:02:46 +01:00
Davy Hélard
775c02a57e Add torque actions. 2024-12-02 16:02:45 +01:00
Davy Hélard
fb299d428a Fix library loading in browsers. 2024-12-02 16:02:45 +01:00
Davy Hélard
acaee8e728 Handle collision layers. 2024-12-02 16:02:44 +01:00
Davy Hélard
4230ef7780 Add the bullet property. 2024-12-02 16:02:44 +01:00
Davy Hélard
68b45e301e Put back the convex radius. 2024-12-02 16:02:43 +01:00
Davy Hélard
e7fddec3ad Fix a memory leak. 2024-12-02 16:02:43 +01:00
Davy Hélard
bf3c4ba2e8 Add collision conditions. 2024-12-02 16:02:42 +01:00
Davy Hélard
9742310d1d Add properties for custom shape size. 2024-12-02 16:02:42 +01:00
Davy Hélard
540b507895 Handle object deletion. 2024-12-02 16:02:41 +01:00
Davy Hélard
91fdf7009f Handle some shapes. 2024-12-02 16:02:41 +01:00
Davy Hélard
582371f954 Add density property. 2024-12-02 16:02:40 +01:00
Davy Hélard
a9fe0bb661 Fix size changes. 2024-12-02 16:02:39 +01:00
Davy Hélard
259b8eefe7 Add bodyType property. 2024-12-02 16:02:38 +01:00
Davy Hélard
a3428e92fb Update object size. 2024-12-02 16:02:38 +01:00
Davy Hélard
38df69378b Add some properties. 2024-12-02 16:02:37 +01:00
Davy Hélard
74269731db Avoid allocations. 2024-12-02 16:02:37 +01:00
Davy Hélard
b3febdcec7 Add gravity and forces. 2024-12-02 16:02:36 +01:00
Davy Hélard
5decafa778 Synchronize positions. 2024-12-02 16:02:36 +01:00
Davy Hélard
96b053f699 Add skeletons. 2024-12-02 16:02:35 +01:00
14 changed files with 11175 additions and 21 deletions

View File

@@ -695,7 +695,7 @@ module.exports = {
.addCondition(
'IsDynamic',
_('Is dynamic'),
_('Test if an object is dynamic.'),
_('Check if an object is dynamic.'),
_('_PARAM0_ is dynamic'),
_('Dynamics'),
'res/physics32.png',
@@ -727,7 +727,7 @@ module.exports = {
.addCondition(
'IsStatic',
_('Is static'),
_('Test if an object is static.'),
_('Check if an object is static.'),
_('_PARAM0_ is static'),
_('Dynamics'),
'res/physics32.png',
@@ -759,7 +759,7 @@ module.exports = {
.addCondition(
'IsKinematic',
_('Is kinematic'),
_('Test if an object is kinematic.'),
_('Check if an object is kinematic.'),
_('_PARAM0_ is kinematic'),
_('Dynamics'),
'res/physics32.png',
@@ -790,9 +790,9 @@ module.exports = {
aut
.addCondition(
'IsBullet',
_('Is treat as bullet'),
_('Test if an object is being treat as a bullet.'),
_('_PARAM0_ is bullet'),
_('Is treated as a bullet'),
_('Check if the object is being treated as a bullet.'),
_('_PARAM0_ is treated as a bullet'),
_('Dynamics'),
'res/physics32.png',
'res/physics32.png'
@@ -825,7 +825,7 @@ module.exports = {
.addCondition(
'HasFixedRotation',
_('Has fixed rotation'),
_('Test if an object has fixed rotation.'),
_('Check if an object has fixed rotation.'),
_('_PARAM0_ has fixed rotation'),
_('Dynamics'),
'res/physics32.png',
@@ -859,7 +859,7 @@ module.exports = {
.addCondition(
'IsSleepingAllowed',
_('Is sleeping allowed'),
_('Test if an object can sleep.'),
_('Check if an object can sleep.'),
_('_PARAM0_ can sleep'),
_('Dynamics'),
'res/physics32.png',
@@ -898,7 +898,7 @@ module.exports = {
.addCondition(
'IsSleeping',
_('Is sleeping'),
_('Test if an object is sleeping.'),
_('Check if an object is sleeping.'),
_('_PARAM0_ is sleeping'),
_('Dynamics'),
'res/physics32.png',
@@ -1267,7 +1267,7 @@ module.exports = {
.addCondition(
'LayerEnabled',
_('Layer enabled'),
_('Test if an object has a specific layer enabled.'),
_('Check if an object has a specific layer enabled.'),
_('_PARAM0_ has layer _PARAM2_ enabled'),
_('Filtering'),
'res/physics32.png',
@@ -1303,7 +1303,7 @@ module.exports = {
.addCondition(
'MaskEnabled',
_('Mask enabled'),
_('Test if an object has a specific mask enabled.'),
_('Check if an object has a specific mask enabled.'),
_('_PARAM0_ has mask _PARAM2_ enabled'),
_('Filtering'),
'res/physics32.png',
@@ -1897,7 +1897,7 @@ module.exports = {
.addCondition(
'JointFirstObject',
_('Joint first object'),
_('Test if an object is the first object on a joint.'),
_('Check if an object is the first object on a joint.'),
_('_PARAM0_ is the first object for joint _PARAM2_'),
_('Joints'),
'res/physics32.png',
@@ -1913,7 +1913,7 @@ module.exports = {
.addCondition(
'JointSecondObject',
_('Joint second object'),
_('Test if an object is the second object on a joint.'),
_('Check if an object is the second object on a joint.'),
_('_PARAM0_ is the second object for joint _PARAM2_'),
_('Joints'),
'res/physics32.png',
@@ -2382,7 +2382,7 @@ module.exports = {
.addCondition(
'RevoluteJointLimitsEnabled',
_('Revolute joint limits enabled'),
_('Test if a revolute joint limits are enabled.'),
_('Check if a revolute joint limits are enabled.'),
_('Limits for revolute joint _PARAM2_ are enabled'),
_('Joints/Revolute'),
'JsPlatform/Extensions/revolute_joint24.png',
@@ -2461,7 +2461,7 @@ module.exports = {
.addCondition(
'RevoluteJointMotorEnabled',
_('Revolute joint motor enabled'),
_('Test if a revolute joint motor is enabled.'),
_('Check if a revolute joint motor is enabled.'),
_('Motor of revolute joint _PARAM2_ is enabled'),
_('Joints/Revolute'),
'JsPlatform/Extensions/revolute_joint24.png',
@@ -2700,7 +2700,7 @@ module.exports = {
.addCondition(
'PrismaticJointLimitsEnabled',
_('Prismatic joint limits enabled'),
_('Test if a prismatic joint limits are enabled.'),
_('Check if a prismatic joint limits are enabled.'),
_('Limits for prismatic joint _PARAM2_ are enabled'),
_('Joints/Prismatic'),
'JsPlatform/Extensions/prismatic_joint24.png',
@@ -2779,7 +2779,7 @@ module.exports = {
.addCondition(
'PrismaticJointMotorEnabled',
_('Prismatic joint motor enabled'),
_('Test if a prismatic joint motor is enabled.'),
_('Check if a prismatic joint motor is enabled.'),
_('Motor for prismatic joint _PARAM2_ is enabled'),
_('Joints/Prismatic'),
'JsPlatform/Extensions/prismatic_joint24.png',
@@ -3459,7 +3459,7 @@ module.exports = {
.addCondition(
'WheelJointMotorEnabled',
_('Wheel joint motor enabled'),
_('Test if a wheel joint motor is enabled.'),
_('Check if a wheel joint motor is enabled.'),
_('Motor for wheel joint _PARAM2_ is enabled'),
_('Joints/Wheel'),
'JsPlatform/Extensions/wheel_joint24.png',
@@ -4203,7 +4203,7 @@ module.exports = {
.getCodeExtraInformation()
.addIncludeFile('Extensions/Physics2Behavior/physics2tools.js')
.addIncludeFile('Extensions/Physics2Behavior/physics2runtimebehavior.js')
.setFunctionName('gdjs.physics2.objectsCollide');
.setFunctionName('gdjs.physics2.areObjectsColliding');
extension
.addCondition(

View File

@@ -1,6 +1,6 @@
namespace gdjs {
export namespace physics2 {
export const objectsCollide = function (
export const areObjectsColliding = function (
objectsLists1: Hashtable<Array<gdjs.RuntimeObject>>,
behaviorName: string,
objectsLists2: Hashtable<Array<gdjs.RuntimeObject>>,

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,90 @@
namespace gdjs {
export namespace physics3d {
export const areObjectsColliding = function (
objectsLists1: Hashtable<Array<gdjs.RuntimeObject>>,
behaviorName: string,
objectsLists2: Hashtable<Array<gdjs.RuntimeObject>>,
behaviorName2: string,
inverted: boolean
) {
return gdjs.evtTools.object.twoListsTest(
gdjs.Physics3DRuntimeBehavior.areObjectsColliding,
objectsLists1,
objectsLists2,
inverted,
behaviorName
);
};
export const haveObjectsStartedColliding = function (
objectsLists1: Hashtable<Array<gdjs.RuntimeObject>>,
behaviorName: string,
objectsLists2: Hashtable<Array<gdjs.RuntimeObject>>,
behaviorName2: string,
inverted: boolean
) {
return gdjs.evtTools.object.twoListsTest(
gdjs.Physics3DRuntimeBehavior.hasCollisionStartedBetween,
objectsLists1,
objectsLists2,
inverted,
behaviorName
);
};
export const haveObjectsStoppedColliding = function (
objectsLists1: Hashtable<Array<gdjs.RuntimeObject>>,
behaviorName: string,
objectsLists2: Hashtable<Array<gdjs.RuntimeObject>>,
behaviorName2: string,
inverted: boolean
) {
return gdjs.evtTools.object.twoListsTest(
gdjs.Physics3DRuntimeBehavior.hasCollisionStoppedBetween,
objectsLists1,
objectsLists2,
inverted,
behaviorName
);
};
type BehaviorNamePair = { character: string; physics: string };
const isOnPlatformAdapter = (
characterObject: gdjs.RuntimeObject,
physicsObject: gdjs.RuntimeObject,
behaviorNamePair: BehaviorNamePair
): boolean => {
const characterBehavior = characterObject.getBehavior(
behaviorNamePair.character
) as gdjs.PhysicsCharacter3DRuntimeBehavior;
const physicsBehavior = physicsObject.getBehavior(
behaviorNamePair.physics
) as gdjs.Physics3DRuntimeBehavior;
if (!characterBehavior || !physicsBehavior) {
return false;
}
return characterBehavior.isOnFloorObject(physicsBehavior);
};
const behaviorNamePair: BehaviorNamePair = { character: '', physics: '' };
export const isOnPlatform = (
characterObjectsLists: Hashtable<Array<gdjs.RuntimeObject>>,
characterBehaviorName: string,
physicsObjectsLists: Hashtable<Array<gdjs.RuntimeObject>>,
physicsBehaviorName: string,
inverted: boolean
) => {
behaviorNamePair.character = characterBehaviorName;
behaviorNamePair.physics = physicsBehaviorName;
return gdjs.evtTools.object.twoListsTest(
isOnPlatformAdapter,
characterObjectsLists,
physicsObjectsLists,
inverted,
behaviorNamePair
);
};
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1 @@
describe('Physics3DRuntimeBehavior', () => {});

View File

@@ -231,9 +231,13 @@ namespace gdjs {
...super.getNetworkSyncData(),
props: {
cs: this._currentSpeed,
// TODO Try to remove these 3 fields from the synch
// They are reset every frame and are not part of the state.
rdx: this._requestedDeltaX,
rdy: this._requestedDeltaY,
ldy: this._lastDeltaY,
cfs: this._currentFallSpeed,
cj: this._canJump,
ldl: this._lastDirectionIsLeft,

View File

@@ -30,7 +30,12 @@
</head>
<body>
<script type="module">
// import latest
import initJolt from 'https://www.unpkg.com/jolt-physics/dist/jolt-physics.wasm-compat.js';
//import initJolt from './Extensions/Physics3DBehavior/jolt-physics.multithread.wasm-compat.js';
globalThis.initializeJoltPhysics = initJolt;
</script>
<!-- GDJS_CUSTOM_HTML -->
<script>

View File

@@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="14" height="14" version="1.1" viewBox="0 0 14 14" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><path d="m7 0-6 3.5v7l6 3.5 6-3.5v-7l-6-3.5z" fill="#2e388a"/><g transform="translate(-.0405 .026)" fill="none" stroke="#53a6da" stroke-width=".7"><path d="m8.294 9.112c-1.291 0.7556-2.601 1.165-3.664 1.229-1.085 0.0656-1.803-0.2277-2.095-0.7272-0.2924-0.4996-0.1966-1.269 0.3921-2.183 0.5768-0.8956 1.575-1.837 2.866-2.593 1.291-0.7556 2.601-1.165 3.664-1.229 1.085-0.06552 1.803 0.2277 2.095 0.7272s0.1964 1.269-0.3862 2.174-1.581 1.846-2.872 2.602z"/><path d="m5.787 9.112c1.291 0.7556 2.601 1.165 3.664 1.229 1.085 0.0656 1.803-0.2277 2.095-0.7272 0.2924-0.4996 0.1966-1.269-0.3921-2.183-0.5768-0.8956-1.575-1.837-2.866-2.593-1.291-0.7556-2.601-1.165-3.664-1.229-1.085-0.06552-1.803 0.2277-2.095 0.7272s-0.1964 1.269 0.3862 2.174 1.581 1.846 2.872 2.602z"/><path d="m7.038 1.75c-0.5788 0-1.194 0.4711-1.686 1.441-0.4817 0.9502-0.7898 2.287-0.7898 3.783s0.3081 2.833 0.7898 3.783c0.4916 0.9697 1.107 1.441 1.686 1.441s1.194-0.4712 1.686-1.441c0.4817-0.9502 0.7898-2.287 0.7898-3.783s-0.3081-2.833-0.7898-3.783c-0.4916-0.9698-1.107-1.441-1.686-1.441z"/></g><path d="m7 8c0.5524 0 1-0.4478 1-1 0-0.5524-0.4478-1-1-1s-1 0.4478-1 1c0 0.5524 0.4478 1 1 1z" fill="#fff" stroke-width=".6439"/></svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="14" height="14" version="1.1" viewBox="0 0 14 14" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><path d="m7 0-6 3.5v7l6 3.5 6-3.5v-7l-6-3.5z" fill="#2e388a"/><g fill="#27aae1" stroke-width=".7"><path d="m9.1 3.801v1.398h-0.6992-2.801-2.1v1.4 1.4h1.4v-1.4h0.6992v2.801h-2.1v1.4h2.1 1.4v-1.4h1.4 0.6992v1.4h1.4v-1.4-1.4h-2.1v-1.4h2.1v-1.4-1.398h-1.4z"/><path d="m7 5.2c0.7732 0 1.4-0.6268 1.4-1.4s-0.6268-1.4-1.4-1.4-1.4 0.6268-1.4 1.4 0.6268 1.4 1.4 1.4z"/></g></svg>

After

Width:  |  Height:  |  Size: 528 B

View File

@@ -1,6 +1,7 @@
// @flow
import BehaviorPropertiesEditor from './Editors/BehaviorPropertiesEditor';
import Physics2Editor from './Editors/Physics2Editor';
import Physics3DEditor from './Editors/Physics3DEditor';
/**
* A service returning editor components for each behavior type.
@@ -16,6 +17,9 @@ const BehaviorsEditorService = {
'Physics2::Physics2Behavior': {
component: Physics2Editor,
},
'Physics3D::Physics3DBehavior': {
component: Physics3DEditor,
},
},
};

View File

@@ -0,0 +1,402 @@
// @flow
import { t } from '@lingui/macro';
import { Trans } from '@lingui/macro';
import * as React from 'react';
import { Line, Column, Spacer } from '../../../UI/Grid';
import Checkbox from '../../../UI/Checkbox';
import SelectField from '../../../UI/SelectField';
import SelectOption from '../../../UI/SelectOption';
import SemiControlledTextField from '../../../UI/SemiControlledTextField';
import { getMeasurementUnitShortLabel } from '../../../PropertiesEditor/PropertiesMapToSchema';
import MeasurementUnitDocumentation from '../../../PropertiesEditor/MeasurementUnitDocumentation';
import { type BehaviorEditorProps } from '../BehaviorEditorProps.flow';
import Text from '../../../UI/Text';
import DismissableAlertMessage from '../../../UI/DismissableAlertMessage';
import { ResponsiveLineStackLayout } from '../../../UI/Layout';
import useForceUpdate from '../../../Utils/UseForceUpdate';
import Button from '@material-ui/core/Button';
import ButtonGroup from '@material-ui/core/ButtonGroup';
import InputAdornment from '@material-ui/core/InputAdornment';
import Tooltip from '@material-ui/core/Tooltip';
type Props = BehaviorEditorProps;
const NumericProperty = (props: {|
id?: string,
properties: gdMapStringPropertyDescriptor,
propertyName: string,
step: number,
onUpdate: (newValue: string) => void,
|}) => {
const { properties, propertyName, step, onUpdate, id } = props;
const property = properties.get(propertyName);
return (
<SemiControlledTextField
id={id}
fullWidth
value={property.getValue()}
key={propertyName}
floatingLabelText={property.getLabel()}
step={step}
onChange={onUpdate}
type="number"
endAdornment={<UnitAdornment property={property} />}
/>
);
};
const UnitAdornment = (props: {| property: gdPropertyDescriptor |}) => {
const { property } = props;
const measurementUnit = property.getMeasurementUnit();
return (
<Tooltip
title={
<MeasurementUnitDocumentation
label={measurementUnit.getLabel()}
description={measurementUnit.getDescription()}
elementsWithWords={measurementUnit.getElementsWithWords()}
/>
}
>
<InputAdornment position="end">
{getMeasurementUnitShortLabel(measurementUnit)}
</InputAdornment>
</Tooltip>
);
};
const BitGroupEditor = (props: {|
bits: Array<boolean>,
onChange: (index: number, value: boolean) => void,
firstIndex: number,
disabled: boolean,
|}) => {
return (
<div style={{ overflowX: 'auto', flex: 1 }}>
<ButtonGroup disableElevation fullWidth disabled={props.disabled}>
{props.bits.map((bit, index) => (
<Button
key={props.firstIndex + index}
variant={bit ? 'contained' : 'outlined'}
color={bit ? 'primary' : 'default'}
onClick={() => props.onChange(props.firstIndex + index, !bit)}
>
{props.firstIndex + index + 1}
</Button>
))}
</ButtonGroup>
</div>
);
};
const isBitEnabled = (bitsValue: number, pos: number) => {
return !!(bitsValue & (1 << pos));
};
const enableBit = (bitsValue: number, pos: number, enable: boolean) => {
if (enable) bitsValue |= 1 << pos;
else bitsValue &= ~(1 << pos);
return bitsValue;
};
const Physics3DEditor = (props: Props) => {
const { behavior, onBehaviorUpdated } = props;
const forceUpdate = useForceUpdate();
const updateBehaviorProperty = React.useCallback(
(property, value) => {
behavior.updateProperty(property, value);
forceUpdate();
onBehaviorUpdated();
},
[behavior, forceUpdate, onBehaviorUpdated]
);
const properties = behavior.getProperties();
const staticBits = Array(4).fill(null);
const dynamicBits = Array(4).fill(null);
const shape = properties.get('shape').getValue();
const layersValues = parseInt(properties.get('layers').getValue(), 10);
const masksValues = parseInt(properties.get('masks').getValue(), 10);
const isStatic = properties.get('bodyType').getValue() === 'Static';
return (
<Column
expand
// Avoid overflow on small screens
noOverflowParent
>
<Line>
<SelectField
id="physics3d-parameter-body-type"
key={'bodyType'}
fullWidth
floatingLabelText={properties.get('bodyType').getLabel()}
value={properties.get('bodyType').getValue()}
onChange={(e, i, newValue: string) =>
updateBehaviorProperty('bodyType', newValue)
}
>
{[
<SelectOption
key={'dynamic'}
value={'Dynamic'}
label={t`Dynamic`}
/>,
<SelectOption key={'static'} value={'Static'} label={t`Static`} />,
<SelectOption
key={'kinematic'}
value={'Kinematic'}
label={t`Kinematic`}
/>,
]}
</SelectField>
</Line>
<ResponsiveLineStackLayout>
<Checkbox
label={properties.get('bullet').getLabel()}
checked={properties.get('bullet').getValue() === 'true'}
onCheck={(e, checked) =>
updateBehaviorProperty('bullet', checked ? '1' : '0')
}
/>
<Checkbox
label={properties.get('fixedRotation').getLabel()}
checked={properties.get('fixedRotation').getValue() === 'true'}
onCheck={(e, checked) =>
updateBehaviorProperty('fixedRotation', checked ? '1' : '0')
}
/>
</ResponsiveLineStackLayout>
<Line>
<DismissableAlertMessage
identifier="physics2-shape-collisions"
kind="info"
>
<Trans>
The shape used in the Physics behavior is independent from the
collision mask of the object. Be sure to use the "Collision"
condition provided by the Physics behavior in the events. The usual
"Collision" condition won't take into account the shape that you've
set up here.
</Trans>
</DismissableAlertMessage>
</Line>
<ResponsiveLineStackLayout>
<SelectField
id="physics3d-parameter-shape"
fullWidth
floatingLabelText={properties.get('shape').getLabel()}
value={properties.get('shape').getValue()}
onChange={(e, i, newValue: string) =>
updateBehaviorProperty('shape', newValue)
}
>
<SelectOption key={'sphere'} value={'Sphere'} label={t`Sphere`} />
<SelectOption key={'box'} value={'Box'} label={t`Box`} />
<SelectOption key={'capsule'} value={'Capsule'} label={t`Capsule`} />
<SelectOption
key={'cylinder'}
value={'Cylinder'}
label={t`Cylinder`}
/>
</SelectField>
<SelectField
id="physics3d-parameter-shape-orientation"
fullWidth
floatingLabelText={properties.get('shapeOrientation').getLabel()}
value={properties.get('shapeOrientation').getValue()}
onChange={(e, i, newValue: string) =>
updateBehaviorProperty('shapeOrientation', newValue)
}
disabled={
properties.get('shape').getValue() === 'Sphere' ||
properties.get('shape').getValue() === 'Box'
}
>
<SelectOption key={'shape-orientation-z'} value={'Z'} label={t`Z`} />
<SelectOption key={'shape-orientation-y'} value={'Y'} label={t`Y`} />
<SelectOption key={'shape-orientation-x'} value={'X'} label={t`X`} />
</SelectField>
</ResponsiveLineStackLayout>
<ResponsiveLineStackLayout>
<SemiControlledTextField
fullWidth
value={properties.get('shapeDimensionA').getValue()}
key={'shapeDimensionA'}
floatingLabelText={shape === 'Box' ? 'Width' : 'Radius'}
min={0}
onChange={newValue =>
updateBehaviorProperty('shapeDimensionA', newValue)
}
type="number"
endAdornment={
<UnitAdornment property={properties.get('shapeDimensionA')} />
}
/>
{shape !== 'Sphere' && (
<SemiControlledTextField
fullWidth
value={properties.get('shapeDimensionB').getValue()}
key={'shapeDimensionB'}
floatingLabelText={shape === 'Box' ? 'Width' : 'Depth'}
min={0}
onChange={newValue =>
updateBehaviorProperty('shapeDimensionB', newValue)
}
type="number"
endAdornment={
<UnitAdornment property={properties.get('shapeDimensionB')} />
}
/>
)}
{shape === 'Box' && (
<SemiControlledTextField
fullWidth
value={properties.get('shapeDimensionC').getValue()}
key={'shapeDimensionC'}
floatingLabelText={'Depth'}
min={0}
onChange={newValue =>
updateBehaviorProperty('shapeDimensionC', newValue)
}
type="number"
endAdornment={
<UnitAdornment property={properties.get('shapeDimensionC')} />
}
/>
)}
</ResponsiveLineStackLayout>
<ResponsiveLineStackLayout>
<NumericProperty
id="physics3d-parameter-density"
properties={properties}
propertyName={'density'}
step={0.1}
onUpdate={newValue =>
updateBehaviorProperty(
'density',
parseFloat(newValue) > 0 ? newValue : '0'
)
}
/>
<NumericProperty
properties={properties}
propertyName={'gravityScale'}
step={0.1}
onUpdate={newValue =>
updateBehaviorProperty('gravityScale', newValue)
}
/>
</ResponsiveLineStackLayout>
<ResponsiveLineStackLayout>
<NumericProperty
properties={properties}
propertyName={'friction'}
step={0.1}
onUpdate={newValue =>
updateBehaviorProperty(
'friction',
parseFloat(newValue) > 0 ? newValue : '0'
)
}
/>
<NumericProperty
properties={properties}
propertyName={'restitution'}
step={0.1}
onUpdate={newValue =>
updateBehaviorProperty(
'restitution',
parseFloat(newValue) > 0 ? newValue : '0'
)
}
/>
</ResponsiveLineStackLayout>
<ResponsiveLineStackLayout>
<NumericProperty
properties={properties}
propertyName={'linearDamping'}
step={0.05}
onUpdate={newValue =>
updateBehaviorProperty('linearDamping', newValue)
}
/>
<NumericProperty
id="physics3d-parameter-angular-damping"
properties={properties}
propertyName={'angularDamping'}
step={0.05}
onUpdate={newValue =>
updateBehaviorProperty('angularDamping', newValue)
}
/>
</ResponsiveLineStackLayout>
<Line>
<Text style={{ marginRight: 10 }}>
{properties.get('layers').getLabel()}
</Text>
<BitGroupEditor
key={'static-layers'}
firstIndex={0}
bits={staticBits.map(
(_, index) => isBitEnabled(layersValues, index) && isStatic
)}
onChange={(index, value) => {
const newValue = enableBit(layersValues, index, value);
updateBehaviorProperty('layers', newValue.toString(10));
}}
disabled={!isStatic}
/>
<Spacer />
<BitGroupEditor
key={'dynamic-layers'}
firstIndex={4}
bits={dynamicBits.map(
(_, index) => isBitEnabled(layersValues, index + 4) && !isStatic
)}
onChange={(index, value) => {
const newValue = enableBit(layersValues, index, value);
updateBehaviorProperty('layers', newValue.toString(10));
}}
disabled={isStatic}
/>
</Line>
<Line>
<Text style={{ marginRight: 10 }}>
{properties.get('masks').getLabel()}
</Text>
<BitGroupEditor
key={'static-mask'}
firstIndex={0}
bits={staticBits.map(
(_, index) => isBitEnabled(masksValues, index) || isStatic
)}
onChange={(index, value) => {
const newValue = enableBit(masksValues, index, value);
updateBehaviorProperty('masks', newValue.toString(10));
}}
disabled={isStatic}
/>
<Spacer />
<BitGroupEditor
key={'dynamic-mask'}
firstIndex={4}
bits={dynamicBits.map(
(_, index) => isBitEnabled(masksValues, index + 4) || isStatic
)}
onChange={(index, value) => {
const newValue = enableBit(masksValues, index, value);
updateBehaviorProperty('masks', newValue.toString(10));
}}
disabled={isStatic}
/>
</Line>
</Column>
);
};
export default Physics3DEditor;