feat: added interactions, demo packs and destructables
This commit is contained in:
parent
d66c999039
commit
5a4ac26c72
33
modules/wave_survival/interactable.cpp
Normal file
33
modules/wave_survival/interactable.cpp
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
#include "interactable.h"
|
||||||
|
#include "macros.h"
|
||||||
|
|
||||||
|
void Interactable::_bind_methods() {
|
||||||
|
ClassDB::bind_method(D_METHOD("activate", "interactor"), &self_type::activate);
|
||||||
|
ClassDB::bind_method(D_METHOD("set_highlighted", "value"), &self_type::set_highlighted);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_highlighted"), &self_type::get_highlighted);
|
||||||
|
GDVIRTUAL_BIND(_activated, "interactor");
|
||||||
|
GDVIRTUAL_BIND(_highlight_changed, "interactor", "value");
|
||||||
|
}
|
||||||
|
|
||||||
|
void Interactable::activate(PlayerInteractor *interactor) {
|
||||||
|
activated(interactor);
|
||||||
|
GDVIRTUAL_CALL(_activated, interactor);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Interactable::set_highlighted(PlayerInteractor *interactor, bool value) {
|
||||||
|
this->highlighted = value;
|
||||||
|
highlight_changed(interactor, value);
|
||||||
|
GDVIRTUAL_CALL(_highlight_changed, interactor, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Interactable::get_highlighted() const {
|
||||||
|
return this->highlighted;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Interactable::set_highlight_tooltip(String value) {
|
||||||
|
this->highlight_tooltip = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
String Interactable::get_highlight_tooltip() const {
|
||||||
|
return this->highlight_tooltip;
|
||||||
|
}
|
30
modules/wave_survival/interactable.h
Normal file
30
modules/wave_survival/interactable.h
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
#ifndef INTERACTABLE_H
|
||||||
|
#define INTERACTABLE_H
|
||||||
|
|
||||||
|
#include "player_interactor.h"
|
||||||
|
#include "scene/main/node.h"
|
||||||
|
|
||||||
|
class Interactable : public Node {
|
||||||
|
GDCLASS(Interactable, Node);
|
||||||
|
static void _bind_methods();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void activated(PlayerInteractor *interactor) {}
|
||||||
|
GDVIRTUAL1_REQUIRED(_activated, PlayerInteractor *);
|
||||||
|
virtual void highlight_changed(PlayerInteractor *interactor, bool new_value) {}
|
||||||
|
GDVIRTUAL2(_highlight_changed, PlayerInteractor *, bool);
|
||||||
|
|
||||||
|
public:
|
||||||
|
void activate(PlayerInteractor *interactor);
|
||||||
|
|
||||||
|
void set_highlighted(PlayerInteractor *interactor, bool value);
|
||||||
|
bool get_highlighted() const;
|
||||||
|
void set_highlight_tooltip(String value);
|
||||||
|
String get_highlight_tooltip() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool highlighted{ false };
|
||||||
|
String highlight_tooltip{ "Activate" };
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // !INTERACTABLE_H
|
|
@ -9,6 +9,7 @@ String PlayerInput::sig_switch_weapon{ "switch_weapon" };
|
||||||
String PlayerInput::sig_run{ "run" };
|
String PlayerInput::sig_run{ "run" };
|
||||||
String PlayerInput::sig_jump{ "jump" };
|
String PlayerInput::sig_jump{ "jump" };
|
||||||
String PlayerInput::sig_crouch{ "crouch" };
|
String PlayerInput::sig_crouch{ "crouch" };
|
||||||
|
String PlayerInput::sig_activate{ "activate" };
|
||||||
|
|
||||||
void PlayerInput::_bind_methods() {
|
void PlayerInput::_bind_methods() {
|
||||||
ADD_SIGNAL(MethodInfo(sig_movement_input, PropertyInfo(Variant::VECTOR2, "axes")));
|
ADD_SIGNAL(MethodInfo(sig_movement_input, PropertyInfo(Variant::VECTOR2, "axes")));
|
||||||
|
@ -19,6 +20,7 @@ void PlayerInput::_bind_methods() {
|
||||||
ADD_SIGNAL(MethodInfo(sig_run, PropertyInfo(Variant::BOOL, "is_running")));
|
ADD_SIGNAL(MethodInfo(sig_run, PropertyInfo(Variant::BOOL, "is_running")));
|
||||||
ADD_SIGNAL(MethodInfo(sig_jump));
|
ADD_SIGNAL(MethodInfo(sig_jump));
|
||||||
ADD_SIGNAL(MethodInfo(sig_crouch, PropertyInfo(Variant::BOOL, "is_crouching")));
|
ADD_SIGNAL(MethodInfo(sig_crouch, PropertyInfo(Variant::BOOL, "is_crouching")));
|
||||||
|
ADD_SIGNAL(MethodInfo(sig_activate));
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerInput::normalize_input() {
|
void PlayerInput::normalize_input() {
|
||||||
|
@ -83,4 +85,7 @@ void PlayerInput::unhandled_input(Ref<InputEvent> const &event) {
|
||||||
if (event->is_action("switch_weapon") && event->is_pressed()) {
|
if (event->is_action("switch_weapon") && event->is_pressed()) {
|
||||||
emit_signal(sig_switch_weapon);
|
emit_signal(sig_switch_weapon);
|
||||||
}
|
}
|
||||||
|
if (event->is_action("activate") && event->is_pressed()) {
|
||||||
|
emit_signal(sig_activate);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ public:
|
||||||
static String sig_run;
|
static String sig_run;
|
||||||
static String sig_jump;
|
static String sig_jump;
|
||||||
static String sig_crouch;
|
static String sig_crouch;
|
||||||
|
static String sig_activate;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool was_paused{ false };
|
bool was_paused{ false };
|
||||||
|
|
87
modules/wave_survival/player_interactor.cpp
Normal file
87
modules/wave_survival/player_interactor.cpp
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
#include "player_interactor.h"
|
||||||
|
#include "interactable.h"
|
||||||
|
#include "player_body.h"
|
||||||
|
#include "player_input.h"
|
||||||
|
|
||||||
|
void PlayerInteractor::_bind_methods() {
|
||||||
|
ClassDB::bind_method(D_METHOD("pickup_demo_pack"), &self_type::pickup_demo_pack);
|
||||||
|
ClassDB::bind_method(D_METHOD("try_use_demo_pack"), &self_type::try_use_demo_pack);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlayerInteractor::highlight_removed() {
|
||||||
|
this->interactable->disconnect("tree_exiting", this->on_highlight_removed);
|
||||||
|
this->interactable->set_highlighted(this, false);
|
||||||
|
this->interactable = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlayerInteractor::activate() {
|
||||||
|
if (interactable != nullptr) {
|
||||||
|
interactable->activate(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlayerInteractor::ready() {
|
||||||
|
PlayerInput *input{ cast_to<PlayerInput>(get_node(NodePath("%PlayerInput"))) };
|
||||||
|
input->connect(PlayerInput::sig_activate, callable_mp(this, &self_type::activate));
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlayerInteractor::process(double delta) {
|
||||||
|
Interactable *new_interactable{ nullptr };
|
||||||
|
if (is_colliding()) {
|
||||||
|
if (Node * hit{ cast_to<Node>(this->get_collider(0)) }) {
|
||||||
|
TypedArray<Node> interactables = hit->find_children("*", Interactable::get_class_static());
|
||||||
|
new_interactable = interactables.size() > 0 ? cast_to<Interactable>(interactables[0]) : nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (new_interactable != this->interactable) {
|
||||||
|
if (this->interactable != nullptr) {
|
||||||
|
this->interactable->set_highlighted(this, false);
|
||||||
|
this->interactable->disconnect("tree_exiting", this->on_highlight_removed);
|
||||||
|
}
|
||||||
|
this->interactable = new_interactable;
|
||||||
|
if (this->interactable != nullptr) {
|
||||||
|
this->interactable->set_highlighted(this, true);
|
||||||
|
this->interactable->connect("tree_exiting", this->on_highlight_removed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlayerInteractor::_notification(int what) {
|
||||||
|
if (Engine::get_singleton()->is_editor_hint()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch (what) {
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
case NOTIFICATION_READY:
|
||||||
|
set_process(true);
|
||||||
|
ready();
|
||||||
|
return;
|
||||||
|
case NOTIFICATION_PROCESS:
|
||||||
|
process(get_process_delta_time());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PackedStringArray PlayerInteractor::get_configuration_warnings() const {
|
||||||
|
PackedStringArray warnings{ super_type::get_configuration_warnings() };
|
||||||
|
if (cast_to<PlayerBody>(get_owner()) == nullptr) {
|
||||||
|
warnings.push_back("PlayerInteractor should be part of and owned by a PlayerBody node to work properly.");
|
||||||
|
}
|
||||||
|
if (get_node(NodePath("%PlayerInput")) == nullptr) {
|
||||||
|
warnings.push_back("PlayerInteractor should have a node named '%PlayerInput' in the same scene as it");
|
||||||
|
}
|
||||||
|
return warnings;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlayerInteractor::pickup_demo_pack() {
|
||||||
|
++this->num_demo_packs;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PlayerInteractor::try_use_demo_pack() {
|
||||||
|
if (this->num_demo_packs > 0) {
|
||||||
|
--this->num_demo_packs;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
30
modules/wave_survival/player_interactor.h
Normal file
30
modules/wave_survival/player_interactor.h
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
#ifndef PLAYER_INTERACTOR_H
|
||||||
|
#define PLAYER_INTERACTOR_H
|
||||||
|
|
||||||
|
#include "scene/3d/physics/shape_cast_3d.h"
|
||||||
|
class Interactable;
|
||||||
|
|
||||||
|
class PlayerInteractor : public ShapeCast3D {
|
||||||
|
GDCLASS(PlayerInteractor, ShapeCast3D);
|
||||||
|
static void _bind_methods();
|
||||||
|
void highlight_removed();
|
||||||
|
void activate();
|
||||||
|
void ready();
|
||||||
|
void process(double delta);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void _notification(int what);
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual PackedStringArray get_configuration_warnings() const override;
|
||||||
|
void pickup_demo_pack();
|
||||||
|
bool try_use_demo_pack();
|
||||||
|
|
||||||
|
private:
|
||||||
|
int num_demo_packs{ 0 };
|
||||||
|
Interactable *interactable{ nullptr };
|
||||||
|
Callable on_highlight_removed{ callable_mp(this, &self_type::highlight_removed) };
|
||||||
|
static String activate_method_name;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // !PLAYER_INTERACTOR_H
|
|
@ -7,12 +7,14 @@
|
||||||
#include "wave_survival/health_status.h"
|
#include "wave_survival/health_status.h"
|
||||||
#include "wave_survival/hitbox.h"
|
#include "wave_survival/hitbox.h"
|
||||||
#include "wave_survival/hitscan_muzzle.h"
|
#include "wave_survival/hitscan_muzzle.h"
|
||||||
|
#include "wave_survival/interactable.h"
|
||||||
#include "wave_survival/npc_unit.h"
|
#include "wave_survival/npc_unit.h"
|
||||||
#include "wave_survival/patrol_path.h"
|
#include "wave_survival/patrol_path.h"
|
||||||
#include "wave_survival/player_body.h"
|
#include "wave_survival/player_body.h"
|
||||||
#include "wave_survival/player_camera.h"
|
#include "wave_survival/player_camera.h"
|
||||||
#include "wave_survival/player_detector.h"
|
#include "wave_survival/player_detector.h"
|
||||||
#include "wave_survival/player_input.h"
|
#include "wave_survival/player_input.h"
|
||||||
|
#include "wave_survival/player_interactor.h"
|
||||||
#include "wave_survival/state.h"
|
#include "wave_survival/state.h"
|
||||||
#include "wave_survival/state_machine.h"
|
#include "wave_survival/state_machine.h"
|
||||||
#include "wave_survival/weapon_base.h"
|
#include "wave_survival/weapon_base.h"
|
||||||
|
@ -43,6 +45,8 @@ void initialize_wave_survival_module(ModuleInitializationLevel p_level) {
|
||||||
GDREGISTER_CLASS(PlayerDetector);
|
GDREGISTER_CLASS(PlayerDetector);
|
||||||
GDREGISTER_CLASS(Hitbox);
|
GDREGISTER_CLASS(Hitbox);
|
||||||
GDREGISTER_CLASS(DamageBox);
|
GDREGISTER_CLASS(DamageBox);
|
||||||
|
GDREGISTER_CLASS(PlayerInteractor);
|
||||||
|
GDREGISTER_CLASS(Interactable);
|
||||||
}
|
}
|
||||||
|
|
||||||
void uninitialize_wave_survival_module(ModuleInitializationLevel p_level) {
|
void uninitialize_wave_survival_module(ModuleInitializationLevel p_level) {
|
||||||
|
|
|
@ -25,6 +25,9 @@ public:
|
||||||
void set_starting_weapon(Ref<PackedScene> weapon_scene);
|
void set_starting_weapon(Ref<PackedScene> weapon_scene);
|
||||||
Ref<PackedScene> get_starting_weapon() const;
|
Ref<PackedScene> get_starting_weapon() const;
|
||||||
|
|
||||||
|
void pickup_demo_pack();
|
||||||
|
bool try_use_demo_pack();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Node3D *weapon_parent{ nullptr };
|
Node3D *weapon_parent{ nullptr };
|
||||||
unsigned current{ 0 };
|
unsigned current{ 0 };
|
||||||
|
|
File diff suppressed because one or more lines are too long
27
project/objects/pickups/demo_pack_pickup.tscn
Normal file
27
project/objects/pickups/demo_pack_pickup.tscn
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
[gd_scene load_steps=4 format=3 uid="uid://cclghy01gblif"]
|
||||||
|
|
||||||
|
[sub_resource type="SphereShape3D" id="SphereShape3D_kl827"]
|
||||||
|
radius = 0.1282442
|
||||||
|
|
||||||
|
[sub_resource type="GDScript" id="GDScript_kl827"]
|
||||||
|
script/source = "extends Interactable
|
||||||
|
|
||||||
|
func _activated(interactor: PlayerInteractor) -> void:
|
||||||
|
interactor.pickup_demo_pack()
|
||||||
|
get_owner().queue_free()
|
||||||
|
"
|
||||||
|
|
||||||
|
[sub_resource type="BoxMesh" id="BoxMesh_kl827"]
|
||||||
|
size = Vector3(0.2, 0.1, 0.2)
|
||||||
|
|
||||||
|
[node name="DemoPackPickup" type="StaticBody3D"]
|
||||||
|
collision_layer = 18
|
||||||
|
|
||||||
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
|
||||||
|
shape = SubResource("SphereShape3D_kl827")
|
||||||
|
|
||||||
|
[node name="Interactable" type="Interactable" parent="."]
|
||||||
|
script = SubResource("GDScript_kl827")
|
||||||
|
|
||||||
|
[node name="MeshInstance3D" type="MeshInstance3D" parent="."]
|
||||||
|
mesh = SubResource("BoxMesh_kl827")
|
|
@ -1,7 +1,10 @@
|
||||||
[gd_scene load_steps=5 format=3 uid="uid://snjgu4yp5swd"]
|
[gd_scene load_steps=6 format=3 uid="uid://snjgu4yp5swd"]
|
||||||
|
|
||||||
[ext_resource type="PackedScene" uid="uid://ce40pq785yoyi" path="res://objects/weapons/rifle.tscn" id="1_eqqp1"]
|
[ext_resource type="PackedScene" uid="uid://ce40pq785yoyi" path="res://objects/weapons/rifle.tscn" id="1_eqqp1"]
|
||||||
|
|
||||||
|
[sub_resource type="SphereShape3D" id="SphereShape3D_eqqp1"]
|
||||||
|
radius = 0.2
|
||||||
|
|
||||||
[sub_resource type="GDScript" id="GDScript_eqqp1"]
|
[sub_resource type="GDScript" id="GDScript_eqqp1"]
|
||||||
script/source = "extends HealthStatus
|
script/source = "extends HealthStatus
|
||||||
|
|
||||||
|
@ -23,6 +26,12 @@ unique_name_in_owner = true
|
||||||
transform = Transform3D(-1, 0, -8.74228e-08, 0, 1, 0, 8.74228e-08, 0, -1, 0, 1.60811, 0)
|
transform = Transform3D(-1, 0, -8.74228e-08, 0, 1, 0, 8.74228e-08, 0, -1, 0, 1.60811, 0)
|
||||||
fov = 60.0
|
fov = 60.0
|
||||||
|
|
||||||
|
[node name="PlayerInteractor" type="PlayerInteractor" parent="PlayerCamera"]
|
||||||
|
shape = SubResource("SphereShape3D_eqqp1")
|
||||||
|
target_position = Vector3(0, 0, -2)
|
||||||
|
collision_mask = 22
|
||||||
|
collide_with_areas = true
|
||||||
|
|
||||||
[node name="PlayerInput" type="PlayerInput" parent="."]
|
[node name="PlayerInput" type="PlayerInput" parent="."]
|
||||||
unique_name_in_owner = true
|
unique_name_in_owner = true
|
||||||
process_mode = 3
|
process_mode = 3
|
||||||
|
|
|
@ -91,6 +91,7 @@ activate={
|
||||||
3d_physics/layer_2="Precision"
|
3d_physics/layer_2="Precision"
|
||||||
3d_physics/layer_3="Hitbox(Enemy)"
|
3d_physics/layer_3="Hitbox(Enemy)"
|
||||||
3d_physics/layer_4="Hitbox(Player)"
|
3d_physics/layer_4="Hitbox(Player)"
|
||||||
|
3d_physics/layer_5="Interactables"
|
||||||
|
|
||||||
[physics]
|
[physics]
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue