How would I go about explosion physics?

Terrible example but rocket jumping from tf2, if the player is in a radius of the exploding object the player will then get an impulse based on their position relative to the exploding object.

1 Like

So you need to cycle through each object in a certain radius and apply a force to each of them that will depend on the distance (for example - linear multiplier).

Here is an example of the logic you are interested in in another thread on stackoverflow

1 Like

In my own perspective for the functionality you would do exactly what @robert.ua said for pushing dynamic entities away from the explosion. For visuals you could use the explosion demo project using the particle system made by playcanvas. If you set an event when the particle system is played to initiate a function for the force and tweak the timing right you could have a good looking and visually appealing explosion.

I have a gravity script that could be modified to do this, it pulls entities with certain tags to it, it could be modified to do the same to all dynamic entities, and just change the force of a ā€œpullā€ to the center mass of the object with a script to inverted (negative) so it pushes it away and add the functionality I defined earlier.

Could I get that?
Thanks

1 Like

the only issue is youā€™d have to add either an impulse function or disable the force after explosion, as the gravity code currently constantly pulls the entity to it.

i could add that myself

1 Like
var GravityScript = pc.createScript('gravityScript');

// attribute for gravity strength
GravityScript.attributes.add('gravityStrength', { type: 'number', default: 9.8 });

// attribute to select the child entity which defines the gravity radius
GravityScript.attributes.add('gravityRadiusEntity', { type: 'entity' });

// initialize script
GravityScript.prototype.initialize = function() {
    this.affectedBodies = new Set();
    
    // Listen for trigger events if the child entity has a trigger collider
    if (this.gravityRadiusEntity && this.gravityRadiusEntity.collision) {
        this.gravityRadiusEntity.collision.on('triggerenter', this.onTriggerEnter, this);
        this.gravityRadiusEntity.collision.on('triggerleave', this.onTriggerLeave, this);
    }
};

// when an object enters the gravity radius
GravityScript.prototype.onTriggerEnter = function(otherEntity) {
    if (otherEntity.tags.has('11')) {
        this.affectedBodies.add(otherEntity);
    }
};

// when an object leaves the gravity radius
GravityScript.prototype.onTriggerLeave = function(otherEntity) {
    if (otherEntity.tags.has('11')) {
        this.affectedBodies.delete(otherEntity);
    }
};

// called every frame
GravityScript.prototype.update = function(dt) {
    this.affectedBodies.forEach(function(otherEntity) {
        var distance = this.entity.getPosition().distance(otherEntity.getPosition());
        var forceMagnitude = this.gravityStrength * (this.entity.rigidbody.mass * otherEntity.rigidbody.mass) / (distance * distance);
        var forceDirection = this.entity.getPosition().sub(otherEntity.getPosition()).normalize();
        var force = forceDirection.scale(forceMagnitude);
        
        otherEntity.rigidbody.applyForce(force);
    }, this);
};

Additionally, ensure the dynamic entities have the tags: ā€œ11ā€ or change this to apply to dynamic bodies all together.

thanks ill use this after I finish a different area

1 Like

Hey, its giving an error when it runs forEach(function(otherEntity) hereā€™s the code just incase i messed something up

var Explode = pc.createScript('explode');
Explode.attributes.add("countdown", {
    type: "number",
    default: 5
})
// attribute for gravity strength
Explode.attributes.add('gravityStrength', { type: 'number', default: 9.8 });

// attribute to select the child entity which defines the gravity radius
Explode.attributes.add('gravityRadiusEntity', { type: 'entity' });

// initialize code called once per entity
Explode.prototype.initialize = function() {
this.precountdown = this.countdown
this.counting = true
this.affectedBodies = new Set();
    
    // Listen for trigger events if the child entity has a trigger collider
    if (this.gravityRadiusEntity && this.gravityRadiusEntity.collision) {
        this.gravityRadiusEntity.collision.on('triggerenter', this.onTriggerEnter, this);
        this.gravityRadiusEntity.collision.on('triggerleave', this.onTriggerLeave, this);
    }
};

// update code called every frame
Explode.prototype.update = function(dt) {
    this.objectPos = this.entity.getPosition()
    this.push()
    if (this.counting == true){
        this.countdown -= dt
    }
    
    if (this.countdown <= 0){
        console.log('yeh')
        this.counting = false
        this.countdown = this.precountdown
        this.push()
    }
};


// initialize script
Explode.prototype.initialize = function() {
    
};

// when an object enters the gravity radius
Explode.prototype.onTriggerEnter = function(otherEntity) {
    if (otherEntity.tags.has('moveable')) {
        this.affectedBodies.add(otherEntity);
    }
};

// when an object leaves the gravity radius
Explode.prototype.onTriggerLeave = function(otherEntity) {
    if (otherEntity.tags.has('moveable')) {
        this.affectedBodies.delete(otherEntity);
    }
};

// called every frame
Explode.prototype.push = function(dt) {
    this.affectedBodies.forEach(function(otherEntity) {
        var distance = this.entity.getPosition().distance(otherEntity.getPosition());
        var forceMagnitude = this.gravityStrength * (this.entity.rigidbody.mass * otherEntity.rigidbody.mass) / (distance * distance);
        var forceDirection = this.entity.getPosition().sub(otherEntity.getPosition()).normalize();
        var force = forceDirection.scale(forceMagnitude);
        
        otherEntity.rigidbody.applyImpulse(force * -1);
    }, this);
};

// swap method called for script hot-reloading
// inherit your script state here
// Explode.prototype.swap = function(old) { };

// to learn more about script anatomy, please read:
// https://developer.playcanvas.com/en/user-manual/scripting/
1 Like

The issue might be that the context of this inside the forEach loop is not what you expect. You can fix this by using arrow function syntax like this:

Explode.prototype.push = function(dt) {
    this.affectedBodies.forEach((otherEntity) => {
        var distance = this.entity.getPosition().distance(otherEntity.getPosition());
        var forceMagnitude = this.gravityStrength * (this.entity.rigidbody.mass * otherEntity.rigidbody.mass) / (distance * distance);
        var forceDirection = this.entity.getPosition().sub(otherEntity.getPosition()).normalize();
        var force = forceDirection.scale(forceMagnitude);
        
        otherEntity.rigidbody.applyImpulse(force.clone().scale(-1));
    });
};

Hope this helps

I could better diagnose the issue having read the console logs and the launch error from the launch page if this is still not working.

Iā€™m dumb for that ill share it if this doesnā€™t work

1 Like

Hereā€™s the project too just in case: PlayCanvas | HTML5 Game Engine

[explode.js?id=165694350&branchId=b2942a4a-94bf-41e2-93e8-f20607f1c95f:66]: Cannot read properties of undefined (reading ā€˜forEachā€™)

TypeError: Cannot read properties of undefined (reading ā€˜forEachā€™)
at Explode.push (https://launch.playcanvas.com/api/assets/files/Scripts/Player/Weapons/Projectiles/explode.js?id=165694350&branchId=b2942a4a-94bf-41e2-93e8-f20607f1c95f:66:25)
at Explode.update (https://launch.playcanvas.com/api/assets/files/Scripts/Player/Weapons/Projectiles/explode.js?id=165694350&branchId=b2942a4a-94bf-41e2-93e8-f20607f1c95f:31:10)
at ScriptComponent._scriptMethod (https://code.playcanvas.com/playcanvas-1.68.1.dbg.js:102680:22)
at ScriptComponent._onUpdate (https://code.playcanvas.com/playcanvas-1.68.1.dbg.js:102714:15)
at ScriptComponentSystem._callComponentMethod (https://code.playcanvas.com/playcanvas-1.68.1.dbg.js:103476:52)
at ScriptComponentSystem._onUpdate (https://code.playcanvas.com/playcanvas-1.68.1.dbg.js:103494:11)
at ComponentSystemRegistry.fire (https://code.playcanvas.com/playcanvas-1.68.1.dbg.js:1647:21)
at AppBase.update (https://code.playcanvas.com/playcanvas-1.68.1.dbg.js:70025:19)
at AppBase.tick (https://code.playcanvas.com/playcanvas-1.68.1.dbg.js:71078:20)
at AppBase.start (https://code.playcanvas.com/playcanvas-1.68.1.dbg.js:69986:11)

1 Like

I think the problem might be that the list of affected bodies isnā€™t getting set up properly. This could be why itā€™s showing as ā€œundefinedā€ when you try to use it in the forEach loop. Double-check how youā€™re setting up this.affectedBodies to make sure itā€™s getting populated correctly with the entities that should be affected by the explosion.

I noticed that most the code in the project is simply not being used or some functions are either never read, undefined or never used. Is there a reason for this? Is this project just starting out or is this just an error?

its relatively new

1 Like

ok ive figured out that its not reading anything in the initialize function but i have to go

1 Like

nvm i have time