Findings after my first small project and questions for next bigger project

I did a small project to get use to PlayCanvas and Javascript which where both new to me and to prepare for a much bigger project.

PlayCanvas findings after first (small) project:

In general I like it very much. I like the Entity-Component architecture. And I like that you can do almost anything using Javascript. I just scratched the surface but I’m sure a lot of things are possible.

All feels very solid. I had zero crashes. Well, the iPhone crashed because I used to many big textures. But that is off course not a PlayCanvas problem.

Graphics quality seems to be quite good.

What I found confusing is what object types you are dealing with. Sometimes you have a reference to an Entity or GraphNode and sometimes it is a script you are referencing to. (findByName() returns a reference to GraphNode in stead of Entity)

When I added 1000 entities to a scene, the framerate got really low. So performance is a thing I’m concerned about.

General questions for next (bigger) project:

Where should I put my scripts that are not attached to any entity. I will have a lot of supporting Javascript classes to make the game. Should I attach them to the root? Or just place them in the script folder?

My next project will need hundreds or thousands of objects. Most of them moving. Are there some ‘good practice’ tips for PlayCanvas and or Javascript so that we get the most performant code? Is for instance the extraction of a script reference from some entity a slow operation? Will it be better to do that once and remember the reference if possible?
And what is that fastest way to store and access variables? Are instance variables slower than global variables? How to deal with arrays to have fast access? What is the underlaying storage technique? Does it need to move the whole array when growing in size (like a vector in C++)? If so, can you reserve memory for some number of items so that it does not has to move in memory when growing?

Are there documents describing underlying techniques so that you can make better choices?

Does PlayCanvas assumes some unit size? Will a delta of 1.0 in position correspond to 1 meter? Or is this completely up to the user? Sometimes deep in an engine there are assumptions about this. I guess it is important for the physics simulation for instance.

What is the best (fastest) way to communicate between scripts attached to different entities?
A: using SomeObject.attribute.add(‘refval’, {type: ‘entity’) and set refval to some other entity? Then getting the script reference from this?
B: searching for the entity using app.root.findByName() and getting the script reference from this?
C: using events?

Which documents would you advice to study to prepare for the bigger project?

Thanks PlayCanvas team for this amazing engine!
I’m looking forward to start my bigger project :slight_smile:

Hi @simmania,

Happy that you’ve found PlayCanvas to be of help with your project!

This isn’t a comprehensive reply to your questions, but some things to get you started:

  1. On best practices when it comes to performance (this is a broad topic, especially when it comes to JavaScript performance): Optimization Guidelines | Learn PlayCanvas

  2. Specifically on the subject of adding hundreds of objects definitely take a look on batching: Batching | Learn PlayCanvas

And/or hardware instancing: Hardware Instancing | Learn PlayCanvas

  1. PlayCanvas units are just units, it’s up to you what they correspond to. But when it comes to collisions/physics then yes, it’s a good practice to use 1 meter for each unit (this an Ammo.js assumption, the underlying physics engine PlayCanvas uses).

  2. On script communication: Communication | Learn PlayCanvas

Hope that’s of help to get you started!

And do use the forum search function, there are plenty of hidden gems on this forum shared by the community on several of the topics you mention.

Here’s a good demo of hardware instancing being used to have 100s of ‘objects’ in a scene:

AFAIK, anything that isn’t a POD in JS, is allocated on the heap :frowning: So the standard rules around garbage collection applies.

It’s a O(1) operation.

PlayCanvas workflows are very similar to Unity so similar tips apply.

For example, I use these general guidelines in my own projects:

  • Templates are ‘self sufficient’/‘self enclosed’ meaning that they can be used and ran in isolation from anything else. Makes it easier to maintain and test.
  • Only reference children entities, never parents in the Editor
  • Use the Entity as the messaging bus between scripts on the same Entity
  • Use the Entity as the messaging bus to communicate out events. This allows scripts that are referencing that Entity to subscribe to events.
  • Use ES6 classes over ES5. Autocomplete is so much better in the code editor and all I lose is hotswap (example usage: https://playcanvas.com/project/950571/overview/fps-pit). ES6 can be used 98.34% of browsers but worse case scenario, I can take it through Babel post build for that last 1.7%
1 Like

@yaustar , thx a lot! I really like this kind of information. I’m one of those guys that wants to understand what is going on beneath the surface. Not only because I’m interrested in that, but also it wil allow me to make better code.

Thx for the hardware instancing example link. This give me confidence that we can make very attractive game play.

You say referencing a script from an entity is a O(1) operation. As said, I like to understand thinks in more detail. If an entity has multiple scripts attached, doesn’t it has to search for the script when referencing a script? Or is this done at compile time and does it only need to search when adding scripts at run-time?

I really like the article about garbage collection. I would love to see more such informative articles!

You say: “Only reference children entities, never parents”. I do not understand. Referencing a parent would be a O(1) operation. While referencing children would mean we have to search for it in the children list. Can you explain?

I would love to use ES6 classes. But as I understood from serveral forum threads, this is not yet possible when using the Editor.

@Leonidas , thx for the optimization guide and bathing info! I really appreciate that kind of info.

About the communication between scripts: You pointed me to the event communication option.
Are events faster then getting a refference to the other script and calling its functions?

In absolute terms, events are slightly slower when compared to getting a reference to the other script directly.

So if for example you’re looping through tons of objects or you’re executing code in your update loop, use references.

Otherwise events are recommended since they can help with code maintenance and lead to good development practices.

A JS object is basically a dictionary so any property lookup is O(1)

Its now about entity management. If you are only referencing children, its easy to convert entities to templates, copy, paste and move between scenes and projects.

You can reference children via script attributes in the Editor so it’s an O(1) operation.

Anything that can run directly in the browser will work on the Editor. This includes ES6 classes. See the project i linked to before