From 61091b05dbf473163c15860a3ec202aa3557b1a0 Mon Sep 17 00:00:00 2001 From: Nekojimi Date: Fri, 25 Mar 2022 21:34:43 +0000 Subject: [PATCH] Added initial version of loop-drawing functionality. --- GridNumbers.xcf | Bin 0 -> 204915 bytes addons/godot-git-plugin/git_api.gdnlib | 36 ++-- default_env.tres | 2 + project.godot | 19 ++ scenes/Cell.tscn | 8 + scenes/GameScene.tscn | 21 +++ scenes/Line.tscn | 18 ++ scenes/Scene.tscn | 10 ++ scripts/Cell.gd | 37 ++++ scripts/GameScene.gd | 238 +++++++++++++++++++++++++ scripts/GameState.gd | 32 ++++ scripts/Line.gd | 47 +++++ scripts/PlayerController.gd | 16 ++ 13 files changed, 466 insertions(+), 18 deletions(-) create mode 100644 GridNumbers.xcf create mode 100644 scenes/Cell.tscn create mode 100644 scenes/GameScene.tscn create mode 100644 scenes/Line.tscn create mode 100644 scenes/Scene.tscn create mode 100644 scripts/Cell.gd create mode 100644 scripts/GameScene.gd create mode 100644 scripts/GameState.gd create mode 100644 scripts/Line.gd create mode 100644 scripts/PlayerController.gd diff --git a/GridNumbers.xcf b/GridNumbers.xcf new file mode 100644 index 0000000000000000000000000000000000000000..609226965d0d1ea91a9d8728e2fb7ee12ee2d797 GIT binary patch literal 204915 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 Jep}G<{|7Vc?6&{_ literal 0 HcmV?d00001 diff --git a/addons/godot-git-plugin/git_api.gdnlib b/addons/godot-git-plugin/git_api.gdnlib index 0918c1c..18a34ed 100644 --- a/addons/godot-git-plugin/git_api.gdnlib +++ b/addons/godot-git-plugin/git_api.gdnlib @@ -1,18 +1,18 @@ -[general] - -singleton=true -load_once=true -symbol_prefix="godot_" -reloadable=false - -[entry] - -OSX.64="res://addons/godot-git-plugin/osx/release/libgitapi.dylib" -Windows.64="res://addons/godot-git-plugin/win64/release/libgitapi.dll" -X11.64="res://addons/godot-git-plugin/x11/release/libgitapi.so" - -[dependencies] - -OSX.64=[ ] -Windows.64=[ ] -X11.64=[ ] +[general] + +singleton=true +load_once=true +symbol_prefix="godot_" +reloadable=false + +[entry] + +OSX.64="res://addons/godot-git-plugin/osx/release/libgitapi.dylib" +Windows.64="res://addons/godot-git-plugin/win64/release/libgitapi.dll" +X11.64="res://addons/godot-git-plugin/x11/release/libgitapi.so" + +[dependencies] + +OSX.64=[ ] +Windows.64=[ ] +X11.64=[ ] diff --git a/default_env.tres b/default_env.tres index 98f26a7..20207a4 100644 --- a/default_env.tres +++ b/default_env.tres @@ -1,5 +1,7 @@ [gd_resource type="Environment" load_steps=2 format=2] + [sub_resource type="ProceduralSky" id=1] + [resource] background_mode = 2 background_sky = SubResource( 1 ) diff --git a/project.godot b/project.godot index e969bcd..398b1d2 100644 --- a/project.godot +++ b/project.godot @@ -9,20 +9,39 @@ config_version=4 _global_script_classes=[ { +"base": "Node2D", +"class": "GameScene", +"language": "GDScript", +"path": "res://scripts/GameScene.gd" +}, { +"base": "Reference", +"class": "GameState", +"language": "GDScript", +"path": "res://scripts/GameState.gd" +}, { "base": "", "class": "GitAPI", "language": "NativeScript", "path": "res://addons/godot-git-plugin/git_api.gdns" } ] _global_script_class_icons={ +"GameScene": "", +"GameState": "", "GitAPI": "" } [application] config/name="LoopyTest" +run/main_scene="res://scenes/GameScene.tscn" config/icon="res://icon.png" +[debug] + +gdscript/warnings/treat_warnings_as_errors=true +gdscript/warnings/return_value_discarded=false +gdscript/warnings/integer_division=false + [gdnative] singletons=[ "res://addons/godot-git-plugin/git_api.gdnlib" ] diff --git a/scenes/Cell.tscn b/scenes/Cell.tscn new file mode 100644 index 0000000..0ec9248 --- /dev/null +++ b/scenes/Cell.tscn @@ -0,0 +1,8 @@ +[gd_scene load_steps=2 format=2] + +[ext_resource path="res://scripts/Cell.gd" type="Script" id=1] + +[node name="Cell" type="Polygon2D"] +position = Vector2( 329, 258 ) +polygon = PoolVector2Array( 35.3553, 35.3553, -35.3553, 35.3553, -35.3553, -35.3553, 35.3553, -35.3553 ) +script = ExtResource( 1 ) diff --git a/scenes/GameScene.tscn b/scenes/GameScene.tscn new file mode 100644 index 0000000..6868f31 --- /dev/null +++ b/scenes/GameScene.tscn @@ -0,0 +1,21 @@ +[gd_scene load_steps=4 format=2] + +[ext_resource path="res://scripts/Line.gd" type="Script" id=1] +[ext_resource path="res://scripts/GameScene.gd" type="Script" id=2] +[ext_resource path="res://scripts/PlayerController.gd" type="Script" id=3] + + +[node name="GameBoard" type="Node2D"] +script = ExtResource( 2 ) + +[node name="Cell" parent="." instance_placeholder="res://Cell.tscn"] +color = Color( 0.978975, 0.256011, 0.734578, 1 ) + +[node name="Line" type="Line2D" parent="."] +position = Vector2( 55.0797, -23.3827 ) +points = PoolVector2Array( 236.347, 320.204, 236.382, 243.676 ) +default_color = Color( 0.537255, 0.537255, 0.537255, 1 ) +script = ExtResource( 1 ) + +[node name="PlayerController" type="Node" parent="."] +script = ExtResource( 3 ) diff --git a/scenes/Line.tscn b/scenes/Line.tscn new file mode 100644 index 0000000..06e4365 --- /dev/null +++ b/scenes/Line.tscn @@ -0,0 +1,18 @@ +[gd_scene load_steps=3 format=2] + +[ext_resource path="res://scripts/Line.gd" type="Script" id=1] + +[sub_resource type="CapsuleShape2D" id=1] +height = 10.2288 + +[node name="Line" type="Line2D"] +points = PoolVector2Array( 0, 0, 1, 1 ) +default_color = Color( 0.537255, 0.537255, 0.537255, 1 ) +script = ExtResource( 1 ) + +[node name="Area2D" type="Area2D" parent="."] + +[node name="CollisionShape2D" type="CollisionShape2D" parent="Area2D"] +shape = SubResource( 1 ) +[connection signal="mouse_entered" from="Area2D" to="." method="_on_Area2D_mouse_entered"] +[connection signal="mouse_exited" from="Area2D" to="." method="_on_Area2D_mouse_exited"] diff --git a/scenes/Scene.tscn b/scenes/Scene.tscn new file mode 100644 index 0000000..32c41d7 --- /dev/null +++ b/scenes/Scene.tscn @@ -0,0 +1,10 @@ +[gd_scene load_steps=3 format=2] + +[ext_resource path="res://scripts/PlayerController.gd" type="Script" id=3] +[ext_resource path="res://scripts/GameScene.gd" type="Script" id=4] + +[node name="Node2D" type="Node2D"] +script = ExtResource( 4 ) + +[node name="PlayerController" type="Node" parent="."] +script = ExtResource( 3 ) diff --git a/scripts/Cell.gd b/scripts/Cell.gd new file mode 100644 index 0000000..94465de --- /dev/null +++ b/scripts/Cell.gd @@ -0,0 +1,37 @@ +extends Polygon2D + +export var sides: int = 4 +export var size: float = 50 + +var idx: int +var accessor: GameScene.CellAccessor + +var moveSpeed: float = rand_range(0.5,1.5) + +func _ready() -> void: + init() + +func init() -> void: + var points: PoolVector2Array = [] + + for side in range(sides): + var angle: float = ((side / float(sides)) + (0.5 / sides) ) * (2 * PI) + points.append(Vector2(cos(angle),sin(angle)) * size) + + polygon = points + +# color = Color(randf(),randf(),randf()) + accessor = get_parent().get_cell(idx) + +func _process(delta): + var target: Vector2 = accessor.get_pos() + Vector2(size,size) + position = position.linear_interpolate(target,delta*moveSpeed) + + var owner: int = accessor.get_owner() + match owner: + 0: + color = Color.white + 1: + color = Color.pink + 2: + color = Color.skyblue diff --git a/scripts/GameScene.gd b/scripts/GameScene.gd new file mode 100644 index 0000000..efa40ce --- /dev/null +++ b/scripts/GameScene.gd @@ -0,0 +1,238 @@ +extends Node2D + +export var boardSize: Vector2 = Vector2(10,7) + +class_name GameScene + +var reality: GameState +var simulate: GameState + +func _ready() -> void: + reality = GameState.new() + reality.init_arrays(boardSize) + + var cellScene: PackedScene = load("res://scenes/Cell.tscn") + var lineScene: PackedScene = load("res://scenes/Line.tscn") + for cellIdx in range(reality.get_cell_count()): + var cell: Node = cellScene.instance() + cell.idx = cellIdx + add_child(cell) + for lineIdx in range(reality.get_line_count()): + var line: Node = lineScene.instance() + line.idx = lineIdx + add_child(line) + line.connect("line_clicked", self, "_line_clicked") + + print("Lines at 0,0: %s" % [get_lines_by_grid(Vector2(0,0))]) + print("Lines at 0,1: %s" % [get_lines_by_grid(Vector2(0,1))]) + + +func _line_clicked(lineIdx: int): + var line: LineAccessor = get_line(lineIdx) + line.set_owner(1) + var surrounds: int = test_line_surrounds(lineIdx) + print("Line %d clicked! Surrounded: %d" % [lineIdx, surrounds]) + # +ve: down and left + # -ve: up and right + var cell: CellAccessor = null + if surrounds > 0: + if line.get_horizontal(): + cell = get_cell_by_grid(line.get_grid1() + Vector2(0,1)) + else: + cell = get_cell_by_grid(line.get_grid1()) + elif surrounds < 0: + if line.get_horizontal(): + cell = get_cell_by_grid(line.get_grid1()) + else: + cell = get_cell_by_grid(line.get_grid1() + Vector2(1,0)) + if cell != null: + flood_owner(cell, 1) + +func flood_owner(cell: CellAccessor, owner: int): + if cell.get_owner() != 0: + return + cell.set_owner(owner) + if get_line_by_grid(cell.get_grid() - Vector2(0,1), true).get_owner() == 0: + flood_owner(get_cell_by_grid(cell.get_grid() - Vector2(0,1)), owner) + if get_line_by_grid(cell.get_grid(), true).get_owner() == 0: + flood_owner(get_cell_by_grid(cell.get_grid() + Vector2(0,1)), owner) + if get_line_by_grid(cell.get_grid() - Vector2(1,0), false).get_owner() == 0: + flood_owner(get_cell_by_grid(cell.get_grid() - Vector2(1,0)), owner) + if get_line_by_grid(cell.get_grid(), false).get_owner() == 0: + flood_owner(get_cell_by_grid(cell.get_grid() + Vector2(1,0)), owner) + +func test_line_surrounds(startIdx: int) -> int: + var startLine: LineAccessor = get_line(startIdx) + var grid0: Vector2 = startLine.get_grid0() + var grid1: Vector2 = startLine.get_grid1() + + var openSet: Array = [grid0] # points yet to visit + var closedSet: Array = [] # points visited already + + while openSet.size() > 0: + var point: Vector2 = openSet.pop_front() + closedSet.push_back(point) + + var lines: Array = get_lines_by_grid(point) + for line in lines: + if line.get_owner() == 0: + continue # don't follow unowned lines + if line.idx == startIdx: + continue # don't follow the start line + var otherSide: Vector2 = line.get_grid_other_end(point) + if otherSide == grid1: + closedSet.append(otherSide) + print("Loop found: %s" % [closedSet]) + return calulate_winding(closedSet) # we made it! + if otherSide in closedSet: + continue # been there done that + elif otherSide in openSet: + continue # we already plan to go there + else: + openSet.push_back(otherSide) + + return 0 + +func calulate_winding(points: Array) -> int: + # Sum over the edges, (x2 − x1)(y2 + y1). + # If the result is positive the curve is clockwise, if it's negative the curve is counter-clockwise. + # (The result is twice the enclosed area, with a +/- convention.) + + var ret: int = 0 + for idx in range(points.size()): + var point1: Vector2 = points[idx-1] + var point2: Vector2 = points[idx] + ret += int(point2.x - point1.x) * int(point2.y + point1.y) + + return ret/2 + +func get_cell(idx: int) -> CellAccessor: + var ret: CellAccessor = CellAccessor.new() + ret.gameScene = self + ret.idx = idx + return ret + +func get_cell_idx_by_grid(pos: Vector2) -> int: + return int((pos.y * boardSize.x) + pos.x) + +func get_cell_by_grid(pos: Vector2) -> CellAccessor: + return get_cell(get_cell_idx_by_grid(pos)) + +func get_line(idx: int) -> LineAccessor: + var ret: LineAccessor = LineAccessor.new() + ret.idx = idx + ret.gameScene = self + return ret + +func get_line_by_grid(pos: Vector2, horizontal: bool) -> LineAccessor: + var idx: int + if horizontal: + idx = get_cell_idx_by_grid(pos) + else: + var cellsLastRow: int = int ((boardSize.x * boardSize.y) - boardSize.x) + idx = int(cellsLastRow + pos.y + (pos.x * boardSize.y)) + return get_line(idx) + +func get_lines_by_grid(grid: Vector2) -> Array: + var ret: Array = [] + if grid.y >= 0: + ret.append(get_line_by_grid(grid, false)) + if grid.x >= 0: + ret.append(get_line_by_grid(grid, true)) + ret.append(get_line_by_grid(grid + Vector2(0,1),false)) + ret.append(get_line_by_grid(grid + Vector2(1,0),true)) + return ret + +class CellAccessor: + var gameScene: GameScene + var idx: int + + func get_state(real: bool = true): # NOTE: duplicated + if real: + return gameScene.reality + else: + return gameScene.simulate + + func get_owner(real: bool = true) -> int: + return get_state(real).cellOwners[idx] + + func set_owner(owner: int, real: bool = true): + get_state(real).cellOwners[idx] = owner + + func get_grid() -> Vector2: + var col: int = idx % int(gameScene.boardSize.x) + var row: int = idx / int(gameScene.boardSize.x) + return Vector2(col,row) + + func get_pos() -> Vector2: + return get_grid() * 75 + +class LineAccessor: + var gameScene: GameScene + var idx: int + + func get_state(real: bool = true): # NOTE: duplicated + if real: + return gameScene.reality + else: + return gameScene.simulate + + func get_owner(real: bool = true) -> int: + return get_state(real).lineOwners[idx] + + func set_owner(owner: int, real: bool = true): + get_state(real).lineOwners[idx] = owner + + func get_cellIdx() -> int: + var cellsLastRow: int = int ((gameScene.boardSize.x * gameScene.boardSize.y) - gameScene.boardSize.x) + if idx < cellsLastRow: + return idx + else: + var ln: int = idx - cellsLastRow + var row: int = ln % int(gameScene.boardSize.y) + var col: int = ln / int(gameScene.boardSize.y) + return (row * int(gameScene.boardSize.x)) + col + + func get_horizontal() -> bool: + var cellsLastRow: int = int ((gameScene.boardSize.x * gameScene.boardSize.y) - gameScene.boardSize.x) + return idx <= cellsLastRow + + func get_point0() -> Vector2: + return (get_grid0() * 75) + Vector2(85,85) + + func get_point1() -> Vector2: + return (get_grid1() * 75) + Vector2(85,85) + + func get_grid0() -> Vector2: + var grid1: Vector2 = get_grid1() + if get_horizontal(): + return grid1 - Vector2(1,0) + else: + return grid1 - Vector2(0,1) + + func get_grid1() -> Vector2: + # NOTE: duplicated + var cellIdx: int = get_cellIdx() + var col: int = cellIdx % int(gameScene.boardSize.x) + var row: int = cellIdx / int(gameScene.boardSize.x) + return Vector2(col,row) + + func get_grid_other_end(grid: Vector2): + if grid == get_grid0(): + return get_grid1() + elif grid == get_grid1(): + return get_grid0() + else: + assert(false) + + func get_neighbours() -> Array: + var ret: Array = [] + for line in gameScene.get_lines_by_grid(get_grid0()): + ret.append(line) + for line in gameScene.get_lines_by_grid(get_grid1()): + ret.append(line) + ret.remove(ret.find(self)) + return ret + + func _to_string() -> String: + return "Line %d" % [idx] diff --git a/scripts/GameState.gd b/scripts/GameState.gd new file mode 100644 index 0000000..25422bf --- /dev/null +++ b/scripts/GameState.gd @@ -0,0 +1,32 @@ +extends Reference + +class_name GameState + +# var parent: GameState # possibly reference the previous state and only store changed cells + +# cell state info +var cellOwners: Array + +# line state info +var lineOwners: Array + +func init_arrays(size: Vector2): + var cells: int = int(size.x * size.y) + # A grid graph G_(m,n) has mn nodes and (m-1)n+(n-1)m=2mn-m-n edges + var lines: int = int((2 * size.x * size.y) - size.x - size.y) + for _cell in range(cells): + cellOwners.append(0) + for _line in range(lines): + lineOwners.append(0) + +func clone() -> GameState: + var ret = .new() + ret.cellOwners = cellOwners.duplicate() + ret.lineOwners = lineOwners.duplicate() + return ret; + +func get_cell_count(): + return cellOwners.size() + +func get_line_count(): + return lineOwners.size() diff --git a/scripts/Line.gd b/scripts/Line.gd new file mode 100644 index 0000000..811f370 --- /dev/null +++ b/scripts/Line.gd @@ -0,0 +1,47 @@ +extends Line2D + +var idx: int +var accessor: GameScene.LineAccessor + +var hovered: bool + +var moveSpeed: float = rand_range(0.5,1.5) + +signal line_clicked(id) + +func _ready() -> void: + accessor = get_parent().get_line(idx) + +func _process(delta: float) -> void: + var p0: Vector2 = accessor.get_point0() + var p1: Vector2 = accessor.get_point1() + points[0] = points[0].linear_interpolate(p0,delta*moveSpeed) + points[1] = points[1].linear_interpolate(p1,delta*moveSpeed) + + if $Area2D/CollisionShape2D != null: + $Area2D/CollisionShape2D.rotation = p0.angle_to(p1) + (0.5 * PI) + $Area2D/CollisionShape2D.position = p0.linear_interpolate(p1,0.5) + $Area2D/CollisionShape2D.shape.height = p0.distance_to(p1) + + var owner: int = accessor.get_owner() + match owner: + 0: + default_color = Color.gray + 1: + default_color = Color.red + 2: + default_color = Color.blue + + if hovered: + default_color = default_color.lightened(0.2) + +func _input(event: InputEvent) -> void: + if event is InputEventMouseButton: + if event.button_index == BUTTON_LEFT and event.pressed and hovered: + emit_signal("line_clicked", idx) + +func _on_Area2D_mouse_entered() -> void: + hovered = true + +func _on_Area2D_mouse_exited() -> void: + hovered = false diff --git a/scripts/PlayerController.gd b/scripts/PlayerController.gd new file mode 100644 index 0000000..291ae5d --- /dev/null +++ b/scripts/PlayerController.gd @@ -0,0 +1,16 @@ +extends Node + + +# Declare member variables here. Examples: +# var a: int = 2 +# var b: String = "text" + + +# Called when the node enters the scene tree for the first time. +func _ready() -> void: + pass # Replace with function body. + + +# Called every frame. 'delta' is the elapsed time since the previous frame. +#func _process(delta: float) -> void: +# pass