Spawn Bullets and Destroy Player

Full workflows and code to spawn bullets and self-destruct Player

What you'll develop on this page

Player is able to spawn bullets and self-destruct

We will spawn bullets and self-destruct the player from user inputs.

Github branch link: https://github.com/moetsi/Unity-DOTS-Multiplayer-XR-Sample/tree/Shooting-and-Destroying-Player

Spawning a bullet

  • In order to spawn a bullet, we need to know where exactly we want it spawned

  • We are going to update our Player prefab with a BulletSpawn GameObject

    • First, open the Player prefab and add an empty GameObject to the Hierarchy named Bullet Spawn

    • Change the position to (0.5, 0 , 1)

We could simply "remember" the offset (0.5, 0, 1) by implementing it in our bullet spawn system (via writing it into the script). The issue with this approach is that every time the Player prefab is updated, you'd need to remember to go back and update this code in the bullet spawn system (easy to remember on a small simple project like this, but harder to do on complex projects). Instead, we want to link the GameObject position to component data on the player entity. This way if the Player prefab is updated and the Bullet Spawn GameObject is moved around, the code does not have to change.

  • Let's create the BulletSpawnOffsetComponent and paste the below code snippet into BulletSpawnOffsetComponent.cs:

  • This is the component that will be added (via 'Add Component') to the player entity to store the Bullet Spawn offset

Creating BulletSpawn GameObject and BulletSpawnOffsetComponent
  • Next, we need to use IConvertGameObjectToEntity to run a process that takes in the BulletSpawn GameObject Transform and sets BulletSpawnOffsetComponent to that value

  • Let's create the SetBulletSpawnOffset and paste the below code snippet to SetBulletSpawnOffset.cs:

Create SetBulletSpawnOffset and check out the DOTS Windows to see player entity
  • Next we open our Player prefab, put SetBulletSpawnOffset on our Player prefab (via Add Component), then drag the Bullet Spawn GameObject in Hierachy into the bulletSpawn field in the Inspector window when Player is selected

  • Hit "play" and then navigate to the DOTS Windows to check out the Player archetype by finding the Archetype that contains the BulletSpawnOffsetComponent

DOTS Windows showing the Player Archetype
  • Now let's find the Player entity in the DOTS Hierarchy tab and check out the component values in the inspector

    • You will see the Bullet Spawn Offset Component and the values of .5, 0, 1

Player Entity in the Editor Inspector Window with component values
  • We will use this value in InputSpawnSystem to spawn our bullet

  • Now we must create a Bullet prefab

  • We will follow the same process as we did for asteroids and players

  • Create Bullet prefab

    • In the SampleScene Hierarchy, Create a 3D object > Sphere GameObject named "Bullet," drag it into the Scripts and Prefabs project folder

    • Once Bullet has been dragged into the folder, delete the Bullet GameObject from the Hierarchy

    • Open the Bullet prefab and change the scale to (0.1, 0.1, 0.1)

    • Change the material to "Black"

    • Remove the Sphere Collider component

  • Create a BulletTag component and add it to the Bullet prefab

    • paste the below code snippet into BulletTag.cs:

Create Bullet prefab and add BulletTag
  • Now we are going to create a new Authoring component we did not have for asteroids or players, named BulletAgeComponent, and put it on the Bullet prefab by clicking "Add Component" while Bullet is selected in Hierarchy

    • This component will be used to delete bullets after a specific amount of time

      • Why the time limit? Not sure about you, but we don't want bullets to live forever in the game and use up resources

  • Paste the code snippet below into BulletAgeComponent.cs:

  • Add the BulletAgeComponent to the Bullet prefab and make maxAge = 5 by typing in 5 to the Max Age field

    • This will set the lifetime of a bullet to 5 seconds

Create the BulletAgeComponent and Add it to the Bullet prefab with a maxAge of 5
  • Next we'll create BulletAuthoringComponent to be put on the PrefabCollection in ConvertedSubScene

  • Paste the below code snippet into BulletAuthoringComponent.cs:

  • Navigate to ConvertedSubScene, add the BulletAuthoringComponent to our PrefabCollection GameObject by clicking "Add Component" in Inspector

  • Drag the Bullet Prefab into the "Prefab" field in the Bullet Authoring Component in Inspector

  • save, and navigate to SampleScene, and reimport ConvertedSubScene

Create the BulletAuthoringComponent and add it to our PrefabCollection GameObject
  • Next, we add the VelocityComponent to to the Bullet so it can travel

Adding the VelocityComponent to the Bullet Prefab
  • Now we we are ready to update InputSpawnSystem to spawn a Bullet

  • Paste the below code snippet into InputSpawnSystem.cs:

  • We just updated the rate in InputSpawnSystem to limit bullet generation to 10 per second

    • Otherwise bullets will be generated as fast as the .ForEach() can be run

  • Let's hit "play", spawn our player and shoot some bullets and check it out

After updating InputSpawnSystem we are able to spawn Bullet prefabs
  • Again, because our bullets have a Translation and VelocityComponent, our MovementSystem acts on them as well

  • The bullets are traveling too fast to make out

  • Navigate to ConvertedSubScene, and go to GameSettings to change the BulletVelocity to 20 in Inspector

  • Save, return to SampleScene, reimport the ConvertedSubScene, hit play, spawn your player, and shoot around again

Change Bullet Velocity to 200 in GameSettings
  • Much better, but we still need to add a system that destroys bullets when they pass their max age value we set in the BulletAgeComponent

  • Paste the code snippet below into BulletAgeSystem.cs:

  • After creating BulletAgeSystem, hit "play", spawn a player, spawn bullets, and checkout the BulletAgeSystem at work

BulletAgeSystem works and destroys bullets after their max age

Player self-destruction

  • We are now going going to add the ability for the player to self-destruct if the "p" button is pressed

    • Because the player is floating in space it is easy to get lost and so this will provide a way to bail and return to the origin

  • First we need to update InputSpawnSystem to add a DestroyTag to the player when "p" is pressed

  • Update InputSpawnSystem.cs with the code below:

  • Now we need a PlayerDestructionSystem that will destroy the player entities

  • Create PlayerDestructionSystem and paste the code snippet below into PlayerDestructionSystem.cs:

  • Notice that the PlayerDestructionSystem is nearly identical to the AsteroidDestructionSystem

    • If they are so similar, then why not just make a "DestructionSystem" that destroys anything with a destroy tag?

      • The reason is because this gitbook has a NetCode section where Player destruction needs to follow a player-specific process, so that's why we set it up this way here

    • Then why not make a "GeneralDestructionSystem" that has .WithNone<PlayerTag>() and .WithAll<DestroyTag>() to destroy all entities that need to be destroyed that aren't player entities?

      • First off, the purpose of this gitbook is not to illustrate excellent game architecture, but to show the "how" of putting different Unity technologies together. But even so, a single destruction system is bad software engineering for ECS. Instead, it's better to learn how to make tight, focused Systems that touch exactly as much as they're supposed to. Building a mega-huge Destruction System would make it hard to compartmentalize.

  • Hit "play", spawn your player, move around, then hit "p" to self-destruct

Update InputSpawnSystem and add PlayerDestructionSystem

Github branch link: https://github.com/moetsi/Unity-DOTS-Multiplayer-XR-Sample/tree/Spawning-Updating-and-Destroying-Asteroids

git clone https://github.com/moetsi/Unity-DOTS-Multiplayer-XR-Sample/ git checkout 'Shooting-and-Destroying-Player'

One more (extremely rad that shows off DOTS) thing...

Fast enter play-mode in Unity is not the default because most projects are game object based and game object based projects have a tendency to use tons of static variables for state. And doing that by default makes it so that a domain reload is required to reset all the static state before entering playmode. By design, everything we do in DOTS avoids this pattern. Multiple worlds, per world singletons etc. They exist so that it becomes trivial to turn on the faster enter play mode option. This is the recommended setting in a DOTS based project: upload_2020-10-8_10-52-42.png

From Joachim (the founder of Unity)

  • Because this gitbook is a DOTS-based project we can enable "Enter Play Mode Settings Options"

  • First, hit "play" and notice how long it takes to load the game

  • Now navigate to "File", choose "Build Settings", then "Player Settings...", then "Editor", then scroll to the bottom to "Play Mode Settings" and enable "Enter Play Mode Settings Options"

  • Save and then navigate back to SampleScene and hit "play"

Enable "Enter Play Mode Settings Options" to speed up load of "play"
  • Holy moly! Start up is less than a second!

    • Why didn't we make this clear at the beginning of the gitbook?

    • To learn it, you must earn it 🙃

    • (actually because we needed to understand how DOTS worked to make sense of Joachim's post and not just assume it is a magic toggle)

Last updated