学习python几天了,做个游戏项目实战一下。
过程中经常出现几个Bug
问题1:
unindent does not match any outer indentation level
对于此错误,最常见的原因是,的确没有缩进。根据错误提示的行数,去代码中看了下,看起来没有什么问题呀,都有缩进,而且语法也没有错误。
最终发现代码报错原因还真是出在这里,错误提示的这行看起来是缩进了,实际上确没有缩进,这就是问题的根源所在。
不要看起来代码缩进了就感觉ok了,实际上是没有缩进的。
问题2:'str' object has no attribute 'Ball'
变量类型错误
问题3:
local variable 'game_ball' referenced before assignment
局部变量与全局变量
判断球与砖块的碰撞的函数的大致想法
def bomb_b(self, brick):
if brick.x - self.w <= self.x <= brick.x + brick.w:
if brick.y-self.h <= self.y <= brick.y + brick.h:
if self.x>brick.x:
if self.x+self.w<brick.x+brick.w:
self.turnx()
elif self.y>brick.y:
if self.y+self.h<brick.y+brick.h:
self.turny()
else:
self.turnx
self.turny
return True
return False
总结:有些问题在学习的时候就被着重指出,但是还是会出现这样那样的问题。希望在以后的项目中不断地提升自己减少这些不必要的错误的出现。
贴上主程序和球类;
import tkinter
import random
import time
import config
import paddle
import image
import Ball
import Brick
#定义砖头
bricks=[]
#定义个球
balls=[]
# 定义hp变量,保存板子对象
hp = ""
#吃糖吗?
#candys=[]
# 定义当前用户的分数
life = 1
score = 0
# 定义游戏状态
game_state = config.GAME_START
# 创建窗体
game_window = tkinter.Tk()
# 窗口文字设置
game_window.title('进击的球球')
# 窗口位置处理
screenwidth = game_window.winfo_screenwidth()
screenheight = game_window.winfo_screenheight()
size = '%dx%d+%d+%d' % (config.GAME_WIDTH, config.GAME_HEIGHT, (screenwidth-config.GAME_WIDTH)/2, 20)
game_window.geometry(size)
# 加载游戏用到的所有的图片
back, ball_image, brick_image, paddle_image= image.load_image(tkinter)
start_image,stop_image = image.load_state_image(tkinter)
# 获取画布
window_canvas = tkinter.Canvas(game_window)
# 画布包装方式
window_canvas.pack(expand=tkinter.YES, fill=tkinter.BOTH)
# 用来协助控制时间
count = 0
def enter_action():# 10ms执行一次
global count
count += 1
if count%80 == 0:
n=random.randint(2,10)
for x in range(1,n):
brick = Brick.Brick(brick_image)# 生成一个敌人
bricks.append(brick)# 敌人添加到列表中
window_canvas.create_image(brick.x,brick.y,anchor = tkinter.NW,image=brick.image,tag=brick.tag)
def step_action():
global count
if count%80 == 0:
for brick in bricks:
brick.step(window_canvas)
for ball in balls:
ball.step(window_canvas)
def call_back_click(event):
global game_state
# 如果游戏状态为启动状态,则修改状态为运行
# 如果游戏状态为结束状态,则修改状态为启动状态
if game_state == config.GAME_START:
game_state = config.GAME_RUNNING
# 画分和命
window_canvas.create_text(10, 10, text="分数:%d" % (score), anchor=tkinter.NW, fill="red", font="time 24 bold",
tag="SCORE")
window_canvas.create_text(10, 50, text="生命:%d" % (life), anchor=tkinter.NW, fill="red", font="time 24 bold",
tag="LIFE")
# 删除启动图片
window_canvas.delete("START")
elif game_state == config.GAME_STOP:
window_canvas.delete("BACK")
window_canvas.delete("HP")
window_canvas.delete("STOP")
game_state = config.GAME_START
game_start()
def out_of_bounds_action():
for ball in balls:
ball.bombout()
ball.bombp(hp)
if ball.bomblose(hp)==True:
game_state=config.GAME_STOP
game_over()
global score
for brick in bricks:
if ball.bomb_b(brick):
score+=1
bricks.remove(brick)
window_canvas.delete(brick.tag)
def game_over():
global game_state
game_state = config.GAME_STOP
for ball in balls:
window_canvas.delete(ball.tag)
for brick in bricks:
window_canvas.delete(brick.tag)
balls.clear()
bricks.clear()
window_canvas.create_image(0,0,anchor=tkinter.NW,image=stop_image,tag="STOP")
def call_back_move(event):
if game_state == config.GAME_RUNNING:
old_x = hp.x
hp.x = event.x - hp.w/2
window_canvas.move("HP", hp.x-old_x,0)
def draw_action():
# 画分和,命
window_canvas.delete("SCORE")
window_canvas.delete("LIFE")
window_canvas.create_text(10,10,text="分数:%d"%(score),anchor=tkinter.NW,fill="red",font="time 24 bold",tag="SCORE")
window_canvas.create_text(10,50,text="生命:%d"%(life),anchor=tkinter.NW,fill="red",font="time 24 bold",tag="LIFE")
def game_start():
global life
global score
life = 1
score = 0
# 画游戏背景
window_canvas.create_image(0, 0, anchor=tkinter.NW, image=back, tag="BACK")
# 把我的板子拿来
global hp
hp = paddle.Paddle(paddle_image)
global ball
ball = Ball.Ball(ball_image)
balls.append(ball)
window_canvas.create_image(ball.x, ball.y, anchor=tkinter.NW, image=ball.image, tag=ball.tag)
window_canvas.create_image(hp.x, hp.y, anchor=tkinter.NW, image=hp.image, tag="HP")
window_canvas.create_image(0, 0, anchor=tkinter.NW, image=start_image, tag="START")
def game():
if game_state == config.GAME_START:
game_start()
window_canvas.bind("<Motion>",call_back_move)
window_canvas.bind("<Button-1>",call_back_click)
while True:
if game_state == config.GAME_RUNNING:
# 入场
enter_action()
# 动起来
step_action()
# 判断游戏能否继续
out_of_bounds_action()
if life >= 0:
# 画分和命
draw_action()
# 更新显示
game_window.update()
# 休眠10ms
time.sleep(0.01)
if __name__ == "__main__":
game()
game_window.mainloop()
import random
import config
import Brick
class Ball:
BAll_count = 0
def __init__(self, image, x=150, y=450):
Ball.BAll_count+=1
self.tag ="Ball_"+str(Ball.BAll_count)
self.x = x
self.y = y
self.image = image
self.w = image.width()
self.h = image.height()
Ball_direction=[-1,-1]
def step(self, canvas):
a=random.randint(0,3)
canvas.move(self.tag, a*Ball.Ball_direction[0], a*Ball.Ball_direction[1])
self.y += a*Ball.Ball_direction[1]
self.x += a*Ball.Ball_direction[0]
def bombout(self):
if self.y < 0:
Ball.Ball_direction[1]=1
if self.x < (0 + self.w):
Ball.Ball_direction[0]=1
if self.x > (config.GAME_WIDTH-self.w):
Ball.Ball_direction[0]=-1
def bomblose(self,hp):
pass
if self.y>hp.y+hp.w:
return True
def bombp(self,hp):
if hp.x - self.w <= self.x <= hp.x + hp.w:
if hp.y-self.h <= self.y <= hp.y + hp.h:
Ball.Ball_direction[1]=-1
def bomb_b(self, brick):
if brick.x - self.w <= self.x <= brick.x + brick.w:
if brick.y-self.h <= self.y <= brick.y + brick.h:
if self.x>brick.x:
if self.x+self.w<brick.x+brick.w:
Ball.Ball_direction[0]*=-1
elif self.y>brick.y:
if self.y+self.h<brick.y+brick.h:
Ball.Ball_direction[1]*=-1
else:
Ball.Ball_direction[0]*=-1
Ball.Ball_direction[1]*=-1
return True
return False