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_jump{ "jump" };
 | 
			
		||||
String PlayerInput::sig_crouch{ "crouch" };
 | 
			
		||||
String PlayerInput::sig_activate{ "activate" };
 | 
			
		||||
 | 
			
		||||
void PlayerInput::_bind_methods() {
 | 
			
		||||
	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_jump));
 | 
			
		||||
	ADD_SIGNAL(MethodInfo(sig_crouch, PropertyInfo(Variant::BOOL, "is_crouching")));
 | 
			
		||||
	ADD_SIGNAL(MethodInfo(sig_activate));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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()) {
 | 
			
		||||
		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_jump;
 | 
			
		||||
	static String sig_crouch;
 | 
			
		||||
	static String sig_activate;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	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/hitbox.h"
 | 
			
		||||
#include "wave_survival/hitscan_muzzle.h"
 | 
			
		||||
#include "wave_survival/interactable.h"
 | 
			
		||||
#include "wave_survival/npc_unit.h"
 | 
			
		||||
#include "wave_survival/patrol_path.h"
 | 
			
		||||
#include "wave_survival/player_body.h"
 | 
			
		||||
#include "wave_survival/player_camera.h"
 | 
			
		||||
#include "wave_survival/player_detector.h"
 | 
			
		||||
#include "wave_survival/player_input.h"
 | 
			
		||||
#include "wave_survival/player_interactor.h"
 | 
			
		||||
#include "wave_survival/state.h"
 | 
			
		||||
#include "wave_survival/state_machine.h"
 | 
			
		||||
#include "wave_survival/weapon_base.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -43,6 +45,8 @@ void initialize_wave_survival_module(ModuleInitializationLevel p_level) {
 | 
			
		|||
	GDREGISTER_CLASS(PlayerDetector);
 | 
			
		||||
	GDREGISTER_CLASS(Hitbox);
 | 
			
		||||
	GDREGISTER_CLASS(DamageBox);
 | 
			
		||||
	GDREGISTER_CLASS(PlayerInteractor);
 | 
			
		||||
	GDREGISTER_CLASS(Interactable);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void uninitialize_wave_survival_module(ModuleInitializationLevel p_level) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -25,6 +25,9 @@ public:
 | 
			
		|||
	void set_starting_weapon(Ref<PackedScene> weapon_scene);
 | 
			
		||||
	Ref<PackedScene> get_starting_weapon() const;
 | 
			
		||||
 | 
			
		||||
	void pickup_demo_pack();
 | 
			
		||||
	bool try_use_demo_pack();
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	Node3D *weapon_parent{ nullptr };
 | 
			
		||||
	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"]
 | 
			
		||||
 | 
			
		||||
[sub_resource type="SphereShape3D" id="SphereShape3D_eqqp1"]
 | 
			
		||||
radius = 0.2
 | 
			
		||||
 | 
			
		||||
[sub_resource type="GDScript" id="GDScript_eqqp1"]
 | 
			
		||||
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)
 | 
			
		||||
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="."]
 | 
			
		||||
unique_name_in_owner = true
 | 
			
		||||
process_mode = 3
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -91,6 +91,7 @@ activate={
 | 
			
		|||
3d_physics/layer_2="Precision"
 | 
			
		||||
3d_physics/layer_3="Hitbox(Enemy)"
 | 
			
		||||
3d_physics/layer_4="Hitbox(Player)"
 | 
			
		||||
3d_physics/layer_5="Interactables"
 | 
			
		||||
 | 
			
		||||
[physics]
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue