http://roguebasin.com/api.php?action=feedcontributions&user=Cprofitt&feedformat=atomRogueBasin - User contributions [en]2024-03-29T11:12:46ZUser contributionsMediaWiki 1.36.0http://roguebasin.com/index.php?title=Roguelike_Tutorial,_using_python3%2Btdl,_part_1&diff=47709Roguelike Tutorial, using python3+tdl, part 12018-10-28T19:14:00Z<p>Cprofitt: /* Setting it up */</p>
<hr />
<div><center><table border="0" cellpadding="10" cellspacing="0" style="background:#F0E68C"><tr><td><center><br />
This is part of a series of tutorials; the main page can be found [[Roguelike Tutorial, using python3+tdl|here]].<br />
<br />
The tutorial uses tdl version 3.1.0 and Python 3.5<br />
<br />
</center></td></tr></table></center><br />
<br />
<br />
__TOC__<br />
<br />
<center><h1>'''Graphics'''</h1></center><br />
<br />
== Setting it up ==<br />
<br />
Ok, now that we got that out of our way let's get our hands dirty!<br />
<br />
* If you haven't yet, [http://www.python.org/download/ download and install Python 3.5].<br />
<br />
* Install the tdl module for python3. <br />
<br />
* In windows:<br />
<br />
[http://www.mingw.org/ MinGW] must be on the Windows path for use with pycparser.<br />
<br />
<div style="padding: 5px; border: solid 1px #C0C0C0; background-color: #F0F0F0"><syntaxhighlight lang="python">python3 -m pip install tdl</syntaxhighlight></div><br />
<br />
* Note: If you're working on a fresh environment or a new PC, don't forget to install the latest Microsoft Visual C++ runtime. If you've made sure that your x32 or x64 version of Python matches both your operating system and the install packages and you're still getting "ImportError: DLL Load Failed" when you try to execute the code, this may be the issue.<br />
<br />
As of version 3, tdl now depends on libtcod-cffi. It will be installed automatically by pip.<br />
<br />
* In Linux:<br />
<br />
If using a Debian or Ubuuntu based distro, install the following dependencies:<br />
<br />
<div style="padding: 5px; border: solid 1px #C0C0C0; background-color: #F0F0F0"><syntaxhighlight lang="python">apt-get install gcc libsdl2-dev libffi-dev python-dev</syntaxhighlight></div><br />
<br />
If using Fedora, install using the folloowing commands:<br />
<br />
<div style="padding: 5px; border: solid 1px #C0C0C0; background-color: #F0F0F0"><syntaxhighlight lang="python">dnf install gcc-c++ SDL2-devel libffi-devel python3-devel</syntaxhighlight></div><br />
<br />
If you use a different distro, you'll have to figure out the equivalent packages. Feel free to update this wiki with the relevant information.<br />
<br />
Next, install tdl:<br />
<br />
<div style="padding: 5px; border: solid 1px #C0C0C0; background-color: #F0F0F0"><syntaxhighlight lang="python">pip3 install tdl</syntaxhighlight></div><br />
<br />
Now to create your project's folder. Create an empty file with a name of your choice, like ''firstrl.py''. <br />
You'll also need a font file in png format. We chose '' arial10x10.png'', which you can download [https://github.com/HexDecimal/python-tdl/blob/master/fonts/libtcod/arial10x10.png here].<br />
<br />
More fonts are available [https://github.com/HexDecimal/python-tdl/tree/master/fonts/libtcod here].<br />
<br />
== Choice of code editor ==<br />
<br />
If you're just starting out with Python, you'll find that many Python coders just use a simple editor and run their scripts from a console to see any debugging output. Most Python coders don't feel the need to use a fancy IDE! On Windows, Notepad++ is an excellent bet; most Linux programmers already have an editor of choice. Almost all editors allow you to configure shortcut keys (like F5 for instance) to quickly run the script you're editing, without having to switch to a console.<br />
<br />
[[Complete Roguelike Tutorial, using Python+libtcod, extras#A neat Python shortcut for Notepad++|See this page from the libtcod tutorial]] if you want to set up a Notepad++ shortcut with a couple of nice features for debugging, or if you tried to roll your own and hit the infamous "module not found" error.<br />
<br />
<br />
== Showing the @ on screen ==<br />
<br />
This first part will be a bit of a crash-course. The reason is that you need a few lines of boilerplate code that will initialize and handle the basics of a libtcod window. And though there are many options, we won't explain them all or this part will really start to drag out. Fortunately the code involved is not as much as in many other libraries!<br />
<br />
First we import the library.<br />
<br />
<div style="padding: 5px; border: solid 1px #C0C0C0; background-color: #F0F0F0"><syntaxhighlight lang="python">import tdl</syntaxhighlight></div><br />
<br />
<br />
Then, a couple of important values. It's good practice to define special numbers that might get reused. Many people capitalize them to distinguish from variables that may change.<br />
<br />
<br />
<div style="padding: 5px; border: solid 1px #C0C0C0; background-color: #F0F0F0"><syntaxhighlight lang="python">SCREEN_WIDTH = 80<br />
SCREEN_HEIGHT = 50<br />
LIMIT_FPS = 20</syntaxhighlight></div><br />
<br />
<br />
Now we're going to use a custom font! It's pretty easy. You can find many choices [https://github.com/HexDecimal/python-tdl/tree/master/fonts/libtcod here]. Remember however that they can be in different '''formats''', and you'll need to tell it about this. This one is "grayscale" and using the "tcod layout", which we indicate by setting the parameter ''altLayout=True''. Most fonts are in this format and thus end with ''_gs_tc''. If you want to use a font with a different layout or make your own, the [http://roguecentral.org/doryen/data/libtcod/doc/1.5.1/html2/console_set_custom_font.html?c=false&cpp=false&cs=false&py=true&lua=false docs on the subject] are really informative. <b>If you do switch the font, you may also need to change the "greyscale" and/or the "altLayout" settings to "False."</b> You can worry about that at a later time though. Notice that the size of a font is automatically detected.<br />
<br />
<br />
<div style="padding: 5px; border: solid 1px #C0C0C0; background-color: #F0F0F0"><syntaxhighlight lang="python">tdl.set_font('arial10x10.png', greyscale=True, altLayout=True)<br />
</syntaxhighlight></div><br />
<br />
<br />
This is probably the most important call, initializing the window. We're specifying its size, the title (change it now if you want to), and the last parameter tells it if it should be fullscreen or not.<br />
<br />
<br />
<div style="padding: 5px; border: solid 1px #C0C0C0; background-color: #F0F0F0"><syntaxhighlight lang="python">console = tdl.init(SCREEN_WIDTH, SCREEN_HEIGHT, title="Roguelike", fullscreen=False)</syntaxhighlight></div><br />
<br />
<br />
For a real-time roguelike, you wanna limit the speed of the game (frames-per-second or FPS). If you want it to be turn-based, ignore this line. (This line will simply have no effect if your game is turn-based.)<br />
<br />
<div style="padding: 5px; border: solid 1px #C0C0C0; background-color: #D0FFC2"><syntaxhighlight lang="python">tdl.setFPS(LIMIT_FPS)</syntaxhighlight></div><br />
<br />
<br />
Now the main loop. It will keep running the logic of your game as long as the window is not closed.<br />
<br />
<br />
<div style="padding: 5px; border: solid 1px #C0C0C0; background-color: #F0F0F0"><syntaxhighlight lang="python">while not tdl.event.is_window_closed():</syntaxhighlight></div><br />
<br />
<br />
For each iteration we'll want to print something useful to the window. If your game is turn-based each iteration is a turn; if it's real-time, each one is a frame. <br />
<br />
Now print a character to the coordinates (1,1). Can you guess what that character is? No, it doesn't move yet! <br />
<br />
Don't forget the indentation at the beginning of the line, it's extra-important in Python. '''Make sure you don't mix tabs with spaces for indentation!''' This comes up often if you copy-and-paste code from the net, and you'll see an error telling you something about the indentation (that's a pretty big clue right there!). Choose one option and stick with it. In this tutorial we're using the 4-spaces convention, but tabs are easy to work with in many editors so they're a valid choice too.<br />
<br />
<div style="padding: 5px; border: solid 1px #C0C0C0; background-color: #F0F0F0"><syntaxhighlight lang="python"> console.draw_char(1, 1, '@', bg=None, fg=(255,255,255))</syntaxhighlight></div><br />
<br />
Here we're setting the text color to be white. In RGB color codes, that's ''255,255,255'' [http://roguecentral.org/doryen/data/libtcod/doc/1.5.1/html2/color.html?c=false&cpp=false&cs=false&py=true&lua=false There's a good list of colors you can use here], along with some info about mixing them and all that. Alternatively, we can use hexidecimal color codes. For white, that would be: ''0xFFFFFF'' (note that there are no quotations around it, since Python will read it as a hexidecimal integer, not a string.)<br />
<br />
<br />
At the end of the main loop you'll always need to present the changes to the screen. This is called ''flushing'' the console and is done with the following line.<br />
<br />
<br />
<div style="padding: 5px; border: solid 1px #C0C0C0; background-color: #F0F0F0"><syntaxhighlight lang="python"> tdl.flush()</syntaxhighlight></div><br />
<br />
<br />
Ta-da! You're done. Run that code and give yourself a pat on the back!<br />
<br />
Note that since we don't have any input handling code, the game may crash on exit (it won't process the OS's requests to close). Oops! Don't worry though, this problem will go away as soon as we add keyboard support.<br />
<br />
[[Roguelike Tutorial, using python3+tld, part 1 code#Showing the @ on screen|Here]]'s the complete code so far.<br />
<br />
== Moving around ==<br />
<br />
That was pretty neat, huh? Now we're going to move around that @ with the keys!<br />
<br />
First, we need to keep track of the player's position. We'll use these variables for that, and take the opportunity to initialize them to the center of the screen instead of the top-left corner. This can go just before the main loop.<br />
<br />
<br />
<div style="padding: 5px; border: solid 1px #C0C0C0; background-color: #F0F0F0"><syntaxhighlight lang="python">playerx = SCREEN_WIDTH//2<br />
playery = SCREEN_HEIGHT//2</syntaxhighlight></div><br />
<br />
<br />
There are functions to check for pressed keys. When that happens, just change the coordinates accordingly. Then, print the @ at those coordinates. We'll make a separate function to handle the keys.<br />
<br />
<br />
<div style="padding: 5px; border: solid 1px #C0C0C0; background-color: #F0F0F0"><syntaxhighlight lang="python">def handle_keys():<br />
global playerx, playery<br />
<br />
user_input = tdl.event.key_wait()<br />
<br />
#movement keys<br />
if user_input.key == 'UP':<br />
playery -= 1<br />
<br />
elif user_input.key == 'DOWN':<br />
playery += 1<br />
<br />
elif user_input.key == 'LEFT':<br />
playerx -= 1<br />
<br />
elif user_input.key == 'RIGHT':<br />
playerx += 1</syntaxhighlight></div><br />
<br />
<br />
Done! These are the arrow keys, if you want to use other keys here's a [https://pythonhosted.org/tdl/tdl.event.KeyEvent-class.html#key reference]. Most codes are self-explanatory. KP stands for ''keypad''. <br />
<br />
While we're at it, why not include keys to toggle fullscreen mode, and exit the game? You can put this just above the movement keys.<br />
<br />
<br />
<div style="padding: 5px; border: solid 1px #C0C0C0; background-color: #F0F0F0"><syntaxhighlight lang="python"> if user_input.key == 'ENTER' and user_input.alt:<br />
#Alt+Enter: toggle fullscreen<br />
tdl.set_fullscreen(not tdl.get_fullscreen())<br />
<br />
elif user_input.key == 'ESCAPE':<br />
return True #exit game</syntaxhighlight></div><br />
<br />
From now on, we'll show code for a <span style="background-color: #D0FFC2">'''real-time game'''</span> with a green background, and code for a <span style="background-color: #DFEEFF">'''turn-based game'''</span> with a blue background.<br />
<br />
So far, we've been writing a turn-based game. Then the game won't go on unless the player presses a key. So effectively you have a turn-based game now. However, we'll introduce another option at this point. If we comment out the line ''user_input = tdl.event.key_wait()'' and replace it with the following block of code, we'll have a real-time game:<br />
<br />
<div style="padding: 5px; border: solid 1px #C0C0C0; background-color: #D0FFC2"><syntaxhighlight lang="python"> #realtime<br />
keypress = False<br />
for event in tdl.event.get():<br />
if event.type == 'KEYDOWN':<br />
user_input = event<br />
keypress = True<br />
if not keypress:<br />
return</syntaxhighlight></div><br />
<br />
This works because ''tdl.event.get()'' won't block the game.<br />
<br />
Now, the main loop needs to call this function in order for it to work. If the returned value is True, then we "break" from the main loop, ending the game. The inside of the main loop should now look like this:<br />
<br />
<div style="padding: 5px; border: solid 1px #C0C0C0; background-color: #F0F0F0"><syntaxhighlight lang="python">console.draw_char(playerx, playery, '@', bg=None, fg=(255,255,255))<br />
<br />
tdl.flush()<br />
<br />
#handle keys and exit game if needed<br />
exit_game = handle_keys()<br />
if exit_game:<br />
break</syntaxhighlight></div><br />
<br />
<br />
The reason why we draw stuff before handling key input is that, in a turn-based game, the first screen is shown before the first key is pressed (otherwise the first screen would be blank).<br />
<br />
One more thing! If you try that, you'll see that moving you leave around a trail of little @'s. That's not what we want! We need to clear the character at the last position before moving to the new one, this can be done by simply printing a space there. Put this just before ''exit_game = handle_keys()''.<br />
<br />
<br />
<div style="padding: 5px; border: solid 1px #C0C0C0; background-color: #F0F0F0"><syntaxhighlight lang="python"> console.draw_char(playerx, playery, ' ', bg=None)</syntaxhighlight></div><br />
<br />
<br />
[[Roguelike Tutorial, using python3+tdl, part 1 code#Moving around|Here]]'s a rundown of the whole code so far.<br />
<br />
[[Roguelike Tutorial, using python3+tdl, part 2|Go on to the next part]].<br />
<br />
[[Category:Developing]]</div>Cprofitt