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
