From c7de3b4d363f016bd1bea39c9d878f86e77ac86c Mon Sep 17 00:00:00 2001 From: Nathan Lovato Date: Tue, 12 Nov 2019 11:02:06 +0100 Subject: [PATCH] Refactor the Player and gun to fit our code guidelines --- platformer-2d-rework/project.godot | 6 ++ platformer-2d-rework/src/Actors/Gun.gd | 22 ++++ platformer-2d-rework/src/Actors/Player.gd | 106 +++++++++++--------- platformer-2d-rework/src/Actors/Player.tscn | 26 +++-- 4 files changed, 104 insertions(+), 56 deletions(-) create mode 100644 platformer-2d-rework/src/Actors/Gun.gd diff --git a/platformer-2d-rework/project.godot b/platformer-2d-rework/project.godot index 8303bc3..536de60 100644 --- a/platformer-2d-rework/project.godot +++ b/platformer-2d-rework/project.godot @@ -29,6 +29,11 @@ _global_script_classes=[ { "language": "GDScript", "path": "res://src/Actors/Enemy.gd" }, { +"base": "Position2D", +"class": "Gun", +"language": "GDScript", +"path": "res://src/Actors/Gun.gd" +}, { "base": "Node2D", "class": "MovingPlatform", "language": "GDScript", @@ -44,6 +49,7 @@ _global_script_class_icons={ "Bullet": "", "Coin": "", "Enemy": "", +"Gun": "", "MovingPlatform": "", "Player": "" } diff --git a/platformer-2d-rework/src/Actors/Gun.gd b/platformer-2d-rework/src/Actors/Gun.gd new file mode 100644 index 0000000..8bad2ff --- /dev/null +++ b/platformer-2d-rework/src/Actors/Gun.gd @@ -0,0 +1,22 @@ +extends Position2D +class_name Gun + + +onready var sound_shoot: AudioStreamPlayer2D = $Shoot +onready var timer: Timer = $Cooldown + +const Bullet = preload("res://src/Objects/Bullet.tscn") +const BULLET_VELOCITY := 1000.0 + + +func shoot(direction: int = 1) -> bool: + if not timer.is_stopped(): + return false + var bullet = Bullet.instance() + bullet.global_position = global_position + bullet.linear_velocity = Vector2(direction * BULLET_VELOCITY, 0) + + bullet.set_as_toplevel(true) + add_child(bullet) + sound_shoot.play() + return true diff --git a/platformer-2d-rework/src/Actors/Player.gd b/platformer-2d-rework/src/Actors/Player.gd index 3158c7e..fb6abf7 100644 --- a/platformer-2d-rework/src/Actors/Player.gd +++ b/platformer-2d-rework/src/Actors/Player.gd @@ -1,67 +1,59 @@ extends Actor - class_name Player -onready var ray: RayCast2D = $PlatformDetector + +onready var platform_detector: RayCast2D = $PlatformDetector onready var sprite: Sprite = $Sprite -onready var sound_shoot: AudioStreamPlayer2D = $SoundShoot onready var animation_player: AnimationPlayer = $AnimationPlayer -onready var gun_position: Position2D = $Sprite/GunPosition - -const BULLET_VELOCITY := 1000.0 -const SHOOT_TIME_SHOW_WEAPON := 0.2 - -var _current_animation := "" -var _shoot_time := 99.0 # time since last shot - -var Bullet = preload("res://src/Objects/Bullet.tscn") - - -func _physics_process(delta): - _shoot_time += delta +onready var shoot_timer: = $ShootAnimation +onready var gun: Gun = $Sprite/Gun + + +""" +Physics process is a built-in loop in Godot. +If you define _physics_process on a node, Godot will call it every frame. + +We use separate functions to calculate the direction and velocity to make this one easier to read. +At a glance, you can see that the physics process loop: + 1. Calculates the move direction. + 2. Calculates the move velocity. + 3. Moves the character. + 4. Updates the sprite direction. + 5. Shoots bullets. + 6. Updates the animation. + +Splitting the physics process logic into functions not only makes it easier to read, it help to change or improve the code later on: + - If you need to change a calculation, you can use Go To -> Function (Ctrl Alt F) to quickly jump to the corresponding function. + - If you split the character into a state machine or more advanced pattern, you can easily move individual functions. +""" +func _physics_process(delta: float) -> void: + var direction: = get_direction() var is_jump_interrupted: = Input.is_action_just_released("jump") and _velocity.y < 0.0 - - var direction: = get_direction() _velocity = calculate_move_velocity(_velocity, direction, speed, is_jump_interrupted) - var is_snapping: Vector2 = Vector2.DOWN * 60.0 if direction.y == 0.0 else Vector2.ZERO - var is_on_platform: = ray.is_colliding() + + var is_snapping: = Vector2.DOWN * 60.0 if direction.y == 0.0 else Vector2.ZERO + var is_on_platform: = platform_detector.is_colliding() _velocity = move_and_slide_with_snap( _velocity, is_snapping, FLOOR_NORMAL, not is_on_platform, 4, 0.9, false ) - ### Shooting - if Input.is_action_just_pressed("shoot"): - var bullet = Bullet.instance() - bullet.position = gun_position.global_position # use node for shoot position - bullet.linear_velocity = Vector2(sprite.scale.x * BULLET_VELOCITY, 0) - bullet.add_collision_exception_with(self) # don't want player to collide with bullet - get_parent().add_child(bullet) # don't want bullet to move with me, so add it as child of parent - sound_shoot.play() - _shoot_time = 0 - - ### Animation - var new_animation = "idle" - - if abs(direction.x) > 0: + # When the character’s direction changes, we want to to scale the Sprite accordingly to flip it. This will make Robi face left or right depending on the direction you move. + if direction.x != 0: sprite.scale.x = direction.x - - if is_on_floor(): - if abs(_velocity.x) > 0: - new_animation = "run" - else: - - if _velocity.y > 0: - new_animation = "falling" - else: - new_animation = "jumping" - if _shoot_time < SHOOT_TIME_SHOW_WEAPON: - new_animation += "_weapon" + # We use the sprite's scale to store Robi’s look direction which allows us in turn to shoot bullets forward. + # There are many situations like these where you can reuse existing properties instead of creating new variables. + var is_shooting: = false + if Input.is_action_just_pressed("shoot"): + is_shooting = gun.shoot(sprite.scale.x) - if new_animation != _current_animation: - _current_animation = new_animation - animation_player.play(new_animation) + + var animation: = get_new_animation(is_shooting) + if animation != animation_player.current_animation and shoot_timer.is_stopped(): + if is_shooting: + shoot_timer.start() + animation_player.play(animation) func get_direction() -> Vector2: @@ -71,6 +63,10 @@ func get_direction() -> Vector2: ) +""" +This function calculates a new velocity whenever you need it. +It allows you to interrupt jumps. +""" func calculate_move_velocity( linear_velocity: Vector2, direction: Vector2, @@ -83,5 +79,15 @@ func calculate_move_velocity( velocity.y = speed.y * direction.y if is_jump_interrupted: velocity.y = 0.0 - return velocity + + +func get_new_animation(is_shooting: bool = false) -> String: + var animation_new: = "" + if is_on_floor(): + animation_new = "run" if abs(_velocity.x) > 0 else "idle" + else: + animation_new = "falling" if _velocity.y > 0 else "jumping" + if is_shooting: + animation_new += "_weapon" + return animation_new diff --git a/platformer-2d-rework/src/Actors/Player.tscn b/platformer-2d-rework/src/Actors/Player.tscn index ad2ca91..81706fd 100644 --- a/platformer-2d-rework/src/Actors/Player.tscn +++ b/platformer-2d-rework/src/Actors/Player.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=20 format=2] +[gd_scene load_steps=21 format=2] [ext_resource path="res://src/Actors/Player.gd" type="Script" id=1] [ext_resource path="res://assets/art/player/robot_demo.png" type="Texture" id=2] @@ -8,6 +8,7 @@ [ext_resource path="res://assets/art/ui/touch_button_right.png" type="Texture" id=6] [ext_resource path="res://assets/art/ui/touch_button_jump.png" type="Texture" id=7] [ext_resource path="res://assets/art/ui/touch_button_fire.png" type="Texture" id=8] +[ext_resource path="res://src/Actors/Gun.gd" type="Script" id=9] [sub_resource type="Animation" id=1] resource_name = "crouch" @@ -191,6 +192,11 @@ script = ExtResource( 1 ) speed = Vector2( 400, 700 ) gravity = 1800.0 +[node name="ShootAnimation" type="Timer" parent="."] +process_mode = 0 +wait_time = 0.2 +one_shot = true + [node name="PlatformDetector" type="RayCast2D" parent="."] position = Vector2( 0, 29.9245 ) enabled = true @@ -201,9 +207,20 @@ collision_mask = 8 texture = ExtResource( 2 ) vframes = 2 hframes = 16 +frame = 26 -[node name="GunPosition" type="Position2D" parent="Sprite"] +[node name="Gun" type="Position2D" parent="Sprite"] position = Vector2( 30.6589, 6.13176 ) +script = ExtResource( 9 ) + +[node name="Shoot" type="AudioStreamPlayer2D" parent="Sprite/Gun"] +position = Vector2( -30.6589, -6.13176 ) +stream = ExtResource( 4 ) + +[node name="Cooldown" type="Timer" parent="Sprite/Gun"] +process_mode = 0 +wait_time = 0.3 +one_shot = true [node name="AnimationPlayer" type="AnimationPlayer" parent="."] playback_speed = 2.6 @@ -225,12 +242,9 @@ current = true position = Vector2( 0.291992, -0.835023 ) shape = SubResource( 11 ) -[node name="SoundJump" type="AudioStreamPlayer2D" parent="."] +[node name="Jump" type="AudioStreamPlayer2D" parent="."] stream = ExtResource( 3 ) -[node name="SoundShoot" type="AudioStreamPlayer2D" parent="."] -stream = ExtResource( 4 ) - [node name="UI" type="CanvasLayer" parent="."] layer = 0