generated from Nekojimi/GodotTemplate
parent
dd4ff4da14
commit
61091b05db
Binary file not shown.
@ -1,18 +1,18 @@ |
|||||||
[general] |
[general] |
||||||
|
|
||||||
singleton=true |
singleton=true |
||||||
load_once=true |
load_once=true |
||||||
symbol_prefix="godot_" |
symbol_prefix="godot_" |
||||||
reloadable=false |
reloadable=false |
||||||
|
|
||||||
[entry] |
[entry] |
||||||
|
|
||||||
OSX.64="res://addons/godot-git-plugin/osx/release/libgitapi.dylib" |
OSX.64="res://addons/godot-git-plugin/osx/release/libgitapi.dylib" |
||||||
Windows.64="res://addons/godot-git-plugin/win64/release/libgitapi.dll" |
Windows.64="res://addons/godot-git-plugin/win64/release/libgitapi.dll" |
||||||
X11.64="res://addons/godot-git-plugin/x11/release/libgitapi.so" |
X11.64="res://addons/godot-git-plugin/x11/release/libgitapi.so" |
||||||
|
|
||||||
[dependencies] |
[dependencies] |
||||||
|
|
||||||
OSX.64=[ ] |
OSX.64=[ ] |
||||||
Windows.64=[ ] |
Windows.64=[ ] |
||||||
X11.64=[ ] |
X11.64=[ ] |
||||||
|
@ -1,5 +1,7 @@ |
|||||||
[gd_resource type="Environment" load_steps=2 format=2] |
[gd_resource type="Environment" load_steps=2 format=2] |
||||||
|
|
||||||
[sub_resource type="ProceduralSky" id=1] |
[sub_resource type="ProceduralSky" id=1] |
||||||
|
|
||||||
[resource] |
[resource] |
||||||
background_mode = 2 |
background_mode = 2 |
||||||
background_sky = SubResource( 1 ) |
background_sky = SubResource( 1 ) |
||||||
|
@ -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