Add lever and jump pad components with activation logic
This commit is contained in:
264
addons/rmsmartshape/shapes/index_map.gd
Normal file
264
addons/rmsmartshape/shapes/index_map.gd
Normal file
@@ -0,0 +1,264 @@
|
||||
@tool
|
||||
extends RefCounted
|
||||
class_name SS2D_IndexMap
|
||||
|
||||
## Maps a set of indicies to an object.
|
||||
|
||||
var object: Variant = null
|
||||
var indicies: PackedInt32Array
|
||||
|
||||
|
||||
## Parameter [param subresources] has no effect, no subresources to duplicate.
|
||||
func duplicate(_subresources: bool = false) -> SS2D_IndexMap:
|
||||
return SS2D_IndexMap.new(indicies.duplicate(), object)
|
||||
|
||||
|
||||
func _init(i: PackedInt32Array, o: Variant) -> void:
|
||||
indicies = i
|
||||
object = o
|
||||
|
||||
|
||||
func _to_string() -> String:
|
||||
return "[M_2_IDX] (%s) | %s" % [str(object), indicies]
|
||||
|
||||
|
||||
static func is_index_array_valid(idx_array: PackedInt32Array) -> bool:
|
||||
return idx_array.size() >= 2
|
||||
|
||||
|
||||
func is_valid() -> bool:
|
||||
return SS2D_IndexMap.is_index_array_valid(indicies)
|
||||
|
||||
|
||||
# FIXME: Unused. Remove eventually
|
||||
# func get_contiguous_segments() -> Array:
|
||||
# if is_contiguous():
|
||||
# return [indicies.duplicate()]
|
||||
# var segments: Array = []
|
||||
# var break_idx: int = find_break()
|
||||
# var remainder: Array[int] = indicies.duplicate()
|
||||
# while break_idx != -1:
|
||||
# var new_slice: Array[int] = []
|
||||
# for i in range(0, break_idx):
|
||||
# new_slice.push_back(remainder[i])
|
||||
# segments.push_back(new_slice)
|
||||
# remainder = remainder.slice(break_idx, remainder.size())
|
||||
# break_idx = SS2D_IndexMap.find_break_in_array(remainder)
|
||||
# if not remainder.is_empty():
|
||||
# segments.push_back(remainder)
|
||||
# return segments
|
||||
|
||||
|
||||
## Will join together segments that share the same idx,
|
||||
## ex. [1,2], [4,5], and [2,3,4] become [1,2,3,4,5]
|
||||
static func join_segments(segments: Array[PackedInt32Array]) -> Array[PackedInt32Array]:
|
||||
var final_segments: Array[PackedInt32Array] = []
|
||||
final_segments.assign(segments.duplicate())
|
||||
|
||||
var to_join_tuple: Vector2i
|
||||
var join_performed := true
|
||||
while join_performed:
|
||||
join_performed = false
|
||||
for i in range(0, final_segments.size()):
|
||||
if join_performed:
|
||||
break
|
||||
for ii in range(i + 1, final_segments.size()):
|
||||
var a := final_segments[i]
|
||||
var b := final_segments[ii]
|
||||
if a[-1] == b[0]:
|
||||
to_join_tuple = Vector2i(i, ii)
|
||||
join_performed = true
|
||||
if b[-1] == a[0]:
|
||||
to_join_tuple = Vector2i(ii, i)
|
||||
join_performed = true
|
||||
if join_performed:
|
||||
break
|
||||
if join_performed:
|
||||
var idx_lowest: int = to_join_tuple[0]
|
||||
var idx_highest: int = to_join_tuple[1]
|
||||
var lowest: PackedInt32Array = final_segments[idx_lowest]
|
||||
var highest: PackedInt32Array = final_segments[idx_highest]
|
||||
final_segments.erase(lowest)
|
||||
final_segments.erase(highest)
|
||||
# pop the shared idx from lowest
|
||||
lowest.remove_at(lowest.size() - 1)
|
||||
var new_segment := lowest + highest
|
||||
final_segments.push_back(new_segment)
|
||||
|
||||
return final_segments
|
||||
|
||||
|
||||
## Does each index increment by 1 without any breaks.
|
||||
func is_contiguous() -> bool:
|
||||
return SS2D_IndexMap.is_array_contiguous(indicies)
|
||||
|
||||
|
||||
static func is_array_contiguous(a: PackedInt32Array) -> bool:
|
||||
return find_break_in_array(a) == -1
|
||||
|
||||
|
||||
## Find a break in the indexes where they aren't contiguous.[br]
|
||||
## Will return -1 if there's no break.[br]
|
||||
func find_break() -> int:
|
||||
return SS2D_IndexMap.find_break_in_array(indicies)
|
||||
|
||||
|
||||
static func find_break_in_array(a: PackedInt32Array, offset: int = 0) -> int:
|
||||
for i in range(offset, a.size() - 1, 1):
|
||||
if is_break_at_index_in_array(a, i):
|
||||
return i + 1
|
||||
return -1
|
||||
|
||||
|
||||
## Whether there is a break at the given index.[br]
|
||||
## Will return -1 if there's no break.[br]
|
||||
func is_break_at_index(i: int) -> bool:
|
||||
return SS2D_IndexMap.is_break_at_index_in_array(indicies, i)
|
||||
|
||||
|
||||
static func is_break_at_index_in_array(a: PackedInt32Array, i: int) -> bool:
|
||||
var difference: int = absi((a[i]) - (a[i + 1]))
|
||||
return difference != 1
|
||||
|
||||
|
||||
func has_index(idx: int) -> bool:
|
||||
return indicies.has(idx)
|
||||
|
||||
|
||||
# FIXME: Unused, remove eventually.
|
||||
# func lowest_index() -> int:
|
||||
# return indicies.min()
|
||||
#
|
||||
#
|
||||
# func highest_index() -> int:
|
||||
# return indicies.max()
|
||||
|
||||
|
||||
# FIXME: Unused, remove eventually
|
||||
func _split_indicies_into_multiple_mappings(new_indicies: PackedInt32Array) -> Array[SS2D_IndexMap]:
|
||||
var maps: Array[SS2D_IndexMap] = []
|
||||
var break_idx := SS2D_IndexMap.find_break_in_array(new_indicies)
|
||||
var offset := 0
|
||||
var sub_indicies: PackedInt32Array
|
||||
|
||||
while break_idx != -1:
|
||||
sub_indicies = new_indicies.slice(offset, break_idx)
|
||||
|
||||
if SS2D_IndexMap.is_index_array_valid(sub_indicies):
|
||||
maps.push_back(SS2D_IndexMap.new(sub_indicies, object))
|
||||
|
||||
offset = break_idx
|
||||
break_idx = SS2D_IndexMap.find_break_in_array(new_indicies, offset)
|
||||
|
||||
sub_indicies = new_indicies.slice(offset)
|
||||
|
||||
if SS2D_IndexMap.is_index_array_valid(sub_indicies):
|
||||
maps.push_back(SS2D_IndexMap.new(sub_indicies, object))
|
||||
|
||||
return maps
|
||||
|
||||
|
||||
## FIXME: Unused, remove eventually
|
||||
## Will create a new set of SS2D_IndexMaps. [br][br]
|
||||
##
|
||||
## The new set will contain all of the indicies of the current set,
|
||||
## minus the ones specified in the indicies parameter. [br][br]
|
||||
##
|
||||
## Example: [br]
|
||||
## indicies = [0,1,2,3,4,5,6] [br]
|
||||
## to_remove = [3,4] [br]
|
||||
## new_sets = [0,1,2] [5,6] [br][br]
|
||||
##
|
||||
## This may split the IndexMap or make it invalid entirely.
|
||||
## As a result, the returned array could have 0 or several IndexMaps.
|
||||
func remove_indicies(to_remove: PackedInt32Array) -> Array[SS2D_IndexMap]:
|
||||
var out: Array[SS2D_IndexMap] = []
|
||||
var new_indicies := indicies.duplicate()
|
||||
|
||||
for r in to_remove:
|
||||
var idx := new_indicies.find(r)
|
||||
if idx >= 0:
|
||||
new_indicies.remove_at(idx)
|
||||
|
||||
if not SS2D_IndexMap.is_index_array_valid(new_indicies):
|
||||
return out
|
||||
|
||||
if SS2D_IndexMap.is_array_contiguous(new_indicies):
|
||||
out.push_back(SS2D_IndexMap.new(new_indicies, object))
|
||||
return out
|
||||
|
||||
return _split_indicies_into_multiple_mappings(new_indicies)
|
||||
|
||||
|
||||
## Will create a new set of SS2D_IndexMaps. [br][br]
|
||||
##
|
||||
## The new set will contain all of the edges of the current set,
|
||||
## minus the ones specified in the indicies parameter. [br][br]
|
||||
##
|
||||
## Example: [br]
|
||||
## indicies = [0,1,2,3,4,5,6] [br]
|
||||
## to_remove = [4,5] [br]
|
||||
## new_sets = [0,1,2,3,4] [4,5,6] [br][br]
|
||||
##
|
||||
## This may split the IndexMap or make it invalid entirely.
|
||||
## As a result, the returned array could have 0 or several IndexMaps.
|
||||
func remove_edges(to_remove: PackedInt32Array) -> Array[SS2D_IndexMap]:
|
||||
# Corner case
|
||||
if to_remove.size() == 2:
|
||||
var idx: int = indicies.find(to_remove[0])
|
||||
if idx != indicies.size()-1:
|
||||
if indicies[idx+1] == to_remove[1]:
|
||||
# Need one split
|
||||
var set_1 := indicies.slice(0, idx+1)
|
||||
var set_2 := indicies.slice(idx+1, indicies.size())
|
||||
var new_maps: Array[SS2D_IndexMap] = []
|
||||
if SS2D_IndexMap.is_index_array_valid(set_1):
|
||||
new_maps.push_back(SS2D_IndexMap.new(set_1, object))
|
||||
if SS2D_IndexMap.is_index_array_valid(set_2):
|
||||
new_maps.push_back(SS2D_IndexMap.new(set_2, object))
|
||||
return new_maps
|
||||
return [SS2D_IndexMap.new(indicies, object)]
|
||||
|
||||
# General case
|
||||
var new_edges := SS2D_IndexMap.indicies_to_edges(indicies)
|
||||
for i in range(0, to_remove.size() - 1, 1):
|
||||
var idx1: int = to_remove[i]
|
||||
var idx2: int = to_remove[i + 1]
|
||||
var edges_to_remove := PackedInt32Array()
|
||||
for ii in new_edges.size():
|
||||
var edge := new_edges[ii]
|
||||
if (edge[0] == idx1 or edge[0] == idx2) and (edge[1] == idx1 or edge[1] == idx2):
|
||||
edges_to_remove.push_back(ii)
|
||||
# Reverse iterate
|
||||
for ii in range(edges_to_remove.size()-1, -1, -1):
|
||||
new_edges.remove_at(edges_to_remove[ii])
|
||||
|
||||
new_edges = SS2D_IndexMap.join_segments(new_edges)
|
||||
var new_index_mappings: Array[SS2D_IndexMap] = []
|
||||
for e in new_edges:
|
||||
new_index_mappings.push_back(SS2D_IndexMap.new(e, object))
|
||||
return new_index_mappings
|
||||
|
||||
|
||||
# NOTE: Even though it makes more sense to return an Array[Vector2i], we return PackedInt32Arrays
|
||||
# instead because it makes things easier in the context where this function output is needed.
|
||||
static func indicies_to_edges(p_indicies: PackedInt32Array) -> Array[PackedInt32Array]:
|
||||
var edges: Array[PackedInt32Array] = []
|
||||
for i in p_indicies.size() - 1:
|
||||
var edge := PackedInt32Array([ i, i+1 ])
|
||||
if absi(edge[0] - edge[1]) == 1:
|
||||
edges.push_back(edge)
|
||||
return edges
|
||||
|
||||
|
||||
## Returns a Dict[Variant, Array[SS2D_IndexMap]]
|
||||
static func index_map_array_sort_by_object(imaps: Array) -> Dictionary:
|
||||
var dict := {}
|
||||
for imap: SS2D_IndexMap in imaps:
|
||||
if not dict.has(imap.object):
|
||||
var arr: Array[SS2D_IndexMap] = [ imap ]
|
||||
dict[imap.object] = arr
|
||||
else:
|
||||
var arr: Array[SS2D_IndexMap] = dict[imap.object]
|
||||
arr.push_back(imap)
|
||||
return dict
|
Reference in New Issue
Block a user