85 lines
3.1 KiB
Markdown
85 lines
3.1 KiB
Markdown
|
## Exercise 1: Projectiles
|
||
|
|
||
|
There are several ways we can create projectiles in Godot. To choose the right one we need to think about how the projectiles should behave. Consider the following:
|
||
|
|
||
|
* Should there be a limited number of projectiles?
|
||
|
* What happens to projectiles that leave the viewing area?
|
||
|
* Should shots ricochet?
|
||
|
* Do projectiles need momentum, acceleration, deceleration?
|
||
|
|
||
|
Depending on what we need the projectiles to do, we could choose a body type for them.
|
||
|
|
||
|
### Area Node Bullet
|
||
|
|
||
|
The area node is probably the simplest way to achieve a projectile. Areas can receive signals when a child collision shape intersects another collision shape (so they know when they have hit something).
|
||
|
|
||
|
An area node also inherits a Transform, with a position property that can be written to.
|
||
|
|
||
|
```
|
||
|
extends Area2D
|
||
|
|
||
|
var speed = 750
|
||
|
|
||
|
func setSpeed(speedVal):
|
||
|
speed = speedVal
|
||
|
|
||
|
func _physics_process(delta):
|
||
|
position += transform.x * speed * delta
|
||
|
|
||
|
func _on_body_entered(body):
|
||
|
# blast the body?
|
||
|
if body.is_in_group("boxes"):
|
||
|
body.queue_free()
|
||
|
queue_free()
|
||
|
```
|
||
|
|
||
|
Now to use our bullet we need to be able to create the bullet and position it with code. This is called instantiation.
|
||
|
|
||
|
To be able to instantiate a scene in Godot we must pre-load it.
|
||
|
|
||
|
`var bullet = preload("res://scenes/bullet.tscn")`
|
||
|
|
||
|
We can now create as many isntances of the bullet as we wish!
|
||
|
|
||
|
But be careful! When we add our bullet to the world, we want to add it at the global scope - not at the scope of the character. Otherwise, when the character moves the bullet will move with them.
|
||
|
|
||
|
```
|
||
|
if Input.is_action_just_pressed("blast"):
|
||
|
var mybullet = bullet.instantiate()
|
||
|
mybullet.setSpeed(-BLAST_SPEED if faceLeft else BLAST_SPEED)
|
||
|
owner.add_child(mybullet)
|
||
|
mybullet.transform = markerLeft.global_transform if faceLeft else markerRight.global_transform
|
||
|
```
|
||
|
|
||
|
### RigidBody Missile
|
||
|
|
||
|
For our next example, we will create our projectile from a RigidBody so that it can react via physics to the environment.
|
||
|
|
||
|
One thing to note about RigidBodies is that they do not by default hear collision signals. This is a performance consideration, and usually this is a good thing, but in the case of our missile we want the RigidBody to know about the collision.
|
||
|
|
||
|
For this reason in the inspector we will need to turn on collision_monitor and set a value in max_collision_objects. After this, we will be able to detect collisions.
|
||
|
|
||
|
```
|
||
|
extends RigidBody2D
|
||
|
|
||
|
func _on_body_entered(body):
|
||
|
# check here to see if the thing should explode
|
||
|
print("missile hit something")
|
||
|
|
||
|
if body.is_in_group("boxes"):
|
||
|
body.queue_free()
|
||
|
if not body.is_in_group("player"):
|
||
|
queue_free()
|
||
|
```
|
||
|
|
||
|
As before, we need to think about instantiation of the missile. Depending on the direction the player is facing, we could either apply a negative or a positive impulse to the RigidBody.
|
||
|
|
||
|
```
|
||
|
if Input.is_action_just_pressed("blast"):
|
||
|
var myMissile = missile.instantiate()
|
||
|
owner.add_child(myMissile)
|
||
|
myMissile.transform = markerLeft.global_transform if faceLeft else markerRight.global_transform
|
||
|
var missileForce = -600 if faceLeft else 600
|
||
|
myMissile.apply_impulse(Vector2(missileForce,10), Vector2(0, 0))
|
||
|
```
|