





🌟 Special thanks to our amazing supporters:
✨ $10 Tier: [Geeks Love Detail]
🌈 $5 Tier: [Benedikt][David Martínez Martí]
This has been made by devcey, this is his blog on this project that he did for this game, which is incredible, I had to share it! You can check out the blog on infi.land here. [previewyoutube=R-6Z2PfNzdQ;full][/previewyoutube]
ffmpeg -i .\badapple.mp4 frames\frame-%04d.jpg
This essentially extracts each frame and saves it as a .jpg file in a seperate dictionary called 'frames'. Every frame is appended by a 4 digit number of it's index. E.g.: 0001, 0002, ... 0727, 0728, ... 6472, 6473.
Next up those frames had to be converted to sharp images that fit on the TCC level editor (32x22px in size), like this:
magick.exe mogrify -resize 32x22 *.jpg //Used to simply downscale each image.
magick.exe mogrify -colors 2 -colorspace gray -normalize -format png *.jpg //Used to apply a constrast of 2 grayspace colors, in order to eliminate any gray pixels
With this completed, the frames have been prepared.
[hr][/hr]
{"ROOT":[
{"x":448,"obj":"o_whiteblock","y":192},
{"x":448,"obj":"o_whiteblock","y":224},
{"x":480,"obj":"o_whiteblock","y":192},
{"x":480,"obj":"o_whiteblock","y":224}
]}
import os
from PIL import Image
frameDirectory = "frames"
jsonDirectory = "json"
for file in os.listdir(frameDirectory):
jsonFile = open(f"{jsonDirectory}\{file}.json", "w") #create the json and start writing.
jsonFile.write('{"ROOT":[') #append to the file
frame = Image.open(f"{frameDirectory}\{file}") #instantiate as image
for x in range(29): //max width. even though its at 32x22, this was set to 29 to keep the aspect ratio!
for y in range(22): //max height
pix = frame.load()
if pix[x,y] >= 100:
x_coord_int = x*32
y_coord_int = 64+y*32
x_coord = str(x_coord_int)
y_coord = str(y_coord_int)
#{"x":x-coord,"obj":"o_whiteblock","y":y-coord},
jsonFile.write('{"x":')
jsonFile.write(x_coord)
jsonFile.write(',"obj":"o_whiteblock","y":')
jsonFile.write(y_coord)
jsonFile.write('},')
#print('{"x":', x_coord, ',"obj":"o_whiteblock","y":', y_coord, '},')
jsonFile.seek(jsonFile.tell() - 1, os.SEEK_SET)
jsonFile.write('') # Intentionally empty to remove last comma if needed before closing bracket
jsonFile.write("]}")
jsonFile.close() #finish writing.
It's not the cleanest code but what this file essentially does is to loop through every image in my frames folder, create a valid LevelEditor.sav for it until there are no frames left to process. For reading the image, I imported PIL from the Image library. It checks through each pixel using an if-statement which checks for the brightness of the respective pixel. If it is bright enough, an object is added.
There is one bug in this script - if one frame is completely dark (as in, there are no white pixels) then it creates an invalid file. This is because an object is always created with a comma in the end, however this comma must be removed for the last object. So I made the script always remove the last symbol before closing the list of objects. This causes a syntax error and requires a manual fix. -
Why didn't I add another if-statement regarding the type of symbol the last symbol is? I don't know, I was just lazy, haha.
[hr][/hr]
import pyautogui #used to mouse click
import shutil
import os
import time
levelDirectory = "json"
tccLevel = r"C:\Users\devcey\AppData\Roaming\The_Colorful_Creature\LevelEditor Files\Badapple\LevelEditor.sav"
pyautogui.keyDown("ctrl")
for file in os.listdir(levelDirectory):
start = time.time()
shutil.copy(f"{levelDirectory}\{file}", tccLevel)
end = time.time()
elapse = end - start
time.sleep(0.3 - elapse) # Ensure consistent timing, original value was 0.03, might need adjustment
pyautogui.typewrite("l")
#pyautogui.click(955,265)
pyautogui.keyUp("ctrl")
What this does is to essentially loop through every LevelEditor.sav we've created, copy it into the TCC level directory while keeping its name "LevelEditor.sav". While it constantly holds CTRL, it presses L after each paste. In order to keep it constant, a sort of timer is applied which makes sure the same amount of time passes between two levels, as copying and pasting a level that is 110 bytes small needs less time than one that is 15 kilobytes large.
So all we need to do is to run this file, focus the TCC window and let it do it's job, all while recording our screen. Then we need to edit the recording by speeding it up to match the original video.
Except, the game would constantly crash. I've not been able to figure out the issue so what I did is to just redo the level loading process but with starting at a later frame that I've already loaded before.
So by mixing together multiple recordings and speeding them up, we receive the end result. Please do not look at the clock in my recording :)
[hr][/hr]
[ 6021 ]
[ 1645 ]
[ 1922 ]