|
@@ -140,6 +140,9 @@ node, so we'll add a script. Click the ``Player`` node and click the
|
|
|
In the script settings window, you can leave the default settings alone. Just
|
|
|
click "Create":
|
|
|
|
|
|
+.. note:: If you're creating a C# script or other languages, select the
|
|
|
+ language from the `language` drop down menu before hitting create.
|
|
|
+
|
|
|
.. image:: img/attach_node_window.png
|
|
|
|
|
|
.. note:: If this is your first time encountering GDScript, please read
|
|
@@ -147,28 +150,51 @@ click "Create":
|
|
|
|
|
|
Start by declaring the member variables this object will need:
|
|
|
|
|
|
-::
|
|
|
+.. tabs::
|
|
|
+ .. code-tab:: gdscript GDScript
|
|
|
|
|
|
extends Area2D
|
|
|
|
|
|
export (int) var SPEED # how fast the player will move (pixels/sec)
|
|
|
var screensize # size of the game window
|
|
|
+
|
|
|
+ .. code-tab:: csharp
|
|
|
+
|
|
|
+ public class Player : Area2D
|
|
|
+ {
|
|
|
+ [Export]
|
|
|
+ public int Speed = 0;
|
|
|
+
|
|
|
+ private Vector2 _screenSize;
|
|
|
+ }
|
|
|
+
|
|
|
|
|
|
Using the ``export`` keyword on the first variable ``SPEED`` allows us to
|
|
|
set its value in the Inspector. This can be very handy for values that you
|
|
|
want to be able to adjust just like a node's built-in properties. Click on
|
|
|
the ``Player`` node and set the speed property to ``400``.
|
|
|
|
|
|
+.. warning:: If you're using C#, you need to restart godot editor temporarily to see
|
|
|
+ exported variables in the editor until it's fixed.
|
|
|
+
|
|
|
.. image:: img/export_variable.png
|
|
|
|
|
|
The ``_ready()`` function is called when a node enters the scene tree,
|
|
|
which is a good time to find the size of the game window:
|
|
|
|
|
|
-::
|
|
|
+.. tabs::
|
|
|
+ .. code-tab:: gdscript GDScript
|
|
|
|
|
|
func _ready():
|
|
|
screensize = get_viewport_rect().size
|
|
|
|
|
|
+ .. code-tab:: csharp
|
|
|
+
|
|
|
+ public override void _Ready()
|
|
|
+ {
|
|
|
+ _screenSize = GetViewport().GetSize();
|
|
|
+ }
|
|
|
+
|
|
|
Now we can use the ``_process()`` function to define what the player will do.
|
|
|
``_process()`` is called every frame, so we'll use it to update
|
|
|
elements of our game which we expect will change often. Here we'll make it:
|
|
@@ -188,7 +214,8 @@ You can detect whether a key is pressed using
|
|
|
``Input.is_action_pressed()``, which returns ``true`` if it is pressed
|
|
|
or ``false`` if it isn't.
|
|
|
|
|
|
-::
|
|
|
+.. tabs::
|
|
|
+ .. code-tab:: gdscript GDScript
|
|
|
|
|
|
func _process(delta):
|
|
|
var velocity = Vector2() # the player's movement vector
|
|
@@ -206,6 +233,36 @@ or ``false`` if it isn't.
|
|
|
else:
|
|
|
$AnimatedSprite.stop()
|
|
|
|
|
|
+ .. code-tab:: csharp
|
|
|
+
|
|
|
+ public override void _Process(float delta)
|
|
|
+ {
|
|
|
+ var velocity = new Vector2();
|
|
|
+ if (Input.IsActionPressed("ui_right")) {
|
|
|
+ velocity.x += 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (Input.IsActionPressed("ui_left")) {
|
|
|
+ velocity.x -= 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (Input.IsActionPressed("ui_down")) {
|
|
|
+ velocity.y += 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (Input.IsActionPressed("ui_up")) {
|
|
|
+ velocity.y -= 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ var animatedSprite = (AnimatedSprite) GetNode("AnimatedSprite");
|
|
|
+ if (velocity.Length() > 0) {
|
|
|
+ velocity = velocity.Normalized() * Speed;
|
|
|
+ animatedSprite.Play();
|
|
|
+ } else {
|
|
|
+ animatedSprite.Stop();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
We check each input and add/subtract from the ``velocity`` to obtain a
|
|
|
total direction. For example, if you hold ``right`` and ``down`` at
|
|
|
the same time, the resulting ``velocity`` vector will be ``(1, 1)``. In
|
|
@@ -230,14 +287,24 @@ AnimatedSprite animation.
|
|
|
So in the code above, ``$AnimatedSprite.play()`` is the same as ``get_node("AnimatedSprite").play()``.
|
|
|
|
|
|
Now that we have a movement direction, we can update ``Player``'s position
|
|
|
-and use ``clamp()`` to prevent it from leaving the screen:
|
|
|
+and use ``clamp()`` to prevent it from leaving the screen by adding the following
|
|
|
+to the bottom of the ``_process`` function:
|
|
|
|
|
|
-::
|
|
|
+.. tabs::
|
|
|
+ .. code-tab:: gdscript GDScript
|
|
|
|
|
|
position += velocity * delta
|
|
|
position.x = clamp(position.x, 0, screensize.x)
|
|
|
position.y = clamp(position.y, 0, screensize.y)
|
|
|
|
|
|
+ .. code-tab:: csharp
|
|
|
+
|
|
|
+ Position += velocity * delta;
|
|
|
+ Position = new Vector2(
|
|
|
+ Mathf.Clamp(Position.x, 0, _screenSize.x),
|
|
|
+ Mathf.Clamp(Position.y, 0, _screenSize.y)
|
|
|
+ );
|
|
|
+
|
|
|
|
|
|
.. tip:: *Clamping* a value means restricting it to a given range.
|
|
|
|
|
@@ -258,7 +325,8 @@ property for left movement, and an "up" animation, which should be
|
|
|
flipped vertically with ``flip_v`` for downward movement.
|
|
|
Let's place this code at the end of our ``_process()`` function:
|
|
|
|
|
|
-::
|
|
|
+.. tabs::
|
|
|
+ .. code-tab:: gdscript GDScript
|
|
|
|
|
|
if velocity.x != 0:
|
|
|
$AnimatedSprite.animation = "right"
|
|
@@ -267,16 +335,32 @@ Let's place this code at the end of our ``_process()`` function:
|
|
|
elif velocity.y != 0:
|
|
|
$AnimatedSprite.animation = "up"
|
|
|
$AnimatedSprite.flip_v = velocity.y > 0
|
|
|
+
|
|
|
+ .. code-tab:: csharp
|
|
|
+
|
|
|
+ if (velocity.x != 0) {
|
|
|
+ animatedSprite.Animation = "right";
|
|
|
+ animatedSprite.FlipH = velocity.x < 0;
|
|
|
+ animatedSprite.FlipV = false;
|
|
|
+ } else if(velocity.y != 0) {
|
|
|
+ animatedSprite.Animation = "up";
|
|
|
+ animatedSprite.FlipV = velocity.y > 0;
|
|
|
+ }
|
|
|
|
|
|
Play the scene again and check that the animations are correct in each
|
|
|
of the directions. When you're sure the movement is working correctly,
|
|
|
add this line to ``_ready()`` so the player will be hidden when the game
|
|
|
starts:
|
|
|
|
|
|
-::
|
|
|
+.. tabs::
|
|
|
+ .. code-tab:: gdscript GDScript
|
|
|
|
|
|
hide()
|
|
|
|
|
|
+ .. code-tab:: csharp
|
|
|
+
|
|
|
+ Hide();
|
|
|
+
|
|
|
Preparing for Collisions
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
@@ -286,10 +370,16 @@ made any enemies yet! That's OK, because we're going to use Godot's
|
|
|
|
|
|
Add the following at the top of the script, after ``extends Area2d``:
|
|
|
|
|
|
-::
|
|
|
+.. tabs::
|
|
|
+ .. code-tab:: gdscript GDScript
|
|
|
|
|
|
signal hit
|
|
|
|
|
|
+ .. code-tab:: csharp
|
|
|
+
|
|
|
+ [Signal]
|
|
|
+ public delegate void Hit();
|
|
|
+
|
|
|
This defines a custom signal called "hit" that we will have our player
|
|
|
emit (send out) when it collides with an enemy. We will use ``Area2D`` to
|
|
|
detect the collision. Select the ``Player`` node and click the "Node" tab
|
|
@@ -311,13 +401,27 @@ settings - Godot will automatically create a function called
|
|
|
|
|
|
Add this code to the function:
|
|
|
|
|
|
-::
|
|
|
+.. tabs::
|
|
|
+ .. code-tab:: gdscript GDScript
|
|
|
|
|
|
func _on_Player_body_entered( body ):
|
|
|
hide() # Player disappears after being hit
|
|
|
emit_signal("hit")
|
|
|
$CollisionShape2D.disabled = true
|
|
|
|
|
|
+ .. code-tab:: csharp
|
|
|
+
|
|
|
+ public void OnPlayerBodyEntered(Godot.Object body)
|
|
|
+ {
|
|
|
+ Hide();
|
|
|
+ EmitSignal("Hit");
|
|
|
+
|
|
|
+ // for the sake of this example, but it's better to create a class var
|
|
|
+ // then assign the variable inside _Ready()
|
|
|
+ var collisionShape2D = (CollisionShape2D) GetNode("CollisionShape2D");
|
|
|
+ collisionShape2D.Disabled = true;
|
|
|
+ }
|
|
|
+
|
|
|
.. Note:: Disabling the area's collision shape means
|
|
|
it won't detect collisions. By turning it off, we make
|
|
|
sure we don't trigger the ``hit`` signal more than once.
|
|
@@ -326,13 +430,25 @@ Add this code to the function:
|
|
|
The last piece for our player is to add a function we can call to reset
|
|
|
the player when starting a new game.
|
|
|
|
|
|
-::
|
|
|
+.. tabs::
|
|
|
+ .. code-tab:: gdscript GDScript
|
|
|
|
|
|
func start(pos):
|
|
|
position = pos
|
|
|
show()
|
|
|
$CollisionShape2D.disabled = false
|
|
|
|
|
|
+ .. code-tab:: csharp
|
|
|
+
|
|
|
+ public void Start(Vector2 pos)
|
|
|
+ {
|
|
|
+ Position = pos;
|
|
|
+ Show();
|
|
|
+
|
|
|
+ var collisionShape2D = (CollisionShape2D) GetNode("CollisionShape2D");
|
|
|
+ collisionShape2D.Disabled = false;
|
|
|
+ }
|
|
|
+
|
|
|
Enemy Scene
|
|
|
-----------
|
|
|
|
|
@@ -388,7 +504,8 @@ Enemy Script
|
|
|
|
|
|
Add a script to the ``Mob`` and add the following member variables:
|
|
|
|
|
|
-::
|
|
|
+.. tabs::
|
|
|
+ .. code-tab:: gdscript GDScript
|
|
|
|
|
|
extends RigidBody2D
|
|
|
|
|
@@ -396,6 +513,19 @@ Add a script to the ``Mob`` and add the following member variables:
|
|
|
export (int) var MAX_SPEED # maximum speed range
|
|
|
var mob_types = ["walk", "swim", "fly"]
|
|
|
|
|
|
+ .. code-tab:: csharp
|
|
|
+
|
|
|
+ public class Mob : RigidBody2D
|
|
|
+ {
|
|
|
+ [Export]
|
|
|
+ public int MinSpeed = 150;
|
|
|
+
|
|
|
+ [Export]
|
|
|
+ public int MaxSpeed = 250;
|
|
|
+
|
|
|
+ private String[] _mobTypes = {"walk", "swim", "fly"};
|
|
|
+ }
|
|
|
+
|
|
|
We'll pick a random value between ``MIN_SPEED`` and ``MAX_SPEED`` for
|
|
|
how fast each mob will move (it would be boring if they were all moving
|
|
|
at the same speed). Set them to ``150`` and ``250`` in the Inspector. We
|
|
@@ -405,11 +535,27 @@ we'll use to select a random one.
|
|
|
Now let's look at the rest of the script. In ``_ready()`` we randomly
|
|
|
choose one of the three animation types:
|
|
|
|
|
|
-::
|
|
|
+.. tabs::
|
|
|
+ .. code-tab:: gdscript GDScript
|
|
|
|
|
|
func _ready():
|
|
|
$AnimatedSprite.animation = mob_types[randi() % mob_types.size()]
|
|
|
|
|
|
+ .. code-tab:: csharp
|
|
|
+
|
|
|
+ public override void _Ready()
|
|
|
+ {
|
|
|
+ var animatedSprite = (AnimatedSprite) GetNode("AnimatedSprite");
|
|
|
+
|
|
|
+ // C# doesn't implement gdscript's random methods, so we use Random
|
|
|
+ // as an alternative.
|
|
|
+ //
|
|
|
+ // Note: Never define random multiple times in real projects. Create a
|
|
|
+ // class memory and reuse it to get true random numbers.
|
|
|
+ var randomMob = new Random();
|
|
|
+ animatedSprite.Animation = _mobTypes[randomMob.Next(0, _mobTypes.Length)];
|
|
|
+ }
|
|
|
+
|
|
|
.. note:: You must use ``randomize()`` if you want
|
|
|
your sequence of "random" numbers to be different every time you run
|
|
|
the scene. We're going to use ``randomize()`` in our ``Main`` scene,
|
|
@@ -420,11 +566,19 @@ The last piece is to make the mobs delete themselves when they leave the
|
|
|
screen. Connect the ``screen_exited()`` signal of the ``Visibility``
|
|
|
node and add this code:
|
|
|
|
|
|
-::
|
|
|
+.. tabs::
|
|
|
+ .. code-tab:: gdscript GDScript
|
|
|
|
|
|
func _on_Visibility_screen_exited():
|
|
|
queue_free()
|
|
|
|
|
|
+ .. code-tab:: csharp
|
|
|
+
|
|
|
+ public void onVisibilityScreenExited()
|
|
|
+ {
|
|
|
+ QueueFree();
|
|
|
+ }
|
|
|
+
|
|
|
This completes the `Mob` scene.
|
|
|
|
|
|
Main Scene
|
|
@@ -492,7 +646,8 @@ Add a script to ``Main``. At the top of the script we use
|
|
|
``export (PackedScene)`` to allow us to choose the Mob scene we want to
|
|
|
instance.
|
|
|
|
|
|
-::
|
|
|
+.. tabs::
|
|
|
+ .. code-tab:: gdscript GDScript
|
|
|
|
|
|
extends Node
|
|
|
|
|
@@ -502,6 +657,30 @@ instance.
|
|
|
func _ready():
|
|
|
randomize()
|
|
|
|
|
|
+ .. code-tab:: csharp
|
|
|
+
|
|
|
+ public class Main : Node
|
|
|
+ {
|
|
|
+ [Export]
|
|
|
+ public PackedScene Mob;
|
|
|
+
|
|
|
+ public int Score = 0;
|
|
|
+
|
|
|
+ // note: we're going to use this many times, so instantiating it
|
|
|
+ // allows our numbers to consistently be random
|
|
|
+ private Random rand = new Random();
|
|
|
+
|
|
|
+ public override void _Ready()
|
|
|
+ {
|
|
|
+ }
|
|
|
+
|
|
|
+ // we'll use this later because c# doesn't support gdscript's randi()
|
|
|
+ private float RandRand(float min, float max)
|
|
|
+ {
|
|
|
+ return (float) (rand.NextDouble() * (max - min) + min);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
Drag ``Mob.tscn`` from the "FileSystem" panel and drop it in the
|
|
|
``Mob`` property under the Script Variables of the ``Main`` node.
|
|
|
|
|
@@ -511,7 +690,8 @@ game ends. Type "game_over" in the "Method In Node" box at the bottom of the
|
|
|
"Connecting Signal" window. Add the following code, as well as a ``new_game``
|
|
|
function to set everything up for a new game:
|
|
|
|
|
|
-::
|
|
|
+.. tabs::
|
|
|
+ .. code-tab:: gdscript GDScript
|
|
|
|
|
|
func game_over():
|
|
|
$ScoreTimer.stop()
|
|
@@ -522,12 +702,36 @@ function to set everything up for a new game:
|
|
|
$Player.start($StartPosition.position)
|
|
|
$StartTimer.start()
|
|
|
|
|
|
+ .. code-tab:: csharp
|
|
|
+
|
|
|
+ public void GameOver()
|
|
|
+ {
|
|
|
+ //timers
|
|
|
+ var mobTimer = (Timer) GetNode("MobTimer");
|
|
|
+ var scoreTimer = (Timer) GetNode("ScoreTimer");
|
|
|
+
|
|
|
+ scoreTimer.Stop();
|
|
|
+ mobTimer.Stop();
|
|
|
+ }
|
|
|
+
|
|
|
+ public void NewGame()
|
|
|
+ {
|
|
|
+ Score = 0;
|
|
|
+
|
|
|
+ var player = (Player) GetNode("Player");
|
|
|
+ var startTimer = (Timer) GetNode("StartTimer");
|
|
|
+ var startPosition = (Position2D) GetNode("StartPosition");
|
|
|
+
|
|
|
+ player.Start(startPosition.Position);
|
|
|
+ startTimer.Start();
|
|
|
+ }
|
|
|
|
|
|
Now connect the ``timeout()`` signal of each of the Timer nodes.
|
|
|
``StartTimer`` will start the other two timers. ``ScoreTimer`` will
|
|
|
increment the score by 1.
|
|
|
|
|
|
-::
|
|
|
+.. tabs::
|
|
|
+ .. code-tab:: gdscript GDScript
|
|
|
|
|
|
func _on_StartTimer_timeout():
|
|
|
$MobTimer.start()
|
|
@@ -536,6 +740,23 @@ increment the score by 1.
|
|
|
func _on_ScoreTimer_timeout():
|
|
|
score += 1
|
|
|
|
|
|
+ .. code-tab:: csharp
|
|
|
+
|
|
|
+ public void OnStartTimerTimeout()
|
|
|
+ {
|
|
|
+ //timers
|
|
|
+ var mobTimer = (Timer) GetNode("MobTimer");
|
|
|
+ var scoreTimer = (Timer) GetNode("ScoreTimer");
|
|
|
+
|
|
|
+ mobTimer.Start();
|
|
|
+ scoreTimer.Start();
|
|
|
+ }
|
|
|
+
|
|
|
+ public void OnScoreTimerTimeout()
|
|
|
+ {
|
|
|
+ Score += 1;
|
|
|
+ }
|
|
|
+
|
|
|
In ``_on_MobTimer_timeout()`` we will create a mob instance, pick a
|
|
|
random starting location along the ``Path2D``, and set the mob in
|
|
|
motion. The ``PathFollow2D`` node will automatically rotate as it
|
|
@@ -545,7 +766,8 @@ well as its position.
|
|
|
Note that a new instance must be added to the scene using
|
|
|
``add_child()``.
|
|
|
|
|
|
-::
|
|
|
+.. tabs::
|
|
|
+ .. code-tab:: gdscript GDScript
|
|
|
|
|
|
func _on_MobTimer_timeout():
|
|
|
# choose a random location on Path2D
|
|
@@ -563,6 +785,27 @@ Note that a new instance must be added to the scene using
|
|
|
# choose the velocity
|
|
|
mob.set_linear_velocity(Vector2(rand_range(mob.MIN_SPEED, mob.MAX_SPEED), 0).rotated(direction))
|
|
|
|
|
|
+ .. code-tab:: csharp
|
|
|
+
|
|
|
+ public void OnMobTimerTimeout()
|
|
|
+ {
|
|
|
+ //choose random location on path2d
|
|
|
+ var mobSpawnLocation = (PathFollow2D) GetNode("MobPath/MobSpawnLocation");
|
|
|
+ mobSpawnLocation.SetOffset(rand.Next());
|
|
|
+
|
|
|
+ //set direction
|
|
|
+ var direction = mobSpawnLocation.Rotation + Mathf.PI/2;
|
|
|
+ direction += RandRand(-Mathf.PI/4, Mathf.PI/4);
|
|
|
+
|
|
|
+ //create mob instance and add it to scene
|
|
|
+ var mobInstance = (RigidBody2D) Mob.Instance();
|
|
|
+ mobInstance.Position = mobSpawnLocation.Position;
|
|
|
+ mobInstance.Rotation = direction;
|
|
|
+ mobInstance.SetLinearVelocity(new Vector2(RandRand(150f, 250f), 0).Rotated(direction));
|
|
|
+
|
|
|
+ AddChild(mobInstance);
|
|
|
+ }
|
|
|
+
|
|
|
.. important:: In functions requiring angles, GDScript uses *radians*,
|
|
|
not degrees. If you're more comfortable working with
|
|
|
degrees, you'll need to use the ``deg2rad()`` and
|
|
@@ -669,27 +912,50 @@ the three ``Control`` nodes:
|
|
|
|
|
|
Now add this script to ``HUD``:
|
|
|
|
|
|
-::
|
|
|
+.. tabs::
|
|
|
+ .. code-tab:: gdscript GDScript
|
|
|
|
|
|
extends CanvasLayer
|
|
|
|
|
|
signal start_game
|
|
|
|
|
|
+ .. code-tab:: csharp
|
|
|
+
|
|
|
+ public class HUD : CanvasLayer
|
|
|
+ {
|
|
|
+ [Signal]
|
|
|
+ public delegate void StartGame();
|
|
|
+ }
|
|
|
+
|
|
|
The ``start_game`` signal tells the ``Main`` node that the button
|
|
|
has been pressed.
|
|
|
|
|
|
-::
|
|
|
+.. tabs::
|
|
|
+ .. code-tab:: gdscript GDScript
|
|
|
|
|
|
func show_message(text):
|
|
|
$MessageLabel.text = text
|
|
|
$MessageLabel.show()
|
|
|
$MessageTimer.start()
|
|
|
|
|
|
+ .. code-tab:: csharp
|
|
|
+
|
|
|
+ public void ShowMessage(string text)
|
|
|
+ {
|
|
|
+ var messageTimer = (Timer) GetNode("MessageTimer");
|
|
|
+ var messageLabel = (Label) GetNode("MessageLabel");
|
|
|
+
|
|
|
+ messageLabel.Text = text;
|
|
|
+ messageLabel.Show();
|
|
|
+ messageTimer.Start();
|
|
|
+ }
|
|
|
+
|
|
|
This function is called when we want to display a message
|
|
|
temporarily, such as "Get Ready". On the ``MessageTimer``, set the
|
|
|
``Wait Time`` to ``2`` and set the ``One Shot`` property to "On".
|
|
|
|
|
|
-::
|
|
|
+.. tabs::
|
|
|
+ .. code-tab:: gdscript GDScript
|
|
|
|
|
|
func show_game_over():
|
|
|
show_message("Game Over")
|
|
@@ -698,21 +964,48 @@ temporarily, such as "Get Ready". On the ``MessageTimer``, set the
|
|
|
$MessageLabel.text = "Dodge the\nCreeps!"
|
|
|
$MessageLabel.show()
|
|
|
|
|
|
+ .. code-tab:: csharp
|
|
|
+
|
|
|
+ async public void ShowGameOver()
|
|
|
+ {
|
|
|
+ ShowMessage("Game Over");
|
|
|
+
|
|
|
+ var startButton = (Button) GetNode("StartButton");
|
|
|
+ var messageTimer = (Timer) GetNode("MessageTimer");
|
|
|
+ var messageLabel = (Label) GetNode("MessageLabel");
|
|
|
+
|
|
|
+ //work around for gdscript's yield
|
|
|
+ await Task.Delay((int) messageTimer.WaitTime * 1000);
|
|
|
+ messageLabel.Text = "Dodge the\nCreeps!";
|
|
|
+ messageLabel.Show();
|
|
|
+ startButton.Show();
|
|
|
+ }
|
|
|
+
|
|
|
This function is called when the player loses. It will show "Game
|
|
|
Over" for 2 seconds, then return to the title screen and show the
|
|
|
"Start" button.
|
|
|
|
|
|
-::
|
|
|
+.. tabs::
|
|
|
+ .. code-tab:: gdscript GDScript
|
|
|
|
|
|
func update_score(score):
|
|
|
$ScoreLabel.text = str(score)
|
|
|
|
|
|
+ .. code-tab:: csharp
|
|
|
+
|
|
|
+ public void UpdateScore(int score)
|
|
|
+ {
|
|
|
+ var scoreLabel = (Label) GetNode("ScoreLabel");
|
|
|
+ scoreLabel.Text = score.ToString();
|
|
|
+ }
|
|
|
+
|
|
|
This function is called in ``Main`` whenever the score changes.
|
|
|
|
|
|
Connect the ``timeout()`` signal of ``MessageTimer`` and the
|
|
|
``pressed()`` signal of ``StartButton``.
|
|
|
|
|
|
-::
|
|
|
+.. tabs::
|
|
|
+ .. code-tab:: gdscript GDScript
|
|
|
|
|
|
func _on_StartButton_pressed():
|
|
|
$StartButton.hide()
|
|
@@ -721,6 +1014,22 @@ Connect the ``timeout()`` signal of ``MessageTimer`` and the
|
|
|
func _on_MessageTimer_timeout():
|
|
|
$MessageLabel.hide()
|
|
|
|
|
|
+ .. code-tab:: csharp
|
|
|
+
|
|
|
+ public void OnStartButtonPressed()
|
|
|
+ {
|
|
|
+ var startButton = (Button) GetNode("StartButton");
|
|
|
+ startButton.Hide();
|
|
|
+
|
|
|
+ EmitSignal("StartGame");
|
|
|
+ }
|
|
|
+
|
|
|
+ public void OnMessageTimerTimeout()
|
|
|
+ {
|
|
|
+ var messageLabel = (Label) GetNode("MessageLabel");
|
|
|
+ messageLabel.Hide();
|
|
|
+ }
|
|
|
+
|
|
|
Connecting HUD to Main
|
|
|
~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
@@ -740,24 +1049,43 @@ In the Node tab, connect the HUD's ``start_game`` signal to the
|
|
|
In ``new_game()``, update the score display and show the "Get Ready"
|
|
|
message:
|
|
|
|
|
|
-::
|
|
|
+.. tabs::
|
|
|
+ .. code-tab:: gdscript GDScript
|
|
|
|
|
|
$HUD.update_score(score)
|
|
|
$HUD.show_message("Get Ready")
|
|
|
|
|
|
+ .. code-tab:: csharp
|
|
|
+
|
|
|
+ var hud = (HUD) GetNode("HUD");
|
|
|
+ hud.UpdateScore(Score);
|
|
|
+ hud.ShowMessage("Get Ready!");
|
|
|
+
|
|
|
In ``game_over()`` we need to call the corresponding ``HUD`` function:
|
|
|
|
|
|
-::
|
|
|
+.. tabs::
|
|
|
+ .. code-tab:: gdscript GDScript
|
|
|
|
|
|
$HUD.show_game_over()
|
|
|
|
|
|
+ .. code-tab:: csharp
|
|
|
+
|
|
|
+ var hud = (HUD) GetNode("HUD");
|
|
|
+ hud.ShowGameOver();
|
|
|
+
|
|
|
Finally, add this to ``_on_ScoreTimer_timeout()`` to keep the display in
|
|
|
sync with the changing score:
|
|
|
|
|
|
-::
|
|
|
+.. tabs::
|
|
|
+ .. code-tab:: gdscript GDScript
|
|
|
|
|
|
$HUD.update_score(score)
|
|
|
|
|
|
+ .. code-tab:: csharp
|
|
|
+
|
|
|
+ var hud = (HUD) GetNode("HUD");
|
|
|
+ hud.UpdateScore(Score);
|
|
|
+
|
|
|
Now you're ready to play! Click the "Play the Project" button. You will
|
|
|
be asked to select a main scene, so choose ``Main.tscn``.
|
|
|
|