GDevelopApp/GDevelop-examples

Flocking Example

Closed this issue ยท 12 comments

Describe the example

An example for using the flocking behavior

Checklist

  • I've followed all of the best practices.
  • My game has a proper name in the game properties.
  • My game package name behind with com.example..
  • My game has all events unfolded.
  • I've added myself as the author in the game properties.
  • I've included a file called "README.md" with a description in proper English, explaining what this example is doing.
  • I confirm that this game and all of its resources can be integrated to this GitHub repository, distributed and MIT licensed.
  • I've cleaned unused resources.

Game folder

flocking-example.zip

Bouh commented

This is more of an extension review:

  • Two number inputs are prefered for the ObjectToSpawn parameter. This way you can use the expressions. Like Fish.X() and Fish.Y().
  • In spawnBoid function you hide the spawner, the creator may wish to see the spawn in their games. I suggest removing this action, this has to be led by the creator in their game.
  • In onCreated function, you create a boids array in the object. if one day in the engine we need to use boids you will redefine this scope.
    Instead, you can create a private scope with the name of the extension: object._extensionFlocking.boids
  • In spawnBoid function: you define random function, we have one in gdjs (GDevelop JavaScript api): https://docs.gdevelop.io/GDJS%20Runtime%20Documentation/modules/gdjs.html#random
    gdjs is in the global scope so you can use it everywhere in a JS Event.
  • Same for normalizing and a few other methods, see in gdjs. (this will reduce the size of your extension)

I'm skipping the Boid class, because of the complex math, @D8H I think this might interest you.

  • Boid.prototype.borders no need for this, we have an extension for it: Screen Wrap:
    https://wiki.gdevelop.io/gdevelop5/extensions/screen-wrap/reference
  • Boids is more know than Flocking, right? If yes, I think we should rename the extension Boids ๐Ÿ‘
    And in the short description you can mention it is a "Flocking swarm behaviour"
  • Please fill the description, version number 1.0.0, and author name if you have one ;)

This is more of an extension review:

  • Two number inputs are prefered for the ObjectToSpawn parameter. This way you can use the expressions. Like Fish.X() and Fish.Y().
  • In spawnBoid function you hide the spawner, the creator may wish to see the spawn in their games. I suggest removing this action, this has to be led by the creator in their game.
  • In onCreated function, you create a boids array in the object. if one day in the engine we need to use boids you will redefine this scope.
    Instead, you can create a private scope with the name of the extension: object._extensionFlocking.boids
  • In spawnBoid function: you define random function, we have one in gdjs (GDevelop JavaScript api): https://docs.gdevelop.io/GDJS%20Runtime%20Documentation/modules/gdjs.html#random
    gdjs is in the global scope so you can use it everywhere in a JS Event.
  • Boids is more know than Flocking, right? If yes, I think we should rename the extension Boids ๐Ÿ‘
    And in the short description you can mention it is a "Flocking swarm behaviour"
  • Please fill the description, version number 1.0.0, and author name if you have one ;)
  • Same for normalizing and a few other methods, see in gdjs. (this will reduce the size of your extension)
    I'm skipping the Boid class, because of the complex math, @D8H I think this might interest you.
  • Boid.prototype.borders no need for this, we have an extension for it: Screen Wrap:
    https://wiki.gdevelop.io/gdevelop5/extensions/screen-wrap/reference

I'm not sure how to do that, added dependency for it tho, need help on this

Game Folder

boids-example.zip

D8H commented

It's impressive, very cool extension!

  • The lifecycle "doStepPreEvents" can be used instead of "runBoids". It's called automatically every frame.
  • The behavior should be attached to the fish directly. If you need to know other fishes, you can add them in an Array (attached to the scene) each time onCreate is called and remove them at onDestroy. Take a look at the community extension called "Recolorizer", it does something similar.

To go further:

Bouh commented

I'm not sure how to do that, added dependency for it tho, need help on this

I see you used it in your latest zip file ๐Ÿ‘

I think it even could be improved by two different mechanics.
1 ) Like currently, teleport to the opposite side.
2 ) Limit the boids in the camera view by making them bounce on the border by changing the boids direction.
In the behavior properties, you can achieve that with a True/False parameter.

For a first extension, you made a solid one!

D8H commented

I think it even could be improved by two different mechanics. 1 ) Like currently, teleport to the opposite side. 2 ) Limit the boids in the camera view by making them bounce on the border by changing the boids direction. In the behavior properties, you can achieve that with a True/False parameter.

I think that the boid behavior should not care about warping things. It should be done by users with events outside of the extension.

It's impressive, very cool extension!

  • The lifecycle "doStepPreEvents" can be used instead of "runBoids". It's called automatically every frame.

Moved the run function here

  • The behavior should be attached to the fish directly. If you need to know other fishes, you can add them in an Array (attached to the scene) each time onCreate is called and remove them at onDestroy. Take a look at the community extension called "Recolorizer", it does something similar.

Added this one too

To go further:

Hmm typescript? I used the Recolorizer shared defined classes

Fixed this one, other behaviors can modify the boids.

I see you used it in your latest zip file ๐Ÿ‘

I think it even could be improved by two different mechanics.
1 ) Like currently, teleport to the opposite side.
2 ) Limit the boids in the camera view by making them bounce on the border by changing the boids direction. In the behavior properties, you can achieve that with a True/False parameter.

Oh no more features, I need to know the border limits where the boids can follow

For a first extension, you made a solid one!

Updated Game Folder

boids-example.zip

D8H commented

Accessing the behavior

There is no garentee this will work. If a user adds the behavior 2 times, it creates one named "BoidsBehaviour" and another one "BoidsBehaviour2" then the user can remove "BoidsBehaviour".

Boid.prototype.getBehavior = function() {
  return this.gObject.getBehavior("BoidsBehaviour");
}

Methods from Boid can be added to the behavior prototype directly. The prototype can be retried like this within onCreate:

const object = objects[0];
const behaviorName = eventsFunctionContext.getBehaviorName("Behavior");
const behavior = object.getBehavior(behaviorName);
const prototype = Object.getPrototypeOf(behavior);

This way this is the behavior instance and this.owner the object.

Typing

The code editor support documentation with typing. It helps the autocompletion.

For instance, this comment...

// Separation
// Method checks for nearby boids and steers away
Boid.prototype.separate = function(boids) {

... can be replaced by something like this:

/**
 * Separation: checks for nearby boids and steers away.
 * @param boids {Boid[]}
 * @return {Vector} steer force
 */
Boid.prototype.separate = function(boids) {

Vector operations

I'm not sure that the operation methods of the Vector class make the code easier to read. I guess that the goal is to avoid to repeat the formula for x and y but the operators doesn't stand out which make it difficult to read in my opinion.

Accessing the behavior

There is no garentee this will work. If a user adds the behavior 2 times, it creates one named "BoidsBehaviour" and another one "BoidsBehaviour2" then the user can remove "BoidsBehaviour".
...
Methods from Boid can be added to the behavior prototype directly. The prototype can be retried like this within onCreate:
...
This way this is the behavior instance and this.owner the object.

Updated the code

Typing

The code editor support documentation with typing. It helps the autocompletion.
...

Added doc blocks

Vector operations

I'm not sure that the operation methods of the Vector class make the code easier to read. I guess that the goal is to avoid to repeat the formula for x and y but the operators doesn't stand out which make it difficult to read in my opinion.

Can't remove this one, I need the vectors to calculate the average speed and direction of the boids

Updated Game Folder

boids-example.zip

Bouh commented

Lgtm, this extension is nice and well made!
@D8H I let you the choice to merge or let me know.
To me, it's a go ๐Ÿ‘

D8H commented

I did some changes:
https://www.dropbox.com/s/e5gk9zfgetatxt0/fish-school.zip?dl=1

New features

  • Add new actions ("avoid" and "move to") to allow interactions with the boids
  • Add properties to tweak the direction decision

Bug fixes

  • Remove the hard-coded dimension of the fish from the calculus
  • Remove the screen warp requirement property
  • Fix the cohesion calculus (return this.seek(sum); like it was done in the source material)
  • Sum the intended direction instead of summing the steer forces (this allows to actually respect the speed properties and better parametriarization)
  • Use timeDelta to evaluate the movement
  • Handle behavior disabling

Efficiency

  • Use a R-Tree
  • Remove any allocation repeated every frame
  • Remove useless divisions before normalization
  • Use SqDistance to avoid square root calculus

Best practices

  • Mark it as experimental
  • Rename some properties
  • Rename expressions to remove the "Get" prefix
  • Rename action to replace "Change" by "Set"
  • Add dot in description
  • Reword name and descriptions
  • Reorganize groups
  • Move the boids manager from gdjs to runtimScene

Nitpicks

  • Change the background color to be easier on the eyes
  • Remove the batch create action
  • Change the getPosition to use this instead of a parameter
  • Define classes using a standard way

Just checked it out, looks very nice!
you can feed the fish :)

D8H commented

I went ahead and submitted the extension:

I added a scene to the example to configure the behavior properties with sliders:

Fishes