Menu
CoddyTech

Một đối thủ trên vạch xuất phát

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

Một chiếc xe màu hồng đang chờ bên cạnh bạn. Đó là đối thủ và không cần đánh lái: xe chạy theo đường tâm của đường đua, lệch sang một bên một chút.

Lưu quãng đường xe đã đi quanh đường đua trong progress và tăng giá trị này với tốc độ tối đa của xe. track.point_at(progress) là điểm trên đường tâm đó, còn direction_at là hướng đường đua chạy qua điểm đó:

func place() -> void:
	var direction: Vector2 = track.direction_at(progress)
	position = track.point_at(progress) + direction.orthogonal() * lane
	rotation = direction.angle()

lane dịch xe khỏi đường tâm một khoảng tính bằng pixel, nhờ vậy các đối thủ có thể chạy song song. progress tiếp tục tăng sau mỗi vòng đua; point_at đưa giá trị này quay vòng.

challenge icon

Thử thách

Dễ

Thêm một chiếc xe đối thủ.

  1. Trong rival.gd, khai báo xuất top_speed := 200.0, lane := 0.0 và start_offset := 40.0.
  2. Thêm var progress := 0.0, var active := true và dòng theo dõi @onready.
  3. Trong _ready, đặt progress = start_offset rồi gọi place().
  4. Trong _physics_process, khi xe đang hoạt động, cộng top_speed * delta vào progress rồi gọi place().

Nhấn Chơi: chiếc xe màu hồng chạy vòng quanh đường đua. 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
var active := true

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


func _physics_process(delta: float) -> void:
	var throttle := 0.0
	var steer := 0.0
	if active:
		throttle = Input.get_axis("move_down", "move_up")
		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