**Title says all. How would I go about coding an upgrade where after the player character picks up a specific item, they temporarily get the ability to fire 3 shots. One shot would fly forward and the other two would fly in a diagonal manner.
Some specifics I’ll note is that my game uses a top down perspective and for shooting, it uses the current mouse position on the screen and shoots whenever I press the left mouse button.
I can also post what I’ve coded so far regarding the shooting controls and powerups if it would be helpful regarding what code I can add in and where. Thanks!**
I aim to manage the number of additional shots dynamically.
For instance, if I decide to offer 5 additional shots instead of 3, I would utilize a variable named shots_remaining and adjust its value within the pickup_powerup() function.
Simultaneously, I’d implement a timer mechanism to reset shots_remaining back to 1 upon its expiration, which would be handled by the reset_powerup() function. Within the shoot() function, I’d instantiate bullet instances corresponding to the current shots_remaining value, adjusting their directions accordingly for diagonal shooting angles.
I see, if possible, do you know of a code that can be used to apply the diagonal shooting angles to the 2 bullets that are meant to travel in diagonal directions?
Kinda new to Godot, but the Vector2 class supports inputs in polar coordinates. I presume you have the mouse x and y in a Vector2 instance. Using the Vector2’s rotated() function, you could take the vector to the mouse, spawn a bullet, rotate by, say, pi/4 radians, spawn a bullet, rotate the mouse vector by -pi/4 radians, spawn a bullet, all in one frame. I haven’t tested it, but that should work.
bullet_instance.global_rotation = global_rotation # for one bullet
# for 3 bullets:
for i in tree_bullets:
var bullet_instance = bullet.instantiate()
var inc = (i - 1)* 0.5 # 0.5 rad I guess - not sure rad or deg here
bullet_instance.global_rotation = (
global_rotation + inc
get_tree().root.call_deferred('add_child', bullet_instance)
I never tested it in godot. This is the way I would do it.
Hmm, would you mind if I share the code of my Bullet Scene, Bullet Manager Scene, and Player Scene? I feel like showing what I have coded so far might help out here.
extends Area2D
var speed : int = 600
var direction : Vector2
# Called every frame. 'delta' is the elapsed time since the previous frame.
#Bullet Physics
func _process(delta):
position += speed * direction * delta
func _on_timer_timeout():
queue_free()
#Code for killing enemies with bullets
func _on_body_entered(body):
if body.name == "World":
queue_free()
else:
if body.alive:
body.die()
queue_free()
Here’s the code for my Bullet Manager, the scene which handles my bullets in the game:
extends Node2D
#Used to get the scene for bullets
@export var bullet_scene : PackedScene
func _on_player_shoot(pos, dir):
var bullet = bullet_scene.instantiate()
add_child(bullet)
bullet.position = pos
bullet.direction = dir.normalized()
bullet.add_to_group("bullets")
Lastly, here’s the code for my player, the controls and powerups are handled here:
extends CharacterBody2D
signal shoot
@onready var hurtblink = $HurtBlink
@onready var hurttimer = $HurtTimer
const START_SPEED : int = 200
const BOOST_SPEED : int = 400
const NORMAL_SHOT : float = 0.5
const FAST_SHOT : float = 0.1
var speed : int
var screen_size : Vector2
var can_shoot : bool
func _ready():
screen_size = get_viewport_rect().size
reset()
hurtblink.play("RESET")
func reset():
can_shoot = true
position = screen_size/2
speed = START_SPEED
$ShotTimer.wait_time = NORMAL_SHOT
# Called when the node enters the scene tree for the first time.
func get_input():
var input_dir = Input.get_vector("left", "right", "up", "down")
velocity = input_dir.normalized() * speed
#Handle shooting when pressing left mouse button
if Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT) and can_shoot:
var dir = get_global_mouse_position() - position
shoot.emit(position, dir)
$Shoot.play()
can_shoot = false
$ShotTimer.start()
if Input.is_action_pressed("pause"):
get_tree().paused = true
$PauseMenu.visible = true
func _physics_process(_delta):
get_input()
move_and_slide()
#limit movement to window size
position = position.clamp(Vector2.ZERO, screen_size)
var mouse = get_local_mouse_position()
var angle = snappedf(mouse.angle(), PI / 4) / (PI / 4)
angle = wrapi(int(angle), 0, 8)
$AnimatedSprite2D.animation = "walk" + str(angle)
if velocity.length() != 0:
$AnimatedSprite2D.play()
else:
$AnimatedSprite2D.stop()
$AnimatedSprite2D.frame = 1
#Code for when player picks up a speed powerup
func boost():
$BoostTimer.start()
$CoffeePickup.play()
speed = BOOST_SPEED
#Code for when player picks up a firing speed powerup
func quick_fire():
$FastFireTimer.start()
$GunPickup.play()
$ShotTimer.wait_time = FAST_SHOT
#Code for when player picks up an extra life, rest of code is handled in the main game scene
func extralife():
$LifePickup.play()
func on_hit():
hurtblink.play("hurtblink")
hurttimer.start()
await hurttimer.timeout
hurtblink.play("RESET")
func _on_shot_timer_timeout():
can_shoot = true
func _on_boost_timer_timeout():
speed = START_SPEED
func _on_fast_fire_timer_timeout():
$ShotTimer.wait_time = NORMAL_SHOT
func _on_resume_button_pressed():
get_tree().paused = false
$PauseMenu.visible = false
func _on_quit_button_pressed():
get_tree().change_scene_to_file("res://scenes/title_screen.tscn")
looks like you need to rotate a normalize direction to an angle to ±30° for example. Choose your own degree.
instantiate more 2 bullets and set direction like code below:
The Bullet Manager script would be the best place to put it. The best way I could think of implementing this is something like this: Add an argument to the Shoot signal called bullet number or something like that. Then in the Bullet Manager, check the number of bullets, and add that many bullets. The benefit of this is if you wanted to add a rare 5-shot power up, you could. The code might look something like this:
func set_bullet():
var bullet = bullet_scene.instantiate()
add_child(bullet)
bullet.position = pos
func _on_player_shoot(pos, dir, num):
set_bullet()
bullet.direction = dir.normalized()
bullet.add_to_group("bullets")
if num == 3
set_bullet()
bullet.direction = dir.rotated(1/6 * pi).normalized()
#directions in godot use radians and 1/6 pi radians is 30 degrees
#you can change this number if you want.
bullet.add_to_group("bullets")
set_bullet()
bullet.direction = dir.rotated(-1 * 1/6 * pi).normalized()
bullet.add_to_group("bullets")