I hope this question isn't inherently nonsensical.
I'm developing a game. I've separated out the underlying game engine (in Python) from the graphics component. I have a script that fuzzes some parameters, simulates part of a game using the game engine, and then visualizes it using Pygame.
I'd like to automate the following process:
Ideally, I'd like to do this a few times a day so non-technical members of my team could view the video and give feedback on visual aspects of the game.
I'd like to use Pygame because I've already got the code ready to go. But I suspect I should probably use something like PIL to create a series of image files and go from there.
Is this possible with Pygame? Should I just use PIL? Any other ideas for accomplishing something like this?
Assuming you are running on linux, and your graphics engine works in X, you can headlessly run any application you want using Xvfb (X virtual framebuffer). You can run a video encoder of the virtual (headless) framebuffer session. There are a couple of utilities to make this task easier:
You'd want to make a top level script which would:
Xvfb and ffmpeg are definitely the way to go for recording the game headlessly, this ensures you can record your game as is with no modifications. It should be doable but not necessarily easy. The above scripts should hopefully get you started.
Anton's answer inspired me to dig deeper into this question. Happily, I discovered it is possible to run Pygame headlessly, enabling me to accomplish what I wanted to do a bit more simply than Anton's method.
The basic workflow goes as follows:
Sample code (simplified version of my own code so this has not been strictly tested):
# imports
import os
import subprocess
import pygame
import mygame
# setup pygame to run headlessly
os.environ['SDL_VIDEODRIVER'] = 'dummy'
pygame.display.set_mode((1,1))
# can't use display surface to capture images for some reason, so I set up
# my own screen using a pygame rect
width, height = 400, 400
black = (0,0,0)
flags = pygame.SRCALPHA
depth = 32
screen = pygame.Surface((width, height), flags, depth)
pygame.draw.rect(screen, black, (0, 0, width, height), 0)
# my game object: screen becomes attribute of game object: game.screen
game = mygame.MyGame(screen)
# need this file format for saving images and encoding video with ffmpeg
image_file_f = 'frame_%03d.png'
# run game, saving images of each screen
game.init()
while game.is_running:
game.update() # updates screen
image_path = image_file_f % (game.frame_num)
pygame.image.save(game.screen, image_path)
# create video of images using ffmpeg
output_path = '/tmp/mygame_clip_for_youtube.mp4'
ffmpeg_command = (
'ffmpeg',
'-r', str(game.fps),
'-sameq',
'-y',
'-i', image_file_f,
output_path
)
subprocess.check_call(ffmpeg_command)
print "video file created:", output_path
# upload video to Youtube using youtube-upload
gmail_address='[email protected]'
gmail_password='test123'
upload_command = (
'youtube-upload',
'--unlisted',
'--email=%s' % (gmail_address),
'--password=%s' % (gmail_password),
'--title="Sample Game Clip"',
'--description="See https://stackoverflow.com/q/14450581/1093087"',
'--category=Games',
output_path
)
proc = subprocess.Popen(
upload_command,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
)
out, err = proc.communicate()
print "youtube link: %s" % (out)
You'd probably want to delete all the image files once your video was created.
I did have a little trouble capturing screenshots headlessly, which I worked around as described here: In Pygame, how can I save a screen image in headless mode?
I was able to schedule my script to run as a cronjob without issues.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With