Mario Party
parent
2e9b1264f0
commit
5ab6f82f4b
|
@ -11,7 +11,7 @@ config_version=5
|
||||||
[application]
|
[application]
|
||||||
|
|
||||||
config/name="pathfinding-algorithms"
|
config/name="pathfinding-algorithms"
|
||||||
run/main_scene="res://scenes/custom-solver/custom-graph-solver.tscn"
|
run/main_scene="res://scenes/mario-party/MarioParty.tscn"
|
||||||
config/features=PackedStringArray("4.3", "Forward Plus")
|
config/features=PackedStringArray("4.3", "Forward Plus")
|
||||||
config/icon="res://icon.svg"
|
config/icon="res://icon.svg"
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,204 @@
|
||||||
|
class_name MPNavigationGraph
|
||||||
|
extends Node2D
|
||||||
|
|
||||||
|
# godot does not support types on dictionaries, actual type is Dictionary[NavigationNode, Array[NavigationNode]]
|
||||||
|
var navigation_nodes: Dictionary = {}
|
||||||
|
var latest_navigation_result: PathfindingResult = null
|
||||||
|
var draw_nodes: bool = true
|
||||||
|
var draw_edges: bool = true
|
||||||
|
|
||||||
|
|
||||||
|
func all_nodes() -> Array[NavigationNode]:
|
||||||
|
# i've had a problem where godot would not allow me to directly return navigation_nodes.keys()
|
||||||
|
# because it wasn't able to cast the keys to Array[NavigationNode] directly because the type is not explicit
|
||||||
|
# on the dictionary, so i had to do this workaround.
|
||||||
|
var keys: Array = navigation_nodes.keys()
|
||||||
|
var nodes: Array[NavigationNode] = []
|
||||||
|
for key in keys:
|
||||||
|
if key is NavigationNode:
|
||||||
|
nodes.append(key)
|
||||||
|
else:
|
||||||
|
push_error("Key is not a NavigationNode: %s" % key)
|
||||||
|
return nodes
|
||||||
|
|
||||||
|
|
||||||
|
func get_connections(from: NavigationNode) -> Array[NavigationNode]:
|
||||||
|
# the same problem as the all_nodes() function
|
||||||
|
var connections: Array = navigation_nodes[from]
|
||||||
|
var nodes: Array[NavigationNode] = []
|
||||||
|
for connection in connections:
|
||||||
|
if connection is NavigationNode:
|
||||||
|
nodes.append(connection)
|
||||||
|
else:
|
||||||
|
push_error("Connection is not a NavigationNode: %s" % connection)
|
||||||
|
return nodes
|
||||||
|
|
||||||
|
|
||||||
|
func add_connection(from: NavigationNode, to: NavigationNode) -> void:
|
||||||
|
if all_nodes().has(from):
|
||||||
|
navigation_nodes[from].append(to)
|
||||||
|
else:
|
||||||
|
navigation_nodes[from] = [to]
|
||||||
|
|
||||||
|
|
||||||
|
func add_node(x: float, y: float, merge_threshold: float = -1.0) -> NavigationNode:
|
||||||
|
if merge_threshold > 0:
|
||||||
|
var closest_node: NavigationNode = find_closest_node_with_threshold(Vector2(x, y), merge_threshold)
|
||||||
|
if closest_node:
|
||||||
|
closest_node.was_merged = true
|
||||||
|
return closest_node
|
||||||
|
var node: NavigationNode = NavigationNode.new()
|
||||||
|
node.set_position(Vector2(x, y))
|
||||||
|
navigation_nodes[node] = []
|
||||||
|
return node
|
||||||
|
|
||||||
|
|
||||||
|
func find_closest_node_with_threshold(position: Vector2, threshold: float) -> NavigationNode:
|
||||||
|
var closest_node: NavigationNode = null
|
||||||
|
var closest_distance: float = threshold
|
||||||
|
for node in all_nodes():
|
||||||
|
var distance: float = position.distance_to(node.position)
|
||||||
|
if distance < closest_distance:
|
||||||
|
closest_node = node
|
||||||
|
closest_distance = distance
|
||||||
|
return closest_node
|
||||||
|
|
||||||
|
|
||||||
|
func remove_connection(from: NavigationNode, to: NavigationNode) -> void:
|
||||||
|
if all_nodes().has(from):
|
||||||
|
navigation_nodes[from].erase(to)
|
||||||
|
|
||||||
|
|
||||||
|
func remove_node(node: NavigationNode) -> void:
|
||||||
|
navigation_nodes.erase(node)
|
||||||
|
for other_node in all_nodes():
|
||||||
|
if other_node != node:
|
||||||
|
remove_connection(other_node, node)
|
||||||
|
|
||||||
|
|
||||||
|
func _draw() -> void:
|
||||||
|
print("Drawing navigation graph")
|
||||||
|
if draw_nodes or draw_edges:
|
||||||
|
for from in all_nodes():
|
||||||
|
if draw_edges:
|
||||||
|
for to in get_connections(from):
|
||||||
|
draw_line(local_to_world(from.position), local_to_world(to.position), Color.RED, 1, false)
|
||||||
|
if draw_nodes:
|
||||||
|
draw_circle(local_to_world(from.position), 5, Color.RED)
|
||||||
|
|
||||||
|
if latest_navigation_result != null:
|
||||||
|
if latest_navigation_result.path.size() > 1:
|
||||||
|
for i in range(latest_navigation_result.path.size() - 1):
|
||||||
|
draw_line(local_to_world(latest_navigation_result.path[i].position), local_to_world(latest_navigation_result.path[i + 1].position), Color.GREEN, 1, false)
|
||||||
|
draw_circle(local_to_world(latest_navigation_result.next_position), 5, Color.GREEN)
|
||||||
|
|
||||||
|
|
||||||
|
func local_to_world(location: Vector2) -> Vector2:
|
||||||
|
return location * 32 + Vector2(16, 16)
|
||||||
|
|
||||||
|
func draw_pathfinding_result(result: PathfindingResult) -> void:
|
||||||
|
if latest_navigation_result and latest_navigation_result.is_identical_to(result):
|
||||||
|
return
|
||||||
|
latest_navigation_result = result
|
||||||
|
queue_redraw()
|
||||||
|
|
||||||
|
|
||||||
|
func determine_next_position(current_position: Vector2, target_position: Vector2) -> PathfindingResult:
|
||||||
|
var result: PathfindingResult = PathfindingResult.new()
|
||||||
|
|
||||||
|
# Find the closest node to the current position
|
||||||
|
var start_node: NavigationNode = find_closest_node_with_threshold(current_position, INF)
|
||||||
|
if start_node == null:
|
||||||
|
# No nodes exist; cannot navigate
|
||||||
|
result.is_next_target = true
|
||||||
|
result.next_position = current_position
|
||||||
|
return result
|
||||||
|
|
||||||
|
# Find the closest node to the target position
|
||||||
|
var end_node: NavigationNode = find_closest_node_with_threshold(target_position, INF)
|
||||||
|
if end_node == null:
|
||||||
|
# No nodes exist; cannot navigate
|
||||||
|
result.is_next_target = true
|
||||||
|
result.next_position = current_position
|
||||||
|
return result
|
||||||
|
|
||||||
|
# If the start and end nodes are the same, go directly to the target position
|
||||||
|
if start_node == end_node:
|
||||||
|
result.is_next_target = true
|
||||||
|
result.next_position = target_position
|
||||||
|
return result
|
||||||
|
|
||||||
|
# Run Dijkstra's algorithm to find the path
|
||||||
|
var path: Array[NavigationNode] = dijkstra(start_node, end_node)
|
||||||
|
result.path = path
|
||||||
|
|
||||||
|
# If a path is found, return the position of the next node in the path
|
||||||
|
if path.size() > 1:
|
||||||
|
# Next node in the path
|
||||||
|
result.next_position = path[1].position
|
||||||
|
return result
|
||||||
|
elif path.size() == 1:
|
||||||
|
# Directly reachable
|
||||||
|
result.is_next_target = true
|
||||||
|
result.next_position = target_position
|
||||||
|
else:
|
||||||
|
# No path found; return current position
|
||||||
|
result.is_next_target = true
|
||||||
|
result.next_position = current_position
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
func array_contains_node(arr: Array, node: NavigationNode) -> bool:
|
||||||
|
for item in arr:
|
||||||
|
if item == node:
|
||||||
|
return true
|
||||||
|
return false
|
||||||
|
|
||||||
|
|
||||||
|
func dijkstra(start_node: NavigationNode, end_node: NavigationNode) -> Array[NavigationNode]:
|
||||||
|
var open_set: Array[NavigationNode] = []
|
||||||
|
var closed_set: Array[NavigationNode] = []
|
||||||
|
var distances: Dictionary = {}
|
||||||
|
var previous_nodes: Dictionary = {}
|
||||||
|
|
||||||
|
distances[start_node] = 0
|
||||||
|
open_set.append(start_node)
|
||||||
|
|
||||||
|
while open_set.size() > 0:
|
||||||
|
# Find the node with the smallest tentative distance
|
||||||
|
var current_node: NavigationNode = open_set[0]
|
||||||
|
var current_distance: float = distances[current_node]
|
||||||
|
for node in open_set:
|
||||||
|
if distances[node] < current_distance:
|
||||||
|
current_node = node
|
||||||
|
current_distance = distances[node]
|
||||||
|
|
||||||
|
# If the end node is reached, reconstruct the path
|
||||||
|
if current_node == end_node:
|
||||||
|
var path: Array[NavigationNode] = []
|
||||||
|
var node: NavigationNode = end_node
|
||||||
|
while node != null:
|
||||||
|
path.insert(0, node)
|
||||||
|
node = previous_nodes.get(node, null)
|
||||||
|
return path
|
||||||
|
|
||||||
|
open_set.erase(current_node)
|
||||||
|
closed_set.append(current_node)
|
||||||
|
|
||||||
|
# Examine neighbors of the current node
|
||||||
|
var neighbors = get_connections(current_node)
|
||||||
|
for neighbor in neighbors:
|
||||||
|
if array_contains_node(closed_set, neighbor):
|
||||||
|
continue
|
||||||
|
|
||||||
|
var tentative_distance: float = distances[current_node] + current_node.position.distance_to(neighbor.position)
|
||||||
|
|
||||||
|
if not array_contains_node(open_set, neighbor) or tentative_distance < distances.get(neighbor, INF):
|
||||||
|
distances[neighbor] = tentative_distance
|
||||||
|
previous_nodes[neighbor] = current_node
|
||||||
|
if not array_contains_node(open_set, neighbor):
|
||||||
|
open_set.append(neighbor)
|
||||||
|
|
||||||
|
# No path found; return an empty array
|
||||||
|
return []
|
|
@ -0,0 +1,2 @@
|
||||||
|
class_name MPNavigationNode
|
||||||
|
extends Node2D
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,125 @@
|
||||||
|
extends Node2D
|
||||||
|
|
||||||
|
@onready var ground_layer: TileMapLayer = $GroundLayer
|
||||||
|
@onready var path_layer: TileMapLayer = $PathLayer
|
||||||
|
@onready var data_layer: TileMapLayer = $TestDataLayer
|
||||||
|
@onready var navigation_graph: MPNavigationGraph = $NavigationGraph
|
||||||
|
const DIRECTIONS: Dictionary = {
|
||||||
|
"up": Vector2(0, -1),
|
||||||
|
"down": Vector2(0, 1),
|
||||||
|
"left": Vector2(-1, 0),
|
||||||
|
"right": Vector2(1, 0)
|
||||||
|
}
|
||||||
|
var node_positions: Dictionary = {}
|
||||||
|
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
build_graph()
|
||||||
|
|
||||||
|
|
||||||
|
func build_graph() -> void:
|
||||||
|
print("Identifying nodes")
|
||||||
|
# Step 1: Place nodes at positions where is_tile is true
|
||||||
|
for position in data_layer.get_used_cells():
|
||||||
|
var tile_data: TileData = data_layer.get_cell_tile_data(position)
|
||||||
|
var is_tile: bool = tile_data.get_custom_data("is_tile")
|
||||||
|
if is_tile:
|
||||||
|
var node: NavigationNode = navigation_graph.add_node(position.x, position.y)
|
||||||
|
node_positions[position] = node
|
||||||
|
print(Vector2(position))
|
||||||
|
|
||||||
|
# Step 2: Connect nodes using flood-fill based on walkable tiles
|
||||||
|
print("Connecting nodes")
|
||||||
|
for position in node_positions.keys():
|
||||||
|
connect_node(position)
|
||||||
|
|
||||||
|
|
||||||
|
func connect_node(start_position: Vector2) -> void:
|
||||||
|
var start_node = node_positions.get(Vector2i(start_position))
|
||||||
|
var visited: Dictionary = {}
|
||||||
|
visited[start_position] = true
|
||||||
|
print("Connecting node at ", start_position)
|
||||||
|
|
||||||
|
# For each direction, perform flood-fill
|
||||||
|
for dir_name in DIRECTIONS.keys():
|
||||||
|
var direction = DIRECTIONS[dir_name]
|
||||||
|
var next_position = start_position + direction
|
||||||
|
|
||||||
|
print("Checking direction ", dir_name, " from ", start_position, " to ", next_position)
|
||||||
|
|
||||||
|
# Ensure the first tile respects the direction
|
||||||
|
if not is_valid_direction(next_position, dir_name):
|
||||||
|
continue
|
||||||
|
print("Flood-fill in direction ", dir_name, " from ", next_position)
|
||||||
|
|
||||||
|
# Perform flood-fill from the valid tile
|
||||||
|
var connected_nodes: Array = flood_fill(next_position, visited)
|
||||||
|
|
||||||
|
# Add connections between the start node and found nodes
|
||||||
|
for target_position in connected_nodes:
|
||||||
|
if target_position != start_position:
|
||||||
|
if node_positions.has(Vector2i(target_position)):
|
||||||
|
var target_node = node_positions.get(Vector2i(target_position))
|
||||||
|
navigation_graph.add_connection(start_node, target_node)
|
||||||
|
print(start_position, " --> ", target_position)
|
||||||
|
|
||||||
|
|
||||||
|
func flood_fill(start_position: Vector2, visited: Dictionary) -> Array:
|
||||||
|
var stack: Array[Vector2] = [start_position]
|
||||||
|
var connected_nodes: Array[Vector2] = []
|
||||||
|
|
||||||
|
while stack.size() > 0:
|
||||||
|
var current_position = stack.pop_back()
|
||||||
|
print(" - Visiting ", current_position)
|
||||||
|
|
||||||
|
# Skip if already visited
|
||||||
|
if visited.has(current_position):
|
||||||
|
continue
|
||||||
|
|
||||||
|
visited[current_position] = true
|
||||||
|
|
||||||
|
# Skip if not walkable
|
||||||
|
var tile_data: TileData = data_layer.get_cell_tile_data(current_position)
|
||||||
|
if tile_data == null:
|
||||||
|
continue
|
||||||
|
|
||||||
|
var is_walkable: bool = tile_data.get_custom_data("is_walkable")
|
||||||
|
var is_tile: bool = tile_data.get_custom_data("is_tile")
|
||||||
|
if (not is_walkable) and (not is_tile):
|
||||||
|
continue
|
||||||
|
|
||||||
|
# If this position is a node, add it to the result
|
||||||
|
if is_tile:
|
||||||
|
print(" - Found node tile at ", current_position)
|
||||||
|
connected_nodes.append(current_position)
|
||||||
|
else:
|
||||||
|
print(" - Found walkable tile at ", current_position)
|
||||||
|
|
||||||
|
# Add neighboring tiles to the stack if they respect the direction
|
||||||
|
for dir_name in DIRECTIONS.keys():
|
||||||
|
var direction = DIRECTIONS[dir_name]
|
||||||
|
var neighbor_position = current_position + direction
|
||||||
|
|
||||||
|
if not visited.has(neighbor_position):
|
||||||
|
if is_valid_direction(current_position, dir_name):
|
||||||
|
stack.append(neighbor_position)
|
||||||
|
|
||||||
|
return connected_nodes
|
||||||
|
|
||||||
|
|
||||||
|
func is_valid_direction(position: Vector2, required_dir: String) -> bool:
|
||||||
|
var tile_data: TileData = data_layer.get_cell_tile_data(position)
|
||||||
|
if tile_data == null:
|
||||||
|
print(" L Cancelled due to null tile data")
|
||||||
|
return false
|
||||||
|
|
||||||
|
var is_walkable: bool = tile_data.get_custom_data("is_walkable")
|
||||||
|
var walk_dir: String = tile_data.get_custom_data("walk_dir")
|
||||||
|
# If walk_dir is empty, treat it as "any" direction
|
||||||
|
if walk_dir == "":
|
||||||
|
walk_dir = "any"
|
||||||
|
|
||||||
|
print(" L ", position, " ", is_walkable, " ", walk_dir, " ", required_dir)
|
||||||
|
|
||||||
|
# Check if the tile is walkable and allows movement in the required direction
|
||||||
|
return is_walkable and (walk_dir == required_dir or walk_dir == "any")
|
|
@ -0,0 +1,122 @@
|
||||||
|
[gd_resource type="TileSet" load_steps=7 format=3 uid="uid://cm6wi7fjgfk56"]
|
||||||
|
|
||||||
|
[ext_resource type="Texture2D" uid="uid://cmb6k735nhxmy" path="res://scenes/mario-party/img/data_layer.png" id="1_pdyr2"]
|
||||||
|
[ext_resource type="Texture2D" uid="uid://bngfh7nslvij1" path="res://addons/sprout_lands_tilemap/assets/Tilesets/Grass.png" id="2_ev1xx"]
|
||||||
|
[ext_resource type="Texture2D" uid="uid://cvemyer4jq6we" path="res://addons/sprout_lands_tilemap/assets/Objects/Paths.png" id="3_eigvu"]
|
||||||
|
|
||||||
|
[sub_resource type="TileSetAtlasSource" id="TileSetAtlasSource_tp5r2"]
|
||||||
|
texture = ExtResource("1_pdyr2")
|
||||||
|
0:0/0 = 0
|
||||||
|
0:0/0/custom_data_0 = true
|
||||||
|
0:1/0 = 0
|
||||||
|
0:1/0/custom_data_1 = true
|
||||||
|
1:0/0 = 0
|
||||||
|
1:0/0/custom_data_0 = true
|
||||||
|
1:0/0/custom_data_2 = "up"
|
||||||
|
2:0/0 = 0
|
||||||
|
2:0/0/custom_data_0 = true
|
||||||
|
2:0/0/custom_data_2 = "right"
|
||||||
|
3:0/0 = 0
|
||||||
|
3:0/0/custom_data_0 = true
|
||||||
|
3:0/0/custom_data_2 = "down"
|
||||||
|
4:0/0 = 0
|
||||||
|
4:0/0/custom_data_0 = true
|
||||||
|
4:0/0/custom_data_2 = "left"
|
||||||
|
|
||||||
|
[sub_resource type="TileSetAtlasSource" id="TileSetAtlasSource_m45pk"]
|
||||||
|
texture = ExtResource("2_ev1xx")
|
||||||
|
0:0/0 = 0
|
||||||
|
1:0/0 = 0
|
||||||
|
2:0/0 = 0
|
||||||
|
3:0/0 = 0
|
||||||
|
4:0/0 = 0
|
||||||
|
5:0/0 = 0
|
||||||
|
6:0/0 = 0
|
||||||
|
7:0/0 = 0
|
||||||
|
0:1/0 = 0
|
||||||
|
1:1/0 = 0
|
||||||
|
2:1/0 = 0
|
||||||
|
3:1/0 = 0
|
||||||
|
4:1/0 = 0
|
||||||
|
5:1/0 = 0
|
||||||
|
6:1/0 = 0
|
||||||
|
0:2/0 = 0
|
||||||
|
1:2/0 = 0
|
||||||
|
2:2/0 = 0
|
||||||
|
3:2/0 = 0
|
||||||
|
4:2/0 = 0
|
||||||
|
5:2/0 = 0
|
||||||
|
6:2/0 = 0
|
||||||
|
7:2/0 = 0
|
||||||
|
8:2/0 = 0
|
||||||
|
9:2/0 = 0
|
||||||
|
0:3/0 = 0
|
||||||
|
1:3/0 = 0
|
||||||
|
2:3/0 = 0
|
||||||
|
3:3/0 = 0
|
||||||
|
4:3/0 = 0
|
||||||
|
5:3/0 = 0
|
||||||
|
6:3/0 = 0
|
||||||
|
7:3/0 = 0
|
||||||
|
8:3/0 = 0
|
||||||
|
9:3/0 = 0
|
||||||
|
0:4/0 = 0
|
||||||
|
1:4/0 = 0
|
||||||
|
2:4/0 = 0
|
||||||
|
3:4/0 = 0
|
||||||
|
4:4/0 = 0
|
||||||
|
5:4/0 = 0
|
||||||
|
6:4/0 = 0
|
||||||
|
7:4/0 = 0
|
||||||
|
8:4/0 = 0
|
||||||
|
9:4/0 = 0
|
||||||
|
0:5/0 = 0
|
||||||
|
1:5/0 = 0
|
||||||
|
2:5/0 = 0
|
||||||
|
3:5/0 = 0
|
||||||
|
4:5/0 = 0
|
||||||
|
5:5/0 = 0
|
||||||
|
6:5/0 = 0
|
||||||
|
7:5/0 = 0
|
||||||
|
8:5/0 = 0
|
||||||
|
9:5/0 = 0
|
||||||
|
0:6/0 = 0
|
||||||
|
1:6/0 = 0
|
||||||
|
2:6/0 = 0
|
||||||
|
3:6/0 = 0
|
||||||
|
4:6/0 = 0
|
||||||
|
5:6/0 = 0
|
||||||
|
6:6/0 = 0
|
||||||
|
7:6/0 = 0
|
||||||
|
0:7/0 = 0
|
||||||
|
1:7/0 = 0
|
||||||
|
2:7/0 = 0
|
||||||
|
3:7/0 = 0
|
||||||
|
4:7/0 = 0
|
||||||
|
5:7/0 = 0
|
||||||
|
6:7/0 = 0
|
||||||
|
7:7/0 = 0
|
||||||
|
|
||||||
|
[sub_resource type="TileSetAtlasSource" id="TileSetAtlasSource_xi3gi"]
|
||||||
|
texture = ExtResource("3_eigvu")
|
||||||
|
0:0/0 = 0
|
||||||
|
0:1/0 = 0
|
||||||
|
1:1/0 = 0
|
||||||
|
2:1/0 = 0
|
||||||
|
0:2/0 = 0
|
||||||
|
1:2/0 = 0
|
||||||
|
2:2/0 = 0
|
||||||
|
1:3/0 = 0
|
||||||
|
2:3/0 = 0
|
||||||
|
3:3/0 = 0
|
||||||
|
|
||||||
|
[resource]
|
||||||
|
custom_data_layer_0/name = "is_walkable"
|
||||||
|
custom_data_layer_0/type = 1
|
||||||
|
custom_data_layer_1/name = "is_tile"
|
||||||
|
custom_data_layer_1/type = 1
|
||||||
|
custom_data_layer_2/name = "walk_dir"
|
||||||
|
custom_data_layer_2/type = 4
|
||||||
|
sources/1 = SubResource("TileSetAtlasSource_tp5r2")
|
||||||
|
sources/2 = SubResource("TileSetAtlasSource_m45pk")
|
||||||
|
sources/3 = SubResource("TileSetAtlasSource_xi3gi")
|
Binary file not shown.
After Width: | Height: | Size: 1.0 KiB |
|
@ -0,0 +1,34 @@
|
||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://cmb6k735nhxmy"
|
||||||
|
path="res://.godot/imported/data_layer.png-fa47112c212f2f74d495ba11ee8a8eff.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://scenes/mario-party/img/data_layer.png"
|
||||||
|
dest_files=["res://.godot/imported/data_layer.png-fa47112c212f2f74d495ba11ee8a8eff.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=false
|
||||||
|
mipmaps/limit=-1
|
||||||
|
roughness/mode=0
|
||||||
|
roughness/src_normal=""
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
process/hdr_as_srgb=false
|
||||||
|
process/hdr_clamp_exposure=false
|
||||||
|
process/size_limit=0
|
||||||
|
detect_3d/compress_to=1
|
Loading…
Reference in New Issue