├── .gitignore ├── icon.png ├── scripts ├── CollisionLayers.gd ├── Background.gd ├── Character.gd ├── Penguin.gd ├── Main.gd └── ObjectPool.gd ├── assets └── sprites │ ├── characters │ ├── JarJar.png │ ├── Trump.png │ ├── Cruella.png │ ├── Denethor.png │ ├── Umbridge.png │ ├── CaptainHook.png │ ├── Character1.png │ ├── Character2.png │ └── Voldemort.png │ ├── players │ └── Penguin.png │ └── backgrounds │ └── PinkBackground.png ├── default_env.tres ├── README.md ├── scenes ├── characters │ ├── Voldemort.tscn │ ├── JarJar.tscn │ ├── Trump.tscn │ ├── Cruella.tscn │ ├── Denethor.tscn │ ├── Umbridge.tscn │ ├── CaptainHook.tscn │ ├── GenericCharacter1.tscn │ └── GenericCharacter2.tscn ├── Main.tscn └── Penguin.tscn └── project.godot /.gitignore: -------------------------------------------------------------------------------- 1 | *.import 2 | export_presets.cfg 3 | 4 | *.tmp 5 | *.swp 6 | -------------------------------------------------------------------------------- /icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arcticmatt/porta_penguin_godot_tutorials/HEAD/icon.png -------------------------------------------------------------------------------- /scripts/CollisionLayers.gd: -------------------------------------------------------------------------------- 1 | extends Node 2 | 3 | enum Layers { 4 | WALL = 0, 5 | PENGUIN = 1 6 | } 7 | -------------------------------------------------------------------------------- /assets/sprites/characters/JarJar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arcticmatt/porta_penguin_godot_tutorials/HEAD/assets/sprites/characters/JarJar.png -------------------------------------------------------------------------------- /assets/sprites/characters/Trump.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arcticmatt/porta_penguin_godot_tutorials/HEAD/assets/sprites/characters/Trump.png -------------------------------------------------------------------------------- /assets/sprites/players/Penguin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arcticmatt/porta_penguin_godot_tutorials/HEAD/assets/sprites/players/Penguin.png -------------------------------------------------------------------------------- /assets/sprites/characters/Cruella.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arcticmatt/porta_penguin_godot_tutorials/HEAD/assets/sprites/characters/Cruella.png -------------------------------------------------------------------------------- /assets/sprites/characters/Denethor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arcticmatt/porta_penguin_godot_tutorials/HEAD/assets/sprites/characters/Denethor.png -------------------------------------------------------------------------------- /assets/sprites/characters/Umbridge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arcticmatt/porta_penguin_godot_tutorials/HEAD/assets/sprites/characters/Umbridge.png -------------------------------------------------------------------------------- /assets/sprites/characters/CaptainHook.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arcticmatt/porta_penguin_godot_tutorials/HEAD/assets/sprites/characters/CaptainHook.png -------------------------------------------------------------------------------- /assets/sprites/characters/Character1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arcticmatt/porta_penguin_godot_tutorials/HEAD/assets/sprites/characters/Character1.png -------------------------------------------------------------------------------- /assets/sprites/characters/Character2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arcticmatt/porta_penguin_godot_tutorials/HEAD/assets/sprites/characters/Character2.png -------------------------------------------------------------------------------- /assets/sprites/characters/Voldemort.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arcticmatt/porta_penguin_godot_tutorials/HEAD/assets/sprites/characters/Voldemort.png -------------------------------------------------------------------------------- /assets/sprites/backgrounds/PinkBackground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arcticmatt/porta_penguin_godot_tutorials/HEAD/assets/sprites/backgrounds/PinkBackground.png -------------------------------------------------------------------------------- /default_env.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Environment" load_steps=2 format=2] 2 | 3 | [sub_resource type="ProceduralSky" id=1] 4 | 5 | [resource] 6 | background_mode = 2 7 | background_sky = SubResource( 1 ) 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Porta Penguin Godot Tutorials 2 | 3 | Code for the Porta Penguin Godot Tutorial series. 4 | 5 | Blog posts can be found here TODO link. 6 | YouTube videos can be found here TODO link. 7 | 8 | In order to view the code for a specific tutorial, look at the [branches](https://github.com/arcticmatt/porta_penguin_godot_tutorials/branches). -------------------------------------------------------------------------------- /scripts/Background.gd: -------------------------------------------------------------------------------- 1 | extends Sprite 2 | 3 | const VELOCITY: float = -1.5 4 | var g_texture_width: float = 0 5 | 6 | func _ready() -> void: 7 | g_texture_width = texture.get_size().x * scale.x 8 | 9 | func _process(delta: float) -> void: 10 | position.x += VELOCITY 11 | _attempt_reposition() 12 | 13 | func _attempt_reposition() -> void: 14 | if position.x < -g_texture_width: 15 | # Don't just reset position texture width, otherwise there will be a gap 16 | position.x += 2 * g_texture_width 17 | -------------------------------------------------------------------------------- /scripts/Character.gd: -------------------------------------------------------------------------------- 1 | extends StaticBody2D 2 | 3 | # Initially at 0, characters are made to move by the ObjectPool. 4 | var g_velocity: float = 0 5 | 6 | func _process(_delta: float) -> void: 7 | position.x += g_velocity 8 | 9 | # @note: for ObjectPool. 10 | func get_height() -> float: 11 | return $Sprite.texture.get_size().y * scale.y * $Sprite.scale.y 12 | 13 | # @note: for ObjectPool. 14 | func reset() -> void: 15 | g_velocity = 0 16 | 17 | # @note: for ObjectPool. 18 | func start(velocity: float) -> void: 19 | g_velocity = -velocity 20 | $AnimationPlayer.play('Walk') 21 | -------------------------------------------------------------------------------- /scripts/Penguin.gd: -------------------------------------------------------------------------------- 1 | extends RigidBody2D 2 | 3 | const UP_IMPULSE: float = -55.0 4 | 5 | func _ready() -> void: 6 | collision_layer = 0 7 | set_collision_layer_bit(CollisionLayers.Layers.PENGUIN, true) 8 | collision_mask = 0 9 | set_collision_mask_bit(CollisionLayers.Layers.WALL, true) 10 | 11 | func _input(event: InputEvent) -> void: 12 | if event is InputEventKey: 13 | if event.is_action_pressed("ui_select"): 14 | _penguin_jump() 15 | 16 | func _penguin_jump() -> void: 17 | set_linear_velocity(Vector2(0, 0)) 18 | apply_central_impulse(Vector2(0, UP_IMPULSE)) 19 | $FlapAnimationPlayer.stop() 20 | $FlapAnimationPlayer.play("Flap") 21 | -------------------------------------------------------------------------------- /scripts/Main.gd: -------------------------------------------------------------------------------- 1 | extends Node2D 2 | 3 | func _ready() -> void: 4 | # Top wall 5 | _add_wall(Vector2(0, -10), Vector2(1600, 10)) 6 | # Bottom wall, covers grass 7 | _add_wall(Vector2(0, 900), Vector2(1600, 50)) 8 | 9 | func _add_wall(position: Vector2, size: Vector2) -> void: 10 | var rect := RectangleShape2D.new() 11 | rect.set_extents(size) 12 | 13 | var collision_shape := CollisionShape2D.new() 14 | collision_shape.shape = rect 15 | var collision_object := StaticBody2D.new() 16 | collision_object.position = position 17 | collision_object.add_child(collision_shape) 18 | 19 | collision_object.collision_layer = 0 20 | collision_object.set_collision_layer_bit(CollisionLayers.Layers.WALL, true) 21 | collision_object.collision_mask = 0 22 | 23 | add_child(collision_object) 24 | -------------------------------------------------------------------------------- /scenes/characters/Voldemort.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=4 format=2] 2 | 3 | [ext_resource path="res://assets/sprites/characters/Voldemort.png" type="Texture" id=1] 4 | [ext_resource path="res://scripts/Character.gd" type="Script" id=2] 5 | 6 | [sub_resource type="Animation" id=1] 7 | resource_name = "Walk" 8 | tracks/0/type = "value" 9 | tracks/0/path = NodePath("Sprite:frame") 10 | tracks/0/interp = 1 11 | tracks/0/loop_wrap = true 12 | tracks/0/imported = false 13 | tracks/0/enabled = true 14 | tracks/0/keys = { 15 | "times": PoolRealArray( 0, 0.5 ), 16 | "transitions": PoolRealArray( 1, 1 ), 17 | "update": 1, 18 | "values": [ 0, 1 ] 19 | } 20 | 21 | [node name="Voldemort" type="StaticBody2D"] 22 | scale = Vector2( 1.6, 1.6 ) 23 | script = ExtResource( 2 ) 24 | 25 | [node name="Sprite" type="Sprite" parent="."] 26 | texture = ExtResource( 1 ) 27 | hframes = 3 28 | 29 | [node name="AnimationPlayer" type="AnimationPlayer" parent="."] 30 | anims/Walk = SubResource( 1 ) 31 | -------------------------------------------------------------------------------- /scenes/characters/JarJar.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=4 format=2] 2 | 3 | [ext_resource path="res://assets/sprites/characters/JarJar.png" type="Texture" id=1] 4 | [ext_resource path="res://scripts/Character.gd" type="Script" id=2] 5 | 6 | [sub_resource type="Animation" id=1] 7 | resource_name = "Walk" 8 | loop = true 9 | tracks/0/type = "value" 10 | tracks/0/path = NodePath("Sprite:frame") 11 | tracks/0/interp = 1 12 | tracks/0/loop_wrap = true 13 | tracks/0/imported = false 14 | tracks/0/enabled = true 15 | tracks/0/keys = { 16 | "times": PoolRealArray( 0, 0.5 ), 17 | "transitions": PoolRealArray( 1, 1 ), 18 | "update": 1, 19 | "values": [ 0, 1 ] 20 | } 21 | 22 | [node name="Jarjar" type="StaticBody2D"] 23 | scale = Vector2( 1.5, 1.5 ) 24 | script = ExtResource( 2 ) 25 | 26 | [node name="Sprite" type="Sprite" parent="."] 27 | texture = ExtResource( 1 ) 28 | hframes = 3 29 | 30 | [node name="AnimationPlayer" type="AnimationPlayer" parent="."] 31 | anims/Walk = SubResource( 1 ) 32 | -------------------------------------------------------------------------------- /scenes/characters/Trump.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=4 format=2] 2 | 3 | [ext_resource path="res://assets/sprites/characters/Trump.png" type="Texture" id=1] 4 | [ext_resource path="res://scripts/Character.gd" type="Script" id=2] 5 | 6 | [sub_resource type="Animation" id=1] 7 | resource_name = "Walk" 8 | loop = true 9 | tracks/0/type = "value" 10 | tracks/0/path = NodePath("Sprite:frame") 11 | tracks/0/interp = 1 12 | tracks/0/loop_wrap = true 13 | tracks/0/imported = false 14 | tracks/0/enabled = true 15 | tracks/0/keys = { 16 | "times": PoolRealArray( 0, 0.5 ), 17 | "transitions": PoolRealArray( 1, 1 ), 18 | "update": 1, 19 | "values": [ 0, 1 ] 20 | } 21 | 22 | [node name="Trump" type="StaticBody2D"] 23 | scale = Vector2( 1.5, 1.5 ) 24 | script = ExtResource( 2 ) 25 | 26 | [node name="Sprite" type="Sprite" parent="."] 27 | texture = ExtResource( 1 ) 28 | hframes = 3 29 | 30 | [node name="AnimationPlayer" type="AnimationPlayer" parent="."] 31 | anims/Walk = SubResource( 1 ) 32 | -------------------------------------------------------------------------------- /scenes/characters/Cruella.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=4 format=2] 2 | 3 | [ext_resource path="res://assets/sprites/characters/Cruella.png" type="Texture" id=1] 4 | [ext_resource path="res://scripts/Character.gd" type="Script" id=2] 5 | 6 | [sub_resource type="Animation" id=1] 7 | resource_name = "Walk" 8 | loop = true 9 | tracks/0/type = "value" 10 | tracks/0/path = NodePath("Sprite:frame") 11 | tracks/0/interp = 1 12 | tracks/0/loop_wrap = true 13 | tracks/0/imported = false 14 | tracks/0/enabled = true 15 | tracks/0/keys = { 16 | "times": PoolRealArray( 0, 0.5 ), 17 | "transitions": PoolRealArray( 1, 1 ), 18 | "update": 1, 19 | "values": [ 0, 1 ] 20 | } 21 | 22 | [node name="Cruella" type="StaticBody2D"] 23 | scale = Vector2( 1.5, 1.5 ) 24 | script = ExtResource( 2 ) 25 | 26 | [node name="Sprite" type="Sprite" parent="."] 27 | texture = ExtResource( 1 ) 28 | hframes = 3 29 | 30 | [node name="AnimationPlayer" type="AnimationPlayer" parent="."] 31 | anims/Walk = SubResource( 1 ) 32 | -------------------------------------------------------------------------------- /scenes/characters/Denethor.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=4 format=2] 2 | 3 | [ext_resource path="res://assets/sprites/characters/Denethor.png" type="Texture" id=1] 4 | [ext_resource path="res://scripts/Character.gd" type="Script" id=2] 5 | 6 | [sub_resource type="Animation" id=1] 7 | resource_name = "Walk" 8 | loop = true 9 | tracks/0/type = "value" 10 | tracks/0/path = NodePath("Sprite:frame") 11 | tracks/0/interp = 1 12 | tracks/0/loop_wrap = true 13 | tracks/0/imported = false 14 | tracks/0/enabled = true 15 | tracks/0/keys = { 16 | "times": PoolRealArray( 0, 0.5 ), 17 | "transitions": PoolRealArray( 1, 1 ), 18 | "update": 1, 19 | "values": [ 0, 1 ] 20 | } 21 | 22 | [node name="Denethor" type="StaticBody2D"] 23 | scale = Vector2( 1.5, 1.5 ) 24 | script = ExtResource( 2 ) 25 | 26 | [node name="Sprite" type="Sprite" parent="."] 27 | texture = ExtResource( 1 ) 28 | hframes = 3 29 | 30 | [node name="AnimationPlayer" type="AnimationPlayer" parent="."] 31 | anims/Walk = SubResource( 1 ) 32 | -------------------------------------------------------------------------------- /scenes/characters/Umbridge.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=4 format=2] 2 | 3 | [ext_resource path="res://assets/sprites/characters/Umbridge.png" type="Texture" id=1] 4 | [ext_resource path="res://scripts/Character.gd" type="Script" id=2] 5 | 6 | [sub_resource type="Animation" id=1] 7 | resource_name = "Walk" 8 | loop = true 9 | tracks/0/type = "value" 10 | tracks/0/path = NodePath("Sprite:frame") 11 | tracks/0/interp = 1 12 | tracks/0/loop_wrap = true 13 | tracks/0/imported = false 14 | tracks/0/enabled = true 15 | tracks/0/keys = { 16 | "times": PoolRealArray( 0, 0.5 ), 17 | "transitions": PoolRealArray( 1, 1 ), 18 | "update": 1, 19 | "values": [ 0, 1 ] 20 | } 21 | 22 | [node name="Umbridge" type="StaticBody2D"] 23 | scale = Vector2( 1.5, 1.5 ) 24 | script = ExtResource( 2 ) 25 | 26 | [node name="Sprite" type="Sprite" parent="."] 27 | texture = ExtResource( 1 ) 28 | hframes = 3 29 | 30 | [node name="AnimationPlayer" type="AnimationPlayer" parent="."] 31 | anims/Walk = SubResource( 1 ) 32 | -------------------------------------------------------------------------------- /scenes/characters/CaptainHook.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=4 format=2] 2 | 3 | [ext_resource path="res://assets/sprites/characters/CaptainHook.png" type="Texture" id=1] 4 | [ext_resource path="res://scripts/Character.gd" type="Script" id=2] 5 | 6 | [sub_resource type="Animation" id=1] 7 | resource_name = "Walk" 8 | loop = true 9 | tracks/0/type = "value" 10 | tracks/0/path = NodePath("Sprite:frame") 11 | tracks/0/interp = 1 12 | tracks/0/loop_wrap = true 13 | tracks/0/imported = false 14 | tracks/0/enabled = true 15 | tracks/0/keys = { 16 | "times": PoolRealArray( 0, 0.5 ), 17 | "transitions": PoolRealArray( 1, 1 ), 18 | "update": 1, 19 | "values": [ 0, 1 ] 20 | } 21 | 22 | [node name="CaptainHook" type="StaticBody2D"] 23 | scale = Vector2( 1.5, 1.5 ) 24 | script = ExtResource( 2 ) 25 | 26 | [node name="Sprite" type="Sprite" parent="."] 27 | texture = ExtResource( 1 ) 28 | hframes = 3 29 | 30 | [node name="AnimationPlayer" type="AnimationPlayer" parent="."] 31 | anims/Walk = SubResource( 1 ) 32 | -------------------------------------------------------------------------------- /project.godot: -------------------------------------------------------------------------------- 1 | ; Engine configuration file. 2 | ; It's best edited using the editor UI and not directly, 3 | ; since the parameters that go here are not all obvious. 4 | ; 5 | ; Format: 6 | ; [section] ; section goes between [] 7 | ; param=value ; assign values to parameters 8 | 9 | config_version=4 10 | 11 | _global_script_classes=[ ] 12 | _global_script_class_icons={ 13 | 14 | } 15 | 16 | [application] 17 | 18 | config/name="porta_penguin_godot_tutorials" 19 | run/main_scene="res://scenes/Main.tscn" 20 | config/icon="res://icon.png" 21 | 22 | [autoload] 23 | 24 | CollisionLayers="*res://scripts/CollisionLayers.gd" 25 | 26 | [display] 27 | 28 | window/size/width=1600 29 | window/size/height=900 30 | window/size/test_width=1200 31 | window/size/test_height=675 32 | window/stretch/mode="2d" 33 | 34 | [rendering] 35 | 36 | quality/driver/driver_name="GLES2" 37 | vram_compression/import_etc=true 38 | vram_compression/import_etc2=false 39 | environment/default_environment="res://default_env.tres" 40 | -------------------------------------------------------------------------------- /scenes/characters/GenericCharacter1.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=4 format=2] 2 | 3 | [ext_resource path="res://assets/sprites/characters/Character1.png" type="Texture" id=1] 4 | [ext_resource path="res://scripts/Character.gd" type="Script" id=2] 5 | 6 | [sub_resource type="Animation" id=1] 7 | resource_name = "Walk" 8 | loop = true 9 | tracks/0/type = "value" 10 | tracks/0/path = NodePath("Sprite:frame") 11 | tracks/0/interp = 1 12 | tracks/0/loop_wrap = true 13 | tracks/0/imported = false 14 | tracks/0/enabled = true 15 | tracks/0/keys = { 16 | "times": PoolRealArray( 0, 0.5 ), 17 | "transitions": PoolRealArray( 1, 1 ), 18 | "update": 1, 19 | "values": [ 0, 1 ] 20 | } 21 | 22 | [node name="GenericCharacter1" type="StaticBody2D"] 23 | scale = Vector2( 1.4, 1.4 ) 24 | script = ExtResource( 2 ) 25 | 26 | [node name="Sprite" type="Sprite" parent="."] 27 | scale = Vector2( 5, 5 ) 28 | texture = ExtResource( 1 ) 29 | hframes = 3 30 | 31 | [node name="AnimationPlayer" type="AnimationPlayer" parent="."] 32 | anims/Walk = SubResource( 1 ) 33 | -------------------------------------------------------------------------------- /scenes/characters/GenericCharacter2.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=4 format=2] 2 | 3 | [ext_resource path="res://assets/sprites/characters/Character2.png" type="Texture" id=1] 4 | [ext_resource path="res://scripts/Character.gd" type="Script" id=2] 5 | 6 | [sub_resource type="Animation" id=1] 7 | resource_name = "Walk" 8 | loop = true 9 | tracks/0/type = "value" 10 | tracks/0/path = NodePath("Sprite:frame") 11 | tracks/0/interp = 1 12 | tracks/0/loop_wrap = true 13 | tracks/0/imported = false 14 | tracks/0/enabled = true 15 | tracks/0/keys = { 16 | "times": PoolRealArray( 0, 0.5 ), 17 | "transitions": PoolRealArray( 1, 1 ), 18 | "update": 1, 19 | "values": [ 0, 1 ] 20 | } 21 | 22 | [node name="GenericCharacter2" type="StaticBody2D"] 23 | scale = Vector2( 1.4, 1.4 ) 24 | script = ExtResource( 2 ) 25 | 26 | [node name="Sprite" type="Sprite" parent="."] 27 | scale = Vector2( 5, 5 ) 28 | texture = ExtResource( 1 ) 29 | hframes = 3 30 | 31 | [node name="AnimationPlayer" type="AnimationPlayer" parent="."] 32 | anims/Walk = SubResource( 1 ) 33 | -------------------------------------------------------------------------------- /scenes/Main.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=6 format=2] 2 | 3 | [ext_resource path="res://assets/sprites/backgrounds/PinkBackground.png" type="Texture" id=1] 4 | [ext_resource path="res://scripts/Background.gd" type="Script" id=2] 5 | [ext_resource path="res://scripts/Main.gd" type="Script" id=3] 6 | [ext_resource path="res://scenes/Penguin.tscn" type="PackedScene" id=4] 7 | [ext_resource path="res://scripts/ObjectPool.gd" type="Script" id=5] 8 | 9 | [node name="Main" type="Node2D"] 10 | script = ExtResource( 3 ) 11 | 12 | [node name="Background1" type="Sprite" parent="."] 13 | scale = Vector2( 10, 10 ) 14 | texture = ExtResource( 1 ) 15 | centered = false 16 | script = ExtResource( 2 ) 17 | 18 | [node name="Background2" type="Sprite" parent="."] 19 | position = Vector2( 1600, 0 ) 20 | scale = Vector2( 10, 10 ) 21 | texture = ExtResource( 1 ) 22 | centered = false 23 | script = ExtResource( 2 ) 24 | 25 | [node name="Penguin" parent="." instance=ExtResource( 4 )] 26 | position = Vector2( 157.575, 302.834 ) 27 | 28 | [node name="CharacterPool" type="Node2D" parent="."] 29 | script = ExtResource( 5 ) 30 | g_path = "res://scenes/characters/" 31 | -------------------------------------------------------------------------------- /scenes/Penguin.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=4 format=2] 2 | 3 | [ext_resource path="res://assets/sprites/players/Penguin.png" type="Texture" id=1] 4 | [ext_resource path="res://scripts/Penguin.gd" type="Script" id=2] 5 | 6 | [sub_resource type="Animation" id=1] 7 | resource_name = "Flap" 8 | tracks/0/type = "value" 9 | tracks/0/path = NodePath("PenguinSprite:frame") 10 | tracks/0/interp = 1 11 | tracks/0/loop_wrap = true 12 | tracks/0/imported = false 13 | tracks/0/enabled = true 14 | tracks/0/keys = { 15 | "times": PoolRealArray( 0, 0.4 ), 16 | "transitions": PoolRealArray( 1, 1 ), 17 | "update": 1, 18 | "values": [ 1, 0 ] 19 | } 20 | 21 | [node name="Penguin" type="RigidBody2D"] 22 | position = Vector2( 214.17, 167.676 ) 23 | mass = 0.102041 24 | gravity_scale = 16.0 25 | script = ExtResource( 2 ) 26 | 27 | [node name="PenguinSprite" type="Sprite" parent="."] 28 | position = Vector2( 0, -0.494629 ) 29 | texture = ExtResource( 1 ) 30 | hframes = 3 31 | 32 | [node name="FlapAnimationPlayer" type="AnimationPlayer" parent="."] 33 | anims/Flap = SubResource( 1 ) 34 | 35 | [node name="Collision" type="CollisionPolygon2D" parent="."] 36 | position = Vector2( 155.468, -0.157196 ) 37 | polygon = PoolVector2Array( -105.5, -34, -104.3, -31.5, -95.5, -31.5, -95.5, -29.2, -89.5, -21.5, -81.1, -21.5, -79.1, -16.5, -76.7, -16.5, -73.5, -13.3, -73.5, -5.7, -88.5, -3.7, -88.5, -1.5, -103.5, 10.5, -103.5, 28.5, -113.5, 35.5, -113.5, 37.5, -221.5, 37.5, -221.5, 36.5, -232.5, 36.5, -232.5, 18.5, -230.5, 18.5, -223.5, 8.5, -221.5, 8.5, -221.5, 0.5, -219.4, 0.5, -203.4, -16.5, -141.5, -16.5, -141.5, -19.5, -139.3, -19.5, -124.5, -34.3, -124.5, -36.5, -105.5, -36.5 ) 38 | -------------------------------------------------------------------------------- /scripts/ObjectPool.gd: -------------------------------------------------------------------------------- 1 | extends Node 2 | 3 | ### Export variables 4 | export var g_copies_of_each: int = 2 5 | export var g_min_y: int = 860 6 | export var g_max_y: int = 860 7 | export var g_min_spawn_wait_ms: int = 1000 8 | export var g_max_spawn_wait_ms: int = 2000 9 | export var g_object_velocity: float = 5 10 | export var g_path: String = "" 11 | export var g_starting_x: int = 1700 12 | 13 | ### Object pool globals 14 | var g_last_spawn_time_ms: int = 0 15 | var g_max_available_objects: int = 0 16 | var g_object_pool: Array = [] 17 | var g_object_pool_available: Array = [] 18 | var g_rand_spawn_wait_ms: int = 0 19 | 20 | ### Constants 21 | const LEFT_BOUND: int = -50 22 | 23 | func _ready(): 24 | var paths: Array = _get_full_paths(g_path) 25 | for path in paths: 26 | var resource = load(path) 27 | for _i in g_copies_of_each: 28 | var object: Node2D = resource.instance() 29 | object.global_position = _get_random_global_position(object) 30 | g_object_pool.append(object) 31 | g_object_pool_available.append(object) 32 | get_parent().call_deferred('add_child_below_node', self, object) 33 | 34 | g_max_available_objects = paths.size() * g_copies_of_each 35 | 36 | func _process(delta: float) -> void: 37 | var time_diff = OS.get_system_time_msecs() - g_last_spawn_time_ms 38 | if time_diff > g_rand_spawn_wait_ms: 39 | var available_object = _find_and_remove_available_object() 40 | if available_object: 41 | available_object.global_position = _get_random_global_position(available_object) 42 | available_object.start(g_object_velocity) 43 | g_last_spawn_time_ms = OS.get_system_time_msecs() 44 | g_rand_spawn_wait_ms = rand_range(g_min_spawn_wait_ms, g_max_spawn_wait_ms) 45 | _add_to_available_objects() 46 | 47 | func _add_to_available_objects() -> void: 48 | for object in g_object_pool: 49 | if object.is_inside_tree() and object.global_position.x < LEFT_BOUND: 50 | object.global_position = _get_random_global_position(object) 51 | object.reset() 52 | g_object_pool_available.append(object) 53 | 54 | assert(g_object_pool_available.size() <= g_max_available_objects) 55 | 56 | # Returns and removes a random object from the pool of available objects, 57 | # if one exists. 58 | func _find_and_remove_available_object() -> Node2D: 59 | if g_object_pool_available.size() == 0: 60 | return null 61 | var available_index: int = randi() % g_object_pool_available.size() 62 | var available_object: Node2D = g_object_pool_available[available_index] 63 | g_object_pool_available.remove(available_index) 64 | return available_object 65 | 66 | # Given a path to either a file or directory, returns a list of all the paths 67 | # for which we should instance a resource. 68 | # @param path either a file (.tscn) or a directory of scene files. 69 | # @return the path names for which we should instance a resource. 70 | func _get_full_paths(path: String) -> Array: 71 | if path.ends_with('.tscn'): 72 | return [path] 73 | 74 | var files = _list_files_in_directory(path) 75 | var paths = [] 76 | for file in files: 77 | paths.append(path + file) 78 | return paths 79 | 80 | # Returns a random (within certain boundaries) global position to spawn the 81 | # passed-in object at. 82 | func _get_random_global_position(object: Node2D) -> Vector2: 83 | var texture_height: float = object.get_height() 84 | var starting_y: float = rand_range(g_min_y, g_max_y) - (texture_height / 2) 85 | return Vector2(g_starting_x, starting_y) 86 | 87 | # Given a path to a directory, returns the names of all 88 | # files in that directory. 89 | # @param path the path to a directory, e.g. "res://scenes/characters" 90 | # @return the names of all files in that directory, e.g. ["CaptainHook.tscn"] 91 | func _list_files_in_directory(path: String) -> Array: 92 | var files: Array = [] 93 | var dir := Directory.new() 94 | 95 | dir.open(path) 96 | 97 | # Initialize stream used to list all files and directories 98 | dir.list_dir_begin() 99 | 100 | while true: 101 | var file: String = dir.get_next() 102 | if file == "": 103 | break 104 | elif not file.begins_with("."): 105 | files.append(file) 106 | 107 | # Close stream 108 | dir.list_dir_end() 109 | 110 | return files 111 | --------------------------------------------------------------------------------