Grid wip
This commit is contained in:
parent
f816a8b886
commit
090de86455
14 changed files with 294 additions and 12 deletions
169
systems/grid.gd
Normal file
169
systems/grid.gd
Normal file
|
|
@ -0,0 +1,169 @@
|
|||
extends Node2D
|
||||
|
||||
|
||||
## Grid with cells in it
|
||||
class_name Grid
|
||||
|
||||
## Out of bounds return value
|
||||
const OUT_OF_BOUNDS: int = -1
|
||||
|
||||
## Amount of rows (max Y value)
|
||||
@export var rows: int = 1
|
||||
## Amount of columns (max X value)
|
||||
@export var columns: int = 1
|
||||
|
||||
## Node that marks right down position of grid
|
||||
@export var right_border_marker: Node2D
|
||||
|
||||
## Computed size of one cell
|
||||
@onready var cell_size = (right_border_marker.global_position - global_position) / Vector2(columns,rows)
|
||||
## Computed rect of grid
|
||||
@onready var rect: Rect2 = Rect2(global_position,(right_border_marker.global_position - global_position))
|
||||
|
||||
## Array that holds units
|
||||
var grid: Array[Unit] = []
|
||||
|
||||
func _ready() -> void:
|
||||
grid.resize(rows*columns)
|
||||
|
||||
## Returns true if position is in bounds else returns false.
|
||||
func is_position_valid(pos: Vector2) -> bool:
|
||||
return rect.has_point(pos)
|
||||
|
||||
## Turns position into internal array index. Returns -1 if position is incorrect
|
||||
func to_index(pos: Vector2) -> int:
|
||||
if is_position_valid(pos) == false: return OUT_OF_BOUNDS
|
||||
var snapped_position: Vector2 = (pos - global_position)/cell_size
|
||||
return int(snapped_position.x) + columns * int(snapped_position.y)
|
||||
|
||||
## Turns index into global world position
|
||||
func from_index(index: int, centered: bool = false) -> Vector2:
|
||||
if index < 0 or index >= columns * rows:
|
||||
return Vector2.ZERO
|
||||
return Vector2(index % columns, index / columns) * cell_size + (cell_size/2.0 if centered else Vector2.ZERO)
|
||||
|
||||
## Snaps position through grid
|
||||
func snap_position(pos: Vector2, centered: bool = false) -> Vector2:
|
||||
return global_position + (pos - global_position).snapped(cell_size) + (cell_size / 2) if centered else Vector2.ZERO
|
||||
|
||||
## Returns position as grid snapped local coordinates
|
||||
func to_snapped(pos: Vector2) -> Vector2:
|
||||
if is_position_valid(pos) == false: return Vector2.ZERO
|
||||
var snapped_position: Vector2 = (pos - global_position)/cell_size
|
||||
return Vector2(floor(snapped_position.x),floor(snapped_position.y))
|
||||
|
||||
## Tries to set unit at position and returns false if unit already exists or out of bounds
|
||||
func try_set_unit(pos: Vector2, unit: Unit) -> bool:
|
||||
var index: int = to_index(pos)
|
||||
if index == OUT_OF_BOUNDS:
|
||||
return false
|
||||
|
||||
if grid[index] != null:
|
||||
return false
|
||||
|
||||
grid[index] = unit
|
||||
return true
|
||||
|
||||
## Returns true if cell is occupied or out of bounds and false if cell is empty.
|
||||
func is_occupied(pos: Vector2) -> bool:
|
||||
var index: int = to_index(pos)
|
||||
if index == OUT_OF_BOUNDS:
|
||||
return true
|
||||
|
||||
return grid[index] != null
|
||||
|
||||
## Returns units with given rule predicate.[br]
|
||||
## rule - predicate with signature [code](x,y,source_x,source_y)[/code] -> bool
|
||||
## that needs to return true if cell needs to be checked.[br]
|
||||
## unit - source unit.
|
||||
func get_units(rule: Callable,unit: Unit) -> Array[Unit]:
|
||||
var unit_pos = to_snapped(unit.global_position)
|
||||
var result: Array[Unit] = []
|
||||
for i in range(columns * rows):
|
||||
if rule.call(i%columns,i/columns,int(unit_pos.x),int(unit_pos.y)) and grid[i] != null:
|
||||
result.append(grid[i])
|
||||
|
||||
return result
|
||||
|
||||
## WIP[br]
|
||||
## Returns units with given rule predicate. Checks from source unit with rays and stops only when ray failed.[br]
|
||||
## rule - predicate with signature [code](x,y,source_x,source_y)[/code] -> bool
|
||||
## that needs to return true if cell needs to be checked.[br]
|
||||
## unit - source unit.[br]
|
||||
## rays - amount of rays to check from unit.
|
||||
func get_units_stoppable(rule: Callable, unit: Unit, rays: int = 8) -> Array[Unit]:
|
||||
return []
|
||||
|
||||
## Returns empty cells with given rule predicate.[br]
|
||||
## rule - predicate with signature [code](x,y,source_x,source_y)[/code] -> bool
|
||||
## that needs to return true if cell needs to be checked.[br]
|
||||
## unit - source unit.
|
||||
func get_empty(rule: Callable, unit: Unit) -> Array[int]:
|
||||
var unit_pos = to_snapped(unit.global_position)
|
||||
var result: Array[int] = []
|
||||
for i: int in range(columns * rows):
|
||||
if rule.call(i%columns,i/columns,int(unit_pos.x),int(unit_pos.y)) and grid[i] == null:
|
||||
result.append(i)
|
||||
|
||||
return result
|
||||
|
||||
## WIP[br]
|
||||
## Returns empty with given rule predicate. Checks from source unit with rays and stops only when ray failed.[br]
|
||||
## rule - predicate with signature [code](x,y,source_x,source_y)[/code] -> bool
|
||||
## that needs to return true if cell needs to be checked.[br]
|
||||
## unit - source unit.[br]
|
||||
## rays - amount of rays to check from unit.
|
||||
func get_empty_stoppable(rule: Callable, unit: Unit, rays: int = 8) -> Array[int]:
|
||||
return []
|
||||
|
||||
## Casts a ray along [code]direction[/code] from [code]from[/code] to find unit. If distance is given, restricts lookup to [code]distance[/code] cells.
|
||||
func raycast_unit(from: Vector2,direction: Vector2,distance: float = -1) -> Unit:
|
||||
if not direction.is_normalized():
|
||||
direction = direction.normalized()
|
||||
var result = null
|
||||
|
||||
var to: Vector2 = from + direction * rows * columns
|
||||
var dv: Vector2 = to.floor() - from.floor()
|
||||
var step = abs(dv.x) + 1 if abs(dv.x) > abs(dv.y) else abs(dv.y) + 1
|
||||
var check_pos = from
|
||||
|
||||
while is_position_valid(check_pos) and distance != 0:
|
||||
check_pos += dv/step
|
||||
distance -= 1
|
||||
|
||||
return result
|
||||
|
||||
## Casts a ray along [code]direction[/code] from [code]from[/code] to find all empty cells. If distance is given, restricts lookup to [code]distance[/code] cells.
|
||||
func raycast_empty(from: Vector2,direction: Vector2,distance: float = -1) -> Array[int]:
|
||||
if not direction.is_normalized():
|
||||
direction = direction.normalized()
|
||||
var result: Array[int] = []
|
||||
|
||||
var dv: Vector2 = (Vector2.ONE/direction).round()
|
||||
var steps_y: int = int(abs(dv.y))
|
||||
var steps_x: int = int(abs(dv.x))
|
||||
var check_pos = from.floor()
|
||||
var change_y: bool = true if abs(dv.y) > abs(dv.x) else false
|
||||
|
||||
while is_position_valid(check_pos) and distance != 0:
|
||||
if steps_x == 0:
|
||||
steps_x = int(abs(dv.x))
|
||||
change_y = true
|
||||
elif steps_y == 0:
|
||||
steps_y = int(abs(dv.y))
|
||||
change_y = false
|
||||
|
||||
if change_y:
|
||||
check_pos += Vector2(0,sign(dv.y)) * cell_size
|
||||
steps_y-=1
|
||||
else:
|
||||
check_pos += Vector2(sign(dv.x),0) * cell_size
|
||||
steps_x -= 1
|
||||
|
||||
var index = to_index(check_pos)
|
||||
if index == -1:
|
||||
break
|
||||
if grid[index] == null:
|
||||
result.append(index)
|
||||
|
||||
return result
|
||||
Loading…
Add table
Add a link
Reference in a new issue