Weapon Projectiles
Making a Simple Bullet
We need a scene to spawn in, quickly setup this in a new scene:
- Area2D
- CollisionShape2D
- Sprite2D
- Area2D
Give it a script and connect the Area2D's own
on_body_enteredsignal to itselfMake a new global variable inside your bullet script called
direction.Make a new global constant as well, for the
SPEEDof the bullet. Your player moves at speed 300 by default, so try something around 500-700.In a
_physics_process(delta)function, adddirection * speed * deltatoposition. We multiply bydeltabecause we're manually moving the position instead of using CharacterBody2D'smove_and_slide()function which does that for you.deltais the time between the last physics frame and this one.Fast moving bulletsIf you increase your bullet's speed by a lot, it might move over the enemy in the span of a frame. This means it won't detect its collision.
Continuous Collision Detection (CCD) is used to counteract this. With RigidBody2D you can enable CCD. To do this, make the root node of your bullet a RigidBody2D. Enable Continuous CD in RigidBody2D > Solver in the inspector.
You'll have to use RigidBody2D's available methods and signals to form this, which won't be as simple. Also, it won't be as fast.
If you want fast bullets, a better way would be to add a RayCast2D to your player and just see if anything is colliding in its path when firing. Use multiple ray casts for making bullet width. This doesn't come with having any feedback that the player fired a bullet to kill the enemy. If you can make a kill animation or some sort of way to tell the player they fired, it's the best way to make fast firing bullets.
This is also how hit-scan works in all FPS games, if you are aware of the concept.
In your function connected to the
on_body_enteredsignal, enter:if body is Enemy: body.queue_free()
All in all, these will move the projectile every frame in an unspecified direction, and then when it runs into an enemy it'll delete it.
Spawning the Bullet
We don't want to spawn a bullet every frame or physics frame, so we can't use _process or _physics_process to spawn in a bullet.
Add a Timer node to your player scene.
In the Inspector, set the wait time to be how long you want between shots. Turn Autostart on so it starts when the game plays. Leave One Shot off so that it repeats the timer.
SRPNow, we could just connect the
timeoutsignal to our player script. But as previously mentioned, it's a good idea to split your project up into as many files as possible for every different use.The single responsibility principle (SRP) is mentioned several times across Godot's best practices docs.
In essence, keep scripts/functions/nodes to just one use. In this case, the Timer node is purely for spawning and shooting off projectiles.
Add a script to the projectile spawner Timer node and connect its own
timeoutsignal to itself.This is very similar to spawning in enemies. Make a new global variable in the script for the main node, in the
_readyfunction set that node to your singleton'smain_node.From the FileSystem dock, find and drag your bullet scene into your script, and before you release the mouse, hold ctrl/cmd.
Instructions for the rest are going to be very general, try to remember how they were implemented.
In your function connected to the
timeoutsignal, make a new variable set to an instance of the scene.Get your player as a global variable for the script.
Back in the function, set that variable's
direction, or equivalent, value toplayer.velocity.normalized(). Do the same with the projectile's and your player'sglobal_position.Then, add it as a child of your main scene's root node.
- I've created a bullet scene
- The bullets are spawned by a timer