Ocean and island navigation usable
parent
7aa4b2d4b9
commit
bc662d616d
11
Globals.gd
11
Globals.gd
|
@ -9,17 +9,22 @@ const SHOVEL_DURATION=1
|
||||||
var DebugLabel = null
|
var DebugLabel = null
|
||||||
var HexGrid = null
|
var HexGrid = null
|
||||||
var HexCell = null
|
var HexCell = null
|
||||||
var OceanGrid = null
|
var OceanNavGrid = null
|
||||||
|
var IslandNavGrid = null
|
||||||
|
|
||||||
var hex_size = 128
|
var hex_size = 128
|
||||||
|
var debug_nav = false
|
||||||
|
|
||||||
# Called when the node enters the scene tree for the first time.
|
# Called when the node enters the scene tree for the first time.
|
||||||
func _ready():
|
func _ready():
|
||||||
HexGrid = preload("../thirdparty/gdhexgrid/HexGrid.gd").new()
|
HexGrid = preload("../thirdparty/gdhexgrid/HexGrid.gd").new()
|
||||||
HexGrid.hex_scale = Vector2(hex_size, hex_size)
|
HexGrid.hex_scale = Vector2(hex_size, hex_size)
|
||||||
|
|
||||||
OceanGrid = preload("../thirdparty/gdhexgrid/HexGrid.gd").new()
|
OceanNavGrid = preload("../thirdparty/gdhexgrid/HexGrid.gd").new()
|
||||||
OceanGrid.hex_scale = Vector2(hex_size, hex_size)
|
OceanNavGrid.hex_scale = Vector2(hex_size, hex_size)
|
||||||
|
|
||||||
|
IslandNavGrid = preload("../thirdparty/gdhexgrid/HexGrid.gd").new()
|
||||||
|
IslandNavGrid.hex_scale = Vector2(hex_size, hex_size)
|
||||||
|
|
||||||
HexCell = preload("../thirdparty/gdhexgrid/HexCell.gd").new()
|
HexCell = preload("../thirdparty/gdhexgrid/HexCell.gd").new()
|
||||||
|
|
||||||
|
|
|
@ -23,17 +23,13 @@ func set_hex_scale(scale):
|
||||||
|
|
||||||
HexPoints = PoolVector2Array()
|
HexPoints = PoolVector2Array()
|
||||||
|
|
||||||
var NoneColors = PoolColorArray()
|
|
||||||
var SandColors = PoolColorArray()
|
|
||||||
var GrassColors = PoolColorArray()
|
|
||||||
|
|
||||||
for i in range (7):
|
for i in range (7):
|
||||||
var angle = (60 * i) * PI / 180
|
var angle = (60 * i) * PI / 180
|
||||||
HexPoints.append(Vector2(cos(angle), sin(angle)) * hex_scale.x / 2)
|
HexPoints.append(Vector2(cos(angle), sin(angle)) * hex_scale.x / 2)
|
||||||
NoneColors.append("#885555")
|
|
||||||
SandColors.append("#ffa106")
|
|
||||||
GrassColors.append("#4b9635")
|
|
||||||
|
|
||||||
|
var NoneColors = create_color_array ("#885555")
|
||||||
|
var SandColors = create_color_array ("#ffa106")
|
||||||
|
var GrassColors = create_color_array ("#4b9635")
|
||||||
|
|
||||||
HexColors = {
|
HexColors = {
|
||||||
TileType.None: NoneColors,
|
TileType.None: NoneColors,
|
||||||
|
@ -41,6 +37,14 @@ func set_hex_scale(scale):
|
||||||
TileType.Grass: GrassColors
|
TileType.Grass: GrassColors
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func create_color_array(color: Color):
|
||||||
|
var result = PoolColorArray()
|
||||||
|
for _i in range (7):
|
||||||
|
result.append(color)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
func get_tile_color (type_name: String):
|
func get_tile_color (type_name: String):
|
||||||
match type_name:
|
match type_name:
|
||||||
"None": return HexColors[TileType.None]
|
"None": return HexColors[TileType.None]
|
||||||
|
|
|
@ -8,6 +8,11 @@ var tile_local_coords = []
|
||||||
var rect_local = Rect2()
|
var rect_local = Rect2()
|
||||||
var radius_world = 0.0
|
var radius_world = 0.0
|
||||||
var is_active = false
|
var is_active = false
|
||||||
|
var landing_site_local_coord = null
|
||||||
|
var landing_site_world = null
|
||||||
|
var ship_anchor_world = null
|
||||||
|
var obstacles_local_coords = {}
|
||||||
|
|
||||||
|
|
||||||
# Called when the node enters the scene tree for the first time.
|
# Called when the node enters the scene tree for the first time.
|
||||||
func _ready():
|
func _ready():
|
||||||
|
@ -58,6 +63,19 @@ func calc_bbox():
|
||||||
print ("center coord: " + str(center_coord))
|
print ("center coord: " + str(center_coord))
|
||||||
radius_world = max(rect_local.size.x, rect_local.size.y) * 0.5
|
radius_world = max(rect_local.size.x, rect_local.size.y) * 0.5
|
||||||
|
|
||||||
|
# brute force the bbox tiles
|
||||||
|
obstacles_local_coords = {}
|
||||||
|
var dx = Globals.hex_size * 0.5
|
||||||
|
var dy = Globals.hex_size * 0.5
|
||||||
|
var n_tiles_x = (rect_local.size.x + Globals.hex_size * 2) / dx
|
||||||
|
var n_tiles_y = (rect_local.size.y + Globals.hex_size * 2) / dy
|
||||||
|
|
||||||
|
for r in range (n_tiles_y):
|
||||||
|
for c in range (n_tiles_x):
|
||||||
|
var point_hex_local = Globals.WorldToHexCenter(Vector2(rect_local.position.x+ c * dx, rect_local.position.y + r * dy) - Vector2.ONE * Globals.hex_size * 0.5)
|
||||||
|
if not obstacles_local_coords.has(point_hex_local) and not tiles.has(point_hex_local):
|
||||||
|
obstacles_local_coords[point_hex_local] = "#bb44aa"
|
||||||
|
|
||||||
|
|
||||||
func save_island(path: String):
|
func save_island(path: String):
|
||||||
var island_save_data = File.new()
|
var island_save_data = File.new()
|
||||||
|
@ -110,12 +128,21 @@ func check_overlap(other):
|
||||||
|
|
||||||
|
|
||||||
func get_tile_by_world_coord(world_coord: Vector2):
|
func get_tile_by_world_coord(world_coord: Vector2):
|
||||||
var center_world = Globals.WorldToHexCenter(world_coord - offset_world)
|
var local_coord = get_local_coord_by_world_coord(world_coord)
|
||||||
if center_world in tiles.keys():
|
|
||||||
return tiles[center_world]
|
if local_coord in tiles.keys():
|
||||||
|
return tiles[local_coord]
|
||||||
return null
|
return null
|
||||||
|
|
||||||
|
|
||||||
|
func is_point_on_landing_site(world_coord: Vector2):
|
||||||
|
return (Globals.WorldToHex(world_coord) - Globals.WorldToHex(landing_site_world)).length_squared() < 1
|
||||||
|
|
||||||
|
|
||||||
|
func get_local_coord_by_world_coord(world_coord: Vector2):
|
||||||
|
return Globals.WorldToHexCenter(world_coord - offset_world)
|
||||||
|
|
||||||
|
|
||||||
func calc_rect_world():
|
func calc_rect_world():
|
||||||
var rect_world = Rect2(rect_local)
|
var rect_world = Rect2(rect_local)
|
||||||
rect_world.position = transform.origin + rect_world.position + offset_world
|
rect_world.position = transform.origin + rect_world.position + offset_world
|
||||||
|
@ -130,15 +157,19 @@ func draw_bsphere():
|
||||||
|
|
||||||
|
|
||||||
func _draw():
|
func _draw():
|
||||||
|
var transform = get_transform()
|
||||||
|
|
||||||
for coord in tiles.keys():
|
for coord in tiles.keys():
|
||||||
draw_set_transform (coord + offset_world, 0, Vector2.ONE)
|
draw_set_transform (coord + offset_world, 0, Vector2.ONE)
|
||||||
draw_polygon(HexTileDrawer.HexPoints, HexTileDrawer.get_tile_color(tiles[coord]))
|
draw_polygon(HexTileDrawer.HexPoints, HexTileDrawer.get_tile_color(tiles[coord]))
|
||||||
|
|
||||||
var transform = get_transform()
|
|
||||||
draw_set_transform(transform.origin + offset_world, transform.get_rotation(), transform.get_scale())
|
draw_set_transform(transform.origin + offset_world, transform.get_rotation(), transform.get_scale())
|
||||||
|
|
||||||
if is_active:
|
if Globals.debug_nav and is_active:
|
||||||
draw_rect(rect_local, Color.red, false)
|
draw_rect(rect_local, Color.red, false)
|
||||||
|
|
||||||
var default_font = Control.new().get_font("font")
|
draw_set_transform_matrix(transform)
|
||||||
draw_string(default_font, Vector2(0, 0), name + str(" ") + str(offset_world))
|
for coord in obstacles_local_coords.keys():
|
||||||
|
draw_set_transform(coord + offset_world, 0, Vector2.ONE)
|
||||||
|
draw_polygon(HexTileDrawer.HexPoints, HexTileDrawer.create_color_array("#922"))
|
||||||
|
|
||||||
|
|
166
scenes/World.gd
166
scenes/World.gd
|
@ -26,7 +26,11 @@ var drag_start = null
|
||||||
var target = Vector2()
|
var target = Vector2()
|
||||||
var tile_data = {}
|
var tile_data = {}
|
||||||
var current_island = null
|
var current_island = null
|
||||||
|
var anchor_tile = null
|
||||||
|
var landing_tile = null
|
||||||
var player_navigation_path = []
|
var player_navigation_path = []
|
||||||
|
var player_path_plan_start = null
|
||||||
|
var player_path_plan_end = null
|
||||||
var hex_line_path = []
|
var hex_line_path = []
|
||||||
|
|
||||||
|
|
||||||
|
@ -45,7 +49,6 @@ func _ready():
|
||||||
|
|
||||||
func _process(_delta):
|
func _process(_delta):
|
||||||
WorldCamera.offset = PlayerChar.position
|
WorldCamera.offset = PlayerChar.position
|
||||||
PlayerBoat.transform.origin = PlayerChar.transform.origin
|
|
||||||
|
|
||||||
if len(player_navigation_path) > 1:
|
if len(player_navigation_path) > 1:
|
||||||
var player_coord = Globals.WorldToHexCenter(PlayerChar.transform.origin)
|
var player_coord = Globals.WorldToHexCenter(PlayerChar.transform.origin)
|
||||||
|
@ -56,10 +59,11 @@ func _process(_delta):
|
||||||
PlayerChar.target = player_navigation_path[0]
|
PlayerChar.target = player_navigation_path[0]
|
||||||
|
|
||||||
update_current_island()
|
update_current_island()
|
||||||
|
|
||||||
if current_island:
|
if current_island:
|
||||||
PlayerBoat.visible = false
|
PlayerBoat.transform.origin = Globals.HexToWorld(anchor_tile)
|
||||||
else:
|
else:
|
||||||
PlayerBoat.visible = true
|
PlayerBoat.transform.origin = PlayerChar.transform.origin
|
||||||
|
|
||||||
|
|
||||||
func draw_hex_path (path: Array, color: Color):
|
func draw_hex_path (path: Array, color: Color):
|
||||||
|
@ -75,9 +79,13 @@ func draw_hex_path (path: Array, color: Color):
|
||||||
|
|
||||||
|
|
||||||
func _draw():
|
func _draw():
|
||||||
draw_hex_path (hex_line_path, "#00f2f2")
|
if Globals.debug_nav:
|
||||||
draw_hex_path (player_navigation_path, "#f200f2")
|
draw_hex_path (hex_line_path, "#00f2f2")
|
||||||
|
draw_hex_path (player_navigation_path, "#f200f2")
|
||||||
|
|
||||||
|
if player_path_plan_start != null and player_path_plan_end != null:
|
||||||
|
draw_circle (player_path_plan_start, 12, "#2288f2")
|
||||||
|
draw_circle (player_path_plan_end, 12, "#2288f2")
|
||||||
|
|
||||||
#
|
#
|
||||||
# World Modification/Query
|
# World Modification/Query
|
||||||
|
@ -156,27 +164,35 @@ func generate():
|
||||||
print ("Placed after " + str(overlap_retry_num) + " retries.")
|
print ("Placed after " + str(overlap_retry_num) + " retries.")
|
||||||
Islands.add_child(island)
|
Islands.add_child(island)
|
||||||
|
|
||||||
populate_ocean_grid()
|
populate_ocean_nav_grid()
|
||||||
|
|
||||||
# var island = Islands.get_children()[0]
|
|
||||||
# var player_pos = island.center_world_coord + island.offset_world
|
|
||||||
# PlayerChar.position = player_pos
|
|
||||||
# PlayerChar.target = player_pos
|
|
||||||
# PlayerChar.update()
|
|
||||||
# print (player_pos)
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Navigation
|
# Navigation
|
||||||
#
|
#
|
||||||
func populate_ocean_grid():
|
func populate_ocean_nav_grid():
|
||||||
var obstacles = Globals.OceanGrid.get_obstacles()
|
var obstacles = Globals.OceanNavGrid.get_obstacles()
|
||||||
Globals.OceanGrid.remove_obstacles(obstacles.keys())
|
Globals.OceanNavGrid.remove_obstacles(obstacles.keys())
|
||||||
Globals.OceanGrid.set_bounds(Vector2.ONE * -500, Vector2.ONE * 500)
|
Globals.OceanNavGrid.set_bounds(Vector2.ONE * -500, Vector2.ONE * 500)
|
||||||
|
|
||||||
for island in Islands.get_children():
|
for island in Islands.get_children():
|
||||||
for tile in island.tiles.keys():
|
for tile in island.tiles.keys():
|
||||||
var grid_coords = Globals.WorldToHex(tile + island.offset_world)
|
var grid_coords = Globals.WorldToHex(tile + island.offset_world)
|
||||||
Globals.OceanGrid.add_obstacles(grid_coords, 15)
|
Globals.OceanNavGrid.add_obstacles(grid_coords, 0)
|
||||||
|
|
||||||
|
|
||||||
|
func populate_island_nav_grid():
|
||||||
|
var obstacles = Globals.IslandNavGrid.get_obstacles()
|
||||||
|
Globals.IslandNavGrid.remove_obstacles(obstacles.keys())
|
||||||
|
Globals.IslandNavGrid.set_bounds(Vector2.ONE * -500, Vector2.ONE * 500)
|
||||||
|
|
||||||
|
if current_island == null:
|
||||||
|
print ("Error: cannot populate island nav grid: no island")
|
||||||
|
return
|
||||||
|
|
||||||
|
for tile in current_island.obstacles_local_coords.keys():
|
||||||
|
var grid_coords = Globals.WorldToHex(tile + current_island.offset_world)
|
||||||
|
Globals.IslandNavGrid.add_obstacles(grid_coords, 0)
|
||||||
|
|
||||||
|
|
||||||
func update_current_island():
|
func update_current_island():
|
||||||
|
@ -191,36 +207,82 @@ func update_current_island():
|
||||||
|
|
||||||
if last_current_island != current_island:
|
if last_current_island != current_island:
|
||||||
if last_current_island != null:
|
if last_current_island != null:
|
||||||
last_current_island.is_active = false
|
on_leave_island(last_current_island)
|
||||||
last_current_island.update()
|
|
||||||
if current_island != null:
|
if current_island != null:
|
||||||
current_island.is_active = true
|
on_enter_island(current_island)
|
||||||
current_island.update()
|
|
||||||
|
|
||||||
|
|
||||||
func update_player_navigation_target(target_world: Vector2):
|
func on_enter_island(island):
|
||||||
player_navigation_path = []
|
print ("Entering island")
|
||||||
|
current_island = island
|
||||||
|
anchor_tile = PlayerChar.prev_tile
|
||||||
|
landing_tile = PlayerChar.cur_tile
|
||||||
|
island.landing_site_world = Globals.WorldToHexCenter(PlayerChar.position)
|
||||||
|
island.landing_site_local_coord = island.get_local_coord_by_world_coord(PlayerChar.position)
|
||||||
|
island.is_active = true
|
||||||
|
populate_island_nav_grid()
|
||||||
|
island.update()
|
||||||
|
|
||||||
var start_world = PlayerChar.transform.origin
|
|
||||||
|
func on_leave_island(island):
|
||||||
|
print ("Leaving island")
|
||||||
|
island.is_active = false
|
||||||
|
island.landing_site_local_coord = null
|
||||||
|
island.update()
|
||||||
|
|
||||||
|
|
||||||
|
func check_player_near_anchor():
|
||||||
|
if current_island == null:
|
||||||
|
return false
|
||||||
|
|
||||||
|
var anchor_world = Globals.HexToWorld(anchor_tile)
|
||||||
|
return (PlayerChar.position - anchor_world).length() < Globals.hex_size
|
||||||
|
|
||||||
|
func update_navigation_target_ocean(start_world: Vector2, target_world: Vector2):
|
||||||
var start_coord = Globals.WorldToHex(start_world)
|
var start_coord = Globals.WorldToHex(start_world)
|
||||||
var goal_coord = Globals.WorldToHex(target_world)
|
var goal_coord = Globals.WorldToHex(target_world)
|
||||||
|
var island_landing_site_world = null
|
||||||
|
|
||||||
|
player_path_plan_start = null
|
||||||
|
player_path_plan_end = null
|
||||||
|
|
||||||
|
var direct_path = Globals.WorldLineToHexTiles(start_world, target_world)
|
||||||
|
|
||||||
|
if get_tile_type(start_world) != null and current_island != null and len(direct_path) > 1:
|
||||||
|
print ("type 0: ", get_tile_type(direct_path[0]))
|
||||||
|
print ("type 1: ", get_tile_type(direct_path[1]))
|
||||||
|
print ("on landing site: ", current_island.is_point_on_landing_site (start_world))
|
||||||
|
if current_island.is_point_on_landing_site (start_world):
|
||||||
|
if get_tile_type(direct_path[1]) == null:
|
||||||
|
print ("starting from landing site")
|
||||||
|
direct_path.pop_front()
|
||||||
|
start_coord = Globals.WorldToHex(direct_path.front())
|
||||||
|
else:
|
||||||
|
print ("Invalid start")
|
||||||
|
return
|
||||||
|
|
||||||
|
# In case target is on an island we find both a landing site and
|
||||||
|
# the first point on the ocean that we can reach.
|
||||||
if get_tile_type(target_world) != null:
|
if get_tile_type(target_world) != null:
|
||||||
var direct_path = Globals.WorldLineToHexTiles(target_world, start_world)
|
|
||||||
var last_removed = null
|
var last_removed = null
|
||||||
while len(direct_path) > 0 and get_tile_type(direct_path[0]) != null:
|
while len(direct_path) > 0 and get_tile_type(direct_path.back()) != null:
|
||||||
last_removed = direct_path[0]
|
last_removed = direct_path.back()
|
||||||
direct_path.remove(0)
|
direct_path.pop_back()
|
||||||
|
|
||||||
if len(direct_path) == 0:
|
if len(direct_path) == 0:
|
||||||
print ("Could not find path!")
|
print ("Could not find path!")
|
||||||
return
|
return
|
||||||
|
|
||||||
print ("Using ", Globals.WorldToHex(direct_path[0]), " instead of ", goal_coord, " as goal.")
|
print ("Using ", Globals.WorldToHex(direct_path.back()), " instead of ", goal_coord, " as goal.")
|
||||||
goal_coord = Globals.WorldToHex(last_removed)
|
goal_coord = Globals.WorldToHex(direct_path.back())
|
||||||
|
island_landing_site_world = last_removed
|
||||||
|
|
||||||
var path = Globals.OceanGrid.find_path(start_coord, goal_coord)
|
player_path_plan_start = Globals.HexToWorld(start_coord)
|
||||||
for target in path.slice(1,-1):
|
player_path_plan_end = Globals.HexToWorld(goal_coord)
|
||||||
|
|
||||||
|
var path = Globals.OceanNavGrid.find_path(start_coord, goal_coord)
|
||||||
|
for target in path.slice(0,-1):
|
||||||
var target_world_coord = Globals.HexToWorld(target.axial_coords)
|
var target_world_coord = Globals.HexToWorld(target.axial_coords)
|
||||||
var target_type = get_tile_type(target_world_coord)
|
var target_type = get_tile_type(target_world_coord)
|
||||||
|
|
||||||
|
@ -229,9 +291,49 @@ func update_player_navigation_target(target_world: Vector2):
|
||||||
if target_type == "Sand":
|
if target_type == "Sand":
|
||||||
break
|
break
|
||||||
|
|
||||||
|
if island_landing_site_world != null:
|
||||||
|
player_navigation_path.append(island_landing_site_world)
|
||||||
|
|
||||||
if len(player_navigation_path) > 0:
|
if len(player_navigation_path) > 0:
|
||||||
PlayerChar.target = player_navigation_path[0]
|
PlayerChar.target = player_navigation_path[0]
|
||||||
|
|
||||||
|
|
||||||
|
func update_navigation_target_island(start_world: Vector2, target_world: Vector2):
|
||||||
|
print ("Navigating Island")
|
||||||
|
var start_coord = Globals.WorldToHex(start_world)
|
||||||
|
var goal_coord = Globals.WorldToHex(target_world)
|
||||||
|
|
||||||
|
var path = Globals.IslandNavGrid.find_path(start_coord, goal_coord)
|
||||||
|
print ("Path length: ", len(path))
|
||||||
|
for target in path.slice(0,-1):
|
||||||
|
var target_world_coord = Globals.HexToWorld(target.axial_coords)
|
||||||
|
var target_type = get_tile_type(target_world_coord)
|
||||||
|
|
||||||
|
player_navigation_path.append(target_world_coord)
|
||||||
|
|
||||||
|
|
||||||
|
func update_player_navigation_target(target_world: Vector2):
|
||||||
|
var start_world = PlayerChar.transform.origin
|
||||||
|
|
||||||
|
player_navigation_path = []
|
||||||
|
|
||||||
|
var start_timestamp = OS.get_system_time_msecs()
|
||||||
|
|
||||||
|
var player_near_anchor = check_player_near_anchor()
|
||||||
|
print ("Player near anchor: ", player_near_anchor)
|
||||||
|
|
||||||
|
if current_island != null:
|
||||||
|
update_navigation_target_island(start_world, target_world)
|
||||||
|
|
||||||
|
if len(player_navigation_path) == 0 and player_near_anchor:
|
||||||
|
start_world = Globals.HexToWorld(anchor_tile)
|
||||||
|
|
||||||
|
if current_island == null or (len(player_navigation_path) == 0 and player_near_anchor):
|
||||||
|
update_navigation_target_ocean(start_world, target_world)
|
||||||
|
|
||||||
|
var planning_duration_msec = OS.get_system_time_msecs() - start_timestamp
|
||||||
|
print ("Planning took ", round(planning_duration_msec), "ms.")
|
||||||
|
|
||||||
update()
|
update()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,8 @@ export (int) var speed = 200
|
||||||
|
|
||||||
var velocity = Vector2()
|
var velocity = Vector2()
|
||||||
var target = Vector2()
|
var target = Vector2()
|
||||||
|
var prev_tile = null # Hex coords of previous tile
|
||||||
|
var cur_tile = null # Hex coords of current tile
|
||||||
|
|
||||||
func get_input():
|
func get_input():
|
||||||
velocity = Vector2()
|
velocity = Vector2()
|
||||||
|
@ -17,11 +19,18 @@ func get_input():
|
||||||
velocity.y -= 1
|
velocity.y -= 1
|
||||||
velocity = velocity.normalized() * speed
|
velocity = velocity.normalized() * speed
|
||||||
|
|
||||||
|
|
||||||
func _physics_process(_delta):
|
func _physics_process(_delta):
|
||||||
velocity = position.direction_to(target) * speed
|
velocity = position.direction_to(target) * speed
|
||||||
if position.distance_to(target) > 5:
|
if position.distance_to(target) > 5:
|
||||||
velocity = move_and_slide(velocity)
|
velocity = move_and_slide(velocity)
|
||||||
|
|
||||||
|
var tile = Globals.WorldToHex(position)
|
||||||
|
if tile != cur_tile:
|
||||||
|
prev_tile = cur_tile
|
||||||
|
cur_tile = tile
|
||||||
|
|
||||||
|
|
||||||
# Called when the node enters the scene tree for the first time.
|
# Called when the node enters the scene tree for the first time.
|
||||||
func _ready():
|
func _ready():
|
||||||
position = Vector2(0,0)
|
position = Vector2(0,0)
|
||||||
|
|
Loading…
Reference in New Issue