This is an old revision of the document!
Table of Contents
Turtle
Introduction
Python Season 3 needs something interesting, so we will begin by designing a script language we can use for other things. This is an important concept due to it's wide range of applications in fields such as AI and robotics, system design and so forth.
Game.py
We will begin with the Game class. main.py and Window.py are unchanged from a Basic Pygame Program style boilerplate.
import pygame from Turtle import * from TurtleProgram import * class Game: def __init__(self, window): self.window = window self.screen = window.screen self.logo = window.logo self.font = window.font # Game Data self.FPS = 60 self.clock = pygame.time.Clock() self.turtle = Turtle(self.window.width, self.window.height) self.turtle.x = self.window.width//2 self.turtle.y = self.window.height//2 self.d = 0 self.t = TurtleProgram(self.turtle) self.t.load_file("flower.t") for line in self.t.program: print(line) quit() def start(self): while True: self.checkEvents() self.update() self.draw() self.clock.tick(self.FPS) def draw(self): self.screen.fill((0, 0, 0)) # Clear the screen self.turtle.draw(self.screen) pygame.display.flip() def update(self): self.t.run() def checkEvents(self): for event in pygame.event.get(): if event.type == pygame.QUIT: self.quit() return if event.type == pygame.KEYDOWN: # key down event, process keys. if event.key == pygame.K_q: self.quit() def drawText(self, at_x, at_y, text, color): text_surface = self.font.render(text, False, color) x = self.window.fontwidth * at_x y = self.window.fontheight * at_y self.screen.blit(text_surface, (x + 2, y)) def quit(self): quit() exit()
Here drawText() could be removed. The new code revolves around this:
self.turtle = Turtle(self.window.width, self.window.height) self.turtle.x = self.window.width//2 self.turtle.y = self.window.height//2 self.d = 0 self.t = TurtleProgram(self.turtle) self.t.load_file("flower.t") for line in self.t.program: print(line)
First we instantiate the Turtle class and give it our window information so it can create it's Turtle data. We set x and y to be the window height and width – but this can and should be moved into the Turtle constructor.
A second part includes loading an example turtle script from a file – but this could be done in the Game constructor by using self.t.add(“reset”) and so forth.
You can also remove the for loop which just prints out the program to console.
Turtle.py
The gameworld here is the Turtle world, which is built on top of Game.py.
import pygame import math class Turtle: def __init__(self, w, h): # Set width and height self.width = w self.height = h self.color = (255, 255, 255) self.line_width = 1 # Create an image surface self.image = pygame.Surface((w, h)) # Reset to baseline self.reset() def draw(self, screen): screen.blit(self.image, (0, 0))
We begin the constructor by defining the Turtle world and the turtle itself. These two concepts could theoretically be split into two classes. But, we will have them combined for the sake of brevity, for now.
The turtle world is the self.image = pygame.Surface(). This is an image which represents what was drawn by the turtle. Our draw function just blits this to the screen. Therefore the minimum framerate is 1, i.e. we do not need a high framerate as most of the time it will display a static image. This also implies that the turtle does not need to repeatedly draw itself every frame, but this is a change that will be made later in Game.py, and is left as an exercise to the reader (for now).
Turtle Commands
In this next section of the code, we define what the turtle can do. These are the “turtle commands”. Think of them like opcodes on a CPU, with the turtle world itself (self.image) being the “computer system” such as it's memory.
######################################## # Turtle Commands # ######################################## def clear(self): self.image.fill((0,0,0)) def reset(self): self.pen = False self.clear() self.x = self.width//2 self.y = self.height//2 self.d = 0 self.turnLeft(90) def penUp(self): self.pen = False def penDown(self): self.pen = True def turnLeft(self, deg): self.d = self.d - deg if self.d < 0: self.d = self.d % 360 def turnRight(self, deg): self.d = self.d + deg if self.d > 360: self.d = self.d % 360 def forward(self, distance): # Get angle in radians a = math.radians(self.d) # Calculate rise and run rise = distance * math.sin(a) run = distance * math.cos(a) x1 = self.x y1 = self.y x2 = x1 + run y2 = y1 + rise if self.pen: pygame.draw.line(self.image, self.color, (x1, y1), (x2, y2), self.line_width) self.x = x2 self.y = y2
The turtle has a small number of basic commands, as follows:
- reset – This command clears the screen, lifts the pen, and resets the turtle position.
- up – this raises the pen thus turning off drawing during turtle movement.
- down – thus lowers the pen thus turning on drawing during turtle movement.
- go – This moves the turtle forward, drawing a line if the pen is down.
- left – This causes the turtle to turn a number of degrees to the left.
- right – This causes the turtle to turn to the right, similar to the left command.
Thus there are three basic movement commands (go, turn left, turn right), and three system related commands (up, down, reset).
This class clearly and succinctly defines the turtle world and the position and velocity of the turtle.