generated from Nekojimi/GodotTemplate
Added initial version of loop-drawing functionality.
This commit is contained in:
parent
dd4ff4da14
commit
61091b05db
Binary file not shown.
|
@ -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=[ ]
|
||||
|
|
|
@ -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 )
|
||||
|
|
|
@ -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" ]
|
||||
|
|
|
@ -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 )
|
|
@ -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 )
|
|
@ -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"]
|
|
@ -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 )
|
|
@ -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
|
|
@ -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]
|
|
@ -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()
|
|
@ -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
|
|
@ -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
|
Loading…
Reference in New Issue