small racing game im working on
Diffstat (limited to 'race.gd')
| -rw-r--r-- | race.gd | 165 |
1 files changed, 107 insertions, 58 deletions
@@ -7,21 +7,26 @@ var track_loader_scene: PackedScene var ghost_scene: PackedScene var track_res: TrackResource var track: TrackLoader -var data: GhostData +var data: Array[GhostData] var best_time_data: GhostData -var car: Car +var cars: Array[Car] +var cars_needed: PackedInt32Array = [] +var finished_cars := 0 +@onready var mp := cars_needed.size() > 1 var ghost: GhostCar var start_frame: int -var current_lap := 0 +var current_lap: PackedInt32Array = [] var playing := false -var timer := GameTimer.new() +var timers: Array[GameTimer] +var distances: PackedFloat32Array = [] signal next_lap -signal created_car(car: Car) +signal created_car(car: Car, n: int) signal created_ghost(ghost: GhostCar) -signal finished(time: float, prev_time: float) -signal split(time: float, prev_time: float) +signal finished(time: float, prev_time: float, n: int) +signal all_finished +signal split(time: float, prev_time: float, n: int) signal did_reset func _init(t: TrackResource, ghost_data: GhostData, _car_scene, _ghost_scene, _track_loader_scene) -> void: @@ -43,36 +48,48 @@ func reset_ghost() -> void: ghost.engine.volume = .2 else: ghost.engine.volume = 0 - ghost.global_position = track.start_transf.origin + Vector3(0, 1, 0) + ghost.global_position = track.start_transf.origin + Vector3(0, 1, -2) ghost.rotation = track.start_transf.basis.get_euler()# + Vector3(0, PI, -PI/2) ghost.reset() ghost.hide() -func reset_car() -> void: +func reset_car(i: int) -> void: await get_tree().physics_frame - car.rotation = track.start_transf.basis.get_euler()# + Vector3(0, PI, -PI/2) - car.global_position = track.start_transf.origin + Vector3(0, 1, 0) - car.linear_velocity = Vector3.ZERO - car.angular_velocity = Vector3.ZERO - car.current_gear = 0 - car.reset() - -func mkcar() -> void: - car = HumanCar.attach(car_scene) - add_child(car) - reset_car() - created_car.emit(car) + cars[i].rotation = track.start_transf.basis.get_euler()# + Vector3(0, PI, -PI/2) + cars[i].global_position = track.start_transf.origin + Vector3(0, 1, -2) + cars[i].linear_velocity = Vector3.ZERO + cars[i].angular_velocity = Vector3.ZERO + cars[i].current_gear = 0 + cars[i].reset() + +func mkcar(i: int, dev: int) -> void: + cars[i] = HumanCar.attach(car_scene, dev) + add_child(cars[i]) + reset_car(i) + created_car.emit(cars[i], i) + if !mp: + cars[i].collision_mask = 2 ^ 1 func _ready() -> void: set_physics_process(false) track = track_loader_scene.instantiate() track.track = track_res add_child(track) - data = GhostData.new(track.checkpoints.size(), track_res.laps) - mkcar() + data.resize(cars_needed.size()) + cars.resize(cars_needed.size()) + current_lap.resize(cars_needed.size()) + current_lap.fill(0) + timers.resize(cars_needed.size()) + if mp: + distances.resize(cars_needed.size()) + distances.fill(0) + for i in cars_needed.size(): + data[i] = GhostData.new(track.checkpoints.size(), track_res.laps) + timers[i] = GameTimer.new() + add_child(timers[i]) + mkcar(i, cars_needed[i]) mkghost() connect_checkpoints() - add_child(timer) func _input(event: InputEvent) -> void: if event.is_action("reset") and playing: @@ -80,46 +97,76 @@ func _input(event: InputEvent) -> void: func reset() -> void: playing = false + finished_cars = 0 if best_time_data: if ghost: reset_ghost() - await reset_car() + distances.fill(0) + for car in cars.size(): + await reset_car(car) + current_lap[car] = 0 set_physics_process(false) - current_lap = 0 - data.clear() - timer.reset() + for d in data: + d.clear() + for timer in timers: + timer.reset() did_reset.emit() +func fcar(c: Car) -> int: + return cars.find(c) + func connect_checkpoints() -> void: for i in len(track.checkpoints): - track.checkpoints[i].collected.connect(passed_cp.bind(i)) - track.finish.collected.connect(passed_finish) + track.checkpoints[i].collected.connect(func(c: Car): passed_cp(i, fcar(c))) + track.finish.collected.connect(func(c: Car): passed_finish(fcar(c))) -func passed_cp(cp: int) -> void: if playing and !data.has_collected(current_lap, cp): collect(cp) +func passed_cp(cp: int, car: int) -> void: if playing and !data[car].has_collected(current_lap[car], cp): collect(cp, car) -func passed_finish() -> void: +func passed_finish(car: int) -> void: if !playing: return - for i in len(data.checkpoints[current_lap]) - 1: - if data.checkpoints[current_lap][i] < 0: + for i in len(data[car].checkpoints[current_lap[car]]) - 1: + if data[car].checkpoints[current_lap[car]][i] < 0: return - collect(-1) - if track_res.laps - 1 == current_lap: - playing = false - timer.stop() - car.reset() - if not best_time_data or data.time < best_time_data.time: - finished.emit(data.time, best_time_data.time if best_time_data else -1.0) - data.save(Globals.SAVES % track_res.name) - best_time_data = data - else: - finished.emit(data.time, best_time_data.time) - data = GhostData.new(track.checkpoints.size(), track_res.laps) + collect(-1, car) + if track_res.laps - 1 == current_lap[car]: + timers[car].stop() + cars[car].reset() + finished_cars += 1 + finished.emit(data[car].time, best_time_data.time if best_time_data else -1.0, car) + if finished_cars > cars.size() - 1: # all finished + var best = {time = INF} + for datapoint in data: + if best.time > datapoint.time: + best = datapoint + if not best_time_data or best.time < best_time_data.time: + best.save(Globals.SAVES % track_res.name) + best_time_data = best + all_finished.emit() + playing = false else: - current_lap += 1 + current_lap[car] += 1 next_lap.emit() func _physics_process(delta: float) -> void: - data.snapshot(car) + if mp: + for i in cars_needed.size(): + if distances[i] < 0: + continue + var flag := true + for j in cars_needed.size(): + if j == i: continue + var dist := cars[i].global_position.distance_squared_to(cars[j].global_position) + if dist > 50: + continue + flag = false + break # gdscript cant label loops + if flag: + distances[i] = distances[i] + delta + if distances[i] > 1.5: # when apart for longer than 1.5 seconds, enable collisions + distances[i] = -1 + cars[i].collision_mask = 1 ^ 2 # world & players + for i in data.size(): + data[i].snapshot(cars[i]) if best_time_data: if best_time_data.snap_count - 1 < Engine.get_physics_frames() - start_frame: if ghost.visible: @@ -127,20 +174,22 @@ func _physics_process(delta: float) -> void: ghost.engine.volume = 0 return ghost.update(best_time_data.load_snap(Engine.get_physics_frames() - start_frame), delta) - ghost.visible = (ghost.global_position.distance_squared_to(car.global_position) > 10) - ghost.engine.volume = lerpf(ghost.engine.volume, .7, delta * 3) if (ghost.global_position.distance_squared_to(car.global_position) > 20) else lerpf(ghost.engine.volume, .2, delta * 3) + ghost.visible = (ghost.global_position.distance_squared_to(cars[0].global_position) > 10) + ghost.engine.volume = lerpf(ghost.engine.volume, .7, delta * 3) if (ghost.global_position.distance_squared_to(cars[0].global_position) > 20) else lerpf(ghost.engine.volume, .2, delta * 3) -func collect(cp: int) -> void: +func collect(cp: int, car: int) -> void: if cp != -1: - car.checkpoint_sound.play() - var time := best_time_data.get_time(current_lap, cp) if best_time_data else -1.0 - time = best_time_data.time if (not track_res.laps or track_res.laps == current_lap + 1) and cp == -1 and time != -1.0 else time - split.emit(snappedf(timer.now(), .001), time) - data.collect(current_lap, cp, snappedf(timer.now(), .001)) + cars[car].checkpoint_sound.play() + var time := best_time_data.get_time(current_lap[car], cp) if best_time_data else -1.0 + time = best_time_data.time if (not track_res.laps or track_res.laps == current_lap[car] + 1) and cp == -1 and time != -1.0 else time + split.emit(snappedf(timers[car].now(), .001), time, car) + data[car].collect(current_lap[car], cp, snappedf(timers[car].now(), .001)) func start() -> void: - timer.start() + for timer in timers: + timer.start() start_frame = Engine.get_physics_frames() playing = true - car.start() set_physics_process(true) + for car in cars: + car.start() |