feat: Implement core game mechanics including player, enemies, bullets, HUD, and level setup.
This commit is contained in:
4
.editorconfig
Normal file
4
.editorconfig
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
2
.gitattributes
vendored
Normal file
2
.gitattributes
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
# Normalize EOL for all files that Git considers text files.
|
||||||
|
* text=auto eol=lf
|
||||||
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# Godot 4+ specific ignores
|
||||||
|
.godot/
|
||||||
|
/android/
|
||||||
3
.vscode/settings.json
vendored
Normal file
3
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"godotTools.editorPath.godot4": "/home/mathias/Desktop/Godot_v4.5.1-stable_linux.x86_64"
|
||||||
|
}
|
||||||
BIN
assets/cat_tank_hull.png
Normal file
BIN
assets/cat_tank_hull.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 507 B |
40
assets/cat_tank_hull.png.import
Normal file
40
assets/cat_tank_hull.png.import
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://bxvveyvfp8gmq"
|
||||||
|
path="res://.godot/imported/cat_tank_hull.png-a49130f175b9a61446fee1a66af4f122.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/cat_tank_hull.png"
|
||||||
|
dest_files=["res://.godot/imported/cat_tank_hull.png-a49130f175b9a61446fee1a66af4f122.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/uastc_level=0
|
||||||
|
compress/rdo_quality_loss=0.0
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=false
|
||||||
|
mipmaps/limit=-1
|
||||||
|
roughness/mode=0
|
||||||
|
roughness/src_normal=""
|
||||||
|
process/channel_remap/red=0
|
||||||
|
process/channel_remap/green=1
|
||||||
|
process/channel_remap/blue=2
|
||||||
|
process/channel_remap/alpha=3
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
process/hdr_as_srgb=false
|
||||||
|
process/hdr_clamp_exposure=false
|
||||||
|
process/size_limit=0
|
||||||
|
detect_3d/compress_to=1
|
||||||
BIN
assets/cat_tank_turret.png
Normal file
BIN
assets/cat_tank_turret.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 563 B |
40
assets/cat_tank_turret.png.import
Normal file
40
assets/cat_tank_turret.png.import
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://ddktwa3t2dnlv"
|
||||||
|
path="res://.godot/imported/cat_tank_turret.png-457811b15b6bbddead7047b686919c6d.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/cat_tank_turret.png"
|
||||||
|
dest_files=["res://.godot/imported/cat_tank_turret.png-457811b15b6bbddead7047b686919c6d.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/uastc_level=0
|
||||||
|
compress/rdo_quality_loss=0.0
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=false
|
||||||
|
mipmaps/limit=-1
|
||||||
|
roughness/mode=0
|
||||||
|
roughness/src_normal=""
|
||||||
|
process/channel_remap/red=0
|
||||||
|
process/channel_remap/green=1
|
||||||
|
process/channel_remap/blue=2
|
||||||
|
process/channel_remap/alpha=3
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
process/hdr_as_srgb=false
|
||||||
|
process/hdr_clamp_exposure=false
|
||||||
|
process/size_limit=0
|
||||||
|
detect_3d/compress_to=1
|
||||||
1
icon.svg
Normal file
1
icon.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128"><rect width="124" height="124" x="2" y="2" fill="#363d52" stroke="#212532" stroke-width="4" rx="14"/><g fill="#fff" transform="translate(12.322 12.322)scale(.101)"><path d="M105 673v33q407 354 814 0v-33z"/><path fill="#478cbf" d="m105 673 152 14q12 1 15 14l4 67 132 10 8-61q2-11 15-15h162q13 4 15 15l8 61 132-10 4-67q3-13 15-14l152-14V427q30-39 56-81-35-59-83-108-43 20-82 47-40-37-88-64 7-51 8-102-59-28-123-42-26 43-46 89-49-7-98 0-20-46-46-89-64 14-123 42 1 51 8 102-48 27-88 64-39-27-82-47-48 49-83 108 26 42 56 81zm0 33v39c0 276 813 276 814 0v-39l-134 12-5 69q-2 10-14 13l-162 11q-12 0-16-11l-10-65H446l-10 65q-4 11-16 11l-162-11q-12-3-14-13l-5-69z"/><path d="M483 600c0 34 58 34 58 0v-86c0-34-58-34-58 0z"/><circle cx="725" cy="526" r="90"/><circle cx="299" cy="526" r="90"/></g><g fill="#414042" transform="translate(12.322 12.322)scale(.101)"><circle cx="307" cy="532" r="60"/><circle cx="717" cy="532" r="60"/></g></svg>
|
||||||
|
After Width: | Height: | Size: 995 B |
43
icon.svg.import
Normal file
43
icon.svg.import
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://ddmjl3yshqcjw"
|
||||||
|
path="res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://icon.svg"
|
||||||
|
dest_files=["res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/uastc_level=0
|
||||||
|
compress/rdo_quality_loss=0.0
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=false
|
||||||
|
mipmaps/limit=-1
|
||||||
|
roughness/mode=0
|
||||||
|
roughness/src_normal=""
|
||||||
|
process/channel_remap/red=0
|
||||||
|
process/channel_remap/green=1
|
||||||
|
process/channel_remap/blue=2
|
||||||
|
process/channel_remap/alpha=3
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
process/hdr_as_srgb=false
|
||||||
|
process/hdr_clamp_exposure=false
|
||||||
|
process/size_limit=0
|
||||||
|
detect_3d/compress_to=1
|
||||||
|
svg/scale=1.0
|
||||||
|
editor/scale_with_editor_scale=false
|
||||||
|
editor/convert_colors_with_editor_theme=false
|
||||||
43
project.godot
Normal file
43
project.godot
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
; Engine configuration file.
|
||||||
|
; It's best edited using the editor UI and not directly,
|
||||||
|
; since the parameters that go here are not all obvious.
|
||||||
|
;
|
||||||
|
; Format:
|
||||||
|
; [section] ; section goes between []
|
||||||
|
; param=value ; assign values to parameters
|
||||||
|
|
||||||
|
config_version=5
|
||||||
|
|
||||||
|
[application]
|
||||||
|
|
||||||
|
config/name="CatTank"
|
||||||
|
run/main_scene="uid://cfwyr25ftoqpk"
|
||||||
|
config/features=PackedStringArray("4.5", "Forward Plus")
|
||||||
|
config/icon="res://icon.svg"
|
||||||
|
|
||||||
|
[input]
|
||||||
|
|
||||||
|
kb_w={
|
||||||
|
"deadzone": 0.2,
|
||||||
|
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":87,"key_label":0,"unicode":119,"location":0,"echo":false,"script":null)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
kb_a={
|
||||||
|
"deadzone": 0.2,
|
||||||
|
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":65,"key_label":0,"unicode":97,"location":0,"echo":false,"script":null)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
kb_s={
|
||||||
|
"deadzone": 0.2,
|
||||||
|
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":83,"key_label":0,"unicode":115,"location":0,"echo":false,"script":null)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
kb_d={
|
||||||
|
"deadzone": 0.2,
|
||||||
|
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":68,"key_label":0,"unicode":100,"location":0,"echo":false,"script":null)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
[rendering]
|
||||||
|
|
||||||
|
textures/canvas_textures/default_texture_filter=0
|
||||||
18
scenes/ammo_pickup.tscn
Normal file
18
scenes/ammo_pickup.tscn
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
[gd_scene load_steps=4 format=3 uid="uid://mmopickup123"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" path="res://scripts/ammo_pickup.gd" id="1_pickup"]
|
||||||
|
[ext_resource type="Texture2D" uid="uid://ddmjl3yshqcjw" path="res://icon.svg" id="2_icon"]
|
||||||
|
|
||||||
|
[sub_resource type="RectangleShape2D" id="RectangleShape2D_pickup"]
|
||||||
|
size = Vector2(32, 32)
|
||||||
|
|
||||||
|
[node name="AmmoPickup" type="Area2D"]
|
||||||
|
script = ExtResource("1_pickup")
|
||||||
|
|
||||||
|
[node name="Sprite2D" type="Sprite2D" parent="."]
|
||||||
|
modulate = Color(0, 1, 0, 1)
|
||||||
|
scale = Vector2(0.25, 0.25)
|
||||||
|
texture = ExtResource("2_icon")
|
||||||
|
|
||||||
|
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
|
||||||
|
shape = SubResource("RectangleShape2D_pickup")
|
||||||
17
scenes/bullet.tscn
Normal file
17
scenes/bullet.tscn
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
[gd_scene load_steps=4 format=3 uid="uid://b6x4y208a1b2c"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" path="res://scripts/bullet.gd" id="1_bullet"]
|
||||||
|
[ext_resource type="Texture2D" uid="uid://ddmjl3yshqcjw" path="res://icon.svg" id="2_icon"]
|
||||||
|
|
||||||
|
[sub_resource type="RectangleShape2D" id="RectangleShape2D_1"]
|
||||||
|
size = Vector2(16, 16)
|
||||||
|
|
||||||
|
[node name="Bullet" type="Area2D"]
|
||||||
|
script = ExtResource("1_bullet")
|
||||||
|
|
||||||
|
[node name="Sprite2D" type="Sprite2D" parent="."]
|
||||||
|
scale = Vector2(0.2, 0.2)
|
||||||
|
texture = ExtResource("2_icon")
|
||||||
|
|
||||||
|
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
|
||||||
|
shape = SubResource("RectangleShape2D_1")
|
||||||
20
scenes/bullet_ap.tscn
Normal file
20
scenes/bullet_ap.tscn
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
[gd_scene load_steps=4 format=3 uid="uid://bulletap12345"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" path="res://scripts/bullet.gd" id="1_bullet"]
|
||||||
|
[ext_resource type="Texture2D" uid="uid://ddmjl3yshqcjw" path="res://icon.svg" id="2_icon"]
|
||||||
|
|
||||||
|
[sub_resource type="RectangleShape2D" id="RectangleShape2D_1"]
|
||||||
|
size = Vector2(16, 16)
|
||||||
|
|
||||||
|
[node name="BulletAP" type="Area2D"]
|
||||||
|
script = ExtResource("1_bullet")
|
||||||
|
speed = 700.0
|
||||||
|
damage = 50.0
|
||||||
|
ammo_type = 0
|
||||||
|
|
||||||
|
[node name="Sprite2D" type="Sprite2D" parent="."]
|
||||||
|
scale = Vector2(0.2, 0.2)
|
||||||
|
texture = ExtResource("2_icon")
|
||||||
|
|
||||||
|
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
|
||||||
|
shape = SubResource("RectangleShape2D_1")
|
||||||
21
scenes/bullet_he.tscn
Normal file
21
scenes/bullet_he.tscn
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
[gd_scene load_steps=4 format=3 uid="uid://bullethe68aa0"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" path="res://scripts/bullet.gd" id="1_bullet"]
|
||||||
|
[ext_resource type="Texture2D" uid="uid://ddmjl3yshqcjw" path="res://icon.svg" id="2_icon"]
|
||||||
|
|
||||||
|
[sub_resource type="RectangleShape2D" id="RectangleShape2D_1"]
|
||||||
|
size = Vector2(20, 20)
|
||||||
|
|
||||||
|
[node name="BulletHE" type="Area2D"]
|
||||||
|
script = ExtResource("1_bullet")
|
||||||
|
speed = 400.0
|
||||||
|
damage = 20.0
|
||||||
|
ammo_type = 1
|
||||||
|
|
||||||
|
[node name="Sprite2D" type="Sprite2D" parent="."]
|
||||||
|
modulate = Color(1, 0, 0, 1)
|
||||||
|
scale = Vector2(0.25, 0.25)
|
||||||
|
texture = ExtResource("2_icon")
|
||||||
|
|
||||||
|
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
|
||||||
|
shape = SubResource("RectangleShape2D_1")
|
||||||
33
scenes/enemy.tscn
Normal file
33
scenes/enemy.tscn
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
[gd_scene load_steps=5 format=3 uid="uid://enemy1234567"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" path="res://scripts/enemy.gd" id="1_enemy"]
|
||||||
|
[ext_resource type="Texture2D" uid="uid://bxvveyvfp8gmq" path="res://assets/cat_tank_hull.png" id="2_hull"]
|
||||||
|
[ext_resource type="Texture2D" uid="uid://ddktwa3t2dnlv" path="res://assets/cat_tank_turret.png" id="3_turret"]
|
||||||
|
|
||||||
|
[sub_resource type="CircleShape2D" id="CircleShape2D_enemy"]
|
||||||
|
radius = 24.0
|
||||||
|
|
||||||
|
[node name="Enemy" type="CharacterBody2D"]
|
||||||
|
script = ExtResource("1_enemy")
|
||||||
|
|
||||||
|
[node name="Sprite2D" type="Sprite2D" parent="."]
|
||||||
|
modulate = Color(1, 0.5, 0.5, 1)
|
||||||
|
rotation = 1.5707964
|
||||||
|
texture = ExtResource("2_hull")
|
||||||
|
|
||||||
|
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
|
||||||
|
shape = SubResource("CircleShape2D_enemy")
|
||||||
|
|
||||||
|
[node name="Turret" type="Node2D" parent="."]
|
||||||
|
|
||||||
|
[node name="Sprite2D" type="Sprite2D" parent="Turret"]
|
||||||
|
modulate = Color(1, 0.5, 0.5, 1)
|
||||||
|
rotation = 1.5707964
|
||||||
|
texture = ExtResource("3_turret")
|
||||||
|
|
||||||
|
[node name="HealthBar" type="ProgressBar" parent="."]
|
||||||
|
offset_left = -24.0
|
||||||
|
offset_top = -40.0
|
||||||
|
offset_right = 24.0
|
||||||
|
offset_bottom = -34.0
|
||||||
|
show_percentage = false
|
||||||
98
scenes/hud.tscn
Normal file
98
scenes/hud.tscn
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
[gd_scene load_steps=2 format=3 uid="uid://hud12345678"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" path="res://scripts/hud.gd" id="1_hud"]
|
||||||
|
|
||||||
|
[node name="HUD" type="CanvasLayer"]
|
||||||
|
script = ExtResource("1_hud")
|
||||||
|
|
||||||
|
[node name="Control" type="Control" parent="."]
|
||||||
|
layout_mode = 3
|
||||||
|
anchors_preset = 15
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
mouse_filter = 2
|
||||||
|
|
||||||
|
[node name="HealthBar" type="ProgressBar" parent="Control"]
|
||||||
|
layout_mode = 0
|
||||||
|
offset_left = 20.0
|
||||||
|
offset_top = 20.0
|
||||||
|
offset_right = 220.0
|
||||||
|
offset_bottom = 50.0
|
||||||
|
value = 100.0
|
||||||
|
|
||||||
|
[node name="AmmoContainer" type="VBoxContainer" parent="Control"]
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 3
|
||||||
|
anchor_left = 1.0
|
||||||
|
anchor_top = 1.0
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
offset_left = -150.0
|
||||||
|
offset_top = -80.0
|
||||||
|
offset_right = -20.0
|
||||||
|
offset_bottom = -20.0
|
||||||
|
grow_horizontal = 0
|
||||||
|
grow_vertical = 0
|
||||||
|
|
||||||
|
[node name="APLabel" type="Label" parent="Control/AmmoContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
text = "AP: 20"
|
||||||
|
horizontal_alignment = 2
|
||||||
|
|
||||||
|
[node name="HELabel" type="Label" parent="Control/AmmoContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
text = "HE: 10"
|
||||||
|
horizontal_alignment = 2
|
||||||
|
|
||||||
|
[node name="GameOverScreen" type="Control" parent="."]
|
||||||
|
visible = false
|
||||||
|
layout_mode = 3
|
||||||
|
anchors_preset = 15
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
|
||||||
|
[node name="ColorRect" type="ColorRect" parent="GameOverScreen"]
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 15
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
color = Color(0, 0, 0, 0.5)
|
||||||
|
|
||||||
|
[node name="Label" type="Label" parent="GameOverScreen"]
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 8
|
||||||
|
anchor_left = 0.5
|
||||||
|
anchor_top = 0.5
|
||||||
|
anchor_right = 0.5
|
||||||
|
anchor_bottom = 0.5
|
||||||
|
offset_left = -46.0
|
||||||
|
offset_top = -13.0
|
||||||
|
offset_right = 46.0
|
||||||
|
offset_bottom = 13.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
theme_override_font_sizes/font_size = 32
|
||||||
|
text = "GAME OVER"
|
||||||
|
|
||||||
|
[node name="RestartButton" type="Button" parent="GameOverScreen"]
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 8
|
||||||
|
anchor_left = 0.5
|
||||||
|
anchor_top = 0.5
|
||||||
|
anchor_right = 0.5
|
||||||
|
anchor_bottom = 0.5
|
||||||
|
offset_left = -48.0
|
||||||
|
offset_top = 40.0
|
||||||
|
offset_right = 48.0
|
||||||
|
offset_bottom = 71.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
text = "Restart"
|
||||||
|
|
||||||
|
[connection signal="pressed" from="GameOverScreen/RestartButton" to="." method="_on_restart_button_pressed"]
|
||||||
28
scenes/level_0.tscn
Normal file
28
scenes/level_0.tscn
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
[gd_scene load_steps=6 format=3 uid="uid://cfwyr25ftoqpk"]
|
||||||
|
|
||||||
|
[ext_resource type="PackedScene" uid="uid://cywexaqp3mvxh" path="res://scenes/player.tscn" id="1_7wnc2"]
|
||||||
|
[ext_resource type="Script" uid="uid://m3ii2yiagrn1" path="res://scripts/level_0.gd" id="1_level"]
|
||||||
|
[ext_resource type="Script" uid="uid://bgbuwhxk7uqah" path="res://scripts/spawner.gd" id="2_spawner"]
|
||||||
|
[ext_resource type="PackedScene" uid="uid://enemy1234567" path="res://scenes/enemy.tscn" id="3_enemy"]
|
||||||
|
[ext_resource type="PackedScene" path="res://scenes/hud.tscn" id="4_hud"]
|
||||||
|
[ext_resource type="Script" path="res://scripts/camera_zoom.gd" id="5_camera"]
|
||||||
|
[ext_resource type="Script" path="res://scripts/ammo_spawner.gd" id="6_ammo_spawner"]
|
||||||
|
|
||||||
|
[node name="Level0" type="Node2D"]
|
||||||
|
script = ExtResource("1_level")
|
||||||
|
|
||||||
|
[node name="player" parent="." instance=ExtResource("1_7wnc2")]
|
||||||
|
position = Vector2(234, 192)
|
||||||
|
|
||||||
|
[node name="Camera2D" type="Camera2D" parent="player"]
|
||||||
|
zoom = Vector2(3, 3)
|
||||||
|
script = ExtResource("5_camera")
|
||||||
|
|
||||||
|
[node name="Spawner" type="Node" parent="."]
|
||||||
|
script = ExtResource("2_spawner")
|
||||||
|
enemy_scene = ExtResource("3_enemy")
|
||||||
|
|
||||||
|
[node name="AmmoSpawner" type="Node" parent="."]
|
||||||
|
script = ExtResource("6_ammo_spawner")
|
||||||
|
|
||||||
|
[node name="HUD" parent="." instance=ExtResource("4_hud")]
|
||||||
26
scenes/player.tscn
Normal file
26
scenes/player.tscn
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
[gd_scene load_steps=6 format=3 uid="uid://cywexaqp3mvxh"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://b1bepj67ddf6c" path="res://scripts/player.gd" id="1_g2els"]
|
||||||
|
[ext_resource type="Texture2D" uid="uid://bxvveyvfp8gmq" path="res://assets/cat_tank_hull.png" id="2_dqkch"]
|
||||||
|
[ext_resource type="Script" uid="uid://8jk475ak64ud" path="res://scripts/turret.gd" id="3_qhqgy"]
|
||||||
|
[ext_resource type="Texture2D" uid="uid://ddktwa3t2dnlv" path="res://assets/cat_tank_turret.png" id="4_qlg0r"]
|
||||||
|
|
||||||
|
[sub_resource type="CircleShape2D" id="CircleShape2D_tuyoq"]
|
||||||
|
radius = 24.0
|
||||||
|
|
||||||
|
[node name="tank" type="CharacterBody2D"]
|
||||||
|
script = ExtResource("1_g2els")
|
||||||
|
|
||||||
|
[node name="Sprite2D" type="Sprite2D" parent="."]
|
||||||
|
rotation = 1.5707964
|
||||||
|
texture = ExtResource("2_dqkch")
|
||||||
|
|
||||||
|
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
|
||||||
|
shape = SubResource("CircleShape2D_tuyoq")
|
||||||
|
|
||||||
|
[node name="turret" type="Node2D" parent="."]
|
||||||
|
script = ExtResource("3_qhqgy")
|
||||||
|
|
||||||
|
[node name="Sprite2D" type="Sprite2D" parent="turret"]
|
||||||
|
rotation = 1.5707964
|
||||||
|
texture = ExtResource("4_qlg0r")
|
||||||
14
scripts/ammo_pickup.gd
Normal file
14
scripts/ammo_pickup.gd
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
extends Area2D
|
||||||
|
|
||||||
|
@export_enum("AP", "HE") var ammo_type: int = 0
|
||||||
|
@export var amount: int = 10
|
||||||
|
|
||||||
|
func _ready():
|
||||||
|
body_entered.connect(_on_body_entered)
|
||||||
|
|
||||||
|
func _on_body_entered(body):
|
||||||
|
if body.is_in_group("player"):
|
||||||
|
var turret = body.get_node_or_null("turret")
|
||||||
|
if turret and turret.has_method("add_ammo"):
|
||||||
|
turret.add_ammo(ammo_type, amount)
|
||||||
|
queue_free()
|
||||||
1
scripts/ammo_pickup.gd.uid
Normal file
1
scripts/ammo_pickup.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://6gehiohye62a
|
||||||
34
scripts/ammo_spawner.gd
Normal file
34
scripts/ammo_spawner.gd
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
extends Node
|
||||||
|
|
||||||
|
@export var ammo_scene: PackedScene = preload("res://scenes/ammo_pickup.tscn")
|
||||||
|
@export var spawn_interval_min: float = 5.0
|
||||||
|
@export var spawn_interval_max: float = 15.0
|
||||||
|
@export var spawn_radius: float = 300.0
|
||||||
|
|
||||||
|
func _ready():
|
||||||
|
spawn_loop()
|
||||||
|
|
||||||
|
func spawn_loop():
|
||||||
|
var wait_time = randf_range(spawn_interval_min, spawn_interval_max)
|
||||||
|
await get_tree().create_timer(wait_time).timeout
|
||||||
|
spawn_ammo()
|
||||||
|
spawn_loop()
|
||||||
|
|
||||||
|
func spawn_ammo():
|
||||||
|
var player = get_tree().get_first_node_in_group("player")
|
||||||
|
if not player:
|
||||||
|
return
|
||||||
|
|
||||||
|
var pickup = ammo_scene.instantiate()
|
||||||
|
|
||||||
|
# Randomize type
|
||||||
|
pickup.ammo_type = randi() % 2 # 0 or 1
|
||||||
|
pickup.amount = 10 if pickup.ammo_type == 0 else 5 # More AP than HE
|
||||||
|
|
||||||
|
# Random position around player
|
||||||
|
var angle = randf() * TAU
|
||||||
|
var distance = randf_range(100.0, spawn_radius)
|
||||||
|
var pos = player.global_position + Vector2.RIGHT.rotated(angle) * distance
|
||||||
|
|
||||||
|
pickup.global_position = pos
|
||||||
|
get_parent().add_child(pickup)
|
||||||
1
scripts/ammo_spawner.gd.uid
Normal file
1
scripts/ammo_spawner.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://pdbp514t20bf
|
||||||
44
scripts/bullet.gd
Normal file
44
scripts/bullet.gd
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
extends Area2D
|
||||||
|
|
||||||
|
@export var speed: float = 500.0
|
||||||
|
@export var lifetime: float = 2.0
|
||||||
|
@export var damage: float = 10.0
|
||||||
|
@export_enum("AP", "HE") var ammo_type: int = 0
|
||||||
|
@export var explosion_radius: float = 100.0
|
||||||
|
var shooter_group: String = "player"
|
||||||
|
|
||||||
|
func _ready():
|
||||||
|
# Connect collision signal
|
||||||
|
body_entered.connect(_on_body_entered)
|
||||||
|
|
||||||
|
# Delete bullet after lifetime seconds
|
||||||
|
await get_tree().create_timer(lifetime).timeout
|
||||||
|
queue_free()
|
||||||
|
|
||||||
|
func _physics_process(delta):
|
||||||
|
position += Vector2.RIGHT.rotated(rotation) * speed * delta
|
||||||
|
|
||||||
|
func _on_body_entered(body):
|
||||||
|
if body.is_in_group(shooter_group):
|
||||||
|
return
|
||||||
|
|
||||||
|
if ammo_type == 0: # AP
|
||||||
|
if body.has_method("take_damage"):
|
||||||
|
body.take_damage(damage)
|
||||||
|
elif ammo_type == 1: # HE
|
||||||
|
explode()
|
||||||
|
|
||||||
|
queue_free()
|
||||||
|
|
||||||
|
func explode():
|
||||||
|
# Visual effect could go here
|
||||||
|
# Find all potential targets
|
||||||
|
# If shooter is player, target enemies. If shooter is enemy, target player.
|
||||||
|
var target_group = "enemy" if shooter_group == "player" else "player"
|
||||||
|
var targets = get_tree().get_nodes_in_group(target_group)
|
||||||
|
|
||||||
|
for target in targets:
|
||||||
|
var distance = global_position.distance_to(target.global_position)
|
||||||
|
if distance <= explosion_radius:
|
||||||
|
if target.has_method("take_damage"):
|
||||||
|
target.take_damage(damage)
|
||||||
1
scripts/bullet.gd.uid
Normal file
1
scripts/bullet.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://c362pdnaor5td
|
||||||
24
scripts/camera_zoom.gd
Normal file
24
scripts/camera_zoom.gd
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
extends Camera2D
|
||||||
|
|
||||||
|
@export var zoom_speed: float = 0.5
|
||||||
|
@export var min_zoom: float = 1.0
|
||||||
|
@export var max_zoom: float = 5.0
|
||||||
|
@export var zoom_smoothing: float = 10.0
|
||||||
|
|
||||||
|
var target_zoom: Vector2
|
||||||
|
|
||||||
|
func _ready():
|
||||||
|
target_zoom = zoom
|
||||||
|
|
||||||
|
func _process(delta):
|
||||||
|
zoom = zoom.lerp(target_zoom, zoom_smoothing * delta)
|
||||||
|
|
||||||
|
func _unhandled_input(event):
|
||||||
|
if event is InputEventMouseButton:
|
||||||
|
if event.is_pressed():
|
||||||
|
if event.button_index == MOUSE_BUTTON_WHEEL_UP:
|
||||||
|
target_zoom += Vector2(zoom_speed, zoom_speed)
|
||||||
|
elif event.button_index == MOUSE_BUTTON_WHEEL_DOWN:
|
||||||
|
target_zoom -= Vector2(zoom_speed, zoom_speed)
|
||||||
|
|
||||||
|
target_zoom = target_zoom.clamp(Vector2(min_zoom, min_zoom), Vector2(max_zoom, max_zoom))
|
||||||
1
scripts/camera_zoom.gd.uid
Normal file
1
scripts/camera_zoom.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://cm8prlxndx0kk
|
||||||
65
scripts/enemy.gd
Normal file
65
scripts/enemy.gd
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
extends CharacterBody2D
|
||||||
|
|
||||||
|
@export var speed: float = 100.0
|
||||||
|
@export var max_health: float = 100.0
|
||||||
|
var current_health: float
|
||||||
|
|
||||||
|
var player: Node2D
|
||||||
|
@onready var health_bar = $HealthBar
|
||||||
|
@onready var turret = $Turret
|
||||||
|
|
||||||
|
@export var bullet_scene: PackedScene = preload("res://scenes/bullet.tscn")
|
||||||
|
@export var fire_rate: float = 2.0
|
||||||
|
var can_shoot: bool = true
|
||||||
|
|
||||||
|
func _ready():
|
||||||
|
add_to_group("enemy")
|
||||||
|
current_health = max_health
|
||||||
|
if health_bar:
|
||||||
|
health_bar.max_value = max_health
|
||||||
|
health_bar.value = current_health
|
||||||
|
health_bar.hide() # Hide initially, show on damage
|
||||||
|
|
||||||
|
# Find the player in the scene tree
|
||||||
|
player = get_tree().get_first_node_in_group("player")
|
||||||
|
if not player:
|
||||||
|
# Fallback: try to find by name if group not set
|
||||||
|
player = get_parent().get_node_or_null("player")
|
||||||
|
|
||||||
|
func _physics_process(_delta):
|
||||||
|
if player:
|
||||||
|
var direction = (player.global_position - global_position).normalized()
|
||||||
|
velocity = direction * speed
|
||||||
|
rotation = direction.angle()
|
||||||
|
move_and_slide()
|
||||||
|
|
||||||
|
# Aim turret at player
|
||||||
|
if turret:
|
||||||
|
turret.look_at(player.global_position)
|
||||||
|
|
||||||
|
# Shoot if close enough
|
||||||
|
if global_position.distance_to(player.global_position) < 400.0 and can_shoot:
|
||||||
|
shoot()
|
||||||
|
|
||||||
|
func shoot():
|
||||||
|
var bullet = bullet_scene.instantiate()
|
||||||
|
bullet.shooter_group = "enemy"
|
||||||
|
get_tree().root.add_child(bullet)
|
||||||
|
bullet.global_position = turret.global_position
|
||||||
|
bullet.global_rotation = turret.global_rotation
|
||||||
|
|
||||||
|
can_shoot = false
|
||||||
|
await get_tree().create_timer(fire_rate).timeout
|
||||||
|
can_shoot = true
|
||||||
|
|
||||||
|
func take_damage(amount: float):
|
||||||
|
current_health -= amount
|
||||||
|
if health_bar:
|
||||||
|
health_bar.show()
|
||||||
|
health_bar.value = current_health
|
||||||
|
|
||||||
|
if current_health <= 0:
|
||||||
|
die()
|
||||||
|
|
||||||
|
func die():
|
||||||
|
queue_free()
|
||||||
1
scripts/enemy.gd.uid
Normal file
1
scripts/enemy.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://b48lm617ynd2n
|
||||||
22
scripts/hud.gd
Normal file
22
scripts/hud.gd
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
extends CanvasLayer
|
||||||
|
|
||||||
|
@onready var health_bar = $Control/HealthBar
|
||||||
|
@onready var game_over_screen = $GameOverScreen
|
||||||
|
@onready var ap_label = $Control/AmmoContainer/APLabel
|
||||||
|
@onready var he_label = $Control/AmmoContainer/HELabel
|
||||||
|
|
||||||
|
func update_health(current, max_val):
|
||||||
|
health_bar.max_value = max_val
|
||||||
|
health_bar.value = current
|
||||||
|
|
||||||
|
func update_ammo(ap, he):
|
||||||
|
ap_label.text = "AP: " + str(ap)
|
||||||
|
he_label.text = "HE: " + str(he)
|
||||||
|
|
||||||
|
func show_game_over():
|
||||||
|
game_over_screen.show()
|
||||||
|
get_tree().paused = true
|
||||||
|
|
||||||
|
func _on_restart_button_pressed():
|
||||||
|
get_tree().paused = false
|
||||||
|
get_tree().reload_current_scene()
|
||||||
1
scripts/hud.gd.uid
Normal file
1
scripts/hud.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://cqp2fhlqjmigi
|
||||||
13
scripts/level_0.gd
Normal file
13
scripts/level_0.gd
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
extends Node2D
|
||||||
|
|
||||||
|
@onready var player = $player
|
||||||
|
@onready var hud = $HUD
|
||||||
|
|
||||||
|
func _ready():
|
||||||
|
if player:
|
||||||
|
player.health_changed.connect(hud.update_health)
|
||||||
|
player.died.connect(hud.show_game_over)
|
||||||
|
|
||||||
|
var turret = player.get_node("turret")
|
||||||
|
if turret:
|
||||||
|
turret.ammo_changed.connect(hud.update_ammo)
|
||||||
1
scripts/level_0.gd.uid
Normal file
1
scripts/level_0.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://m3ii2yiagrn1
|
||||||
47
scripts/player.gd
Normal file
47
scripts/player.gd
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
extends CharacterBody2D
|
||||||
|
|
||||||
|
|
||||||
|
@export var max_speed: float = 150.0
|
||||||
|
@export var acceleration: float = 250.0
|
||||||
|
@export var deceleration: float = 120.0
|
||||||
|
@export var rotation_speed: float = 2.5
|
||||||
|
@export var max_health: float = 100.0
|
||||||
|
|
||||||
|
signal health_changed(current, max)
|
||||||
|
signal died
|
||||||
|
|
||||||
|
var current_health: float
|
||||||
|
|
||||||
|
func _ready():
|
||||||
|
add_to_group("player")
|
||||||
|
current_health = max_health
|
||||||
|
health_changed.emit(current_health, max_health)
|
||||||
|
|
||||||
|
func take_damage(amount: float):
|
||||||
|
current_health -= amount
|
||||||
|
health_changed.emit(current_health, max_health)
|
||||||
|
|
||||||
|
if current_health <= 0:
|
||||||
|
die()
|
||||||
|
|
||||||
|
func die():
|
||||||
|
died.emit()
|
||||||
|
|
||||||
|
func _physics_process(delta):
|
||||||
|
#rotate
|
||||||
|
var turn_input = Input.get_action_strength("kb_d") - Input.get_action_strength("kb_a")
|
||||||
|
rotation += turn_input * rotation_speed * delta
|
||||||
|
|
||||||
|
#move
|
||||||
|
var move_input = Input.get_action_strength("kb_w") - Input.get_action_strength("kb_s")
|
||||||
|
|
||||||
|
#current hull direction
|
||||||
|
var forward_dir = Vector2.RIGHT.rotated(rotation)
|
||||||
|
|
||||||
|
#calc velocity
|
||||||
|
var forward_speed = velocity.dot(forward_dir)
|
||||||
|
var target_speed = move_input * max_speed
|
||||||
|
forward_speed = move_toward(forward_speed, target_speed, (acceleration if move_input != 0 else deceleration) * delta)
|
||||||
|
velocity = forward_dir * forward_speed
|
||||||
|
|
||||||
|
move_and_slide()
|
||||||
1
scripts/player.gd.uid
Normal file
1
scripts/player.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://b1bepj67ddf6c
|
||||||
36
scripts/spawner.gd
Normal file
36
scripts/spawner.gd
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
extends Node
|
||||||
|
|
||||||
|
@export var enemy_scene: PackedScene
|
||||||
|
@export var min_spawn_time: float = 1.0
|
||||||
|
@export var max_spawn_time: float = 7.0
|
||||||
|
|
||||||
|
func _ready():
|
||||||
|
start_spawn_timer()
|
||||||
|
|
||||||
|
func start_spawn_timer():
|
||||||
|
var time = randf_range(min_spawn_time, max_spawn_time)
|
||||||
|
await get_tree().create_timer(time).timeout
|
||||||
|
spawn_enemy()
|
||||||
|
start_spawn_timer()
|
||||||
|
|
||||||
|
func spawn_enemy():
|
||||||
|
if not enemy_scene:
|
||||||
|
return
|
||||||
|
|
||||||
|
var enemy = enemy_scene.instantiate()
|
||||||
|
get_parent().add_child(enemy)
|
||||||
|
|
||||||
|
# Calculate random position outside the screen
|
||||||
|
var viewport_rect = get_viewport().get_visible_rect()
|
||||||
|
var camera = get_viewport().get_camera_2d()
|
||||||
|
var center = Vector2.ZERO
|
||||||
|
if camera:
|
||||||
|
center = camera.get_screen_center_position()
|
||||||
|
# Adjust rect size for zoom
|
||||||
|
viewport_rect.size /= camera.zoom
|
||||||
|
|
||||||
|
# Pick a random angle and a distance slightly larger than half the diagonal
|
||||||
|
var angle = randf() * TAU
|
||||||
|
var distance = viewport_rect.size.length() / 2.0 + 100.0 # +100 buffer
|
||||||
|
|
||||||
|
enemy.global_position = center + Vector2.RIGHT.rotated(angle) * distance
|
||||||
1
scripts/spawner.gd.uid
Normal file
1
scripts/spawner.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://bgbuwhxk7uqah
|
||||||
74
scripts/turret.gd
Normal file
74
scripts/turret.gd
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
extends Node2D
|
||||||
|
|
||||||
|
@export var rotation_speed: float = 3.0
|
||||||
|
@export var bullet_ap_scene: PackedScene = preload("res://scenes/bullet_ap.tscn")
|
||||||
|
@export var bullet_he_scene: PackedScene = preload("res://scenes/bullet_he.tscn")
|
||||||
|
@export var fire_rate: float = 0.5
|
||||||
|
|
||||||
|
@export var max_ammo_ap: int = 20
|
||||||
|
@export var max_ammo_he: int = 10
|
||||||
|
var ammo_ap: int
|
||||||
|
var ammo_he: int
|
||||||
|
|
||||||
|
signal ammo_changed(ap, he)
|
||||||
|
|
||||||
|
enum AmmoType {AP, HE}
|
||||||
|
var current_ammo_type: AmmoType = AmmoType.AP
|
||||||
|
|
||||||
|
var can_shoot: bool = true
|
||||||
|
|
||||||
|
func _ready():
|
||||||
|
ammo_ap = max_ammo_ap
|
||||||
|
ammo_he = max_ammo_he
|
||||||
|
# Defer emit to ensure connections are ready
|
||||||
|
call_deferred("emit_ammo_signal")
|
||||||
|
|
||||||
|
func emit_ammo_signal():
|
||||||
|
ammo_changed.emit(ammo_ap, ammo_he)
|
||||||
|
|
||||||
|
func _process(delta):
|
||||||
|
var mouse_pos = get_global_mouse_position()
|
||||||
|
var target_angle = (mouse_pos - global_position).angle()
|
||||||
|
|
||||||
|
# Sanftes Nachdrehen
|
||||||
|
var angle_diff = wrapf(target_angle - global_rotation, -PI, PI)
|
||||||
|
global_rotation += clamp(angle_diff, -rotation_speed * delta, rotation_speed * delta)
|
||||||
|
|
||||||
|
if Input.is_key_pressed(KEY_1):
|
||||||
|
current_ammo_type = AmmoType.AP
|
||||||
|
if Input.is_key_pressed(KEY_2):
|
||||||
|
current_ammo_type = AmmoType.HE
|
||||||
|
|
||||||
|
if Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT) and can_shoot:
|
||||||
|
shoot()
|
||||||
|
|
||||||
|
func shoot():
|
||||||
|
if current_ammo_type == AmmoType.AP:
|
||||||
|
if ammo_ap > 0:
|
||||||
|
ammo_ap -= 1
|
||||||
|
else:
|
||||||
|
return # Out of ammo
|
||||||
|
elif current_ammo_type == AmmoType.HE:
|
||||||
|
if ammo_he > 0:
|
||||||
|
ammo_he -= 1
|
||||||
|
else:
|
||||||
|
return # Out of ammo
|
||||||
|
|
||||||
|
ammo_changed.emit(ammo_ap, ammo_he)
|
||||||
|
|
||||||
|
var bullet_scene = bullet_ap_scene if current_ammo_type == AmmoType.AP else bullet_he_scene
|
||||||
|
var bullet = bullet_scene.instantiate()
|
||||||
|
get_tree().root.add_child(bullet)
|
||||||
|
bullet.global_position = global_position
|
||||||
|
bullet.global_rotation = global_rotation
|
||||||
|
|
||||||
|
can_shoot = false
|
||||||
|
await get_tree().create_timer(fire_rate).timeout
|
||||||
|
can_shoot = true
|
||||||
|
|
||||||
|
func add_ammo(type_index: int, amount: int):
|
||||||
|
if type_index == 0: # AP
|
||||||
|
ammo_ap += amount
|
||||||
|
elif type_index == 1: # HE
|
||||||
|
ammo_he += amount
|
||||||
|
ammo_changed.emit(ammo_ap, ammo_he)
|
||||||
1
scripts/turret.gd.uid
Normal file
1
scripts/turret.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://8jk475ak64ud
|
||||||
Reference in New Issue
Block a user