From a4f951a1015e2c435bf8febb9f098338e5eda605 Mon Sep 17 00:00:00 2001 From: Jacob Wilkins Date: Wed, 10 Mar 2021 19:45:04 +0000 Subject: [PATCH] Chess now playable --- Board.gd | 95 ++++++++++++++++++++++++++++++++++++++++++++++++++ Draggable.gd | 62 ++++++++++++++++++++++++++++++++ Draggable.tscn | 18 ++++++++++ FileParser.gd | 6 +++- MainGame.gd | 5 +++ MainGame.tscn | 5 +-- Piece.gd | 37 +++++++++++++++++--- Piece.tscn | 1 + UI.gd | 10 ++++-- UI.tscn | 56 ++++++++++++----------------- tmp.pgn | 0 11 files changed, 250 insertions(+), 45 deletions(-) create mode 100644 Board.gd create mode 100644 Draggable.gd create mode 100644 Draggable.tscn create mode 100644 tmp.pgn diff --git a/Board.gd b/Board.gd new file mode 100644 index 0000000..a31e23e --- /dev/null +++ b/Board.gd @@ -0,0 +1,95 @@ +extends TileMap + +onready var PIECE = preload("res://Piece.tscn") + +const LET = {"a":1, "b":2, "c":3, "d":4, "e":5, "f":6, "g":7, "h":8} +const NUM = {1:"a", 2:"b", 3:"c", 4:"d", 5:"e", 6:"f", 7:"g", 8:"h"} + +signal error(title, message) +signal piece_moved(SAN) +var positions = {} +const TILE_OFFSET := Vector2(32,32) +onready var game = get_parent() + +func add_piece(colour, type, pos): + if pos in self.positions: + emit_signal("error","Cannot add piece", "Tile "+str(pos)+" occupied") + var piece = PIECE.instance() + piece.init(colour, type) + add_child(piece) + update_piece(piece, pos) + piece.moved = false + +func remove_piece(piece): + piece.queue_free() + self.positions.erase(piece) + +func update_piece(piece, location: Vector2): + if piece.gridPos in self.positions: + self.positions.erase(piece.gridPos) + piece.gridPos = location + piece.position = self.map_to_world(piece.gridPos) + TILE_OFFSET + piece.moved = true + self.positions[piece.gridPos] = piece + +func move_piece(pos:Vector2, newLoc:Vector2): + if not pos in self.positions: + emit_signal("error","Cannot move piece", "No piece in position") + return + if (newLoc.x * newLoc.y < 0) or newLoc.x > 8 or newLoc.y > 8: + emit_signal("error","Cannot move piece", "Not on board") + return + + var moving = self.positions[pos] + var SAN = moving.TYPES_SAN[moving.type] + self.from_grid(pos) + var capture = false + var promote = false + var target = null + + if moving.colour != game.currTurn: + emit_signal("error","Cannot move piece", "Not current player") + return + + if newLoc in self.positions: + target = self.positions[newLoc] + if target.colour != moving.colour: + capture = true + else: + emit_signal("error","Cannot move piece", "Tile occupied") + return + + if not moving.can_move(newLoc, capture): + emit_signal("error","Cannot move piece", "Piece cannot move there") + return + + if target: + self.remove_piece(target) + + self.update_piece(moving, newLoc) + + + if capture: + SAN += "x" + if promote: + SAN += "="+moving.TYPES_SAN[moving.type] + SAN += self.from_grid(newLoc) + match moving.castled: + -1: + SAN = "O-O" + var rook = self.positions[Vector2(1,moving.colour*7+1)] + update_piece(rook, Vector2(3,moving.colour*7+1)) + moving.castled = 0 + 1: + SAN = "O-O-O" + var rook = self.positions[Vector2(8,moving.colour*7+1)] + update_piece(rook, Vector2(6,moving.colour*7+1)) + moving.castled = 0 + + emit_signal("piece_moved", SAN) + +func to_grid(pos: String) -> Vector2: + return Vector2(LET[pos[0]], int(pos[1])) + +func from_grid(pos: Vector2) -> String: + return NUM[int(pos.x)] + str(pos.y) + diff --git a/Draggable.gd b/Draggable.gd new file mode 100644 index 0000000..62de41e --- /dev/null +++ b/Draggable.gd @@ -0,0 +1,62 @@ +extends Area2D + +export (bool) var active = true +var dragging := false +var mouse_in := false +var stored_pos: Vector2 +onready var parent = get_parent() + +const COL_ACTIVE = 1 << 20 + +signal drag +signal stopdrag +signal deselect +signal select(parent) + +func _ready(): + add_to_group("draggable") + if active: + activate() + else: + deactivate() + +func _undrag(): + dragging = false + set_process_unhandled_input(false) + +func _drag(): + dragging = true + set_process_unhandled_input(true) + +func _input(event): + if mouse_in: + if event is InputEventMouseButton: + if event.button_index == BUTTON_LEFT and event.pressed: + stored_pos = parent.position + emit_signal("drag") + emit_signal("select", parent) + get_tree().set_input_as_handled() + +func _unhandled_input(event): + if event is InputEventMouseButton: + if not event.pressed and dragging: + emit_signal("stopdrag") + +func set_shape(shape: Shape2D): + $Area.set_shape(shape) + +func activate(): + active = true + collision_layer = COL_ACTIVE + +func deactivate(): + _undrag() + active = false + collision_layer = 0 + +func _mouse_enter(): + mouse_in = true + +func _mouse_exit(): + mouse_in = false + diff --git a/Draggable.tscn b/Draggable.tscn new file mode 100644 index 0000000..9a39a44 --- /dev/null +++ b/Draggable.tscn @@ -0,0 +1,18 @@ +[gd_scene load_steps=3 format=2] + +[ext_resource path="res://Draggable.gd" type="Script" id=1] + +[sub_resource type="RectangleShape2D" id=1] +extents = Vector2( 64, 64 ) + +[node name="Draggable" type="Area2D"] +collision_layer = 524288 +collision_mask = 0 +script = ExtResource( 1 ) + +[node name="Area" type="CollisionShape2D" parent="."] +shape = SubResource( 1 ) +[connection signal="drag" from="." to="." method="_drag"] +[connection signal="mouse_entered" from="." to="." method="_mouse_enter"] +[connection signal="mouse_exited" from="." to="." method="_mouse_exit"] +[connection signal="stopdrag" from="." to="." method="_undrag"] diff --git a/FileParser.gd b/FileParser.gd index e9d6928..f874b41 100644 --- a/FileParser.gd +++ b/FileParser.gd @@ -2,12 +2,16 @@ extends Node var path := "" var data := {} -var turns := [] +var turns := [Turn.new()] const COLOURS = ["White", "Black"] signal read signal error(title, message) +func _ready(): + turns = [Turn.new()] + func read(filepath): + self.turns = [] self.path = filepath var file := File.new() var status = file.open(self.path, File.READ) diff --git a/MainGame.gd b/MainGame.gd index 544b42c..b5c54ad 100644 --- a/MainGame.gd +++ b/MainGame.gd @@ -5,6 +5,7 @@ var nTurns = 0 signal turn_updated var fileParsers := [] var currFileParser = 0 +var currTurn = 0 func update_turns(): self.nTurns = len($FileParser.turns) @@ -31,3 +32,7 @@ func load_turn(turn: int): for pos in currTurn.positions: $Board.add_piece("WB".find(pos[0]),"KQBNRP".find(pos[1]),currTurn.positions[pos]) emit_signal("turn_updated", self.turnID) + + +func _on_Board_piece_moved(SAN) -> void: + self.currTurn = 1 - self.currTurn diff --git a/MainGame.tscn b/MainGame.tscn index 1661c50..d3bd8b7 100644 --- a/MainGame.tscn +++ b/MainGame.tscn @@ -47,8 +47,5 @@ tile_data = PoolIntArray( 65537, 1, 0, 65538, 0, 0, 65539, 1, 0, 65540, 0, 0, 65 script = ExtResource( 4 ) [node name="FileParser" parent="." instance=ExtResource( 1 )] - -[node name="Camera2D" type="Camera2D" parent="."] -position = Vector2( 320, 320 ) -current = true +[connection signal="piece_moved" from="Board" to="." method="_on_Board_piece_moved"] [connection signal="read" from="FileParser" to="." method="update_turns"] diff --git a/Piece.gd b/Piece.gd index 896f702..2fb054c 100644 --- a/Piece.gd +++ b/Piece.gd @@ -2,7 +2,7 @@ extends Sprite enum TYPES {KING, QUEEN, BISHOP, KNIGHT, ROOK, PAWN} enum COLOUR {WHITE=0, BLACK=1} -const PAWN_DIR = [-1, 1] +const PAWN_DIR = [1, -1] const KNIGHT_MOVES = [Vector2(1,2), Vector2(-1,2), Vector2(-1,-2), @@ -11,12 +11,14 @@ const KNIGHT_MOVES = [Vector2(1,2), Vector2(-2,1), Vector2(-2,-1), Vector2(2,-1)] +const TYPES_SAN = "KQBNRP" var gridPos : Vector2 var type : int var moved : bool = false var colour : int onready var board = get_parent() +var castled : int = 0 func init(colour: int, type: int) -> void: self.colour = colour @@ -30,17 +32,42 @@ func can_move(newLoc, capture=false) -> bool: TYPES.QUEEN: return ref.x == 0 or ref.y == 0 or ref.x == ref.y TYPES.KING: - return ref.length_squared < 2 + print(self.moved, newLoc, self.colour*7+1) + if not self.moved and newLoc in [Vector2(3, self.colour*7+1), Vector2(7, self.colour*7+1)]: + print("Hello") + match int(newLoc.x): + 3: + if (not newLoc in board.positions and + not newLoc + Vector2.RIGHT in board.positions and + Vector2(1,self.colour*7+1) in board.positions and + not board.positions[Vector2(1,self.colour*7+1)].moved): + self.castled = -1 + return true + 7: + if (not newLoc in board.positions and + not newLoc + Vector2.LEFT in board.positions and + Vector2(8,self.colour*7+1) in board.positions and + not board.positions[Vector2(8,self.colour*7+1)].moved): + self.castled = 1 + return true + _: + print("Nope") + pass + return ref.length_squared() < 2 TYPES.KNIGHT: return ref in KNIGHT_MOVES TYPES.ROOK: return ref.x == 0 or ref.y == 0 TYPES.BISHOP: return ref.x == ref.y - TYPES.PAWN: + TYPES.PAWN: if not self.moved: - return ref.x == int(capture) and raw in [PAWN_DIR[self.colour], PAWN_DIR[self.colour]*2] + return ref.x == int(capture) and raw.y in [PAWN_DIR[self.colour], PAWN_DIR[self.colour]*2] else: - return ref.x == int(capture) and raw == PAWN_DIR[self.colour] + return ref.x == int(capture) and raw.y == PAWN_DIR[self.colour] return false +func _on_Draggable_stopdrag() -> void: + var mousePos = get_viewport().get_mouse_position() + var newPos = board.world_to_map(mousePos) + board.move_piece(self.gridPos, newPos) diff --git a/Piece.tscn b/Piece.tscn index 8ad418e..8f66dfe 100644 --- a/Piece.tscn +++ b/Piece.tscn @@ -13,3 +13,4 @@ frame = 11 script = ExtResource( 2 ) [node name="Draggable" parent="." instance=ExtResource( 3 )] +[connection signal="stopdrag" from="Draggable" to="." method="_on_Draggable_stopdrag"] diff --git a/UI.gd b/UI.gd index 16c3834..4701820 100644 --- a/UI.gd +++ b/UI.gd @@ -1,10 +1,16 @@ extends Control -onready var game = $ViewportContainer/Viewport/MainGame -onready var parser = $ViewportContainer/Viewport/MainGame/FileParser +onready var game = $MainGame +onready var parser = game.get_node("FileParser") onready var turnsList = $PanelContainer/VBoxContainer/Turns/VBoxContainer var lastTurn = 0 +func _ready(): + var file = File.new() + file.open("res://tmp.pgn", File.WRITE) + file.close() + load_file("res://tmp.pgn") + func load_file(path): parser.read(path) diff --git a/UI.tscn b/UI.tscn index 5573e14..fba880b 100644 --- a/UI.tscn +++ b/UI.tscn @@ -4,33 +4,20 @@ [ext_resource path="res://UI.gd" type="Script" id=2] [node name="UI" type="Control"] +anchor_left = 1.0 anchor_right = 1.0 anchor_bottom = 1.0 +margin_left = -308.0 script = ExtResource( 2 ) __meta__ = { "_edit_use_anchors_": false } -[node name="ViewportContainer" type="ViewportContainer" parent="."] -anchor_bottom = 1.0 -margin_right = 770.0 -stretch = true -__meta__ = { -"_edit_use_anchors_": false -} - -[node name="Viewport" type="Viewport" parent="ViewportContainer"] -size = Vector2( 770, 600 ) -handle_input_locally = false -render_target_update_mode = 3 - -[node name="MainGame" parent="ViewportContainer/Viewport" instance=ExtResource( 1 )] +[node name="MainGame" parent="." instance=ExtResource( 1 )] [node name="PanelContainer" type="PanelContainer" parent="."] -anchor_left = 0.707 anchor_right = 1.0 anchor_bottom = 1.0 -margin_left = 0.0319824 rect_min_size = Vector2( 300, 0 ) __meta__ = { "_edit_use_anchors_": false @@ -39,16 +26,16 @@ __meta__ = { [node name="VBoxContainer" type="VBoxContainer" parent="PanelContainer"] margin_left = 7.0 margin_top = 7.0 -margin_right = 293.0 +margin_right = 301.0 margin_bottom = 593.0 [node name="GameDetails" type="Label" parent="PanelContainer/VBoxContainer"] -margin_right = 286.0 +margin_right = 294.0 margin_bottom = 14.0 [node name="HBoxContainer" type="HBoxContainer" parent="PanelContainer/VBoxContainer"] margin_top = 18.0 -margin_right = 286.0 +margin_right = 294.0 margin_bottom = 32.0 [node name="TurnLabel" type="Label" parent="PanelContainer/VBoxContainer/HBoxContainer"] @@ -63,7 +50,7 @@ margin_bottom = 14.0 [node name="Turns" type="ScrollContainer" parent="PanelContainer/VBoxContainer"] margin_top = 36.0 -margin_right = 286.0 +margin_right = 294.0 margin_bottom = 510.0 size_flags_vertical = 11 follow_focus = true @@ -73,50 +60,50 @@ scroll_horizontal_enabled = false [node name="HBoxContainer2" type="HBoxContainer" parent="PanelContainer/VBoxContainer"] margin_top = 514.0 -margin_right = 286.0 +margin_right = 294.0 margin_bottom = 534.0 alignment = 1 [node name="prevTurn" type="Button" parent="PanelContainer/VBoxContainer/HBoxContainer2"] -margin_left = 116.0 -margin_right = 141.0 +margin_left = 120.0 +margin_right = 145.0 margin_bottom = 20.0 text = "<-" [node name="nextTurn" type="Button" parent="PanelContainer/VBoxContainer/HBoxContainer2"] -margin_left = 145.0 -margin_right = 170.0 +margin_left = 149.0 +margin_right = 174.0 margin_bottom = 20.0 text = "->" [node name="HBoxContainer3" type="HBoxContainer" parent="PanelContainer/VBoxContainer"] margin_top = 538.0 -margin_right = 286.0 +margin_right = 294.0 margin_bottom = 562.0 [node name="Path" type="LineEdit" parent="PanelContainer/VBoxContainer/HBoxContainer3"] -margin_right = 177.0 +margin_right = 185.0 margin_bottom = 24.0 size_flags_horizontal = 3 align = 3 [node name="Search" type="Button" parent="PanelContainer/VBoxContainer/HBoxContainer3"] -margin_left = 181.0 -margin_right = 240.0 +margin_left = 189.0 +margin_right = 248.0 margin_bottom = 24.0 text = "Browse" align = 2 [node name="Load" type="Button" parent="PanelContainer/VBoxContainer/HBoxContainer3"] -margin_left = 244.0 -margin_right = 286.0 +margin_left = 252.0 +margin_right = 294.0 margin_bottom = 24.0 text = "Load" align = 2 [node name="QuitButton" type="Button" parent="PanelContainer/VBoxContainer"] margin_top = 566.0 -margin_right = 286.0 +margin_right = 294.0 margin_bottom = 586.0 text = "Quit" @@ -141,10 +128,13 @@ anchor_right = 1.0 anchor_bottom = 1.0 align = 1 valign = 1 -[connection signal="turn_updated" from="ViewportContainer/Viewport/MainGame" to="." method="update_turn"] +[connection signal="turn_updated" from="MainGame" to="." method="update_turn"] +[connection signal="error" from="MainGame/Board" to="." method="_error"] [connection signal="button_up" from="PanelContainer/VBoxContainer/HBoxContainer2/prevTurn" to="." method="_on_prevTurn_button_up"] [connection signal="button_up" from="PanelContainer/VBoxContainer/HBoxContainer2/nextTurn" to="." method="_on_nextTurn_button_up"] [connection signal="pressed" from="PanelContainer/VBoxContainer/HBoxContainer3/Search" to="." method="_on_Search_pressed"] [connection signal="pressed" from="PanelContainer/VBoxContainer/HBoxContainer3/Load" to="." method="_on_Load_pressed"] [connection signal="pressed" from="PanelContainer/VBoxContainer/QuitButton" to="." method="quit"] [connection signal="file_selected" from="FileDialog" to="." method="_on_FileDialog_file_selected"] + +[editable path="MainGame"] diff --git a/tmp.pgn b/tmp.pgn new file mode 100644 index 0000000..e69de29