从<趣学Python编程>上看到的例子,小人在石头上跑跳直到达到门
我做了以下改进:
1. 模块化:
素材:
门d_1.gif
跑动的小人
man_l_1
man_l_2
man_l_3
man_r_1
man_r_2
man_r_3
模块化代码:
helper.py
#Object
class Sprite:
def __init__(self, game):
self.game = game
self.endGame = False
self.co = None
def move(self):
pass
def coords(self):
return self.co
class Coords:
def __init__(self, x1 = 0, y1 = 0, x2 = 0, y2 = 0):
self.x1 = x1
self.x2 = x2
self.y1 = y1
self.y2 = y2
#intersection
def inter_x(co1, co2):
if (co1.x1 >= co2.x2) or (co1.x2 <= co2.x1):
return False
else:
return True
def inter_y(co1, co2):
if (co1.y1 >= co2.y2) or (co1.y2 <= co2.y1):
return False
else:
return True
def collide_left(co1, co2):
if inter_y(co1,co2) and co1.x1 <= co2.x2 and co1.x1 >= co2.x1:
return True
return False
def collide_right(co1, co2):
if inter_y(co1,co2) and co1.x2 <= co2.x2 and co1.x2 >= co2.x1:
return True
return False
def collide_top(co1, co2):
if inter_x(co1,co2) and co1.y1 <= co2.y2 and co1.y1 >= co2.y1:
return True
return False
def collide_bottom(y, co1, co2):
y = co1.y2 + y
if inter_x(co1,co2) and y <= co2.y2 and y >= co2.y1:
return True
return False
from helper import *
class Stone(Sprite):
def __init__(self, game, x, y, w, h):
Sprite.__init__(self, game);#call father
self.image = game.canvas.create_rectangle(x, y, x + w, y + h, fill='pink')
self.co = Coords(x, y, x + w, y + h)
from helper import *
from tkinter import *
class Door(Sprite):
def __init__(self, game, x, y):
Sprite.__init__(self, game);#call father
self.photo_image = PhotoImage(file = 'd_1.gif');
self.image = game.canvas.create_image(x, y, image = self.photo_image, anchor = 'nw')
self.co = Coords(x, y, x + 27, y + 30)
self.endGame = True
from helper import *
import time
from tkinter import *
class Man(Sprite):
def __init__(self, game):
Sprite.__init__(self, game);#call father
self.image_l = [
PhotoImage(file="man_l_1.gif"),
PhotoImage(file="man_l_2.gif"),
PhotoImage(file="man_l_3.gif")
]
self.image_r = [
PhotoImage(file="man_r_1.gif"),
PhotoImage(file="man_r_2.gif"),
PhotoImage(file="man_r_3.gif")
]
self.image = game.canvas.create_image(0, 0, image=self.image_l[0], anchor='nw')
self.x = -2
self.y = 0
self.current_img = 0#image index
self.current_img_add = 1
self.jump_count = 0#use for jump
self.last_time = time.time()
self.co = Coords()
game.canvas.bind_all("", self.turn_left)
game.canvas.bind_all("", self.turn_right)
game.canvas.bind_all("", self.jump)
def turn_left(self, evt):
#if self.y == 0:
self.x = -2
def turn_right(self, evt):
#if self.y == 0:
self.x = 2
def jump(self, evt):
if self.y == 0:
self.y = -4
self.jump_count = 0
#important change img of Man
def animate(self):
if self.x != 0 and self.y == 0:
if time.time() - self.last_time > 0.1: #change img slowly
self.last_time = time.time()
self.current_img += self.current_img_add
if self.current_img >= 2:
self.current_img_add = -1
elif self.current_img <= 0:
self.current_img_add = 1
if self.x < 0:
if self.y != 0:
self.game.canvas.itemconfig(self.image, \
image = self.image_l[2])
else:
self.game.canvas.itemconfig(self.image, \
image = self.image_l[self.current_img])
if self.x > 0:
if self.y != 0:
self.game.canvas.itemconfig(self.image, \
image = self.image_r[2])
else:
self.game.canvas.itemconfig(self.image, \
image = self.image_r[self.current_img])
def coords(self):
xy = self.game.canvas.coords(self.image)
self.co.x1 = xy[0]
self.co.y1 = xy[1]
self.co.x2 = xy[0] + 27
self.co.y2 = xy[1] + 30
return self.co
#important
def move(self):
self.animate()
#for jump case, update y
if self.y < 0:
self.jump_count = self.jump_count + 1
if self.jump_count > 20:
self.y = 4
elif self.y > 0:
self.jump_count = self.jump_count - 1
#collision check
co = self.coords()
left = True
right = True
top = True
btm = True
falling = True
#1.collide with canvas
if self.y > 0 and co.y2 >= self.game.canvas_h:
self.y = 0
btm = False
elif self.y < 0 and co.y2 <= 0:
self.y = 0
top = False
if self.x > 0 and co.x2 >= self.game.canvas_w:
self.x = 0
right = False
elif self.x < 0 and co.x2 <= 0:
self.x = 0
left = False
#2.collide with stone
for s in self.game.sprites:
if s == self:
continue
s_co = s.coords()
if top and self.y < 0 and collide_top(co, s_co):#collide top
self.y = - self.y
top = False
if btm and self.y > 0 and collide_bottom(self.y, co, s_co):#collide btm
#self.y = s_co.y1 - co.y2
#if self.y < 0:
self.y = 0
btm = False
top = False
if btm and falling and self.y == 0 \
and (co.y2 >= self.game.canvas_h \
or collide_bottom(1, co, s_co)): #man stand on the stone
falling = False
if left and self.x < 0 and collide_left(co, s_co):#collide left
self.x = 0
left = False
if s.endGame:#if s is door
self.game.running = False
if right and self.x > 0 and collide_right(co, s_co):#collide right
self.x = 0
right = False
if s.endGame:#if s is door
self.game.running = False
print ("btm is %s" % btm);
#let the man fall
if falling and btm and self.y == 0\
and co.y2 < self.game.canvas_h:
self.y = 4
self.game.canvas.move(self.image, self.x, self.y)
from tkinter import *
import random
from stone import *
from man import *
from door import *
#Game controller
class Game:
def __init__(self):
self.tk = Tk()
self.tk.title("Run away from gost house")
self.tk.resizable(0,0)
self.tk.wm_attributes("-topmost", 1)
self.canvas = Canvas(self.tk, width = 500, height = 500, highlightthickness=0)
self.canvas.pack()
self.tk.update()
self.canvas_h = 500
self.canvas_w = 500
self.bg = PhotoImage(file="bg.gif")
w = self.bg.width()
h = self.bg.height()
for x in range(0,5):
for y in range(0,5):
self.canvas.create_image( x * w, y * h, image=self.bg, anchor='nw')
self.sprites = []
self.running = True
def loop(self):
while 1:
if self.running:
for sprite in self.sprites:
sprite.move()
self.tk.update_idletasks()
self.tk.update()
time.sleep(0.01)
g = Game()
for i in range(60, 500, 30):
x = random.randint(0, 450)
y = random.randint(-5, 5)
width = random.randint(40, 100)
g.sprites.append(Stone(g, x, i + y, width, 10))
#door
door = Door(g, 50, 300)
g.sprites.append(door)
lastStone = Stone(g, 50, 300, 60, 10)
g.sprites.append(lastStone)
m = Man(g)
g.sprites.append(m)
g.loop()