[SOLVED] Best practices for organizing PlayCanvas scripts

My game is becoming increasingly complex, making the overview more difficult.
That is why I wondered what the best way is to keep my scripts organized.

For example, should I place everything from the enemy AI in one script or do I have to create each function in a separate script (which makes communication between scripts more difficult) …

Someone tips?

For related scripts, I do tend to group them into a single JS file. For example, the physics constraints scripts:

https://playcanvas.com/editor/code/618829?tabs=19981369

And the first person camera:

https://playcanvas.com/editor/code/626211?tabs=21037147

Also, as a general tip, don’t have scripts call each other directly. Instead, use fire and on to send/receive events. The Flappy Bird game, for example, uses this approach:

https://playcanvas.com/project/375389/overview/flappy-bird

1 Like

In Unity/C# there was a way to divide one script into a number of parts (such as different pages). Is that also possible with PlayCanvas/JS?

Yes, you can do that. You can have the declaration of a script type in one script, and several of its methods in one or more other files.

You just need to make sure the other files are loaded after the script file that has the declaration of the script type (in your projects settings, script loading order tab).

So, if the script itself is enemy.js, the script part can be called enemy_movement.js? How to connect these scripts?

I Will do.

The filename can be anything, it doesn’t matter how it’s called.

All Javascript is being appended to the same site so it’s “connected” automatically.

For example here is your enemy.js initial script:

var Enemy = pc.createScript('enemy');

// initialize code called once per entity
Enemy.prototype.initialize = function() {
    
};

// update code called every frame
Enemy.prototype.update = function(dt) {
    
};

And here is another script file named enemy-movement-more.js, where you can remove the initial code Playcanvas puts in and you can add methods extending the enemy.js script:

Enemy.prototype.calculateMovement = function() {
   // logic code  
};

image

The important thing is the enemy-movement-more.js script has to be loaded after the enemy.js script:

image

3 Likes

Perfect! With this information it will work, thanks @Leonidas!

1 Like

Can someone explain why i have to use this:

this.app.on('game:explosion', this.explosion, this);
this.app.fire('game:explosion');

instead of using this:

game.script.game.explosion();
1 Like

You can do either, whatever suits you both.

If you would like more info on why you should use one over the other search for OOP programming paradigms, especially talks from Alan Kay (he could be the father of what we are talking here).

1 Like

Yeah, exactly. My preference is the event fire/on style. It’s just because I believe decoupling scripts makes your code more robust (say if you add/remove scripts at runtime via the Editor).

2 Likes

Hello @Leonidas, It looks like this is not longer working after I use the parse button. The main enemy script can no longer find the functions. Any idea how I can fix this?

Usually when the parser fails it’s because an object or method is misnamed.

Can you share your script code here?

I use the method above to order my functions in diffrent scripts. But after i used the parse button of the script where i removed the initials it don’t work anymore. I don’t think its because midnamed because the problem is with all functions right now.

I found the problem. My scripts with no initials where to far after the main script in the loading order. So they where not yet loaded while the main script already need them.

1 Like