Here you will find the source code for the Kitty Hero game, 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