Här kommer en guide för hur man bygger ett spel i turtle och det byggs i repl.it’s miljö. Spelet vi skall bygga är ett spel där din spelare skall fånga bollar för att samla poäng inne i en avgränsad yta. Spelet kommer byggas steg för steg tills vi har ett fungerande spel som går att bygga vidare på.
Det färdiga spelet ser ut så här:

Nu gäller det att bygga spelet steg för steg och följande saker behöver vi bygga upp.
- Fixa till spelplanen
- Skapa en spelare som vi kan styra
- Se till att spelaren håller sig inom spelplanen
- Slumpa poängbollar
- Ta hand om kollision mellan spelare och boll
- Beräkna poäng och skriv ut dessa
Fixa spelplanen
Här vill vi bygga en färgad bakgrund och sedan rita en ram i denna. Ramen skall sedan bli en begränsning så att spelet pågår inne i ramen.
# Nödvändiga importer import turtle window = turtle.Screen() # Namnger vår screen window.bgcolor("light blue") # Bakgrundsfärg på vår spelplan window.tracer(3) # Låter var tredje "bild" visas, risk att det hackar annars # Ritar upp en ram på spelplanen border = turtle.Turtle() # Skapar en turtle border.speed(50) # Ritar upp ytan snabbt border.penup() border.setposition(-300,-300) border.pendown() border.pensize(3) for side in range (4): # Ritar fyra sidor border.forward(600) border.left(90) border.hideturtle() # Skall gömma turtle border men gör inte det just nu. # Tvingar fönstret att vara öppet (inte obligatoriskt på repl.it) turtle.done()
Skapa spelaren
Nu skapar vi spelaren, här har jag testat att ändra på kodraden window.tracer(3) för att se hur fort jag vill att spelaren skall gå. window.tracer() handlar om hur ofta spelet skall ritas ut på skärmen.
# Nödvändiga importer import turtle window = turtle.Screen() # Namnger vår screen window.bgcolor("light blue") # Bakgrundsfärg på vår spelplan window.tracer(1) # Testar att rita ut varje "bild" på skärmen # Ritar upp en ram på spelplanen border = turtle.Turtle() # Skapar en turtle border.speed(50) # Ritar upp ytan snabbt border.penup() border.setposition(-300,-300) border.pendown() border.pensize(3) for side in range (4): # Ritar fyra sidor border.forward(600) border.left(90) border.hideturtle() # Skall gömma turtle border men gör inte det. # Skapa spelaren player = turtle.Turtle() player.color('red') player.shape('turtle') player.penup() # Eftersom vi inte vill rita ett spår #player.speed(10) #defined when keybinding for speed; animation speed, not movement speed, this is fastest speed # Players hastighet, ändrar till window.tracer(1) för att inte minhastigheten skall bli för snabb. speed = 1 # Funktioner för att svänga vår turtle def turnLeft(): player.left(30) # 30 grader vänster def turnRight(): player.right(30) # 30 grader höger #Keyboard binding window.onkey(turnLeft, "Left") window.onkey(turnRight, "Right") window.listen() # Make player move while True: player.forward(speed) # Hastigheten bestämmer hur fort vår player går # Tvingar fönstret att vara öppet (inte obligatoriskt på repl.it) turtle.done()
Håll spelaren innanför spelplanen
Nu skall vi bygga en funktion, checkBoundary() för att kontrollera att player inte hamnar utanför spelplanen. Vi bygger denna funktion så att den kan påverka vilken turtle som helst, både en spelare men också de bollar som vi skall skapa senare. Studsen är 180grader vilket innebär att alla turtles kommer studsa tillbaka precis på det sätt som de kom ifrån. Det ser inte så verkligt ut men vi kör på det sättet först.
# Nödvändiga importer import turtle window = turtle.Screen() # Namnger vår screen window.bgcolor("light blue") # Bakgrundsfärg på vår spelplan window.tracer(1) # Låter var tredje "bild" visas, risk att det hackar annars # Ritar upp en ram på spelplanen border = turtle.Turtle() # Skapar en turtle border.speed(50) # Ritar upp ytan snabbt border.penup() border.setposition(-300,-300) border.pendown() border.pensize(3) for side in range (4): # Ritar fyra sidor border.forward(600) border.left(90) border.hideturtle() # Gömmer turtle # Skapa spelaren player = turtle.Turtle() player.color('red') player.shape('turtle') player.penup() # Eftersom vi inte vill rita ett spår #player.speed(10) #defined when keybinding for speed; animation speed, not movement speed, this is fastest speed # Players hastighet, ändrar till window.tracer(1) för att inte minhastigheten skall bli för snabb. speed = 1 # Funktioner för att svänga vår turtle def turnLeft(): player.left(30) # 30 grader vänster def turnRight(): player.right(30) # 30 grader höger # Funktion för att studsa mot kanten def checkBoundary(turtle): if turtle.xcor() > 290 or turtle.xcor() < -290: turtle.right(180) if turtle.ycor() > 290 or turtle.ycor() < -290: turtle.right(180) #Keyboard binding window.onkey(turnLeft, "Left") window.onkey(turnRight, "Right") window.listen() # Make player move while True: player.forward(speed) # Hastigheten bestämmer hur fort vår player går # Kolla så att vi inte hamnar utanför spelplanen checkBoundary(player) # Tvingar fönstret att vara öppet (inte obligatoriskt på repl.it) turtle.done()
Slumpa poängbollar
Bollarna skapas och rör sig. Vi använder också funktionen checkBoundary() för att kolla att bollarna inte hamnar utanför spelplanen och att de studsar på rätt sätt.
# Nödvändiga importer import turtle import random window = turtle.Screen() # Namnger vår screen window.bgcolor("light blue") # Bakgrundsfärg på vår spelplan window.tracer(3) # Låter var tredje "bild" visas, risk att det hackar annars # Ritar upp en ram på spelplanen border = turtle.Turtle() # Skapar en turtle border.speed(50) # Ritar upp ytan snabbt border.penup() border.setposition(-300,-300) border.pendown() border.pensize(3) for side in range (4): # Ritar fyra sidor border.forward(600) border.left(90) border.hideturtle() # Gömmer turtle border # Skapa spelaren player = turtle.Turtle() player.color('red') player.shape('turtle') player.penup() # Eftersom vi inte vill rita ett spår #player.speed(10) #defined when keybinding for speed; animation speed, not movement speed, this is fastest speed # Players hastighet, ändrar till window.tracer(1) för att inte minhastigheten skall bli för snabb. speed = 1 # skapar bollar maxBalls = 5 balls = [] # Bygger upp listan med alla bollar. for b in range(maxBalls): balls.append(turtle.Turtle()) # Skapar en ny boll balls[b].color('yellow') # Ger bollen en färg balls[b].shape('circle') # Ger bollen ett utseende balls[b].speed(0) # Ger bollen en hastighet balls[b].penup() # Lyfter pennan balls[b].right(random.randint(0,360)) # Ger bollen en slumpad riktning balls[b].setposition(random.randint(-300,300), random.randint(-300,300)) # Ger bollen en slumpad position # Funktioner för att svänga vår turtle def turnLeft(): player.left(30) # 30 grader vänster def turnRight(): player.right(30) # 30 grader höger # Funktion för att studsa mot kanten, # studsar tillbaka på precis samma sätt, hur ändrar vi det? def checkBoundary(turtle): if turtle.xcor() > 290 or turtle.xcor() < -290: turtle.right(180) if turtle.ycor() > 290 or turtle.ycor() < -290: turtle.right(180) #Keyboard binding window.onkey(turnLeft, "Left") window.onkey(turnRight, "Right") window.listen() # Make player move while True: player.forward(speed) # Hastigheten bestämmer hur fort vår player går # Kolla så att vi inte hamnar utanför spelplanen checkBoundary(player) # Loopa igenom alla bollarna for b in range(maxBalls): balls[b].forward(3) # Flytta bollen 3 pixlar framåt checkBoundary(balls[b]) # Kolla om bollen studsar # Tvingar fönstret att vara öppet (inte obligatoriskt på repl.it) turtle.done()
Här finns en tydlig bugg och det är att en boll som skapas på kanten blir kvar i en oändlig turn-around eftersom den bara byter riktning men inte hinner flyttas så långt som behövs för att den skall “hinna” ifrån kanten innan nästa riktningsförändring skall göras. Här kan vi se till att bollar inte kan skapas så nära kanten.
Kollision mellan spelare och poängbollar
Jag skapar en funktion för att kolla om två turtels kolliderar. Det görs med avståndsformeln, som kollar hur långt det är mellan två turtels och om de är tillräckligt nära så anses de kollidera, och vid kollision så får bollen en ny position och en ny riktning. Alternativet är att ta bort bollen och skapa en ny, men nu låter jag samma boll få en ny position istället.
# Nödvändiga importer import turtle import random import math window = turtle.Screen() # Namnger vår screen window.bgcolor("light blue") # Bakgrundsfärg på vår spelplan window.tracer(3) # Låter var tredje "bild" visas, risk att det hackar annars # Ritar upp en ram på spelplanen border = turtle.Turtle() # Skapar en turtle border.speed(50) # Ritar upp ytan snabbt border.penup() border.setposition(-300,-300) border.pendown() border.pensize(3) for side in range (4): # Ritar fyra sidor border.forward(600) border.left(90) border.hideturtle() # Gömmer turtle när ramen är färdigritad. # Skapa spelaren player = turtle.Turtle() player.color('red') player.shape('turtle') player.penup() # Eftersom vi inte vill rita ett spår #player.speed(10) #defined when keybinding for speed; animation speed, not movement speed, this is fastest speed # Players hastighet, ändrar till window.tracer(1) för att inte minhastigheten skall bli för snabb. speed = 1 # skapar bollar maxBalls = 5 balls = [] # Bygger upp listan med alla bollar. for b in range(maxBalls): balls.append(turtle.Turtle()) # Skapar en ny boll balls[b].color('yellow') # Ger bollen en färg balls[b].shape('circle') # Ger bollen ett utseende balls[b].speed(0) # Ger bollen en hastighet balls[b].penup() # Lyfter pennan balls[b].right(random.randint(0,360)) # Ger bollen en slumpad riktning balls[b].setposition(random.randint(-300,300), random.randint(-300,300)) # Ger bollen en slumpad position # Funktioner för att svänga vår turtle def turnLeft(): player.left(30) # 30 grader vänster def turnRight(): player.right(30) # 30 grader höger # Funktion för att studsa mot kanten, # studsar tillbaka på precis samma sätt, hur ändrar vi det? def checkBoundary(turtle): if turtle.xcor() > 290 or turtle.xcor() < -290: turtle.right(180) if turtle.ycor() > 290 or turtle.ycor() < -290: turtle.right(180) # Funktion som kollar om player krockar med bollen def isCollision(turtle1, turtle2): d = math.sqrt(math.pow(turtle1.xcor() - turtle2.xcor(),2) + math.pow(turtle1.ycor() - turtle2.ycor(),2)) # Avståndsformeln if d < 20: # Om avståndet mellan player och boll är mindre än 20px så anser vi att de har kolliderat. return True # Returnerar True, kollision har inträffat else: return False # Returnerar False, ingen kollision #Keyboard binding window.onkey(turnLeft, "Left") window.onkey(turnRight, "Right") window.listen() # Make player move while True: player.forward(speed) # Hastigheten bestämmer hur fort vår player går # Kolla så att vi inte hamnar utanför spelplanen checkBoundary(player) # Loopa igenom alla bollarna for b in range(maxBalls): balls[b].forward(3) # Flytta bollen 3 pixlar framåt checkBoundary(balls[b]) # Kolla om bollen studsar # Tar hand om en kollision if(isCollision(player, balls[b])): balls[b].setposition(random.randint(-300,300), random.randint(-300,300)) # Ger bollen en ny position (tar alltså inte bort den) balls[b].right(random.randint(0,360)) # Ger bollen en ny riktning # Tvingar fönstret att vara öppet (inte obligatoriskt på repl.it) turtle.done()
Nu upptäcker vi ett problem med att spelarens fart är konstant, och ganska så långsam, vilket gör att vi får planera hur vi skall nå bollarna då vi inte kan jaga ikapp dem. Detta kan du gärna ändra om du vill, men vi behöver nog också se över hur vi skall kunna öka och minska farten på spelaren lite senare.
Räkna poäng och skriv ut dessa
Nu skall vi skapa en poängberäkning och även se till att denna skrivs ut i spelet. Tänk på att vi inte kan använda svenska tecken, å/ä/ö, när vi skriver ut i repl.it.
# Nödvändiga importer import turtle import random import math window = turtle.Screen() # Namnger vår screen window.bgcolor("light blue") # Bakgrundsfärg på vår spelplan window.tracer(3) # Låter var tredje "bild" visas, risk att det hackar annars # Ritar upp en ram på spelplanen border = turtle.Turtle() # Skapar en turtle border.speed(50) # Ritar upp ytan snabbt border.penup() border.setposition(-300,-300) border.pendown() border.pensize(3) for side in range (4): # Ritar fyra sidor border.forward(600) border.left(90) border.hideturtle() # Gömmer turtle när ramen är färdigritad. # Skapa spelaren player = turtle.Turtle() player.color('red') player.shape('turtle') player.penup() # Eftersom vi inte vill rita ett spår #player.speed(10) #defined when keybinding for speed; animation speed, not movement speed, this is fastest speed # Players hastighet, ändrar till window.tracer(1) för att inte minhastigheten skall bli för snabb. speed = 1 # En variabel som lagrar poängen score = 0 # Vi behöver skapa en turtle för att skriva ut poängen penna = turtle.Turtle() penna.hideturtle() penna.penup() penna.setundobuffer(1000) # Behövs för att inte texterna skall skrivas på varandra. # skapar bollar maxBalls = 5 balls = [] # Bygger upp listan med alla bollar. for b in range(maxBalls): balls.append(turtle.Turtle()) # Skapar en ny boll balls[b].color('yellow') # Ger bollen en färg balls[b].shape('circle') # Ger bollen ett utseende balls[b].speed(0) # Ger bollen en hastighet balls[b].penup() # Lyfter pennan balls[b].right(random.randint(0,360)) # Ger bollen en slumpad riktning balls[b].setposition(random.randint(-300,300), random.randint(-300,300)) # Ger bollen en slumpad position # Funktioner för att svänga vår turtle def turnLeft(): player.left(30) # 30 grader vänster def turnRight(): player.right(30) # 30 grader höger # Funktion för att studsa mot kanten, # studsar tillbaka på precis samma sätt, hur ändrar vi det? def checkBoundary(turtle): if turtle.xcor() > 290 or turtle.xcor() < -290: turtle.right(180) if turtle.ycor() > 290 or turtle.ycor() < -290: turtle.right(180) # Funktion som kollar om player krockar med bollen def isCollision(turtle1, turtle2): d = math.sqrt(math.pow(turtle1.xcor() - turtle2.xcor(),2) + math.pow(turtle1.ycor() - turtle2.ycor(),2)) # Avståndsformeln if d < 20: # Om avståndet mellan player och boll är mindre än 20px så anser vi att de har kolliderat. return True # Returnerar True, kollision har inträffat else: return False # Returnerar False, ingen kollision #Keyboard binding window.onkey(turnLeft, "Left") window.onkey(turnRight, "Right") window.listen() # Make player move while True: player.forward(speed) # Hastigheten bestämmer hur fort vår player går # Kolla så att vi inte hamnar utanför spelplanen checkBoundary(player) # Loopa igenom alla bollarna for b in range(maxBalls): balls[b].forward(3) # Flytta bollen 3 pixlar framåt checkBoundary(balls[b]) # Kolla om bollen studsar # Tar hand om en kollision if(isCollision(player, balls[b])): balls[b].setposition(random.randint(-300,300), random.randint(-300,300)) # Ger bollen en ny position (tar alltså inte bort den) balls[b].right(random.randint(0,360)) # Ger bollen en ny riktning # Har vi kolliderat så skall vi få poäng score = score + 1 # Hanterar utskriften av poängen penna.undo() # Tar bort tidigare text penna.setposition(-290,310) utskrift = "Poang: {}".format(score) penna.write(utskrift, False, align="left", font = ("Arial", 14, "normal")) # Tvingar fönstret att vara öppet (inte obligatoriskt på repl.it) turtle.done()
Nu kommer poängen skrivas ut så fort vi får vår första poäng. Här skulle vi behöva skriva ut poängen även när spelet startar. Då behöver vi göra det utanför while-loopen för annars kommer det skrivas ut så många gånger att spelet inte hänger med och spelet börjar lagga. Eftersom vi skriver ut samma sak från två olika ställen i programmet så kan det vara värt att skapa en funktion som anropas när vi behöver skriva ut poängen. Vi kommer också bara skriva ut poängen när det har uppdaterats. Vi skall undvika att göra onödiga saker tar extra kraft för programmet.
Buggar & features
Nu har vi ett fungerande spel om än något buggigt och med behov av att förbättras. Här nedan listar jag några punkter som du kan jobba vidare med.
- Bollar som skapas på kanten och fastnar där.
- Studsen som borde vara mer verklighetstrogen och inte bara studsa tillbaka i exakt motsatt riktning som den kom ifrån. Går det att använda turtle.towards() eller turtle.heading() för att läsa ut infallsvinkel och sedan beräkna en reflektionsvinkel, se bild nedan.
- Spelaren har en konstant och låg fart för tillfället. Ett alternativ är att höja farten, det är ganska lätt gjort, eller så får vi skapa en möjlighet att öka, och minska, farten med tangenter. Detta kan göras på flera olika sätt men det kan också vara bra att sätta en begränsning så att farten inte kan bli hur hög som helst, då finns det risk att vi skapar andra buggar som behöver tas om hand.
