Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: generate a new chunk at each lap #42

Merged
merged 4 commits into from
Feb 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion .github/workflows/release-packaging.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
name: Release Packaging

on:
push:
workflow_dispatch:
# Ensure the build works on main
push:
branches: [main]
tags:
# Ensure the build works on each pull request
pull_request:

env:
BRANCH_NAME: ${{ github.head_ref || github.ref_name }}
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
### Removed
### Fixed
- Use a custom `EditorExportPlugin` to set build info ([#41](https://github.com/MechanicalFlower/Marble/pull/41))
- Generate a new chunk at each lap ([#42](https://github.com/MechanicalFlower/Marble/pull/42))
### Security
### Dependencies
- Bump `actions/cache` from 3 to 4 ([#40](https://github.com/MechanicalFlower/Marble/pull/40))
Expand Down
32 changes: 20 additions & 12 deletions scripts/main.gd
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,13 @@ var _mode: int = State.MODE_START
var _current_marble_index := 0
var _time := 0.0
var _explosion_enabled := false
var _need_new_chunk := false
var _race_has_started := false

# Variables used in explosion mode to check
# if we need to generate another chunk of the race
var _max_checkpoint_count := -1
var _old_lap_count := 0

# There are limited places to ensure equality among the marbles.
# TODO : remove this limit
var _positions := []
Expand Down Expand Up @@ -101,7 +105,7 @@ func _unhandled_input(event):
# Debug command to generate a new race
KEY_R:
if _mode == State.MODE_MARBLE:
_race.call_deferred(&"generate_race", !_explosion_enabled)
_race.generate_race(!_explosion_enabled)

KEY_SPACE:
for marble in _marbles:
Expand Down Expand Up @@ -211,7 +215,7 @@ func set_mode(mode):
await Fade.fade_out(1, Color.BLACK, "Diamond", false, false).finished

_explosion_enabled = SettingsManager.get_value(&"marbles", &"explosion_enabled") as bool
_race.call_deferred(&"generate_race", !_explosion_enabled)
_race.generate_race(!_explosion_enabled)

_overlay.reset()
reset_position()
Expand Down Expand Up @@ -276,7 +280,7 @@ func _process(delta):
if _time > TIME_PERIOD:
if _mode == State.MODE_START:
# Regenerate race
_race.call_deferred(&"generate_race", true)
_race.generate_race(true)

# Reset timer
_time = 0
Expand All @@ -300,14 +304,18 @@ func _process(delta):
_explosion.set_emitting(true)

if _ranking._first_marble:
if (
_need_new_chunk
and (_ranking._first_marble._checkpoint_count + 3) % _race._step_count != 0
):
_race.generate_chunk()
_need_new_chunk = false
elif (_ranking._first_marble._checkpoint_count + 3) % _race._step_count == 0:
_need_new_chunk = true
# If a new checkpoint is crossed by the first marble
if _ranking._first_marble._checkpoint_count > _max_checkpoint_count:
# Store the max number of checkpoints crossed
_max_checkpoint_count = _ranking._first_marble._checkpoint_count

# Compute the lap (1 lap equals to one chunk)
var lap_count: int = ceil((_max_checkpoint_count + 3) / _race._step_count)
# If one more lap was done
if lap_count > _old_lap_count:
# Generate a chunk
_race.generate_chunk()
_old_lap_count = lap_count
else:
_panel_timer.hide()

Expand Down
145 changes: 106 additions & 39 deletions scripts/race.gd
Original file line number Diff line number Diff line change
@@ -1,17 +1,25 @@
@tool

class_name Race
extends Node

var PieceList = load("res://scripts/constants/piece_list.gd")
var Group = load("res://scripts/constants/groups.gd")
# Constants and resource paths
const PieceList = preload("res://scripts/constants/piece_list.gd")
const Group = preload("res://scripts/constants/groups.gd")

@export var regenerate_race: bool:
set = generate_race

# Number of steps in the race generation
var _step_count := 10
var _previous_piece: Piece = null
var _piece_orientation = null

var _previous_piece = null
var _previous_piece_orientation = null
var _previous_rotation_index := 0
var _curve: Curve3D

# Curve to store the race path
@onready var curve: Curve3D = Curve3D.new()

# Reference to the path node
@onready var path := get_node(^"Path") as Path3D


Expand All @@ -22,79 +30,138 @@ static func umod(x: int, d: int) -> int:


func _ready() -> void:
_curve = Curve3D.new()
path.set_curve(_curve)
# Initialize the curve and set it to the path
path.set_curve(curve)

# Check if explosion is enabled from settings
var explosion_enabled = SettingsManager.get_value(&"marbles", &"explosion_enabled") as bool
generate_race(!explosion_enabled)


# Main function to generate the race
func generate_race(with_end: bool = true) -> void:
_curve.clear_points()
# Clear previous race path
curve.clear_points()
# Clear previous pieces from the scene
clear_previous_pieces()
# Place the start line
place_start_line()

for piece in get_children():
if piece.is_in_group(Group.PIECES):
piece.queue_free()
# Generate a race chunk
generate_chunk()

# Place the finish line if required
if with_end:
place_finish_line()


# Function to generate a race chunk
func generate_chunk() -> void:
randomize()

# Reset values
for _i in range(_step_count):
# Select a random piece and place it
var piece_index = randomize_piece_index()
place_piece(piece_index)


# Function to clear previous pieces from the scene
func clear_previous_pieces() -> void:
_previous_piece = null
_piece_orientation = null
_previous_piece_orientation = null
_previous_rotation_index = 0

# Place the start line
place_piece(-2)
for piece in get_children():
if piece.is_in_group(Group.PIECES):
piece.queue_free()

generate_chunk()

if with_end:
# Place the finish line
place_piece(-1)
# Function to select a random piece index
func randomize_piece_index() -> int:
return umod(randi(), len(PieceList.PIECES) - 2)


func generate_chunk():
for step in _step_count:
# Select a random piece
var piece_index = umod(randi(), len(PieceList.PIECES) - 2)
place_piece(piece_index)
# Function to place the start line
func place_start_line() -> void:
place_piece(-2)


# Function to place the finish line
func place_finish_line() -> void:
place_piece(-1)


# Function to place a piece on the race path
func place_piece(piece_index: int) -> void:
# Instantiate the piece
var piece_data = PieceList.PIECES[piece_index]
var piece: Node = piece_data[&"resource"].instantiate()
var piece: Piece = piece_data[&"resource"].instantiate()

# Optimize piece visibility
optimize_piece_visibility(piece)

# naive hlod
# Add the piece to the scene
add_child(piece)

# Rotate and translate the piece
rotate_piece(piece)
translate_piece(piece)

# Store data for next piece and positions for the race path
store_piece_data(piece, piece_data)
store_piece_positions(piece)


# Function to optimize piece visibility
func optimize_piece_visibility(piece: Piece) -> void:
for child in piece.get_children():
if child is MeshInstance3D:
child.visibility_range_end = 150

# Add the piece to the main Node
add_child(piece)

# Rotate the piece
# Function to rotate a piece based on previous orientation
func rotate_piece(piece: Piece) -> void:
var rotation_index = calculate_rotation_index(piece)
piece.rotate_y(float(rotation_index) * PI / 2.0)


# Function to calculate the rotation index for a piece
func calculate_rotation_index(_piece: Piece) -> int:
var rotation_index = _previous_rotation_index
if _piece_orientation == PieceList.TURN_LEFT:
if _previous_piece_orientation == PieceList.TURN_LEFT:
rotation_index = (rotation_index + 1) % 4
elif _piece_orientation == PieceList.TURN_RIGHT:
elif _previous_piece_orientation == PieceList.TURN_RIGHT:
rotation_index = (rotation_index - 1) % 4
piece.rotate_y(float(rotation_index) * PI / 2.0)
return rotation_index


# Translate the piece
# Function to translate a piece based on previous piece position
func translate_piece(piece: Piece) -> void:
var offset = calculate_translation_offset(piece)
piece.global_translate(offset)


# Function to calculate the translation offset for a piece
func calculate_translation_offset(piece: Piece) -> Vector3:
var offset = Vector3(-10, 25, 0)
if _previous_piece != null:
offset = (
_previous_piece.get_end().global_transform.origin
- piece.get_begin().global_transform.origin
)
piece.global_translate(offset)
return offset

# Store data for next piece

# Function to store data for the next piece
func store_piece_data(piece: Piece, piece_data: Dictionary) -> void:
_previous_piece = piece
_piece_orientation = piece_data[&"next_piece_orientation"]
_previous_rotation_index = rotation_index
_previous_rotation_index = calculate_rotation_index(piece)
_previous_piece_orientation = piece_data[&"next_piece_orientation"]


# Function to store positions for the race path
func store_piece_positions(piece: Piece) -> void:
var positions := piece.get_node(^"Positions") as Marker3D
if positions:
for pos in positions.get_children():
_curve.add_point(pos.global_position)
curve.add_point(pos.global_position)
Loading