Merge pull request '[Feature]: Tower Placement' (!7) from story/TD-11-tower-platzieren into trunk
All checks were successful
Quality Check / Linting (push) Successful in 6s

Reviewed-on: #7
Reviewed-by: SZUT-Rajbir <rajbir2@schule.bremen.de>
This commit is contained in:
SZUT-Kevin 2025-03-11 07:17:34 +00:00 committed by Euph Forge
commit 8342b744a7
Signed by: Euph Forge
GPG key ID: 85A06461FB6BDBB7
12 changed files with 222 additions and 26 deletions

View file

@ -3,7 +3,7 @@ _choose:
lint: lint:
-gdlint . -gdlint .
-gdformat -d . -gdformat .
api_version := "v0.0.0-rc.4" api_version := "v0.0.0-rc.4"
api_location := "scripts/api-client" api_location := "scripts/api-client"

View file

@ -26,8 +26,6 @@ CurrentMatch="*res://scripts/match/current_match.gd"
window/size/viewport_width=1920 window/size/viewport_width=1920
window/size/viewport_height=1080 window/size/viewport_height=1080
window/stretch/mode="viewport"
window/stretch/aspect="expand"
[editor_plugins] [editor_plugins]
@ -37,6 +35,14 @@ enabled=PackedStringArray("res://addons/format_on_save/plugin.cfg")
theme/custom="res://ui/theme.tres" theme/custom="res://ui/theme.tres"
[input]
place={
"deadzone": 0.0,
"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":0,"position":Vector2(0, 0),"global_position":Vector2(0, 0),"factor":1.0,"button_index":1,"canceled":false,"pressed":false,"double_click":false,"script":null)
]
}
[rendering] [rendering]
renderer/rendering_method="gl_compatibility" renderer/rendering_method="gl_compatibility"

View file

@ -1,13 +1,18 @@
[gd_scene load_steps=3 format=3 uid="uid://co1x3hlc2efr6"] [gd_scene load_steps=6 format=4 uid="uid://co1x3hlc2efr6"]
[ext_resource type="Script" path="res://scripts/match/ui/opponent_name.gd" id="1_saby1"] [ext_resource type="Script" path="res://scripts/match/ui/opponent_name.gd" id="1_saby1"]
[ext_resource type="Script" path="res://scripts/match/ui/current_game_time.gd" id="2_3jcub"] [ext_resource type="Script" path="res://scripts/match/ui/current_game_time.gd" id="2_3jcub"]
[ext_resource type="TileSet" uid="uid://cvp867israfjk" path="res://tile_set.tres" id="3_0etcd"]
[ext_resource type="Script" path="res://scripts/match/map.gd" id="4_4c550"]
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_86u83"]
bg_color = Color(0.198848, 0.584132, 0.720474, 1)
[node name="Game" type="Node2D"] [node name="Game" type="Node2D"]
[node name="CanvasLayer" type="CanvasLayer" parent="."] [node name="UI" type="CanvasLayer" parent="."]
[node name="HUD" type="Control" parent="CanvasLayer"] [node name="HUD" type="Control" parent="UI"]
layout_mode = 3 layout_mode = 3
anchors_preset = 15 anchors_preset = 15
anchor_right = 1.0 anchor_right = 1.0
@ -15,7 +20,7 @@ anchor_bottom = 1.0
grow_horizontal = 2 grow_horizontal = 2
grow_vertical = 2 grow_vertical = 2
[node name="Opponent Name" type="RichTextLabel" parent="CanvasLayer/HUD"] [node name="Opponent Name" type="RichTextLabel" parent="UI/HUD"]
layout_mode = 1 layout_mode = 1
anchors_preset = 5 anchors_preset = 5
anchor_left = 0.5 anchor_left = 0.5
@ -30,7 +35,7 @@ scroll_active = false
autowrap_mode = 0 autowrap_mode = 0
script = ExtResource("1_saby1") script = ExtResource("1_saby1")
[node name="Time" type="RichTextLabel" parent="CanvasLayer/HUD"] [node name="Time" type="RichTextLabel" parent="UI/HUD"]
layout_mode = 1 layout_mode = 1
anchors_preset = 8 anchors_preset = 8
anchor_left = 0.5 anchor_left = 0.5
@ -47,3 +52,34 @@ fit_content = true
scroll_active = false scroll_active = false
autowrap_mode = 0 autowrap_mode = 0
script = ExtResource("2_3jcub") script = ExtResource("2_3jcub")
[node name="Seperator" type="Panel" parent="UI/HUD"]
custom_minimum_size = Vector2(4, 0)
layout_mode = 1
anchors_preset = 13
anchor_left = 0.5
anchor_right = 0.5
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
theme_override_styles/panel = SubResource("StyleBoxFlat_86u83")
[node name="Camera" type="Camera2D" parent="."]
[node name="Map" type="Node2D" parent="." node_paths=PackedStringArray("player_map", "player_tower_map", "opponent_map", "opponent_tower_map", "camera")]
script = ExtResource("4_4c550")
tile_set = ExtResource("3_0etcd")
player_map = NodePath("PlayerMap")
player_tower_map = NodePath("PlayerMap/Tower")
opponent_map = NodePath("OpentMap")
opponent_tower_map = NodePath("OpentMap/Tower")
camera = NodePath("../Camera")
[node name="PlayerMap" type="Node2D" parent="Map"]
[node name="Tower" type="TileMapLayer" parent="Map/PlayerMap"]
[node name="OpentMap" type="Node2D" parent="Map"]
[node name="Tower" type="TileMapLayer" parent="Map/OpentMap"]
tile_map_data = PackedByteArray("AAAAAAAAAQAAAAAAAAAAAAEAAQAAAAAAAAAAAAIAAQAAAAAAAAAAAAMAAQAAAAAAAAAAAAQAAQAAAAAAAAAAAAUAAQAAAAAAAAAAAAYAAQAAAAAAAAAAAAcAAQAAAAAAAAAAAAgAAQAAAAAAAAAAAAkAAQAAAAAAAAAAAAoAAQAAAAAAAAAAAAsAAQAAAAAAAAAAAAwAAQAAAAAAAAAAAA0AAQAAAAAAAAAAAA4AAQAAAAAAAAAAAA8AAQAAAAAAAAAAABAAAQAAAAAAAAAAABEAAQAAAAAAAAAAABIAAQAAAAAAAAAAABMAAQAAAAAAAAABAAAAAQAAAAAAAAABABMAAQAAAAAAAAACAAAAAQAAAAAAAAACABMAAQAAAAAAAAADAAAAAQAAAAAAAAADABMAAQAAAAAAAAAEAAAAAQAAAAAAAAAEABMAAQAAAAAAAAAFAAAAAQAAAAAAAAAFABMAAQAAAAAAAAAGAAAAAQAAAAAAAAAGABMAAQAAAAAAAAAHAAAAAQAAAAAAAAAHABMAAQAAAAAAAAAIAAAAAQAAAAAAAAAIABMAAQAAAAAAAAAJAAAAAQAAAAAAAAAJAAEAAQAAAAAAAAAJAAIAAQAAAAAAAAAJAAMAAQAAAAAAAAAJAAQAAQAAAAAAAAAJAAUAAQAAAAAAAAAJAAYAAQAAAAAAAAAJAAcAAQAAAAAAAAAJAAgAAQAAAAAAAAAJAAkAAQAAAAAAAAAJAAoAAQAAAAAAAAAJAAsAAQAAAAAAAAAJAAwAAQAAAAAAAAAJAA0AAQAAAAAAAAAJAA4AAQAAAAAAAAAJAA8AAQAAAAAAAAAJABAAAQAAAAAAAAAJABEAAQAAAAAAAAAJABIAAQAAAAAAAAAJABMAAQAAAAAAAAA=")

View file

@ -1,12 +0,0 @@
class_name CurrentUnixTimeMessage
extends Message
const MESSAGE_ID: String = "CurrentUnixTime"
@export var time: int
# gdlint:ignore = class-variable-name
@export var matchId: String
func get_message_id() -> String:
return MESSAGE_ID

View file

@ -0,0 +1,13 @@
class_name InvalidPlacementMessage
extends Message
enum Reason { OUT_OF_BOUNDS, LOCATION_USED }
const MESSAGE_ID: String = "InvalidPlacement"
@export var x: int
@export var y: int
@export var reason: Reason
func get_message_id() -> String:
return MESSAGE_ID

View file

@ -1,6 +1,7 @@
extends Channel extends Channel
signal on_match_update(msg: CurrentUnixTimeMessage) signal on_match_update(msg: TowerPlacedMessage)
signal on_invalid_placing(msg: InvalidPlacementMessage)
func get_channel_location() -> String: func get_channel_location() -> String:
@ -12,9 +13,26 @@ func _process(_delta: float) -> void:
if self.socket.get_ready_state() != WebSocketPeer.STATE_OPEN: if self.socket.get_ready_state() != WebSocketPeer.STATE_OPEN:
return return
while self.socket.get_available_packet_count(): while self.socket.get_available_packet_count():
var msg := CurrentUnixTimeMessage.deserialize( var msg: Message = (
self.socket.get_packet().get_string_from_utf8(), [CurrentUnixTimeMessage] CurrentUnixTimeMessage
. deserialize(
self.socket.get_packet().get_string_from_utf8(),
[TowerPlacedMessage, InvalidPlacementMessage],
) )
if msg.get_message_id() != CurrentUnixTimeMessage.MESSAGE_ID: )
return match msg.get_message_id():
TowerPlacedMessage.MESSAGE_ID:
on_match_update.emit(msg) on_match_update.emit(msg)
InvalidPlacementMessage.MESSAGE_ID:
on_invalid_placing.emit(msg)
_:
continue
func send_request_place(x: int, y: int) -> void:
if self.socket.get_ready_state() != WebSocketPeer.STATE_OPEN:
return
var msg := RequestTowerPlacingMessage.new()
msg.x = x
msg.y = y
self.socket.send_text(Message.serialize(msg))

View file

@ -0,0 +1,11 @@
class_name RequestTowerPlacingMessage
extends Message
const MESSAGE_ID: String = "RequestTowerPlacing"
@export var x: int
@export var y: int
func get_message_id() -> String:
return MESSAGE_ID

View file

@ -0,0 +1,13 @@
class_name TowerPlacedMessage
extends Message
enum GamePlayerMaps { PLAYER, OPPONENT }
const MESSAGE_ID: String = "TowerPlaced"
@export var x: int
@export var y: int
@export var map: GamePlayerMaps
func get_message_id() -> String:
return MESSAGE_ID

65
scripts/match/map.gd Normal file
View file

@ -0,0 +1,65 @@
extends Node2D
@export var tile_set: TileSet
@export var player_map: Node2D
@export var player_tower_map: TileMapLayer
@export var opponent_map: Node2D
@export var opponent_tower_map: TileMapLayer
@export var map_size := Vector2i(10, 20)
@export var camera: Camera2D
var clicked: bool = false
var clicked_pos: Vector2
func _ready() -> void:
player_tower_map.tile_set = tile_set
opponent_tower_map.tile_set = tile_set
player_tower_map.clear()
opponent_tower_map.clear()
MatchChannel.connect("on_match_update", on_match_update)
func _process(_delta: float) -> void:
# gdlint:ignore = max-line-length
var new_zoom := float(get_window().size.y) / float(map_size.y * tile_set.tile_size.y)
camera.zoom = Vector2(new_zoom, new_zoom)
var new_base_postion := get_window().size / 2 / new_zoom
camera.position = new_base_postion
self.position.x = new_base_postion.x - map_size.x * tile_set.tile_size.x
opponent_map.position.x = map_size.x * tile_set.tile_size.x
func _input(_event) -> void:
if Input.is_action_just_pressed("place"):
clicked_pos = get_global_mouse_position()
clicked = true
func _physics_process(_delta: float) -> void:
if clicked:
clicked = false
var pos: Vector2i = world_to_game_pos(clicked_pos)
if pos == Vector2i(-1, -1):
return
MatchChannel.send_request_place(pos.x, pos.y)
func on_match_update(msg: TowerPlacedMessage) -> void:
if msg.map == TowerPlacedMessage.GamePlayerMaps.PLAYER:
player_tower_map.set_cell(Vector2i(msg.x, msg.y), 1, Vector2i(0, 0))
else:
opponent_tower_map.set_cell(Vector2i(msg.x, msg.y), 1, Vector2i(0, 0))
func world_to_game_pos(world_pos: Vector2) -> Vector2i:
if (
world_pos.x < self.position.x
|| world_pos.x > self.position.x + map_size.x * tile_set.tile_size.x
):
return Vector2i(-1, -1)
return Vector2i(
(world_pos.x - self.position.x) / tile_set.tile_size.x,
world_pos.y / tile_set.tile_size.y,
)

BIN
textures/tiles/tower.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 161 B

View file

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://bj8jwha8g5y8n"
path="res://.godot/imported/tower.png-afe2561faadc2586f630d8a5c5939231.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://textures/tiles/tower.png"
dest_files=["res://.godot/imported/tower.png-afe2561faadc2586f630d8a5c5939231.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

12
tile_set.tres Normal file
View file

@ -0,0 +1,12 @@
[gd_resource type="TileSet" load_steps=3 format=3 uid="uid://cvp867israfjk"]
[ext_resource type="Texture2D" uid="uid://bj8jwha8g5y8n" path="res://textures/tiles/tower.png" id="1_4stpq"]
[sub_resource type="TileSetAtlasSource" id="TileSetAtlasSource_tivyh"]
texture = ExtResource("1_4stpq")
texture_region_size = Vector2i(32, 32)
0:0/0 = 0
[resource]
tile_size = Vector2i(32, 32)
sources/1 = SubResource("TileSetAtlasSource_tivyh")