As promised,, here is the second part of this guide. This will attempt to demonstrate some more advanced concepts related to games. Beforehand though, let's make sure that we are on the same page.
What you should already know
Loops, both for and while
Passing Parameters to Functions
List and string Slicing
Dictionaries (Not critical but good to know)
Classes (Possibly inheritance but not a big deal if you don't totally understand the concept, I used it once in a project)
Class properties and how to access them
Importing modules (I will mention this shortly)
While it seems basic, I still would like to touch on the import statement, just to make sure that we are on the same page.
The normal import
What you may be familiar with is something like this:
import math print(math.pi)
That is one way to link modules. However, to save you some typing, you can also do this:
from math import * print(pi)
So what is the difference between the two?
The box analogy
Let's pretend that the Python console and the math module are boxes. The "import math" statement makes the two boxes sit next to each other. When you say something like "math.pi", you are basically opening the lid of a box labeled math, pull out the variable called pi, use it within your line of code, and put it back in the box shutting it as you do so. The advantage to this approach is that it keeps your global namespace nice and clean, unlike the second import method.
The second import method is a little more crude. Instead of leaving the boxes next to each other, it takes the math box, opens it, dumps it's contents into the current namespace (The python console in my case) and then throws it away. This is why the earlier example with print(pi) works. We basically move whatever we specified in our import statement into the current namespace and throw everything else away.
The drawbacks of the from statement
Python is really nice. It allows us to change a string to an integer, or a boolean to a function. However, that can also become an issue if you love typing "from x import *". Because Python is so nice, it does not complain when you override a variable and change it's type. If your module has a function named "walk" that deals with moving objects around the grid and you type "from os import *", your walk function will be overwritten with the os's walk method which deals with looping through files and directories on your PC. The interpreter won't complain about the override until you try and use the walking function to move an object because as I said before, Python is nice.
There is another spectrum to consider, however. Sometimes, you won't immediately notice that a function has been overwritten until you have moved farther along the development. A good example of this is the "open" function. It is available by default, dealing with opening files on your computer. If you also have a function named open in your module that accepts two strings as it's parameters, you would override the standard open method and will have a difficult time telling why something doesn't work as you expect it too.
I have been saying functions, but they are not the only things that can be changed. Classes, lists, dictionaries... anything can change types in an instant when it comes to Python. Again, it's not bad, but it is something you should keep in mind. To that end, I use your standard "import x" and generally avoid "from x import y" in most cases. When I do use it, here is something that runs through my head before I include such statement.
Am I using a star? Star tells Python to import everything from a module and thus is the most dangerous to use.
Is it a standard or pip-installed library? If yes, then I avoid using a star all together and just import the entire module. (If you don't know what pip is, you will soon.) (If something is not in your project folder, math, for example, you know that it's either pip-installed or something that comes with the interpreter.)
Can I reuse this later? This is important. If you import math in script1.py and you type from script1 import * in script2.py, you can use math in script2 without importing it again. If I can reuse the import in some way, it will have a greater chance of persuading me to type "from x import y"
These questions help me decide if it's worth it to clutter my namespace.
Enough! Skip to games
When it comes to making games, there are a few options available.
Other libraries that I probably left out
This guide will focus on Pygame, as it is what I use on the daily bases. If you like other examples to be included, PM me with the converted versions of the ones that will be shown here.
Installing Pygame is really simple. Assuming that you already have Python installed, opening up the command line and typing
pip install pygame
should do the trick. To verify that Pygame has been installed, open up your Python console and type import pygame. If you get no errors, great! You can continue with this guide.
Wait, what is Pip
Pip is a package manager for Python. It simplifies downloading and installing packages onto your machine. A good rule of thumb when lacking a module to run a project is to type pip install module_name to see if it can cut out some searching on your part.
Are there any modules you recommend
I think everybody should have pip-review, pip install pip-review. It's like an auto-updater for all of your packages. To use it, type pip-review --interactive in your command line and if you get a prompt that a new version is available for a module type in a. This will update everything to the latest version.
So... what about that window
Right. After installing Pygame, save this bit of code. This will be your template for pretty much everything dealing with games.
import pygame pygame.init() screen = pygame.display.set_mode((600, 400)) #Window height and width. The assignment is optional, but it is useful if you want to mess with the screen later. pygame.display.set_caption("caption name") #Name of your game def main(): while 1: pygame.time.wait(2) #Wait for 2 milliseconds between each loop main()
Wait, it crashed.
Ah, yes. If you run that bit of code you will indeed see that it doesn't work. What is the reason for it not working? That bit of code just loops forever, it doesn't try to communicate with the system at all, making your computer think that the program crashed. Add this to your template.
#In the while loop, before the wait statement keyloop() #After the wait statement but before the call to main def keyloop(): for event in pygame.event.get(): if event.type == pygame.QUIT: #The user clicked on the close button pygame.quit() exit() #Shut down the window.
Now the program should work as expected, or at least not crash when you run it.
Making windows is great, but...
I know, I know. The most important of them all, keyboard input. Let's rewrite our quitting program from earlier by making the user press space to quit.
import pygame, pygame.locals as pl #pygame.locals is now known as pl pygame.init() screen = pygame.display.set_mode((600, 400)) pygame.display.set_caption("caption name") def main(): while 1: keyloop() pygame.time.wait(2) def keyloop(): for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() exit() if event.type == pygame.KEYDOWN: #A key event that has been detected if event.key == pl.K_SPACE: #The user pressed space pygame.quit() exit() main()
There you have it. A list of all the keys can be found here
So far, I have shown you a way to get keys every time they're pressed. This is useful for reading out player's health and coordinates, but it is not so helpful when it comes to something like walking or firing a gun. To that end, consider this bit of code.
import pygame, pygame.locals as pl #pygame.locals is now known as pl screen = pygame.display.set_mode((600, 400)) pygame.display.set_caption("Caption name") counter = 0 #To be used for key holding demonstration def main(): while 1: keyloop() pygame.time.wait(2) def keyloop(): global counter #Without this Python will traceback because I haven't created a variable called counter in this function for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() exit() keylist = pygame.key.get_pressed() #This retrieves the state of every single key on the keyboard. if keylist[pl.K_SPACE]: #Will trigger only when space is pressed counter += 1 if counter >= 300: #About 1 second pygame.quit() exit() main()
Run this bit of code and you will indeed see that this event occurs multiple times. Move the check to the for loop, and you'll see that you have to press space 300 times to quit the program. Remove the if statement checking for counter equality, and regardless where the check is, the program will exit.
Wait, what is different between the two methods?
The first method (the for loop) loops through the events and checks if they're equal to the values in your if statements. This essentially means that the event will only have 1 equal value. Typing this will not work
for event in pygame.event.get() if event.type == pygame.KEYDOWN: if event.key == pl.K_SPACE and event.key == pl.K_a: #Do our logic.
As I've stated, this method will not work. Think of it as a math expression (2+x = 5). What is x in this case? 3. It can't be 4, nore 1, because that will make the problem false. So, let's rewrite our for loop to demonstrate the flaw with this logic.
for event in pygame.event.get(): if 2+x = 5 and 2+x = 6: #Do our logic here
Now that's an interesting problem... how can 2+x equal to five and 6 at the same time? The simple answer is that this problem cannot be solved and the condition above will never be triggered.
So why does the get_pressed() function work?
In the for loop, we only have 1 x. In a list we could potentially have thousands of variables. Boot up your python console and type this to verify that the method will, in fact, fire correctly.
x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] print(1 in x and 2 in x and 3 in x and 4 in x and 5 in x and 6 in x)
The result? Assuming that you have used my code, you should get the output of "true".
Where's my speech!
You have two options for outputting a message to your screen reader.
Tolk is the first and the most simplistic option. It is easy to use, is quite strait forward, and doesn't provide a lot of complications. The downside to Tolk is that it only works on the Windows operating system.
AO2 is a bit more difficult to setup, but where Tolk only works on Windows, AO2 can work on anything but IOS, i.e, Linux and Mac.
The pip way
pip install accessible_output2
should do the trick. I have not tested it without the required modules, however, so that may be something to keep in mind when running the command. If the install fails, read on to see what could be the issue.
Installing modules for Accessible Output Two
First, try to type this into your command line:
pip install libloader
pip install platform_utils
If pip fails to install the modules, try typing the following:
pip install https://github.com/cartertemm/continuum-repositories/raw/master/continuum/libloader-8cf2e5262508.zip pip install https://github.com/cartertemm/continuum-repositories/raw/40f1a495dfc9c5bcae91d12f4279a09bb2156b5b/continuum/platform_utils-042203769da7.zip
If that fails, download libloader from here and platform_utils from here.
To install the modules, open up the command line, go into the respective directories (I would do libloader first) and type python setup.py.
As usual, to verify that everything installed correctly, boot up your python console and type
import libloader, platform_utils
If you get no errors, great. You should be fine to use AO2.
An example of speaking using Tolk
Make sure that everything you've downloaded from the Tolk link provided above is in the folder with your script before trying to run it. Also, let me know if I screwed up the dlls again, I tried to cut out some of the work when it comes to guessing the correct windows version.
import Tolk, time Tolk.load() Tolk.output("testing testing 1 2 3...", True) time.sleep(2) Tolk.output("I am a really long message, yes I am", True) Tolk.output("i will not interrupt myself until I finish speaking", False) time.sleep(3)
An example of speaking using Accessible Output Two
Before doing anything, grab this speech file from here, courtesy of Carter Temm. After the file has been downloaded, copy it to the folder where you plan to save your file in. Do the same with Accessible Output Two folder. Now, create a file and populate it with the following code
import time from speech import speak #A rare case where I use from speak(,this is a test!") time.sleep(2) speak("I am a really long message! Yes I am!") speak("i will not interrupt myself until I'm finished speaking", False) time.sleep(2)
I would like to mention that import speech and speech.speak() would have worked just as well, but this is the way I saw it used first and it stuck with me ever since.
If the tiny upload links do not work for you, try these.
Carter's speech file, you will have to copy the code and save it as speech.py in order for the example of using accessible output two to work properly
By this point, you should know how to create windows, get keyboard input, and output messages to a screen reader. The next and the last part of this guide will cover sound, menus, timers, saving and loading data, and copying text to your clipboard. It will also cover code protection with Cython and compilation of such code into an executable.
I hope that these guides are useful to you. If you believe that I have left out some information that is crucial to this guide, please let me know so I can update this to be of the utmost help.
Parts of this guide
What is hard is making code that accepts different and sometimes unexpected types of input and still works.
This is what truly takes a large amount of effort on a developer's part.