[英]Python Game Too Slow
My game became too slow after I created code under #sensors comments (see code below, it has a lot of iterations in its for-loops).在#sensors 注释下创建代码后,我的游戏变得太慢了(参见下面的代码,它的 for 循环中有很多迭代)。 I have made controls for a human to move the red dot, but the game is supposed to be played by itself, by computer.
我已经为人类制作了移动红点的控件,但游戏应该由计算机自己玩。
My question is:我的问题是:
or something else?或者是其他东西?
This is my code:这是我的代码:
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, list(range(-300,301))))
bounderies.extend(merge(list(range(-300,301)), [-300] * 601))
bounderies.extend(merge(list(range(-300,301)), [300] * 601))
bounderies.extend(merge([-150] * 301, list(range(-150,151))))
bounderies.extend(merge([150] * 301, list(range(-150,151))))
bounderies.extend(merge(list(range(-150,151)), [-150] * 301))
bounderies.extend(merge(list(range(-150,151)), [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,0)
yCoordinate = 0
xCoordinate = 0
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
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))
return minForwDist
def leftForwardDistance():
forwardDistance = []
minForwDist = 0
tupleCoordinate = (0,0)
yCoordinate = 0
xCoordinate = 0
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
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-forward distance: ", int(minForwDist))
return minForwDist
def rightDistance():
forwardDistance = []
minForwDist = 0
tupleCoordinate = (0,0)
yCoordinate = 0
xCoordinate = 0
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
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("Right distance: ", int(minForwDist))
return minForwDist
def rightForwardDistance():
forwardDistance = []
minForwDist = 0
tupleCoordinate = (0,0)
yCoordinate = 0
xCoordinate = 0
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
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("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)
I have copied and ran your code and let me first answer the questions:我已经复制并运行了您的代码,让我先回答问题:
The main place where the code is making a lot of processing is in the wile True
condition.代码进行大量处理的主要地方是
wile True
条件。 There you call 10 functions:在那里你调用了 10 个函数:
rightForwardDistance()
rightDistance()
leftForwardDistance()
leftDistance()
forwardDistance()
sensors = {'left': leftDistance(), 'left forward': leftForwardDistance(), 'forward': forwardDistance(),
'right forward': rightForwardDistance(), 'right': rightDistance()}
where each one of them has a for loop of a range of 1000, removing/commenting the first 5 would make the game a little faster.其中每个人都有一个范围为 1000 的 for 循环,删除/评论前 5 个将使游戏更快一点。
rightForwardDistance()
rightDistance()
leftForwardDistance()
leftDistance()
forwardDistance()
Besides that, the code could be improved in different ways, for example:除此之外,还可以通过不同的方式改进代码,例如:
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))
That code is repeated 5 times and can be moved to a function to avoid repeating it.该代码重复 5 次,可以移动到 function 以避免重复。 The code also has unused variables, that could be removed.
该代码还有未使用的变量,可以删除。
yCoordinate = 0
xCoordinate = 0
After those changes, the code would be more readable and a little faster:在这些更改之后,代码将更具可读性并且速度更快:
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, list(range(-300, 301))))
bounderies.extend(merge(list(range(-300, 301)), [-300] * 601))
bounderies.extend(merge(list(range(-300, 301)), [300] * 601))
bounderies.extend(merge([-150] * 301, list(range(-150, 151))))
bounderies.extend(merge([150] * 301, list(range(-150, 151))))
bounderies.extend(merge(list(range(-150, 151)), [-150] * 301))
bounderies.extend(merge(list(range(-150, 151)), [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, position, 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, position, 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, position, 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, position, tangent)
def doMath(heading, position, 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(), '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)
You have quite a few places like:您有很多地方,例如:
if something in bounderies: ...
Problem is, bounderies
is a list so that lookup is a O(n) operation.问题是,
bounderies
是一个列表,因此查找是一个 O(n) 操作。 And since the most common case is that something not in bounderies
, it's usually going to have to examine the entire list to see that your coordinates aren't in it.而且由于最常见的情况是
something not in bounderies
,因此通常必须检查整个列表以查看您的坐标不在其中。
Adding a single line:添加单行:
...
bounderies.extend(merge(list(range(-150,151)), [-150] * 301))
bounderies.extend(merge(list(range(-150,151)), [150] * 301))
bounderies = set(bounderies) # <--
turns that super expensive - and frequent, - lookup from O(n) to O(1).将超级昂贵且频繁的查找从 O(n) 变为 O(1)。 and on my computer made the whole program run about 18x faster.
在我的电脑上,整个程序的运行速度提高了大约 18 倍。
There are still plenty of other things you can do to make this faster, but this is a super easy and effective optimization.你仍然可以做很多其他的事情来加快速度,但这是一个超级简单有效的优化。
There are several problems with your code.您的代码有几个问题。 First is the
bounderies
[sic] set issue that @KirkStrauser nicely addresses.首先是
bounderies
很好地解决的边界[原文如此] 设置问题。 But the problem with sensors
is even greater than @LucasBelfanti suggests.但
sensors
的问题甚至比@LucasBelfanti 建议的还要严重。 Instead of doing the math (ie geometry ) and finding the distance to the target, you test every possible point along every element of a vector towards the target.您无需进行数学运算(即几何)并找到到目标的距离,而是测试沿矢量的每个元素朝向目标的每个可能点。 Short of fixing the geometry, since you're only looking along one vector at a time, the first intercept should be the point you want, and you can break out of the sensor and avoid the next 500 or so tests.
没有固定几何形状,因为您一次只查看一个向量,第一个截距应该是您想要的点,您可以脱离传感器并避免接下来的 500 次左右的测试。
If we combine that with using math.tan()
instead of math.sin()/math.cos()
, and use modular arithmetic on the angle, for one of your sensors we get something like:如果我们将其与使用
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
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.