prefab-user-properties-initializing.rst 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. .. include:: ../_header.rst
  2. Initializing other properties
  3. `````````````````````````````
  4. It's possible you want to change other properties of the prefab instance, in dependence of the values of the user properties. For example, if the **flameType** property value is ``"fire"``, then you set the mass of the body to ``50``. Because the property values are not set in the constructor, you can listen to the ``scene-awake`` event and setup the body properties:
  5. .. code::
  6. class Dragon extends Phaser.GameObjects.Sprite {
  7. constructor(scene,...) {
  8. ...
  9. /* START-USER-CTR-CODE */
  10. scene.events.once("scene-awake", this.awake, this);
  11. /* END-USER-CTR-CODE */
  12. }
  13. /** @type {"fire"|"smoke"|"laser"} */
  14. flameType = "fire";
  15. /* START-USER-CODE */
  16. awake() {
  17. // at this point, all objects in the scene are created
  18. // and the user properties are set with new values
  19. if (this.flameType === "fire") {
  20. this.body.mass = 50;
  21. }
  22. }
  23. /* END-USER-CODE */
  24. }
  25. If you enable the **Generate Awake Handler** flag in the **Compiler Prefab Settings**, the |SceneCompiler|_ will generate this code for you:
  26. .. image:: ../images/scene-editor-prefab-settings-08212021.webp
  27. :alt: Generate awake event handler.
  28. .. code::
  29. class Level extends Phaser.GameObjects.Image {
  30. constructor(scene,...) {
  31. // awake handler
  32. this.scene.events.once("scene-awake", () => this.awake());
  33. ...
  34. }
  35. }
  36. It is your responsibility to write the ``awake`` method.
  37. The ``scene-awake`` event
  38. '''''''''''''''''''''''''
  39. The ``scene-awake`` event is not part of the Phaser_ API. It's a custom event the |SceneEditor|_ uses as convention. When the |SceneCompiler|_ generates the code of a scene, it also generates the code for emitting the ``scene-awake`` event. This event is emitted just after all objects are created:
  40. .. code::
  41. class Level extends Phaser.Scene {
  42. ...
  43. editorCreate() {
  44. ...
  45. // dragon
  46. const dragon = new Dragon(this, 370, 218);
  47. this.add.existing(dragon);
  48. ...
  49. // dragon (prefab fields)
  50. dragon.maxSpeed = 300;
  51. dragon.flameType = "smoke";
  52. dragon.onClickHandler = obj => this.selectDragon(obj);
  53. ...
  54. this.events.emit("scene-awake");
  55. }
  56. ...
  57. }
  58. As we mentioned in the previous sections, prefabs_ and `user components <./user-components.html>`_ can listen to this event for reading the values set to the user properties.
  59. It is important that you keep in mind that if you create a dynamic prefab instance, and it requires the ``scene-awake`` event, then you should call it manually:
  60. .. code::
  61. spawnDino(scene, x, y, flame) {
  62. const dragon = new Dragon(scene, x, y);
  63. dragon.flameType = flame;
  64. // send the awake notification to the new object
  65. scene.events.emit("scene-awake");
  66. }
  67. Because the ``scene-awake`` event is listened once in prefabs_ and `user components`_, only the new objects will be notified.
  68. As alternative to the ``scene-awake`` event, you can listen the ``Phaser.Scenes.Events.UPDATE`` event. It is emitted by the scene at every tick, so you just need to register the listener to be called **once**:
  69. .. code::
  70. scene.events.once("Phaser.Scenes.Events.UPDATE", this.start, this);
  71. Note that if you need to "awake" prefab before the game starts updating, you should listen to the ``scene-awake`` event.
  72. The ``scene-awake`` event is also used by components, `learn more about it <./user-components-awake-event.html>`_.
  73. Using properties with custom definition
  74. '''''''''''''''''''''''''''''''''''''''
  75. You can set a user property with a **Custom Definition**:
  76. .. image:: ../images/prefab-user-properties-initializing-custom-prop-07092021.webp
  77. :alt: Set custom definition flag.
  78. This means, the |SceneCompiler|_ skips the definition of the property. For example, if you set the ``flameType`` as **Custom Definition**, the ``flameType`` property declaration isn't generated. Instead, a ``flameType`` property initialization is included in the constructor:
  79. .. code::
  80. class Dragon extends Phaser.GameObjects.Sprite {
  81. constructor(scene,...) {
  82. ...
  83. // the compiler adds this
  84. this.flameType = "fire";
  85. }
  86. // the compiler skips this:
  87. // flameType = "fire";
  88. }
  89. Then, you can write a custom setter and initialize other fields of the prefab:
  90. .. code::
  91. class Dragon extends Phaser.GameObjects.Sprite {
  92. constructor(scene,...) {
  93. ...
  94. this.flameType = "fire";
  95. }
  96. /* START-USER-CODE */
  97. set flameType(flameType) {
  98. // update the body with the flameType
  99. if (flameType === "fire") {
  100. this.body.mass = 50;
  101. }
  102. }
  103. /* END-USER-CODE */
  104. }
  105. Note that you don't need to listen for the ``prefab-awake`` event anymore. Setting the ``flameType`` property will update the prefab state in the expected way. It's possible you also need to define a getter for the ``flameType``. If that's the case, you can store its value in a new field, or compute it.