Tutorial (Godot Engine v3 - GDScript) - Colour use! by sp33dy

View this thread on steempeak.com
· @sp33dy · (edited)
$33.67
Tutorial (Godot Engine v3 - GDScript) - Colour use!
# ![Godot Engine Logo v3 (Beginner).png](https://steemit-production-imageproxy-upload.s3.amazonaws.com/DQmenztXPYjpJLwd6Y1rTfWEUX9g5tsYMEhty5PzaKmaFcZ)   Tutorial

![](https://steemit-production-imageproxy-thumbnail.s3.amazonaws.com/DQmeRXYK5hTURHD9TqUuGi4vPsockATFzcKFZdawUYpq24B_1680x8400) ...learn to add colour to the game!

# What Will I Learn?
I ended the last Tutorial stating that the next step is to add colour to the game! 

If you've tried the ["Space Invaders"](https://sp33dy.itch.io/alien-invaders) clone on itch.io, you will already be aware of what I mean by this; i.e. I've implemented a touch of colour! 

The invaders begin with random colours and the player may select a ship colour, by pressing up/down. If an Invader is struck by a bullet of a matching colour, it is destroyed, otherwise, it raises its shield; thereby protecting it.

I'm going to show you how to add these features!

<center>
![shields a working.gif](https://res.cloudinary.com/hpiynhbhq/image/upload/v1521327237/x4u5lsutrozce9pddwbs.gif)
</center>
<center>Note: the recording method does so at 30fps</center>
<center>therefore it ruins the quality throughout this article!</center>

----

### Assumptions
> * You have installed [Godot Engine v3.0](https://steemit.com/gamedev/@sp33dy/installing-godot-engine-v3-0-windows)
> * You are familiar with GDScipt
> * You are familiar with the previous tutorials

### You will

* Add Screen Wrap Node to the player ship
* Change the screen to HD resolution
* Add multi-coloured Invaders
* Add colour to the Player's Ship
* Add colour to the lasers
* Add shields to the Invaders

# Requirements

You must have installed [Godot Engine v3.0](https://steemit.com/gamedev/@sp33dy/installing-godot-engine-v3-0-windows).

All the code from this tutorial is provided in a [GitHub repository](https://github.com/sp33dy/Godot-v3-Tutorials-Competent). I'll explain more about this, towards the end of the tutorial. You may want to download this

----

# Add Screen Wrap Node to the player ship
I've written a competent level [article](https://steemit.com/utopian-io/@sp33dy/tutorial-godot-engine-v3-gdscript-generic-screen-wrapping-node) explaining how to build and apply an [Asteroid]() style screen wrap to any _Node2D_ class.

We shall take the code from its project and apply it to the _Player_ Scene. 

> You will need to access the [GitHub source files](https://github.com/sp33dy/Godot-v3-Tutorials-Competent/tree/master/Screen%20Wrap%20Node)

![image.png](https://res.cloudinary.com/hpiynhbhq/image/upload/v1521306060/pjgmhkrblipusm9tyepp.png)

You require a copy of the ScreenWrap folder, along with its content; two files.

With this copied into place, open up the _Player_ Scene and add a ScreenWrap instance:

![image.png](https://res.cloudinary.com/hpiynhbhq/image/upload/v1521306202/mx08wjbbgjcu6jlqpsvo.png)

The following structure is formed for the Player Ship (I've moved the ScreenWrap instance up, but there is no necessity to do so; as long as it remains a child of the Sprite)
![image.png](https://res.cloudinary.com/hpiynhbhq/image/upload/v1521306253/ergryczdmv9cwslaab48.png)

Try running the game now, does it work?

... the answer is no. Do you know why?

When we previously added the _Player_ script, we deliberately restricted the player to the edges, because the ship was sailing off the edges. 

Given we now have a wrap solution, we should remove the clamps.

Open the _Player_ Scene and edit its script:
![image.png](https://res.cloudinary.com/hpiynhbhq/image/upload/v1521306819/pxplj5c6uib0bsbcetut.png)

Remove the four highlighted rows 24 to 27, pinning the _Ship_ to the borders.

Try rerunning!

![wrapping.gif](https://res.cloudinary.com/hpiynhbhq/image/upload/v1521307419/a3av1fxtnjcr8mqrlk3c.gif)

This demonstrates how easy it is to add the _Wrap node_ into any project. 

## Let's tidy up the code a little more before we move on.
The _Move_ function can be compressed to this:

    func move(adjustment):
    	position.x = position.x + adjustment.x

Given we aren't clamping to the borders, there is no need to maintain the additional variable

In the _ready_ function, there is no need to calculate the borders, therefore we can delete the following highlighted rows

![image.png](https://res.cloudinary.com/hpiynhbhq/image/upload/v1521307564/hdldeciuu5im6oomnmbu.png)

Rows 14, 15 & 16

You can also delete the two _Class_ variables above the function; rows 8 & 9.

These small little improvements shrink and cleanse the script, making it much easier to understand.

#  Change the screen to HD resolution
Although the following steps weren't absolutely necessary for this tutorial. I felt an urge to remove my concern and issue with the game resolution. 

> I dislike the default 1024 x 600 resolution

Further to this, it doesn't lend itself to resizing for different devices; thus, fixing this now, will save pain down the road.

Please open up the Project Settings and set the screen to 1920 x 1080, the standard resolution for HD (High Definition).
![image.png](https://res.cloudinary.com/hpiynhbhq/image/upload/v1521309021/gqsc34njfmdtlbf3m9ql.png)

If you run the game again, you'll notice the screen becomes extremely wide and everything is misplaced.

Resolutions will be different on devices, i.e. an iPhone will be different to an Android, an iPad will be different to another Tablet, even a monitor will be sold with different capabilities.

What we need to do is build this 'Space Invaders' clone, with the capability of adapting to any device.

> ...but how are we going to do that?

The decision for this game is to build it to operate at a High Definition resolution and then scale up/down as required.

Godot Engine supports this for us, through its Project Settings.

#### Correct the stars
Since we changed to HD resolution, the star background is smaller than the screen size, we need to stretch it again:
![image.png](https://res.cloudinary.com/hpiynhbhq/image/upload/v1521309974/swo8dsftknx824ndfelr.png)

We will replace this fixed image for dynamic particles soon, but for now, open the _Stars_ Scene. Click on the Sprite and change the _Node_ Inspector property Transform/Scale to 2 x 2:
![image.png](https://res.cloudinary.com/hpiynhbhq/image/upload/v1521310132/vlf6nwdx1h4grp6hiodi.png)

This will double the size of the image. When you save and return back to the _Game_ Scene, it shall be filled with stars again!
![image.png](https://res.cloudinary.com/hpiynhbhq/image/upload/v1521310185/krjun3r7lnxiwfxxjsua.png)

> If you don't use 2 x 2, but instead use say 2 x 1, the Stars will fit, but will be squashed in aspect, i.e. you double its width but would retain its height (like one of those magic mirrors at the funfair)

When you run the game now, a massive window will open again, with the Stars present. However, it is all too large (unless you have a 4k monitor; lucky whats-it!).

Let's use one of the really neat features of Godot-Engine. It has the capability to correct the size by shrinking or stretching as required!

Scroll to the bottom of the Project Settings of the Window
![image.png](https://res.cloudinary.com/hpiynhbhq/image/upload/v1521309438/nqz5ufpw7ddzqndrsbao.png)

> * Change the Stretch/Mode property to 2D
> * Change the Aspect property to Keep (which is keep the aspect ratio based on both axes)

Scroll back up to the Size properties and enter 960 for Test Width and 540 for Test Height.
![image.png](https://res.cloudinary.com/hpiynhbhq/image/upload/v1521310406/lhvqukfmpf1prewuggse.png)

> If you have the luxury (I don't) of a monitor with greater than HD resolution, I recommend you don't set this setting! You can develop in full HD mode; oh, how I lust for a 4K monitor.

Assuming you don't have a tiny monitor when you rerun, normality will return!
<center>
![image.png](https://res.cloudinary.com/hpiynhbhq/image/upload/v1521310441/z5iezpeytxrxt14tdn3v.png)
</center>

A sensibly sized window will display! In effect, we've increased our resolution to HD and then instructed Godot Engine to scale it to half HD size; this will be easily displayable by the monitor, although we've LOST half the quality of the graphics. For devices that do have the resolution, they benefit from greater clarity!

If you play with the test sizes, you'll see how Godot Engine deals with different resolutions. It will automatically scale and add black bars where it needs to, in order to preserve the screen aspect.

> Aspect is measured and discussed as a ratio. I.E. take 1920 and divide by 1080, you get an aspect ration of 1.77 (recurring). 
> To fill the screen, the pixels cannot be square, or you would have a TV with an aspect ratio of 1. 
> Instead, the pixels will be wider than they are high!
> I.E. for every vertical pixel it will be wider than a single pixel, in fact, 1.77-pixel size for HD Aspect! Therefore, if you draw a square of 10 pixels high, it will measure ~17.777 pixels wide!

When a game is loaded by a non-HD device, we want it to maintain these pixels. I.E. we've configured Godot Engine to keep to Both Aspects, but there are other options, i.e. maintain only horizontal or vertical, or ignore aspect etc! Have a play with the different settings.

Once the game is ready, we will enable FULL SCREEN. 

The full resolution of the device would then influence how the game initialises. With our configuration, it would respect our Aspect Ratio, ensuring the design of our game remains good on any device, Albiet with potential black bars to pad it out!

#### Fix _Player_ ship
With the new resolution, you will notice our _Player_ now starts in the wrong place, let's move it by implementing a 'start position' in its script.

Here are the new lines of the script (top half of entire script):
![image.png](https://res.cloudinary.com/hpiynhbhq/image/upload/v1521312564/l2gbh8m4m1ttw6sa7zp4.png)

    var screenWidth = ProjectSettings.get_setting("display/window/size/width")
    var screenHeight = ProjectSettings.get_setting("display/window/size/height")
> I've added the fetch for the screen height (line 7)

    func _ready():
    	moveToStartPosition()
    	$Area2D.connect("area_entered", self, "hit")

> I've added the call to the _moveToStartPosition_ function to the _ready_ function (line 12)

    func moveToStartPosition():
    	var halfSpriteSize = (texture.get_size() / 2) * scale
    	position = Vector2(screenWidth/2, screenHeight - halfSpriteSize.y)
> The new function calculates the sprite size, halves it and then scales the resultv(line 16)
> The ship is then moved to the centre on the horizontal and a half a sprite height up from the bottom on the vertical axis (line 17)

However, if you run this, something very peculiar occurs!
<center>
![wrapping bug.gif](https://res.cloudinary.com/hpiynhbhq/image/upload/v1521312902/qtnllumqxouvgsumxhht.gif)
</center>

The Ship is restricted to the left and middle of the screen wrapping!

> I've inadvertently discovered a BUG in the generic _ScreenWrap Node_!!!!!!

Given we are now using the Screen Stretching Aspect of Godot Engine, the generic code uses the _get_viewport_ function to obtain the screen size. However, the viewport is the actual size of our Test Window setting or Device, NOT our intended Screen Size setting of the project Setting!

A fix is required in the generic _Screen Wrap Node_! Open the ScreenWrap script and change the initWrapArea function to this:

    # Initialise the wrap area to screen size if not set
    func initWrapArea():
    	if wrapArea == null:
    		var screenWidth = ProjectSettings.get_setting("display/window/size/width")
    		var screenHeight = ProjectSettings.get_setting("display/window/size/height")
    		wrapArea = Rect2(Vector2(), Vector2(screenWidth, screenHeight))
> I've removed the get_viewport().size in the wrapArea assignment and replaced it with a new Vector2 create using the screen Width and Height, obtained from the ProjectSettings

If you run the game again, all is well in the world!
<center>
![fixed wrap.gif](https://res.cloudinary.com/hpiynhbhq/image/upload/v1521313331/hbyoui0nguc8zg7yb9oj.gif)
</center>

The automatic aspect is applied for us, but our Ship moves to the original dimensions (of HD)! This neatly illustrates my point! We can design the game at HD quality and Godot will automatically scale it to different resolutions, allowing us to forget about individual devices. This technique doesn't work for all games, but it does for the majority. If you need absoutely EVERY pixel of a specific game at a specific Aspect resolution, you would build each time individually.

IF I'd not thought of dealing with the device sizes today, I would have discovered the problem of my generic wrap node a long way down the development path. For which it might have been a LOT harder to rectify. So this is actually a good catch! Although, I hate making obvious errors like this.

#### Resize the Ship
Let's resize the ship to something that will look reasonable onscreen, safe in the knowledge it will look right when scaled to all devices.

I like the Ship scale set to (0.8, 0.8):
![image.png](https://res.cloudinary.com/hpiynhbhq/image/upload/v1521313665/mefdfdg8jerdp2ydeclu.png)

Feel free to experiment and set what you like! 

Resizing works because we've included the _scale_ value in our calculations. It is important to remember that Scale is applied to all textures. When I first learnt Godot, this and rotation, kept tripping me up!

#### Resize the Invaders
As with the Ship, let's turn our attention to the Invaders!

The current Invader image is relatively small, therefore I like the (1, 1) scale; but we'll revisit this when we add other types of Invader.
![image.png](https://res.cloudinary.com/hpiynhbhq/image/upload/v1521313971/nouuolaaojekhfsdtlet.png)

On running the game, I'm happier because it looks much better. A small tweak to the scale of the laser bullet (0.8, 0.8) completes the job!
![resized.gif](https://res.cloudinary.com/hpiynhbhq/image/upload/v1521314294/rcaehwommkmmbx5pxfkc.gif)

Looking at the result, I will increase the velocity of the bullets shortly; see if you can figure that out for yourself?!?!

# Add multi-coloured Invaders
Finally, we join the mission at hand. Let's introduce coloured Invaders!

Making them different colours is a trivial task of amending the _Invader_ Scene script.

First, we add in a constant variable that will preload each individual Invader image:

    const INVADER_TYPES = [
    	preload("res://Invader/images/spaceship-white-03.png"),
    	preload("res://Invader/images/spaceship-red-03.png"),
    	preload("res://Invader/images/spaceship-yellow-03.png"),
    	preload("res://Invader/images/spaceship-blue-03.png"),
    	preload("res://Invader/images/spaceship-grey-03.png"),
    	preload("res://Invader/images/spaceship-black-03.png")
    ]

The _preload_ does exactly that. It instructs Godot to load the image into its cache, ready for use by the script.

Given we have an array, we can pick an image at random, by referencing the array[position]! Thus, we can assign one of these to the Sprite's texture property and the correct Sprite with Colour will show.

Next, we'll add a property to _Invader_ so that the colourType can be set.

    export (int, "WHITE", "RED", "YELLOW", "BLUE", "GREY", "BLACK") var colourType setget setColourType

This variable is exposed as a property for the _Node_ Inspector, because individual Invaders may be added via the 2D view. ... but I also wanted to show the possibilities that export provides! As you can see, I've listed each colour as a String, but when selected in the Inspector, an integer is returned, representing the position; i.e. 0 is White,1 is Red, and so forth.

    func setColourType(newColourType):
    	if newColourType != null:
    		colourType = newColourType
    		texture = INVADER_TYPES[colourType]
> A _setColourType_ function is required. This is called by either the _setget_ condition, when the colourType is set by the tool or by other external classes. 
> It first determines if a new colour type (integer) has been provided, ignoring it if not; this is important because on an initialise, a null value can be received.
> Given a value is present, set the local variable (because the setget doesn't do this automatically) and then set the Sprite's texture to the colour image found in the constant array.

    func setSize():
    	size = texture.get_size() * get_scale()
> The size was originally calculated in the _init_ function, but I've lifted it into its own separate function for clarity and reuse

    func initType():
    	if colourType == null:
    		var pick = randi() % INVADER_TYPES.size()
    		setColourType(pick)
> A new _initType_ function is added and called by the _init_ function (below)
> If the initialise stage is triggered and the _colourType_ remains null, we will randomly pick a colour instead. Therefore the random integer function is called with the number of images in the array. This value is then sent to the _setColourType_ function, which sets the texture!

    func _init():
    	initType()
    	setSize()
> The new initialise function ensures a type has been set before the size function establishes the Sprites size; if it isn't, there is no loaded texture and the initialise can't happen (i.e. there is nothing loaded to gauge a size from)

Running the game now results in what we expected:
<center>
![coloured invaders.gif](https://res.cloudinary.com/hpiynhbhq/image/upload/v1521317145/f0zkusgklaerjbiipjg4.gif)
</center>

See if you can add colour to the Player ship; hint, it is very similar, but you need to think about the user control!

# Add colour to Player ship
Adding colour to the ship is a similar process to the _Invader_. Add the constants and _colourType_, ensuring you set the correct image paths for the Player ship!

    const PLAYER_TYPES = [
    	preload("res://Player/images/spaceship-white-07.png"),
    	preload("res://Player/images/spaceship-red-07.png"),
    	preload("res://Player/images/spaceship-yellow-07.png"),
    	preload("res://Player/images/spaceship-blue-07.png"),
    	preload("res://Player/images/spaceship-grey-07.png"),
    	preload("res://Player/images/spaceship-black-07.png")
    ]

    export (int, "WHITE", "RED", "YELLOW", "BLUE", "GREY", "BLACK") var colourType setget setColourType

> As stated, the preload is for the Player image, rather than Invader, but it looks similar
> We also keep the _colourType_ variable

    func setColourType(newColourType):
    	if newColourType != null:
    		colourType = newColourType
    		texture = PLAYER_TYPES[colourType]

    func _init():
    	setColourType(0)

> We reuse the same _setColourType_ function and ensure it is called by the initialise function; hardwiring it to zero (White)

If you run the game, you'll note the Player now starts in white!

...but how does the player change colour? We want them to use the up/down cursor key, so we need to adjust the _Game_ script and add a function to the _Player_ script to modify the colour.

Let's start by adding a function to the _Player_ script:

    func adjustColour(adjust):
    	var newColourType = colourType + adjust
    	if newColourType < 0:
    		newColourType += PLAYER_TYPES.size()
    	elif newColourType >= PLAYER_TYPES.size():
    		newColourType -= PLAYER_TYPES.size()
    	setColourType(newColourType)

> This function accepts an adjustment value in colour, which is added to the existing value

> It then wraps the colour round if it reaches the end

In the _Game_ script, we add the following to the _process_ function:

		if Input.is_key_pressed(KEY_UP):
			$Player.adjustColour(-1)
		if Input.is_key_pressed(KEY_DOWN):
			$Player.adjustColour(1)

> This instructs the _Player_ to change colour when either UP or DOWN cursor key is pressed

Try running it!

... it works, but!?!

<center>
![colour change quick.gif](https://res.cloudinary.com/hpiynhbhq/image/upload/v1521318217/picemfalwvzw90xczlv2.gif)
</center>

... Yes, we need to add a delay to the colour change. The _Player_ script should only allow the change IF it is ready. So we need to introduce a counting variable , a decrement in the _process_ function and a condition in the adjust function:

    const CHANGE_COLOUR_TIME = 0.2
    var changingColour = 0.0

> Declared is the constant time between allowable colour changes and a counter variable of how long there is left before a colour change can occur

    func _process(delta):
    	reloading -= delta
    	changingColour -= delta

> In the _process_ function, we now decrement delta from the _changingColour_ counter

    func adjustColour(adjust):
    	if changingColour < 0.0:
    		var newColourType = colourType + adjust
    		if newColourType < 0:
    			newColourType += PLAYER_TYPES.size()
    		elif newColourType >= PLAYER_TYPES.size():
    			newColourType -= PLAYER_TYPES.size()
    		setColourType(newColourType)

> The condition is added to ensure the colour change can only occur if the counter has run out

    func setColourType(newColourType):
    	if newColourType != null:
    		colourType = newColourType
    		texture = PLAYER_TYPES[colourType]
    		changingColour = CHANGE_COLOUR_TIME

> Finally, the colour change function resets the count down, to prevent another change in the period defined

Running it is now reflects expected behaviour:
<center>
![delayed colour change.gif](https://res.cloudinary.com/hpiynhbhq/image/upload/v1521318798/ixzkxlximfenet3k5wtj.gif)
</center>

# Add colour to lasers
The laser colour will depend on the Ship's colour, hence we either pass the colour of the ship to the laser or get the laser to check the parent. Given the ship 'could' change colour whilst a bullet is issued, it is best in this scenario to pass the colour when firing the bullet.

The changes to the laser script resemble those applied to the Ship.

    const VELOCITY = Vector2(0, -600)

    const LASER_TYPES = [
    	preload("res://Bullets/Laser/images/laser-white-02.png"),
    	preload("res://Bullets/Laser/images/laser-red-02.png"),
    	preload("res://Bullets/Laser/images/laser-yellow-02.png"),
    	preload("res://Bullets/Laser/images/laser-blue-02.png"),
    	preload("res://Bullets/Laser/images/laser-grey-02.png"),
    	preload("res://Bullets/Laser/images/laser-black-02.png")
    ]

    export (int, "WHITE", "RED", "YELLOW", "BLUE", "GREY", "BLACK") var colourType setget setColourType

    func setColourType(newColourType):
    	if newColourType != null:
    		colourType = newColourType
    		texture = LASER_TYPES[colourType]

> I changed the velocity whilst I was in this script, doubling its speed

> The constants for the laser colour, along with the colourType and set function were added

We then modify the _Player_ Scene script, because we shall set the _Laser_ colour from it:

    func fire():
    	if reloading <= 0.0:
    		var bullet = BULLET_LASER.instance()
    		_bullet.colourType = colourType_
    		bullet.global_position = global_position
    		get_parent().add_child(bullet)
    		reloading = RELOAD_TIME

> In the _fire_ method, we set the _Bullet colourType_ to the _colourType_ value of the _Ship_

Try running it! 

<center>
![coloured lasers.gif](https://res.cloudinary.com/hpiynhbhq/image/upload/v1521323428/j6ad8tzxtbzoatyghqo5.gif)
</center>

... all is good!

Can you guess how we implement the shield of the Invaders? Hint: think about the colourType variables, they will help you!

# Add shields to the Invaders
This, for me, is the exciting bit! 

The aim of game development is to make it unique and stand out. I don't want to build a clone of 'Space Invaders', I want to build my own twist on it. Something that people will pick-up and want to play! 

Using colour is one differentiator, but I have other thoughts to explore too!

I asked in the last section if you could think of how to implement the shields of the Invaders. This is really quite simple!

When a bullet is detected by the _Invader_, the Area2D sends a signal to the _Invader_ hit function. The call to the _hit_ function includes the object that struck it, i.e. the _Laser_!

All we need to do is check the _colourType_ against the _Invader_, if it matches, the _Invader_ is destroyed. Alternatively, the shield shown and an automatic reduction of the shield alpha colour channel can be performed at each frame.

In the _Invader_ script, the _hit_ function is modified:

    func hit(object):
    	if object.name == 'LaserArea':
    		if object.get_parent().colourType == colourType:
    			queue_free()

> The _Invader_ is only removed if the object striking it was a LaserArea and that its parent (_Laser Scene Script_) was the same colour

Try running the game!

<center>
![coloured invaders killed.gif](https://res.cloudinary.com/hpiynhbhq/image/upload/v1521325892/txbcxokk9j3b7rin8deh.gif)
</center>

... half of the design is now implemented, but what about the other?

The _Invaders_ can now only be killed by the correct bullet colour.

However, they need shields! The shield is purely a cosmetic special effect, to reflect back to the player the invicibility of the Alien!

A new _Shield_ Scene was created, utilising new images with elipse shapes that have a slight opacity.

![image.png](https://res.cloudinary.com/hpiynhbhq/image/upload/v1521326124/zu9ouhwc7xnc7mbj3fhw.png)

The _Shield_ script was coded much like the other _Nodes_:

    extends Sprite

    const SHIELD_TYPE = [
    	preload("res://Shield/images/shieldWhite.png"),
    	preload("res://Shield/images/shieldRed.png"),
    	preload("res://Shield/images/shieldYellow.png"),
    	preload("res://Shield/images/shieldBlue.png"),
    	preload("res://Shield/images/shieldGrey.png"),
    	preload("res://Shield/images/shieldBlack.png")
    ]

    var colourType setget setColourType

    func setColourType(newColourType):
    	colourType = newColourType

    func _ready():
    	if colourType != null:
    		texture = SHIELD_TYPE[colourType ]

    func _process(delta):
    	modulate.a -= 1.0 * delta

> The script displays the correct shield image and colour

> It automatically reduces the opacity levels until it vanishes

The _Invader_ script is modified to add a shield when it is _ready_:

    const SHIELD = preload("res://Shield/Shield.tscn")

> A constant variable is initialised for the _Shield_ Scene

    func addShield():
    	var shield = SHIELD.instance()
    	shield.colourType = colourType
    	shield.modulate.a = 0.0
    	add_child(shield)

> A new _addShield_ function has been added to instance a new _Shield_ Node, setting it to the colour of the _Invader_ and make the shield invisible. Finally it is added as a child to the Invader parent

The final amendment is extending the _Invader_ hit function:

    func hit(object):
    	if object.name == 'LaserArea':
   		if object.get_parent().colourType == colourType:
    			queue_free()
    		else:
    			$Shield.modulate.a = 0.9

> The additional else condition has been set for when the _Bullet_ colour does not match the _Invader_. 
> In that situation, the shield's alpha channel is increased, thus revealing it onscreen, ready for its own _process_ function to drain it again; therefore on screen, we see a flash of the shield!

Try running it again:

<center>
![shields a working.gif](https://res.cloudinary.com/hpiynhbhq/image/upload/v1521327237/x4u5lsutrozce9pddwbs.gif)
</center>

Success! The game delivers as expected (for now).


# Finally
This tutorial took so much more time to write than the others! It was a simple solution for me to develop, but has been far more involved in describing. Maybe I've dropped into too low level, but my intention was to show how straight forward the implementation is! It's not complex in any shape or form, yet, the result looks good (well, in my opinion)!

My next intention is divided! I'm torn between showing 'formations' of Invaders swooping in, OR, getting the game life cycle running, i.e. a Splash Screen, Game and End. There is a need at some stage to create a 'game' and have the context between states. I'll ponder over this for now.

Don't forget to check out the game on [itch.io](https://sp33dy.itch.io/alien-invaders). I'm publishing the game in advance of tutorials, so it is worth you checking it out periodically! You'll be able to guess what is coming up in my posts!

Please do comment and ask questions! I'm more than happy to interact with you.

# Sample Project

I hope you've read through this Tutorial, as it will provide you with the hands-on skills that you simply can't learn from downloading the sample set of code. 

However, for those wanting the code, please download from [GitHub](https://github.com/sp33dy/Godot-v3-Tutorials-Beginner).

You should then Import the "Space Invaders (part 8)" folder into Godot Engine.

# Other Tutorials

#### Beginners

> * [Install Godot Engine 3.0](https://steemit.com/gamedev/@sp33dy/installing-godot-engine-v3-0-windows)
> * [Installing your First Demo](https://steemit.com/gamedev/@sp33dy/first-demo-godot-engine-v3-0)
> * [Your first Sprite!](https://steemit.com/utopian-io/@sp33dy/tutorial-godot-engine-v3-gdscript-your-first-moving-sprite)
> * [Move your first Sprite!](https://steemit.com/utopian-io/@sp33dy/tutorial-godot-engine-v3-gdscript-move-your-sprite)
> * [Create lots of Sprites!](https://steemit.com/utopian-io/@sp33dy/tutorial-godot-engine-v3-gdscript-create-lots-of-sprites)
> * [Sprite formations!](https://steemit.com/utopian-io/@sp33dy/tutorial-godot-engine-v3-gdscript-sprite-formations)
> * [Smooth Movement!](https://steemit.com/utopian-io/@sp33dy/tutorial-godot-engine-v3-gdscript-smooth-movement#comments)
> * [Invader Graphics!](https://steemit.com/utopian-io/@sp33dy/tutorial-godot-engine-v3-gdscript-invader-graphics)
> * [Player Ship!](https://steemit.com/utopian-io/@sp33dy/tutorial-godot-engine-v3-gdscript-player-ship)
> * [Bullets](https://steemit.com/utopian-io/@sp33dy/tutorial-godot-engine-v3-gdscript-bullets)
> * [Collision Detection!](https://steemit.com/utopian-io/@sp33dy/tutorial-godot-engine-v3-gdscript-collision-dectection)

#### Competent

> * [Custom TileMaps](https://steemit.com/utopian-io/@sp33dy/tutorial-godot-engine-v3-gdscript-custom-tilemap)
> * [Custom TileMap Scrolling](https://steemit.com/utopian-io/@sp33dy/tutorial-godot-engine-v3-gdscript-custom-tilemap-scrolling)
> * [Screen Wrapping Sprite](https://steemit.com/utopian-io/@sp33dy/tutorial-godot-engine-v3-gdscript-generic-screen-wrapping-sprite)
> * [Screen Wrap Node](https://steemit.com/utopian-io/@sp33dy/tutorial-godot-engine-v3-gdscript-generic-screen-wrapping-node)

<br /><hr/><em>Posted on <a href="https://utopian.io/utopian-io/@sp33dy/tutorial-godot-engine-v3-gdscript-colour-use">Utopian.io -  Rewarding Open Source Contributors</a></em><hr/>
👍  , , , , , , , , , , , , , ,
properties (23)
post_id39,152,556
authorsp33dy
permlinktutorial-godot-engine-v3-gdscript-colour-use
categoryutopian-io
json_metadata"{"repository": {"owner": {"login": "godotengine"}, "id": 15634981, "full_name": "godotengine/godot", "fork": false, "name": "godot", "html_url": "https://github.com/godotengine/godot"}, "moderator": {"pending": false, "account": "roj", "reviewed": true, "flagged": false, "time": "2018-03-18T08:46:54.313Z"}, "format": "markdown", "platform": "github", "tags": ["utopian-io", "gamedev", "gaming", "tutorial", "godot-engine"], "questions": [{"selected": 0, "question": "Is the project description formal?", "answers": [{"value": "Yes it\u2019s straight to the point", "score": 10, "selected": true}, {"value": "Need more description ", "score": 5, "selected": false}, {"value": "Not too descriptive", "score": 0, "selected": false}]}, {"selected": 0, "question": "Is the language / grammar correct?", "answers": [{"value": "Yes", "score": 20, "selected": true}, {"value": "A few mistakes", "score": 10, "selected": false}, {"value": "It's pretty bad", "score": 0, "selected": false}]}, {"selected": 0, "question": "Was the template followed?", "answers": [{"value": "Yes", "score": 10, "selected": true}, {"value": "Partially", "score": 5, "selected": false}, {"value": "No", "score": 0, "selected": false}]}, {"selected": 0, "question": "Is there information about the additional frameworks?", "answers": [{"value": "Yes, everything is explained", "score": 5, "selected": true}, {"value": "Yes, but not enough", "score": 3, "selected": false}, {"value": "No details at all", "score": 0, "selected": false}]}, {"selected": 0, "question": "Is there code in the tutorial?", "answers": [{"value": "Yes, and it\u2019s well explained", "score": 5, "selected": true}, {"value": "Yes, but no explanation", "score": 3, "selected": false}, {"value": "No", "score": 0, "selected": false}]}, {"selected": 0, "question": "Is the tutorial explains technical aspects well enough?", "answers": [{"value": "Yes, it teaches how and why about technical aspects", "score": 5, "selected": true}, {"value": "Yes, but it\u2019s not good/enough", "score": 3, "selected": false}, {"value": "No, it explains poorly", "score": 0, "selected": false}]}, {"selected": 1, "question": "Is the tutorial general and dense enough?", "answers": [{"value": "Yes, it\u2019s general and dense", "score": 5, "selected": false}, {"value": "Kinda, it might be more generalized", "score": 3, "selected": true}, {"value": "No, it\u2019s sliced unnecessarily to keep part number high", "score": 0, "selected": false}]}, {"selected": 1, "question": "Is there an outline for the tutorial content at the beginning of the post", "answers": [{"value": "Yes, there is a well prepared outline in \u201cWhat will I learn?\u201d or another outline section", "score": 5, "selected": false}, {"value": "Yes, but there is no proper listing for every step of the tutorial or it\u2019s not detailed enough", "score": 3, "selected": true}, {"value": "No, there is no outline for the steps.", "score": 0, "selected": false}]}, {"selected": 0, "question": "Is the visual content of good quality?", "answers": [{"value": "Yes", "score": 5, "selected": true}, {"value": "Yes, but bad quality", "score": 3, "selected": false}, {"value": "No", "score": 0, "selected": false}]}, {"selected": 0, "question": "Is this a tutorial series?", "answers": [{"value": "Yes", "score": 5, "selected": true}, {"value": "Yes, but first part", "score": 3, "selected": false}, {"value": "No", "score": 0, "selected": false}]}, {"selected": 0, "question": "Is the tutorial post structured?", "answers": [{"value": "Yes", "score": 5, "selected": true}, {"value": "Not so good", "score": 3, "selected": false}, {"value": "No", "score": 0, "selected": false}]}], "community": "utopian", "type": "tutorials", "pullRequests": [], "score": 49, "links": ["https://steemit-production-imageproxy-upload.s3.amazonaws.com/DQmenztXPYjpJLwd6Y1rTfWEUX9g5tsYMEhty5PzaKmaFcZ", "https://sp33dy.itch.io/alien-invaders", "https://res.cloudinary.com/hpiynhbhq/image/upload/v1521327237/x4u5lsutrozce9pddwbs.gif", "https://steemit.com/gamedev/@sp33dy/installing-godot-engine-v3-0-windows", "https://github.com/sp33dy/Godot-v3-Tutorials-Competent", "https://steemit.com/utopian-io/@sp33dy/tutorial-godot-engine-v3-gdscript-generic-screen-wrapping-node", "https://github.com/sp33dy/Godot-v3-Tutorials-Competent/tree/master/Screen%20Wrap%20Node", "https://res.cloudinary.com/hpiynhbhq/image/upload/v1521306060/pjgmhkrblipusm9tyepp.png", "https://res.cloudinary.com/hpiynhbhq/image/upload/v1521306202/mx08wjbbgjcu6jlqpsvo.png", "https://res.cloudinary.com/hpiynhbhq/image/upload/v1521306253/ergryczdmv9cwslaab48.png", "https://res.cloudinary.com/hpiynhbhq/image/upload/v1521306819/pxplj5c6uib0bsbcetut.png", "https://res.cloudinary.com/hpiynhbhq/image/upload/v1521307419/a3av1fxtnjcr8mqrlk3c.gif", "https://res.cloudinary.com/hpiynhbhq/image/upload/v1521307564/hdldeciuu5im6oomnmbu.png", "https://res.cloudinary.com/hpiynhbhq/image/upload/v1521309021/gqsc34njfmdtlbf3m9ql.png", "https://res.cloudinary.com/hpiynhbhq/image/upload/v1521309974/swo8dsftknx824ndfelr.png", "https://res.cloudinary.com/hpiynhbhq/image/upload/v1521310132/vlf6nwdx1h4grp6hiodi.png", "https://res.cloudinary.com/hpiynhbhq/image/upload/v1521310185/krjun3r7lnxiwfxxjsua.png", "https://res.cloudinary.com/hpiynhbhq/image/upload/v1521309438/nqz5ufpw7ddzqndrsbao.png", "https://res.cloudinary.com/hpiynhbhq/image/upload/v1521310406/lhvqukfmpf1prewuggse.png", "https://res.cloudinary.com/hpiynhbhq/image/upload/v1521310441/z5iezpeytxrxt14tdn3v.png", "https://res.cloudinary.com/hpiynhbhq/image/upload/v1521312564/l2gbh8m4m1ttw6sa7zp4.png", "https://res.cloudinary.com/hpiynhbhq/image/upload/v1521312902/qtnllumqxouvgsumxhht.gif", "https://res.cloudinary.com/hpiynhbhq/image/upload/v1521313331/hbyoui0nguc8zg7yb9oj.gif", "https://res.cloudinary.com/hpiynhbhq/image/upload/v1521313665/mefdfdg8jerdp2ydeclu.png", "https://res.cloudinary.com/hpiynhbhq/image/upload/v1521313971/nouuolaaojekhfsdtlet.png", "https://res.cloudinary.com/hpiynhbhq/image/upload/v1521314294/rcaehwommkmmbx5pxfkc.gif", "https://res.cloudinary.com/hpiynhbhq/image/upload/v1521317145/f0zkusgklaerjbiipjg4.gif", "https://res.cloudinary.com/hpiynhbhq/image/upload/v1521318217/picemfalwvzw90xczlv2.gif", "https://res.cloudinary.com/hpiynhbhq/image/upload/v1521318798/ixzkxlximfenet3k5wtj.gif", "https://res.cloudinary.com/hpiynhbhq/image/upload/v1521323428/j6ad8tzxtbzoatyghqo5.gif", "https://res.cloudinary.com/hpiynhbhq/image/upload/v1521325892/txbcxokk9j3b7rin8deh.gif", "https://res.cloudinary.com/hpiynhbhq/image/upload/v1521326124/zu9ouhwc7xnc7mbj3fhw.png", "https://github.com/sp33dy/Godot-v3-Tutorials-Beginner", "https://steemit.com/gamedev/@sp33dy/first-demo-godot-engine-v3-0", "https://steemit.com/utopian-io/@sp33dy/tutorial-godot-engine-v3-gdscript-your-first-moving-sprite", "https://steemit.com/utopian-io/@sp33dy/tutorial-godot-engine-v3-gdscript-move-your-sprite", "https://steemit.com/utopian-io/@sp33dy/tutorial-godot-engine-v3-gdscript-create-lots-of-sprites", "https://steemit.com/utopian-io/@sp33dy/tutorial-godot-engine-v3-gdscript-sprite-formations", "https://steemit.com/utopian-io/@sp33dy/tutorial-godot-engine-v3-gdscript-smooth-movement#comments", "https://steemit.com/utopian-io/@sp33dy/tutorial-godot-engine-v3-gdscript-invader-graphics", "https://steemit.com/utopian-io/@sp33dy/tutorial-godot-engine-v3-gdscript-player-ship", "https://steemit.com/utopian-io/@sp33dy/tutorial-godot-engine-v3-gdscript-bullets", "https://steemit.com/utopian-io/@sp33dy/tutorial-godot-engine-v3-gdscript-collision-dectection", "https://steemit.com/utopian-io/@sp33dy/tutorial-godot-engine-v3-gdscript-custom-tilemap", "https://steemit.com/utopian-io/@sp33dy/tutorial-godot-engine-v3-gdscript-custom-tilemap-scrolling", "https://steemit.com/utopian-io/@sp33dy/tutorial-godot-engine-v3-gdscript-generic-screen-wrapping-sprite"], "app": "utopian/1.0.0", "users": ["sp33dy"], "image": ["https://steemit-production-imageproxy-upload.s3.amazonaws.com/DQmenztXPYjpJLwd6Y1rTfWEUX9g5tsYMEhty5PzaKmaFcZ"]}"
created2018-03-17 23:41:24
last_update2018-03-18 08:46:54
depth0
children3
net_rshares12,158,599,451,735
last_payout2018-03-24 23:41:24
cashout_time1969-12-31 23:59:59
total_payout_value23.440 SBD
curator_payout_value10.233 SBD
pending_payout_value0.000 SBD
promoted0.000 SBD
body_length30,727
author_reputation3,476,250,874,387
root_title"Tutorial (Godot Engine v3 - GDScript) - Colour use!"
beneficiaries
0.
accountutopian.pay
weight2,500
max_accepted_payout1,000,000.000 SBD
percent_steem_dollars10,000
author_curate_reward""
vote details (15)
@roj ·
$1.46
Thank you for the contribution. It has been approved.

You can contact us on [Discord](https://discord.gg/uTyJkNm).
**[[utopian-moderator]](https://utopian.io/moderators)**
👍  ,
properties (23)
post_id39,207,662
authorroj
permlinkre-sp33dy-tutorial-godot-engine-v3-gdscript-colour-use-20180318t084707449z
categoryutopian-io
json_metadata"{"app": "utopian/1.0.0", "community": "utopian", "tags": ["utopian-io"]}"
created2018-03-18 08:47:12
last_update2018-03-18 08:47:12
depth1
children1
net_rshares430,598,813,948
last_payout2018-03-25 08:47:12
cashout_time1969-12-31 23:59:59
total_payout_value1.114 SBD
curator_payout_value0.350 SBD
pending_payout_value0.000 SBD
promoted0.000 SBD
body_length172
author_reputation12,621,504,053,655
root_title"Tutorial (Godot Engine v3 - GDScript) - Colour use!"
beneficiaries[]
max_accepted_payout1,000,000.000 SBD
percent_steem_dollars10,000
author_curate_reward""
vote details (2)
@utopian.tip ·
Hey @roj, I just gave you a tip for your hard work on moderation. Upvote this comment to support the utopian moderators and increase your future rewards!
👍  ,
properties (23)
post_id39,249,589
authorutopian.tip
permlinkre-re-sp33dy-tutorial-godot-engine-v3-gdscript-colour-use-20180318t084707449z-20180318t142617
categoryutopian-io
json_metadata{}
created2018-03-18 14:26:18
last_update2018-03-18 14:26:18
depth2
children0
net_rshares3,837,904,129
last_payout2018-03-25 14:26:18
cashout_time1969-12-31 23:59:59
total_payout_value0.000 SBD
curator_payout_value0.000 SBD
pending_payout_value0.000 SBD
promoted0.000 SBD
body_length153
author_reputation238,049,167,312
root_title"Tutorial (Godot Engine v3 - GDScript) - Colour use!"
beneficiaries[]
max_accepted_payout1,000,000.000 SBD
percent_steem_dollars10,000
author_curate_reward""
vote details (2)
@utopian-io ·
### Hey @sp33dy I am @utopian-io. I have just upvoted you!
#### Achievements
- You have less than 500 followers. Just gave you a gift to help you succeed!
- Seems like you contribute quite often. AMAZING!
#### Community-Driven Witness!
I am the first and only Steem Community-Driven Witness. <a href="https://discord.gg/zTrEMqB">Participate on Discord</a>. Lets GROW TOGETHER!
- <a href="https://v2.steemconnect.com/sign/account-witness-vote?witness=utopian-io&approve=1">Vote for my Witness With SteemConnect</a>
- <a href="https://v2.steemconnect.com/sign/account-witness-proxy?proxy=utopian-io&approve=1">Proxy vote to Utopian Witness with SteemConnect</a>
- Or vote/proxy on <a href="https://steemit.com/~witnesses">Steemit Witnesses</a>

[![mooncryption-utopian-witness-gif](https://steemitimages.com/DQmYPUuQRptAqNBCQRwQjKWAqWU3zJkL3RXVUtEKVury8up/mooncryption-s-utopian-io-witness-gif.gif)](https://steemit.com/~witnesses)

**Up-vote this comment to grow my power and help Open Source contributions like this one. Want to chat? Join me on Discord https://discord.gg/Pc8HG9x**
👍  
properties (23)
post_id39,231,421
authorutopian-io
permlinkre-sp33dy-tutorial-godot-engine-v3-gdscript-colour-use-20180318t121551713z
categoryutopian-io
json_metadata"{"app": "utopian/1.0.0", "community": "utopian", "tags": ["utopian-io"]}"
created2018-03-18 12:15:51
last_update2018-03-18 12:15:51
depth1
children0
net_rshares2,087,842,264
last_payout2018-03-25 12:15:51
cashout_time1969-12-31 23:59:59
total_payout_value0.000 SBD
curator_payout_value0.000 SBD
pending_payout_value0.000 SBD
promoted0.000 SBD
body_length1,082
author_reputation152,913,012,544,965
root_title"Tutorial (Godot Engine v3 - GDScript) - Colour use!"
beneficiaries[]
max_accepted_payout1,000,000.000 SBD
percent_steem_dollars10,000
author_curate_reward""
vote details (1)