Here you will find the source code for the pirate animation, as described in the upcoming book Graphic Guide to Python
Copyright 2018 Antony Lees
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
def setup(): size(600, 1000, P3D) # game board global standard_tile standard_tile = "standard" global hole_tile hole_tile = "hole" global hole_hit_tile hole_hit_tile = "hit" global target_tile target_tile = "target" global number_of_columns number_of_columns = 5 global tiles tiles = [] global tile_size tile_size = width/number_of_columns/2 global number_of_rows number_of_rows = (height/tile_size) * 2 global x_offset x_offset = (width-tile_size * number_of_columns)/2 grace_period = 1 # initialise tiles for i in range(number_of_rows): # set y coordinates (-y so scrolls downwards) y = -i * tile_size for j in range(number_of_columns): # set x coordinate x = j * tile_size + x_offset if i > grace_period: tile_type = random_tile_type() tile = Tile(x, y, tile_type) tiles.append(tile) #cat global cat_size cat_size = tile_size global cat cat = Cat(cat_size) # initial position cat.x = width/2 cat.y = height/2 # display global score score = 0 global lives lives = 3 # speed global lowest_speed lowest_speed = 5 global highest_speed highest_speed = 20 global speed speed = lowest_speed def draw(): background(0) lights() global score fill(255) textSize(tile_size/2.5) text("Score: {}".format(score), 10, tile_size/2) global lives text("Lives: {}".format(lives), width-(tile_size*1.5), tile_size/2) # set speed but keep within limits speed = constrain(score/2, lowest_speed, highest_speed) pushMatrix() rotateX(radians(50)) cat.draw_cat() for tile in tiles: if lives >= 1: tile.y = tile.y + speed tile.draw_tile() # check each tile for hits if tile.target_hit(cat.x, cat.y): score += 1 if tile.hole_hit(cat.x, cat.y): lives -=1 popMatrix() recycle_tiles() # recycle tiles off the screen def recycle_tiles(): # get y coord of last tile y = 0 global tiles for tile in tiles: if tile.y < y: y = tile.y # moves tiles to the end (x coord can stay the same) new_y = y - tile_size for tile in tiles: # if off the screen if tile.y > height: tile.y = new_y tile.type = random_tile_type() # generate a random type of tile def random_tile_type(): tile_type = standard_tile # randomised tile chances if random(0, 5) > 4: tile_type = hole_tile if random(0, 50) > 45: tile_type = target_tile return tile_type class Cat: def __init__(self, cat_size): self.x = 0 self.y = 0 self.cat_colour = color(255, 200, 0) self.cat_size = cat_size self.tail_length = cat_size/4 self.tail_thickness = cat_size/7 self.tail = [] # initialise tail parts using 2 dimensional list for i in range (self.tail_length): self.tail.append([0, 0]) def draw_cat(self): # draw body in separate matrix so can rotate pushMatrix() noStroke() translate(self.x, self.y) rotateX(frameCount/20.0) # roll sphereDetail(7) fill(self.cat_colour) sphere(cat_size * 0.4) popMatrix() pushMatrix() noStroke() # draw head translate(self.x, self.y - (cat_size/2)) sphereDetail(8) sphere(self.cat_size * 0.2) # draw ears # left pushMatrix() #fill(0, 0, 255) translate(-cat_size*0.1, -cat_size*0.05, cat_size*0.15) rotateY(0.5) rotateX(4) sphereDetail(1) sphere(cat_size*0.1) popMatrix() # right pushMatrix() translate(cat_size*0.1, -cat_size*0.05, cat_size*0.15) rotateY(3) rotateX(2) sphereDetail(1) sphere(cat_size*0.1) popMatrix() #triangle(-size*0.1, -size*0.05, -size*0.05, -size*0.2, -size*0.25, -size*0.3) #triangle(size*0.1, -size*0.05, size*0.05, -size*0.20, size*0.25, -size*0.3) # draw tail sphereDetail(8) # tail end self.tail[self.tail_length-1][0] = (sin(frameCount * 0.2) * 10) self.tail[self.tail_length-1][1] = cat_size/2 # rest of tail for i in range(self.tail_length-1): self.tail[i][0] = self.tail[i+1][0] self.tail[i][1] = self.tail[i+1][1] + (self.tail_thickness/2) pushMatrix() #ellipse(tail[i].x, tail[i].y, tailThickness, tailThickness) translate(self.tail[i][0], self.tail[i][1]) sphere(self.tail_thickness) popMatrix() popMatrix() # class for tiles class Tile: global standard_tile_colour standard_tile_colour = color(255) # white global hole_tile_colour hole_tile_colour = color(0) # black global hole_hit_tile_colour hole_hit_tile_colour = color(255, 0, 0) #red global target_tile_colour target_tile_colour = color(255, 255, 0) # yellow def __init__(self, x, y, type): self.x = x self.y = y self.type = type def draw_tile(self): stroke(0) if self.type == standard_tile: tile_colour = fill(standard_tile_colour) elif self.type == hole_tile: tile_colour = fill(hole_tile_colour) elif self.type == hole_hit_tile: tile_colour = fill(hole_hit_tile_colour) elif self.type == target_tile: tile_colour = fill(target_tile_colour) square(self.x, self.y, tile_size) def target_hit(self, cat_x, cat_y): target_hit = self.hit(cat_x, cat_y) and self.type == target_tile if target_hit: self.type = standard_tile return target_hit def hole_hit(self, cat_x, cat_y): hole_hit = self.hit(cat_x, cat_y) and self.type == hole_tile if hole_hit: self.type = hole_hit_tile return hole_hit # check if we hit a tile def hit(self, cat_x, cat_y): hit = cat_y >= self.y and cat_y <= self.y + tile_size and cat_x >= self.x and cat_x <= self.x + tile_size return hit def mouseMoved(): cat.x = mouseX cat.y = mouseY def setup(): # set the size of the window size(600, 400) global ships ships = [] for i in range(10): ships.append(PirateShip()) # waves global wave_max_height wave_max_height = 20 global wave_min_height wave_min_height = 5 global wave_height wave_height = wave_max_height global up up = 1 global down down = -1 global wave_direction wave_direction = up def draw(): # light blue background background(102, 205, 170) # waves global wave_max_height global wave_min_height global wave_height global wave_direction noFill() # determine of the vwaes should be going up or down if wave_height <= wave_min_height: wave_direction = up if wave_height >= wave_max_height: wave_direction = down # change the wave height for next time wave_height += wave_direction # wave y coordinate wave_y = wave_max_height//2 # while the y coordinate is less than the height of the window while wave_y <= height: # wave x coordinate wave_x = 0 # while the x coordinate is less than the width of the window while wave_x <= width: # draw a semi=circle arc arc(wave_x, wave_y, wave_max_height, wave_height, 0, PI) # increase the x coordinate by 20 wave_x += wave_max_height # increase the y coordinate by 20 wave_y += wave_max_height global ships for ship in ships: ship.display() ship.move() class PirateShip: # pirate ship variables x_position = 0 y_position = 0 ship_length = 0 sails = 0 sail_colour = 0 porthole_count = 0 sail_spacing = 0 speed = 0 def __init__(self): # initialise the ship self.initialise() def initialise(self): # initialise the ship at a random-ish location self.x_position = random(600, 700) self.y_position = random(50, 350) self.ship_length = random(40, 100) # speed self.speed = self.ship_length//20 # sails self.sails = int(min((self.ship_length//30), 3)) self.sail_colour = color(random(255), random(255), random(255)) self.sail_spacing = floor(self.ship_length / 3) # portholes self.porthole_count = int(self.ship_length//12) def display(self): # calculate ship coordinates front_of_ship_x_position = self.x_position - (self.ship_length / 2) back_of_ship_x_position = self.x_position + self.ship_length + (self.ship_length / 3) # ship hull # brown lines and fill stroke(139, 71, 38) fill(139, 71, 38) # middle rectangle rect(self.x_position, self.y_position, self.ship_length, 20) # front and back triangle(front_of_ship_x_position, self.y_position, self.x_position, self.y_position, self.x_position, self.y_position + 20) triangle(self.x_position + self.ship_length, self.y_position, back_of_ship_x_position, self.y_position, self.x_position + self.ship_length, self.y_position + 20) # draw the sails initial_sail_x_position = self.x_position + 15 # black lines stroke(0) for i in range(self.sails): # sail fill(self.sail_colour) quad(initial_sail_x_position + (self.sail_spacing * i), self.y_position - 40, initial_sail_x_position + (self.sail_spacing * i) + 10, self.y_position - 40, initial_sail_x_position + (self.sail_spacing * i) + 20, self.y_position - 10, initial_sail_x_position + (self.sail_spacing * i), self.y_position - 10) # mast fill(0) line(initial_sail_x_position + (self.sail_spacing * i), self.y_position - 10, initial_sail_x_position + (self.sail_spacing * i), self.y_position) line(initial_sail_x_position + (self.sail_spacing * i), self.y_position - 40, initial_sail_x_position + (self.sail_spacing * i), self.y_position - 50) # flag fill(0) rect(initial_sail_x_position + (self.sail_spacing * i), self.y_position - 50, 10, 5) # jolly roger stroke(255) line(initial_sail_x_position + (self.sail_spacing * i) + 2, self.y_position - 49, initial_sail_x_position + (self.sail_spacing * i) + 8, self.y_position - 46) line(initial_sail_x_position + (self.sail_spacing * i) + 8, self.y_position - 49, initial_sail_x_position + (self.sail_spacing * i) + 2, self.y_position - 46) stroke(0) # draw the portholes for i in range(self.porthole_count): # portholes fill(0) circle(self.x_position+(15*i),self.y_position+10,5) # ship has left the screen if back_of_ship_x_position <= 0: # start again self.initialise() def move(self): self.x_position -= self.speed