How do I port a game which uses print-output to pygame font rendering with the least amount of work?

by Schrodinger'sStat   Last Updated May 15, 2018 19:13 PM

I've been working on a text based RPG. It's pretty simple, I'm not very experienced with Python, or any other language for that matter.

Edit: For context, I recently posted this question: Python 3: How can I make my Text-based game windowed?

Here's my game you'd like to check out the code:

I took a long hiatus from working on the game because I became caught up in work, and after coming back to it today I've decided that I want it to run in a window, not a console.

I want my end product to have background art and audio files. I have a pretty good idea of how to do this (I've done very simple versions of this in languages like MATLAB and Processing)

What I'm beginning to realize though, is that many of the functions that I use in my game don't just magically "transfer" over to pygame. I don't get to just create a window and poof my game is there.

For example, my print() commands all won't appear in a pygame window, correct? So I did some research and it seems like I could (maybe) create a font, and replace them with:

textsurface = myfont.render('Some Text', False, (0, 0, 0))

But then I realized, how the hell do I get commands in there?

What about strings that are attributes of objects, will those display?

Is the way my game logic is written even compatible with this module?

So now I'm pretty bummed out and frazzled. I'm willing to restart from scratch I guess, but part of what motivated me to come back to the game was that I wanted to finish it.

Would the best move be to completely start over, or can a good amount of my code be salvaged and made compatible with displaying in a pygame window?

Answers 1

This sounds like a pretty classic abstraction problem, general to all programming and not just games. I'll provide some explanation in terms of a text game though to suit your question.

Absolutely nothing in your game logic should ever draw directly to the screen. In a console app, this would include print. If you want text to show up, do not just blit it. Instead, put it into a text buffer somewhere, and then once per update/frame, blit that whole buffer.

Likewise for input. The code that processes and handles input has nothing to do with rendering or keystrokes. Abstract the two. The core window renderer can deal with make an input area and handling keystrokes and the like, and then just provides the final string to the gameplay code when the user hits Enter.

This is after all exactly what your terminal emulator is doing when it renders your text app. :)

At that point, if your game is staying purely text, you'll have a simple abstraction for "print some text to the screen" and another for "process input from the user."

Since printing to the screen is the same at the abstraction level whether you're printing to the console or whether you're eventually rendering it to the screen, you can just do a big search and replace on your code right now and replace every print with my_print, which in graphics mode would put its text into a buffer. Likewise, the input-handling code would just be a function like handle_input(text) and it wouldn't have any reason to care whether that text parameter came from stdin on the console or came from a custom GUI text input box.

The input one is probably the harder abstraction to retrofit depending on how you've gone about coding everything... but if you did sprinkle raw input code all over your game logic, then you've got a bigger problem than just moving to windowed input, unfortunately. This happens even in games that are purely graphical from the start; I've seen a lot of novice/student game developers read raw input in game code and then get really stuck when they need to add game controller or key remapping support. Input should be abstracted.

Really, everything reasonable should be abstracted. Game logic code in your case figures out what to print. Another module should figure out how to print it. This is all part of the Single Responsibility Principle - a piece of code should only be doing one thing. Code that takes input, figures out new game state, formats an output string, and draws that to the string is doing four things, which is three too many for any single self-contained piece of code.

(There's exemptions to those code design guidelines that arise when one is worrying about performance, but that's more if you're working on the next Battlefield or whatever and not a pygame project.)

The short version is that you probably don't need to rewrite anything, but you will need to apply some sensible abstractions to your existing code to get ready for the transition to graphics.

Sean Middleditch
Sean Middleditch
May 15, 2018 18:56 PM

Related Questions

Problem with game responses

Updated February 28, 2016 01:05 AM

Replace text in Unity

Updated April 03, 2016 08:05 AM