mirror of
https://github.com/godotengine/godot-docs.git
synced 2026-01-05 22:09:56 +03:00
Remove outdated C++ tutorial in "Your first 2D game"
This commit is contained in:
@@ -45,43 +45,6 @@ Start by declaring the member variables this object will need:
|
||||
public Vector2 ScreenSize; // Size of the game window.
|
||||
}
|
||||
|
||||
.. code-tab:: cpp
|
||||
|
||||
// A `player.gdns` file has already been created for you. Attach it to the Player node.
|
||||
|
||||
// Create two files `player.cpp` and `player.hpp` next to `entry.cpp` in `src`.
|
||||
// This code goes in `player.hpp`. We also define the methods we'll be using here.
|
||||
#ifndef PLAYER_H
|
||||
#define PLAYER_H
|
||||
|
||||
#include <AnimatedSprite2D.hpp>
|
||||
#include <Area2D.hpp>
|
||||
#include <CollisionShape2D.hpp>
|
||||
#include <Godot.hpp>
|
||||
#include <Input.hpp>
|
||||
|
||||
class Player : public godot::Area2D {
|
||||
GODOT_CLASS(Player, godot::Area2D)
|
||||
|
||||
godot::AnimatedSprite2D *_animated_sprite;
|
||||
godot::CollisionShape2D *_collision_shape;
|
||||
godot::Input *_input;
|
||||
godot::Vector2 _screen_size; // Size of the game window.
|
||||
|
||||
public:
|
||||
real_t speed = 400; // How fast the player will move (pixels/sec).
|
||||
|
||||
void _init() {}
|
||||
void _ready();
|
||||
void _process(const double p_delta);
|
||||
void start(const godot::Vector2 p_position);
|
||||
void _on_body_entered(godot::Node2D *_body);
|
||||
|
||||
static void _register_methods();
|
||||
};
|
||||
|
||||
#endif // PLAYER_H
|
||||
|
||||
Using the ``export`` keyword on the first variable ``speed`` allows us to set
|
||||
its value in the Inspector. This can be handy for values that you want to be
|
||||
able to adjust just like a node's built-in properties. Click on the ``Player``
|
||||
@@ -121,18 +84,6 @@ a good time to find the size of the game window:
|
||||
ScreenSize = GetViewportRect().Size;
|
||||
}
|
||||
|
||||
.. code-tab:: cpp
|
||||
|
||||
// This code goes in `player.cpp`.
|
||||
#include "player.hpp"
|
||||
|
||||
void Player::_ready() {
|
||||
_animated_sprite = get_node<godot::AnimatedSprite2D>("AnimatedSprite2D");
|
||||
_collision_shape = get_node<godot::CollisionShape2D>("CollisionShape2D");
|
||||
_input = godot::Input::get_singleton();
|
||||
_screen_size = get_viewport_rect().size;
|
||||
}
|
||||
|
||||
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. For the player, we need to do the
|
||||
@@ -245,23 +196,6 @@ which returns ``true`` if it's pressed or ``false`` if it isn't.
|
||||
}
|
||||
}
|
||||
|
||||
.. code-tab:: cpp
|
||||
|
||||
// This code goes in `player.cpp`.
|
||||
void Player::_process(const double p_delta) {
|
||||
godot::Vector2 velocity(0, 0);
|
||||
|
||||
velocity.x = _input->get_action_strength("move_right") - _input->get_action_strength("move_left");
|
||||
velocity.y = _input->get_action_strength("move_down") - _input->get_action_strength("move_up");
|
||||
|
||||
if (velocity.length() > 0) {
|
||||
velocity = velocity.normalized() * speed;
|
||||
_animated_sprite->play();
|
||||
} else {
|
||||
_animated_sprite->stop();
|
||||
}
|
||||
}
|
||||
|
||||
We start by setting the ``velocity`` to ``(0, 0)`` - by default, the player
|
||||
should not be moving. Then we check each input and add/subtract from the
|
||||
``velocity`` to obtain a total direction. For example, if you hold ``right`` and
|
||||
@@ -308,14 +242,6 @@ the ``_process`` function (make sure it's not indented under the `else`):
|
||||
y: Mathf.Clamp(Position.Y, 0, ScreenSize.Y)
|
||||
);
|
||||
|
||||
.. code-tab:: cpp
|
||||
|
||||
godot::Vector2 position = get_position();
|
||||
position += velocity * (real_t)p_delta;
|
||||
position.x = godot::Math::clamp(position.x, (real_t)0.0, _screen_size.x);
|
||||
position.y = godot::Math::clamp(position.y, (real_t)0.0, _screen_size.y);
|
||||
set_position(position);
|
||||
|
||||
.. tip:: The `delta` parameter in the `_process()` function refers to the *frame
|
||||
length* - the amount of time that the previous frame took to complete.
|
||||
Using this value ensures that your movement will remain consistent even
|
||||
@@ -370,18 +296,6 @@ movement. Let's place this code at the end of the ``_process()`` function:
|
||||
animatedSprite2D.FlipV = velocity.Y > 0;
|
||||
}
|
||||
|
||||
.. code-tab:: cpp
|
||||
|
||||
if (velocity.x != 0) {
|
||||
_animated_sprite->set_animation("walk");
|
||||
_animated_sprite->set_flip_v(false);
|
||||
// See the note below about boolean assignment.
|
||||
_animated_sprite->set_flip_h(velocity.x < 0);
|
||||
} else if (velocity.y != 0) {
|
||||
_animated_sprite->set_animation("up");
|
||||
_animated_sprite->set_flip_v(velocity.y > 0);
|
||||
}
|
||||
|
||||
.. Note:: The boolean assignments in the code above are a common shorthand for
|
||||
programmers. Since we're doing a comparison test (boolean) and also
|
||||
*assigning* a boolean value, we can do both at the same time. Consider
|
||||
@@ -426,10 +340,6 @@ When you're sure the movement is working correctly, add this line to
|
||||
|
||||
Hide();
|
||||
|
||||
.. code-tab:: cpp
|
||||
|
||||
hide();
|
||||
|
||||
Preparing for collisions
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -452,21 +362,6 @@ Add the following at the top of the script. If you're using GDScript, add it aft
|
||||
[Signal]
|
||||
public delegate void HitEventHandler();
|
||||
|
||||
.. code-tab:: cpp
|
||||
|
||||
// This code goes in `player.cpp`.
|
||||
// We need to register the signal here, and while we're here, we can also
|
||||
// register the other methods and register the speed property.
|
||||
void Player::_register_methods() {
|
||||
godot::register_method("_ready", &Player::_ready);
|
||||
godot::register_method("_process", &Player::_process);
|
||||
godot::register_method("start", &Player::start);
|
||||
godot::register_method("_on_body_entered", &Player::_on_body_entered);
|
||||
godot::register_property("speed", &Player::speed, (real_t)400.0);
|
||||
// This below line is the signal.
|
||||
godot::register_signal<Player>("hit", godot::Dictionary());
|
||||
}
|
||||
|
||||
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 next to the
|
||||
@@ -505,16 +400,6 @@ this code to the function:
|
||||
GetNode<CollisionShape2D>("CollisionShape2D").SetDeferred(CollisionShape2D.PropertyName.Disabled, true);
|
||||
}
|
||||
|
||||
.. code-tab:: cpp
|
||||
|
||||
// This code goes in `player.cpp`.
|
||||
void Player::_on_body_entered(godot::Node2D *_body) {
|
||||
hide(); // Player disappears after being hit.
|
||||
emit_signal("hit");
|
||||
// Must be deferred as we can't change physics properties on a physics callback.
|
||||
_collision_shape->set_deferred("disabled", true);
|
||||
}
|
||||
|
||||
Each time an enemy hits the player, the signal is going to be emitted. We need
|
||||
to disable the player's collision so that we don't trigger the ``hit`` signal
|
||||
more than once.
|
||||
@@ -544,13 +429,4 @@ starting a new game.
|
||||
GetNode<CollisionShape2D>("CollisionShape2D").Disabled = false;
|
||||
}
|
||||
|
||||
.. code-tab:: cpp
|
||||
|
||||
// This code goes in `player.cpp`.
|
||||
void Player::start(const godot::Vector2 p_position) {
|
||||
set_position(p_position);
|
||||
show();
|
||||
_collision_shape->set_disabled(false);
|
||||
}
|
||||
|
||||
With the player working, we'll work on the enemy in the next lesson.
|
||||
|
||||
@@ -78,35 +78,6 @@ Add a script to the ``Mob`` like this:
|
||||
// Don't forget to rebuild the project.
|
||||
}
|
||||
|
||||
.. code-tab:: cpp
|
||||
|
||||
// Copy `player.gdns` to `mob.gdns` and replace `Player` with `Mob`.
|
||||
// Attach the `mob.gdns` file to the Mob node.
|
||||
|
||||
// Create two files `mob.cpp` and `mob.hpp` next to `entry.cpp` in `src`.
|
||||
// This code goes in `mob.hpp`. We also define the methods we'll be using here.
|
||||
#ifndef MOB_H
|
||||
#define MOB_H
|
||||
|
||||
#include <AnimatedSprite2D.hpp>
|
||||
#include <Godot.hpp>
|
||||
#include <RigidBody2D.hpp>
|
||||
|
||||
class Mob : public godot::RigidBody2D {
|
||||
GODOT_CLASS(Mob, godot::RigidBody2D)
|
||||
|
||||
godot::AnimatedSprite2D *_animated_sprite;
|
||||
|
||||
public:
|
||||
void _init() {}
|
||||
void _ready();
|
||||
void _on_visible_on_screen_notifier_2d_screen_exited();
|
||||
|
||||
static void _register_methods();
|
||||
};
|
||||
|
||||
#endif // MOB_H
|
||||
|
||||
Now let's look at the rest of the script. In ``_ready()`` we play the animation
|
||||
and randomly choose one of the three animation types:
|
||||
|
||||
@@ -126,22 +97,6 @@ and randomly choose one of the three animation types:
|
||||
animatedSprite2D.Play(mobTypes[GD.Randi() % mobTypes.Length]);
|
||||
}
|
||||
|
||||
.. code-tab:: cpp
|
||||
|
||||
// This code goes in `mob.cpp`.
|
||||
#include "mob.hpp"
|
||||
|
||||
#include <RandomNumberGenerator.hpp>
|
||||
#include <SpriteFrames.hpp>
|
||||
|
||||
void Mob::_ready() {
|
||||
godot::Ref<godot::RandomNumberGenerator> random = godot::RandomNumberGenerator::_new();
|
||||
_animated_sprite = get_node<godot::AnimatedSprite2D>("AnimatedSprite2D");
|
||||
_animated_sprite->set_playing(true);
|
||||
godot::PoolStringArray mob_types = _animated_sprite->get_sprite_frames()->get_animation_names();
|
||||
_animated_sprite->set_animation(mob_types[random->randi() % mob_types.size()]);
|
||||
}
|
||||
|
||||
First, we get the list of animation names from the AnimatedSprite2D's ``sprite_frames``
|
||||
property. This returns an Array containing all three animation names: ``["walk",
|
||||
"swim", "fly"]``.
|
||||
@@ -167,13 +122,6 @@ to the ``Mob`` and add this code:
|
||||
QueueFree();
|
||||
}
|
||||
|
||||
.. code-tab:: cpp
|
||||
|
||||
// This code goes in `mob.cpp`.
|
||||
void Mob::_on_visible_on_screen_notifier_2d_screen_exited() {
|
||||
queue_free();
|
||||
}
|
||||
|
||||
This completes the `Mob` scene.
|
||||
|
||||
With the player and enemies ready, in the next part, we'll bring them together
|
||||
|
||||
@@ -99,80 +99,6 @@ to instance.
|
||||
private int _score;
|
||||
}
|
||||
|
||||
.. code-tab:: cpp
|
||||
|
||||
// Copy `player.gdns` to `main.gdns` and replace `Player` with `Main`.
|
||||
// Attach the `main.gdns` file to the Main node.
|
||||
|
||||
// Create two files `main.cpp` and `main.hpp` next to `entry.cpp` in `src`.
|
||||
// This code goes in `main.hpp`. We also define the methods we'll be using here.
|
||||
#ifndef MAIN_H
|
||||
#define MAIN_H
|
||||
|
||||
#include <AudioStreamPlayer.hpp>
|
||||
#include <CanvasLayer.hpp>
|
||||
#include <Godot.hpp>
|
||||
#include <Node.hpp>
|
||||
#include <PackedScene.hpp>
|
||||
#include <PathFollow2D.hpp>
|
||||
#include <RandomNumberGenerator.hpp>
|
||||
#include <Timer.hpp>
|
||||
|
||||
#include "hud.hpp"
|
||||
#include "player.hpp"
|
||||
|
||||
class Main : public godot::Node {
|
||||
GODOT_CLASS(Main, godot::Node)
|
||||
|
||||
int score;
|
||||
HUD *_hud;
|
||||
Player *_player;
|
||||
godot::Node2D *_start_position;
|
||||
godot::PathFollow2D *_mob_spawn_location;
|
||||
godot::Timer *_mob_timer;
|
||||
godot::Timer *_score_timer;
|
||||
godot::Timer *_start_timer;
|
||||
godot::AudioStreamPlayer *_music;
|
||||
godot::AudioStreamPlayer *_death_sound;
|
||||
godot::Ref<godot::RandomNumberGenerator> _random;
|
||||
|
||||
public:
|
||||
godot::Ref<godot::PackedScene> mob_scene;
|
||||
|
||||
void _init() {}
|
||||
void _ready();
|
||||
void game_over();
|
||||
void new_game();
|
||||
void _on_MobTimer_timeout();
|
||||
void _on_ScoreTimer_timeout();
|
||||
void _on_StartTimer_timeout();
|
||||
|
||||
static void _register_methods();
|
||||
};
|
||||
|
||||
#endif // MAIN_H
|
||||
|
||||
// This code goes in `main.cpp`.
|
||||
#include "main.hpp"
|
||||
|
||||
#include <SceneTree.hpp>
|
||||
|
||||
#include "mob.hpp"
|
||||
|
||||
void Main::_ready() {
|
||||
_hud = get_node<HUD>("HUD");
|
||||
_player = get_node<Player>("Player");
|
||||
_start_position = get_node<godot::Node2D>("StartPosition");
|
||||
_mob_spawn_location = get_node<godot::PathFollow2D>("MobPath/MobSpawnLocation");
|
||||
_mob_timer = get_node<godot::Timer>("MobTimer");
|
||||
_score_timer = get_node<godot::Timer>("ScoreTimer");
|
||||
_start_timer = get_node<godot::Timer>("StartTimer");
|
||||
// Uncomment these after adding the nodes in the "Sound effects" section of "Finishing up".
|
||||
//_music = get_node<godot::AudioStreamPlayer>("Music");
|
||||
//_death_sound = get_node<godot::AudioStreamPlayer>("DeathSound");
|
||||
_random = (godot::Ref<godot::RandomNumberGenerator>)godot::RandomNumberGenerator::_new();
|
||||
}
|
||||
|
||||
Click the ``Main`` node and you will see the ``Mob Scene`` property in the Inspector
|
||||
under "Script Variables".
|
||||
|
||||
@@ -227,20 +153,6 @@ everything up for a new game:
|
||||
GetNode<Timer>("StartTimer").Start();
|
||||
}
|
||||
|
||||
.. code-tab:: cpp
|
||||
|
||||
// This code goes in `main.cpp`.
|
||||
void Main::game_over() {
|
||||
_score_timer->stop();
|
||||
_mob_timer->stop();
|
||||
}
|
||||
|
||||
void Main::new_game() {
|
||||
score = 0;
|
||||
_player->start(_start_position->get_position());
|
||||
_start_timer->start();
|
||||
}
|
||||
|
||||
Now connect the ``timeout()`` signal of each of the Timer nodes (``StartTimer``,
|
||||
``ScoreTimer``, and ``MobTimer``) to the main script. ``StartTimer`` will start
|
||||
the other two timers. ``ScoreTimer`` will increment the score by 1.
|
||||
@@ -268,29 +180,6 @@ the other two timers. ``ScoreTimer`` will increment the score by 1.
|
||||
GetNode<Timer>("ScoreTimer").Start();
|
||||
}
|
||||
|
||||
.. code-tab:: cpp
|
||||
|
||||
// This code goes in `main.cpp`.
|
||||
void Main::_on_ScoreTimer_timeout() {
|
||||
score += 1;
|
||||
}
|
||||
|
||||
void Main::_on_StartTimer_timeout() {
|
||||
_mob_timer->start();
|
||||
_score_timer->start();
|
||||
}
|
||||
|
||||
// Also add this to register all methods and the mob scene property.
|
||||
void Main::_register_methods() {
|
||||
godot::register_method("_ready", &Main::_ready);
|
||||
godot::register_method("game_over", &Main::game_over);
|
||||
godot::register_method("new_game", &Main::new_game);
|
||||
godot::register_method("_on_MobTimer_timeout", &Main::_on_MobTimer_timeout);
|
||||
godot::register_method("_on_ScoreTimer_timeout", &Main::_on_ScoreTimer_timeout);
|
||||
godot::register_method("_on_StartTimer_timeout", &Main::_on_StartTimer_timeout);
|
||||
godot::register_property("mob_scene", &Main::mob_scene, (godot::Ref<godot::PackedScene>)nullptr);
|
||||
}
|
||||
|
||||
In ``_on_mob_timer_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 follows the path, so we
|
||||
@@ -362,34 +251,6 @@ Note that a new instance must be added to the scene using ``add_child()``.
|
||||
AddChild(mob);
|
||||
}
|
||||
|
||||
.. code-tab:: cpp
|
||||
|
||||
// This code goes in `main.cpp`.
|
||||
void Main::_on_MobTimer_timeout() {
|
||||
// Create a new instance of the Mob scene.
|
||||
godot::Node *mob = mob_scene->instance();
|
||||
|
||||
// Choose a random location on Path2D.
|
||||
_mob_spawn_location->set_progress_ratio((real_t)_random->randf());
|
||||
|
||||
// Set the mob's direction perpendicular to the path direction.
|
||||
real_t direction = _mob_spawn_location->get_rotation() + (real_t)Math_PI / 2;
|
||||
|
||||
// Set the mob's position to a random location.
|
||||
mob->set("position", _mob_spawn_location->get_position());
|
||||
|
||||
// Add some randomness to the direction.
|
||||
direction += _random->randf_range((real_t)-Math_PI / 4, (real_t)Math_PI / 4);
|
||||
mob->set("rotation", direction);
|
||||
|
||||
// Choose the velocity for the mob.
|
||||
godot::Vector2 velocity = godot::Vector2(_random->randf_range(150.0, 250.0), 0.0);
|
||||
mob->set("linear_velocity", velocity.rotated(direction));
|
||||
|
||||
// Spawn the mob by adding it to the Main scene.
|
||||
add_child(mob);
|
||||
}
|
||||
|
||||
.. important:: Why ``PI``? In functions requiring angles, Godot uses *radians*,
|
||||
not degrees. Pi represents a half turn in radians, about
|
||||
``3.1415`` (there is also ``TAU`` which is equal to ``2 * PI``).
|
||||
@@ -416,13 +277,6 @@ call to ``_ready()``:
|
||||
NewGame();
|
||||
}
|
||||
|
||||
.. code-tab:: cpp
|
||||
|
||||
// This code goes in `main.cpp`.
|
||||
void Main::_ready() {
|
||||
new_game();
|
||||
}
|
||||
|
||||
Let's also assign ``Main`` as our "Main Scene" - the one that runs automatically
|
||||
when the game launches. Press the "Play" button and select ``main.tscn`` when
|
||||
prompted.
|
||||
|
||||
@@ -105,47 +105,6 @@ Now add this script to ``HUD``:
|
||||
public delegate void StartGameEventHandler();
|
||||
}
|
||||
|
||||
.. code-tab:: cpp
|
||||
|
||||
// Copy `player.gdns` to `hud.gdns` and replace `Player` with `HUD`.
|
||||
// Attach the `hud.gdns` file to the HUD node.
|
||||
|
||||
// Create two files `hud.cpp` and `hud.hpp` next to `entry.cpp` in `src`.
|
||||
// This code goes in `hud.hpp`. We also define the methods we'll be using here.
|
||||
#ifndef HUD_H
|
||||
#define HUD_H
|
||||
|
||||
#include <Button.hpp>
|
||||
#include <CanvasLayer.hpp>
|
||||
#include <Godot.hpp>
|
||||
#include <Label.hpp>
|
||||
#include <Timer.hpp>
|
||||
|
||||
class HUD : public godot::CanvasLayer {
|
||||
GODOT_CLASS(HUD, godot::CanvasLayer)
|
||||
|
||||
godot::Label *_score_label;
|
||||
godot::Label *_message_label;
|
||||
godot::Timer *_start_message_timer;
|
||||
godot::Timer *_get_ready_message_timer;
|
||||
godot::Button *_start_button;
|
||||
godot::Timer *_start_button_timer;
|
||||
|
||||
public:
|
||||
void _init() {}
|
||||
void _ready();
|
||||
void show_get_ready();
|
||||
void show_game_over();
|
||||
void update_score(const int score);
|
||||
void _on_StartButton_pressed();
|
||||
void _on_StartMessageTimer_timeout();
|
||||
void _on_GetReadyMessageTimer_timeout();
|
||||
|
||||
static void _register_methods();
|
||||
};
|
||||
|
||||
#endif // HUD_H
|
||||
|
||||
We now want to display a message temporarily,
|
||||
such as "Get Ready", so we add the following code
|
||||
|
||||
@@ -168,31 +127,6 @@ such as "Get Ready", so we add the following code
|
||||
GetNode<Timer>("MessageTimer").Start();
|
||||
}
|
||||
|
||||
.. code-tab:: cpp
|
||||
|
||||
// This code goes in `hud.cpp`.
|
||||
#include "hud.hpp"
|
||||
|
||||
void HUD::_ready() {
|
||||
_score_label = get_node<godot::Label>("ScoreLabel");
|
||||
_message_label = get_node<godot::Label>("MessageLabel");
|
||||
_start_message_timer = get_node<godot::Timer>("StartMessageTimer");
|
||||
_get_ready_message_timer = get_node<godot::Timer>("GetReadyMessageTimer");
|
||||
_start_button = get_node<godot::Button>("StartButton");
|
||||
_start_button_timer = get_node<godot::Timer>("StartButtonTimer");
|
||||
}
|
||||
|
||||
void HUD::_register_methods() {
|
||||
godot::register_method("_ready", &HUD::_ready);
|
||||
godot::register_method("show_get_ready", &HUD::show_get_ready);
|
||||
godot::register_method("show_game_over", &HUD::show_game_over);
|
||||
godot::register_method("update_score", &HUD::update_score);
|
||||
godot::register_method("_on_StartButton_pressed", &HUD::_on_StartButton_pressed);
|
||||
godot::register_method("_on_StartMessageTimer_timeout", &HUD::_on_StartMessageTimer_timeout);
|
||||
godot::register_method("_on_GetReadyMessageTimer_timeout", &HUD::_on_GetReadyMessageTimer_timeout);
|
||||
godot::register_signal<HUD>("start_game", godot::Dictionary());
|
||||
}
|
||||
|
||||
We also need to process what happens when the player loses. The code below will show "Game Over" for 2 seconds, then return to the title screen and, after a brief pause, show the "Start" button.
|
||||
|
||||
.. tabs::
|
||||
@@ -226,23 +160,6 @@ We also need to process what happens when the player loses. The code below will
|
||||
GetNode<Button>("StartButton").Show();
|
||||
}
|
||||
|
||||
.. code-tab:: cpp
|
||||
|
||||
// This code goes in `hud.cpp`.
|
||||
// There is no `yield` in GDExtension, so we need to have every
|
||||
// step be its own method that is called on timer timeout.
|
||||
void HUD::show_get_ready() {
|
||||
_message_label->set_text("Get Ready");
|
||||
_message_label->show();
|
||||
_get_ready_message_timer->start();
|
||||
}
|
||||
|
||||
void HUD::show_game_over() {
|
||||
_message_label->set_text("Game Over");
|
||||
_message_label->show();
|
||||
_start_message_timer->start();
|
||||
}
|
||||
|
||||
This function is called when the player loses. It will show "Game Over" for 2
|
||||
seconds, then return to the title screen and, after a brief pause, show the
|
||||
"Start" button.
|
||||
@@ -267,13 +184,6 @@ Add the code below to ``HUD`` to update the score
|
||||
GetNode<Label>("ScoreLabel").Text = score.ToString();
|
||||
}
|
||||
|
||||
.. code-tab:: cpp
|
||||
|
||||
// This code goes in `hud.cpp`.
|
||||
void HUD::update_score(const int p_score) {
|
||||
_score_label->set_text(godot::Variant(p_score));
|
||||
}
|
||||
|
||||
Connect the ``timeout()`` signal of ``MessageTimer`` and the ``pressed()``
|
||||
signal of ``StartButton``, and add the following code to the new functions:
|
||||
|
||||
@@ -300,25 +210,6 @@ signal of ``StartButton``, and add the following code to the new functions:
|
||||
GetNode<Label>("Message").Hide();
|
||||
}
|
||||
|
||||
.. code-tab:: cpp
|
||||
|
||||
// This code goes in `hud.cpp`.
|
||||
void HUD::_on_StartButton_pressed() {
|
||||
_start_button_timer->stop();
|
||||
_start_button->hide();
|
||||
emit_signal("start_game");
|
||||
}
|
||||
|
||||
void HUD::_on_StartMessageTimer_timeout() {
|
||||
_message_label->set_text("Dodge the Creeps!");
|
||||
_message_label->show();
|
||||
_start_button_timer->start();
|
||||
}
|
||||
|
||||
void HUD::_on_GetReadyMessageTimer_timeout() {
|
||||
_message_label->hide();
|
||||
}
|
||||
|
||||
Connecting HUD to Main
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -351,11 +242,6 @@ In ``new_game()``, update the score display and show the "Get Ready" message:
|
||||
hud.UpdateScore(_score);
|
||||
hud.ShowMessage("Get Ready!");
|
||||
|
||||
.. code-tab:: cpp
|
||||
|
||||
_hud->update_score(score);
|
||||
_hud->show_get_ready();
|
||||
|
||||
In ``game_over()`` we need to call the corresponding ``HUD`` function:
|
||||
|
||||
.. tabs::
|
||||
@@ -367,10 +253,6 @@ In ``game_over()`` we need to call the corresponding ``HUD`` function:
|
||||
|
||||
GetNode<HUD>("HUD").ShowGameOver();
|
||||
|
||||
.. code-tab:: cpp
|
||||
|
||||
_hud->show_game_over();
|
||||
|
||||
Finally, add this to ``_on_score_timer_timeout()`` to keep the display in sync
|
||||
with the changing score:
|
||||
|
||||
@@ -383,10 +265,6 @@ with the changing score:
|
||||
|
||||
GetNode<HUD>("HUD").UpdateScore(_score);
|
||||
|
||||
.. code-tab:: cpp
|
||||
|
||||
_hud->update_score(score);
|
||||
|
||||
.. warning::
|
||||
|
||||
Remember to remove the call to ``new_game()`` from
|
||||
@@ -424,10 +302,6 @@ the ``new_game()`` function in ``Main``:
|
||||
// we have to use the original Godot snake_case name.
|
||||
GetTree().CallGroup("mobs", Node.MethodName.QueueFree);
|
||||
|
||||
.. code-tab:: cpp
|
||||
|
||||
get_tree()->call_group("mobs", "queue_free");
|
||||
|
||||
The ``call_group()`` function calls the named function on every node in a
|
||||
group - in this case we are telling every mob to delete itself.
|
||||
|
||||
|
||||
@@ -69,25 +69,6 @@ Finally, add ``$DeathSound.play()`` in the ``game_over()`` function.
|
||||
GetNode<AudioStreamPlayer>("Music").Play();
|
||||
}
|
||||
|
||||
.. code-tab:: cpp
|
||||
|
||||
void Main::_ready() {
|
||||
...
|
||||
_music = get_node<godot::AudioStreamPlayer>("Music");
|
||||
_death_sound = get_node<godot::AudioStreamPlayer>("DeathSound");
|
||||
}
|
||||
|
||||
void Main::game_over() {
|
||||
...
|
||||
_music->stop();
|
||||
_death_sound->play();
|
||||
}
|
||||
|
||||
void Main::new_game() {
|
||||
...
|
||||
_music->play();
|
||||
}
|
||||
|
||||
|
||||
Keyboard shortcut
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
Reference in New Issue
Block a user