227 lines
7.2 KiB
GDScript
227 lines
7.2 KiB
GDScript
extends Spatial
|
|
|
|
class_name Board
|
|
|
|
onready var CardTemplate := preload("res://Scenes/Components/Card.tscn")
|
|
|
|
onready var camera := $Camera
|
|
onready var hand := $Camera/PlayerHand
|
|
onready var oppHand := $Camera/OppHand
|
|
onready var ui := $BoardUI
|
|
onready var cards := $Cards
|
|
|
|
export var mouseHandThreshold = 0.85
|
|
|
|
var holdingCard: Card = null
|
|
var focusedCard: Card = null
|
|
var currentZone: Stack = null
|
|
|
|
var mouseOrigin: Vector2
|
|
var lastCameraTransform: Transform
|
|
|
|
onready var zones: Dictionary = {
|
|
"player1.deck": $Cards/P1Deck,
|
|
"player1.banished": $Cards/P1Banished,
|
|
"player1.graveyard": $Cards/P1Graveyard,
|
|
"player1.problem": $Cards/P1Problem,
|
|
"player2.deck": $Cards/P2Deck,
|
|
"player2.banished": $Cards/P2Banished,
|
|
"player2.graveyard": $Cards/P2Graveyard,
|
|
"player2.problem": $Cards/P2Problem
|
|
}
|
|
|
|
func _ready():
|
|
add_card("pr10", 0, false)
|
|
add_card("ff33", 0, true)
|
|
add_card("ff100", 0, true)
|
|
add_card("ff44", 0, true)
|
|
add_card("eo11", 0, true)
|
|
add_card("pr168", 0, true)
|
|
add_card("ad176", 0, true)
|
|
|
|
add_card("ff33", 1, true)
|
|
add_card("ff33", 1, true)
|
|
add_card("ff33", 1, true)
|
|
add_card("ff33", 1, true)
|
|
reorder_hand(0)
|
|
reorder_hand(1)
|
|
|
|
func _input(event: InputEvent):
|
|
# Camera zoom
|
|
if event.is_action("zoom_in"):
|
|
camera.zoom(true)
|
|
elif event.is_action("zoom_out"):
|
|
camera.zoom(false)
|
|
# Save original camera and mouse position before panning
|
|
if event.is_action_pressed("pan"):
|
|
mouseOrigin = get_viewport().get_mouse_position()
|
|
lastCameraTransform = camera.transform
|
|
|
|
func _process(delta: float):
|
|
# If mouse is under a certain area then we're managing our hand
|
|
var absMousePos := get_viewport().get_mouse_position()
|
|
# If panning, translate mouse delta to camera delta
|
|
if Input.is_action_pressed("pan"):
|
|
var mouseDelta := absMousePos - mouseOrigin
|
|
var mousePos: Vector2 = mouseDelta * 0.0096 * (1-camera.get_zoom()/5) # Magic numbers everywhere
|
|
camera.transform.origin = lastCameraTransform.origin - Vector3(mousePos.x, 0, mousePos.y)
|
|
# If holding a card, move it between board/hand
|
|
if holdingCard != null:
|
|
# Check if we're selecting our hand while holding a card
|
|
var relPos: Vector2 = absMousePos / get_viewport().size
|
|
var xMargin = 1.0-HAND_SCREEN_PERC
|
|
var selectingHand: bool = relPos.y > mouseHandThreshold and (relPos.x > xMargin/2 and relPos.x < (1.0-xMargin/2))
|
|
# Move card in/out hand
|
|
if selectingHand and not holdingCard.inHand:
|
|
holdingCard.inHand = true
|
|
call_deferred("reparent", holdingCard, cards, hand)
|
|
elif not selectingHand and holdingCard.inHand:
|
|
holdingCard.inHand = false
|
|
call_deferred("reparent", holdingCard, hand, cards)
|
|
|
|
# Move card to/from zone
|
|
if currentZone != null:
|
|
if holdingCard.inZone:
|
|
if holdingCard.zoneName != currentZone.zoneName:
|
|
# Move from old zone to new
|
|
call_deferred("reparent", holdingCard, zones[holdingCard.zoneName], currentZone)
|
|
holdingCard.zoneName = currentZone.zoneName
|
|
holdingCard.flipped = currentZone.faceDown
|
|
else:
|
|
holdingCard.inZone = true
|
|
holdingCard.zoneName = currentZone.zoneName
|
|
holdingCard.flipped = currentZone.faceDown
|
|
if holdingCard.inHand:
|
|
call_deferred("reparent", holdingCard, hand, currentZone)
|
|
else:
|
|
call_deferred("reparent", holdingCard, cards, currentZone)
|
|
elif holdingCard.inZone:
|
|
# Move from zone to hand/field
|
|
if holdingCard.inHand:
|
|
call_deferred("reparent", holdingCard, zones[holdingCard.zoneName], hand)
|
|
else:
|
|
call_deferred("reparent", holdingCard, zones[holdingCard.zoneName], cards)
|
|
holdingCard.inZone = false
|
|
holdingCard.zoneName = ""
|
|
holdingCard.flipped = false
|
|
|
|
func _physics_process(delta):
|
|
# Do some raycast magic that normal Godot events cannot get (like ignoring items)
|
|
var space_state := get_world().direct_space_state
|
|
var absMousePos := get_viewport().get_mouse_position()
|
|
var from: Vector3 = camera.project_ray_origin(absMousePos)
|
|
var to: Vector3 = from + camera.project_ray_normal(absMousePos) * 1000
|
|
var result := space_state.intersect_ray(from, to, [self, holdingCard], 0x7FFFFFFF, true, true)
|
|
if result:
|
|
if result.collider is Stack:
|
|
currentZone = result.collider
|
|
else:
|
|
currentZone = null
|
|
|
|
func _card_picked(card: Card):
|
|
# Call pop if applicable
|
|
if card.inZone:
|
|
zones[card.zoneName].pop_card()
|
|
holdingCard = card
|
|
holdingCard.animation.queue("lift")
|
|
|
|
func _card_dropped(card: Card):
|
|
if card.inHand:
|
|
card.animation.queue("drop-hand")
|
|
reorder_hand(0)
|
|
else:
|
|
card.animation.queue("drop-board")
|
|
if currentZone != null:
|
|
card.inZone = true
|
|
currentZone.push_card(card)
|
|
holdingCard = null
|
|
|
|
func _card_selected(card: Card):
|
|
if card.inHand and focusedCard == null:
|
|
focusedCard = card
|
|
card.animation.queue("focus")
|
|
|
|
func _card_unselected(card: Card):
|
|
if focusedCard == card:
|
|
focusedCard = null
|
|
card.animation.queue("blur")
|
|
|
|
func reparent(object: Node, from: Node, to: Node):
|
|
from.remove_child(object)
|
|
to.add_child(object)
|
|
object.set_owner(to)
|
|
reorder_hand(0)
|
|
|
|
func add_card(cardID: String, playerID: int, inHand: bool):
|
|
var card := CardTemplate.instance()
|
|
card.cardID = cardID
|
|
card.playerID = playerID
|
|
card.inHand = inHand
|
|
card.connect("card_dropped", self, "_card_dropped", [card])
|
|
card.connect("card_picked", self, "_card_picked", [card])
|
|
card.connect("card_selected", ui, "_card_selected", [card])
|
|
card.connect("card_unselected", ui, "_card_unselected", [card])
|
|
card.connect("card_selected", self, "_card_selected", [card])
|
|
card.connect("card_unselected", self, "_card_unselected", [card])
|
|
card.connect("card_dropped_anim", self, "check_hand_drop", [card])
|
|
card.connect("card_menu", ui, "show_card_menu", [card])
|
|
if inHand:
|
|
# TODO support for >2 players
|
|
if playerID == 0:
|
|
hand.add_child(card)
|
|
else:
|
|
oppHand.add_child(card)
|
|
else:
|
|
cards.add_child(card)
|
|
|
|
func check_hand_drop(card: Card):
|
|
# Re-order hand as soon as the animation is over
|
|
if card.inHand:
|
|
card.reset_transform()
|
|
reorder_hand(0)
|
|
|
|
const MAX_CARD_DISTANCE := 0.5
|
|
const HAND_SCREEN_PERC := 0.6
|
|
const CARD_ROTATION := 0.03
|
|
const UNITSPERPX := 0.003
|
|
|
|
func reorder_hand(playerID: int):
|
|
var cardsInHand: Array = []
|
|
if playerID == 0:
|
|
cardsInHand = hand.get_children()
|
|
else:
|
|
cardsInHand = oppHand.get_children()
|
|
cardsInHand.sort_custom(TransformSorter, "sort")
|
|
var size := cardsInHand.size()
|
|
|
|
# Check if we have nothing to order
|
|
if size < 1:
|
|
return
|
|
|
|
# Calculate total width of the player's hand and other things
|
|
# This is done in two ways, for small hands, MAX_CARD_DISTANCE is usually used
|
|
# as constant distance between cards, however, as the hand gets larger we don't
|
|
# want them to go offscreen, therefore a "maximum screen %" is used to determine
|
|
# how to fit all the cards within a % of the viewport's width
|
|
var distancePerc := get_viewport().size.x * HAND_SCREEN_PERC * UNITSPERPX / size
|
|
var distance := min(distancePerc, MAX_CARD_DISTANCE)
|
|
var totalWidth := distance * (size-1)
|
|
var minX := -totalWidth/2
|
|
|
|
# Iterate over all items, keep track of the index
|
|
var i := 0
|
|
for child in cardsInHand:
|
|
child.tween_move_to(Vector3(minX + distance * i, 0.02*i, -0.005*i))
|
|
child.tween_rotate(Vector3(0, CARD_ROTATION * (size/2.0 - i), 0))
|
|
i += 1
|
|
child.reset_transform()
|
|
child.tween()
|
|
|
|
class TransformSorter:
|
|
static func sort(a, b):
|
|
if a.transform.origin.x < b.transform.origin.x:
|
|
return true
|
|
return false
|
|
|
|
func _card_picked_zone(card, zone):
|
|
_card_picked(card)
|