diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..70bbfed --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,18 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "GDScript Godot", + "type": "godot", + "request": "launch", + "project": "${workspaceFolder}", + "port": 6007, + "address": "127.0.0.1", + "launch_game_instance": true, + "launch_scene": false + } + ] +} \ No newline at end of file diff --git a/project.godot b/project.godot index 705ab8c..796cc0f 100644 --- a/project.godot +++ b/project.godot @@ -14,6 +14,16 @@ _global_script_classes=[ { "language": "GDScript", "path": "res://src/Actor/Actor.gd" }, { +"base": "Line2D", +"class": "RayCastDebugLines", +"language": "GDScript", +"path": "res://src/RayCasters/RayCastDebugLines.gd" +}, { +"base": "Node2D", +"class": "RayCaster", +"language": "GDScript", +"path": "res://src/RayCasters/RayCaster.gd" +}, { "base": "Node", "class": "StateMachine", "language": "GDScript", @@ -21,6 +31,8 @@ _global_script_classes=[ { } ] _global_script_class_icons={ "Actor": "", +"RayCastDebugLines": "", +"RayCaster": "", "StateMachine": "" } @@ -34,6 +46,10 @@ config/icon="res://icon.png" PlayerData="*res://src/Autoload/PlayerData.tscn" +[debug] + +settings/fps/force_fps=144 + [display] window/stretch/mode="2d" diff --git a/src/Actor/Actor.gd b/src/Actor/Actor.gd index a33d942..4c217a9 100644 --- a/src/Actor/Actor.gd +++ b/src/Actor/Actor.gd @@ -4,6 +4,6 @@ class_name Actor const FLOOR_NORMAL: = Vector2.UP export var speed: = Vector2(300, 1000) -export var gravity: = 100.0 +export var gravity: = 9800.0 -var _velocity: = Vector2.ZERO +var _velocity: = Vector2.ZERO \ No newline at end of file diff --git a/src/Actor/Blobby.gd b/src/Actor/Blobby.gd index f5e2df8..aa40d7a 100644 --- a/src/Actor/Blobby.gd +++ b/src/Actor/Blobby.gd @@ -2,7 +2,7 @@ extends Actor export var stomp_impulse: = 1000.0 - +# TODO Move events to StateMachine func _on_EnemyDetector_area_entered(area: Area2D) -> void: _velocity = calculate_stomp_velocity(_velocity, stomp_impulse) @@ -11,7 +11,7 @@ func _on_EnemyDetector_body_entered(body: Node) -> void: die() -func _physics_process(delta: float) -> void: +func apply_movement(delta: float) -> void: var is_jump_interrupted: = Input.is_action_just_released("jump") and _velocity.y < 0.0 var direction: = get_direction() _velocity = calculate_move_velocity(_velocity, speed, direction, is_jump_interrupted) @@ -60,5 +60,3 @@ func die() -> void: queue_free() PlayerData.deaths += 1 - - diff --git a/src/Actor/Blobby.tscn b/src/Actor/Blobby.tscn index 04ad04f..faa89ab 100644 --- a/src/Actor/Blobby.tscn +++ b/src/Actor/Blobby.tscn @@ -1,30 +1,37 @@ -[gd_scene load_steps=5 format=2] +[gd_scene load_steps=8 format=2] [ext_resource path="res://start-assets/player.png" type="Texture" id=1] -[ext_resource path="res://src/Actor/Blobby.gd" type="Script" id=2] +[ext_resource path="res://src/Actor/PlayerStateMachine.gd" type="Script" id=2] +[ext_resource path="res://src/RayCasters/RayCaster.gd" type="Script" id=3] +[ext_resource path="res://src/RayCasters/RayCastDebugLines.gd" type="Script" id=4] +[ext_resource path="res://src/Actor/Blobby.gd" type="Script" id=5] [sub_resource type="RectangleShape2D" id=1] -extents = Vector2( 4.85252, 5.80644 ) +extents = Vector2( 30.8418, 32 ) [sub_resource type="RectangleShape2D" id=2] extents = Vector2( 30.9321, 24.5597 ) [node name="Blobby" type="KinematicBody2D"] collision_mask = 8 -script = ExtResource( 2 ) -speed = Vector2( 300, 3000 ) +script = ExtResource( 5 ) [node name="player" type="Sprite" parent="."] -position = Vector2( 2.38419e-07, -31.3866 ) -scale = Vector2( 0.641109, 0.653888 ) +position = Vector2( 1.79366e-43, 5.72205e-06 ) +scale = Vector2( 0.64, 0.64 ) texture = ExtResource( 1 ) [node name="CollisionShape2D" type="CollisionShape2D" parent="."] -position = Vector2( 1.05112, -31.5796 ) -scale = Vector2( 5.68128, 5.29182 ) shape = SubResource( 1 ) +[node name="RayCaster" type="Node2D" parent="CollisionShape2D"] +script = ExtResource( 3 ) + +[node name="RayCastDebugLines" type="Line2D" parent="CollisionShape2D/RayCaster"] +script = ExtResource( 4 ) + [node name="Camera2D" type="Camera2D" parent="."] +visible = false position = Vector2( 0, -181 ) current = true limit_left = 0 @@ -42,7 +49,9 @@ collision_mask = 2 [node name="CollisionShape2D" type="CollisionShape2D" parent="EnemyDetector"] modulate = Color( 0.2, 0, 0.494118, 1 ) -position = Vector2( -0.210228, -30.5284 ) shape = SubResource( 2 ) + +[node name="StateMachine" type="Node" parent="."] +script = ExtResource( 2 ) [connection signal="area_entered" from="EnemyDetector" to="." method="_on_EnemyDetector_area_entered"] [connection signal="body_entered" from="EnemyDetector" to="." method="_on_EnemyDetector_body_entered"] diff --git a/src/Actor/PlayerStateMachine.gd b/src/Actor/PlayerStateMachine.gd index 4e2963f..ad45f44 100644 --- a/src/Actor/PlayerStateMachine.gd +++ b/src/Actor/PlayerStateMachine.gd @@ -1,22 +1,30 @@ extends StateMachine +# Adds the intial states func _ready(): add_state("idle") add_state("run") add_state("jump") add_state("fall") - call_deferred("set_state", states.idle) + print_debug(states) + set_state(states.idle); + +# Calls the parent behaviours according to state func _state_logic(delta): - parent.handle_move_input() - parent.apply_gravity(delta) - parent.apply_movement() + parent.get_node("CollisionShape2D/RayCaster")._raycast(Vector2.DOWN, parent.get_node("CollisionShape2D").get_shape(), parent.collision_mask) + parent.apply_movement(delta) + +# Determines which state should be active at the moment func _get_transition(delta): + return null + func _enter_state(new_state, old_state): pass + func _exit_state(old_state, new_state): - pass \ No newline at end of file + pass diff --git a/src/Levels/Level03.tscn b/src/Levels/Level03.tscn index 3315f21..edfab8d 100644 --- a/src/Levels/Level03.tscn +++ b/src/Levels/Level03.tscn @@ -39,8 +39,6 @@ tile_data = PoolIntArray( -1048576, 0, 0, -1048564, 0, 0, -983040, 0, 0, -983028 [node name="Blobby" parent="." instance=ExtResource( 1 )] position = Vector2( 131, 560 ) -speed = Vector2( 800, 1500 ) -gravity = 4000.0 [node name="player" parent="Blobby" index="0"] position = Vector2( 0, -32 ) diff --git a/src/Levels/LevelTemplate.tscn b/src/Levels/LevelTemplate.tscn index 108dc04..ab09b54 100644 --- a/src/Levels/LevelTemplate.tscn +++ b/src/Levels/LevelTemplate.tscn @@ -64,8 +64,6 @@ tile_data = PoolIntArray( 0, 0, 0, 34, 0, 0, 35, 0, 0, 65536, 0, 0, 65570, 0, 0, [node name="Blobby" parent="." instance=ExtResource( 1 )] position = Vector2( 131, 560 ) -speed = Vector2( 800, 3000 ) -gravity = 4000.0 [node name="Camera2D" parent="Blobby" index="2"] limit_top = 100000000 diff --git a/src/RayCaster.gd b/src/RayCaster.gd deleted file mode 100644 index 22a6218..0000000 --- a/src/RayCaster.gd +++ /dev/null @@ -1,57 +0,0 @@ -extends Node2D - -const UP = Vector2(0, -1) -const DOWN = Vector2(0, 1) -const LEFT = Vector2(-1, 0) -const RIGHT = Vector2(1, 0) -const SKIN_WIDTH = 1 - -export (int) var buffer_size = 3 setget _set_buffer_size -var buffer = [] - -func _raycast(direction, rect, mask, exceptions = [], ray_length = 16, buffer = self.buffer): - if !(direction == UP || direction == DOWN || direction == LEFT || direction == RIGHT): - return 0 - - var space_state = get_world_2d().direct_space_state - var extents = rect.extents - Vector2(SKIN_WIDTH, SKIN_WIDTH) - var count = 0 - var ray_count = buffer.size() - var cast_to = (ray_length + SKIN_WIDTH) * direction - var origin - var spacing - - if direction == UP || direction == DOWN: - spacing = extents.x * 2 / (ray_count - 1) - else: - spacing = extents.y * 2 / (ray_count - 1) - - for i in range(ray_count): - if direction == UP || direction == DOWN: - origin = Vector2(-extents.x + spacing * i, extents.y) - if direction == UP: - origin.y = -origin.y - else: - origin = Vector2(extents.x, -extents.y + spacing * i) - if direction == UP: - origin.x = -origin.x - - var result = space_state.intersect_ray(global_position + origin, global_position + origin + cast_to, - exceptions, mask) - if result: - buffer[count] = result - count += 1 - return {buffer = buffer, count = count} - - - - - -func _set_buffer_size(value): - buffer_size = max(value, 2) - buffer.resize(buffer_size) - -# Called when the node enters the scene tree for the first time. -func _ready(): - _set_buffer_size(buffer_size) - diff --git a/src/RayCasters/RayCastDebugLines.gd b/src/RayCasters/RayCastDebugLines.gd new file mode 100644 index 0000000..e05fa2e --- /dev/null +++ b/src/RayCasters/RayCastDebugLines.gd @@ -0,0 +1,25 @@ +extends Line2D +class_name RayCastDebugLines + +# Declare member variables here. Examples: +# var a: int = 2 +# var b: String = "text" +var Lines = [] + +func add_line(origin, destination, color): + Lines.append([origin, destination, color]) + +func clear_lines(): + Lines = [] + +func _draw(): + for i in range(len(Lines)): + draw_line(Lines[i][0],Lines[i][1],Lines[i][2]) + +# Called when the node enters the scene tree for the first time. +func _ready() -> void: + pass # Replace with function body. + +# Called every frame. 'delta' is the elapsed time since the previous frame. +#func _process(delta: float) -> void: +# pass diff --git a/src/RayCasters/RayCaster.gd b/src/RayCasters/RayCaster.gd new file mode 100644 index 0000000..a8a0317 --- /dev/null +++ b/src/RayCasters/RayCaster.gd @@ -0,0 +1,73 @@ +extends Node2D +class_name RayCaster + +const UP = Vector2(0, -1) +const DOWN = Vector2(0, 1) +const LEFT = Vector2(-1, 0) +const RIGHT = Vector2(1, 0) +const SKIN_WIDTH = 0 + +export (int) var buffer_size = 10 setget _set_buffer_size +var buffer = [] + +# Casts Rays into a given direction. +# direction: 2D up, down, left or right vector +# rect: Shape of the node the raycaster is attached to +# mask: Collision layers +# exceptions: Excepted collision layers +# ray_length: Length of the rays +# ray_buffer: Array to which the rays get saved +func _raycast(direction, rect, mask, exceptions = [], ray_length = 16, ray_buffer = self.buffer): + if !(direction == UP || direction == DOWN || direction == LEFT || direction == RIGHT): + return 0 + + # TODO Manage debug options globally + self.get_child(0).clear_lines() + + var space_state = get_world_2d().direct_space_state + var extents = rect.extents - Vector2(SKIN_WIDTH, SKIN_WIDTH) + var count = 0 + var ray_count = ray_buffer.size() + var cast_to = (ray_length + SKIN_WIDTH) * direction + var origin + var spacing + + if direction == UP || direction == DOWN: + spacing = extents.x * 2 / (ray_count - 1) + else: + spacing = extents.y * 2 / (ray_count - 1) + + for i in range(ray_count): + if direction == UP || direction == DOWN: + origin = Vector2(-extents.x + spacing * i, extents.y) + if direction == UP: + origin.y = -origin.y + else: + # TODO Manage debug options globally + self.get_child(0).add_line(origin, Vector2(origin.x, origin.y + ray_length), Color( 1, 0, 0, 1 )) + else: + origin = Vector2(extents.x, -extents.y + spacing * i) + if direction == LEFT: + origin.x = -origin.x + else: + draw_line(origin, Vector2(origin.x + ray_length, origin.y), Color( 1, 0, 0, 1 )) + + var result = space_state.intersect_ray(global_position + origin, global_position + origin + cast_to, + exceptions, mask) + if result: + ray_buffer[count] = result + count += 1 + + self.get_child(0).update() + + return {ray_buffer = ray_buffer, count = count} + + +func _set_buffer_size(value): + buffer_size = max(value, 2) + self.buffer.resize(buffer_size) + + +# Called when the node enters the scene tree for the first time. +func _ready(): + _set_buffer_size(buffer_size) diff --git a/src/Screens/MainScreen.tscn b/src/Screens/MainScreen.tscn index b707efc..c824d0b 100644 --- a/src/Screens/MainScreen.tscn +++ b/src/Screens/MainScreen.tscn @@ -19,6 +19,10 @@ __meta__ = { [node name="background" type="TextureRect" parent="."] anchor_right = 1.0 anchor_bottom = 1.0 +margin_left = -1.5874 +margin_top = 3.96851 +margin_right = -1.5874 +margin_bottom = 3.96851 texture = ExtResource( 4 ) expand = true stretch_mode = 2 diff --git a/src/StateMachines/StateMachine.gd b/src/StateMachines/StateMachine.gd index 7733240..ec603bf 100644 --- a/src/StateMachines/StateMachine.gd +++ b/src/StateMachines/StateMachine.gd @@ -5,35 +5,38 @@ var state = null setget set_state var previous_state = null var states = {} +# Parent Node that uses these states onready var parent = get_parent() +# Basic process flow for every SM func _physics_process(delta): - if state != null: - _state_logic(delta) - var transition = _get_transition(delta) - if transition != null: - set_state(transition) + if state != null: + _state_logic(delta) + var transition = _get_transition(delta) + if transition != null: + set_state(transition) +# Game logic consequences of state func _state_logic(_delta): - pass + pass func _get_transition(_delta): - return null + return null func _enter_state(_new_state, _previous_state): - pass + pass func _exit_state(_previous_state, _new_state): - pass + pass func set_state(new_state): - previous_state = state - state = new_state + previous_state = state + state = new_state - if previous_state != null: - _exit_state(previous_state, new_state) - if new_state != null: - _enter_state(new_state, previous_state) + if previous_state != null: + _exit_state(previous_state, new_state) + if new_state != null: + _enter_state(new_state, previous_state) func add_state(state_name): - states[states.size()] = state_name + states[state_name] = state_name