summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--Camera.gd35
-rw-r--r--Hex.gd24
-rw-r--r--HexBoard.gd345
-rw-r--r--Los.gd21
-rw-r--r--Main.gd40
-rw-r--r--Main.tscn68
-rw-r--r--Map.gd122
-rw-r--r--Map.tscn4
-rw-r--r--Tile.gd36
-rw-r--r--assets/black.pngbin0 -> 2868 bytes
-rw-r--r--assets/block.pngbin0 -> 5029 bytes
-rw-r--r--assets/green.pngbin0 -> 6204 bytes
-rw-r--r--assets/map-h.pngbin0 -> 18756 bytes
-rw-r--r--assets/map-v.pngbin0 -> 28405 bytes
-rw-r--r--assets/tank.pngbin0 -> 10024 bytes
-rw-r--r--assets/target.pngbin0 -> 8674 bytes
-rw-r--r--default_env.tres7
-rw-r--r--godot/HexBoard.pngbin0 -> 1209 bytes
-rw-r--r--godot/Tile.pngbin0 -> 1209 bytes
-rw-r--r--icon.pngbin0 -> 3305 bytes
-rw-r--r--project.godot37
22 files changed, 740 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..e4fdbdb
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+*.import
diff --git a/Camera.gd b/Camera.gd
new file mode 100644
index 0000000..bb99330
--- /dev/null
+++ b/Camera.gd
@@ -0,0 +1,35 @@
+extends Camera2D
+
+var margin :Vector2
+var window : Vector2
+var map_center : Vector2
+var texture_size : Vector2
+var zoom_boundaries : Vector2
+
+func _ready():
+ margin = Vector2(0, 0)
+ #window = set within Main
+
+func on_configure(c : Vector2, ts : Vector2) -> void:
+ map_center = c
+ texture_size = ts
+ zoom_boundaries = Vector2(1.0, max((texture_size.x + margin.x) / window.x, (texture_size.y + margin.y) / window.y))
+ update_camera(0, 0, zoom_boundaries.y)
+
+func update_camera(x : float, y : float, z : float) -> void:
+ if z != 0:
+ zoom.x = clamp(zoom.x + z, zoom_boundaries.x, zoom_boundaries.y)
+ zoom.y = zoom.x
+ position.x += x
+ position.y += y
+ var delta = texture_size + margin - (window * zoom.x)
+ if (delta.x <= 0):
+ position.x = map_center.x
+ else:
+ var dx = int(delta.x / 2)
+ position.x = clamp(position.x, map_center.x - dx, map_center.x + dx)
+ if (delta.y <= 0):
+ position.y = map_center.y
+ else:
+ var dy = int(delta.y / 2)
+ position.y = clamp(position.y, map_center.y - dy, map_center.y + dy)
diff --git a/Hex.gd b/Hex.gd
new file mode 100644
index 0000000..f06c7bf
--- /dev/null
+++ b/Hex.gd
@@ -0,0 +1,24 @@
+#warning-ignore-all:unused_argument
+extends Tile
+
+class_name Hex, "res://godot/Tile.png"
+
+func inspect() -> String:
+ return "[%d;%d] %s" % [coords.x,coords.y,not blocked]
+
+func block(b : bool) -> void:
+ enable_overlay(0, b)
+
+func is_blocked() -> bool:
+ return is_overlay_on(0)
+
+func block_los(from : Tile, to : Tile, d : float, dt : float) -> bool:
+ return is_blocked()
+
+func show_los(b) -> void:
+ if not b:
+ enable_overlay(1, false)
+ enable_overlay(2, false)
+ else:
+ if blocked: enable_overlay(2, true)
+ else: enable_overlay(1, true)
diff --git a/HexBoard.gd b/HexBoard.gd
new file mode 100644
index 0000000..ce240f8
--- /dev/null
+++ b/HexBoard.gd
@@ -0,0 +1,345 @@
+#warning-ignore-all:integer_division
+extends Node
+
+class_name HexBoard, "res://godot/HexBoard.png"
+
+enum Orientation { E=1, NE=2, N=4, NW=8, W=16, SW=32, S=64, SE=128 }
+
+var bt : Vector2 # bottom corner
+var cr : Vector2 # column, row
+
+var v : bool # hex have a vertical edje
+
+var s : float # hex side length
+var w : float # hex width between 2 parallel sides
+var h : float # hex height from the bottom of the middle rectangle to the top of the upper edje
+var dw : float # half width
+var dh : float # half height (from the top ef tho middle rectangle to the top of the upper edje)
+var m : float # dh / dw
+var im : float # dw / dh
+var tl : int # num of hexes in 2 consecutives rows
+
+var tile_factory_fct : FuncRef
+var angles : Dictionary
+
+func configure(cols : int, rows : int, side : float, v0 : Vector2, vertical : bool) -> void:
+ v = vertical
+ s = side
+ w = s * 1.73205
+ dw = w / 2.0
+ dh = s / 2.0
+ h = s + dh
+ m = dh / dw
+ im = dw / dh
+ if v:
+ bt = v0
+ cr = Vector2(cols, rows)
+ else:
+ bt = v0
+ cr = Vector2(rows, cols)
+ tl = (2 * int(cr.x) - 1)
+ angles = {}
+ if v:
+ angles[Orientation.E] = 0
+ angles[Orientation.NE] = 60
+ angles[Orientation.NW] = 120
+ angles[Orientation.W] = 180
+ angles[Orientation.SW] = 240
+ angles[Orientation.SE] = 300
+ else:
+ angles[Orientation.NE] = 30
+ angles[Orientation.N] = 90
+ angles[Orientation.NW] = 150
+ angles[Orientation.SW] = 210
+ angles[Orientation.S] = 270
+ angles[Orientation.SE] = 330
+
+func size() -> int:
+ return int(cr.y) / 2 * tl + int(cr.y) % 2 * int(cr.x)
+
+func get_tile(coords : Vector2) -> Tile:
+ return tile_factory_fct.call_func(coords, key(coords))
+
+func to_angle(o : int) -> int:
+ return angles.get(o, -1)
+
+func to_orientation(a : float) -> int:
+ for k in angles.keys():
+ if angles[k] == a:
+ return k
+ return -1
+
+func angle(from : Tile, to : Tile) -> int:
+ var a : float = rad2deg((to.position - from.position).angle()) + 2
+ if a < 0: a += 360
+ return int(a / 10) * 10
+
+func opposite(o : int) -> int:
+ if o <= Orientation.NW: return o << 4
+ return o >> 4
+
+func key(coords : Vector2) -> int:
+ if not is_on_map(coords): return -1
+ if v: return _key(int(coords.x), int(coords.y))
+ else: return _key(int(coords.y), int(coords.x))
+
+func _key(x : int, y : int) -> int:
+ var n : int = y / 2
+ var i : int = x - n + n * tl
+ if (y % 2) != 0:
+ i += (int(cr.x) - 1)
+ return i
+
+func is_on_map(coords : Vector2) -> bool:
+ if v: return _is_on_map(int(coords.x), int(coords.y))
+ else: return _is_on_map(int(coords.y), int(coords.x))
+
+func _is_on_map(x : int, y : int) -> bool:
+ if (y < 0) || (y >= int(cr.y)): return false
+ if (x < ((y + 1) / 2)) || (x >= (int(cr.x) + (y / 2))): return false
+ return true
+
+func center_of(coords : Vector2) -> Vector2:
+ if v: return Vector2(bt.x + dw + (coords.x * w) - (coords.y * dw), bt.y + dh + (coords.y * h))
+ else: return Vector2(bt.y + dh + (coords.x * h), bt.x + dw + (coords.y * w) - (coords.x * dw))
+
+func to_map(r : Vector2) -> Vector2:
+ if v: return _to_map(r.x, r.y, false)
+ else: return _to_map(r.y, r.x, true)
+
+func _to_map(x : float, y : float, swap : bool) -> Vector2:
+ var col : int = -1
+ var row : int = -1
+ # compute row
+ var dy : float = y - bt.y
+ row = int(dy / h)
+ if dy < 0:
+ row -= 1
+ # compute col
+ var dx : float = x - bt.x + (row * dw);
+ col = int(dx / w)
+ if dx < 0:
+ col -= 1
+ # upper rectangle or hex body
+ if dy > ((row * h) + s):
+ dy -= ((row * h) + s)
+ dx -= (col * w)
+ # upper left or right rectangle
+ if dx < dw:
+ if dy > (dx * m):
+ # upper left hex
+ row += 1
+ else:
+ if dy > ((w - dx) * m):
+ # upper right hex
+ row += 1
+ col += 1
+ if swap: return Vector2(row, col)
+ else: return Vector2(col, row)
+
+func distance(p0 : Vector2, p1 : Vector2, euclidean : bool = true) -> float:
+ var dx : int = int(p1.x - p0.x)
+ var dy : int = int(p1.y - p0.y)
+ if euclidean:
+ if dx == 0: return abs(dy)
+ elif dy == 0 || dx == dy: return abs(dx)
+ var fdx : float = dx - dy / 2;
+ var fdy : float = dy * 0.86602
+ return sqrt((fdx * fdx) + (fdy * fdy))
+ else:
+ var dz : float = abs((p0.x - p0.y) - (p1.x - p1.y))
+ if dx > dy:
+ if dx > dz : return abs(dx)
+ else:
+ if dy > dz: return abs(dy)
+ return dz
+
+# http://zvold.blogspot.com/2010/01/bresenhams-line-drawing-algorithm-on_26.html
+# http://zvold.blogspot.com/2010/02/line-of-sight-on-hexagonal-grid.html
+func line_of_sight(p0 : Vector2, p1 : Vector2, tiles : Array) -> Vector2:
+ tiles.clear()
+ # orthogonal projection
+ var ox0 : float = p0.x - (p0.y + 1) / 2
+ var ox1 : float = p1.x - (p1.y + 1) / 2
+ var dy : int = int(p1.y) - int(p0.y)
+ var dx : float = ox1 - ox0
+ # quadrant I && III
+ var q13 : bool = (dx >= 0 && dy >= 0) || (dx < 0 && dy < 0)
+ # is positive
+ var xs : int = 1
+ var ys : int = 1
+ if dx < 0: xs = -1
+ if dy < 0: ys = -1
+ # dx counts half width
+ dy = int(abs(dy))
+ dx = abs(2 * dx)
+ var dx3 : int = int(3 * dx)
+ var dy3 : int = 3 * dy
+ # check for diagonals
+ if dx == 0 || dx == dy3:
+ return diagonal_los(p0, p1, (dx == 0), q13, tiles)
+ # angle is less than 45°
+ var flat : bool = dx > dy3
+ var x : int = int(p0.x)
+ var y : int = int(p0.y);
+ var e : int = int(-2 * dx)
+ var from : Tile = get_tile(p0)
+ var to : Tile = get_tile(p1)
+ var d : float = distance(p0, p1)
+ tiles.append(from)
+ from.blocked = false
+ var ret : Vector2 = Vector2(-1, -1)
+ var contact : bool = false
+ var los_blocked : bool = false
+ while (x != p1.x) or (y != p1.y):
+ if e > 0:
+ # quadrant I : up left
+ e -= (dy3 + dx3)
+ y += ys
+ if not q13: x -= xs
+ else:
+ e += dy3
+ if (e > -dx) or (not flat && (e == -dx)):
+ # quadrant I : up right
+ e -= dx3
+ y += ys
+ if q13: x += xs
+ elif e < -dx3:
+ # quadrant I : down right
+ e += dx3
+ y -= ys
+ if not q13: x += xs
+ else:
+ # quadrant I : right
+ e += dy3
+ x += xs
+ var q : Vector2 = Vector2(x, y)
+ var t : Tile = get_tile(q)
+ if los_blocked and not contact:
+ var o : int = to_orientation(angle(tiles[tiles.size() - 1], t))
+ ret = compute_contact(from.position, to.position, o, t.position, true)
+ contact = true
+ tiles.append(t)
+ t.blocked = los_blocked
+ los_blocked = los_blocked or t.block_los(from, to, d, distance(p0, q))
+ return ret
+
+func diagonal_los(p0 : Vector2, p1 : Vector2, flat : bool, q13 : bool, tiles : Array) -> Vector2:
+ var dy : int = 1 if p1.y > p0.y else -1
+ var dx : int = 1 if p1.x > p0.x else -1
+ var x : int = int(p0.x)
+ var y : int = int(p0.y)
+ var from : Tile = get_tile(p0);
+ var to : Tile = get_tile(p1);
+ var d : float = distance(p0, p1)
+ tiles.append(from);
+ from.blocked = false;
+ var ret : Vector2 = Vector2(-1, -1)
+ var blocked : int = 0
+ var contact : bool = false
+ var los_blocked : bool = false
+ while (x != p1.x) or (y != p1.y):
+ var idx : int = 4
+ if flat: y += dy # up left
+ else: x += dx # right
+ var q : Vector2 = Vector2(x, y)
+ var t : Tile = get_tile(q)
+ if t.on_board:
+ tiles.append(t)
+ t.blocked = los_blocked
+ if t.block_los(from, to, d, distance(p0, q)):
+ blocked |= 0x01
+ else:
+ blocked |= 0x01
+ idx = 3
+
+ if flat: x += dx # up right
+ else:
+ y += dy # up right
+ if not q13: x -= dx
+ q = Vector2(x, y)
+ t = get_tile(q)
+ if t.on_board:
+ tiles.append(t)
+ t.blocked = los_blocked
+ if t.block_los(from, to, d, distance(p0, q)):
+ blocked |= 0x02
+ else:
+ blocked |= 0x02
+ idx = 3
+
+ if flat: y += dy # up
+ else: x += dx # diagonal
+ q = Vector2(x, y)
+ t = get_tile(q)
+ tiles.append(t)
+ t.blocked = los_blocked || blocked == 0x03
+ if t.blocked and not contact:
+ var o : int = compute_orientation(dx, dy, flat)
+ if not los_blocked and blocked == 0x03:
+ ret = compute_contact(from.position, to.position, o, t.position, false)
+ else:
+ ret = compute_contact(from.position, to.position, opposite(o), tiles[tiles.size() - idx].position, false)
+ contact = true;
+ los_blocked = t.blocked || t.block_los(from, to, d, distance(p0, q))
+ return ret
+
+func compute_orientation(dx :int, dy :int, flat : bool) -> int:
+ if flat:
+ if v: return Orientation.N if dy == 1 else Orientation.S
+ else: return Orientation.NE if dy == 1 else Orientation.SW
+ if dx == 1:
+ if dy == 1: return Orientation.NE if v else Orientation.E
+ else: return Orientation.SE
+ else:
+ if dy == 1: return Orientation.NW
+ else: return Orientation.SW if v else Orientation.W
+
+func compute_contact(from : Vector2, to : Vector2, o : int, t : Vector2, line : bool) -> Vector2:
+ var dx : float = to.x - from.x
+ var dy : float = to.y - from.y
+ var n : float = 9999999999.0 if dx == 0 else (dy / dx)
+ var c : float = from.y - (n * from.x)
+ if v:
+ if o == Orientation.N: return Vector2(t.x, t.y - s)
+ elif o == Orientation.S: return Vector2(t.x, t.y + s)
+ elif o == Orientation.E:
+ var x : float = t.x - dw
+ return Vector2(x, from.y + n * (x - from.x))
+ elif o == Orientation.W:
+ var x : float = t.x + dw
+ return Vector2(x, from.y + n * (x - from.x))
+ else:
+ if line:
+ var p : float = m if (o == Orientation.SE or o == Orientation.NW) else -m
+ var k : float = t.y - p * t.x
+ if o == Orientation.SE || o == Orientation.SW: k += s
+ else: k -= s
+ var x : float = (k - c) / (n - p)
+ return Vector2(x, n * x + c)
+ else:
+ var x : float = t.x + (-dw if (o == Orientation.NE or o == Orientation.SE) else dw)
+ var y : float = t.y + (dh if (o == Orientation.SE or o == Orientation.SW) else -dh)
+ return Vector2(x, y)
+ else:
+ if o == Orientation.E: return Vector2(t.x - s, t.y)
+ elif o == Orientation.W: return Vector2(t.x + s, t.y)
+ elif o == Orientation.N:
+ var y : float = t.y - dw
+ return Vector2(from.x + (y - from.y) / n, y)
+ elif o == Orientation.S:
+ var y : float = t.y + dw
+ return Vector2(from.x + (y - from.y) / n, y)
+ else:
+ if line:
+# o = 1
+ var p : float = im if (o == Orientation.SE or o == Orientation.NW) else -im
+ var k : float = 0
+ if o == Orientation.SW or o == Orientation.NW: k = t.y - (p * (t.x + s))
+ else: k = t.y - (p * (t.x - s))
+ var x : float = (k - c) / (n - p)
+ return Vector2(x, n * x + c);
+ else:
+ var x : float = t.x + (dh if (o == Orientation.NW || o == Orientation.SW) else -dh)
+ var y : float = t.y + (dw if (o == Orientation.SE || o == Orientation.SW) else -dw)
+ return Vector2(x, y)
diff --git a/Los.gd b/Los.gd
new file mode 100644
index 0000000..324819a
--- /dev/null
+++ b/Los.gd
@@ -0,0 +1,21 @@
+extends Node2D
+
+var p0 : Vector2
+var p1 : Vector2
+var p2 : Vector2
+
+func _ready():
+ pass
+
+func _draw() -> void:
+ if p2.x == -1:
+ draw_line(p0, p1, Color(0, 255, 0))
+ else:
+ draw_line(p0, p2, Color(0, 255, 0))
+ draw_line(p2, p1, Color(255, 0, 0))
+
+func setup(v0 :Vector2, v1 : Vector2, v2 : Vector2) -> void:
+ p0 = v0
+ p1 = v1
+ p2 = v2
+ update()
diff --git a/Main.gd b/Main.gd
new file mode 100644
index 0000000..7de0300
--- /dev/null
+++ b/Main.gd
@@ -0,0 +1,40 @@
+#warning-ignore-all:return_value_discarded
+extends Node2D
+
+var drag_map : bool = false
+
+onready var UI : CanvasLayer = $UI
+onready var Map : Sprite = $ViewportContainer/Viewport/Map
+onready var Camera : Camera2D = $ViewportContainer/Viewport/Camera
+
+func _ready():
+ UI.get_node("rotate").connect("pressed", Map, "on_rotate")
+ Map.connect("configure", Camera, "on_configure")
+ Map.connect("touched", self, "on_touched")
+ Camera.window = $ViewportContainer/Viewport.size
+ Map.on_rotate()
+
+func on_touched(s : String) -> void:
+ UI.get_node("Label").set_text(s)
+
+func _unhandled_input(event : InputEvent) -> void:
+ if event is InputEventMouseMotion:
+ if drag_map:
+ var dv : Vector2 = event.relative * Camera.zoom
+ Camera.update_camera(-dv.x, -dv.y, 0)
+ else:
+ Map.on_mouse_move()
+ elif event is InputEventMouseButton:
+ if event.button_index == 4:
+ Camera.update_camera(0, 0, -0.05)
+ elif event.button_index == 5:
+ Camera.update_camera(0, 0, +0.05)
+ elif event.button_index == 3:
+ drag_map = event.pressed
+ elif event.button_index == 1:
+ Map.on_mouse_1(event.pressed)
+ elif event.button_index == 2:
+ Map.on_mouse_2(event.pressed)
+ elif event is InputEventKey:
+ if event.scancode == KEY_ESCAPE:
+ get_tree().quit()
diff --git a/Main.tscn b/Main.tscn
new file mode 100644
index 0000000..fcecad8
--- /dev/null
+++ b/Main.tscn
@@ -0,0 +1,68 @@
+[gd_scene load_steps=7 format=2]
+
+[ext_resource path="res://Camera.gd" type="Script" id=1]
+[ext_resource path="res://Map.gd" type="Script" id=2]
+[ext_resource path="res://Main.gd" type="Script" id=3]
+[ext_resource path="res://Los.gd" type="Script" id=4]
+[ext_resource path="res://assets/target.png" type="Texture" id=6]
+[ext_resource path="res://assets/tank.png" type="Texture" id=7]
+
+[node name="Main" type="Node2D"]
+script = ExtResource( 3 )
+
+[node name="UI" type="CanvasLayer" parent="."]
+
+[node name="rotate" type="Button" parent="UI"]
+margin_left = 19.0
+margin_top = 17.0
+margin_right = 101.0
+margin_bottom = 56.0
+text = "Rotate"
+__meta__ = {
+"_edit_use_anchors_": false
+}
+
+[node name="Label" type="Label" parent="UI"]
+margin_left = 2.0
+margin_top = 477.0
+margin_right = 131.0
+margin_bottom = 598.0
+__meta__ = {
+"_edit_use_anchors_": false
+}
+
+[node name="ViewportContainer" type="ViewportContainer" parent="."]
+margin_left = 141.0
+margin_top = 19.0
+margin_right = 1004.0
+margin_bottom = 581.0
+mouse_filter = 2
+stretch = true
+__meta__ = {
+"_edit_use_anchors_": false
+}
+
+[node name="Viewport" type="Viewport" parent="ViewportContainer"]
+size = Vector2( 863, 562 )
+handle_input_locally = false
+render_target_update_mode = 3
+
+[node name="Map" type="Sprite" parent="ViewportContainer/Viewport"]
+script = ExtResource( 2 )
+
+[node name="Hexes" type="Node" parent="ViewportContainer/Viewport/Map"]
+
+[node name="Target" type="Sprite" parent="ViewportContainer/Viewport/Map"]
+z_index = 1
+texture = ExtResource( 6 )
+
+[node name="Tank" type="Sprite" parent="ViewportContainer/Viewport/Map"]
+z_index = 1
+texture = ExtResource( 7 )
+
+[node name="Los" type="Node2D" parent="ViewportContainer/Viewport/Map"]
+script = ExtResource( 4 )
+
+[node name="Camera" type="Camera2D" parent="ViewportContainer/Viewport"]
+current = true
+script = ExtResource( 1 )
diff --git a/Map.gd b/Map.gd
new file mode 100644
index 0000000..1300304
--- /dev/null
+++ b/Map.gd
@@ -0,0 +1,122 @@
+extends Sprite
+
+signal configure(center, texture_size)
+signal touched(msg)
+
+const MAPH : String = "res://assets/map-h.png"
+const MAPV : String = "res://assets/map-v.png"
+const BLOCK : String = "res://assets/block.png"
+const BLACK : String = "res://assets/black.png"
+const GREEN : String = "res://assets/green.png"
+
+var drag : Sprite
+
+var board : HexBoard
+var prev : Vector2
+var hexes : Dictionary
+var hex_rotation : int
+var p0 : Vector2
+var p1 : Vector2
+var los : Array
+
+func _ready():
+ board = HexBoard.new()
+ board.tile_factory_fct = funcref(self, "get_tile")
+ board.v = false
+ drag = null
+ hexes = {}
+ los = []
+
+func reset() -> void:
+ hexes.clear()
+ hexes[-1] = Hex.new() # off map
+
+func get_tile(coords : Vector2, k : int) -> Tile:
+ if hexes.has(k): return hexes[k]
+ var hex : Hex = Hex.new()
+ hex.rotation_degrees = hex_rotation
+ hex.configure(board.center_of(coords), coords, [BLOCK, GREEN, BLACK])
+ hexes[k] = hex
+ $Hexes.add_child(hex)
+ return hex
+
+func on_rotate() -> void:
+ texture = load(MAPH if board.v else MAPV)
+ var ts : Vector2 = texture.get_size()
+ var v0 : Vector2 = Vector2(50, 100)
+ var c = ts / 2
+ if centered:
+ if board.v:
+ v0.x -= ts.y / 2
+ v0.y -= ts.x / 2
+ else:
+ v0 -= ts / 2
+ c = Vector2(0, 0)
+ if board.v:
+ hex_rotation = 30
+ board.configure(10, 4, 100, v0, false)
+ else:
+ hex_rotation = 0
+ board.configure(10, 7, 100, v0, true)
+ emit_signal("configure", c, ts)
+ p0 = Vector2(0, 0)
+ p1 = Vector2(3, 3)
+ $Tank.position = board.center_of(p0)
+ $Target.position = board.center_of(p1)
+ for hex in $Hexes.get_children():
+ $Hexes.remove_child(hex)
+ hex.queue_free()
+ reset()
+ update_los()
+
+func on_mouse_move() -> void:
+ if drag != null:
+ drag.position = get_local_mouse_position()
+
+func on_mouse_1(pressed : bool) -> void:
+ var pos : Vector2 = get_local_mouse_position()
+ var coords : Vector2 = board.to_map(pos)
+ if pressed:
+ notify(pos, coords)
+ if drag == null:
+ prev = coords
+ if board.to_map($Tank.position) == coords:
+ drag = $Tank
+ elif board.to_map($Target.position) == coords:
+ drag = $Target
+ else:
+ if drag:
+ if board.is_on_map(coords):
+ drag.position = board.center_of(coords)
+ if drag == $Tank: p0 = coords
+ else: p1 = coords
+ update_los()
+ else:
+ drag.position = board.center_of(prev)
+ drag = null
+
+func on_mouse_2(pressed : bool) -> void:
+ var pos : Vector2 = get_local_mouse_position()
+ var coords : Vector2 = board.to_map(pos)
+ if pressed:
+ notify(pos, coords)
+ var hex : Hex = board.get_tile(coords)
+ if not hex.is_blocked(): hex.block(true)
+ else: hex.block(false)
+ update_los()
+
+func notify(pos : Vector2, coords : Vector2) -> void:
+ if board.is_on_map(coords):
+ var center : Vector2 = board.center_of(coords)
+ var key : int = board.key(coords)
+ emit_signal("touched","%s\n -> %s\n -> %s\n -> %d" % [pos, coords, center, key])
+ else:
+ emit_signal("touched", "off board")
+
+func update_los() -> void:
+ for hex in los:
+ hex.show_los(false)
+ var ct : Vector2 = board.line_of_sight(p0, p1, los)
+ $Los.setup($Tank.position, $Target.position, ct)
+ for hex in los:
+ hex.show_los(true)
diff --git a/Map.tscn b/Map.tscn
new file mode 100644
index 0000000..7ebb23c
--- /dev/null
+++ b/Map.tscn
@@ -0,0 +1,4 @@
+[gd_scene format=2]
+
+[node name="Map" type="Sprite"]
+centered = false
diff --git a/Tile.gd b/Tile.gd
new file mode 100644
index 0000000..ec9b52c
--- /dev/null
+++ b/Tile.gd
@@ -0,0 +1,36 @@
+#warning-ignore-all:unused_argument
+extends Node2D
+
+class_name Tile, "res://godot/Tile.png"
+
+var coords : Vector2
+var blocked : bool
+var on_board : bool = false
+
+func configure(p : Vector2, c: Vector2, o :Array) -> void:
+ position = p
+ coords = c
+ on_board = true
+ for t in o:
+ var s :Sprite = Sprite.new()
+ s.texture = load(t)
+ s.visible = false
+ add_child(s)
+ visible = false
+
+func block_los(from : Tile, to : Tile, d : float, dt : float) -> bool:
+ return false
+
+func enable_overlay(i :int, v : bool) -> void:
+ get_child(i).visible = v
+ if v:
+ visible = true
+ else :
+ visible = false
+ for o in get_children():
+ if o.visible:
+ visible = true
+ break
+
+func is_overlay_on(i) -> bool:
+ return get_child(i).visible
diff --git a/assets/black.png b/assets/black.png
new file mode 100644
index 0000000..09a685d
--- /dev/null
+++ b/assets/black.png
Binary files differ
diff --git a/assets/block.png b/assets/block.png
new file mode 100644
index 0000000..7704d65
--- /dev/null
+++ b/assets/block.png
Binary files differ
diff --git a/assets/green.png b/assets/green.png
new file mode 100644
index 0000000..6970efc
--- /dev/null
+++ b/assets/green.png
Binary files differ
diff --git a/assets/map-h.png b/assets/map-h.png
new file mode 100644
index 0000000..732ef4a
--- /dev/null
+++ b/assets/map-h.png
Binary files differ
diff --git a/assets/map-v.png b/assets/map-v.png
new file mode 100644
index 0000000..fd97059
--- /dev/null
+++ b/assets/map-v.png
Binary files differ
diff --git a/assets/tank.png b/assets/tank.png
new file mode 100644
index 0000000..949ef59
--- /dev/null
+++ b/assets/tank.png
Binary files differ
diff --git a/assets/target.png b/assets/target.png
new file mode 100644
index 0000000..997df02
--- /dev/null
+++ b/assets/target.png
Binary files differ
diff --git a/default_env.tres b/default_env.tres
new file mode 100644
index 0000000..20207a4
--- /dev/null
+++ b/default_env.tres
@@ -0,0 +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/godot/HexBoard.png b/godot/HexBoard.png
new file mode 100644
index 0000000..add6a52
--- /dev/null
+++ b/godot/HexBoard.png
Binary files differ
diff --git a/godot/Tile.png b/godot/Tile.png
new file mode 100644
index 0000000..add6a52
--- /dev/null
+++ b/godot/Tile.png
Binary files differ
diff --git a/icon.png b/icon.png
new file mode 100644
index 0000000..c98fbb6
--- /dev/null
+++ b/icon.png
Binary files differ
diff --git a/project.godot b/project.godot
new file mode 100644
index 0000000..f00effb
--- /dev/null
+++ b/project.godot
@@ -0,0 +1,37 @@
+; Engine configuration file.
+; It's best edited using the editor UI and not directly,
+; since the parameters that go here are not all obvious.
+;
+; Format:
+; [section] ; section goes between []
+; param=value ; assign values to parameters
+
+config_version=4
+
+_global_script_classes=[ {
+"base": "Tile",
+"class": "Hex",
+"language": "GDScript",
+"path": "res://Hex.gd"
+}, {
+"base": "Node",
+"class": "HexBoard",
+"language": "GDScript",
+"path": "res://HexBoard.gd"
+}, {
+"base": "Node2D",
+"class": "Tile",
+"language": "GDScript",
+"path": "res://Tile.gd"
+} ]
+_global_script_class_icons={
+"Hex": "res://godot/Tile.png",
+"HexBoard": "res://godot/HexBoard.png",
+"Tile": "res://godot/Tile.png"
+}
+
+[application]
+
+config/name="hexgrid_demo"
+run/main_scene="res://Main.tscn"
+config/icon="res://icon.png"