working updates
This commit is contained in:
@@ -7,9 +7,9 @@ signal clicked(card_visual: CardVisual)
|
||||
signal hovered(card_visual: CardVisual)
|
||||
signal unhovered(card_visual: CardVisual)
|
||||
|
||||
# Card dimensions (standard card ratio ~2.5:3.5)
|
||||
const CARD_WIDTH: float = 0.63
|
||||
const CARD_HEIGHT: float = 0.88
|
||||
# Card dimensions (doubled for readability, standard card ratio ~2.5:3.5)
|
||||
const CARD_WIDTH: float = 1.26
|
||||
const CARD_HEIGHT: float = 1.76
|
||||
const CARD_THICKNESS: float = 0.02
|
||||
|
||||
# Associated card instance
|
||||
@@ -23,8 +23,10 @@ var is_hovered: bool = false
|
||||
# Animation
|
||||
var target_position: Vector3 = Vector3.ZERO
|
||||
var target_rotation: Vector3 = Vector3.ZERO
|
||||
var base_position: Vector3 = Vector3.ZERO # Position set by zone arrangement (before hover offset)
|
||||
var move_speed: float = 10.0
|
||||
var is_animating: bool = false
|
||||
const HOVER_LIFT: float = 0.15
|
||||
|
||||
# Components
|
||||
var mesh_instance: MeshInstance3D
|
||||
@@ -46,14 +48,21 @@ func _create_card_mesh() -> void:
|
||||
mesh_instance = MeshInstance3D.new()
|
||||
add_child(mesh_instance)
|
||||
|
||||
# Create box mesh for card
|
||||
var box = BoxMesh.new()
|
||||
box.size = Vector3(CARD_WIDTH, CARD_THICKNESS, CARD_HEIGHT)
|
||||
mesh_instance.mesh = box
|
||||
# Create a quad mesh for the card face (more appropriate for card textures)
|
||||
var quad = QuadMesh.new()
|
||||
quad.size = Vector2(CARD_WIDTH, CARD_HEIGHT)
|
||||
mesh_instance.mesh = quad
|
||||
|
||||
# Rotate to lay flat on table (facing up)
|
||||
mesh_instance.rotation_degrees.x = -90
|
||||
|
||||
# Slight offset up so it's above the table
|
||||
mesh_instance.position.y = CARD_THICKNESS / 2
|
||||
|
||||
# Create material
|
||||
material = StandardMaterial3D.new()
|
||||
material.albedo_color = Color.WHITE
|
||||
material.cull_mode = BaseMaterial3D.CULL_DISABLED # Show both sides
|
||||
mesh_instance.material_override = material
|
||||
|
||||
func _setup_collision() -> void:
|
||||
@@ -99,8 +108,10 @@ func _load_card_texture() -> void:
|
||||
var texture = CardDatabase.get_card_texture(card_instance.card_data)
|
||||
if texture:
|
||||
material.albedo_texture = texture
|
||||
material.albedo_color = Color.WHITE # Reset to white so texture shows properly
|
||||
else:
|
||||
# Use element color as fallback
|
||||
# Use element color as fallback when no texture
|
||||
material.albedo_texture = null
|
||||
var element_color = Enums.element_to_color(card_instance.get_element())
|
||||
material.albedo_color = element_color
|
||||
|
||||
@@ -109,18 +120,22 @@ func _update_visual_state() -> void:
|
||||
if not material:
|
||||
return
|
||||
|
||||
var color = normal_color
|
||||
# Only apply color tints if we don't have a texture, or for highlight/dull effects
|
||||
var has_texture = material.albedo_texture != null
|
||||
var base_color = Color.WHITE if has_texture else normal_color
|
||||
|
||||
if is_selected:
|
||||
color = selected_color
|
||||
# Slight green tint for selection
|
||||
base_color = base_color * Color(0.9, 1.1, 0.9)
|
||||
elif is_highlighted:
|
||||
color = highlight_color
|
||||
# Slight yellow tint for highlight
|
||||
base_color = base_color * Color(1.1, 1.1, 0.9)
|
||||
|
||||
# Apply dull tint
|
||||
# Apply dull tint (darkening)
|
||||
if card_instance and card_instance.is_dull():
|
||||
color = color * dull_tint
|
||||
base_color = base_color * dull_tint
|
||||
|
||||
material.albedo_color = color
|
||||
material.albedo_color = base_color
|
||||
|
||||
## Set card as highlighted
|
||||
func set_highlighted(highlighted: bool) -> void:
|
||||
@@ -134,12 +149,16 @@ func set_selected(selected: bool) -> void:
|
||||
|
||||
## Move card to position with animation
|
||||
func move_to(pos: Vector3, rot: Vector3 = Vector3.ZERO) -> void:
|
||||
base_position = pos
|
||||
target_position = pos
|
||||
if is_hovered:
|
||||
target_position.y = pos.y + HOVER_LIFT
|
||||
target_rotation = rot
|
||||
is_animating = true
|
||||
|
||||
## Move card instantly
|
||||
func set_position_instant(pos: Vector3, rot: Vector3 = Vector3.ZERO) -> void:
|
||||
base_position = pos
|
||||
position = pos
|
||||
rotation = rot
|
||||
target_position = pos
|
||||
@@ -163,18 +182,16 @@ func _on_input_event(_camera: Node, event: InputEvent, _position: Vector3, _norm
|
||||
func _on_mouse_entered() -> void:
|
||||
is_hovered = true
|
||||
hovered.emit(self)
|
||||
# Slight raise on hover
|
||||
if not is_animating:
|
||||
target_position.y = position.y + 0.1
|
||||
is_animating = true
|
||||
# Raise card above base position on hover
|
||||
target_position.y = base_position.y + HOVER_LIFT
|
||||
is_animating = true
|
||||
|
||||
func _on_mouse_exited() -> void:
|
||||
is_hovered = false
|
||||
unhovered.emit(self)
|
||||
# Return to normal height
|
||||
if not is_animating and card_instance:
|
||||
target_position.y = position.y - 0.1
|
||||
is_animating = true
|
||||
# Return to base height
|
||||
target_position.y = base_position.y
|
||||
is_animating = true
|
||||
|
||||
## Get display info for UI
|
||||
func get_card_info() -> Dictionary:
|
||||
|
||||
189
scripts/visual/PlaymatRenderer.gd
Normal file
189
scripts/visual/PlaymatRenderer.gd
Normal file
@@ -0,0 +1,189 @@
|
||||
class_name PlaymatRenderer
|
||||
extends Node
|
||||
|
||||
## PlaymatRenderer - Generates a clean programmatic play mat texture using SubViewport
|
||||
## Layout matches FF-TCG official play mat zones:
|
||||
## Left: Damage Zone (top) / Turn Structure (bottom)
|
||||
## Center: Field (Forwards top, Backups bottom)
|
||||
## Right: Deck (top) / Break Zone (bottom)
|
||||
|
||||
const MAT_TEXTURE_WIDTH: int = 2048
|
||||
const MAT_TEXTURE_HEIGHT: int = 1024
|
||||
|
||||
# Color scheme - dark green felt table look
|
||||
const BG_COLOR := Color(0.12, 0.15, 0.12)
|
||||
const ZONE_BORDER_COLOR := Color(0.35, 0.40, 0.30)
|
||||
const ZONE_FILL_COLOR := Color(0.14, 0.18, 0.14)
|
||||
const LABEL_COLOR := Color(0.45, 0.50, 0.40)
|
||||
const FIELD_LINE_COLOR := Color(0.20, 0.25, 0.20)
|
||||
const TURN_TEXT_COLOR := Color(0.35, 0.40, 0.30)
|
||||
|
||||
# Zone regions as pixel rects in the texture
|
||||
# Left column: ~17% width
|
||||
const DAMAGE_RECT := Rect2(30, 30, 320, 460)
|
||||
const TURN_REF_RECT := Rect2(30, 520, 320, 474)
|
||||
# Center: ~66% width
|
||||
const FIELD_RECT := Rect2(380, 30, 1290, 964)
|
||||
# Right column: ~17% width
|
||||
const DECK_RECT := Rect2(1700, 30, 318, 440)
|
||||
const BREAK_RECT := Rect2(1700, 500, 318, 494)
|
||||
|
||||
# Border thickness
|
||||
const BORDER_WIDTH: int = 3
|
||||
|
||||
func render() -> ImageTexture:
|
||||
var viewport = SubViewport.new()
|
||||
viewport.size = Vector2i(MAT_TEXTURE_WIDTH, MAT_TEXTURE_HEIGHT)
|
||||
viewport.render_target_update_mode = SubViewport.UPDATE_ONCE
|
||||
viewport.transparent_bg = false
|
||||
|
||||
# Background
|
||||
var bg = ColorRect.new()
|
||||
bg.color = BG_COLOR
|
||||
bg.position = Vector2.ZERO
|
||||
bg.size = Vector2(MAT_TEXTURE_WIDTH, MAT_TEXTURE_HEIGHT)
|
||||
viewport.add_child(bg)
|
||||
|
||||
# Draw zone rectangles with borders and labels
|
||||
_draw_zone(viewport, DAMAGE_RECT, "DAMAGE ZONE")
|
||||
_draw_zone(viewport, DECK_RECT, "DECK")
|
||||
_draw_zone(viewport, BREAK_RECT, "BREAK ZONE")
|
||||
_draw_zone(viewport, FIELD_RECT, "FIELD")
|
||||
|
||||
# Divider line in Field (separating Forwards from Backups)
|
||||
var divider_y = FIELD_RECT.position.y + FIELD_RECT.size.y * 0.48
|
||||
_draw_dashed_line(viewport, Vector2(FIELD_RECT.position.x + 20, divider_y),
|
||||
Vector2(FIELD_RECT.position.x + FIELD_RECT.size.x - 20, divider_y))
|
||||
|
||||
# Forwards / Backups sub-labels
|
||||
_draw_label(viewport, "FORWARDS",
|
||||
Vector2(FIELD_RECT.position.x + FIELD_RECT.size.x / 2, FIELD_RECT.position.y + FIELD_RECT.size.y * 0.22), 32)
|
||||
_draw_label(viewport, "BACKUPS",
|
||||
Vector2(FIELD_RECT.position.x + FIELD_RECT.size.x / 2, FIELD_RECT.position.y + FIELD_RECT.size.y * 0.74), 32)
|
||||
|
||||
# Turn structure reference (decorative)
|
||||
_draw_turn_structure(viewport)
|
||||
|
||||
# Add outer border around entire mat
|
||||
_draw_border_rect(viewport, Rect2(5, 5, MAT_TEXTURE_WIDTH - 10, MAT_TEXTURE_HEIGHT - 10), ZONE_BORDER_COLOR, 2)
|
||||
|
||||
add_child(viewport)
|
||||
|
||||
# Wait for the viewport to render
|
||||
await RenderingServer.frame_post_draw
|
||||
|
||||
# Grab the rendered image
|
||||
var image = viewport.get_texture().get_image()
|
||||
var texture = ImageTexture.create_from_image(image)
|
||||
|
||||
# Clean up
|
||||
viewport.queue_free()
|
||||
|
||||
return texture
|
||||
|
||||
func _draw_zone(viewport: SubViewport, rect: Rect2, label_text: String) -> void:
|
||||
# Zone fill
|
||||
var fill = ColorRect.new()
|
||||
fill.color = ZONE_FILL_COLOR
|
||||
fill.position = rect.position
|
||||
fill.size = rect.size
|
||||
viewport.add_child(fill)
|
||||
|
||||
# Zone border (4 thin ColorRects forming a rectangle)
|
||||
_draw_border_rect(viewport, rect, ZONE_BORDER_COLOR, BORDER_WIDTH)
|
||||
|
||||
# Zone label centered at top of zone
|
||||
_draw_label(viewport, label_text,
|
||||
Vector2(rect.position.x + rect.size.x / 2, rect.position.y + 30), 28)
|
||||
|
||||
func _draw_border_rect(viewport: SubViewport, rect: Rect2, color: Color, width: int) -> void:
|
||||
# Top edge
|
||||
var top = ColorRect.new()
|
||||
top.color = color
|
||||
top.position = rect.position
|
||||
top.size = Vector2(rect.size.x, width)
|
||||
viewport.add_child(top)
|
||||
|
||||
# Bottom edge
|
||||
var bottom = ColorRect.new()
|
||||
bottom.color = color
|
||||
bottom.position = Vector2(rect.position.x, rect.position.y + rect.size.y - width)
|
||||
bottom.size = Vector2(rect.size.x, width)
|
||||
viewport.add_child(bottom)
|
||||
|
||||
# Left edge
|
||||
var left = ColorRect.new()
|
||||
left.color = color
|
||||
left.position = rect.position
|
||||
left.size = Vector2(width, rect.size.y)
|
||||
viewport.add_child(left)
|
||||
|
||||
# Right edge
|
||||
var right = ColorRect.new()
|
||||
right.color = color
|
||||
right.position = Vector2(rect.position.x + rect.size.x - width, rect.position.y)
|
||||
right.size = Vector2(width, rect.size.y)
|
||||
viewport.add_child(right)
|
||||
|
||||
func _draw_label(viewport: SubViewport, text: String, center_pos: Vector2, font_size: int) -> void:
|
||||
var label = Label.new()
|
||||
label.text = text
|
||||
label.add_theme_font_size_override("font_size", font_size)
|
||||
label.add_theme_color_override("font_color", LABEL_COLOR)
|
||||
label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||
label.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
|
||||
# Size the label wide enough and position so center_pos is the center
|
||||
var label_width = text.length() * font_size * 0.7
|
||||
var label_height = font_size * 1.5
|
||||
label.position = Vector2(center_pos.x - label_width / 2, center_pos.y - label_height / 2)
|
||||
label.size = Vector2(label_width, label_height)
|
||||
viewport.add_child(label)
|
||||
|
||||
func _draw_dashed_line(viewport: SubViewport, from: Vector2, to: Vector2) -> void:
|
||||
var dash_length = 20.0
|
||||
var gap_length = 15.0
|
||||
var direction = (to - from).normalized()
|
||||
var total_length = from.distance_to(to)
|
||||
var current = 0.0
|
||||
|
||||
while current < total_length:
|
||||
var dash_end = min(current + dash_length, total_length)
|
||||
var start_pos = from + direction * current
|
||||
var end_pos = from + direction * dash_end
|
||||
|
||||
var dash = ColorRect.new()
|
||||
dash.color = FIELD_LINE_COLOR
|
||||
dash.position = start_pos
|
||||
dash.size = Vector2(dash_end - current, 2)
|
||||
viewport.add_child(dash)
|
||||
|
||||
current = dash_end + gap_length
|
||||
|
||||
func _draw_turn_structure(viewport: SubViewport) -> void:
|
||||
var phases = [
|
||||
"Turn Structure",
|
||||
"",
|
||||
"1. Active Phase",
|
||||
"2. Draw Phase",
|
||||
"3. Main Phase 1",
|
||||
"4. Attack Phase",
|
||||
"5. Main Phase 2",
|
||||
"6. End Phase",
|
||||
]
|
||||
|
||||
var start_y = TURN_REF_RECT.position.y + 20
|
||||
var x = TURN_REF_RECT.position.x + 15
|
||||
|
||||
for i in range(phases.size()):
|
||||
var text = phases[i]
|
||||
if text == "":
|
||||
continue
|
||||
|
||||
var label = Label.new()
|
||||
label.text = text
|
||||
var font_size = 20 if i == 0 else 16
|
||||
label.add_theme_font_size_override("font_size", font_size)
|
||||
label.add_theme_color_override("font_color", TURN_TEXT_COLOR)
|
||||
label.position = Vector2(x, start_y + i * 28)
|
||||
label.size = Vector2(TURN_REF_RECT.size.x - 30, 28)
|
||||
viewport.add_child(label)
|
||||
@@ -4,9 +4,9 @@ extends Camera3D
|
||||
## TableCamera - Isometric camera for the game table
|
||||
|
||||
# Camera settings
|
||||
@export var camera_distance: float = 18.0
|
||||
@export var camera_distance: float = 17.0
|
||||
@export var camera_angle: float = 55.0 # Degrees from horizontal (higher = more top-down)
|
||||
@export var camera_height_offset: float = 0.0 # Offset to look slightly above center
|
||||
@export var camera_height_offset: float = -4.0 # Offset to look slightly above center
|
||||
|
||||
# Smooth movement
|
||||
@export var smooth_speed: float = 5.0
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
class_name TableSetup
|
||||
extends Node3D
|
||||
|
||||
## TableSetup - Sets up the 3D game table with all zones
|
||||
## TableSetup - Sets up the 3D game table with two play mats and all zones
|
||||
|
||||
signal card_clicked(card_instance: CardInstance, zone_type: Enums.ZoneType, player_index: int)
|
||||
|
||||
@@ -12,32 +12,42 @@ var player_zones: Array[Dictionary] = [{}, {}]
|
||||
var deck_indicators: Array[MeshInstance3D] = [null, null]
|
||||
var deck_count_labels: Array[Label3D] = [null, null]
|
||||
|
||||
# Table dimensions
|
||||
const TABLE_WIDTH: float = 16.0
|
||||
const TABLE_DEPTH: float = 12.0
|
||||
# Table dimensions (scaled up for card readability)
|
||||
const TABLE_WIDTH: float = 20.0
|
||||
const TABLE_DEPTH: float = 16.0
|
||||
|
||||
# Zone positions (relative to table center)
|
||||
# Play mat dimensions (each player gets one)
|
||||
const MAT_WIDTH: float = 18.0
|
||||
const MAT_DEPTH: float = 7.0
|
||||
const MAT_MARGIN: float = 0.3 # Gap between mats and from table center
|
||||
|
||||
# Zone positions (relative to table center, for Player 1)
|
||||
# Player 1 sits at +Z looking toward -Z
|
||||
# Player's left = +X, Player's right = -X
|
||||
const ZONE_POSITIONS = {
|
||||
"deck": Vector3(5.5, 0.1, 3.5),
|
||||
"damage": Vector3(3.5, 0.1, 3.5),
|
||||
"backups": Vector3(0.0, 0.1, 3.5),
|
||||
"break": Vector3(-3.5, 0.1, 3.5),
|
||||
"forwards": Vector3(0.0, 0.1, 1.5),
|
||||
"hand": Vector3(0.0, 0.5, 5.5)
|
||||
"damage": Vector3(7.0, 0.1, 1.5), # Front-left (player's left)
|
||||
"deck": Vector3(-7.0, 0.1, 1.5), # Front-right (player's right)
|
||||
"break": Vector3(-7.0, 0.1, 4.0), # Right side, behind deck
|
||||
"forwards": Vector3(0.0, 0.1, 2.0), # Center, front row
|
||||
"backups": Vector3(0.0, 0.1, 5.0), # Center, back row
|
||||
"hand": Vector3(0.0, 0.5, 7.5) # Not used on table (2D overlay)
|
||||
}
|
||||
|
||||
# Components
|
||||
var table_mesh: MeshInstance3D
|
||||
var player_mat_meshes: Array[MeshInstance3D] = [null, null]
|
||||
var camera: TableCamera
|
||||
|
||||
func _ready() -> void:
|
||||
_create_table()
|
||||
_create_table_base()
|
||||
_create_camera()
|
||||
_create_lighting()
|
||||
_create_zones()
|
||||
_create_deck_indicators()
|
||||
_generate_mats()
|
||||
|
||||
func _create_table() -> void:
|
||||
func _create_table_base() -> void:
|
||||
# Base table surface (dark, slightly larger than mats)
|
||||
table_mesh = MeshInstance3D.new()
|
||||
add_child(table_mesh)
|
||||
|
||||
@@ -45,18 +55,41 @@ func _create_table() -> void:
|
||||
plane.size = Vector2(TABLE_WIDTH, TABLE_DEPTH)
|
||||
table_mesh.mesh = plane
|
||||
|
||||
# Create table material
|
||||
var mat = StandardMaterial3D.new()
|
||||
mat.albedo_color = Color(0.15, 0.2, 0.15) # Dark green felt
|
||||
|
||||
# Try to load playmat texture
|
||||
if ResourceLoader.exists("res://assets/table/playmat.webp"):
|
||||
var texture = load("res://assets/table/playmat.webp")
|
||||
if texture:
|
||||
mat.albedo_texture = texture
|
||||
|
||||
mat.albedo_color = Color(0.08, 0.10, 0.08) # Very dark green base
|
||||
table_mesh.material_override = mat
|
||||
# PlaneMesh in Godot 4 is already horizontal (facing up), no rotation needed
|
||||
|
||||
func _create_player_mat(player_idx: int, texture: ImageTexture) -> void:
|
||||
var mat_mesh = MeshInstance3D.new()
|
||||
add_child(mat_mesh)
|
||||
|
||||
var plane = PlaneMesh.new()
|
||||
plane.size = Vector2(MAT_WIDTH, MAT_DEPTH)
|
||||
mat_mesh.mesh = plane
|
||||
|
||||
var mat = StandardMaterial3D.new()
|
||||
mat.albedo_texture = texture
|
||||
mat_mesh.material_override = mat
|
||||
|
||||
# Position each mat on its half of the table
|
||||
var mat_center_z = MAT_DEPTH / 2.0 + MAT_MARGIN
|
||||
if player_idx == 0:
|
||||
mat_mesh.position = Vector3(0, 0.01, mat_center_z) # Player 1: positive Z
|
||||
else:
|
||||
mat_mesh.position = Vector3(0, 0.01, -mat_center_z) # Player 2: negative Z
|
||||
mat_mesh.rotation.y = deg_to_rad(180) # Rotate 180 so labels face Player 2
|
||||
|
||||
player_mat_meshes[player_idx] = mat_mesh
|
||||
|
||||
func _generate_mats() -> void:
|
||||
var renderer = PlaymatRenderer.new()
|
||||
add_child(renderer)
|
||||
var texture = await renderer.render()
|
||||
renderer.queue_free()
|
||||
|
||||
# Apply texture to both player mats
|
||||
_create_player_mat(0, texture)
|
||||
_create_player_mat(1, texture)
|
||||
|
||||
func _create_camera() -> void:
|
||||
camera = TableCamera.new()
|
||||
@@ -128,7 +161,7 @@ func _create_deck_indicators() -> void:
|
||||
add_child(deck_mesh)
|
||||
|
||||
var box = BoxMesh.new()
|
||||
box.size = Vector3(0.63, 0.3, 0.88) # Card size with thickness for deck
|
||||
box.size = Vector3(1.26, 0.3, 1.76) # Card size with thickness for deck
|
||||
deck_mesh.mesh = box
|
||||
|
||||
var mat = StandardMaterial3D.new()
|
||||
@@ -162,7 +195,7 @@ func _create_zone(zone_type: Enums.ZoneType, player_idx: int, pos: Vector3, rot:
|
||||
# Configure based on zone type
|
||||
match zone_type:
|
||||
Enums.ZoneType.FIELD_FORWARDS, Enums.ZoneType.FIELD_BACKUPS:
|
||||
zone.card_spacing = 0.8
|
||||
zone.card_spacing = 1.5
|
||||
Enums.ZoneType.DAMAGE, Enums.ZoneType.BREAK:
|
||||
zone.stack_offset = 0.02
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ func _create_zone_indicator() -> void:
|
||||
zone_indicator.mesh = plane
|
||||
|
||||
var mat = StandardMaterial3D.new()
|
||||
mat.albedo_color = Color(0.2, 0.2, 0.3, 0.3)
|
||||
mat.albedo_color = Color(0.2, 0.2, 0.3, 0.1) # Nearly transparent (mat texture shows zones)
|
||||
mat.transparency = BaseMaterial3D.TRANSPARENCY_ALPHA
|
||||
zone_indicator.material_override = mat
|
||||
|
||||
@@ -88,7 +88,9 @@ func _arrange_cards() -> void:
|
||||
match zone_type:
|
||||
Enums.ZoneType.HAND:
|
||||
_arrange_hand()
|
||||
Enums.ZoneType.DECK, Enums.ZoneType.DAMAGE, Enums.ZoneType.BREAK:
|
||||
Enums.ZoneType.DAMAGE:
|
||||
_arrange_damage()
|
||||
Enums.ZoneType.DECK, Enums.ZoneType.BREAK:
|
||||
_arrange_stack()
|
||||
Enums.ZoneType.FIELD_FORWARDS, Enums.ZoneType.FIELD_BACKUPS:
|
||||
_arrange_field()
|
||||
@@ -117,12 +119,25 @@ func _arrange_hand() -> void:
|
||||
Vector3(0, 0, deg_to_rad(-angle))
|
||||
)
|
||||
|
||||
## Arrange as a stack (for deck, damage, break zone)
|
||||
## Arrange as a stack (for deck, break zone)
|
||||
func _arrange_stack() -> void:
|
||||
for i in range(card_visuals.size()):
|
||||
var card = card_visuals[i]
|
||||
card.move_to(Vector3(0, i * stack_offset, 0))
|
||||
|
||||
## Arrange damage cards spread along Z axis (vertical column on the mat)
|
||||
func _arrange_damage() -> void:
|
||||
var count = card_visuals.size()
|
||||
if count == 0:
|
||||
return
|
||||
# Spread damage cards along Z axis so they fan out visually
|
||||
var spacing = min(0.5, 3.0 / max(count, 1))
|
||||
var total_depth = (count - 1) * spacing
|
||||
var start_z = -total_depth / 2.0
|
||||
for i in range(count):
|
||||
var card = card_visuals[i]
|
||||
card.move_to(Vector3(0, i * stack_offset, start_z + i * spacing))
|
||||
|
||||
## Arrange in a row (for field zones)
|
||||
func _arrange_field() -> void:
|
||||
var count = card_visuals.size()
|
||||
@@ -135,13 +150,14 @@ func _arrange_field() -> void:
|
||||
for i in range(count):
|
||||
var card = card_visuals[i]
|
||||
var x = start_x + i * card_spacing
|
||||
var y = i * 0.01 # Slight Y offset so cards layer properly
|
||||
|
||||
# Apply dull rotation if card is dull
|
||||
var rot_y = 0.0
|
||||
if card.card_instance and card.card_instance.is_dull():
|
||||
rot_y = deg_to_rad(90)
|
||||
|
||||
card.move_to(Vector3(x, 0, 0), Vector3(0, rot_y, 0))
|
||||
card.move_to(Vector3(x, y, 0), Vector3(0, rot_y, 0))
|
||||
|
||||
## Arrange in a simple row
|
||||
func _arrange_row() -> void:
|
||||
|
||||
Reference in New Issue
Block a user