People new to programming often ask for suggestions of what projects they should work on and a common reply is, “Write a text adventure game!” I think there are even some popular tutorials floating around that assign this as homework since I see it so much. This is a really good suggestion for a few reasons:
- The concept is familiar and fun (everyone loves games!)
- They can be written using core libraries
- The UI is the console
But new programmers often struggle with knowing where to start. That’s why I wrote and published Make Your Own Python Text Adventure. This book is a structured approach to learning Python that teaches the fundamentals of the language, while also guiding the development of your own customizable text adventure game.
For those of you who know some Python and just need a little guidance, there’s an abbreviated version of the book material here on the blog. It assumes you are familiar with basic programming concepts (if-statements, loops, objects, etc.), but are still new to writing full applications.
- Part 1: Items and Enemies
- Part 2: The World Space
- Part 3: Player Actions
- Part 4: The Game Loop
- Appendix A: Saving a Game
Just looking for some code? You can view the tutorial version of the game on GitHub.
Hello, I’ve been testing out your Python Adventure, and for the life of me I’m unable to get it to work.
I receive the following error.
Traceback (most recent call last):
File “adventuretutorial/game.py”, line 5, in
from adventuretutorial import world
ImportError: No module named ‘adventuretutorial’
I’ve done a litte reasearch but I can’t find anything thats relative to the problem I’m having I’ve tested it on multiple versions of Linux / Windows and multiple versions of python 2.7, 3, 3.2, 3.3, 3.4
But the same issue continues to occur!
I would love pointing in the right direction to help me resolve this as I’m really interested in learning python and this guide is very comprehensive and covers many areas I find interesting.
Best regards,
Robert Barton
Please see Part #4:
Pingback: Capstone Day 5 | KWNull
Hello,
I have been working through your tutorial and completed it. It has been very useful in improving my knowledge of python programing. However I am unable to run the program. I am running the latest version of python 3 and I am on a mac. The terminal error says this:
Traceback (most recent call last):
File “/Users/macuser/Documents/Scripting/Python/adventuretutorial/game.py”, line 2, in
from player import Player
File “/Users/macuser/Documents/Scripting/Python/adventuretutorial/player.py”, line 4, in
class Player:
File “/Users/macuser/Documents/Scripting/Python/adventuretutorial/player.py”, line 5, in Player
inventory = [items.Gold(15), items.Rock()]
File “/Users/macuser/Documents/Scripting/Python/adventuretutorial/items.py”, line 14, in __init__
super().__init__(name=”Gold”,
TypeError: super() takes at least 1 argument (0 given)
I believe the error is something to do with the super() function in the items module. However my code is identical to yours. I do not see I can fix this.
If you have any idea I would appreciate some help.
Thank you for your time.
Regards, Iain
I have a strong feeling you are trying to run this using Python 2. The
super()
method was introduced in Python 3. Depending on how you have Python installed, runningpython
at the command line could open a 2.x.x version and runningpython3
could open a 3.x.x version. It really depends on how you have things configured.I am having the exact same problem as lain and am running the code in the latest version of python 3. What do you think the problem could be?
I can confirm this error exists in Python 2.x, but not in 3.x. When you go to a command line and type “python” you will enter an interactive python session and the first line will give you the version number. I have a feeling your PATH is not configured to use the newer version.
I had been running the code with python 3 and was eventually able to fix the errors I was getting. Thank you for your help!
`super` has been part of python since 2.2. The python3 version of `super` doesn’t take any arguments, which is why Iain got the original error: he was using it according to python3 convention and not python2.
There is a great example of future-proofing one’s use of `super` on this page:
http://python-future.org/overview.html
Hi, I was wondering, when I play this game it kind of just piles up the text, is there end way to clear the text every time I go to a different tile?
Sure, check out this Stack Overflow question.
i cant get this game to work either. i get the same ‘no module named adventuretutorial’. how can i fix this problem? I’ve troubleshooted for hours lol
i have the latest python version also
I am using enthought canopy for coding in python. Its fine and all, but doesn’t support python 3. What can I use to run this game, and how?
Vanilla Python? I’m not sure I understand the question. Download and install Python 3.x and you should be good to go.
Well, thank you very much for this tutorial. I have encountered a couple of errors, and I have re-checked the code and the listed code on the posts many times. Here are the errors:
Error 1:
Traceback most recent call:
File Game.py, Line 27 in
play()
File Game.py, Line 9, in play
room = World.tile_exists(Hero.loaction_x, Hero.location_y
Error:(I don’t remember too well) Something like ” no attribute tile_exists for World ”
Error 2:
Traceback most recent call:
File Game.py, Line 27 in
play()
File Game.py, Line 10, in play
Hero = Hero()
InboundLocalError: local variable ‘Hero’ (the last part is blurry in my head) something like used before exists or something.
Error 2 I can easily fix by calling it ‘player’ instead of Hero, but Error 1 is really creating a wall for me here. I will put another post showing the exact wording.
If the error was
('module' object has no attribute '')
then I would make sure you review your map and the assumptions I make in the code about that map.TY I fixed both, but found another error:
Traceback (most recent call last):
File “Game.py”, line 24, in
play()
File “Game.py”, line 6, in play
player = Hero()
TypeError: ‘module’ object is not callable
Here is the code:
import World, Hero
Well, did you also name your Player class Hero? If the Hero class does not exist, then the code will fail when it tries to create a new Hero object.
I named the Player class Hero.
IDK what to do.
Hi, I forked the adventure and ported it to Python 2.x.
Modifications:
– View a map of the dungeon.
– Gold is cumulative
– Loot does not respawn
– map.txt works off spaces instead of tabs so that working in text editors is easier
https://github.com/typedeaf/text-adventure-tut
Thanks!
I like the way you have put all this together. While I like the object oriented aspect of things, I’m still trying to go back to basics… like how would I store the action verbs and a list of objects the way old text adventures were written in BASIC. And I was thinking the exact same thing. Learning Python so I’ll try writing a text adventure!
My second choice would be a D&D Character Generator and then a simple game out of it 🙂
I love your tutorial. Could you possibly explain how I could add a specific enemy tile that wasn’t random? I am new to python. I have been able to modify a few things but I can’t seem to add a specific enemy. I can however change the “r” values to produce a specific enemy but I don’t want the same enemy every time. Can you help? Thank you.
Thanks, I’m glad you’re enjoying it! I would create a new class called
GiantSpiderTile
(or whatever your enemy is). Then in theinit()
function, just setself.enemy = enemies.GiantSpider()
explicitly. Not sure how far you are in the book, but don’t forget to add your new tile type totile_type_dict
.Thank you for the reply. I will try that out tonight! I’ve been trying to learn Python on my own for a few months now. I have bought a few books but yours is by far the most interesting to me. BTW, have you ever thought about making a supplemental to your book that covers modifications? I’d pay for that. Thanks.
My hope is that by the end of the book, you have all the tools you need to complete some of the modifications I suggest in the last chapter. Although I know it can be intimidating going from something guided to unguided. If you need a little more nudging, feel free to email me.
on p67 in the code at the top
line 35 seems incomplete.
Should it read?:
print(“Enemy does {} damage. You have {}HP remaining.”.format(self.enemy.damage,player.hp))
Nice catch, you’re correct, that last line got cut off. I’ll fix that the next time I publish, thanks!
Hi, I have a question. I’m on page 63 on the Enemies chapter. The book says the code is runnable but I’m getting some errors when I move to an EnemyTile. In game.py there is the line:
print(room.intro_text())
This fails with the NotImplementedError that was created for the MapTile class. However, since the EnemyTile is declared as such:
class EnemyTile(MapTile) it will try to call MapTile.intro_text().
I assume I need to call the intro_text() in enemies but I don’t see this in your book at this point.
Take a look at page 62 where the text starts, “In order to alert the player about the enemy…”. Right below that, you should see a code snippet that shows the
intro_text
method. Hope that helps!I have added the intro_text() into the enemy class but it never gets called. This is what it looks like right now:
game.py
room = world.tile_at(player.x, player.y)
This returns EnemyTile found in the world_map. According to the code for EnemyTile it doesn’t implement it’s own intro_text and since it is a subclass of MapTile it will use the intro_text() there and get the NotImplementedError.
Ah, that’s why, you should be adding the
intro_text()
method to theEnemyTile
class, not theEnemy
class. I can see how that might be unclear, but I switched over to theEnemyTile
class at the bottom of page 61. We are referencing theEnemy
class simply to get access to the name of the Enemy, but the intro text takes place in the tile.Ahh, got it.
Thanks
Hi, I have bought your book and have tried to run all the code but I am getting an Error:
I have tried comparing my code to the code in the book but they appear to be the same.
I have never got this error before and am finding it hard to realise what is wrong
That error means Python is trying to look up
' '
in yourtile_type_dict
but it is not finding a match. I would take a look at yourworld_dsl
variable because that is where the map of tiles is defined. My guess is you have some extra spaces where you don’t want them. Try turning on your editor’s “show all characters” mode. That may help you track down the problem.Hi, I started your tutorial and I am new to Python so this will be a great way for me to learn new things. I downloaded the final project on Github to make sure it works on my version of Python, and I get an error when trying to run the game.py in the Python 3.5 IDLE. This is the error:
Traceback (most recent call last):
File “C:\Users\Ben\Documents\Python Programs\text-adventure-tut-master\adventuretutorial\game.py”, line 31, in
play()
File “C:\Users\Ben\Documents\Python Programs\text-adventure-tut-master\adventuretutorial\game.py”, line 10, in play
world.load_tiles()
File “C:\Users\Ben\Documents\Python Programs\text-adventure-tut-master\adventuretutorial\world.py”, line 18, in load_tiles
with open(‘resources/map.txt’, ‘r’) as f:
FileNotFoundError: [Errno 2] No such file or directory: ‘resources/map.txt’
Take a look at Part 4 where I describe how to run the game. Also, I’d suggest learning how to run it from the command line first before introducing the complexity of an IDE. Happy coding!
Thanks, but I don’t understand how to change the path. I don’t understand the link in Part 4 since I work on Windows, not Linux. I understand how to change the path in the environment variables, but I added my game folder as a path there and nothing has changed (it still can’t find the directory).
OK, try this:
cd C:\Users\Ben\Code\PythonGame
python adventuretutorial/game.py
and press enter.What happens?
Hello, and thank you very much for the tutorial! I got it all to work and it works great, except for some reason, when I’m in an enemy room and I kill the enemy inside it, instead of giving me actions to choose from to exit the room, it raises the error “TypeError: ‘method’ object is not iterable”. Any idea about why that may be? Thanks again!
-Justin Hangingtree
This is a guess, but do you have
available_actions = room.available_actions
instead ofavailable_actions = room.available_actions()
in your code? The error is telling you that you are trying to loop through a method object. You actually want to loop through what the method returns, not the method itself. To call the method, you have to include the parentheses. Hope that helps!Hello! I’m creating a text game using your book and I’ve run into a problem in the world.py chapter. Whenever I run the game I get the error: ‘AttributeError: ‘NoneType; object has no attribute ‘intro_text’. I’ve gone over and over my code and I can’t seem to find where I’ve gone off course.
I’m having a lot of fun with this, and I’m hoping to get the game to functioning soon so I can use it as a means of proposing to my boyfriend. Any help would be appreciated!
Take a look at the comments in Part 3 where this has been discussed a bit. It means Python can’t find the tile at the location you gave it, so it returns
None
. BecauseNone
is not the starting room, you get an error thatintro_text
is not part ofNone
. You can usually fix this my modifying your map file or change the starting location of the player. Good luck and I hope he says “Yes”!Your book was a great help. I got the yes! Definitely made for a great proposal story! Thanks a bunch!
That’s awesome to hear, congratulations!
I’m up to page 60 in the book version of your excellent tutorial. I’m finding this WAY easier to understand than Learn Python the Hard Way.
If I run the code as it stands on page 60, I get the following error when I reach a None tile. Is this error expected at this point? Or did I type something wrong? (Btw, I already took a look in the comments at Page 3 and Page 4 of the online tutorial and did not find the answer to my question.)
PS C:\PythonGame> python .\game.py
Escape from Cave Terror!
You find yourself in a cave with a flickering torch on the wall.
You can make out four paths, each equally dark and foreboding.
Action: e
This is a very boring part of the cave.
Action: e
Traceback (most recent call last):
File “.\game.py”, line 30, in
play()
File “.\game.py”, line 10, in play
print(room.intro_text())
AttributeError: ‘NoneType’ object has no attribute ‘intro_text’
I’m glad you’re enjoying the book! It doesn’t look like you’ve done anything wrong, that’s actually one of the bugs that gets fixed in the next chapter. See the “Limiting Actions” section of Chapter 13.
Thanks, Phillip!
It might be worth revising the following line in the next edition from…
“Notably, the game doesn’t end when you reach the VictoryTile and
the player can also wrap around the map.”
to something like
“Notably, the game doesn’t end when you reach the VictoryTile and
entering a None tile triggers an error.”
I also found a potential typo in the book version. The x/y coordinates appear to be flipped in the second example:
Page 62:
world_map = [
[None,VictoryTile(1,0),None],
[None,BoringTile(1,1),None],
[BoringTile(0,2),StartTile(1,2),BoringTile(2,2)],
[None,BoringTile(1,3),None]
]
Page 68:
world_map = [
[None,VictoryTile(0,1),None],
[None,EnemyTile(1,1),None],
[EnemyTile(2,0),StartTile(2,1),EnemyTile(2,2)],
[None,EnemyTile(3,1),None]
]
Nice catch, I’ll fix that in the next update!
Thank you, Phillip, for a wonderful resource. I completed the tutorial and am on my way to customizing the game.
One feature I would like to add is the ability to save progress and restore later. (Serialization.) Research suggests that using Pickle to save certain player/world variables is the way to go, however, I am unable to figure out exactly what to do. Is it very tricky to do?
Thank you.
Best,
Tony
It’s probably not too hard. I’d make a save data class where you write all the relevant variables to and then use the examples here as a guide. You might need to do some restructuring to make it easier to inject variables during unpickling.
Thanks, Phillip!
Another feature I’m struggling with:
I’d like to add a locked room and another room featuring a key to unlock the locked room. I think I’ve got the key room figured out, but I’m having trouble figuring out how to make a locked room with the way the following is structured:
def get_available_actions(room, player):
actions = OrderedDict()
print(“Choose an action: “)
if player.inventory:
action_adder(actions, ‘i’, player.print_inventory, “Print inventory”)
if isinstance(room, world.TraderTile):
action_adder(actions, ‘t’, player.trade, “Trade”)
if isinstance(room, world.EnemyTile) and room.enemy.is_alive():
action_adder(actions, ‘a’, player.attack, “Attack”)
else:
if world.tile_at(room.x, room.y – 1):
action_adder(actions, ‘n’, player.move_north, “Go north”)
if world.tile_at(room.x, room.y + 1):
action_adder(actions, ‘s’, player.move_south, “Go south”)
if world.tile_at(room.x + 1, room.y):
action_adder(actions, ‘e’, player.move_east, “Go east”)
if world.tile_at(room.x – 1, room.y):
action_adder(actions, ‘w’, player.move_west, “Go west”)
if player.hp < 100:
action_adder(actions, 'h', player.heal, "Heal")
return actions
The code looks to see if a room exists next to the current room. Technically, the locked room exists, but I don't want to let the player enter it until they find the key.
Another limitation of the above is adjacent rooms that I want to put a wall between. (Instead of say, travelling east into the next room, the player would see a wall and be forced to travel north, then east, then south.) I could put a "None" room in between the two rooms, but this would produce a undesired column.
Any way to do the above things without having to drastically restructure the way the DSL generates?
Thank you for your time and expertise.
Best,
Tony
So instead of just using
if world.tile_at(room.x – 1, room.y)
, you will probably want to create a new method to handle all of the logic for figuring out what the player can do. To accommodate locks, I would check 1) if the room exists and 2) if the room requires a key and 3) if the player has the correct key in the inventory. Then you only add the action if the result of that new method is true.For walls, you could create a wall tile for the DSL. Then you would just need to add another check to the new method to make sure the tile is not a wall. The
type()
function may help.Thanks, Phillip! I’ll give all this a try.
Re: Wall tile, that would produce an extra column. I think instead, I’ll make certain World tiles that have variables that place walls. (Maybe something like wall_east, wall_west, etc.) And then in the game logic, I’ll check to see if the wall is there and prohibit travelling in that direction.)
Hi,
I have gone through your tutorials online and in the book and I am having the same error (though I can get your github code to work so I know I’ve made a typo somewhere and I can’t figure it out). I have tried going through and comparing your code to mine and I still can’t find any differences besides customizable things. Do you have any idea what might be going on here?
Below is my code for the available_actions function in my tiles.py
And here is my code for the ViewInventory action:
It seems to be upset I haven’t given ViewInventory any arguments in the available_actions function but your code doesn’t do that either, so I’m not sure what I’ve done wrong. Any direction would be much appreciated!
Thank you!
~Adrianna
The only difference I notice is that I name all of my parameters in the
__init__
method. This is kind of tricky, but if you keep going back, you see that the baseAction
class uses**kwargs
. Because of that, I believe you need to name all of your parameters, otherwise Python does not know which belong in**kwargs
and which do not.I am really enjoying your book. But I am having a serious problem. My code is exactly as yours. I keep getting a “Player object has no attribute ‘inventory.’ error. This is when I try to run the game importing the player module and the items modules (all this before the World Building chapter). Says my problem is in line 13 (print_inventory) of the player.py. Cut and pasting my code from the modules here:
(and next module is where I think the problem is, on line 13, but I am pretty sure there are no differences in my code and what is in the book. Any advice you could give me is welcome.)
Just a follow up, I see when I posted that it took out my spacing. My spaces were in there, and match the book. I’m really confused as to what line 13 in the player.py is doing to generate the error. Again, there error is
“Player object has no attribute ‘inventory.’
This happens when I try to access the inventory when running the game.
thanks for any assistance.
Nothing looks obviously wrong to me. How are you trying to run the game? Can you include the full error message?
Hi, I have recently bought your great programming book but want to add some more features. I have encountered a problem when trying to make a “Warp Tile” which transports the player to another position on the map. Here is my code:
Hi Edward,
Neat idea! The reason your player won’t be moved is because you have a
return
statement before you make changes to the player. Thereturn
keyword exits the method. If you want to make changes to the player, you should use themodify_player()
method. Take a look at the finalEnemyTile
at the end of the Enemies section in Chapter 12 for an example. Happy coding!Great tutorial. Gave me a leg up in getting my own thing started. Take a look and let me know what you think so far.
https://github.com/azureknight63/Heart-Of-Virtue
That’s really cool! I like how you implemented a save feature and it’s neat to see that you were able to pull in some RPG elements into the game. Nice work. 🙂
Hello!
I have gone through the book and everything is working except for one thing. The blank areas in the DSL (none) are not rooms the player can go through. So when I have it setup like this:
The player does not have the option of going west at the start. I am not sure where my error is but do you have any ideas?
Thanks!
Are you saying that the player should not be able to walk West, but the player actually can? If so, check your code for
get_available_actions
. If you’re getting an actual error from Python, that might include some helpful details.Hi! I’ve been following your book and have run into an error somewhere in Chapter 13 (I haven’t been able to test the code until the end since it’s all related.)
It seems the map hasn’t generated properly as I am receiving this error immediately upon running the program:
“AttributeError: ‘NoneType’ object has no attribute ‘intro_text'”,
I know that the player location is correct as I can get the program to print it before it terminates, (1,2)
Here’s my map generation code: (Maybe it’s something to do with the order of functions?)
Thanks!
That error means that your
tile_at
is returningNone
instead of an actual room. You mentioned that the player’s location is (1,2). Is that x=1, y=2 (correct) or x=2, y=1 (incorrect)? This might help:Hmmm, it’s x = 1, y = 2…
“Tile at y=2, x=1 does not exist.”
Did the map not generate properly?
Sorry, my knowledge of python is pretty basic soo 😮
So apparently it works when i include “world.parse_world_dsl()” at the beginning of game.py. I suppose I didn’t call the function anywhere and that’s why the map wasn’t built. Would you mind referring me to where you called the function? I must’ve missed something.
It looks like I reference that part of the code in chapter 14, sorry for the confusion! I will add a clarification in the next release of the book.
It’s all good! Thanks for your help 🙂
Hi again XD Just have a couple questions on expanding the game. I’ve finished the main content now, thanks for the awesome book! 🙂
Just wondering if there was a way to make an X, Y, Z coordinate system? I was planning on having a castle which has multiple floors. I suppose when the player goes up / down I could teleport them to another part of the grid and just say it’s down, would that be an efficient way of doing it? The map would be pretty big. :/
Also, is there a way to seperate rooms without a “None” tile? Like lets say these 2 rooms along a corridor are adjacent, but you cant enter one room from the other, you gotta come out and enter through the corridor. (Without adding a none space inbetween them and hence another tile to the corridor)
Sorry for all the questions! Thank you!!
It’s definitely possible to do a 3D coordinate system. The simplest way to do this is to have a list of lists of lists. That is to say: floors, rows, and columns. This is also called a 3D-array since there are three dimensions. I would then build each floor as its own DSL string and include a method to patch them together.
Sometimes it is hard keeping track of all three dimensions in your head, especially if you end up with code like
floors[z][y - 1][x + position]
so you might decide to make a “Floor” class to make things a bit easier to work with.There’s two ways you could create a “wall”. You could make it its own room type that gets included in the map, but then
tile_at
method would ignore any “Wall” tiles. If you want to do something more complex, you could try introducing a new character to the DSL like!
that means “impenetrable”. So you would end up with|EN!EN|FD|
. But if you did that, you would need to determine the adjacent tiles during parsing and keep that information in theMapTile
class. Then thetile_at
method would also need to be smarter because it would have to refer back to that information you stored during parsing.Hope that helps, happy programming!
Hi again! I’ve been tryna implement those things for the last couple days, but as I am a bit of a newbie to python, im not making much progress 🙁
Wouldn’t making a “wall” tile essentially be a NoneTile anyway?
like |EN|WA|EN| = |EN| |EN|?
Kinda want something like
|EN|EN|
|ST!TT|
meaning, to get to the trader from the Start tile, you’ll have to fight 2 enemies. I’m not too sure I understand your second proposed solution. How would you store the adjacent tiles and improve the tile_at function? 😮 Sorry im hopeless ahah
Hey, amazing book. These are my first steps in Python and programming and I am 3/4 through your book and everything is going great so far. Really enjoying it.
Once the game is complete, can it be made to play outside a python terminal? For example, is there a way I can get all my finished code to run in Frotz or something similar with all my other adventure games? I’d like to learn how to port it to other platforms so I can share my work with my friends, perhaps if they could play the game on Android phones?
I’m sorry if this is a dumb noob question… but that’s what I am so far :/
Glad you’re enjoying the book! It is possible to make the game an “application” using third-party tools like py2exe. It looks like it might be possible to do Android too using this python-to-android tool, but I’ve never tried it. Good luck, let me know how it works out!
Hey, im loving your book, i am up to the point where we begin to expand the world.
i am getting a Error:
below is a a copy of my Code:
thanks in advance
If you take a look at the error message, it is telling you there is a problem with line 13 of player.py. It then includes the line with the error
self. x = world.start_tile_location[0]
. I am not sure if this is a copy/paste error, but the code error you pasted has a space betweenself.
andx
which might be the problem. Hope that helps!Hello, I recently decided to try and start learning Python. I really liked this article, and I went through it, and the code seemed right; however, it wouldn’t start. So I decided to download it and see if yours worked on my computer, and found that it didn’t; instead, it gives these errors:
Any ideas?
Are you following this advice?
If so, are you using an IDE?
I found that in moving rescources within the tutorial directory, it made it work, though I’m still confused as to why the code I made was unable to work. Here’s the errors on that:
Traceback (most recent call last):
File “C:/Users/jhard/PycharmProjects/ShadowsOfTlanen/game.py”, line 28, in
play()
File “C:/Users/jhard/PycharmProjects/ShadowsOfTlanen/game.py”, line 10, in play
print(room.intro_text())
AttributeError: ‘NoneType’ object has no attribute ‘intro_text’
seems to be a problem with ‘intro_text’, yet I’m not sure which.
Some other people have had that same problem. Take a look at the other comments on this page. Let me know if you still are stuck!
So now the intro_text glitch is gone, but now it is having different trouble:
File “C:\Users\jhard\PycharmProjects\ShadowsOfTlanen\world.py”, line 18, in load_tiles
_world[(x, y)] = None if tile_name == ” else getattr(__import__(’tiles’), tile_name)(x, y)
AttributeError: module ’tiles’ has no attribute ‘EmptyPassage
‘
Anything I’m missing here? I’ve been looking through the comments and trying solutions. (BTW, thanks for the replies)
Here’s the EmptyPassage code:
class EmptyPassage(MapTile):
def intro_text(self):
return “””
The empty corridor is deathly silent, and you feel the desire to hasten through as quickly as possible.
“””
Fantastic tutorial! Very clear, thoughtful instructions.
I have one question though:
So I’ve spent several hours fleshing out the map and adding monsters and items to create an exciting text adventure, but now let’s say I want to distribute the programme to friends using a stand-alone executable. Using this tutorial as an example, how would I compile game.py with all of its dependencies, including map.txt?
I’ve been reading all over StackOverflow and several other sites looking for answers, and tinkering with PyInstaller every which way, but to no avail.
PyInstaller will probably work fine. The easiest option might be to distribute both the map file and the exe and either assume they are in the same directory or ask the user where the map is. But if you do want to bundle the map inside the exe, this looks like the way to do it. However, I have never used PyInstaller so I can’t verify that.
Hi Phillip,
First; Thanks for the great book. I had a lot of fun learning python this way and you did a great job explaining the game as you went.
Second; I am trying to add an “Escape” action as an acceptable action during a fight. I want it to force the user to move to the previous tile that they occupied, as opposed to picking a direction, which might allow them to simply bypass enemies. Any recommendations on how to achieve this?
Thanks!
You’d need to keep track of the last room the player is in. Something like
self.last_room = (3, 4)
. When the player moves, you would update that value. Then you would add anescape
method that would set the player’sself.x
andself.y
to the values inself.last_room
. Happy programming!Hey Phillip!
This is an awesome tutorial! I’ve been trying to expand it by having NPCs in the tile and giving the player an option to talk to them. I’m having trouble however in my code because I’m trying to add an NPC into a tile and giving the player an option to talk to them. So ideally the dropdown would be:
Choose an action:
….
t: Talk to NPC
BUT I keep getting this error and I can’t figure it out for the life of me:
TypeError: __init__() missing 3 required positional arguments: ‘method’, ‘name’, and ‘hotkey’
Here’s my code pertaining to the talk action
In my actions.py code, I clearly have the arguments and I modeled the format after your attack action in the tutorial and yet I’m having so much trouble! Any idea what might be causing the error?
Thanks!
It looks OK to me. What is the line actually causing the error?
Hey Phillip,
First of all I loved your book, I worked yhrough it in roughly a week! And I’ve been expanding it ever since! Now I have some future ideas of actually adding graphics perhaps using PyGame it seems to be easy.
Do you have any spearpoints or tips, perhaps tutorial references for converting the stuff in your book to an actually graphical rpg? (Simple ofcourse, maybe just some pixel art or something.)
Thanks in advance!
Greetz,
Thursten
I don’t have much experience with graphics programming, but my advice would be start learning how to load a sprite and have it move based on user input. PyGame is a commonly used package to help with this. Here’s one tutorial I found (can’t verify it’s accuracy), but looks like it would be a good start.
Hi, my son has been working through your book (which he is finding great fun) but has struck a problem at the end of chapter 10. The code appears to be correct but this is the error:
Any tips would be appreciated.
Glad your son is enjoying it! Since chapter 10 involves moving things around to different files, I wonder if something just wasn’t correctly copied? The error means that the Player class does not have the
most_powerful_weapon
method. It could also be something likedef most_powerful_weapon()
(incorrect) vsdef most_powerful_weapon(self)
(correct).If neither of those suggestions work, post the whole Player class and I will take a look.
My son has checked multiple times for errors but he probably missed one and also the most_powerful_weapon looks ok so:
Ah, OK so the problem is the indentation. Right now that method is “outside” of the
Player
class. It needs to be indented inside the class.Great thanks! I’ll get him to check it again (the last few comments were actually him….he’s keen to make it go!) He’s really impressed (and so am I) with the level of help that you have given him. I keep telling him that Python is fussy about indenting and this is a perfect example 🙂
Oh sorry, the indents actually didn’t show when I copy pasted
Thanks so much, it works now. Sorry about that indent error, amazing program 🙂
^^ My son means your program is amazing, way cooler than starting with “Hello world.” Thanks again.
Hi! Is there a way to make the game playable from the browser so it could be more easily shared?
Python is a great web programming language, so it would be possible, but I think users would have a better experience if most of the work was done in the browser using JavaScript. Either way, the amount of work to do that is well beyond the scope of this tutorial.
You can use the py2exe utility to distribute Python programs more easily on Windows environments. And with minimal effort, you could make the code python2 compatible, which is available by default on most linux and MacOS installations.
Pingback: Classes: Raymond Hettinger’s ‘Python’s Class Development Toolkit’ Talk – Just Tryin' to Python
Hi! I have your book and I’m teaching my son to code with it. I keep running into problems, over and over. I am wondering if you have a repository somewhere of all the code in the book, so that I can compare it against ours. I downloaded the code on Github, but that doesn’t seem to have everything from the book. Just wondering if you have it all somewhere – maybe with a password based on text from a page number, so you know we bought the book? 😀
Thanks! The code from the book is on the Apress GitHub here.
Thanks! I’ll have a look.
That was much easier to line up with the book. Thank you.
Hello!
My name is Matt, and I’m a amateur Python coder.
I just want to say that your book really helped me understand how to work with Python in pretty short time, and I’m glad I bought it!
After I finished the material from the book, I started working on the RPG by myself. I managed to add stuff like new monsters, items and rooms (like a “rest room” that allows the player to regain HP once) and even figured out how to add a EXP system with leveling up (a simple one so far).
I’ve been thinking to eventually make a proper story for this game, but here’s one problem I have:
I feel that making the game with just one map will not be enough for me, and wanted to add stairs that would allow the player to go to a different dungeon level, and later maybe even add a option to leave the dungeon and explore the world.
But I have trouble figuring out how to do this properly. I know that I should have several different maps like the one created during the tutorial (and probably at one point have seperate files for the world maps and tiles) but what would be the best way to allow the player to move from one map to another? And how should I modify the DSL?
Do you have any advice?
I hope for a quick reply!
Glad you enjoyed the book! You’re right that the method presented in the book doesn’t really scale up easily to multiple maps/levels. I would suggest doing something similar to what is done in the tutorial here on the site. That is to say, put your maps into files that live outside of the code.
You might even find that one map file per level is too confining and you need a “map file” and a “room data file”. The map file would simply have IDs that refer to rooms in the data file. The data file would contain the information like enemies in the room, loot, descriptions, etc. You could also scrap the map all together and put the positional information into the data file! Using a data file definitely gives you more flexibility, room variety, etc. but at the expense of making your code a bit more complex.
Tracking the player’s level is pretty easy, I’d just add another attribute to the player to store which level they are working on. And then the player’s position is calculated using x, y, and the level.
Hi, this tutorial has been very helpful, but I’m having some trouble figuring out a few errors:
Traceback (most recent call last):
From what I can see I have done everything as written in the guide
If you could help me figure it out, it would be greatly appreciated.
You have a typo, it should be
split
notspilt
.Thanks for the help, but now there are some other errors.
I am still a little new to python i’m sorry if it’s something very simple again.
You have another typo. Try comparing your code against my code on the specific line that’s giving you the error.
hi Phillip
thx for your book. That’s a great piece of work! Can you help me to reach the game itself?
I tried https://www.dropbox.com/sh/udvdkxtjhtlqdh1/AAD9H0D6VTb5RGFZ7kBv-ghua?dl=0
but I cannot have the link work.
Maybe for the next edition you could insert a short url
best,
That’s a good suggestion for the short link! Most readers are using the ebook where you can just click the link. Here’s the link (you had a typo): https://www.dropbox.com/sh/udvdkxtjhtlqdh1/AAD9HOD6VTb5RGFZ7kBv-ghua?dl=0.
Hi Phillip I am getting these errors and i’m stuck and don’t know what to do i’ve look at the other comments who also got this error and i still don’t know what to do.
Traceback (most recent call last):
It likely means that your map is invalid. Make sure you review how to create the map and the assumptions about the file that the code makes.
Thank you i found white space in the map but i’m getting this other when i’m playing the game and i’m thinking it has something to do with the map and i tried redoing the map several times and i still get this error when playing the game. Thanks.
Traceback (most recent call last):
File “/home/ubuntu/workspace/adventuretutorial/game.py”, line 29, in
play()
File “/home/ubuntu/workspace/adventuretutorial/game.py”, line 25, in play
player.do_action(action, **action.kwargs)
File “/home/ubuntu/workspace/adventuretutorial/player.py”, line 19, in do_action
action_method(**kwargs)
File “/home/ubuntu/workspace/adventuretutorial/player.py”, line 31, in move_north
self.move(dx=0, dy=-1)
File “/home/ubuntu/workspace/adventuretutorial/player.py”, line 28, in move
print(world.tile_exists(self.location_x, self.location_y).intro_text())
AttributeError: ‘NoneType’ object has no attribute ‘intro_text’
Hello! I was wondering if you know what my problem is. I’m experiencing some trouble with my game.py file when I try to launch it I am fairly new to python. Please let me know which pictures you need, or pieces of code. I hope I’m not taking up too much of your time!.
What command are you using to run the game and what error message do you see?
Pingback: What You Can Do With Python – BODRAY
Hey Philip,
Doing a gamebook/text adventure for a CS class.
My code looks good, but when I run it, it doesnt end after each path the way I had envisioned it in my head.
It will run you through the next lot of code until it runs all ppaths that lead to the end of the code.
Heres what a few section look like:
# Homework_2_Make_a_gamebook
# Overview: A gamebook is a work of fiction that allows the reader to participate in the story by making choices that
# affect the outcome of the story. Of course, the reader does not really affect the outcome of the story,
# the book simply presents multiple paths that the reader may take and the reader only chooses one on any particular
# read-through.
def main():
print ("A Federation Starship receives a distress signal from an unknown vessel. They are far from home and not in "
"immediate contact with support, and the frequency of the distress signal is of unknown origin.....\n")
print ("The Captain is alerted and makes his way to the bridge of the Starship. He discusses his options with his "
"Senior Staff..... \n")
print (
"They decide that there are 3 options that make sense: To ignore the distress signal, open up communication, "
"or wait for support from the nearest Federation vessel.\n")
print ("Your crew looks at you for a decision: ignore, contact or wait, what will you choose?\n")
option1 = input ("Please enter your choice: ignore/contact/wait\n")
if option1 == 'ignore':
print ("Your crew carries out your orders, but it is clear not everyone agrees with your decision. Do you confront "
"the unhappy crew members, yes or no?\n")
option2 = (input ("Please enter your choice: yes/no\n"))
if option2 == 'yes':
print ("After discussing your decision with the disagreeing crew members: do you accept the criticism gracefully, "
"or do you see the criticism as a personal attack? Do you move on, or do you punish dissenters?\n")
option3 = input ("Please enter your choice: move on/punish\n")
if option3 == 'move on':
print ("A few months later, another Federation vessel receives a distress signal from the same unknown frequency. "
"They initiate contact and are ambushed and killed by a god-like alien race. Your crew is grateful for your "
"intuition.\n")
elif option3 == 'punish':
print ("You decide to punish the crew members who disagreed with your order, a mutiny forms and you are imprisoned "
"by your crew.\n")
exit ()
elif option2 == 'no':
print ("A short time later your ship receives another distress signal from the same frequency as the previous "
"distress signal. Your crew logs the incident but does not inform you about it. You become aware of the "
"incident when reviewing the log. Do you avoid any further discussion about the "
"second incident, or do you get more information from the crew members involved?\n")
option4 = input ("Please enter your choice: avoid/more information\n")
if option4 == 'avoid':
print ("The source of the distress signal is eventually contacted by a rival Space Federation. The distress signal "
"was transmitted by a god-like alien race. Your inaction costs the Federation a powerful ally.\n")
elif option4 == 'more information':
print ("All information pertaining to the distress signals are sent to Federation Headquarters for further "
"analysis.\n")
Any feedback and help is greatly appreciated mate.
Pingback: What Can I Do With Python? – Real Python - Almas Ali
Hi, I loved your tutorial but when I try to run the game I keep getting this error:
Traceback (most recent call last):
File “c:\Users\Owner\tutorial\game.py”, line 48, in
play()
File “c:\Users\Owner\tutorial\game.py”, line 27, in play
world.load_tiles()
File “c:\Users\Owner\tutorial\world.py”, line 25, in load_tiles
_world[(x, y)] = None if tile_name == ” else getattr(__import__(’tiles’), tile_name)(x, y)
AttributeError: module ’tiles’ has no attribute ‘