diff --git a/SConstruct b/SConstruct index a17df99..27e219b 100644 --- a/SConstruct +++ b/SConstruct @@ -82,6 +82,8 @@ elif env['platform'] == "windows": # that way you can run scons in a vs 2017 prompt and it will find all the required tools env.Append(ENV=os.environ) + env.Append(CXXFLAGS=['-std=c++17']) + env.Append(LINKFLAGS=[ '--static', '-Wl,--no-undefined', diff --git a/godot/Main.tscn b/godot/Main.tscn index d63b2cb..4257b35 100644 --- a/godot/Main.tscn +++ b/godot/Main.tscn @@ -1,8 +1,9 @@ -[gd_scene load_steps=4 format=2] +[gd_scene load_steps=5 format=2] [ext_resource path="res://Main.gdns" type="Script" id=1] [ext_resource path="res://levels/PrototypeR.tscn" type="PackedScene" id=2] -[ext_resource path="res://GUI/GameOver.tscn" type="PackedScene" id=3] +[ext_resource path="res://gui/GameOver.tscn" type="PackedScene" id=3] +[ext_resource path="res://gui/GameWon.tscn" type="PackedScene" id=4] [node name="Main" type="Node"] pause_mode = 2 @@ -14,3 +15,6 @@ pause_mode = 1 [node name="GameOver" parent="." instance=ExtResource( 3 )] visible = false + +[node name="GameWon" parent="." instance=ExtResource( 4 )] +visible = false diff --git a/godot/characters/enemies/WalkingEnemy.gd b/godot/characters/enemies/WalkingEnemy.gd index c1c54b5..94a01b5 100644 --- a/godot/characters/enemies/WalkingEnemy.gd +++ b/godot/characters/enemies/WalkingEnemy.gd @@ -16,6 +16,7 @@ func _ready() -> void: $AnimatedSprite.flip_h = true $FloorChecker.position.x = $CollisionShape2D.shape.get_extents().x * direction $FloorChecker.enabled = detect_edges + Event.connect("level_loaded", self, "_on_level_loaded") func _physics_process(_delta: float) -> void: @@ -33,6 +34,13 @@ func _physics_process(_delta: float) -> void: if collision.collider.name == "Player": emit_signal("player_touched") + Event.emit_signal("object_updated", self.get_name(), "Walking", global_position, velocity) + func squash() -> void: + Event.emit_signal("object_removed", self.get_name()) queue_free() + + +func _on_level_loaded() -> void: + Event.emit_signal("object_created", self.get_name(), "Walking", global_position, Vector2(0, 0)) diff --git a/godot/characters/enemies/blightwing/Blightwing.gd b/godot/characters/enemies/blightwing/Blightwing.gd index 6186bea..1446628 100644 --- a/godot/characters/enemies/blightwing/Blightwing.gd +++ b/godot/characters/enemies/blightwing/Blightwing.gd @@ -22,6 +22,8 @@ func _ready() -> void: if direction == 1: $AnimatedSprite.flip_h = true + Event.connect("level_loaded", self, "_on_level_loaded") + func _physics_process(delta: float) -> void: if $LeftWallChecker.is_colliding(): @@ -29,17 +31,18 @@ func _physics_process(delta: float) -> void: elif $RightWallChecker.is_colliding(): wall_checker_collided($RightWallChecker) + var velocity: Vector2 = Vector2(0, 0) if not follow_path: var target_position = position target_position.x *= 2 * direction position = position.move_toward(target_position, round(speed * delta)) - var velocity = get_velocity_towards_target(delta) + velocity = get_velocity_towards_target(delta) var collision = move_and_collide(velocity, true, true, true) if collision and collision.collider.name != "Player": var _collision = move_and_collide(velocity) else: - var velocity = get_velocity_towards_target(delta) + velocity = get_velocity_towards_target(delta) var collision = move_and_collide(velocity, true, true, true) if collision and collision.collider.name != "Player": @@ -60,6 +63,8 @@ func _physics_process(delta: float) -> void: elif start_position.x + target.x < position.x: $AnimatedSprite.flip_h = false + Event.emit_signal("object_updated", self.get_name(), "Flying", global_position, velocity) + func get_velocity_towards_target(delta: float) -> Vector2: var velocity = Vector2(0, 0) @@ -80,3 +85,7 @@ func wall_checker_collided(wall_checker: RayCast2D) -> void: emit_signal("player_touched") direction *= -1 $AnimatedSprite.flip_h = not $AnimatedSprite.flip_h + + +func _on_level_loaded() -> void: + Event.emit_signal("object_created", self.get_name(), "Flying", global_position, Vector2(0, 0)) diff --git a/godot/characters/enemies/blockface/Blockface.gd b/godot/characters/enemies/blockface/Blockface.gd index b307882..3f52a5a 100644 --- a/godot/characters/enemies/blockface/Blockface.gd +++ b/godot/characters/enemies/blockface/Blockface.gd @@ -11,9 +11,14 @@ export var fall_speed = 75.0 var return_to_start: bool = false +func _ready() -> void: + Event.connect("level_loaded", self, "_on_level_loaded") + + func _physics_process(delta: float) -> void: if return_to_start: position = position.move_toward(start_position, speed * delta) + Event.emit_signal("object_updated", self.get_name(), "Rising", global_position, velocity) else: var collision = move_and_collide(Vector2(0, (position.y + fall_speed) * delta)) if collision: @@ -21,7 +26,12 @@ func _physics_process(delta: float) -> void: $AnimatedSprite.play("normal") if collision.collider.name == "Player": emit_signal("player_touched") + Event.emit_signal("object_updated", self.get_name(), "Falling", global_position, velocity) if position.y <= start_position.y: return_to_start = false $AnimatedSprite.play("angry") + + +func _on_level_loaded() -> void: + Event.emit_signal("object_created", self.get_name(), "Falling", global_position, Vector2(0, 0)) diff --git a/godot/GUI/GameOver.tscn b/godot/gui/GameOver.tscn similarity index 96% rename from godot/GUI/GameOver.tscn rename to godot/gui/GameOver.tscn index fde9238..56c19a8 100644 --- a/godot/GUI/GameOver.tscn +++ b/godot/gui/GameOver.tscn @@ -2,7 +2,7 @@ [ext_resource path="res://assets/fonts/ttf/PixelOperator8.ttf" type="DynamicFontData" id=1] [ext_resource path="res://assets/fonts/ttf/PixelOperatorHB8.ttf" type="DynamicFontData" id=2] -[ext_resource path="res://GUI/botonreiniciar.gdns" type="Script" id=3] +[ext_resource path="res://gui/GameOverScreen.gdns" type="Script" id=3] [ext_resource path="res://assets/sounds/died.wav" type="AudioStream" id=4] [sub_resource type="DynamicFont" id=1] diff --git a/godot/GUI/botonreiniciar.gdns b/godot/gui/GameOverScreen.gdns similarity index 100% rename from godot/GUI/botonreiniciar.gdns rename to godot/gui/GameOverScreen.gdns diff --git a/godot/gui/GameWon.tscn b/godot/gui/GameWon.tscn new file mode 100644 index 0000000..49889fc --- /dev/null +++ b/godot/gui/GameWon.tscn @@ -0,0 +1,48 @@ +[gd_scene load_steps=7 format=2] + +[ext_resource path="res://assets/fonts/ttf/PixelOperator8.ttf" type="DynamicFontData" id=1] +[ext_resource path="res://assets/fonts/ttf/PixelOperatorHB8.ttf" type="DynamicFontData" id=2] +[ext_resource path="res://gui/GameWonScreen.gdns" type="Script" id=3] + +[sub_resource type="DynamicFont" id=1] +size = 50 +font_data = ExtResource( 1 ) + +[sub_resource type="DynamicFont" id=2] +font_data = ExtResource( 2 ) + +[sub_resource type="StyleBoxFlat" id=3] +bg_color = Color( 0.0705882, 0.917647, 0, 1 ) + +[node name="GameWon" type="CanvasLayer"] +script = ExtResource( 3 ) + +[node name="Control" type="Control" parent="."] +margin_right = 40.0 +margin_bottom = 40.0 + +[node name="ColorRect" type="ColorRect" parent="Control"] +margin_right = 512.0 +margin_bottom = 288.0 +rect_min_size = Vector2( 512, 288 ) +color = Color( 0, 0, 0, 1 ) + +[node name="Label" type="Label" parent="Control"] +margin_left = 66.0 +margin_top = 17.0 +margin_right = 456.0 +margin_bottom = 71.0 +custom_fonts/font = SubResource( 1 ) +text = "GANASTE!" +align = 1 + +[node name="QuitButton" type="Button" parent="Control"] +margin_left = 194.0 +margin_top = 150.0 +margin_right = 338.0 +margin_bottom = 180.0 +custom_fonts/font = SubResource( 2 ) +custom_styles/hover = SubResource( 3 ) +text = "SALIR" + +[connection signal="pressed" from="Control/QuitButton" to="." method="_on_quit_button_pressed"] diff --git a/godot/gui/GameWonScreen.gdns b/godot/gui/GameWonScreen.gdns new file mode 100644 index 0000000..1d6223b --- /dev/null +++ b/godot/gui/GameWonScreen.gdns @@ -0,0 +1,8 @@ +[gd_resource type="NativeScript" load_steps=2 format=2] + +[ext_resource path="res://gdnative/alai.tres" type="GDNativeLibrary" id=1] + +[resource] +resource_name = "GameWonScreen" +class_name = "GameWonScreen" +library = ExtResource( 1 ) diff --git a/godot/monitor/Monitor.gd b/godot/monitor/Monitor.gd index 80ada27..99404ac 100644 --- a/godot/monitor/Monitor.gd +++ b/godot/monitor/Monitor.gd @@ -1,10 +1,8 @@ extends Node -signal monitor_loaded() - - export var monitor_enabled: bool = false +export var debug: bool = false export var development_url: String = "http://localhost:4050/api/v1" var url_real: String = "https://alai.cromer.cl/api/v1" export var use_development_url: bool = false @@ -53,7 +51,11 @@ func _ready() -> void: Event.connect("object_created", self, "_object_created") Event.connect("object_updated", self, "_object_updated") Event.connect("object_removed", self, "_object_removed") + Event.connect("game_started", self, "_on_game_started") + Event.connect("player_died", self, "_on_game_over") + Event.connect("player_won", self, "_on_game_won") Event.connect("coin_collected", self, "_on_coin_update") + game_version = get_parent().game_version player["rut"] = "" @@ -108,7 +110,7 @@ func _physics_process(_delta: float) -> void: if monitor_enabled: if has_node("MonitorGUI") and not $MonitorGUI.visible: $MonitorGUI.visible = true - emit_signal("monitor_loaded") + Event.emit_signal("monitor_loaded") if started and not get_tree().paused: var frame = empty_frame.duplicate(true) @@ -130,13 +132,14 @@ func _physics_process(_delta: float) -> void: start_monitor() else: get_tree().paused = false - emit_signal("monitor_loaded") + Event.emit_signal("monitor_loaded") queue_free() func _on_input_validated(validated_player: Dictionary) -> void: $MonitorGUI.queue_free() get_tree().paused = false + Event.emit_signal("game_started") player = validated_player.duplicate(true) game["player"] = player @@ -161,6 +164,8 @@ func start_monitor() -> void: frames.clear() game["level_id"] = 2 # PrototypeR game["won"] = false + coins = 0 + points = 0 game["timestamp"] = int(Time.get_unix_time_from_system()) start_time = Time.get_ticks_msec() started = true @@ -186,6 +191,7 @@ func remove_object(name: String) -> void: for i in range(0, objects.size()): if objects[i]["name"] == name: objects.remove(i) + return func _on_coin_update(amount: int) -> void: @@ -217,7 +223,16 @@ func send_data() -> void: print("Body B: " + String(body.length())) print("Body MB: " + String(body.length() / pow(2, 20))) - $HTTPRequest.request(url + "/game", headers, false, HTTPClient.METHOD_POST, body) + if not debug: + $HTTPRequest.request(url + "/game", headers, false, HTTPClient.METHOD_POST, body) + else: + var file = File.new() + if file.open("user://game.json", File.WRITE) != 0: + print_debug("Could not open game.json for writing!") + return + + file.store_string(json) + file.close() func compress_payload(payload: String) -> String: @@ -229,3 +244,21 @@ func compress_payload(payload: String) -> String: return new_payload +func _on_game_started() -> void: + print_debug("started game") + if not started: + start_monitor() + + +func _on_game_over() -> void: + if started: + stop_monitor() + game["won"] = false + send_data() + + +func _on_game_won() -> void: + if started: + stop_monitor() + game["won"] = true + send_data() diff --git a/src/CameraLimit.cpp b/src/CameraLimit.cpp index cdc4add..e981127 100644 --- a/src/CameraLimit.cpp +++ b/src/CameraLimit.cpp @@ -7,7 +7,7 @@ void alai::CameraLimit::_register_methods() { - register_method("_ready", &CameraLimit::_ready); + godot::register_method("_ready", &CameraLimit::_ready); } alai::CameraLimit::CameraLimit() diff --git a/src/Event.cpp b/src/Event.cpp index 6561979..8795d1e 100644 --- a/src/Event.cpp +++ b/src/Event.cpp @@ -2,12 +2,15 @@ void alai::Event::_register_methods() { + godot::register_signal("game_started"); + godot::register_signal("monitor_loaded"); + godot::register_signal("level_loaded"); godot::register_signal("object_created", "name", GODOT_VARIANT_TYPE_STRING, "state", GODOT_VARIANT_TYPE_STRING, "position", GODOT_VARIANT_TYPE_VECTOR2, "velocity", GODOT_VARIANT_TYPE_VECTOR2); godot::register_signal("object_updated", "name", GODOT_VARIANT_TYPE_STRING, "state", GODOT_VARIANT_TYPE_STRING, "position", GODOT_VARIANT_TYPE_VECTOR2, "velocity", GODOT_VARIANT_TYPE_VECTOR2); godot::register_signal("object_removed", "name", GODOT_VARIANT_TYPE_STRING); godot::register_signal("coin_collected", "amount", GODOT_VARIANT_TYPE_INT); godot::register_signal("player_died"); - + godot::register_signal("player_won"); } alai::Event::Event() diff --git a/src/Main.cpp b/src/Main.cpp index 4f895bd..353882b 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -1,5 +1,7 @@ #include "Main.h" +#include "Event.h" + #include void alai::Main::_register_methods() @@ -86,24 +88,21 @@ void alai::Main::_ready() void alai::Main::_on_monitor_loaded() { - if (level != nullptr) - { - auto level_node = load_level(); - connect("monitor_loaded", level_node->get_child(0)->find_node("Player", true, false), "_on_monitor_loaded"); - emit_signal("monitor_loaded"); - } + load_level(); + auto event = get_node("/root/Event"); + event->emit_signal("level_loaded"); } void alai::Main::load_monitor() { + auto event = get_node("/root/Event"); + event->connect("monitor_loaded", this, "_on_monitor_loaded"); godot::Ref monitor_scene = _resource_loader->load("res://monitor/Monitor.tscn"); add_child(monitor_scene->instance()); - auto monitor = get_node("Monitor"); - monitor->connect("monitor_loaded", this, "_on_monitor_loaded"); get_tree()->set_pause(true); } -godot::Node *alai::Main::load_level() +void alai::Main::load_level() { if (level != nullptr) { @@ -111,9 +110,7 @@ godot::Node *alai::Main::load_level() auto loaded_level = level->instance(); auto level_node = get_node("Level"); level_node->add_child(loaded_level); - return level_node; } - return nullptr; } void alai::Main::_physics_process(float delta) diff --git a/src/Main.h b/src/Main.h index 9487338..a3cb313 100644 --- a/src/Main.h +++ b/src/Main.h @@ -224,9 +224,8 @@ namespace alai /** * @brief Loads the selected level. * - * @return Node* The level node which we will later add the monitor to. */ - Node *load_level(); + void load_level(); }; } diff --git a/src/coin/CoinCollected.cpp b/src/coin/CoinCollected.cpp index 110be15..0e9921f 100644 --- a/src/coin/CoinCollected.cpp +++ b/src/coin/CoinCollected.cpp @@ -7,9 +7,9 @@ void alai::CoinCollected::_register_methods() { - register_method("_state_enter", &CoinCollected::_state_enter); - register_method("_state_exit", &CoinCollected::_state_exit); - register_method("_on_animation_finished", &CoinCollected::_on_animation_finished); + godot::register_method("_state_enter", &CoinCollected::_state_enter); + godot::register_method("_state_exit", &CoinCollected::_state_exit); + godot::register_method("_on_animation_finished", &CoinCollected::_on_animation_finished); } alai::CoinCollected::CoinCollected() @@ -39,7 +39,6 @@ void alai::CoinCollected::_state_enter() void alai::CoinCollected::_state_exit() { - } void alai::CoinCollected::_on_animation_finished(godot::String anim_name) diff --git a/src/coin/CoinCounter.cpp b/src/coin/CoinCounter.cpp index 667ea9e..c0f5cbe 100644 --- a/src/coin/CoinCounter.cpp +++ b/src/coin/CoinCounter.cpp @@ -6,8 +6,8 @@ void alai::CoinCounter::_register_methods() { - register_method("_on_coin_collected", &CoinCounter::_on_coin_collected); - register_method("_ready", &CoinCounter::_ready); + godot::register_method("_on_coin_collected", &CoinCounter::_on_coin_collected); + godot::register_method("_ready", &CoinCounter::_ready); } alai::CoinCounter::CoinCounter() diff --git a/src/coin/CoinNotCollected.cpp b/src/coin/CoinNotCollected.cpp index c03aa0b..b1c84ee 100644 --- a/src/coin/CoinNotCollected.cpp +++ b/src/coin/CoinNotCollected.cpp @@ -4,9 +4,9 @@ void alai::CoinNotCollected::_register_methods() { - register_method("_state_enter", &CoinNotCollected::_state_enter); - register_method("_state_exit", &CoinNotCollected::_state_exit); - register_method("_on_body_entered", &CoinNotCollected::_on_body_entered); + godot::register_method("_state_enter", &CoinNotCollected::_state_enter); + godot::register_method("_state_exit", &CoinNotCollected::_state_exit); + godot::register_method("_on_body_entered", &CoinNotCollected::_on_body_entered); } alai::CoinNotCollected::CoinNotCollected() diff --git a/src/goal/GoalNotReached.cpp b/src/goal/GoalNotReached.cpp index 08d55f3..8fbec1f 100644 --- a/src/goal/GoalNotReached.cpp +++ b/src/goal/GoalNotReached.cpp @@ -4,9 +4,9 @@ void alai::GoalNotReached::_register_methods() { - register_method("_state_enter", &GoalNotReached::_state_enter); - register_method("_state_exit", &GoalNotReached::_state_exit); - register_method("_on_Goal_body_entered", &GoalNotReached::_on_Goal_body_entered); + godot::register_method("_state_enter", &GoalNotReached::_state_enter); + godot::register_method("_state_exit", &GoalNotReached::_state_exit); + godot::register_method("_on_Goal_body_entered", &GoalNotReached::_on_Goal_body_entered); } alai::GoalNotReached::GoalNotReached() diff --git a/src/goal/GoalReached.cpp b/src/goal/GoalReached.cpp index 06f882c..6afb5f0 100644 --- a/src/goal/GoalReached.cpp +++ b/src/goal/GoalReached.cpp @@ -1,11 +1,13 @@ #include "goal/GoalReached.h" +#include "Event.h" + #include void alai::GoalReached::_register_methods() { - register_method("_state_enter", &GoalReached::_state_enter); - register_method("_state_exit", &GoalReached::_state_exit); + godot::register_method("_state_enter", &GoalReached::_state_enter); + godot::register_method("_state_exit", &GoalReached::_state_exit); } alai::GoalReached::GoalReached() @@ -22,7 +24,8 @@ void alai::GoalReached::_init() void alai::GoalReached::_state_enter() { - godot::Godot::print("Flag touched"); + auto event = get_node("/root/Event"); + event->emit_signal("player_won"); } void alai::GoalReached::_state_exit() diff --git a/src/godot.cpp b/src/godot.cpp index bb724e7..5793fee 100644 --- a/src/godot.cpp +++ b/src/godot.cpp @@ -16,6 +16,7 @@ #include "goal/GoalReached.h" #include "goal/GoalNotReached.h" #include "gui/game_over/GameOverScreen.h" +#include "gui/game_won/GameWonScreen.h" /** * @brief This function connects the gdnative init function. @@ -62,4 +63,5 @@ extern "C" void GDN_EXPORT godot_nativescript_init(void *handle) godot::register_class(); godot::register_class(); godot::register_class(); + godot::register_class(); } diff --git a/src/gui/game_over/GameOverScreen.cpp b/src/gui/game_over/GameOverScreen.cpp index 76a7b64..2c59ea7 100644 --- a/src/gui/game_over/GameOverScreen.cpp +++ b/src/gui/game_over/GameOverScreen.cpp @@ -1,22 +1,22 @@ #include "gui/game_over/GameOverScreen.h" + #include "Event.h" -#include +#include #include #include #include #include #include -#include -#include void alai::GameOverScreen::_register_methods() -{ - register_method("_on_restart_button_pressed", &GameOverScreen::_on_restart_button_pressed); - register_method("_ready", &GameOverScreen::_ready); - register_method("connect_signal", &GameOverScreen::connect_signal); - register_method("_on_player_died", &GameOverScreen::_on_player_died); - register_method("_play music", &GameOverScreen::_play_music); +{ + godot::register_method("_on_restart_button_pressed", &GameOverScreen::_on_restart_button_pressed); + godot::register_method("_ready", &GameOverScreen::_ready); + godot::register_method("restart_game", &GameOverScreen::restart_game); + godot::register_method("connect_signal", &GameOverScreen::connect_signal); + godot::register_method("_on_player_died", &GameOverScreen::_on_player_died); + godot::register_method("_play music", &GameOverScreen::_play_music); } alai::GameOverScreen::GameOverScreen() @@ -32,16 +32,13 @@ void alai::GameOverScreen::_init() _resource_loader = godot::ResourceLoader::get_singleton(); } - void alai::GameOverScreen::_ready() { connect_signal(); - } void alai::GameOverScreen::_on_restart_button_pressed() { - /*_r*/ if (_resource_loader->exists("res://levels/PrototypeR.tscn")) { godot::Ref level_scene = _resource_loader->load("res://levels/PrototypeR.tscn"); @@ -52,7 +49,7 @@ void alai::GameOverScreen::_on_restart_button_pressed() { level_node->add_child(level); set_visible(false); - call_deferred("connect_signal"); + call_deferred("restart_game"); } else { @@ -86,6 +83,13 @@ void alai::GameOverScreen::_on_player_died() } } +void alai::GameOverScreen::restart_game() +{ + auto event = get_node("/root/Event"); + event->emit_signal("game_started"); + connect_signal(); +} + void alai::GameOverScreen::connect_signal() { auto event = get_node("/root/Event"); @@ -94,17 +98,4 @@ void alai::GameOverScreen::connect_signal() void alai::GameOverScreen::_play_music() { - if (this->is_on_screen() == true) - { - auto game_over_sound = get_node("GameOverMusic"); - game_over_sound->play(); - - } - else - { - auto game_over_sound = get_node("GameOverMusic"); - game_over_sound->stop(); - } - - } diff --git a/src/gui/game_over/GameOverScreen.h b/src/gui/game_over/GameOverScreen.h index 6e4b657..3fb679c 100644 --- a/src/gui/game_over/GameOverScreen.h +++ b/src/gui/game_over/GameOverScreen.h @@ -1,5 +1,5 @@ -#ifndef ALAI_GAME_OVER_SCREEN_H -#define ALAI_GAME_OVER_SCREEN_H +#ifndef ALAI_GAME_OVER_GAME_OVER_SCREEN_H +#define ALAI_GAME_OVER_GAME_OVER_SCREEN_H #include #include @@ -53,6 +53,7 @@ namespace alai void _ready(); void _on_player_died(); void _on_restart_button_pressed(); + void restart_game(); void connect_signal(); void _play_music(); }; diff --git a/src/gui/game_won/GameWonScreen.cpp b/src/gui/game_won/GameWonScreen.cpp new file mode 100644 index 0000000..f51822e --- /dev/null +++ b/src/gui/game_won/GameWonScreen.cpp @@ -0,0 +1,66 @@ +#include "gui/game_won/GameWonScreen.h" + +#include "Event.h" + +#include +#include + +void alai::GameWonScreen::_register_methods() +{ + godot::register_method("_ready", &GameWonScreen::_ready); + godot::register_method("connect_signal", &GameWonScreen::connect_signal); + godot::register_method("_on_player_won", &GameWonScreen::_on_player_won); + godot::register_method("_on_quit_button_pressed", &GameWonScreen::_on_quit_button_pressed); +} + +alai::GameWonScreen::GameWonScreen() +{ +} + +alai::GameWonScreen::~GameWonScreen() +{ +} + +void alai::GameWonScreen::_init() +{ +} + +void alai::GameWonScreen::_ready() +{ + connect_signal(); +} + +void alai::GameWonScreen::_on_quit_button_pressed() +{ + get_tree()->quit(); +} + +void alai::GameWonScreen::_on_player_won() +{ + auto event = get_node("/root/Event"); + event->disconnect("player_won", this, "_on_player_won"); + set_visible(true); + auto level_node = get_tree()->get_root()->get_node("Main")->find_node("Level"); + if (level_node != nullptr) + { + auto child = level_node->get_child(0); + if (child != nullptr) + { + child->queue_free(); + } + else + { + WARN_PRINT("Child not found!"); + } + } + else + { + WARN_PRINT("Node level not found!"); + } +} + +void alai::GameWonScreen::connect_signal() +{ + auto event = get_node("/root/Event"); + event->connect("player_won", this, "_on_player_won"); +} diff --git a/src/gui/game_won/GameWonScreen.h b/src/gui/game_won/GameWonScreen.h new file mode 100644 index 0000000..987b7a1 --- /dev/null +++ b/src/gui/game_won/GameWonScreen.h @@ -0,0 +1,51 @@ +#ifndef ALAI_GAME_WON_GAME_WON_SCREEN_H +#define ALAI_GAME_WON_GAME_WON_SCREEN_H + +#include +#include + +namespace alai +{ + /** + * @brief This class controls what happens when the game is won. + * + */ + class GameWonScreen : public godot::CanvasLayer + { + GODOT_CLASS(GameWonScreen, godot::CanvasLayer) + + public: + /** + * @brief This method registers classes with Godot. + * + * @details This method registers methods, properties, and signals with the Godot engine. + */ + static void _register_methods(); + + /** + * @brief Construct a new GameWonScreen object. + * + */ + GameWonScreen(); + + /** + * @brief Destroy the GameWonScreen object. + * + */ + ~GameWonScreen(); + + /** + * @brief Initialize the class from Godot. + * + * @details This method is called just once when the Godot engine connects to the instance of the class. + */ + void _init(); + + void _ready(); + void _on_player_won(); + void _on_quit_button_pressed(); + void connect_signal(); + }; +} + +#endif diff --git a/src/player/Player.cpp b/src/player/Player.cpp index d60cc1d..9a128f9 100644 --- a/src/player/Player.cpp +++ b/src/player/Player.cpp @@ -19,7 +19,7 @@ void alai::player::Player::_register_methods() godot::register_method("set_velocity", &Player::set_velocity); godot::register_method("get_velocity", &Player::get_velocity); godot::register_method("_on_player_touched", &Player::_on_player_touched); - godot::register_method("_on_monitor_loaded", &Player::_on_monitor_loaded); + godot::register_method("_on_level_loaded", &Player::_on_level_loaded); //godot::register_property>("sprite_frames", &Player::set_sprite_frames, &Player::get_sprite_frames, godot::Ref(), GODOT_METHOD_RPC_MODE_DISABLED, GODOT_PROPERTY_USAGE_DEFAULT, GODOT_PROPERTY_HINT_RESOURCE_TYPE, godot::String("SpriteFrames")); godot::register_property("speed", &Player::set_speed, &Player::get_speed, player::speed); godot::register_property("jump_force", &Player::set_jump_force, &Player::get_jump_force, player::jump_force); @@ -51,11 +51,16 @@ void alai::player::Player::_init() coins = 0; + notifier_initialized = false; + velocity = godot::Vector2(); } void alai::player::Player::_ready() { + auto event = get_node("/root/Event"); + event->connect("level_loaded", this, "_on_level_loaded"); + animated_sprite = get_node("AnimatedSprite"); if (!animated_sprite) { @@ -77,7 +82,7 @@ void alai::player::Player::_ready() } } -void alai::player::Player::_on_monitor_loaded() { +void alai::player::Player::_on_level_loaded() { auto state = get_node("StateMachine")->get_child(0); if (state != nullptr) { @@ -100,8 +105,16 @@ void alai::player::Player::_physics_process(float delta) snap_vector = godot::Vector2::DOWN * 20.0; } + auto is_on_platform = false; auto platform_detector = get_node("PlatformDetector"); - auto is_on_platform = platform_detector->is_colliding(); + if (platform_detector != nullptr) + { + is_on_platform = platform_detector->is_colliding(); + } + else + { + WARN_PRINT("PlatformDetector not found!"); + } velocity = move_and_slide_with_snap(velocity, snap_vector, godot::Vector2::UP, !is_on_platform, 4, 0.9, false); //velocity = move_and_slide(velocity, Vector2::UP, !is_on_platform); @@ -130,8 +143,15 @@ void alai::player::Player::_physics_process(float delta) WARN_PRINT("Enemies not found!"); dup->queue_free(); }*/ - auto jump_sound = get_parent()->get_node("Sounds/Jump"); - jump_sound->play(); + auto jump_sound = get_node("Sounds/Jump"); + if (jump_sound != nullptr) + { + jump_sound->play(); + } + else + { + WARN_PRINT("Player jump sound not found!"); + } velocity.y = -get_bounce_force(); } else if (collider->is_in_group("enemy") && (collider->is_in_group("rideable") && godot::Vector2::DOWN.dot(collision->get_normal()) > 0)) @@ -146,38 +166,48 @@ void alai::player::Player::_physics_process(float delta) // Clamp the player's position inside the camera's limits auto camera = get_node("Camera2D"); - auto position = get_global_position(); - auto sprite_node = get_node("AnimatedSprite"); - if (sprite_node != nullptr) + if (camera != nullptr) { - position.x = godot::Math::clamp((float) position.x, (float) camera->get_limit(0), (float) camera->get_limit(2) - sprite_node->get_sprite_frames()->get_frame("idle", 0)->get_size().x); - position.y = godot::Math::clamp((float) position.y, (float) camera->get_limit(1), (float) camera->get_limit(3) + sprite_node->get_sprite_frames()->get_frame("idle", 0)->get_size().y); + auto position = get_global_position(); + auto sprite_node = get_node("AnimatedSprite"); + if (sprite_node != nullptr) + { + position.x = godot::Math::clamp((float) position.x, (float) camera->get_limit(0), (float) camera->get_limit(2) - sprite_node->get_sprite_frames()->get_frame("idle", 0)->get_size().x); + position.y = godot::Math::clamp((float) position.y, (float) camera->get_limit(1), (float) camera->get_limit(3) + sprite_node->get_sprite_frames()->get_frame("idle", 0)->get_size().y); + } + else { + WARN_PRINT("Could not clamp player based on sprite frame size!"); + position.x = godot::Math::clamp((float) position.x, (float) camera->get_limit(0), (float) camera->get_limit(2)); + position.y = godot::Math::clamp((float) position.y, (float) camera->get_limit(1), (float) camera->get_limit(3)); + } + set_global_position(position); } - else { - WARN_PRINT("Could not clamp player based on sprite frame size!"); - position.x = godot::Math::clamp((float) position.x, (float) camera->get_limit(0), (float) camera->get_limit(2)); - position.y = godot::Math::clamp((float) position.y, (float) camera->get_limit(1), (float) camera->get_limit(3)); + else + { + WARN_PRINT("Camera node not found!"); } - set_global_position(position); // If the player is off screen reload the scene auto notifier = get_node("Camera2D/VisibilityNotifier2D"); if (notifier != nullptr) { - if (!notifier->is_on_screen()) + if (notifier->is_inside_tree() && !notifier->is_on_screen()) { - auto event = get_node("/root/Event"); - event->emit_signal("player_died"); - /*if (get_parent()->get_class() == "TileMap") - { - auto error = get_tree()->change_scene("res://Main.tscn"); - if (error != godot::Error::OK) - { - ERR_PRINT(godot::String().num((int) error) + " Could not load scene!"); - } - }*/ + // The first time the notifier is checked always returns false in the first frame + // So skip the check from the first frame + if (notifier_initialized) { + auto event = get_node("/root/Event"); + event->emit_signal("player_died"); + } + else { + notifier_initialized = true; + } } } + else + { + WARN_PRINT("Visibility notifier not found!"); + } auto state = get_node("StateMachine")->get_child(0); if (state != nullptr) @@ -273,9 +303,6 @@ godot::Vector2 alai::player::Player::get_velocity() void alai::player::Player::_on_player_touched() { - auto error = get_tree()->change_scene("res://Main.tscn"); - if (error != godot::Error::OK) - { - ERR_PRINT(godot::String().num((int) error) + " Could not load scene!"); - } + auto event = get_node("/root/Event"); + event->emit_signal("player_died"); } diff --git a/src/player/Player.h b/src/player/Player.h index cedcfb5..578840a 100644 --- a/src/player/Player.h +++ b/src/player/Player.h @@ -117,6 +117,11 @@ namespace alai * */ bool double_jump; + /** + * @brief If the notifier for the player being on screen has been initialized or not. + * + */ + bool notifier_initialized; public: /** @@ -284,7 +289,7 @@ namespace alai * @brief Called when the monitor is loaded to connect the player to it for tracking. * */ - void _on_monitor_loaded(); + void _on_level_loaded(); }; } } diff --git a/src/player/states/PlayerFall.cpp b/src/player/states/PlayerFall.cpp index cd6775e..adc9671 100644 --- a/src/player/states/PlayerFall.cpp +++ b/src/player/states/PlayerFall.cpp @@ -4,9 +4,9 @@ void alai::player::PlayerFall::_register_methods() { - register_method("_state_enter", &PlayerFall::_state_enter); - register_method("_state_exit", &PlayerFall::_state_exit); - register_method("_physics_process", &PlayerFall::_physics_process); + godot::register_method("_state_enter", &PlayerFall::_state_enter); + godot::register_method("_state_exit", &PlayerFall::_state_exit); + godot::register_method("_physics_process", &PlayerFall::_physics_process); } alai::player::PlayerFall::PlayerFall() diff --git a/src/player/states/PlayerIdle.cpp b/src/player/states/PlayerIdle.cpp index bc8a5ed..1043f52 100644 --- a/src/player/states/PlayerIdle.cpp +++ b/src/player/states/PlayerIdle.cpp @@ -4,9 +4,9 @@ void alai::player::PlayerIdle::_register_methods() { - register_method("_state_enter", &PlayerIdle::_state_enter); - register_method("_state_exit", &PlayerIdle::_state_exit); - register_method("_physics_process", &PlayerIdle::_physics_process); + godot::register_method("_state_enter", &PlayerIdle::_state_enter); + godot::register_method("_state_exit", &PlayerIdle::_state_exit); + godot::register_method("_physics_process", &PlayerIdle::_physics_process); } alai::player::PlayerIdle::PlayerIdle() diff --git a/src/player/states/PlayerJump.cpp b/src/player/states/PlayerJump.cpp index 28e5e24..b5417ac 100644 --- a/src/player/states/PlayerJump.cpp +++ b/src/player/states/PlayerJump.cpp @@ -6,9 +6,9 @@ void alai::player::PlayerJump::_register_methods() { - register_method("_state_enter", &PlayerJump::_state_enter); - register_method("_state_exit", &PlayerJump::_state_exit); - register_method("_physics_process", &PlayerJump::_physics_process); + godot::register_method("_state_enter", &PlayerJump::_state_enter); + godot::register_method("_state_exit", &PlayerJump::_state_exit); + godot::register_method("_physics_process", &PlayerJump::_physics_process); } alai::player::PlayerJump::PlayerJump() diff --git a/src/player/states/PlayerMove.cpp b/src/player/states/PlayerMove.cpp index 720ce91..23014db 100644 --- a/src/player/states/PlayerMove.cpp +++ b/src/player/states/PlayerMove.cpp @@ -4,9 +4,9 @@ void alai::player::PlayerMove::_register_methods() { - register_method("_state_enter", &PlayerMove::_state_enter); - register_method("_state_exit", &PlayerMove::_state_exit); - register_method("_physics_process", &PlayerMove::_physics_process); + godot::register_method("_state_enter", &PlayerMove::_state_enter); + godot::register_method("_state_exit", &PlayerMove::_state_exit); + godot::register_method("_physics_process", &PlayerMove::_physics_process); } alai::player::PlayerMove::PlayerMove() diff --git a/src/state_machine/State.cpp b/src/state_machine/State.cpp index 1c66968..eff2576 100644 --- a/src/state_machine/State.cpp +++ b/src/state_machine/State.cpp @@ -2,11 +2,11 @@ void alai::State::_register_methods() { - register_method("set_parent", &State::set_parent); - register_method("get_parent", &State::get_parent); - register_method("set_state_machine", &State::set_state_machine); - register_method("_state_enter", &State::_state_enter); - register_method("_state_exit", &State::_state_exit); + godot::register_method("set_parent", &State::set_parent); + godot::register_method("get_parent", &State::get_parent); + godot::register_method("set_state_machine", &State::set_state_machine); + godot::register_method("_state_enter", &State::_state_enter); + godot::register_method("_state_exit", &State::_state_exit); } alai::State::State()