Skip to content

Creating a chart/note system for rhythm games in Scratch

💡 Having trouble with Scratch block assembly? Don’t know how to implement code logic? 🚀 Get Help Now

RC

RhythmCoder_Pro

Posted on January 23, 2024 • Advanced

🎵 Need Help Building a Chart/Note System

Hey everyone! I’m working on a rhythm game in Scratch and I need to create a comprehensive chart/note system that can handle multiple tracks. Here’s what I’m trying to achieve:

  • Support for 2 separate note tracks (left and right)
  • Precise timing for note appearances and hits
  • Different note types (tap, hold, special)
  • Easy chart editing and data management

I’ve been struggling with organizing the data structure and synchronizing the notes with the music. Any help with the architecture and implementation would be amazing! I’m happy to share my project and give credit to anyone who helps. 🙏

MG

MusicGame_Expert

Replied 4 hours later • ⭐ Best Answer

Excellent question @RhythmCoder_Pro! Building a robust chart/note system is crucial for rhythm games. Here’s a comprehensive approach that will give you professional-level results:

🎼 Chart System Architecture

Here’s how a complete rhythm game chart system works:

flowchart TD A[🎵 Song Start] --> B[Load Chart Data] B --> C[Initialize Note Spawner] C --> D[🎮 Game Loop] D --> E[Update Timer] E --> F{Time to Spawn Note?} F -->|Yes| G[Create Note on Track] F -->|No| H[Continue Loop] G --> I[Set Note Properties] I --> J[Add to Active Notes] J --> H H --> K[Update All Notes] K --> L[Check Hit Detection] L --> M{Note Hit?} M -->|Yes| N[Calculate Score] M -->|No| O[Check Miss] N --> P[Remove Note] O --> Q{Note Passed?} Q -->|Yes| R[Mark as Miss] Q -->|No| D P --> D R --> S[Remove Note] S --> D style A fill:#e1f5fe style B fill:#f3e5f5 style G fill:#e8f5e8 style N fill:#fff3e0

🗂️ Method 1: List-Based Chart System

Create separate lists for each note property:

    when flag clicked
// Initialize chart data lists
delete all of [Note Times v]
delete all of [Note Tracks v]
delete all of [Note Types v]
delete all of [Note Durations v]

// Example chart data (time in milliseconds, track 1 or 2)
add [1000] to [Note Times v]  // Note at 1 second
add [1] to [Note Tracks v]    // Track 1 (left)
add [tap] to [Note Types v]   // Tap note
add [0] to [Note Durations v] // No duration for tap

add [1500] to [Note Times v]  // Note at 1.5 seconds
add [2] to [Note Tracks v]    // Track 2 (right)
add [tap] to [Note Types v]   // Tap note
add [0] to [Note Durations v] // No duration

add [2000] to [Note Times v]  // Note at 2 seconds
add [1] to [Note Tracks v]    // Track 1 (left)
add [hold] to [Note Types v]  // Hold note
add [1000] to [Note Durations v] // Hold for 1 second

// Initialize game variables
set [Song Time v] to [0]
set [Chart Index v] to [1]
set [BPM v] to [120]
  
    // Main game loop
when flag clicked
forever
// Update song time (assuming 60 FPS)
change [Song Time v] by [16.67] // ~16.67ms per frame

// Check if it's time to spawn the next note
if <(Chart Index) <= (length of [Note Times v])> then
if <(Song Time) >= (item (Chart Index) of [Note Times v])> then
// Spawn note
broadcast [spawn note v]
change [Chart Index v] by [1]
end
end
end
  
    // Note spawning system
when I receive [spawn note v]
// Get note data
set [Note Time v] to (item (Chart Index) of [Note Times v])
set [Note Track v] to (item (Chart Index) of [Note Tracks v])
set [Note Type v] to (item (Chart Index) of [Note Types v])
set [Note Duration v] to (item (Chart Index) of [Note Durations v])

// Create note clone
if <(Note Track) = [1]> then
go to x: [-100] y: [180] // Left track spawn position
else
go to x: [100] y: [180]  // Right track spawn position
end

create clone of [Note Sprite v]
  

📊 Method 2: CSV-Based Chart System (Advanced)

For more complex charts, use CSV format for easier editing:

    // CSV Parser - Custom block
define parse csv (csv data) at position (position)
set [csv result v] to []
set [csv position v] to [1]
set [current field v] to [1]

repeat until <(current field) = (position)>
if <(letter (csv position) of (csv data)) = [,]> then
change [current field v] by [1]
end
change [csv position v] by [1]
end

// Extract the field value
repeat until <<(letter (csv position) of (csv data)) = [,]> or <(csv position) > (length of (csv data))>>
set [csv result v] to (join (csv result) (letter (csv position) of (csv data)))
change [csv position v] by [1]
end
  
    // Chart data in CSV format
when flag clicked
set [Chart CSV v] to [1000,1,tap,0
1500,2,tap,0
2000,1,hold,1000
2500,2,tap,0
3000,1,tap,0
3000,2,tap,0]

// Parse chart into lists
delete all of [Note Times v]
delete all of [Note Tracks v]
delete all of [Note Types v]
delete all of [Note Durations v]

set [line number v] to [1]
repeat until <(line number) > (number of lines in (Chart CSV))>
set [current line v] to (line (line number) of (Chart CSV))

// Parse each field
parse csv (current line) at position [1]
add (csv result) to [Note Times v]

parse csv (current line) at position [2]
add (csv result) to [Note Tracks v]

parse csv (current line) at position [3]
add (csv result) to [Note Types v]

parse csv (current line) at position [4]
add (csv result) to [Note Durations v]

change [line number v] by [1]
end
  

🎯 Note Movement and Hit Detection

For the note sprites themselves:

    // Note sprite behavior
when I start as a clone
set [note speed v] to [5] // Pixels per frame
set [hit zone y v] to [-120] // Y position of hit zone
set [note active v] to [1]

forever
if <(note active) = [1]> then
// Move note down
change y by (0 - (note speed))

// Check if note reached hit zone
if <(y position) <= (hit zone y)> then
if <(y position) >= ((hit zone y) - [20])> then
// In hit zone - check for input
if <(Note Track) = [1]> then
if <key [a v] pressed?> then
broadcast [note hit v]
set [note active v] to [0]
delete this clone
end
else
if <key [l v] pressed?> then
broadcast [note hit v]
set [note active v] to [0]
delete this clone
end
end
else
// Note missed
broadcast [note missed v]
set [note active v] to [0]
delete this clone
end
end
end
end
  

🏆 Scoring and Feedback System

Add scoring based on timing accuracy:

    when I receive [note hit v]
// Calculate hit timing accuracy
set [hit distance v] to (abs of ((y position) - (hit zone y)))

if <(hit distance) < [5]> then
// Perfect hit
change [Score v] by [300]
broadcast [show perfect v]
else
if <(hit distance) < [15]> then
// Good hit
change [Score v] by [200]
broadcast [show good v]
else
// OK hit
change [Score v] by [100]
broadcast [show ok v]
end
end

// Update combo
change [Combo v] by [1]
if <(Combo) > (Max Combo)> then
set [Max Combo v] to (Combo)
end
  

💡 Pro Tips for Chart Creation

  • Timing Precision: Use milliseconds for accurate note timing
  • Chart Testing: Create a chart editor mode for easy testing
  • Audio Sync: Account for audio latency in your timing calculations
  • Visual Feedback: Add particle effects for hits and misses
  • Difficulty Scaling: Create multiple chart files for different difficulties
    // Chart editor helper
when [space v] key pressed
if <(editor mode) = [1]> then
// Record current time and track for chart creation
add (Song Time) to [Note Times v]
if <mouse x < [0]> then
add [1] to [Note Tracks v] // Left track
else
add [2] to [Note Tracks v] // Right track
end
add [tap] to [Note Types v]
add [0] to [Note Durations v]
end
  

This system gives you complete control over your rhythm game charts and can handle complex patterns with ease! 🎵

RC

RhythmCoder_Pro

Replied 1 hour later

@MusicGame_Expert This is absolutely incredible! 🎉

The list-based system worked perfectly for my needs. I especially love the CSV approach for more complex charts - it makes editing so much easier. The hit detection is spot on and the scoring system adds great gameplay depth.

Quick question - how would I handle hold notes that need to be held down for a duration?

HD

HoldNote_Dev

Replied 2 hours later

@RhythmCoder_Pro Great question about hold notes! Here’s how to implement them:

    // Hold note behavior
when I start as a clone
if <(Note Type) = [hold]> then
set [hold active v] to [0]
set [hold start time v] to [0]

forever
if <(hold active) = [0]> then
// Check for hold start
if <(y position) <= (hit zone y)> then
if <key [a v] pressed?> then // or appropriate key
set [hold active v] to [1]
set [hold start time v] to (Song Time)
broadcast [hold started v]
end
end
else
// Hold is active - check if key is still pressed
if <not <key [a v] pressed?>> then
// Hold released early
broadcast [hold failed v]
delete this clone
else
// Check if hold duration completed
if <((Song Time) - (hold start time)) >= (Note Duration)> then
broadcast [hold completed v]
delete this clone
end
end
end
end
end
  

This creates a proper hold note system that requires continuous input! 🎵

VB

Vibelf_Community

Pinned Message • Moderator

🚀 Ready to Create Professional Rhythm Games?

Amazing discussion on chart/note systems! For those looking to build even more advanced rhythm game features, our community can help you implement:

  • 🎼 Advanced chart editors with visual timeline
  • 🎵 Audio synchronization and beat detection
  • 🌟 Special note types and effects
  • 🏆 Online leaderboards and replay systems

📚 Related Discussions

Ready to take your rhythm game development to the next level? Get personalized guidance from our expert tutors in the Vibelf app!