如何解决Python 游戏太慢
在#sensors 注释下创建代码后,我的游戏变得太慢了(请参阅下面的代码,它的 for 循环中有很多迭代)。我已经控制了一个人来移动红点,但游戏应该是由电脑自己玩的。
我的问题是:
- 我 2015 年的 15" macbook pro 是否太慢(此代码是否适用于另一台计算机)? 或
- Python 语言是否太慢(此代码是否适用于其他语言)? 或
- Python 模块 (turtle) 执行此类任务是否错误? 或
- 我的代码是不是很糟糕(它不适用于任何语言或任何计算机)?
还是别的?
这是我的代码:
import turtle
import math
#Set up screen
wn = turtle.Screen()
wn.bgcolor("lightyellow")
score = 0
#Draw border
mypen = turtle.Turtle()
mypen.penup()
mypen.setposition(-300,-300)
mypen.speed(0)
mypen.pendown()
mypen.pensize(3)
for side in range(4):
mypen.forward(600)
mypen.left(90)
mypen.hideturtle()
#Draw obstacle
myObstacle = turtle.Turtle()
myObstacle.penup()
myObstacle.setposition(-150,-150)
myObstacle.speed(0)
myObstacle.pendown()
myObstacle.pensize(3)
for side in range(4):
myObstacle.forward(300)
myObstacle.left(90)
myObstacle.hideturtle()
#Create player turtle
player = turtle.Turtle()
player.penup()
player.speed(0)
player.setposition(-200,-200)
player.color("red")
player.shape("circle")
#Set speed variable
speed = 1
#define functions
def turnleft():
player.left(30)
def turnright():
player.right(30)
def increasespeed():
global speed
speed += 1
def decreasespeed():
global speed
if speed > 1:
speed -= 1
#Set keyboard bindings
turtle.listen()
turtle.onkey(turnleft,"Left")
turtle.onkey(turnright,"Right")
turtle.onkey(increasespeed,"Up")
turtle.onkey(decreasespeed,"Down")
#bounderies
def merge(list1,list2):
merged_list = [(list1[i],list2[i]) for i in range(0,len(list1))]
return merged_list
bounderies = merge([-300] * 601,list(range(-300,301)))
bounderies.extend(merge([300] * 601,301))))
bounderies.extend(merge(list(range(-300,301)),[-300] * 601))
bounderies.extend(merge(list(range(-300,[300] * 601))
bounderies.extend(merge([-150] * 301,list(range(-150,151))))
bounderies.extend(merge([150] * 301,151))))
bounderies.extend(merge(list(range(-150,151)),[-150] * 301))
bounderies.extend(merge(list(range(-150,[150] * 301))
def scoreset():
global score
score += 1
scorestring = "score: %s" %score
mypen.undo()
mypen.penup()
mypen.setposition(-340,310)
mypen.pendown()
mypen.color("green")
mypen.write(scorestring,False,align = "left",font=("ariel",16,"bold"))
#sensors
def forwarddistance():
forwarddistance = []
minForwdist = 0
tupleCoordinate = (0,0)
yCoordinate = 0
xCoordinate = 0
position = (int(player.xcor()),int(player.ycor()))
heading = player.heading()
sinus = math.sin(math.radians(heading))
cosinus = math.cos(math.radians(heading))
tangent = sinus / cosinus
for alpha in range(1000):
if (heading < 45 and heading >= 0) or (heading < 360 and heading >= 315):
xCoordinate = position[0] + alpha
yCoordinate = xCoordinate * tangent + (position[1] - position[0] * tangent)
tupleCoordinate = (int(xCoordinate),int(yCoordinate))
elif (heading < 315 and heading >= 225):
yCoordinate = position[1] - alpha
xCoordinate = (yCoordinate - (position[1] - position[0] * tangent)) / tangent
tupleCoordinate = (int(xCoordinate),int(yCoordinate))
elif (heading < 225 and heading >= 135):
xCoordinate = position[0] - alpha
yCoordinate = xCoordinate * tangent + (position[1] - position[0] * tangent)
tupleCoordinate = (int(xCoordinate),int(yCoordinate))
elif (heading < 135 and heading >= 45):
yCoordinate = position[1] + alpha
xCoordinate = (yCoordinate - (position[1] - position[0] * tangent)) / tangent
tupleCoordinate = (int(xCoordinate),int(yCoordinate))
if tupleCoordinate in bounderies:
forwarddistance.append(player.distance(tupleCoordinate))
minForwdist = min(forwarddistance)
#print("Forward distance: ",int(minForwdist))
return minForwdist
def leftdistance():
forwarddistance = []
minForwdist = 0
tupleCoordinate = (0,int(player.ycor()))
if player.heading() + 90 >= 360:
heading = player.heading() + 90 - 360
else:
heading = player.heading() + 90
sinus = math.sin(math.radians(heading))
cosinus = math.cos(math.radians(heading))
tangent = sinus / cosinus
for alpha in range(1000):
if (heading < 45 and heading >= 0) or (heading < 360 and heading >= 315):
xCoordinate = position[0] + alpha
yCoordinate = xCoordinate * tangent + (position[1] - position[0] * tangent)
tupleCoordinate = (int(xCoordinate),int(yCoordinate))
if tupleCoordinate in bounderies:
forwarddistance.append(player.distance(tupleCoordinate))
minForwdist = min(forwarddistance)
#print("Left distance: ",int(minForwdist))
return minForwdist
def leftForwarddistance():
forwarddistance = []
minForwdist = 0
tupleCoordinate = (0,int(player.ycor()))
if player.heading() + 45 >= 360:
heading = player.heading() + 45 - 360
else:
heading = player.heading() + 45
sinus = math.sin(math.radians(heading))
cosinus = math.cos(math.radians(heading))
tangent = sinus / cosinus
for alpha in range(1000):
if (heading < 45 and heading >= 0) or (heading < 360 and heading >= 315):
xCoordinate = position[0] + alpha
yCoordinate = xCoordinate * tangent + (position[1] - position[0] * tangent)
tupleCoordinate = (int(xCoordinate),int(yCoordinate))
if tupleCoordinate in bounderies:
forwarddistance.append(player.distance(tupleCoordinate))
minForwdist = min(forwarddistance)
#print("Left-forward distance: ",int(minForwdist))
return minForwdist
def rightdistance():
forwarddistance = []
minForwdist = 0
tupleCoordinate = (0,int(player.ycor()))
if player.heading() < 90:
heading = 360 - (90 - player.heading())
else:
heading = player.heading() - 90
sinus = math.sin(math.radians(heading))
cosinus = math.cos(math.radians(heading))
tangent = sinus / cosinus
for alpha in range(1000):
if (heading < 45 and heading >= 0) or (heading < 360 and heading >= 315):
xCoordinate = position[0] + alpha
yCoordinate = xCoordinate * tangent + (position[1] - position[0] * tangent)
tupleCoordinate = (int(xCoordinate),int(yCoordinate))
if tupleCoordinate in bounderies:
forwarddistance.append(player.distance(tupleCoordinate))
minForwdist = min(forwarddistance)
#print("Right distance: ",int(minForwdist))
return minForwdist
def rightForwarddistance():
forwarddistance = []
minForwdist = 0
tupleCoordinate = (0,int(player.ycor()))
if player.heading() < 45:
heading = 360 - (45 - player.heading())
else:
heading = player.heading() - 45
sinus = math.sin(math.radians(heading))
cosinus = math.cos(math.radians(heading))
tangent = sinus / cosinus
for alpha in range(1000):
if (heading < 45 and heading >= 0) or (heading < 360 and heading >= 315):
xCoordinate = position[0] + alpha
yCoordinate = xCoordinate * tangent + (position[1] - position[0] * tangent)
tupleCoordinate = (int(xCoordinate),int(yCoordinate))
if tupleCoordinate in bounderies:
forwarddistance.append(player.distance(tupleCoordinate))
minForwdist = min(forwarddistance)
#print("Right-forward distance: ",int(minForwdist))
return minForwdist
#finished sensors
while True:
rightForwarddistance()
rightdistance()
leftForwarddistance()
leftdistance()
forwarddistance()
sensors = {'left': leftdistance(),'left forward': leftForwarddistance(),'forward': forwarddistance(),'right forward': rightForwarddistance(),'right': rightdistance()}
changeDirectionTo = max(sensors,key=sensors.get)
player.forward(speed)
#change Direction To
if changeDirectionTo == 'left':
player.left(90)
elif changeDirectionTo == 'left forward':
player.left(45)
elif changeDirectionTo == 'right forward':
player.right(45)
elif changeDirectionTo == 'right':
player.right(90)
#when hitting the boundary
if (int(player.position()[0]),int(player.position()[1])) in bounderies:
scoreset()
if player.xcor() > 300 or player.xcor() < -300:
player.right(30)
if player.ycor() > 300 or player.ycor() < -300:
player.right(30)
if player.position() == myObstacle.position():
player.right(30)
if player.xcor() > -150 and player.xcor() < 150 and player.ycor() > -150 and player.ycor() < 150:
player.right(30)
解决方法
我已经复制并运行了您的代码,让我先回答问题:
- 不,你的电脑没问题。
- 在这种情况下,这应该不是问题。
- 我不这么认为。检查 documentation。
- 我认为它可以改进。
代码进行大量处理的主要位置是 wile True
条件。你调用了 10 个函数:
rightForwardDistance()
rightDistance()
leftForwardDistance()
leftDistance()
forwardDistance()
sensors = {'left': leftDistance(),'left forward': leftForwardDistance(),'forward': forwardDistance(),'right forward': rightForwardDistance(),'right': rightDistance()}
其中每个都有一个范围为 1000 的 for 循环,删除/评论前 5 个将使游戏更快一点。
rightForwardDistance()
rightDistance()
leftForwardDistance()
leftDistance()
forwardDistance()
除此之外,还可以通过不同的方式改进代码,例如:
for alpha in range(1000):
if (heading < 45 and heading >= 0) or (heading < 360 and heading >= 315):
xCoordinate = position[0] + alpha
yCoordinate = xCoordinate * tangent + (position[1] - position[0] * tangent)
tupleCoordinate = (int(xCoordinate),int(yCoordinate))
elif (heading < 315 and heading >= 225):
yCoordinate = position[1] - alpha
xCoordinate = (yCoordinate - (position[1] - position[0] * tangent)) / tangent
tupleCoordinate = (int(xCoordinate),int(yCoordinate))
elif (heading < 225 and heading >= 135):
xCoordinate = position[0] - alpha
yCoordinate = xCoordinate * tangent + (position[1] - position[0] * tangent)
tupleCoordinate = (int(xCoordinate),int(yCoordinate))
elif (heading < 135 and heading >= 45):
yCoordinate = position[1] + alpha
xCoordinate = (yCoordinate - (position[1] - position[0] * tangent)) / tangent
tupleCoordinate = (int(xCoordinate),int(yCoordinate))
if tupleCoordinate in bounderies:
forwardDistance.append(player.distance(tupleCoordinate))
minForwDist = min(forwardDistance)
# print("Left distance: ",int(minForwDist))
该代码重复了 5 次,并且可以移动到一个函数中以避免重复。 代码还有未使用的变量,可以删除。
yCoordinate = 0
xCoordinate = 0
经过这些更改后,代码会更易读,速度也会更快:
import turtle
import math
# Set up screen
wn = turtle.Screen()
wn.bgcolor("lightyellow")
score = 0
# Draw border
mypen = turtle.Turtle()
mypen.penup()
mypen.setposition(-300,-300)
mypen.speed(0)
mypen.pendown()
mypen.pensize(3)
for side in range(4):
mypen.forward(600)
mypen.left(90)
mypen.hideturtle()
# Draw obstacle
myObstacle = turtle.Turtle()
myObstacle.penup()
myObstacle.setposition(-150,-150)
myObstacle.speed(0)
myObstacle.pendown()
myObstacle.pensize(3)
for side in range(4):
myObstacle.forward(300)
myObstacle.left(90)
myObstacle.hideturtle()
# Create player turtle
player = turtle.Turtle()
player.penup()
player.speed(0)
player.setposition(-200,-200)
player.color("red")
player.shape("circle")
# Set speed variable
speed = 1
# define functions
def turnleft():
player.left(30)
def turnright():
player.right(30)
def increasespeed():
global speed
speed += 1
def decreasespeed():
global speed
if speed > 1:
speed -= 1
# Set keyboard bindings
turtle.listen()
turtle.onkey(turnleft,"Left")
turtle.onkey(turnright,"Right")
turtle.onkey(increasespeed,"Up")
turtle.onkey(decreasespeed,"Down")
# bounderies
def merge(list1,list2):
merged_list = [(list1[i],list2[i]) for i in range(0,len(list1))]
return merged_list
bounderies = merge([-300] * 601,list(range(-300,301)))
bounderies.extend(merge([300] * 601,301))))
bounderies.extend(merge(list(range(-300,301)),[-300] * 601))
bounderies.extend(merge(list(range(-300,[300] * 601))
bounderies.extend(merge([-150] * 301,list(range(-150,151))))
bounderies.extend(merge([150] * 301,151))))
bounderies.extend(merge(list(range(-150,151)),[-150] * 301))
bounderies.extend(merge(list(range(-150,[150] * 301))
def scoreset():
global score
score += 1
scorestring = "Score: %s" % score
mypen.undo()
mypen.penup()
mypen.setposition(-340,310)
mypen.pendown()
mypen.color("green")
mypen.write(scorestring,False,align="left",font=("arial",16,"bold"))
# sensors
def forwardDistance():
position = (int(player.xcor()),int(player.ycor()))
heading = player.heading()
sinus = math.sin(math.radians(heading))
cosinus = math.cos(math.radians(heading))
tangent = sinus / cosinus
return doMath(heading,position,tangent)
def leftDistance():
position = (int(player.xcor()),int(player.ycor()))
if player.heading() + 90 >= 360:
heading = player.heading() + 90 - 360
else:
heading = player.heading() + 90
sinus = math.sin(math.radians(heading))
cosinus = math.cos(math.radians(heading))
tangent = sinus / cosinus
return doMath(heading,tangent)
def leftForwardDistance():
position = (int(player.xcor()),int(player.ycor()))
if player.heading() + 45 >= 360:
heading = player.heading() + 45 - 360
else:
heading = player.heading() + 45
sinus = math.sin(math.radians(heading))
cosinus = math.cos(math.radians(heading))
tangent = sinus / cosinus
return doMath(heading,tangent)
def rightDistance():
position = (int(player.xcor()),int(player.ycor()))
if player.heading() < 90:
heading = 360 - (90 - player.heading())
else:
heading = player.heading() - 90
sinus = math.sin(math.radians(heading))
cosinus = math.cos(math.radians(heading))
tangent = sinus / cosinus
return doMath(heading,tangent)
def rightForwardDistance():
position = (int(player.xcor()),int(player.ycor()))
if player.heading() < 45:
heading = 360 - (45 - player.heading())
else:
heading = player.heading() - 45
sinus = math.sin(math.radians(heading))
cosinus = math.cos(math.radians(heading))
tangent = sinus / cosinus
return doMath(heading,tangent)
def doMath(heading,tangent):
forwardDistance = []
minForwDist = 0
tupleCoordinate = (0,0)
for alpha in range(1000):
if (heading < 45 and heading >= 0) or (heading < 360 and heading >= 315):
xCoordinate = position[0] + alpha
yCoordinate = xCoordinate * tangent + (position[1] - position[0] * tangent)
tupleCoordinate = (int(xCoordinate),int(yCoordinate))
elif (heading < 315 and heading >= 225):
yCoordinate = position[1] - alpha
xCoordinate = (yCoordinate - (position[1] - position[0] * tangent)) / tangent
tupleCoordinate = (int(xCoordinate),int(yCoordinate))
elif (heading < 225 and heading >= 135):
xCoordinate = position[0] - alpha
yCoordinate = xCoordinate * tangent + (position[1] - position[0] * tangent)
tupleCoordinate = (int(xCoordinate),int(yCoordinate))
elif (heading < 135 and heading >= 45):
yCoordinate = position[1] + alpha
xCoordinate = (yCoordinate - (position[1] - position[0] * tangent)) / tangent
tupleCoordinate = (int(xCoordinate),int(yCoordinate))
if tupleCoordinate in bounderies:
forwardDistance.append(player.distance(tupleCoordinate))
minForwDist = min(forwardDistance)
return minForwDist
# finished sensors
while True:
sensors = {'left': leftDistance(),'right': rightDistance()}
changeDirectionTo = max(sensors,key=sensors.get)
player.forward(speed)
# change Direction To
if changeDirectionTo == 'left':
player.left(90)
elif changeDirectionTo == 'left forward':
player.left(45)
elif changeDirectionTo == 'right forward':
player.right(45)
elif changeDirectionTo == 'right':
player.right(90)
# when hitting the boundary
if (int(player.position()[0]),int(player.position()[1])) in bounderies:
scoreset()
if player.xcor() > 300 or player.xcor() < -300:
player.right(30)
if player.ycor() > 300 or player.ycor() < -300:
player.right(30)
if player.position() == myObstacle.position():
player.right(30)
if player.xcor() > -150 and player.xcor() < 150 and player.ycor() > -150 and player.ycor() < 150:
player.right(30)
,
你有很多地方,比如:
if something in bounderies: ...
问题是,bounderies
是一个列表,因此查找是一个 O(n) 操作。由于最常见的情况是 something not in bounderies
,因此通常必须检查整个列表以查看您的坐标不在其中。
添加一行:
...
bounderies.extend(merge(list(range(-150,[150] * 301))
bounderies = set(bounderies) # <--
变得超级昂贵 - 而且很频繁! - 从 O(n) 到 O(1) 的查找,并在我的计算机上使整个程序的运行速度提高了大约 18 倍。
您还可以做很多其他事情来加快速度,但这是一个非常简单有效的优化。
,您的代码有几个问题。首先是@KirkStrauser 很好地解决的 bounderies
[原文如此] 设置问题。但是 sensors
的问题比@LucasBelfanti 所暗示的还要严重。您无需做数学(即几何)并找到到目标的距离,而是沿着每个测试每个可能的点em> 指向目标的向量的元素。由于您一次只沿一个向量查看,因此无需修复几何形状,第一个截距应该是您想要的点,这样您就可以脱离传感器并避免接下来的 500 次左右的测试。
如果我们将其与使用 math.tan()
而不是 math.sin()/math.cos()
相结合,并对角度使用模算术,对于您的一个传感器,我们会得到类似的结果:
from math import radians,tan
def rightDistance():
minForwDist = 0
tupleCoordinate = (0,0)
x,y = int(player.xcor()),int(player.ycor())
heading = (player.heading() - 90) % 360
tangent = tan(radians(heading))
for alpha in range(1000):
if 0 <= heading < 45 or 315 <= heading < 360:
xCoordinate = x + alpha
yCoordinate = xCoordinate * tangent + (y - x * tangent)
tupleCoordinate = (int(xCoordinate),int(yCoordinate))
elif 225 <= heading < 315:
yCoordinate = y - alpha
xCoordinate = (yCoordinate - (y - x * tangent)) / tangent
tupleCoordinate = (int(xCoordinate),int(yCoordinate))
elif 135 <= heading < 225:
xCoordinate = x - alpha
yCoordinate = xCoordinate * tangent + (y - x * tangent)
tupleCoordinate = (int(xCoordinate),int(yCoordinate))
elif 45 <= heading < 135:
yCoordinate = y + alpha
xCoordinate = (yCoordinate - (y - x * tangent)) / tangent
tupleCoordinate = (int(xCoordinate),int(yCoordinate))
if tupleCoordinate in boundaries:
return player.distance(tupleCoordinate)
return minForwDist
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。