Menu
CoddyTech

Các trạm kiểm tra theo thứ tự

Bài học 9 trên 20 trong khóa học Trò chơi Godot: Mạch neon của Coddy.

Một cuộc đua cần có các vòng, và một vòng chỉ được tính nếu bạn thực sự chạy hết một vòng. Nếu không, bạn có thể vượt qua vạch đích, lùi lại rồi vượt qua vạch đó lần nữa. Vì vậy, đường đua có 8 trạm kiểm soát cách đều nhau và bạn phải đi qua chúng theo đúng thứ tự.

Cuộc đua nằm trong race.gd, trên nút Main. track.offset_of(point) cho biết một điểm cách vạch xuất phát bao xa dọc theo đường đua, với 0 tại vạch và track.length là độ dài đường đua. Trạm kiểm soát k nằm tại k * seg:

func check_progress() -> void:
	var seg: float = track.length / CHECKPOINTS
	var offset: float = track.offset_of(car.position)
	var target := next_checkpoint * seg
	var gap: float = absf(wrapf(offset - target, -track.length / 2.0, track.length / 2.0))
	if gap < 24.0 and track.is_on_road(car.position):
		next_checkpoint = (next_checkpoint + 1) % CHECKPOINTS

wrapf giữ cho khoảng cách được tính chính xác tại vạch đích, nơi 1390 và 5 chỉ cách nhau 14 pixel. % CHECKPOINTS đưa trạm kiểm soát tiếp theo sau trạm 7 về 0, tức vạch đích. Điều kiện is_on_road đảm bảo đường tắt băng qua bãi cỏ không được tính.

challenge icon

Thử thách

Trung bình

Hãy tính các trạm kiểm soát theo thứ tự trong cuộc đua.

  1. Trong race.gd, thêm const CHECKPOINTS := 8 và var next_checkpoint := 1.
  2. Lấy track ($Track) và car ($Car) bằng @onready.
  3. Viết hàm check_progress và gọi hàm này từ _physics_process.

Nhấn Chơi rồi lái xe một vòng: hiện chưa có gì mới xuất hiện, vòng đua sẽ có trong bài học tiếp theo. Sau đó, nhấn Kiểm tra.

Tự làm thử

extends Node2D

@export var accel := 260.0
@export var max_speed := 200.0
@export var turn_speed := 3.2
@export var drag := 0.6
@export var grip := 7.0

var velocity := Vector2.ZERO
var boost_time := 0.0
var boost_charge := 0.0

@onready var track: Node2D = $"../Track"


func _physics_process(delta: float) -> void:
	var throttle := Input.get_axis("move_down", "move_up")
	var steer := Input.get_axis("move_left", "move_right")
	if Input.is_action_just_pressed("action") and boost_charge >= 1.0:
		boost_charge = 0.0
		boost_time = 1.0
	boost_charge = minf(1.0, boost_charge + delta / 10.0)
	$"../HUD/Boost".scale.x = boost_charge

	var forward := Vector2.RIGHT.rotated(rotation)
	var speed := velocity.dot(forward)
	var top := max_speed
	var grip_now := grip
	if boost_time > 0.0:
		boost_time -= delta
		top = max_speed * 1.3
		velocity += forward * accel * delta
	for pad in get_tree().get_nodes_in_group("boost_pads"):
		if position.distance_to(pad.position) < 22.0:
			boost_time = maxf(boost_time, 0.4)
	for oil in get_tree().get_nodes_in_group("oil"):
		if position.distance_to(oil.position) < 20.0:
			grip_now = grip * 0.12
	if not track.is_on_road(position):
		top = max_speed * 0.45
		velocity *= 1.0 - 2.5 * delta

	if throttle < 0.0 and speed > 10.0:
		velocity += forward * throttle * accel * 1.6 * delta
	else:
		velocity += forward * throttle * accel * delta
	rotation += steer * turn_speed * delta * clampf(absf(speed) / 90.0, 0.0, 1.0) * signf(speed + 0.01)

	var side := forward.orthogonal()
	velocity -= side * velocity.dot(side) * minf(1.0, grip_now * delta)
	velocity *= 1.0 - drag * delta
	if velocity.length() > top:
		velocity = velocity.move_toward(velocity.limit_length(top), accel * 2.0 * delta)
	position += velocity * delta
	$Exhaust.emitting = throttle > 0.0 or boost_time > 0.0
	$Flame.visible = boost_time > 0.0

Tất cả bài học trong Trò chơi Godot: Mạch neon

Tự luyện tập: Playground Godot