0 votes

i want to make boss that can shoot from 10 different direction and position .how to make this kind code/script short/less mess/easy to modified.

bullet scene

extends Area2D

export (int) var speed
var velocity = Vector2()


func start_position(new_position,new_rotation):
    position = new_position
    rotation = new_rotation.angle()
    velocity = new_rotation* speed


func _process(delta: float) -> void:

    position += velocity*delta

entity scene

extends Sprite

signal shoot


var bullet = preload("res://bullet.tscn")
export (float) var gun_cooldown
var can_shoot = true



func _ready() -> void:
    $gun_speed.wait_time = gun_cooldown

func _process(delta: float) -> void:
    pass
func _input(event: InputEvent) -> void:
    pass

func shoot():
    if can_shoot:
        can_shoot = false

        $gun_speed.start()
        var bullet_dir1 = global_dir.right.rotated($gun1.global_rotation)
        var bullet_dir2 = global_dir.up.rotated($gun2.global_rotation)
        var bullet_dir3 = global_dir.down.rotated($gun3.global_rotation)
        var bullet_dir4 = global_dir.left.rotated($gun4.global_rotation)
        var bullet_dir5 = global_dir.right.rotated($gun5.global_rotation - 0.3) 
        var bullet_dir6 = global_dir.right.rotated($gun6.global_rotation + 0.3) 
        var bullet_dir7 = global_dir.right.rotated($gun7.global_rotation + 1) 
        var bullet_dir8 = global_dir.right.rotated($gun8.global_rotation - 1) 
        var bullet_dir9 = global_dir.right.rotated($gun9.global_rotation)
        var bullet_dir10= global_dir.right.rotated($gun10.global_rotation)
        #############################################################################################
        var bullet_pos1 = $pos1.global_position
        var bullet_pos2 = $pos2.global_position
        var bullet_pos3 = $pos3.global_position
        var bullet_pos4 = $pos4.global_position
        var bullet_pos5 = $pos5.global_position
        var bullet_pos6 = $pos6.global_position
        var bullet_pos7 = $pos7.global_position
        var bullet_pos8 = $pos8.global_position
        var bullet_pos9 = $pos9.global_position
        var bullet_pos10 = $pos10.global_position

        emit_signal("shoot",bullet,bullet_pos1,bullet_pos2,bullet_pos3,bullet_pos4,bullet_pos5,bullet_pos6,bullet_pos7,bullet_pos8,bullet_pos9,bullet_pos10,bullet_dir1,bullet_dir2,bullet_dir3,bullet_dir4,bullet_dir5,bullet_dir6,bullet_dir7,bullet_dir8,bullet_dir9,bullet_dir10)


func _on_gun_speed_timeout() -> void:
    can_shoot = true

map scene

extends Node2D




func _on_player_shoot(bullet,bullet_pos1,bullet_pos2,bullet_pos3,bullet_pos4,bullet_pos5,bullet_pos6,bullet_pos7,bullet_pos8,bullet_pos9,bullet_pos10,bullet_dir1,bullet_dir2,bullet_dir3,bullet_dir4,bullet_dir5,bullet_dir6,bullet_dir7,bullet_dir8,bullet_dir9,bullet_dir10) -> void:
    var instance_bullet1 = bullet.instance()
    var instance_bullet2 = bullet.instance()
    var instance_bullet3 = bullet.instance()
    var instance_bullet4 = bullet.instance()
    var instance_bullet5 = bullet.instance()
    var instance_bullet6 = bullet.instance()
    var instance_bullet7 = bullet.instance()
    var instance_bullet8 = bullet.instance()
    var instance_bullet9 = bullet.instance()
    var instance_bullet10 = bullet.instance()


    instance_bullet1.start_position(bullet_pos1,bullet_dir1)
    instance_bullet2.start_position(bullet_pos2,bullet_dir2)
    instance_bullet3.start_position(bullet_pos3,bullet_dir3)
    instance_bullet4.start_position(bullet_pos4,bullet_dir4)
    instance_bullet5.start_position(bullet_pos5,bullet_dir5)
    instance_bullet6.start_position(bullet_pos6,bullet_dir6)
    instance_bullet7.start_position(bullet_pos7,bullet_dir7)
    instance_bullet8.start_position(bullet_pos8,bullet_dir8)
    instance_bullet9.start_position(bullet_pos9,bullet_dir9)
    instance_bullet10.start_position(bullet_pos10,bullet_dir10)

    add_child(instance_bullet1)
    add_child(instance_bullet2)
    add_child(instance_bullet3)
    add_child(instance_bullet4)
    add_child(instance_bullet5)
    add_child(instance_bullet6)
    add_child(instance_bullet7)
    add_child(instance_bullet8)
    add_child(instance_bullet9)
    add_child(instance_bullet10)

player scene

extends "res://entity.gd"


func _process(delta: float) -> void:
    if Input.is_action_pressed("Lclick"):
        shoot()

autoload global_dir

extends Node

var idle = Vector2(0,0)
var right = Vector2(1,0)
var left = Vector2(-1,0)
var up = Vector2(0,-1)
var down = Vector2(0,1)
in Engine by (390 points)
edited by

Try creating a loop. In this case a for loop would be better as there is a specified amount.

2 Answers

+1 vote

Here's my take on it:

Bullet

extends KinematicBody2D

const SPEED : int = 400

var direction : Vector2 = Vector2.ZERO

func init(origin) -> void:
    global_position = origin.global_position
    global_rotation = origin.global_rotation
    direction = origin.position.normalized()

func _physics_process(delta) -> void:
    var collision = move_and_collide(direction * SPEED * delta)
    if collision: queue_free()

I changed the base node from an Area2D to a KinematicBody2D here, as I assumed you'd like your bullets to collide with your bodies and I consider it easier to use move_and_collide for this than the body_entered-signal.

Player

extends KinematicBody2D

const BULLETS : int = 10
const MUZZLE_DISTANCE : float = 40.0

signal shoot

func _ready() -> void:
    var container = Node2D.new()
    container.name = "Muzzles"
    add_child(container)

    for i in range(BULLETS):
        var muzzle = Position2D.new()
        muzzle.position = Vector2(MUZZLE_DISTANCE, 0).rotated(i * 2*PI/BULLETS)
        muzzle.rotation = muzzle.position.angle()
        container.add_child(muzzle)

func _process(delta: float) -> void:
    if Input.is_action_just_pressed("Lclick"):
        emit_signal("shoot")

I changed the base node from a Sprite to a KinematicBody2D here, as I assumed you'd like your boss to move later on while checking for collisions.
For brevity I omitted the whole can_shoot-thing here, it's perfectly fine though.

Map

extends Node2D

var BULLET : PackedScene = preload("res://Bullet.tscn")

func _ready() -> void:
    $Player.connect("shoot", self, "spawn_bullets", [$Player])

func spawn_bullets(player : KinematicBody2D) -> void:
    for muzzle in player.get_node("Muzzles").get_children():
        var new_bullet = BULLET.instance()
        new_bullet.init(muzzle)
        $Bullets.add_child(new_bullet)

Here I assume that the map-node has a Node2D-child named "Bullets", acting as a container for every bullet that is spawned (regardless of whom spawned it).

by (10,327 points)

thank you for your help.
can you explain bit about this part to me?

    muzzle.position = Vector2(MUZZLE_DISTANCE, 0).rotated(i * 2*PI/BULLETS)
    muzzle.rotation = muzzle.position.angle()

and why i just get 2 direction? here result in youtube video

I decided to place a muzzle for each of the BULLETS equidistantly on a circle. So I took a Vector of length MUZZLE_DISTANCE (equal to the circle radius) pointing to the right and rotate it depending on which muzzle it is: For the first muzzle i will be 0, so I don't rotate the Vector and the muzzle is placed to the right of the player. For the second muzzle i will be 1, so this time we rotate the Vector! Rotating it by 2*PI is the same as rotating it by 360°: a full circle. As we know how many bullets we want to shoot, we also know in how many equidistant parts we have to split that full circle of 360°: We just have to divide 2*PI by the number of BULLETS. So for 10 bullets, the second muzzle will be rotated by one such part (equaling 36°), the third muzzle will be rotated by two such parts (equaling 72°) and so on.

Now all your muzzles are in the right position! However, if you spawn bullets in those positions they will all move into the same direction as all muzzles still use the same coordinate system and are just offset from each other. The second line fixes this issue by rotating each muzzles coordinate system individually. This way you end up with a system, where you can give each bullet the same instruction ("move right") and it will result in different directions, because every muzzle has it's own version of "right".

Now in order to fix your problem, you would need to increase the circle radius, i.e. choose a higher MUZZLE_DISTANCE. As of now most positions on the circle (all except the one to the left and right) happen to lie inside the players collision shape. So you spawn the bullets, but they instantly collide and are freed again. Alternatively you could put your player scene and your bullet scene on different collision layers, so they cannot collide with each other. Or of course remove collision detection altogether.

+1 vote

I can't test it, so you might have to fix a typo or two, but try this.

Entity Scene

extends Sprite

enum DIR {LEFT, RIGHT, UP, DOWN}
enum INDEX {OFFSET = 0, DIR_ENUM = 1}

const max_bullet_count := 10

const rotation_dict := {
    1: [0, DIR.RIGHT],
    2: [0, DIR.UP],
    3: [0, DIR.DOWN],
    4: [0, DIR.LEFT],
    5: [-0.3, DIR.RIGHT],
    6: [0.3, DIR.RIGHT],
    7: [1, DIR.RIGHT],
    8: [1, DIR.RIGHT],
    9: [0, DIR.RIGHT],
    10: [0, DIR.RIGHT],
    }


const k_Bullet_Direction := "Bullet Direction"
const k_Bullet_Position := "Bullet_Position"

var rotation_dict_keys := rotation_dict.keys()
var rotation_dict_val_arrays := rotation_dict.values()
var instanced_bullet_data := {}

var bullet = preload("res://bullet.tscn")
var can_shoot = true
export (float) var gun_cooldown    

func _ready() -> void:
    $gun_speed.wait_time = gun_cooldown

func _process(delta: float) -> void:
    pass

func _input(event: InputEvent) -> void:
    pass


func get_rotated_gun_dir(__dir_enum : int,
                            __int_key : int,
                            __offset : float):

    assert(DIR.values().has(__dir_enum))
    var __c_node : Node = get_node("gun" + str(__int_key))
    assert(__c_node)
    var __c_global_rotation = __c_node.global_rotation

    match __dir_enum:
        DIR.LEFT:
            return global_dir.left.rotated(__c_global_rotation)
        DIR.RIGHT:
            return global_dir.right.rotated(__c_global_rotation)
        DIR.UP:
            return global_dir.up.rotated(__c_global_rotation)
        DIR.DOWN:
            return global_dir.down.rotated(__c_global_rotation)
        _:
            assert(false)   
    pass



func shoot():
    if can_shoot:
        can_shoot = false

        $gun_speed.start()

        var __all_collections := [
            rotation_dict,
            rotation_dict_keys,
            rotation_dict_val_arrays,
            ]

        for __collection in __all_collections:
            assert(__collection.size() == max_bullet_count)

        instanced_bullet_data.clear()

        for __i in max_bullet_count:
            var __c_int_key : int = rotation_dict_keys[__i]
            var __c_pos_node : Node = get_node("pos" + str(__c_int_key))
            assert(__c_pos_node)        

            var __c_rotation_array : Array = rotation_dict_val_arrays[__i]
            var __c_offset : float = float(__c_rotation_array[INDEX.OFFSET])
            var __c_dir_enum : int = __c_rotation_array[INDEX.DIR_ENUM]

            var __c_bullet_pos : Vector2 = __c_pos_node.global_position
            var __c_dir = get_rotated_gun_dir(__c_dir_enum,
                                                __c_int_key,
                                                __c_offset)

            instanced_bullet_data[__c_int_key] = {}
            assert(instanced_bullet_data.has(__c_int_key))
            var __c_data : Dictionary = instanced_bullet_data[__c_int_key]

            __c_data[k_Bullet_Direction] =  __c_dir 
            __c_data[k_Bullet_Position] =  __c_bullet_pos

        assert(instanced_bullet_data.size() == max_bullet_count)
        emit_signal("shoot", bullet, instanced_bullet_data)
        pass

Map Scene

extends Node2D

func _on_player_shoot(__bullet : PackedScene,
                        __instanced_bullet_data : Dictionary) -> void:
    assert(__bullet)
    assert(__instanced_bullet_data.size() == max_bullet_count)

    for __i in max_bullet_count:
        var __instance_bullet = __bullet.instance()
        var __c_pos = __instanced_bullet_data[k_Bullet_Position]
        var __c_dir = __instanced_bullet_data[k_Bullet_Direction]
        __instance_bullet.start_position(__c_pos, __c_dir)
        add_child(__instance_bullet, true)
by (226 points)
edited by
Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to webmaster@godotengine.org with your username.