Vi kodar ett textbaserat äventyr tillsammans! - Night at the museum, Chapter 1 (pt. 2)

Posted on March 24, 2016

Gör ditt eget textbaserade spel!

Om Projektet "Night at the Museum"

Det här avsnittet ingår i en kod-serie som heter "Night at the Museum". Läs gärna tidigare bloggposter för full insyn i projektet:

------

Kom igång

------

Här går vi igenom koden som körs för det textbaserade spelet "Night at the Museum - Chapter 1", steg för steg. Denna tutorial riktar sig mot nybörjare - kanske har du hört talats om Python eller gått en kurs någon gång, men det är inget krav för att klara av att göra spelet. Om du är bekant med Github så kan du även se förklarande/kompletterande kommentarer i koden.

Vi går igenom:

  • Hur man skapar en dialog med förbestämda svar
  • Hur man listar flera svarsalternativ
  • Hur man sparar text som användaren har skrivit och återanvänder den
  • Hur man ändrar på timingen i en dialog med hjälp av time-biblioteket

------

Hur testar jag koden?


Om du vill testa koden som vi går igenom, så kan du göra såhär:

1. Öppna din kommandotolk på datorn (terminal på mac)

2. Klistra in följande kod i kommandotolken (det gör så att spelets python-fil sparas i din dator):

python -c 'import urllib; urllib.urlretrieve("https://raw.githubusercontent.com/elisabettie/nightathemuseum/master/NATM-Chapter1.py", "./NATM-Chapter1.py")'

3. Klistra in följande kod i kommandotolken (så att spelet körs):

python NATM_Chapter_1.py

4. Enjoy the game!

------

Night at the museum - Programmering steg för steg

# textkommentarer i koden

När man har ett #-tecken framför text i koden, så ignorerar programmet meningen. Det låter oss skriva in kommentarer i koden utan att det krånglar till något för programmet.


Svenska tecken i kod

# -*-coding: utf-8 -*-

Okej, det finns vissa undantag för #-tecknet. I det här fallet så tolkar programmet det som står bakom #. Men det är ett undantag, och förhoppningsvis tutorialens mest ologiska detalj.

UTF-8 gör det möjligt att använda svenska bokstäver (äöå) i text utan att det krashar något. Ganska bra att ha med om man vill skriva sin berättelse på svenska!


importera bibliotek

import time
import sys

Ibland vill man att ens program ska kunna göra något som är krångligt. "Krångligt" kan till exempel vara att använda Pi i ett mattetal, eller som i vårt fall - hänvisa till hur många sekunder det ska ta, innan print ska köras.

Att skriva hur programmet ska komma fram till vad två sekunder är för något, är väldigt svårt. Därför hänvisar man istället till ett bibliotek där den koden redan finns, det är lättare än att skriva allt själv varje gång man startar ett nytt projekt.

import betyder att man laddar ett bibliotek där koden som man vill använda finns. Vi använder oss av biblioteket time för att kunna säga till programmet vad 2 sekunder är för något. En import gör man bara en gång i en fil, från det biblioteket kan man sen hänvisa till funktioner (något som programmet ska göra) kopplat till det, till exempel time.sleep().

För att spelet ska kännas mer som en dialog, har vi hämtat time-biblioteket, så att vi kan ändra väntetiden tills nästa mening skrivs ut. Vi laddar också biblioteket sys, för att kunna avsluta/avbryta programmet mitt i spelet.


"Tvätta" terminalen

print (chr(27) + "[2J")

Jag tycker att det är jobbigt när det står en massa text i terminalen innan spelet börjar. Därför googlade jag på kod för att "tvätta" sitt terminalfönster, och detta är en lösning som kom fram. Det första spelet gör är då att rensa historiken i terminalen, så att du startar spelet utan att bli distraherad från en massa gammal text.


Utskrift av text

print ("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
print ("~~~~~~~~~~~~~~~~~Night at the museum~~~~~~~~~~~~~~~~~~~~")
print ("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")

Här används print för att skriva ut titeln på spelet.

I programmet kommer vi att använda print väldigt mycket. På svenska skulle man kunna översätta det till "utskrift".

print indikerar för programmet att den ska skriva ut något på skärmen. Vad som skrivs ut, beror på vad som står efter print. I vårt programmer kommer vi till exempel använda print för att skriva ut dialoger som våra karaktärer har.


print ("Well hello, princess. How nice of you to finally show up!")

Det första vi möter i spelet är en dialog mellan dig och den mystiska personen som har ett uppdrag till dig. För att skriva ut dialogen använder vi oss ocksåav print. I parantesen är texten som vi kan läsa i spelet.


time.sleep(2)

Eftersom vi har hämtat 'time' biblioteket så kan vi använda en funktion som ser ut såhär:

time.sleep(2)

Det är egentligen inte så knepigt att gissa sig fram till vad den gör:

  1. Den hänvisar till biblioteket time, där koden finns
  2. Från biblioteket time så ska den köra en funktion som heter sleep
  3. I paranteserna ser vi hur ofta den ska utföras, vilket är två gånger/två sekunder (2).

Om man skriver 100 så skulle det vara 100 sekunder istället för 2! :-)

Nu har vi gått igenom några funktioner som vi kommer se mycket av i spelets kod. Så vi kör igenom hela koden och går igenom vad som händer i den.


Att spara text som spelaren skrivit

print ("I took the liberty of ordering a beer for you. Wouldn't be surprised if its flat now though."
print
person = raw_input("What's your name? ")
print ("Well, that's not your fault, " + person)
print

Här ser vi att den mystiska personen frågar vad du heter. Detta innebär att spelaren förväntas att svara på frågan, det vill säga skriva in ett eget, påhittat namn.

person = raw_input indikerar att inkommande text (namnet som spelaren svarar), kommer att sparas i programmet. För att kunna återanvända namnet, så sparas det som ett värde till ordet (variabeln) "person". Om jag hämtar person i koden igen (vilket vi kommer se längre ned) så kommer namnet som spelaren svarat att återanvändas i spelet.

Vi ser också att jag har lagt in "tomma" print . Varför? Det gör så att programmet skriver ut tomma meningar, vilket fungerar som radbrytningar.


Att sätta villkor för vad som ska hända härnäst

answer = raw_input("I assume that you know why you are here? ")
print
if answer.lower() == "yes":
print ("Good. Then we don't have to get into details.") print ("All you need to do is retrieve the Bloodsaphire to its rightful owner, which is me.") print ("I will pay for your work of course.")

På nästa fråga ("I assume that you know why you are here?") ska det gå att välja mellan två svar: antingen skriver spelaren 'yes', och då ska programmet känna igen det och ge ett specifikt svar. Eller så kan spelaren svara något annat, vilket ska leda till ett annat print från spelet. Metoden som vi använder här kallas för if-sats på svenska.

En if-sats betyder att programmet följer regeln:

Om (if) svaret är 'yes' > då ska programmet skriva ut "svarsalternativ 1", om svaret är något annat (else) > skriv ut "svarsalternativ 2".

Precis som i namn-scenen tidigare så kommer raw_input att vara något som spelaren svarat/skrivit, och kommer att användas som värde till ordet (variabeln) 'answer'.

answer.lowercase betyder att programmet alltid kommer tolka texten/svaret som spelaren skriver som små bokstäver. Det underlättar, eftersom vi då inte behöver lista alla olika versioner man kan skriva yes på, t.ex. YeS, yeS osv. Om texten/svaret då passar yes så har vi en sekvens med print svar som visas.


Om man inte uppfyller villkoret "yes"

else:
print person + (", what do I pay you for? Let's go through the job again -")
time.sleep(2)
print (" The Bloodsaphire is an artifact currently at the National Gem Museum.")
time.sleep(2)
print (" I want you to hand it to me.")
time.sleep(2)
print (" I will pay you for your work of course. If you succeed.")
time.sleep(2)
print

Här ser vi att namnet som spelaren angett/skrivit i början av spelet kommer att skrivas ut, innan dialogen med den mystiska personen fortsätter. Sedan blir det två sekunders väntetid innan nästa dialog visas.


Att spara flera svarsalternativ

print ("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
print (person + " slowly takes a sip of the beer while thinking about what to answer..")
print options = ["Don't you worry old man. Consider the job done.","Wait a minuite! Stealing from a museum?! Hell no, I'm not doing that!"]

Nu är det inte mycket kvar av första kapitlet av spelet.

I denna scen kommer spelaren att få två svarsalternativ att välja mellan. För att välja svarsalternativ använder vi raw_input igen, som när spelaren skulle skriva in sitt namn. Skillnaden nu är att svaret man skriver in kommer granskas av programmet. Svarsalternativen presenteras i en numrerad lista. För att välja ett svarsalternativ så måste spelaren skriva vilket svarsalternativ/siffra i listan som passar bäst.

Värdet till ordet (variabel) "options" består i detta fall av två svarsalternativ, men det skulle kunna vara många fler. Man kan se det som att "options" är en lista med svar.


Att lista flera svarsalternativ

for (position, option) in enumerate(options):
print position+1, '::', option
print
answer = raw_input("What will you answer? ")
print
print ("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")

Nu när våra svarsalternativ finns sparade i programmet, måste vi först lista dem och sedan ge spelaren en möjlighet att välja ett av dem.

För att lista alternativen i options så använder vi oss av funktionen enumerate.

Så här funkar enumerate(): För varje element (option) som finns i listan (options), kommer enumerate att lägga till ett ordningsnummer (position). I programmering så börjar (oftast) talordning med 0. Det betyder att listan (lite förenklat) skulle se ut såhär:

0 Don't you worry old man. Consider the job done.

1 Wait a minuite! Stealing from a museum?! Hell no, I'm not doing that!

Eftersom vi (människor) börjar räkna med talet 1 så kommer vi att behöva lägga till en liten matteräkning så att listningen som skrivs ut blir 1, 2, 3 istället för 0, 1, 2.

Därför används print position+1. Då tar programmet varje elements placeringstal + 1, så att första placering blir 1 (0+1) och andra placering blir 2 (1+1). Efter Listans nummer skrivs en textsträng med "::" och sedan svarsalternativet ut. Vi kommer därför få en listning som ser ut så här för spelaren:

1 :: Don't you worry old man. Consider the job done.

2 :: Wait a minuite! Stealing from a museum?! Hell no, I'm not doing that!


Vad händer när man valt ett svar i listan?

if answer == "1":
print "Good. I can't give you the money right now, but I have a name. Kaylei Schassy. She works at the local electric shop. Tell her that you want to change your light. She will be able to help you out."
time.sleep(4)
elif answer == "2":
print "You are a disaster! I never want to see you again!"
print
print ("You have failed the mission. But then again, maybe that's a good thing.")
time.sleep(2)
sys.exit() else: print "You know, I'm putting a lot of trust in you right now. Don't screw it up! Talk to Kaylei Schassy. She works at the local electric shop. Tell her that you want to change your light. She will be able to help you out."

Nu vill vi att programmet ska ge olika respons, beroende på om spelaren svarar 1, 2 eller något annat. Här återanvänder vi if-satsen igen! Den enda skillnaden från tidigare är att vi har lagt till elif. Det betyder att vi har ett extra svarsalternativ. Om man svarar något annat än 1 eller 2 så kommer programmet skriva ut det som står vid else.

Eftersom den mystiska personen blir arg vid alternativ 2, så har vi lagt in sys.exit() som sista funktion, för att avbryta spelet vid det tillfället. ;)


Vad händer efter kapitel 1?

print
print ("On the way out of the bar you notice a poster on the wall.")
print
print (" The poster says:")
print (" Young and old! Big and Small!")
print (" Don't miss the grand opening of the amazing National Gem Museum exhibition - crystals beyond imagination, tomorrow at 8 pm.")
print
print ("This means the job needs to be done tonight..")
print
print ("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
print ("~~~~~~~~~~~~~~~~~~~~~~~End of chapter 1~~~~~~~~~~~~~~~~~~~~~~~~")
print ("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")

Kapitel 1 avslutas med att karaktären lämnar den mystiska personen och funderar över vad nästa steg är för att stjäla juvelen. (Detta gäller inte om spelaren har svarat alternativ 2 i dialogen innan.)


Redo att koda!

Nu har vi gått igenom hela koden för första kapitlet av Night at the Museum! Var det lätt eller svårt att förstå? I nästa tutorial kommer vi att fortsätta på storyn, återanvända vissa av elementen vi gått igenom och introducera nya funktioner!

Elisabet Johansson

Elisabet är en kreativ tös som gärna snackar sci-fi filmer, läser serieböcker och odlar grönsaker. När hon inte jobbar som digital AD/interaktionsdesigner försöker hon hitta nya sätt att kombinera sina intressen med teknik.

Github: elisabettie

Twitter: @elisabettie