|
@@ -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.
|