[英]Python Game Too Slow
在#sensors 注釋下創建代碼后,我的游戲變得太慢了(參見下面的代碼,它的 for 循環中有很多迭代)。 我已經為人類制作了移動紅點的控件,但游戲應該由計算機自己玩。
我的問題是:
或者是其他東西?
這是我的代碼:
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)
我已經復制並運行了您的代碼,讓我先回答問題:
代碼進行大量處理的主要地方是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 次,可以移動到 function 以避免重復。 該代碼還有未使用的變量,可以刪除。
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, 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)
您有很多地方,例如:
if something in bounderies: ...
問題是, bounderies
是一個列表,因此查找是一個 O(n) 操作。 而且由於最常見的情況是something not in bounderies
,因此通常必須檢查整個列表以查看您的坐標不在其中。
添加單行:
...
bounderies.extend(merge(list(range(-150,151)), [-150] * 301))
bounderies.extend(merge(list(range(-150,151)), [150] * 301))
bounderies = set(bounderies) # <--
將超級昂貴且頻繁的查找從 O(n) 變為 O(1)。 在我的電腦上,整個程序的運行速度提高了大約 18 倍。
你仍然可以做很多其他的事情來加快速度,但這是一個超級簡單有效的優化。
您的代碼有幾個問題。 首先是bounderies
很好地解決的邊界[原文如此] 設置問題。 但sensors
的問題甚至比@LucasBelfanti 建議的還要嚴重。 您無需進行數學運算(即幾何)並找到到目標的距離,而是測試沿矢量的每個元素朝向目標的每個可能點。 沒有固定幾何形狀,因為您一次只查看一個向量,第一個截距應該是您想要的點,您可以脫離傳感器並避免接下來的 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
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.