small racing game im working on
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
extends PanelContainer
class_name TrackEditor

@export var group: ButtonGroup
@onready var brush := %brush

enum Mode { Select, Move, Rotate, Scale }
var mode: Mode
var selected: Array[TrackObject]:
	set(s):
		if s != selected:
			for b in selected: # easier than finding the items that are not in selected but are in s
				b.live_node.un_highlight()
			selected = s
			for b in selected:
				b.live_node.highlight()
			make_gizmo.emit(mode)
			selection_changed.emit(selected)
var snapping := true
var objects: Array[TrackObject] = []
var history := UndoRedo.new()
var track: TrackResource
signal make_gizmo(mode: Mode)
signal selection_changed(objects: Array[TrackObject])

const loader := preload("res://scenes/track.tscn")

func _ready() -> void:
	track = Globals.editing if Globals.editing else TrackResource.new([])
	var l: TrackLoader = loader.instantiate()
	l.editor = true
	l.track = track
	add_child(l)
	# move over the loaders children
	for c in l.get_children():
		l.remove_child(c)
		%port.add_child(c)
	# the loader has loaded, get rid of it
	l.queue_free()
	objects = track.blocks.duplicate() # duplicate: if not saved, will be lost
	%propertys.name_.text = track.name
	%propertys.laps_.value = track.laps
	%cam.global_transform = IntroCam.get_origin(track) # put the camera up high, looking straight down

	if not FileAccess.file_exists(Globals.TRACKS % track.name) and not track.builtin:
		%save.unsaved = true

	group.pressed.connect(pressed)
	tree_exiting.connect(
		func():
			for obj in objects:
				obj.delete_live()
	)

func pressed(b: Button) -> void:
	mode = Mode[b.name.to_pascal_case()]
	make_gizmo.emit(mode)

func reset_selected() -> void:
	var new: Array[TrackObject] = []
	selected = new

func _on_mousecast_hit(colls: Array[Block]) -> void:
	var new_selected: Array[TrackObject] = []
	new_selected.resize(colls.size())
	var painting: bool = brush.button_pressed and not colls.is_empty()
	if painting:
		history.create_action("paint")
	for i in len(colls):
		new_selected[i] = tobj_from_node(colls[i])
		if painting and colls[i].materials_allowed() & brush.mat:
			history.add_do_method(colls[i].set_mat.bind(brush.mat))
			history.add_undo_method(colls[i].set_mat.bind(colls[i].mat))
		assert(new_selected[i]!=null, "%s was not found" % [colls[i]])
	if not brush.button_pressed:
		selected = new_selected
	if painting:
		history.commit_action()

func _on_snapping_toggled(button_pressed: bool) -> void:
	snapping = button_pressed

func get_trackdata() -> TrackResource:
	objects = objects.filter(func(o: TrackObject): return is_instance_valid(o.live_node))
	track.blocks = objects.duplicate()
	track.name = %propertys.name_.text
	track.laps = %propertys.laps_.value
	return track

func _on_item_created(object: TrackObject) -> void:
	objects.append(object)
	if object.live_node is Booster:
		for block in objects:
			if block.live_node is Booster:
				block.live_node.sync()
	%thonk.pitch_scale = randf_range(.9, 1.2)
	%thonk.play()

func tobj_from_node(node: Block) -> TrackObject:
	for o in objects:
		if o.live_node == node:
			return o
	return null

func _on_delete_pressed() -> void:
	selected = []

func _on_remove_tobj(tobj: TrackObject) -> void:
	objects.erase(tobj)

func _on_brush_toggled(on: bool) -> void:
	if on:
		var painting: bool = brush.button_pressed and not selected.is_empty()
		if painting:
			history.create_action("paint")
		for o in selected:
			if painting and o.live_node.materials_allowed() & brush.mat:
				history.add_do_method(o.live_node.set_mat.bind(brush.mat))
				history.add_undo_method(o.live_node.set_mat.bind(o.live_node.mat))
		if painting:
			history.commit_action()
		reset_selected()