Add gravity and forces.

This commit is contained in:
Davy Hélard
2024-11-04 16:32:58 +01:00
parent 5decafa778
commit b3febdcec7
2 changed files with 256 additions and 4 deletions

View File

@@ -54,6 +54,27 @@ module.exports = {
propertyName,
newValue
) {
console.log("updateProperty: " + propertyName);
if (propertyName === 'gravityX') {
const newValueAsNumber = parseFloat(newValue);
if (newValueAsNumber !== newValueAsNumber) return false;
sharedContent.getChild('gravityX').setDoubleValue(newValueAsNumber);
return true;
}
if (propertyName === 'gravityY') {
const newValueAsNumber = parseFloat(newValue);
if (newValueAsNumber !== newValueAsNumber) return false;
sharedContent.getChild('gravityY').setDoubleValue(newValueAsNumber);
return true;
}
if (propertyName === 'gravityZ') {
const newValueAsNumber = parseFloat(newValue);
if (newValueAsNumber !== newValueAsNumber) return false;
sharedContent.getChild('gravityZ').setDoubleValue(newValueAsNumber);
return true;
}
if (propertyName === 'worldScale') {
const newValueAsNumber = parseInt(newValue, 10);
@@ -70,6 +91,29 @@ module.exports = {
sharedData.getProperties = function (sharedContent) {
const sharedProperties = new gd.MapStringPropertyDescriptor();
sharedProperties
.getOrCreate('gravityX')
.setValue(
sharedContent.getChild('gravityX').getDoubleValue().toString(10)
)
.setType('Number')
.setMeasurementUnit(gd.MeasurementUnit.getNewton());
sharedProperties
.getOrCreate('gravityY')
.setValue(
sharedContent.getChild('gravityY').getDoubleValue().toString(10)
)
.setType('Number')
.setMeasurementUnit(gd.MeasurementUnit.getNewton());
sharedProperties
.getOrCreate('gravityZ')
.setValue(
sharedContent.getChild('gravityZ').getDoubleValue().toString(10)
)
.setType('Number')
.setMeasurementUnit(gd.MeasurementUnit.getNewton());
sharedProperties
.getOrCreate('worldScale')
.setValue(
@@ -80,6 +124,9 @@ module.exports = {
return sharedProperties;
};
sharedData.initializeContent = function (behaviorContent) {
behaviorContent.addChild('gravityX').setDoubleValue(0);
behaviorContent.addChild('gravityY').setDoubleValue(0);
behaviorContent.addChild('gravityZ').setDoubleValue(-9.8);
behaviorContent.addChild('worldScale').setDoubleValue(100);
};
@@ -105,6 +152,115 @@ module.exports = {
//.addIncludeFile('Extensions/Physics3DBehavior/jolt-physics.multithread.wasm-compat.js')
.setOpenFullEditorLabel(_('Edit shape and advanced settings'));
// Forces and impulses
aut
.addAction(
'ApplyForce',
_('Apply force'),
_(
'Apply a force to the object over time. It "accelerates" an object and must be used every frame during a time period.'
),
_('Apply a force of _PARAM2_ ; _PARAM3_ ; _PARAM4_ to _PARAM0_ at _PARAM5_ ; _PARAM6_ ; _PARAM7_'),
_('Forces & impulses'),
'res/physics32.png',
'res/physics32.png'
)
.addParameter('object', _('Object'), '', false)
.addParameter('behavior', _('Behavior'), 'Physics3DBehavior')
.addParameter('expression', _('X component (N)'))
.addParameter('expression', _('Y component (N)'))
.addParameter('expression', _('Z component (N)'))
.setParameterLongDescription(
_('A force is like an acceleration but depends on the mass.')
)
.addParameter('expression', _('Application point on X axis'))
.addParameter('expression', _('Application point on Y axis'))
.addParameter('expression', _('Application point on Z axis'))
.setParameterLongDescription(
_(
'Use `MassCenterX` and `MassCenterY` expressions to avoid any rotation.'
)
)
.getCodeExtraInformation()
.setFunctionName('applyForce');
aut
.addAction(
'ApplyForceAtCenter',
_('Apply force (at center)'),
_(
'Apply a force to the object over time. It "accelerates" an object and must be used every frame during a time period.'
),
_('Apply a force of _PARAM2_ ; _PARAM3_ ; _PARAM4_ at the center of _PARAM0_'),
_('Forces & impulses'),
'res/physics32.png',
'res/physics32.png'
)
.addParameter('object', _('Object'), '', false)
.addParameter('behavior', _('Behavior'), 'Physics3DBehavior')
.addParameter('expression', _('X component (N)'))
.addParameter('expression', _('Y component (N)'))
.addParameter('expression', _('Z component (N)'))
.setParameterLongDescription(
_('A force is like an acceleration but depends on the mass.')
)
.getCodeExtraInformation()
.setFunctionName('applyForceAtCenter');
aut
.addScopedAction(
'ApplyImpulse',
_('Apply impulse'),
_(
'Apply an impulse to the object. It instantly changes the speed, to give an initial speed for instance.'
),
_('Apply an impulse of _PARAM2_ ; _PARAM3_ ; _PARAM4_ to _PARAM0_ at _PARAM5_ ; _PARAM6_ ; _PARAM7_'),
_('Forces & impulses'),
'res/physics32.png',
'res/physics32.png'
)
.addParameter('object', _('Object'), '', false)
.addParameter('behavior', _('Behavior'), 'Physics3DBehavior')
.addParameter('expression', _('X component (N·s or kg·m·s⁻¹)'))
.addParameter('expression', _('Y component (N·s or kg·m·s⁻¹)'))
.addParameter('expression', _('Z component (N·s or kg·m·s⁻¹)'))
.setParameterLongDescription(
_('An impulse is like a speed addition but depends on the mass.')
)
.addParameter('expression', _('Application point on X axis'))
.addParameter('expression', _('Application point on Y axis'))
.addParameter('expression', _('Application point on Z axis'))
.setParameterLongDescription(
_(
'Use `MassCenterX`, `MassCenterY` and `MassCenterZ` expressions to avoid any rotation.'
)
)
.getCodeExtraInformation()
.setFunctionName('applyImpulse');
aut
.addScopedAction(
'ApplyImpulseAtCenter',
_('Apply impulse (at center)'),
_(
'Apply an impulse to the object. It instantly changes the speed, to give an initial speed for instance.'
),
_('Apply an impulse of _PARAM2_ ; _PARAM3_ ; _PARAM4_ at the center of _PARAM0_'),
_('Forces & impulses'),
'res/physics32.png',
'res/physics32.png'
)
.addParameter('object', _('Object'), '', false)
.addParameter('behavior', _('Behavior'), 'Physics3DBehavior')
.addParameter('expression', _('X component (N·s or kg·m·s⁻¹)'))
.addParameter('expression', _('Y component (N·s or kg·m·s⁻¹)'))
.addParameter('expression', _('Z component (N·s or kg·m·s⁻¹)'))
.setParameterLongDescription(
_('An impulse is like a speed addition but depends on the mass.')
)
.getCodeExtraInformation()
.setFunctionName('applyImpulseAtCenter');
return extension;
},

View File

@@ -45,7 +45,7 @@ namespace gdjs {
const LAYER_MOVING = 1;
const NUM_OBJECT_LAYERS = 2;
const setupCollisionFiltering = (settings) => {
const setupCollisionFiltering = (settings: Jolt.JoltSettings) => {
// Layer that objects can be in, determines which other objects it can collide with
// Typically you at least want to have 1 layer for moving bodies and 1 layer for static bodies, but you can have more
// layers if you want. E.g. you could have a layer for high detail collision (which is not used by the physics simulation
@@ -83,6 +83,9 @@ namespace gdjs {
};
export class Physics3DSharedData {
gravityX: float;
gravityY: float;
gravityZ: float;
worldScale: float;
worldInvScale: float;
@@ -100,6 +103,9 @@ namespace gdjs {
constructor(instanceContainer: gdjs.RuntimeInstanceContainer, sharedData) {
this._registeredBehaviors = new Set<Physics3DRuntimeBehavior>();
this.gravityX = sharedData.gravityX;
this.gravityY = sharedData.gravityY;
this.gravityZ = sharedData.gravityZ;
this.worldScale = sharedData.worldScale;
this.worldInvScale = 1 / this.worldScale;
@@ -109,6 +115,9 @@ namespace gdjs {
this.jolt = new Jolt.JoltInterface(settings);
Jolt.destroy(settings);
this.physicsSystem = this.jolt.GetPhysicsSystem();
this.physicsSystem.SetGravity(
new Jolt.Vec3(this.gravityX, this.gravityY, this.gravityZ)
);
this.bodyInterface = this.physicsSystem.GetBodyInterface();
}
@@ -281,9 +290,11 @@ namespace gdjs {
Jolt.EMotionType_Dynamic,
LAYER_MOVING
);
bodyCreationSettings.mFriction = 0.001;
this._body =
this._sharedData.bodyInterface.CreateBody(bodyCreationSettings);
const bodyInterface = this._sharedData.bodyInterface;
this._body = bodyInterface.CreateBody(bodyCreationSettings);
bodyInterface.AddBody(this._body.GetID(), Jolt.EActivation_Activate);
return true;
}
@@ -350,7 +361,10 @@ namespace gdjs {
this._objectOldRotationZ = this.owner3D.getAngle();
}
doStepPostEvents(instanceContainer: gdjs.RuntimeInstanceContainer) {}
doStepPostEvents(instanceContainer: gdjs.RuntimeInstanceContainer) {
// Reset world step to update next frame
this._sharedData.stepped = false;
}
onObjectHotReloaded() {
this.updateBodyFromObject();
@@ -396,6 +410,88 @@ namespace gdjs {
);
}
}
applyForce(
forceX: float,
forceY: float,
forceZ: float,
positionX: float,
positionY: float,
positionZ: float
): void {
// If there is no body, set a new one
if (this._body === null) {
if (!this.createBody()) return;
}
const body = this._body!;
this._sharedData.bodyInterface.AddForce(
body.GetID(),
new Jolt.Vec3(forceX, forceY, forceZ),
new Jolt.RVec3(
positionX * this._sharedData.worldInvScale,
positionY * this._sharedData.worldInvScale,
positionZ * this._sharedData.worldInvScale
),
Jolt.EActivation_Activate
);
}
applyForceAtCenter(forceX: float, forceY: float, forceZ: float): void {
// If there is no body, set a new one
if (this._body === null) {
if (!this.createBody()) return;
}
const body = this._body!;
this._sharedData.bodyInterface.AddForce(
body.GetID(),
new Jolt.Vec3(forceX, forceY, forceZ),
Jolt.EActivation_Activate
);
}
applyImpulse(
impulseX: float,
impulseY: float,
impulseZ: float,
positionX: float,
positionY: float,
positionZ: float
): void {
// If there is no body, set a new one
if (this._body === null) {
if (!this.createBody()) return;
}
const body = this._body!;
this._sharedData.bodyInterface.AddImpulse(
body.GetID(),
new Jolt.Vec3(impulseX, impulseY, impulseZ),
new Jolt.RVec3(
positionX * this._sharedData.worldInvScale,
positionY * this._sharedData.worldInvScale,
positionZ * this._sharedData.worldInvScale
)
);
}
applyImpulseAtCenter(
impulseX: float,
impulseY: float,
impulseZ: float
): void {
// If there is no body, set a new one
if (this._body === null) {
if (!this.createBody()) return;
}
const body = this._body!;
this._sharedData.bodyInterface.AddImpulse(
body.GetID(),
new Jolt.Vec3(impulseX, impulseY, impulseZ)
);
}
}
gdjs.registerBehavior(