Instance scene as a child node, but then have it move independently?

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By Eldirish
:warning: Old Version Published before Godot 3 was released.

Hey guys, so my project is a pew pew schmup and while i’m getting by i ran across a problem i’m not sure how to solve:

I have a scene for the player’s bullet which has the object, sprite and behavior of a bullet. I instance that scene trough code in my player scene when the [fire] key is pressed and add it as a child of an Area2d node that’s my muzzle and where the bullet shoots from.

Now that’s all fine and dandy but the bullet, after spawning continues to move relative to the parent(the muzzle node which is a child of the player kinemacticbody2d node), so while it goes up into the screen it also moves left and right with the ship.

Anyway here’s the code in the ship node that deals with the shooting:

func Shoot():

if (shotrate <= 0):
	var shot = shotscene.instance()
	get_node("muzzle").add_child(shot)
	
	print("fire")
	shotrate = shotratedef
	

I’m not sure on how to fix it so the bullet keeps going up but doesnt follow the ship under it, if i don’t make it a child it doesn’t appear, if i remove the child from muzzle after it spawns it disappears.

And if it’s needed too here’s the code for the bullet:


func _fixed_process(delta):

   move( Vector2(0, speed))

Any help’s appreciated, thanks in advance.

:bust_in_silhouette: Reply From: kubecz3k

In 3d there is set_as_toplevel(boolean) but in 2D I havent found anything like that… However you can still get this effect with use of additional node in hierarchy. Each child of the most simple type of node: Node will have position and rotation in global coords.
So example hierarchy might look like this:

*PlayerShip(Area2D)
   *Collision (CollisionShape2D)
   *Sprite (Sprite2D)
   *(...)
   *bulletsHolder (Node)
      *Bullet1 (Your instanced scene)
      *Bullet2 (Your instanced scene)
      *Bullet3 (Your instanced scene)

And here is sample code that you could use:

#inside Player:
#bulletsHolder is the most simple type: 'Node'
var bulletsHolder = get_node("bulletsHolder");
var newBullet = BulletScn.instance();
bulletsHolder.add_child(newBullet);
newBullet.set_position(get_global_pos());

I tried that: enter image description here

But now the shot doesn’t appear, am I doing something wrong?

Eldirish | 2016-04-20 20:18

Helo, from the screen I’m unsure what is going on… but basically you should have a node of the most basic type Node (muzzle is type of Node2D). And then when you add your bullets to this Node you will need to set their start positions manually (since the bullets are now in global world coordinates), for example:

#inside Player:
#bulletsHolder is the most simple type: 'Node'
var bulletsHolder = get_node("bulletsHolder");
var newBullet = BulletScn.instance();
bulletsHolder.add_child(newBullet);
newBullet.set_position(get_position());

kubecz3k | 2016-04-21 09:12

Hi, I tried that, but I get an error: [Invalid call, none existent function “get_pos” in base “Node”],
get_position also gives me the same error, get_pos only appears in the autocomplete of a node2d but it still gives me the same error even tough set_pos gives me no errors. Is this a bug with the engine?

Eldirish | 2016-04-21 13:30

Node is so basic that it don’t even have it’s position, so don’t ask it for position :slight_smile: You can get positions of concrete individual bullets that are children of this node.

kubecz3k | 2016-04-21 15:36

Ah, thanks it works now :slight_smile:

Since it doesnt have a position tough, they’re spawing on top and in the center of my dude
how would I go about changing where the muzzle is, or changing where in relation to the muzzle the bullets spawn and in what layer(?) they live in so to not draw over other sprites?

I’m still getting used to Godot’s way so sorry for all the questions.

Thanks for helping =)

Eldirish | 2016-04-21 17:27

I haven’t done much coding in 2d, but basically each Node2D have set_z and get_z methods, those allow you to set rendering order (what nodes will be above/below). When it comes to ‘muzzle’ I’m not native English speaker and I cant figure out what this means :slight_smile: But basically it seems that you will need yet another one parent inside “bullets(Node)” that will determine origin point for your bullets.

But this is not what is usually needed to handle bullets in Godot. You should just put your bullets inside bulletsHolderNodeNode and reset their position to whatever you wish and let the bullets move on their own (bullet movement code inside bullet scene)

If you are asking on how to set initial position of bullet to some other node (for example Position2D) then new snipped would look like this:

#inside Player:
#bulletsHolder is the most simple type: 'Node'
#bulletsStartPos is type of Position2D, in tree it's located at the top lvl of the player scene
var initBulletGlobalPos = get_node("bulletsStartPos").get_global_pos();
var bulletsHolder = get_node("bulletsHolder");
var newBullet = BulletScn.instance();
bulletsHolder.add_child(newBullet);
newBullet.set_position(initBulletGlobalPos);

take a note that there is get_global_pos() function

kubecz3k | 2016-04-21 18:43

That’s it, all my current issues fixed, thanks alot!

A muzzle is the tip of a gun, where the bullets come out of. So in this case the muzzle is the spot where the bullets spawn and ideally the tip of ship/where the guns are.

Eldirish | 2016-04-21 18:55

I’m glad it’s working for you now! :slight_smile:

kubecz3k | 2016-04-21 19:05

:bust_in_silhouette: Reply From: ulty

I would just sidestep the problem by adding the bullet to the world instead of the player character: add bullet to parent
Other than that you could add the bullet to a Node inside the player character like so( not sure if collision detection works here):add bullet to node

:bust_in_silhouette: Reply From: SupToasty

I usually get the position of the desired spawn point and set my bullets’ starting positions to that same point. Then I get_node("../").add_child(bullet instance) where "../" is the parent of the object creating the bullet.

var bullet = preload("bullet scn path")
 
 #code that changes muzzle pos when player looks left and right
 
if(check if bullet should spawn):
    var bullet_instance = bullet.instance()
    bullet_instance.set_pos(get_pos() + get the muzzle pos)
    get_node("../").add_child(bullet_instance)

Note that get_node("../") gets the immediate parent, so if the problem persists use get_node("../../") to get the grandparent instead.

get_pos gives me an invalid call error when using both node and node2d for the muzzle, even tough when i use node2d the intelisense has “get_pos” in its options

Eldirish | 2016-04-21 13:32

That is my fault I forgot to add the get_pos() like this:

var muzzle_pos = (self.get_pos() + get_node("muzzle").get_pos())
bullet_instance.set_pos(muzzle_pos)

If this does not resolve your problem make sure that the muzzle is a Position2D node and that it is a child of the object spawning the bullets and not the actual object spawning the bullets. Oh and add_child(bullet_instance) should come after the set_pos().

SupToasty | 2016-04-21 22:25

It’s ok the issue’s fixed thanks for helping =)

Eldirish | 2016-04-22 13:06