What is SkeletonGame? PyProcGameHD?
This project is for people looking to program their own custom or re-themed pinball machines powered by either the P-ROC or P3-ROC (available from pinballcontrollers.com), using the SkeletonGame+PyProcGameHD Framework.
PyProcGameHD is essentially a fork of PyProcGame, a Python based pinball programming framework. PyProcGameHD does not support traditional DMD hardware, but instead supports modern LCD displays (e.g., in the backglass or apron) for high-resolution, full-color animations and effects. The display code is written using SDL2/OpenGL based hardware acceleration.
SkeletonGame runs on top of PyProcGameHD. SkeletonGame tries to reduce the amount of code you need to write to create a new game, by including code for most of the ’typical components’ found in every game.
Overview of PyProcGameHD and SkeletonGame
PyProcGameHD replaces the previous “HD VGA PyProcGame” and it’s functionality is a superset of that version. It has been re-written (and aggressively optimized) to leverage SDL2 (OpenGL) graphics hardware acceleration features. Many things are now possible with nominal overhead, including ‘dot-filter’, alpha transparency, per-pixel alpha, just to name a few. The prior PyGame-based version is available for those who might need it for some reason or another.
Note: If you wish to have projects running on different versions of PyProcGame, the easiest way is to just include the appropriate version of PyProcGame’s procgame folder as a subfolder named procgame in your game’s folder.
SkeletonGame is a collection of classes to speed up new game development that is also included (and maintained) as part of this release. If you are a new P-ROC developer, you should strongly consider using it. The idea being that most games all have the same core functionality, and that you shouldn’t need to code those things. SkeletonGame is a logical extension of PyProcGame’s BasicGame class and includes many things that were lifted from the JD sample game.
The “Goal” of SkeletonGame is to enable the programmer to:
- have VERY few lines of code in the Game class.
- spend most of his/her time coding the logic for modes.
- use helper functions to quickly display “DMD” content.
- get started quickly.
It leverages everything that those of use who use PyProcGame know and love, and only intends to streamline things. It should help you make games faster. If you have an existing PyProcGame project, you may choose to forgo SkeletonGame, and may migrate to the HD Framework with very minimal code changes. That said, I wouldn’t recommend it.
Installation details and getting started documentation is provided on a series of pages, here: https://skeletongame.com/tags/getting-started/
SkeletonGame: Big Picture
Having worked on a few P-ROC projects now, I’ve tried to distill the common bits from each of those games so that I can avoid rewriting the same lines again and again. It also tries to organize and automatically handle the flow of the larger ‘game’ events (game starting, ball starting, ball ending, etc.).
A game class that is subclassed from SkeletonGame should be very short. The example provided is fewer than 60 lines if you exclude imports, comments and whitespace. Most of your code should be present in your mode classes, instead.
- the class
SkeletonGame(which is a subclass of
BasicGame). This class will serve as the new superclass for your game. This class includes the following (by default):
- tracking ball counts, ball time, game counts, game time, loads/saves settings and data
- assetManager (all your images, sounds, music, fonts, lampshows are pre-loaded by defining a yaml file)
- a better
Playerclass: supports player state tracking built in with appropriate methods for access.
soundControllermode auto created and loaded
- OSC mode auto loaded (though apparently based on an old version..oops)
- Built-in (already working) trough, ballsave, ballsearch, and tilt/slam tilt modes (all based on Gerry/Adam’s versions)
- … a VERY simple attract mode that’s based on a simple, yet powerful yaml file/format
- … service mode (basically Adam’s) that senses dmd size
- … high score entry (based on Adam’s but in color) that senses dmd size
- … high score frame generation for display in attract mode
- … score display essentially based on Adam’s but updated to use color fonts, background animations, etc.
- … bonus helper (just like score:
bonus(tag, quantity)) and a built-in bonus tally mode that kicks in at the end of the ball and shows any bonuses awarded to the player during their ball
dmdHelper“mode” that generates a message on screen shown over a single image/animation, or a stack of them. It makes using the DMD extremely painless. It’s usage is:
displayText(text, key)If key is a list, it builds a grouped layer for all the keys. If text is a list instead of single string, all the text is shown on the frame. A single line is centered vertically, two lines are shown at 1/3, and 2/3, three lines at 1/4,2/4, and 3/4… You get the idea.
- Automatic state progressions without having to code for it in your game. No more calls to
- A new optional-Mode superclass called
AdvancedMode; AdvancedMode offers:
- a “lifecycle type” (ball, game, system, or custom) –modes are auto added/removed based on that type. They only need to be created by importing them in the game code and creating them in init. Skeleton game adds/removed them as per their type
- a refined set of game progress events that get sent to AdvancedModes, in priority order, prior to the actual event occuring. Now modes themselves can respond directly to
evt_tilt_ball_endingevents. Modes can also request to postpone the event propagation (i.e., the calling of the next event handler) by returning a number of seconds that the mode needs to ‘finish up’ (e.g., play a special animation or sound) or can delay and stop further propegation by returning a tuple of the delay in seconds and the second entry is
- A small and hopefully well commented example game based on T2.
- automatic handling of AC Relay coils (from yaml markup, only)
- match mode
- more features to the bonus mode: using a yaml file to define about valid bonuses, score per award, Max numbers to allow of said award, etc. the tally is still in progress –this is not totally done.
Game event flow
(changes from PyProcGame, etc.)
Your game class should not call game_start, ball_end, etc. It should also not need to override these methods. If you feel you need to, you should contact me so I can change the framework. As designed, SkeletonGame (and its constiutent parts, including the attract and bonus modes) will handle the successive event progression.
In a typical game, this looks like:
Your game class initializes itself in main()…
Behind the scenes,
super(SkeletonGame,self).__init__() does the following:
- initializes the sound controller
- finds the DMD settings from the config.yaml and sets up your display
- creates a lampshow controller
- loads all your assets from the asset_list.yaml file (shows the player a graphical loading bar)
- initializes and connects the ball_save and trough modes
- loads the OSC mode, bonus mode, score display
Then, any AdvancedMode derived modes that you initialize are automatically added to skeletonGame’s ‘known modes’ so it can add/remove them for you, based on their mode_type (game, ball, system, custom).
When you call reset():
The SkeletonGame version of reset() protects the modes that need to be in the game. The old reset method would remove ALL modes from the game, but reset() in skeletonGame’s will re-add modes that should not be removed and protect certain modes (e.g., the OSC controller) from being removed at all.
The last thing your reset() method should do is call:
Then, SkeletonGame takes over again, initiating the attract mode from the yaml file. When the player presses the switch with the name
startButton, SkeletonGame will automatically:
- ensure that the correct number of balls are in the trough, if not, a message is displayed and a ball-search is initiated. If the balls are present (or found later), it goes on to…
- find modes with method evt_game_starting and call those methods in the order of their mode priority (a mode that needs more time can return a positive number to delay calling the next such method for that many seconds). When completed, it goes on to…
- find modes with method evt_player_added and call them. This allows modes to perform any player specific data storage at this time. Then
- find modes with method evt_ball_starting and call them as above.
- finally, add a ball to the shooter lane; if the ball does not actually close the
shooterlaneswitch, the logic will continue to try to re-feed the shooter lane. The ball is not considered successfully launched or in-play until that switch has been closed.
Your modes hopefully do something here :)
When a ball drains (i.e., the trough is full again), SkeletonGame will automatically:
- finds modes with method evt_ball_ending and calls them
- show the ’end of ball’ and bonus sequence (if bonuses were awarded)
- if the balls number is less than the quantity specified in the machine yaml
- find modes with method evt_ball_starting and call them (repeating the cycle)
- if the ball number is greater than the quantity specified in the machine yaml
- finds modes with method evt_game_ending and calls them
- checks the players score against the high scores. If greater, the player may enter his/her scores
- attract mode is shown again
Making your first SkeletonGame-based game:
The Getting Started series of pages HERE are meant to help you get started working on a new game. You should read through these pages along side the provided Sample Game that is provided in the GitHub repository