[OPTIMIZED] 🐍🎞️🎬 Python Animation! 🐍🎞️🎬
Python Animation But Optimized
Added buffering to @JBYT27's Python Animation Tutorial
Comparsion between the two:
I came across this post today, and the tutorial was quite nice, but the flickering bothered me, so I decided to attempt to optimize it.
DISCLAIMER: I am not hating on other users, I'm doing this purely for a fun challenge
I'm not going to use additional libraries in the spirit of the challenge, so in order to approach this, I will need to use escape sequences.
import time def buff_append(buffer, data): buffer = buffer + data def buff_fflush(buffer): print(buffer) buffer = "" def render(): buffer = ""
We will append everythig into our buffer. We can use escape sequences to clear the screen, move the cursor, etc.
import time def buff_append(buffer, data): buffer = buffer + data return buffer def buff_clear(buffer): buffer = buffer + "\x1b[2J" + "\x1b[H" return buffer def buff_fflush(buffer): print(buffer) buffer = "" return buffer def render(): buffer = ""
\x1b[2J clears the screen and
\x1b[H positions the cursor to the beginning.
frames = [ "o/", "o\\" ]
I'll add in some very simple frames for now which we can use to test our program.
We can initiate a simple loop which will loop through each frame and display it using our current rendering engine.
def next_frame(frame): frame = (frame + 1) % len(frames) return frame def render(): buffer = "" frame = 0 while True: buffer = buff_clear(buffer) buffer = buff_append(buffer, frames[frame]) buffer = buff_fflush(buffer) time.sleep(0.1) frame = next_frame(frame) render()
Let's try a larger animation:
frames = [ "", "", "", "" ] def init_frames(): for i in range(0, 4): for j in range(0, 30): if i == 0 or i == 2: frames[i] = frames[i] + "||||||||||||||||||||||||||||||||||||||||||||||||||||||||\n" if i == 1: frames[i] = frames[i] + "\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\n" if i == 3: frames[i] = frames[i] + "////////////////////////////////////////////////////////\n"
Now the console should run pretty smoothly, but I'll implement a final optimization
def buff_fflush(buffer): buffer = "\x1b[?25l" + buffer + "\x1b[?25h" temp = buffer.split("\n") buffer = "" for s in temp: s = "\x1b[K" + s + "\n" buffer = buffer + s sys.stdout.write(buffer) return "" def render(): buffer = "" frame = 0 while True: buffer = buff_append(buffer, frames[frame]) buffer = buff_fflush(buffer) time.sleep(0.1) frame = next_frame(frame) init_frames() render()
\x1b[?25h will show and hide the cursor so that we don't see the cursor flying around the screen in case printing gets slow. I know I'm using
sys.stdout.write but technically it's not an external library so I'm going to allow it.
Now essentially with
\x1b[K I'm clearing each line while I draw it.
What I did here was essentially very basic I/O buffering. I've never really written Python before this so it was quite a new experience.
Final Program: https://repl.it/@Pankak/ConsoleAnimationOptimized#main.py
Now for good measure, I forked @JBYT27's exact code and ran the same animation, the difference is quite apparent:
Credit to @JBYT27 for the original post
cool. suggestion: in future repls you can make them into pictures instead of lines. very cool tho.