Bad Apple!! on Scratch
Ahh yes, the great programming task of running Bad Apple!! on something it wasn't designed for.
First of all, here's all of my code (on scratch of course)
The code is really simple, the only minorly complex thing is the "draw_frame X" function. Having X count up in a separate thing helps with lag when running on the Scratch website, however due to scratch not wanting to save the project (because of the list being too big) I didn't end up mattering anyways. X is set to a 25 frame offset, because there are a ton of black frames at the start for some reason (still not sure why). If the project is running on the Scratch website, X will be set to increment by 2.5 instead of 1, due to lag of course.
The video comes from the "framedata" list, a massive 6580 line long list, with each line containing 10800 numbers, either a one or a zero. Zero for black; and one for white. I wrote a short program in Godot (my game engine of choice) that scans a sprite-sheet of Bad Apple!! and converts the data to a Scratch-readable format (the framedata list).
extends Node2D var frame_size := Vector2(120, 90) var animation = [] var frame_count = 0 func _ready(): $Sprite.frame = 0 scan_frame() func scan_frame(): var framedata : String = "" var image = preload("res://bad_apple_sheet.png") image = image.get_data() image.lock() var y = 0 var x = 0 for i in 90: x = 0 for j in 120: x = x + 1 var pixcol : Color = image.get_pixelv(Vector2(x + (frame_size.x * $Sprite.frame_coords.x), y + (frame_size.y* $Sprite.frame_coords.y))) match pixcol: Color(0, 0, 0, 1): # Black framedata = str(framedata + "0") Color(1, 1, 1, 1): # White framedata = str(framedata + "1") _: framedata = str(framedata + "何") #Error placeholder, Japanese "Nani" y = y + 1 animation.append(framedata) func _on_Timer_timeout(): if frame_count != 6579: $Sprite.frame = frame_count print($Sprite.frame_coords) scan_frame() frame_count = frame_count + 1 else: $Timer.queue_free() print("fin") var file = File.new() file.open("res://framedata.txt", File.WRITE) file.store_string(create_scratch_readable_file(animation)) file.close() func create_scratch_readable_file(to_convert : Array) -> String: var final_str : String = "" for i in to_convert.size(): final_str = final_str + str(to_convert[i]) + "\n" return final_str
With this code, it converts the image to the scratch readable format
Note, no information about when to move to the next scanline is present in the framedata file, the code already knows to do this after 120 numbers have been processed.
The sprite-sheet, framedata, and source code files will be available to download at the bottom of the project.
Download
Install instructions
--RUNNING ON ITCH--
Simply run the HTML project. This will run at the original 30 FPS that bad apple runs at, it will be (almost) perfectly synced with the original.
--RUNNING ON SCRATCH--
This runs the project as it would naturally on Scratch, this has a choppy framerate, and is prone to lag spikes and slowdowns. There are also two ways to run it on Scratch.
METHOD 1 (Recommended)
First, go to https://scratch.mit.edu/projects/802873205/ and press "See inside" (You do not need a Scratch account for any of this)
Next, go to the "Variables" tab in the blocks list, and be sure to click on the check mark next to the "framedata" list so that it is checked.
Right click on the empty list and press "Import"
Scratch will banish you to your file explorer. Simply navigate over to your framedata.txt and double-click it (You can download this above)
The framedata list will look something like this
Now all you need to do is run the project!
Enjoy!
METHOD 2
Method two requires you to download the Scratch project files (found above) and import them into Scratch. Technically less steps, but it requires you to already have a Scratch account.
Comments
Log in with itch.io to leave a comment.
Almost a year later and I realised I mispelled the scratch audio name (warairingo, it should have been waruiringo). I also messed up the code somewhere to where one frame is repeated twice on accident. This lead to the video being slightly desynced, but because the cymbal crash still lined up with the water droplet I thought it was fine (I didn't realize it lined up with something earlier).