mirror of
https://github.com/4ian/GDevelop.git
synced 2025-10-15 10:19:04 +00:00
Allow 3D physics characters to push each other (#7292)
This commit is contained in:
@@ -1551,6 +1551,13 @@ module.exports = {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (propertyName === 'canBePushed') {
|
||||
behaviorContent
|
||||
.getChild('canBePushed')
|
||||
.setBoolValue(newValue === '1');
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
behavior.getProperties = function (behaviorContent) {
|
||||
@@ -1745,6 +1752,22 @@ module.exports = {
|
||||
.setAdvanced(true)
|
||||
.setQuickCustomizationVisibility(gd.QuickCustomization.Hidden);
|
||||
|
||||
if (!behaviorContent.hasChild('canBePushed')) {
|
||||
behaviorContent.addChild('canBePushed').setBoolValue(true);
|
||||
}
|
||||
behaviorProperties
|
||||
.getOrCreate('canBePushed')
|
||||
.setLabel('Can be pushed by other characters')
|
||||
.setGroup(_('Walk'))
|
||||
.setType('Boolean')
|
||||
.setValue(
|
||||
behaviorContent.getChild('canBePushed').getBoolValue()
|
||||
? 'true'
|
||||
: 'false'
|
||||
)
|
||||
.setAdvanced(true)
|
||||
.setQuickCustomizationVisibility(gd.QuickCustomization.Hidden);
|
||||
|
||||
return behaviorProperties;
|
||||
};
|
||||
|
||||
@@ -1765,6 +1788,7 @@ module.exports = {
|
||||
behaviorContent
|
||||
.addChild('shouldBindObjectAndForwardAngle')
|
||||
.setBoolValue(true);
|
||||
behaviorContent.addChild('canBePushed').setBoolValue(true);
|
||||
};
|
||||
|
||||
const aut = extension
|
||||
|
@@ -807,15 +807,25 @@ namespace gdjs {
|
||||
*/
|
||||
getBodyLayer(): number {
|
||||
return Jolt.ObjectLayerPairFilterMask.prototype.sGetObjectLayer(
|
||||
// Make sure objects don't register in the wrong layer group.
|
||||
this.isStatic()
|
||||
? this.layers & gdjs.Physics3DSharedData.staticLayersMask
|
||||
: this.layers & gdjs.Physics3DSharedData.dynamicLayersMask,
|
||||
// Static objects accept all collisions as it's the mask of dynamic objects that matters.
|
||||
this.isStatic() ? gdjs.Physics3DSharedData.allLayersMask : this.masks
|
||||
this.getLayersAccordingToBodyType(),
|
||||
this.getMasksAccordingToBodyType()
|
||||
);
|
||||
}
|
||||
|
||||
private getLayersAccordingToBodyType(): integer {
|
||||
// Make sure objects don't register in the wrong layer group.
|
||||
return this.isStatic()
|
||||
? this.layers & gdjs.Physics3DSharedData.staticLayersMask
|
||||
: this.layers & gdjs.Physics3DSharedData.dynamicLayersMask;
|
||||
}
|
||||
|
||||
private getMasksAccordingToBodyType(): integer {
|
||||
// Static objects accept all collisions as it's the mask of dynamic objects that matters.
|
||||
return this.isStatic()
|
||||
? gdjs.Physics3DSharedData.allLayersMask
|
||||
: this.masks;
|
||||
}
|
||||
|
||||
doStepPreEvents(instanceContainer: gdjs.RuntimeInstanceContainer) {
|
||||
// Step the world if not done this frame yet.
|
||||
// Don't step at the first frame to allow events to handle overlapping objects.
|
||||
@@ -1689,6 +1699,14 @@ namespace gdjs {
|
||||
}
|
||||
}
|
||||
|
||||
canCollideAgainst(otherBehavior: gdjs.Physics3DRuntimeBehavior): boolean {
|
||||
return (
|
||||
(this.getMasksAccordingToBodyType() &
|
||||
otherBehavior.getLayersAccordingToBodyType()) !==
|
||||
0
|
||||
);
|
||||
}
|
||||
|
||||
static areObjectsColliding(
|
||||
object1: gdjs.RuntimeObject,
|
||||
object2: gdjs.RuntimeObject,
|
||||
|
@@ -72,6 +72,7 @@ namespace gdjs {
|
||||
private _jumpSpeed: float;
|
||||
private _jumpSustainTime: float;
|
||||
private _stairHeightMax: float;
|
||||
_canBePushed: boolean;
|
||||
|
||||
private _hasPressedForwardKey: boolean = false;
|
||||
private _hasPressedBackwardKey: boolean = false;
|
||||
@@ -145,6 +146,10 @@ namespace gdjs {
|
||||
behaviorData.stairHeightMax === undefined
|
||||
? 20
|
||||
: behaviorData.stairHeightMax;
|
||||
this._canBePushed =
|
||||
behaviorData.canBePushed === undefined
|
||||
? true
|
||||
: behaviorData.canBePushed;
|
||||
}
|
||||
|
||||
private getVec3(x: float, y: float, z: float): Jolt.Vec3 {
|
||||
@@ -1324,6 +1329,8 @@ namespace gdjs {
|
||||
export namespace PhysicsCharacter3DRuntimeBehavior {
|
||||
export class CharacterBodyUpdater {
|
||||
characterBehavior: gdjs.PhysicsCharacter3DRuntimeBehavior;
|
||||
/** Handle collisions between characters that can push each other. */
|
||||
static characterVsCharacterCollision: Jolt.CharacterVsCharacterCollisionSimple | null = null;
|
||||
|
||||
constructor(characterBehavior: gdjs.PhysicsCharacter3DRuntimeBehavior) {
|
||||
this.characterBehavior = characterBehavior;
|
||||
@@ -1336,7 +1343,13 @@ namespace gdjs {
|
||||
const shape = behavior.createShape();
|
||||
|
||||
const settings = new Jolt.CharacterVirtualSettings();
|
||||
settings.mInnerBodyLayer = behavior.getBodyLayer();
|
||||
// Characters innerBody are Kinematic body, they don't allow other
|
||||
// characters to push them.
|
||||
// The layer 0 doesn't allow any collision as masking them always result to 0.
|
||||
// This allows CharacterVsCharacterCollisionSimple to handle the collisions.
|
||||
settings.mInnerBodyLayer = this.characterBehavior._canBePushed
|
||||
? 0
|
||||
: behavior.getBodyLayer();
|
||||
settings.mInnerBodyShape = shape;
|
||||
settings.mMass = shape.GetMassProperties().get_mMass();
|
||||
settings.mMaxSlopeAngle = gdjs.toRad(_slopeMaxAngle);
|
||||
@@ -1376,6 +1389,106 @@ namespace gdjs {
|
||||
.GetBodyLockInterface()
|
||||
.TryGetBody(character.GetInnerBodyID());
|
||||
this.characterBehavior.character = character;
|
||||
|
||||
if (this.characterBehavior._canBePushed) {
|
||||
// CharacterVsCharacterCollisionSimple handle characters pushing each other.
|
||||
let characterVsCharacterCollision =
|
||||
CharacterBodyUpdater.characterVsCharacterCollision;
|
||||
if (!characterVsCharacterCollision) {
|
||||
characterVsCharacterCollision = new Jolt.CharacterVsCharacterCollisionSimple();
|
||||
CharacterBodyUpdater.characterVsCharacterCollision = characterVsCharacterCollision;
|
||||
}
|
||||
characterVsCharacterCollision.Add(character);
|
||||
character.SetCharacterVsCharacterCollision(
|
||||
characterVsCharacterCollision
|
||||
);
|
||||
|
||||
const characterContactListener = new Jolt.CharacterContactListenerJS();
|
||||
characterContactListener.OnAdjustBodyVelocity = (
|
||||
character,
|
||||
body2Ptr,
|
||||
linearVelocityPtr,
|
||||
angularVelocity
|
||||
) => {};
|
||||
characterContactListener.OnContactValidate = (
|
||||
character,
|
||||
bodyID2,
|
||||
subShapeID2
|
||||
) => {
|
||||
return true;
|
||||
};
|
||||
characterContactListener.OnCharacterContactValidate = (
|
||||
characterPtr,
|
||||
otherCharacterPtr,
|
||||
subShapeID2
|
||||
) => {
|
||||
// CharacterVsCharacterCollisionSimple doesn't handle collision layers.
|
||||
// We have to filter characters ourself.
|
||||
const character = Jolt.wrapPointer(
|
||||
characterPtr,
|
||||
Jolt.CharacterVirtual
|
||||
);
|
||||
const otherCharacter = Jolt.wrapPointer(
|
||||
otherCharacterPtr,
|
||||
Jolt.CharacterVirtual
|
||||
);
|
||||
|
||||
const body = _sharedData.physicsSystem
|
||||
.GetBodyLockInterface()
|
||||
.TryGetBody(character.GetInnerBodyID());
|
||||
const otherBody = _sharedData.physicsSystem
|
||||
.GetBodyLockInterface()
|
||||
.TryGetBody(otherCharacter.GetInnerBodyID());
|
||||
|
||||
const physicsBehavior = body.gdjsAssociatedBehavior;
|
||||
const otherPhysicsBehavior = otherBody.gdjsAssociatedBehavior;
|
||||
|
||||
if (!physicsBehavior || !otherPhysicsBehavior) {
|
||||
return true;
|
||||
}
|
||||
return physicsBehavior.canCollideAgainst(otherPhysicsBehavior);
|
||||
};
|
||||
characterContactListener.OnContactAdded = (
|
||||
character,
|
||||
bodyID2,
|
||||
subShapeID2,
|
||||
contactPosition,
|
||||
contactNormal,
|
||||
settings
|
||||
) => {};
|
||||
characterContactListener.OnCharacterContactAdded = (
|
||||
character,
|
||||
otherCharacter,
|
||||
subShapeID2,
|
||||
contactPosition,
|
||||
contactNormal,
|
||||
settings
|
||||
) => {};
|
||||
characterContactListener.OnContactSolve = (
|
||||
character,
|
||||
bodyID2,
|
||||
subShapeID2,
|
||||
contactPosition,
|
||||
contactNormal,
|
||||
contactVelocity,
|
||||
contactMaterial,
|
||||
characterVelocity,
|
||||
newCharacterVelocity
|
||||
) => {};
|
||||
characterContactListener.OnCharacterContactSolve = (
|
||||
character,
|
||||
otherCharacter,
|
||||
subShapeID2,
|
||||
contactPosition,
|
||||
contactNormal,
|
||||
contactVelocity,
|
||||
contactMaterial,
|
||||
characterVelocityPtr,
|
||||
newCharacterVelocityPtr
|
||||
) => {};
|
||||
character.SetListener(characterContactListener);
|
||||
}
|
||||
|
||||
// TODO This is not really reliable. We could choose to disable it and force user to use the "is on platform" condition.
|
||||
//body.SetCollideKinematicVsNonDynamic(true);
|
||||
return body;
|
||||
|
Reference in New Issue
Block a user