diff --git a/addons/godot-git-plugin/win64/~libgit_plugin.windows.editor.x86_64.dll b/addons/godot-git-plugin/win64/~libgit_plugin.windows.editor.x86_64.dll new file mode 100644 index 0000000..47bbb1d Binary files /dev/null and b/addons/godot-git-plugin/win64/~libgit_plugin.windows.editor.x86_64.dll differ diff --git a/assets/sprites/ui/ui_icons_blue_down4.png b/assets/sprites/ui/ui_icons_blue_down4.png new file mode 100644 index 0000000..c9e7e1c Binary files /dev/null and b/assets/sprites/ui/ui_icons_blue_down4.png differ diff --git a/assets/sprites/ui/ui_icons_blue_down4.png.import b/assets/sprites/ui/ui_icons_blue_down4.png.import new file mode 100644 index 0000000..ff57188 --- /dev/null +++ b/assets/sprites/ui/ui_icons_blue_down4.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dodxrvydq6fha" +path="res://.godot/imported/ui_icons_blue_down4.png-e76857af9f0775a76b1aec4c9ba310f4.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/sprites/ui/ui_icons_blue_down4.png" +dest_files=["res://.godot/imported/ui_icons_blue_down4.png-e76857af9f0775a76b1aec4c9ba310f4.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +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/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 diff --git a/assets/sprites/ui/ui_icons_green_down4.png b/assets/sprites/ui/ui_icons_green_down4.png new file mode 100644 index 0000000..51eccc2 Binary files /dev/null and b/assets/sprites/ui/ui_icons_green_down4.png differ diff --git a/assets/sprites/ui/ui_icons_green_down4.png.import b/assets/sprites/ui/ui_icons_green_down4.png.import new file mode 100644 index 0000000..3aa1230 --- /dev/null +++ b/assets/sprites/ui/ui_icons_green_down4.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://m5quwcs7xg70" +path="res://.godot/imported/ui_icons_green_down4.png-a9d4d3bbe5c92c27f99f5653a324edc1.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/sprites/ui/ui_icons_green_down4.png" +dest_files=["res://.godot/imported/ui_icons_green_down4.png-a9d4d3bbe5c92c27f99f5653a324edc1.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +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/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 diff --git a/assets/sprites/ui/ui_icons_pink_down4.png b/assets/sprites/ui/ui_icons_pink_down4.png new file mode 100644 index 0000000..4ee9e09 Binary files /dev/null and b/assets/sprites/ui/ui_icons_pink_down4.png differ diff --git a/assets/sprites/ui/ui_icons_pink_down4.png.import b/assets/sprites/ui/ui_icons_pink_down4.png.import new file mode 100644 index 0000000..d7e45a0 --- /dev/null +++ b/assets/sprites/ui/ui_icons_pink_down4.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dvyayp3ndlnun" +path="res://.godot/imported/ui_icons_pink_down4.png-7ec59997376ec15e63c5d7df7180e71c.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/sprites/ui/ui_icons_pink_down4.png" +dest_files=["res://.godot/imported/ui_icons_pink_down4.png-7ec59997376ec15e63c5d7df7180e71c.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +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/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 diff --git a/assets/sprites/ui/ui_icons_red_down4.png b/assets/sprites/ui/ui_icons_red_down4.png new file mode 100644 index 0000000..72654b7 Binary files /dev/null and b/assets/sprites/ui/ui_icons_red_down4.png differ diff --git a/assets/sprites/ui/ui_icons_red_down4.png.import b/assets/sprites/ui/ui_icons_red_down4.png.import new file mode 100644 index 0000000..5c7aa4b --- /dev/null +++ b/assets/sprites/ui/ui_icons_red_down4.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://mgbhev7rsjr7" +path="res://.godot/imported/ui_icons_red_down4.png-91b331abca07894909691d67a64bb00e.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/sprites/ui/ui_icons_red_down4.png" +dest_files=["res://.godot/imported/ui_icons_red_down4.png-91b331abca07894909691d67a64bb00e.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +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/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 diff --git a/assets/sprites/ui/ui_icons_rgb_down4.png b/assets/sprites/ui/ui_icons_rgb_down4.png new file mode 100644 index 0000000..b0cd442 Binary files /dev/null and b/assets/sprites/ui/ui_icons_rgb_down4.png differ diff --git a/assets/sprites/ui/ui_icons_rgb_down4.png.import b/assets/sprites/ui/ui_icons_rgb_down4.png.import new file mode 100644 index 0000000..6ee19d0 --- /dev/null +++ b/assets/sprites/ui/ui_icons_rgb_down4.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://vjb3lohfxdje" +path="res://.godot/imported/ui_icons_rgb_down4.png-085e05397cee56389f7a7d3fb9214d1e.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/sprites/ui/ui_icons_rgb_down4.png" +dest_files=["res://.godot/imported/ui_icons_rgb_down4.png-085e05397cee56389f7a7d3fb9214d1e.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +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/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 diff --git a/debug_size_sprites.tscn b/debug_size_sprites.tscn new file mode 100644 index 0000000..f5edf72 --- /dev/null +++ b/debug_size_sprites.tscn @@ -0,0 +1,12 @@ +[gd_scene load_steps=3 format=3 uid="uid://cfo1w6okjjqdx"] + +[ext_resource type="PackedScene" uid="uid://d1jhpluu86cbd" path="res://scenes/player.tscn" id="1_c73ov"] +[ext_resource type="Texture2D" uid="uid://dodxrvydq6fha" path="res://assets/sprites/ui/ui_icons_blue_down4.png" id="2_m0f23"] + +[node name="Node2D" type="Node2D"] + +[node name="Player" parent="." instance=ExtResource("1_c73ov")] + +[node name="Sprite2D" type="Sprite2D" parent="."] +position = Vector2(0, -17) +texture = ExtResource("2_m0f23") diff --git a/project.godot b/project.godot index 9857c08..7928c4b 100644 --- a/project.godot +++ b/project.godot @@ -15,6 +15,10 @@ run/main_scene="uid://gl6lc08v514x" config/features=PackedStringArray("4.4", "Forward Plus") config/icon="res://icon.svg" +[autoload] + +IsometricMapSystem="*res://scripts/isometric_map_system.gd" + [editor] version_control/plugin_name="GitPlugin" diff --git a/scenes/isometric_map_layer_holder.tscn12214503970.tmp b/scenes/isometric_map_layer_holder.tscn12214503970.tmp new file mode 100644 index 0000000..544aeeb --- /dev/null +++ b/scenes/isometric_map_layer_holder.tscn12214503970.tmp @@ -0,0 +1,146 @@ +[gd_scene load_steps=7 format=3 uid="uid://dg0qxdwe2rlcn"] + +[ext_resource type="Script" uid="uid://dxcfy8xypdde6" path="res://scripts/isometric_map_layer_holder.gd" id="1_4o54u"] +[ext_resource type="Texture2D" uid="uid://p8iyle6kr3nf" path="res://assets/sprites/tiles/iso_tileset.png" id="1_fme3d"] +[ext_resource type="Texture2D" uid="uid://bsox4y2fftlh8" path="res://assets/sprites/tiles/iso_tileset_with_select.png" id="3_s16iq"] + +[sub_resource type="TileSetAtlasSource" id="TileSetAtlasSource_4o54u"] +texture = ExtResource("1_fme3d") +texture_region_size = Vector2i(32, 32) +0:0/0 = 0 +0:0/0/texture_origin = Vector2i(0, -8) +1:0/0 = 0 +1:0/0/texture_origin = Vector2i(0, -8) +2:0/0 = 0 +2:0/0/texture_origin = Vector2i(0, -8) +3:0/0 = 0 +3:0/0/texture_origin = Vector2i(0, -8) +4:0/0 = 0 +4:0/0/texture_origin = Vector2i(0, -8) +5:0/0 = 0 +5:0/0/texture_origin = Vector2i(0, -8) +6:0/0 = 0 +6:0/0/texture_origin = Vector2i(0, -8) + +[sub_resource type="TileSetAtlasSource" id="TileSetAtlasSource_wvhlo"] +texture = ExtResource("3_s16iq") +texture_region_size = Vector2i(32, 32) +0:0/0 = 0 +0:0/0/texture_origin = Vector2i(0, -8) +1:0/0 = 0 +1:0/0/texture_origin = Vector2i(0, -8) +2:0/0 = 0 +2:0/0/texture_origin = Vector2i(0, -8) +3:0/0 = 0 +3:0/0/texture_origin = Vector2i(0, -8) +4:0/0 = 0 +4:0/0/texture_origin = Vector2i(0, -8) +5:0/0 = 0 +5:0/0/texture_origin = Vector2i(0, -8) +6:0/0 = 0 +6:0/0/texture_origin = Vector2i(0, -8) +7:0/0 = 0 +7:0/0/texture_origin = Vector2i(0, -8) +0:1/0 = 0 +0:1/0/texture_origin = Vector2i(0, -8) +1:1/0 = 0 +1:1/0/texture_origin = Vector2i(0, -8) +2:1/0 = 0 +2:1/0/texture_origin = Vector2i(0, -8) +3:1/0 = 0 +3:1/0/texture_origin = Vector2i(0, -8) +4:1/0 = 0 +4:1/0/texture_origin = Vector2i(0, -8) +5:1/0 = 0 +5:1/0/texture_origin = Vector2i(0, -8) +6:1/0 = 0 +6:1/0/texture_origin = Vector2i(0, -8) + +[sub_resource type="TileSet" id="TileSet_s16iq"] +tile_shape = 1 +tile_layout = 5 +tile_offset_axis = 1 +tile_size = Vector2i(32, 16) +sources/0 = SubResource("TileSetAtlasSource_4o54u") +sources/1 = SubResource("TileSetAtlasSource_wvhlo") + +[node name="IsometricMapLayerHolder" type="Node2D"] +script = ExtResource("1_4o54u") + +[node name="Camera2D" type="Camera2D" parent="."] +zoom = Vector2(0.5, 0.5) + +[node name="TileMapLayer" type="TileMapLayer" parent="."] +tile_set = SubResource("TileSet_s16iq") + +[node name="CanvasLayer" type="CanvasLayer" parent="."] + +[node name="ResetButton" type="Button" parent="CanvasLayer"] +anchors_preset = 7 +anchor_left = 0.5 +anchor_top = 1.0 +anchor_right = 0.5 +anchor_bottom = 1.0 +offset_left = -25.5 +offset_top = -31.0 +offset_right = 25.5 +grow_horizontal = 2 +grow_vertical = 0 +size_flags_horizontal = 4 +size_flags_vertical = 4 +text = "Reset" + +[node name="RotationVBoxContainer" type="VBoxContainer" parent="CanvasLayer"] +offset_right = 40.0 +offset_bottom = 40.0 + +[node name="Z_CW" type="Button" parent="CanvasLayer/RotationVBoxContainer"] +layout_mode = 2 +text = "Rotate CW Z-Axis" + +[node name="Z_CCW" type="Button" parent="CanvasLayer/RotationVBoxContainer"] +layout_mode = 2 +text = "Rotate CCW Z-Axis" + +[node name="X_CW" type="Button" parent="CanvasLayer/RotationVBoxContainer"] +layout_mode = 2 +text = "Rotate CW X-Axis" + +[node name="X_CCW" type="Button" parent="CanvasLayer/RotationVBoxContainer"] +layout_mode = 2 +text = "Rotate CCW X-Axis" + +[node name="Y_CW" type="Button" parent="CanvasLayer/RotationVBoxContainer"] +layout_mode = 2 +text = "Rotate CW Y-Axis" + +[node name="Y_CCW" type="Button" parent="CanvasLayer/RotationVBoxContainer"] +layout_mode = 2 +text = "Rotate CCW Y-Axis" + +[node name="DebugPlayerStuff" type="VBoxContainer" parent="CanvasLayer"] +anchors_preset = 5 +anchor_left = 0.5 +anchor_right = 0.5 +offset_left = -37.5 +offset_right = 37.5 +offset_bottom = 70.0 +grow_horizontal = 2 + +[node name="PlayerZLayerChangeUp" type="Button" parent="CanvasLayer/DebugPlayerStuff"] +layout_mode = 2 +text = "Z-layer +" + +[node name="PlayerZLayerChangeDown" type="Button" parent="CanvasLayer/DebugPlayerStuff"] +layout_mode = 2 +text = "Z-layer -" + +[connection signal="pressed" from="CanvasLayer/ResetButton" to="." method="_on_reset_button_pressed"] +[connection signal="pressed" from="CanvasLayer/RotationVBoxContainer/Z_CW" to="." method="_on_cw_pressed"] +[connection signal="pressed" from="CanvasLayer/RotationVBoxContainer/Z_CCW" to="." method="_on_ccw_pressed"] +[connection signal="pressed" from="CanvasLayer/RotationVBoxContainer/X_CW" to="." method="_on_x_cw_pressed"] +[connection signal="pressed" from="CanvasLayer/RotationVBoxContainer/X_CCW" to="." method="_on_x_ccw_pressed"] +[connection signal="pressed" from="CanvasLayer/RotationVBoxContainer/Y_CW" to="." method="_on_y_cw_pressed"] +[connection signal="pressed" from="CanvasLayer/RotationVBoxContainer/Y_CCW" to="." method="_on_y_ccw_pressed"] +[connection signal="pressed" from="CanvasLayer/DebugPlayerStuff/PlayerZLayerChangeUp" to="." method="_on_player_z_layer_change_pressed"] +[connection signal="pressed" from="CanvasLayer/DebugPlayerStuff/PlayerZLayerChangeDown" to="." method="_on_player_z_layer_change_down_pressed"] diff --git a/scenes/main.tscn b/scenes/main.tscn index d344062..5cec166 100644 --- a/scenes/main.tscn +++ b/scenes/main.tscn @@ -7,7 +7,3 @@ [node name="Camera2D" type="Camera2D" parent="."] [node name="MainMenu" parent="." instance=ExtResource("1_o5qli")] - -[node name="GameManager" type="Node" parent="."] - -[node name="TurnManager" type="Node" parent="."] diff --git a/scenes/player.tscn b/scenes/player.tscn index e7547cf..3a46232 100644 --- a/scenes/player.tscn +++ b/scenes/player.tscn @@ -111,7 +111,7 @@ animations = [{ }] [sub_resource type="RectangleShape2D" id="RectangleShape2D_v6fml"] -size = Vector2(36, 51) +size = Vector2(20, 25) [node name="Player" type="CharacterBody2D"] script = ExtResource("1_g2els") @@ -123,5 +123,7 @@ animation = &"down" frame_progress = 0.830149 [node name="CollisionShape2D" type="CollisionShape2D" parent="."] -position = Vector2(0, 4.5) +position = Vector2(0, 2.5) shape = SubResource("RectangleShape2D_v6fml") + +[node name="Camera2D" type="Camera2D" parent="."] diff --git a/scenes/player.tscn12712364768.tmp b/scenes/player.tscn12712364768.tmp new file mode 100644 index 0000000..3a46232 --- /dev/null +++ b/scenes/player.tscn12712364768.tmp @@ -0,0 +1,129 @@ +[gd_scene load_steps=17 format=3 uid="uid://d1jhpluu86cbd"] + +[ext_resource type="Texture2D" uid="uid://d3tfo61gemayy" path="res://assets/sprites/units/$Cat_Female (2).png" id="1_3vyb7"] +[ext_resource type="Script" uid="uid://jfojoaymauh2" path="res://scripts/player.gd" id="1_g2els"] + +[sub_resource type="AtlasTexture" id="AtlasTexture_3li8b"] +atlas = ExtResource("1_3vyb7") +region = Rect2(0, 0, 48, 60) + +[sub_resource type="AtlasTexture" id="AtlasTexture_mdl7e"] +atlas = ExtResource("1_3vyb7") +region = Rect2(48, 0, 48, 60) + +[sub_resource type="AtlasTexture" id="AtlasTexture_qu4a1"] +atlas = ExtResource("1_3vyb7") +region = Rect2(96, 0, 48, 60) + +[sub_resource type="AtlasTexture" id="AtlasTexture_70d11"] +atlas = ExtResource("1_3vyb7") +region = Rect2(0, 60, 48, 60) + +[sub_resource type="AtlasTexture" id="AtlasTexture_cw2d6"] +atlas = ExtResource("1_3vyb7") +region = Rect2(48, 60, 48, 60) + +[sub_resource type="AtlasTexture" id="AtlasTexture_khinc"] +atlas = ExtResource("1_3vyb7") +region = Rect2(96, 60, 48, 60) + +[sub_resource type="AtlasTexture" id="AtlasTexture_bruh7"] +atlas = ExtResource("1_3vyb7") +region = Rect2(0, 120, 48, 60) + +[sub_resource type="AtlasTexture" id="AtlasTexture_6eyey"] +atlas = ExtResource("1_3vyb7") +region = Rect2(48, 120, 48, 60) + +[sub_resource type="AtlasTexture" id="AtlasTexture_d3wef"] +atlas = ExtResource("1_3vyb7") +region = Rect2(96, 120, 48, 60) + +[sub_resource type="AtlasTexture" id="AtlasTexture_o4126"] +atlas = ExtResource("1_3vyb7") +region = Rect2(0, 180, 48, 60) + +[sub_resource type="AtlasTexture" id="AtlasTexture_lkdrv"] +atlas = ExtResource("1_3vyb7") +region = Rect2(48, 180, 48, 60) + +[sub_resource type="AtlasTexture" id="AtlasTexture_p7iby"] +atlas = ExtResource("1_3vyb7") +region = Rect2(96, 180, 48, 60) + +[sub_resource type="SpriteFrames" id="SpriteFrames_0rnld"] +animations = [{ +"frames": [{ +"duration": 1.0, +"texture": SubResource("AtlasTexture_3li8b") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_mdl7e") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_qu4a1") +}], +"loop": true, +"name": &"down", +"speed": 5.0 +}, { +"frames": [{ +"duration": 1.0, +"texture": SubResource("AtlasTexture_70d11") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_cw2d6") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_khinc") +}], +"loop": true, +"name": &"left", +"speed": 5.0 +}, { +"frames": [{ +"duration": 1.0, +"texture": SubResource("AtlasTexture_bruh7") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_6eyey") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_d3wef") +}], +"loop": true, +"name": &"right", +"speed": 5.0 +}, { +"frames": [{ +"duration": 1.0, +"texture": SubResource("AtlasTexture_o4126") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_lkdrv") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_p7iby") +}], +"loop": true, +"name": &"up", +"speed": 5.0 +}] + +[sub_resource type="RectangleShape2D" id="RectangleShape2D_v6fml"] +size = Vector2(20, 25) + +[node name="Player" type="CharacterBody2D"] +script = ExtResource("1_g2els") + +[node name="AnimatedSprite2D" type="AnimatedSprite2D" parent="."] +scale = Vector2(0.5, 0.5) +sprite_frames = SubResource("SpriteFrames_0rnld") +animation = &"down" +frame_progress = 0.830149 + +[node name="CollisionShape2D" type="CollisionShape2D" parent="."] +position = Vector2(0, 2.5) +shape = SubResource("RectangleShape2D_v6fml") + +[node name="Camera2D" type="Camera2D" parent="."] diff --git a/scripts/debug_level.gd b/scripts/debug_level.gd index a3c1bc8..576c5af 100644 --- a/scripts/debug_level.gd +++ b/scripts/debug_level.gd @@ -1,10 +1,13 @@ extends Node2D func _ready(): + # Initialize the systems that should be available globally + if not Engine.has_singleton("IsometricMapSystem"): + Engine.register_singleton("IsometricMapSystem", load("res://scripts/isometric_map_system.gd").new()) + var map = $IsometricMapLayerHolder var player = $Player + + # Setup map and player map.set_player(player) map.init_player() - -func _process(_delta: float) -> void: - pass diff --git a/scripts/isometric_camera_controller.gd b/scripts/isometric_camera_controller.gd new file mode 100644 index 0000000..348d389 --- /dev/null +++ b/scripts/isometric_camera_controller.gd @@ -0,0 +1,46 @@ +extends Node +class_name IsometricCameraController + +var camera : Camera2D +var initial_position : Vector2 +var initial_zoom : Vector2 + +var drag_start = Vector2() +var drag_active = false +var zoom_min = 0.1 +var zoom_max = 4.0 +var zoom_speed = 0.1 + +func _init(camera_node): + camera = camera_node + initial_position = camera.position + initial_zoom = camera.zoom + +func handle_input(event): + # Camera drag (pan) control + if event is InputEventMouseButton: + if event.button_index == MOUSE_BUTTON_RIGHT: + if event.pressed: + drag_start = event.position + drag_active = true + else: + drag_active = false + + # Zoom control with mouse wheel + if event.button_index == MOUSE_BUTTON_WHEEL_DOWN: + zoom_camera(-zoom_speed) + elif event.button_index == MOUSE_BUTTON_WHEEL_UP: + zoom_camera(zoom_speed) + + # Handle camera movement while dragging + if event is InputEventMouseMotion and drag_active: + camera.position -= event.relative / camera.zoom + +func zoom_camera(zoom_amount): + var new_zoom = camera.zoom.x + zoom_amount + new_zoom = clamp(new_zoom, zoom_min, zoom_max) + camera.zoom = Vector2(new_zoom, new_zoom) + +func reset_camera(): + camera.position = initial_position + camera.zoom = initial_zoom diff --git a/scripts/isometric_camera_controller.gd.uid b/scripts/isometric_camera_controller.gd.uid new file mode 100644 index 0000000..c5df04d --- /dev/null +++ b/scripts/isometric_camera_controller.gd.uid @@ -0,0 +1 @@ +uid://tob3fou8cqr7 diff --git a/scripts/isometric_map_data.gd b/scripts/isometric_map_data.gd new file mode 100644 index 0000000..61510f7 --- /dev/null +++ b/scripts/isometric_map_data.gd @@ -0,0 +1,350 @@ +extends Resource +class_name IsometricMapData + +var GRID_SIZE_WIDTH = 50 # play area size x +var GRID_SIZE_LENGTH = 30 # play area size y +var GRID_SIZE_HEIGHT = 30 # play area size z +var OFFSET = 0 +var MAX_ARRAY_SIZE = 0 + +# The actual map data array +var map_data = [] + +func _init(width = 50, length = 30, height = 30, offset = 0): + GRID_SIZE_WIDTH = width + GRID_SIZE_LENGTH = length + GRID_SIZE_HEIGHT = height + OFFSET = offset + _set_max_array_size() + initialize_map_data() + +func _set_max_array_size(): + MAX_ARRAY_SIZE = 0 + + if MAX_ARRAY_SIZE < GRID_SIZE_WIDTH: + MAX_ARRAY_SIZE = GRID_SIZE_WIDTH + if MAX_ARRAY_SIZE < GRID_SIZE_LENGTH: + MAX_ARRAY_SIZE = GRID_SIZE_LENGTH + if MAX_ARRAY_SIZE < GRID_SIZE_HEIGHT: + MAX_ARRAY_SIZE = GRID_SIZE_HEIGHT + +func initialize_map_data(): + # Initialize empty map structure + map_data = [] + + for x in MAX_ARRAY_SIZE: + var y_array = [] + for y in MAX_ARRAY_SIZE: + var z_array = [] + for z in MAX_ARRAY_SIZE: + z_array.append(null) + y_array.append(z_array) + map_data.append(y_array) + +# Get a tile at specific coordinates, return null if out of bounds +func get_tile(x, y, z): + if x < 0 or x >= MAX_ARRAY_SIZE or y < 0 or y >= MAX_ARRAY_SIZE or z < 0 or z >= MAX_ARRAY_SIZE: + return null + return map_data[x][y][z] + +# Set a tile at specific coordinates +func set_tile(x, y, z, tile_data): + if x < 0 or x >= MAX_ARRAY_SIZE or y < 0 or y >= MAX_ARRAY_SIZE or z < 0 or z >= MAX_ARRAY_SIZE: + return + map_data[x][y][z] = tile_data + +# Generate the isometric coordinates for a tile +func generate_iso_coords(x, y, z): + var coord_x = x + (-1 * z) + OFFSET + var coord_y = y + (-1 * z) - OFFSET + return Vector2i(coord_x, coord_y) + +# Create a map with default configuration +func create_default_map(): + # First initialize all tiles with null values + for z in GRID_SIZE_HEIGHT: + for y in GRID_SIZE_LENGTH: + for x in GRID_SIZE_WIDTH: + var iso_coords = generate_iso_coords(x, y, z) + + var tile_data = IsometricMapSystem.create_tile_data( + iso_coords.x, + iso_coords.y, + z, + # Give all tiles valid default atlas positions to avoid null errors + IsometricMapSystem.BLUE_ISOMETRICTILE_ATLAS_POSITION, + IsometricMapSystem.WHITE_ISOMETRICTILE_ATLAS_POSITION + ) + # By default, tiles are not visible + tile_data["visibility"] = false + map_data[x][y][z] = tile_data + + # Set ground floor visible with blue tiles + for y in GRID_SIZE_LENGTH: + for x in GRID_SIZE_WIDTH: + var tile = map_data[x][y][0] + tile["atlas_base_position"] = IsometricMapSystem.BLUE_ISOMETRICTILE_ATLAS_POSITION + tile["atlas_highlight_position"] = IsometricMapSystem.WHITE_ISOMETRICTILE_ATLAS_POSITION + tile["visibility"] = true + + # Add a vertical column of red tiles for demonstration + # Make sure coords are within bounds + if 5 < GRID_SIZE_WIDTH and 5 < GRID_SIZE_LENGTH: + for i in range(1, min(10, GRID_SIZE_HEIGHT)): + var tile = map_data[5][5][i] + if tile != null: + tile["atlas_base_position"] = IsometricMapSystem.RED_ISOMETRICTILE_ATLAS_POSITION + tile["atlas_highlight_position"] = IsometricMapSystem.WHITE_ISOMETRICTILE_ATLAS_POSITION + tile["visibility"] = true + IsometricMapSystem.debug_print("Created red tile at 5,5," + str(i)) + #var tile = map_data[10][10][1] + #if tile != null: + # tile["atlas_base_position"] = IsometricMapSystem.BLACK_ISOMETRICTILE_ATLAS_POSITION + # tile["atlas_highlight_position"] = IsometricMapSystem.GREEN_ISOMETRICTILE_ATLAS_POSITION + # tile["visibility"] = true + # IsometricMapSystem.debug_print("Created black tile at 10,10," + str(1)) + +# Rotate map around X axis +func rotate_around_x_axis(rotation_steps = 1): + rotation_steps = rotation_steps % 4 + + if rotation_steps == 0: + return + + var temp_map = [] + # Initialize temp_map with same structure + for x in MAX_ARRAY_SIZE: + var y_array = [] + for y in MAX_ARRAY_SIZE: + var z_array = [] + for z in MAX_ARRAY_SIZE: + z_array.append(null) + y_array.append(z_array) + temp_map.append(y_array) + + # Create a new map with adjusted dimensions + var new_height = int(GRID_SIZE_LENGTH) if rotation_steps % 2 == 1 else int(GRID_SIZE_HEIGHT) + var new_length = int(GRID_SIZE_HEIGHT) if rotation_steps % 2 == 1 else int(GRID_SIZE_LENGTH) + + # Store the original dimensions + var original_height = GRID_SIZE_HEIGHT + var original_length = GRID_SIZE_LENGTH + + # Temporarily adjust grid dimensions for coordinate calculation + GRID_SIZE_HEIGHT = new_height + GRID_SIZE_LENGTH = new_length + + for x in GRID_SIZE_WIDTH: + for y in original_length: + for z in original_height: + if map_data[x][y][z] == null: + continue + + var new_y = 0 + var new_z = 0 + + match rotation_steps: + 1: # 90 degrees + new_y = z + new_z = original_length - 1 - y + 2: # 180 degrees + new_y = original_length - 1 - y + new_z = original_height - 1 - z + 3: # 270 degrees + new_y = original_height - 1 - z + new_z = y + + if new_y >= 0 and new_y < new_length and new_z >= 0 and new_z < new_height: + temp_map[x][new_y][new_z] = map_data[x][y][z].duplicate() + + var new_coord_x = x + (-1 * new_z) + OFFSET + var new_coord_y = new_y + (-1 * new_z) - OFFSET + + temp_map[x][new_y][new_z]["x"] = new_coord_x + temp_map[x][new_y][new_z]["y"] = new_coord_y + temp_map[x][new_y][new_z]["z"] = new_z + + # Update the grid dimensions + GRID_SIZE_HEIGHT = new_height + GRID_SIZE_LENGTH = new_length + + map_data = temp_map + +# Rotate map around Y axis +func rotate_around_y_axis(rotation_steps = 1): + rotation_steps = rotation_steps % 4 + + if rotation_steps == 0: + return + + var temp_map = [] + # Initialize temp_map with same structure + for x in MAX_ARRAY_SIZE: + var y_array = [] + for y in MAX_ARRAY_SIZE: + var z_array = [] + for z in MAX_ARRAY_SIZE: + z_array.append(null) + y_array.append(z_array) + temp_map.append(y_array) + + # Create a new map with adjusted dimensions + var new_width = int(GRID_SIZE_HEIGHT) if rotation_steps % 2 == 1 else int(GRID_SIZE_WIDTH) + var new_height = int(GRID_SIZE_WIDTH) if rotation_steps % 2 == 1 else int(GRID_SIZE_HEIGHT) + + # Store the original dimensions + var original_width = GRID_SIZE_WIDTH + var original_height = GRID_SIZE_HEIGHT + + # Temporarily adjust grid dimensions for coordinate calculation + GRID_SIZE_WIDTH = new_width + GRID_SIZE_HEIGHT = new_height + + for x in original_width: + for y in GRID_SIZE_LENGTH: + for z in original_height: + if map_data[x][y][z] == null: + continue + + var new_x = 0 + var new_z = 0 + + match rotation_steps: + 1: # 90 degrees clockwise around Y axis + new_x = original_height - 1 - z + new_z = x + 2: # 180 degrees + new_x = original_width - 1 - x + new_z = original_height - 1 - z + 3: # 270 degrees + new_x = z + new_z = original_width - 1 - x + + if new_x >= 0 and new_x < new_width and new_z >= 0 and new_z < new_height: + temp_map[new_x][y][new_z] = map_data[x][y][z].duplicate() + + var new_coord_x = new_x + (-1 * new_z) + OFFSET + var new_coord_y = y + (-1 * new_z) - OFFSET + + temp_map[new_x][y][new_z]["x"] = new_coord_x + temp_map[new_x][y][new_z]["y"] = new_coord_y + temp_map[new_x][y][new_z]["z"] = new_z + + # Update the grid dimensions + GRID_SIZE_WIDTH = new_width + GRID_SIZE_HEIGHT = new_height + + map_data = temp_map + +# Rotate map around Z axis +func rotate_around_z_axis(rotation_steps = 1): + rotation_steps = rotation_steps % 4 + + if rotation_steps == 0: + return + + var temp_map = [] + # Initialize temp_map with same structure + for x in MAX_ARRAY_SIZE: + var y_array = [] + for y in MAX_ARRAY_SIZE: + var z_array = [] + for z in MAX_ARRAY_SIZE: + z_array.append(null) + y_array.append(z_array) + temp_map.append(y_array) + + # Create a new map with adjusted dimensions based on rotation + var new_width = int(GRID_SIZE_LENGTH) if rotation_steps % 2 == 1 else int(GRID_SIZE_WIDTH) + var new_length = int(GRID_SIZE_WIDTH) if rotation_steps % 2 == 1 else int(GRID_SIZE_LENGTH) + + # Store the original dimensions + var original_width = GRID_SIZE_WIDTH + var original_length = GRID_SIZE_LENGTH + + # Temporarily adjust grid dimensions for coordinate calculation + GRID_SIZE_WIDTH = new_width + GRID_SIZE_LENGTH = new_length + + for x in original_width: + for y in original_length: + for z in GRID_SIZE_HEIGHT: + if map_data[x][y][z] == null: + continue + + var new_x = 0 + var new_y = 0 + + match rotation_steps: + 1: # 90 degrees + new_x = y + new_y = original_width - 1 - x + 2: # 180 degrees + new_x = original_width - 1 - x + new_y = original_length - 1 - y + 3: # 270 degrees + new_x = original_length - 1 - y + new_y = x + + if new_x >= 0 and new_x < new_width and new_y >= 0 and new_y < new_length: + temp_map[new_x][new_y][z] = map_data[x][y][z].duplicate() + + var new_coord_x = new_x + (-1 * z) + OFFSET + var new_coord_y = new_y + (-1 * z) - OFFSET + + temp_map[new_x][new_y][z]["x"] = new_coord_x + temp_map[new_x][new_y][z]["y"] = new_coord_y + temp_map[new_x][new_y][z]["z"] = z + + # Update the grid dimensions + GRID_SIZE_WIDTH = new_width + GRID_SIZE_LENGTH = new_length + + map_data = temp_map + +# Find a tile containing a specific unit +func find_unit_tile(unit_type = null): + for z in GRID_SIZE_HEIGHT: + for x in GRID_SIZE_WIDTH: + for y in GRID_SIZE_LENGTH: + var tile = map_data[x][y][z] + if tile and tile["unit"] != null: + if unit_type == null or tile["unit_type"] == unit_type: + return {"tile": tile, "x": x, "y": y, "z": z} + return null + +# Move a unit from one position to another +func move_unit(from_x, from_y, from_z, to_x, to_y, to_z): + # Get the source and destination tiles safely + var from_tile = get_tile(from_x, from_y, from_z) + var to_tile = get_tile(to_x, to_y, to_z) + + # Debug information + print("Moving unit from [", from_x, ",", from_y, ",", from_z, "] to [", to_x, ",", to_y, ",", to_z, "]") + + # Validate that both tiles exist and source has a unit + if from_tile == null: + print("Source tile doesn't exist") + return false + + if to_tile == null: + print("Destination tile doesn't exist") + return false + + if from_tile["unit"] == null: + print("No unit at source tile") + return false + + # Valid move - transfer the unit + to_tile["unit"] = from_tile["unit"] + to_tile["unit_type"] = from_tile["unit_type"] + to_tile["visibility"] = true + + # Clear the source tile + from_tile["unit"] = null + from_tile["unit_type"] = null + # Keep source tile visible + from_tile["visibility"] = true + + print("Unit moved successfully") + return true diff --git a/scripts/isometric_map_data.gd.uid b/scripts/isometric_map_data.gd.uid new file mode 100644 index 0000000..8d1daac --- /dev/null +++ b/scripts/isometric_map_data.gd.uid @@ -0,0 +1 @@ +uid://ba42vqbgh72ff diff --git a/scripts/isometric_map_layer_holder.gd b/scripts/isometric_map_layer_holder.gd index d73bb1b..f0f3064 100644 --- a/scripts/isometric_map_layer_holder.gd +++ b/scripts/isometric_map_layer_holder.gd @@ -1,695 +1,116 @@ extends Node2D +class_name ImprovedIsometricMapLayerHolder -#TODO add player at a tile coordinate from tile array. -#TODO player movement -#TODO player actions (movement and attack) -#TODO highlight possible tiles for actions -#TODO collisions and pathfinding -#TODO add "physiks" and "destroy" feature of tiles -#TODO add enemy with some kind of AI -#TODO refractor code to be more modular -#TODO get nice tileset and create first normal level - - - -# camera stuff +# Components @onready var camera = $Camera2D -var drag_start = Vector2() -var drag_active = false -var zoom_min = 0.1 -var zoom_max = 4.0 -var zoom_speed = 0.1 -var initial_camera_position = Vector2(0, 0) -var initial_camera_zoom = Vector2(1, 1) - -var INITIAL_GRID_SIZE_WIDTH = 50 # play area size x -var INITIAL_GRID_SIZE_LENGTH = 30 # play area size y -var INITIAL_GRID_SIZE_HEIGHT = 30 # play area size z - -var GRID_SIZE_WIDTH = INITIAL_GRID_SIZE_WIDTH # play area size x -var GRID_SIZE_LENGTH = INITIAL_GRID_SIZE_LENGTH # play area size y -var GRID_SIZE_HEIGHT = INITIAL_GRID_SIZE_HEIGHT # play area size z -var TILE_SIZE = 32 # in px -var TILE_SIZE_ISOMETRIC_X = 32 # in px -var TILE_SIZE_ISOMETRIC_Y = 16 # in px -var ROTATION = 0 -const MAIN_SOURCE_ID = 0 -const BLUE_ISOMETRICTILE_ATLAS_POSITION = Vector2i(0,0) -const RED_ISOMETRICTILE_ATLAS_POSITION = Vector2i(1,0) -const GREEN_ISOMETRICTILE_ATLAS_POSITION = Vector2i(2,0) -const WHITE_ISOMETRICTILE_ATLAS_POSITION = Vector2i(3,0) -const BLACK_ISOMETRICTILE_ATLAS_POSITION = Vector2i(4,0) -const PURPLE_ISOMETRICTILE_ATLAS_POSITION = Vector2i(5,0) -const ORANGE_ISOMETRICTILE_ATLAS_POSITION = Vector2i(6,0) -const OFFSET = 0 - -var MAX_ARRAY_SIZE = 0 - -func _set_max_array_size(): - MAX_ARRAY_SIZE = 0 - - if MAX_ARRAY_SIZE < GRID_SIZE_WIDTH: - MAX_ARRAY_SIZE = GRID_SIZE_WIDTH - if MAX_ARRAY_SIZE < GRID_SIZE_LENGTH: - MAX_ARRAY_SIZE = GRID_SIZE_LENGTH - if MAX_ARRAY_SIZE < GRID_SIZE_HEIGHT: - MAX_ARRAY_SIZE = GRID_SIZE_HEIGHT - - - -func create_debug_map_array(): - var _debug_map = [] - - - _set_max_array_size() - for x in MAX_ARRAY_SIZE: - var y_array = [] - for y in MAX_ARRAY_SIZE: - var z_array = [] - for z in MAX_ARRAY_SIZE: - z_array.append(null) - y_array.append(z_array) - _debug_map.append(y_array) - - for z in INITIAL_GRID_SIZE_HEIGHT: - for y in INITIAL_GRID_SIZE_LENGTH: - for x in INITIAL_GRID_SIZE_WIDTH: - var coord_x = x + (-1 * z) + OFFSET - var coord_y = y + (-1 * z) - OFFSET - - var tile_data = { - "x": coord_x, - "y": coord_y, - "z": z, - "atlas_base_position": null, - "atlas_highlight_position": null, - "highlighted": false, - "selected": false, - "hp": 100, - "armour": 0, - "destroyable": false, - "visibility": false, - "unit": null, - "unit_type": null, # PC (more options e.g. can move it) or NPC (can only view it) - "gravity": null, - } - _debug_map[x][y][z] = tile_data - - var tile = _debug_map[0][0][0] - for y in INITIAL_GRID_SIZE_LENGTH: - for x in INITIAL_GRID_SIZE_WIDTH: - tile = _debug_map[x][y][0] - tile["atlas_base_position"] = BLUE_ISOMETRICTILE_ATLAS_POSITION - tile["atlas_highlight_position"] = WHITE_ISOMETRICTILE_ATLAS_POSITION - tile["visibility"] = true - for i in range(1,10): - tile = _debug_map[5][5][i] - tile["atlas_base_position"] = RED_ISOMETRICTILE_ATLAS_POSITION - tile["atlas_highlight_position"] = WHITE_ISOMETRICTILE_ATLAS_POSITION - tile["visibility"] = true - - # for y in INITIAL_GRID_SIZE_LENGTH: - # for x in INITIAL_GRID_SIZE_WIDTH: - # tile = _debug_map[x][y][INITIAL_GRID_SIZE_HEIGHT-1] - # tile["atlas_position"] = BLUE_ISOMETRICTILE_ATLAS_POSITION - # tile["visibility"] = true - - # for z in range(1,INITIAL_GRID_SIZE_HEIGHT-1): - # for x in INITIAL_GRID_SIZE_WIDTH: - # tile = _debug_map[x][0][z] - # tile["atlas_position"] = GREEN_ISOMETRICTILE_ATLAS_POSITION - # tile["visibility"] = true - # for z in range(1,INITIAL_GRID_SIZE_HEIGHT-1): - # for x in INITIAL_GRID_SIZE_WIDTH: - # tile = _debug_map[x][INITIAL_GRID_SIZE_LENGTH-1][z] - # tile["atlas_position"] = GREEN_ISOMETRICTILE_ATLAS_POSITION - # tile["visibility"] = true - - # for z in range(1,INITIAL_GRID_SIZE_HEIGHT-1): - # for y in range(1,INITIAL_GRID_SIZE_LENGTH-1): - # tile = _debug_map[0][y][z] - # tile["atlas_position"] = BLACK_ISOMETRICTILE_ATLAS_POSITION - # tile["visibility"] = true - # for z in range(1,INITIAL_GRID_SIZE_HEIGHT-1): - # for y in range(1,INITIAL_GRID_SIZE_LENGTH-1): - # tile = _debug_map[INITIAL_GRID_SIZE_WIDTH-1][y][z] - # tile["atlas_position"] = RED_ISOMETRICTILE_ATLAS_POSITION - # tile["visibility"] = true - - - GRID_SIZE_WIDTH = INITIAL_GRID_SIZE_WIDTH # play area size x - GRID_SIZE_LENGTH = INITIAL_GRID_SIZE_LENGTH # play area size y - GRID_SIZE_HEIGHT = INITIAL_GRID_SIZE_HEIGHT # play area size z - - return _debug_map - -func rotate_map_around_x_axis(rotation_steps = 1): - rotation_steps = rotation_steps % 4 - - if rotation_steps == 0: - return - - var temp_map = [] - # Initialize temp_map with same structure - - _set_max_array_size() - for x in MAX_ARRAY_SIZE: - var y_array = [] - for y in MAX_ARRAY_SIZE: - var z_array = [] - for z in MAX_ARRAY_SIZE: - z_array.append(null) - y_array.append(z_array) - temp_map.append(y_array) - - # Create a new map with adjusted dimensions - var new_height = int(GRID_SIZE_LENGTH) if rotation_steps % 2 == 1 else int(GRID_SIZE_HEIGHT) - var new_length = int(GRID_SIZE_HEIGHT) if rotation_steps % 2 == 1 else int(GRID_SIZE_LENGTH) - - # Store the original dimensions - var original_height = GRID_SIZE_HEIGHT - var original_length = GRID_SIZE_LENGTH - - # Temporarily adjust grid dimensions for coordinate calculation - GRID_SIZE_HEIGHT = new_height - GRID_SIZE_LENGTH = new_length - - for x in GRID_SIZE_WIDTH: - for y in original_length: - for z in original_height: - if debug_map[x][y][z] == null: - continue - - var new_y = 0 - var new_z = 0 - - match rotation_steps: - 1: # 90 degrees - new_y = z - new_z = original_length - 1 - y - 2: # 180 degrees - new_y = original_length - 1 - y - new_z = original_height - 1 - z - 3: # 270 degrees - new_y = original_height - 1 - z - new_z = y - - if new_y >= 0 and new_y < new_length and new_z >= 0 and new_z < new_height: - temp_map[x][new_y][new_z] = debug_map[x][y][z].duplicate() - - var new_coord_x = x + (-1 * new_z) + OFFSET - var new_coord_y = new_y + (-1 * new_z) - OFFSET - - temp_map[x][new_y][new_z]["x"] = new_coord_x - temp_map[x][new_y][new_z]["y"] = new_coord_y - temp_map[x][new_y][new_z]["z"] = new_z - - # Update the grid dimensions - GRID_SIZE_HEIGHT = new_height - GRID_SIZE_LENGTH = new_length - - debug_map = temp_map - -func rotate_map_around_y_axis(rotation_steps = 1): - rotation_steps = rotation_steps % 4 - - if rotation_steps == 0: - return - - var temp_map = [] - # Initialize temp_map with same structure - _set_max_array_size() - for x in MAX_ARRAY_SIZE: - var y_array = [] - for y in MAX_ARRAY_SIZE: - var z_array = [] - for z in MAX_ARRAY_SIZE: - z_array.append(null) - y_array.append(z_array) - temp_map.append(y_array) - - # Create a new map with adjusted dimensions - var new_width = int(GRID_SIZE_HEIGHT) if rotation_steps % 2 == 1 else int(GRID_SIZE_WIDTH) - var new_height = int(GRID_SIZE_WIDTH) if rotation_steps % 2 == 1 else int(GRID_SIZE_HEIGHT) - - # Store the original dimensions - var original_width = GRID_SIZE_WIDTH - var original_height = GRID_SIZE_HEIGHT - - # Temporarily adjust grid dimensions for coordinate calculation - GRID_SIZE_WIDTH = new_width - GRID_SIZE_HEIGHT = new_height - - for x in original_width: - for y in GRID_SIZE_LENGTH: - for z in original_height: - if debug_map[x][y][z] == null: - continue - - var new_x = 0 - var new_z = 0 - - match rotation_steps: - 1: # 90 degrees clockwise around Y axis - new_x = original_height - 1 - z - new_z = x - 2: # 180 degrees - new_x = original_width - 1 - x - new_z = original_height - 1 - z - 3: # 270 degrees - new_x = z - new_z = original_width - 1 - x - - if new_x >= 0 and new_x < new_width and new_z >= 0 and new_z < new_height: - temp_map[new_x][y][new_z] = debug_map[x][y][z].duplicate() - - var new_coord_x = new_x + (-1 * new_z) + OFFSET - var new_coord_y = y + (-1 * new_z) - OFFSET - - temp_map[new_x][y][new_z]["x"] = new_coord_x - temp_map[new_x][y][new_z]["y"] = new_coord_y - temp_map[new_x][y][new_z]["z"] = new_z - - # Update the grid dimensions - GRID_SIZE_WIDTH = new_width - GRID_SIZE_HEIGHT = new_height - - debug_map = temp_map - -func rotate_map_around_z_axis(rotation_steps = 1): - rotation_steps = rotation_steps % 4 - - if rotation_steps == 0: - return - - var temp_map = [] - # Initialize temp_map with same structure - _set_max_array_size() - for x in MAX_ARRAY_SIZE: - var y_array = [] - for y in MAX_ARRAY_SIZE: - var z_array = [] - for z in MAX_ARRAY_SIZE: - z_array.append(null) - y_array.append(z_array) - temp_map.append(y_array) - - # Create a new map with adjusted dimensions based on rotation - var new_width = int(GRID_SIZE_LENGTH) if rotation_steps % 2 == 1 else int(GRID_SIZE_WIDTH) - var new_length = int(GRID_SIZE_WIDTH) if rotation_steps % 2 == 1 else int(GRID_SIZE_LENGTH) - - # Store the original dimensions - var original_width = GRID_SIZE_WIDTH - var original_length = GRID_SIZE_LENGTH - - # Temporarily adjust grid dimensions for coordinate calculation - GRID_SIZE_WIDTH = new_width - GRID_SIZE_LENGTH = new_length - - for x in original_width: - for y in original_length: - for z in GRID_SIZE_HEIGHT: - if debug_map[x][y][z] == null: - continue - - var new_x = 0 - var new_y = 0 - - match rotation_steps: - 1: # 90 degrees - new_x = y - new_y = original_width - 1 - x - 2: # 180 degrees - new_x = original_width - 1 - x - new_y = original_length - 1 - y - 3: # 270 degrees - new_x = original_length - 1 - y - new_y = x - - if new_x >= 0 and new_x < new_width and new_y >= 0 and new_y < new_length: - temp_map[new_x][new_y][z] = debug_map[x][y][z].duplicate() - - var new_coord_x = new_x + (-1 * z) + OFFSET - var new_coord_y = new_y + (-1 * z) - OFFSET - - temp_map[new_x][new_y][z]["x"] = new_coord_x - temp_map[new_x][new_y][z]["y"] = new_coord_y - temp_map[new_x][new_y][z]["z"] = z - - # Update the grid dimensions - GRID_SIZE_WIDTH = new_width - GRID_SIZE_LENGTH = new_length - - debug_map = temp_map -var isometric_map_layers = [] - -func initialize_map_layers(): - # Clear any existing layers - for layer in isometric_map_layers: - if is_instance_valid(layer): - layer.queue_free() - - isometric_map_layers.clear() - - # Create new layers for each height level - for z in GRID_SIZE_HEIGHT: - var new_layer = TileMapLayer.new() - new_layer.set_name("IsometricMapLayer_" + str(z)) - new_layer.tile_set = $TileMapLayer.tile_set # Set your tileset - new_layer.z_index = z # Set the z-index to match the layer's height - - - add_child(new_layer) - isometric_map_layers.append(new_layer) - -var debug_map = create_debug_map_array() -# Draw the map -func draw_visible_tiles(): - # TODO change it so that tiles behind something is not drawn z+1 at same tile["x"] and tile["y"] - # clear all previously drawn tiles on each layer - for layer in isometric_map_layers: - layer.clear() - # draw the map - for z in GRID_SIZE_HEIGHT: - for y in GRID_SIZE_LENGTH: - for x in GRID_SIZE_WIDTH: - var tile = debug_map[x][y][z] - if tile != null and tile["visibility"]: - # Use the layer that corresponds to the tile's z-value - if z < isometric_map_layers.size(): - isometric_map_layers[z].set_cell( - Vector2i(tile["x"], tile["y"]), - MAIN_SOURCE_ID, - tile["atlas_base_position"] - ) - - -var highlighted_tiles = {} # Dictionary to store all currently highlighted tiles - -func isometric_grid_hover(): - var hover_tile_position = isometric_map_layers[0].local_to_map(get_global_mouse_position()) - var new_highlighted_tiles = {} # Will store tiles to highlight this frame - - # First find all tiles that should be highlighted - for z in GRID_SIZE_HEIGHT: - for x in GRID_SIZE_WIDTH: - for y in GRID_SIZE_LENGTH: - var tile = debug_map[x][y][z] - - if tile != null and tile["visibility"]: - if tile["x"] == hover_tile_position.x and tile["y"] == hover_tile_position.y: - # TODO: change highlighing so when the mouse is over an drawn tile and not the grid - var tile_above = isometric_map_layers[z+1].get_cell_source_id( - Vector2i(tile["x"]-1, tile["y"]-1) - ) - # Store this tile for highlighting - var tile_key = str(x) + "_" + str(y) + "_" + str(z) - # print(tile_above) - # print(tile["x"], " ", tile["y"], " ", z) - # print(hover_tile_position) - if not tile_above: - new_highlighted_tiles[tile_key] = { - "x": x, - "y": y, - "z": z+1 - } - else: - new_highlighted_tiles[tile_key] = { - "x": x, - "y": y, - "z": z - } - - new_highlighted_tiles[tile_key] = { - "x": x, - "y": y, - "z": z - } - - # Highlight new tiles - for tile_key in new_highlighted_tiles: - var tile_data = new_highlighted_tiles[tile_key] - var tile = debug_map[tile_data.x][tile_data.y][tile_data.z] - if not tile["selected"]: - isometric_map_layers[tile_data.z].set_cell( - Vector2i(tile["x"], tile["y"]), - MAIN_SOURCE_ID, - tile["atlas_highlight_position"] - ) - else: - isometric_map_layers[tile_data.z].set_cell( - Vector2i(tile["x"], tile["y"]), - 1, - Vector2i(3,1) # - ) - - - tile["highlighted"] = true - - # De-highlight tiles that are no longer under the cursor - for tile_key in highlighted_tiles: - if not (tile_key in new_highlighted_tiles): - var tile_data = highlighted_tiles[tile_key] - var tile = debug_map[tile_data.x][tile_data.y][tile_data.z] - - if tile != null and tile["visibility"]: - - if not tile["selected"]: - isometric_map_layers[tile_data.z].set_cell( - Vector2i(tile["x"], tile["y"]), - MAIN_SOURCE_ID, - tile["atlas_base_position"] # Original appearance - ) - else: - isometric_map_layers[tile_data.z].set_cell( - Vector2i(tile["x"], tile["y"]), - 1, - Vector2i(0,1) # - ) - tile["highlighted"] = false - - # Update the highlighted tiles list - highlighted_tiles = new_highlighted_tiles - -func _ready() -> void: - # Store initial camera position - initial_camera_position = camera.position - initial_camera_zoom = camera.zoom - initialize_map_layers() - draw_visible_tiles() - -func _process(_delta: float) -> void: - pass - # isometric_grid_hover() - -func _input(event): - if event is InputEventMouseMotion: - isometric_grid_hover() - # Camera drag (pan) control - if event is InputEventMouseButton: - if event.button_index == MOUSE_BUTTON_RIGHT: - if event.pressed: - drag_start = event.position - drag_active = true - else: - drag_active = false - - # Zoom control with mouse wheel - if event.button_index == MOUSE_BUTTON_WHEEL_DOWN: - zoom_camera(-zoom_speed) - elif event.button_index == MOUSE_BUTTON_WHEEL_UP: - zoom_camera(zoom_speed) - - # Handle camera movement while dragging - if event is InputEventMouseMotion and drag_active: - camera.position -= event.relative / camera.zoom - -func _on_reset_button_pressed() -> void: - # Reset camera position and zoom - - debug_map = create_debug_map_array() - initialize_map_layers() - draw_visible_tiles() - camera.position = initial_camera_position - camera.zoom = initial_camera_zoom - -func zoom_camera(zoom_amount): - var new_zoom = camera.zoom.x + zoom_amount - new_zoom = clamp(new_zoom, zoom_min, zoom_max) - camera.zoom = Vector2(new_zoom, new_zoom) - -func _on_cw_pressed() -> void: - _reset_class_values() - rotate_map_around_z_axis(3) - initialize_map_layers() - draw_visible_tiles() - -func _on_ccw_pressed() -> void: - _reset_class_values() - rotate_map_around_z_axis(1) - initialize_map_layers() - draw_visible_tiles() - -func _on_x_cw_pressed() -> void: - _reset_class_values() - rotate_map_around_x_axis(1) - initialize_map_layers() - draw_visible_tiles() - -func _on_x_ccw_pressed() -> void: - _reset_class_values() - rotate_map_around_x_axis(3) - initialize_map_layers() - draw_visible_tiles() - -func _on_y_cw_pressed() -> void: - _reset_class_values() - rotate_map_around_y_axis(3) - initialize_map_layers() - draw_visible_tiles() - -func _on_y_ccw_pressed() -> void: - _reset_class_values() - rotate_map_around_y_axis(1) - initialize_map_layers() - draw_visible_tiles() - - - -func _reset_class_values(): - highlighted_tiles = {} - last_click_time = 0.0 - clicked_position = Vector2i(1, 1) - is_tile_selected = false +var map_data : IsometricMapData +var map_renderer : IsometricMapRenderer +var camera_controller : IsometricCameraController +var player_controller : IsometricPlayerController +# Timing for click detection var click_delay: float = 0.2 var last_click_time: float = 0.0 var clicked_position: Vector2i = Vector2i(1, 1) var is_tile_selected: bool = false -func tile_selction_logic(): - for z in GRID_SIZE_HEIGHT: - for x in GRID_SIZE_WIDTH: - for y in GRID_SIZE_LENGTH: - var tile = debug_map[x][y][z] - if tile["selected"] and tile["highlighted"]: - isometric_map_layers[z].set_cell( - Vector2i(tile["x"], tile["y"]), - 1, - Vector2i(0,1) # - ) - tile["selected"] = false - if tile["selected"] and not tile["highlighted"]: - isometric_map_layers[z].set_cell( - Vector2i(tile["x"], tile["y"]), - 0, - Vector2i(0,0) # - ) - tile["selected"] = false - if not tile["selected"] and tile["highlighted"]: - isometric_map_layers[z].set_cell( - Vector2i(tile["x"], tile["y"]), - 1, - Vector2i(3,1) # - ) - tile["selected"] = true +func _ready() -> void: + # Initialize map data + map_data = IsometricMapData.new(50, 30, 30, 0) + map_data.create_default_map() - + # Initialize the renderer + map_renderer = IsometricMapRenderer.new(map_data, $TileMapLayer) + + # Initialize camera controller + camera_controller = IsometricCameraController.new(camera) + + # Draw initial map state + map_renderer.draw_visible_tiles() -func _unhandled_input(event: InputEvent) -> void: +func _process(_delta: float) -> void: + # This method intentionally left empty - handling done in _input + pass + +func _input(event: InputEvent) -> void: + # Handle camera movement + camera_controller.handle_input(event) + + # Handle hover effects + if event is InputEventMouseMotion: + map_renderer.handle_hover(get_global_mouse_position()) + + # Handle tile selection if event is InputEventMouseButton and event.pressed and event.button_index == MOUSE_BUTTON_LEFT: var current_time = Time.get_ticks_msec() / 1000.0 if current_time - last_click_time >= click_delay: last_click_time = current_time - tile_selction_logic() - elif event is InputEventKey and event.pressed and event.keycode == KEY_ESCAPE: - pass - #deselect_tile() - -var player_node - -func set_player(p): - player_node = p + map_renderer.handle_tile_selection() +# Set a player reference +func set_player(player): + player_controller = IsometricPlayerController.new(player, map_data, map_renderer) +# Initialize player position func init_player(): - var tile = debug_map[10][10][1] - tile["visibility"] = true - tile["unit"] = player_node - tile["unit_type"] ="PC" - var init_player_pos = iso_to_world(tile["x"], tile["y"], tile["z"]) - tile["unit"].set_unit_position(init_player_pos.x, init_player_pos.y, tile["z"]) + return player_controller.init_player() -func _move_up_or_down(up_or_down = "up"): - var z_offset = 0 - if up_or_down == "up": - z_offset = 1 - elif up_or_down == "down": - z_offset = -1 - var new_z = 0 - var new_y = 0 - var new_x = 0 - var tile = debug_map[0][0][0] - for z in GRID_SIZE_HEIGHT: - for x in GRID_SIZE_WIDTH: - for y in GRID_SIZE_LENGTH: - tile = debug_map[x][y][z] - if tile["unit_type"] == "PC": - new_z = z + z_offset - new_y = y - new_x = x - break - if tile["unit_type"] == "PC": - break - if tile["unit_type"] == "PC": - break - print("x ", new_x, " y ", new_y, " z ", new_z) - tile["unit"] = null - tile["unit_type"] = null - tile["visibility"] = null - - - var new_player_tile = debug_map[new_x][new_y][new_z] - new_player_tile["unit"] = player_node - new_player_tile["visibility"] = true - new_player_tile["unit_type"] ="PC" - var new_player_pos = iso_to_world(tile["x"], tile["y"], tile["z"]) - new_player_tile["unit"].set_unit_position(new_player_pos.x, new_player_pos.y, tile["z"]) +# Reset the map to initial state +func _on_reset_button_pressed() -> void: + # Recreate map data + map_data = IsometricMapData.new(50, 30, 30, 0) + map_data.create_default_map() - print(new_player_tile["x"], new_player_tile["y"], new_player_tile["z"]) - -func iso_to_world(tile_x, tile_y, player_z_layer = 0): - # Get the tile size from your tilemap - var tile_width = isometric_map_layers[player_z_layer].tile_set.tile_size.x - var tile_height = isometric_map_layers[player_z_layer].tile_set.tile_size.y + # Reinitialize map renderer + map_renderer.initialize_map_layers($TileMapLayer) + map_renderer.draw_visible_tiles() - # Calculate the world position - var world_x = (tile_x - tile_y) * (tile_width / 2) - var world_y = (tile_x + tile_y) * (tile_height / 2) - (player_z_layer * tile_height / 2) - - return Vector2(world_x, world_y) + # Reset camera + camera_controller.reset_camera() -# Converts world position to isometric tile coordinates -func world_to_iso(world_pos, player_z_layer = 0): - # Get the tile size from your tilemap - var tile_width = isometric_map_layers[player_z_layer].tile_set.tile_size.x - var tile_height = isometric_map_layers[player_z_layer].tile_set.tile_size.y - - # Adjust y position based on z-layer - var adjusted_y = world_pos.y + (player_z_layer * tile_height / 2) - - # Calculate the tile coordinates - var tile_x = (world_pos.x / (tile_width / 2) + adjusted_y / (tile_height / 2)) / 2 - var tile_y = (adjusted_y / (tile_height / 2) - world_pos.x / (tile_width / 2)) / 2 - - return Vector2i(round(tile_x), round(tile_y)) +# Rotation handlers +func _on_cw_pressed() -> void: + map_data.rotate_around_z_axis(3) + map_renderer.initialize_map_layers($TileMapLayer) + map_renderer.draw_visible_tiles() +func _on_ccw_pressed() -> void: + map_data.rotate_around_z_axis(1) + map_renderer.initialize_map_layers($TileMapLayer) + map_renderer.draw_visible_tiles() +func _on_x_cw_pressed() -> void: + map_data.rotate_around_x_axis(1) + map_renderer.initialize_map_layers($TileMapLayer) + map_renderer.draw_visible_tiles() +func _on_x_ccw_pressed() -> void: + map_data.rotate_around_x_axis(3) + map_renderer.initialize_map_layers($TileMapLayer) + map_renderer.draw_visible_tiles() +func _on_y_cw_pressed() -> void: + map_data.rotate_around_y_axis(3) + map_renderer.initialize_map_layers($TileMapLayer) + map_renderer.draw_visible_tiles() + +func _on_y_ccw_pressed() -> void: + map_data.rotate_around_y_axis(1) + map_renderer.initialize_map_layers($TileMapLayer) + map_renderer.draw_visible_tiles() + +# Player movement handlers func _on_player_z_layer_change_pressed() -> void: - _move_up_or_down("up") + print("Moving player up") + var success = player_controller.move_vertical("up") + print("Move success: ", success) + # Always redraw the visible tiles to ensure consistent state + map_renderer.draw_visible_tiles() func _on_player_z_layer_change_down_pressed() -> void: - _move_up_or_down("down") + print("Moving player down") + var success = player_controller.move_vertical("down") + print("Move success: ", success) + # Always redraw the visible tiles to ensure consistent state + map_renderer.draw_visible_tiles() diff --git a/scripts/isometric_map_renderer.gd b/scripts/isometric_map_renderer.gd new file mode 100644 index 0000000..220154e --- /dev/null +++ b/scripts/isometric_map_renderer.gd @@ -0,0 +1,189 @@ +extends Node +class_name IsometricMapRenderer + +var map_data = null +var isometric_map_layers = [] +var highlighted_tiles = {} # Dictionary to store all currently highlighted tiles + +var TILE_SIZE_ISOMETRIC_X = 32 # in px +var TILE_SIZE_ISOMETRIC_Y = 16 # in px + +# Initialize with reference to a map data object and a tilemap to use as template +func _init(map_data_ref, tilemap_template): + map_data = map_data_ref + initialize_map_layers(tilemap_template) + +# Initialize all the map layers for different heights +func initialize_map_layers(tilemap_template): + # Clear any existing layers + for layer in isometric_map_layers: + if is_instance_valid(layer): + layer.queue_free() + + isometric_map_layers.clear() + + # Create new layers for each height level + for z in map_data.GRID_SIZE_HEIGHT: + var new_layer = TileMapLayer.new() + new_layer.set_name("IsometricMapLayer_" + str(z)) + new_layer.tile_set = tilemap_template.tile_set + new_layer.z_index = z # Set the z-index to match the layer's height + + tilemap_template.get_parent().add_child(new_layer) + isometric_map_layers.append(new_layer) + +# Draw all visible tiles on the map +func draw_visible_tiles(): + # Clear all previously drawn tiles on each layer + for layer in isometric_map_layers: + layer.clear() + + # Draw the map + for z in map_data.GRID_SIZE_HEIGHT: + for y in map_data.GRID_SIZE_LENGTH: + for x in map_data.GRID_SIZE_WIDTH: + var tile = map_data.get_tile(x, y, z) + if tile != null and tile["visibility"] and tile["atlas_base_position"] != null: + # Use the layer that corresponds to the tile's z-value + if z < isometric_map_layers.size(): + isometric_map_layers[z].set_cell( + Vector2i(tile["x"], tile["y"]), + IsometricMapSystem.MAIN_SOURCE_ID, + tile["atlas_base_position"] + ) + +# Handle hovering over tiles +func handle_hover(mouse_position): + var hover_tile_position = isometric_map_layers[0].local_to_map(mouse_position) + var new_highlighted_tiles = {} # Will store tiles to highlight this frame + + # First find all tiles that should be highlighted + for z in map_data.GRID_SIZE_HEIGHT: + for x in map_data.GRID_SIZE_WIDTH: + for y in map_data.GRID_SIZE_LENGTH: + var tile = map_data.get_tile(x, y, z) + + if tile != null and tile["visibility"] and not tile["unit"]: + if tile["x"] == hover_tile_position.x and tile["y"] == hover_tile_position.y: + # Store this tile for highlighting + var tile_key = str(x) + "_" + str(y) + "_" + str(z) + + new_highlighted_tiles[tile_key] = { + "x": x, + "y": y, + "z": z + } + + # Highlight new tiles + for tile_key in new_highlighted_tiles: + var tile_data = new_highlighted_tiles[tile_key] + var tile = map_data.get_tile(tile_data.x, tile_data.y, tile_data.z) + if tile == null: + continue + + if not tile["selected"] and not tile["unit"]: + # Only set cell if we have a valid highlight position + if tile["atlas_highlight_position"] != null: + isometric_map_layers[tile_data.z].set_cell( + Vector2i(tile["x"], tile["y"]), + IsometricMapSystem.MAIN_SOURCE_ID, + tile["atlas_highlight_position"] + ) + else: + isometric_map_layers[tile_data.z].set_cell( + Vector2i(tile["x"], tile["y"]), + 1, + Vector2i(3,1) # + ) + + tile["highlighted"] = true + + # De-highlight tiles that are no longer under the cursor + for tile_key in highlighted_tiles: + if not (tile_key in new_highlighted_tiles): + var tile_data = highlighted_tiles[tile_key] + var tile = map_data.get_tile(tile_data.x, tile_data.y, tile_data.z) + + if tile != null and tile["visibility"] and not tile["unit"]: + + if not tile["selected"]: + # Only set cell if we have a valid base position + if tile["atlas_base_position"] != null: + isometric_map_layers[tile_data.z].set_cell( + Vector2i(tile["x"], tile["y"]), + IsometricMapSystem.MAIN_SOURCE_ID, + tile["atlas_base_position"] # Original appearance + ) + else: + isometric_map_layers[tile_data.z].set_cell( + Vector2i(tile["x"], tile["y"]), + 1, + Vector2i(0,1) # + ) + tile["highlighted"] = false + + # Update the highlighted tiles list + highlighted_tiles = new_highlighted_tiles + +# Handle tile selection logic +func handle_tile_selection(): + for z in map_data.GRID_SIZE_HEIGHT: + for x in map_data.GRID_SIZE_WIDTH: + for y in map_data.GRID_SIZE_LENGTH: + var tile = map_data.get_tile(x, y, z) + if tile == null or not tile["visibility"]: + continue + + # Get valid coordinates + var tile_x = tile["x"] + var tile_y = tile["y"] + + if tile["selected"] and tile["highlighted"]: + print("direct de selected: ", Vector2i(tile_x, tile_y)) + isometric_map_layers[z].set_cell( + Vector2i(tile_x, tile_y), + IsometricMapSystem.MAIN_SOURCE_ID, + IsometricMapSystem.SELECTED_BLUE_ISOMETRICTILE_ATLAS_POSITION + ) + tile["selected"] = false + + elif tile["selected"] and not tile["highlighted"]: + print("old de selected: ", Vector2i(tile_x, tile_y)) + # If there's a base position, restore it, otherwise use a default + if tile["atlas_base_position"] != null: + isometric_map_layers[z].set_cell( + Vector2i(tile_x, tile_y), + IsometricMapSystem.MAIN_SOURCE_ID, + tile["atlas_base_position"] + ) + else: + isometric_map_layers[z].set_cell( + Vector2i(tile_x, tile_y), + IsometricMapSystem.MAIN_SOURCE_ID, + IsometricMapSystem.BLUE_ISOMETRICTILE_ATLAS_POSITION + ) + tile["selected"] = false + + elif not tile["selected"] and tile["highlighted"]: + print("new selected: ", Vector2i(tile_x, tile_y)) + isometric_map_layers[z].set_cell( + Vector2i(tile_x, tile_y), + IsometricMapSystem.MAIN_SOURCE_ID, + IsometricMapSystem.SELECTED_WHITE_ISOMETRICTILE_ATLAS_POSITION + ) + tile["selected"] = true + +# Position a unit on the map visually +func position_unit(unit, tile_x, tile_y, tile_z): + var world_pos = IsometricMapSystem.iso_to_world( + tile_x, + tile_y, + tile_z, + TILE_SIZE_ISOMETRIC_X, + TILE_SIZE_ISOMETRIC_Y + ) + + unit.z_index = tile_z + # Assuming unit has a set_unit_position method to handle actual positioning + if unit.has_method("set_unit_position"): + unit.set_unit_position(world_pos.x, world_pos.y, tile_z) diff --git a/scripts/isometric_map_renderer.gd.uid b/scripts/isometric_map_renderer.gd.uid new file mode 100644 index 0000000..351e952 --- /dev/null +++ b/scripts/isometric_map_renderer.gd.uid @@ -0,0 +1 @@ +uid://bkjmtgsjwhna4 diff --git a/scripts/isometric_map_system.gd b/scripts/isometric_map_system.gd new file mode 100644 index 0000000..6f592af --- /dev/null +++ b/scripts/isometric_map_system.gd @@ -0,0 +1,68 @@ +extends Node + +# Constants for tile types/colors +const MAIN_SOURCE_ID = 1 +const BLUE_ISOMETRICTILE_ATLAS_POSITION = Vector2i(0,0) +const RED_ISOMETRICTILE_ATLAS_POSITION = Vector2i(1,0) +const GREEN_ISOMETRICTILE_ATLAS_POSITION = Vector2i(2,0) +const WHITE_ISOMETRICTILE_ATLAS_POSITION = Vector2i(3,0) +const BLACK_ISOMETRICTILE_ATLAS_POSITION = Vector2i(4,0) +const PURPLE_ISOMETRICTILE_ATLAS_POSITION = Vector2i(5,0) +const ORANGE_ISOMETRICTILE_ATLAS_POSITION = Vector2i(6,0) +const LOW_ALPHA_BLOCK_ISOMETRICTILE_ATLAS_POSITION = Vector2i(7,0) +const SELECTED_BLUE_ISOMETRICTILE_ATLAS_POSITION = Vector2i(0,1) +const SELECTED_RED_ISOMETRICTILE_ATLAS_POSITION = Vector2i(1,1) +const SELECTED_GREEN_ISOMETRICTILE_ATLAS_POSITION = Vector2i(2,1) +const SELECTED_WHITE_ISOMETRICTILE_ATLAS_POSITION = Vector2i(3,1) +const SELECTED_BLACK_ISOMETRICTILE_ATLAS_POSITION = Vector2i(4,1) +const SELECTED_PURPLE_ISOMETRICTILE_ATLAS_POSITION = Vector2i(5,1) +const SELECTED_ORANGE_ISOMETRICTILE_ATLAS_POSITION = Vector2i(6,1) +# Debug flags +var debug_enabled = true + +# Debug function that only prints when debug is enabled +func debug_print(message): + if debug_enabled: + print("[IsometricMapSystem] " + str(message)) + +# Utility functions for conversion between coordinate systems +func iso_to_world(tile_x, tile_y, player_z_layer = 0, tile_width = 32, tile_height = 16): + # Calculate the world position from isometric coordinates + var world_x = (tile_x - tile_y) * (tile_width / 2) + var world_y = (tile_x + tile_y) * (tile_height / 2) - (player_z_layer * tile_height / 2) + + return Vector2(world_x, world_y) + +# Converts world position to isometric tile coordinates +func world_to_iso(world_pos, player_z_layer = 0, tile_width = 32, tile_height = 16): + # Adjust y position based on z-layer + var adjusted_y = world_pos.y + (player_z_layer * tile_height / 2) + + # Calculate the tile coordinates + var tile_x = (world_pos.x / (tile_width / 2) + adjusted_y / (tile_height / 2)) / 2 + var tile_y = (adjusted_y / (tile_height / 2) - world_pos.x / (tile_width / 2)) / 2 + + return Vector2i(round(tile_x), round(tile_y)) + +# Create a new tile data structure with default values +func create_tile_data(coord_x, coord_y, z, atlas_base_position = null, atlas_highlight_position = null): + # Ensure we have valid default positions to avoid null reference errors + var base_pos = atlas_base_position if atlas_base_position != null else BLUE_ISOMETRICTILE_ATLAS_POSITION + var highlight_pos = atlas_highlight_position if atlas_highlight_position != null else WHITE_ISOMETRICTILE_ATLAS_POSITION + + return { + "x": coord_x, + "y": coord_y, + "z": z, + "atlas_base_position": null, + "atlas_highlight_position": null, + "highlighted": false, + "selected": false, + "hp": 100, + "armour": 0, + "destroyable": false, + "visibility": false, + "unit": null, + "unit_type": null, # PC (more options e.g. can move it) or NPC (can only view it) + "gravity": null, + } diff --git a/scripts/isometric_map_system.gd.uid b/scripts/isometric_map_system.gd.uid new file mode 100644 index 0000000..2f4ae0e --- /dev/null +++ b/scripts/isometric_map_system.gd.uid @@ -0,0 +1 @@ +uid://buyf5d883rdj5 diff --git a/scripts/isometric_player_controller.gd b/scripts/isometric_player_controller.gd new file mode 100644 index 0000000..551cb9c --- /dev/null +++ b/scripts/isometric_player_controller.gd @@ -0,0 +1,74 @@ +extends Node +class_name IsometricPlayerController + +var player_node +var map_data +var map_renderer + +func _init(player, map_data_ref, renderer): + player_node = player + map_data = map_data_ref + map_renderer = renderer + +# Initialize player at a specific position +func init_player(x=10, y=10, z=1): + var tile = map_data.get_tile(x, y, z) + if tile: + tile["visibility"] = true + tile["unit"] = player_node + tile["unit_type"] = "PC" + + # Use renderer to position the player + map_renderer.position_unit(player_node, tile["x"], tile["y"], tile["z"]) + return true + return false + +# Move player up or down a layer +func move_vertical(direction = "up"): + var z_offset = 0 + if direction == "up": + z_offset = 1 + elif direction == "down": + z_offset = -1 + + # Find current player position + var player_position = map_data.find_unit_tile("PC") + if not player_position: + print("Cannot find player position") + return false + + var current_x = player_position.x + var current_y = player_position.y + var current_z = player_position.z + var new_z = current_z + z_offset + + # Check if new position is valid + if new_z < 0 or new_z >= map_data.GRID_SIZE_HEIGHT: + print("New Z position out of bounds: ", new_z) + return false + + # Check if destination tile exists + var destination_tile = map_data.get_tile(current_x, current_y, new_z) + if destination_tile == null: + print("Destination tile doesn't exist at: ", current_x, ", ", current_y, ", ", new_z) + return false + + # Debug the current tile before moving + var current_tile = map_data.get_tile(current_x, current_y, current_z) + print("Current tile before move: ", current_tile) + + # Set up the destination tile to receive the player + destination_tile["unit"] = current_tile["unit"] + destination_tile["unit_type"] = "PC" + destination_tile["visibility"] = true + + # Clear the current tile's unit data + current_tile["unit"] = null + current_tile["unit_type"] = null + destination_tile["visibility"] = false + + # Update visual position + map_renderer.position_unit(player_node, destination_tile["x"], destination_tile["y"], destination_tile["z"]) + print("Player moved to: ", current_x, ", ", current_y, ", ", new_z) + + return true diff --git a/scripts/isometric_player_controller.gd.uid b/scripts/isometric_player_controller.gd.uid new file mode 100644 index 0000000..084152f --- /dev/null +++ b/scripts/isometric_player_controller.gd.uid @@ -0,0 +1 @@ +uid://bvqgwafyxcr8r diff --git a/scripts/player.gd b/scripts/player.gd index 867f446..b9fd6fa 100644 --- a/scripts/player.gd +++ b/scripts/player.gd @@ -2,6 +2,21 @@ extends CharacterBody2D @onready var collision_shape_2d: CollisionShape2D = $CollisionShape2D @onready var animated_sprite: AnimatedSprite2D = $AnimatedSprite2D +@onready var player: CharacterBody2D = $"." + +var hovered_unit = null + +var hover_indicator = preload("res://assets/sprites/ui/ui_icons_green_down4.png") + +func _ready(): + + var hover_sprite = Sprite2D.new() + hover_sprite.texture = hover_indicator + hover_sprite.position.y = -15 + hover_sprite.visible = false + hover_sprite.name = "HoverIndicator" + hover_sprite.z_index = 100 + player.add_child(hover_sprite) var player_data = { "stats": { @@ -13,22 +28,52 @@ var player_data = { "inventory": [], "name": "Hero" } - - - +func _input(event): + if event is InputEventMouseMotion: + check_hover() + +func check_hover(): + var mouse_pos = get_global_mouse_position() + print("Mouse pos: ", mouse_pos, " Player pos: ", player.position) + + if hovered_unit: + hovered_unit.get_node("HoverIndicator").visible = false + hovered_unit = null + + if player.has_node("CollisionShape2D"): + var collision = player.get_node("CollisionShape2D") + var shape = collision.shape + + var local_pos = player.to_local(mouse_pos) + + if shape is RectangleShape2D: + var extents = shape.extents + if local_pos.x >= -extents.x and local_pos.x <= extents.x and \ + local_pos.y >= -extents.y and local_pos.y <= extents.y: + hovered_unit = player + player.get_node("HoverIndicator").visible = true + + func set_unit_position(x, y, z): var z_layer = z - var x_position = x + #var x_position = x + var x_position = x + 16 var y_position = y + #var y_position = y + get_sprite_size().size.y/2 # Update the visual z-index directly animated_sprite.z_index = z_layer animated_sprite.position = Vector2i(x_position, y_position) + print("Palyer Global Pos: ", animated_sprite.position) print("Palyer Z-Layer: ", z_layer) - + +func get_sprite_size(): + return collision_shape_2d.shape func _process(_delta: float): - play_idle_animation() + check_hover() + play_player_animation("idle") -func play_idle_animation(): - animated_sprite.play("down") +func play_player_animation(state="idle"): + if state == "idle": + animated_sprite.play("down")