首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >游戏AI慢速工作

游戏AI慢速工作
EN

Code Review用户
提问于 2019-02-17 22:19:29
回答 1查看 73关注 0票数 2

我已经编写了一些python代码来播放这个抓人游戏。,但是它要慢一些才能正确地工作,因为如果它单击每一帧,它就会获得几乎相同的屏幕截图,如下所示

代码语言:javascript
复制
 ____
_    _  |     ______
       _|______
        |

Click
Screenshot

 ____
_    _   |    ______
       __|_____
         |

所以它再次点击,因为它认为它仍然低到足以跳跃,所以它双跳而死。

关于如何提高速度,让它工作,有什么想法吗?以下是代码:

代码语言:javascript
复制
#Circle on scratch destroyer
import numpy as np #Numpy
import screenUtils #My custom code that gets the screenshot (Not a problem the screenshots are lightning fast)
from time import sleep, time #Sleep for sleep and time for time checking
from pymouse import PyMouse #Mouse clicking
from pykeyboard import PyKeyboardEvent #Failsafe key is q
from threading import Thread #Threading for keyboard input and the screen shot loop
m = PyMouse() #Init mouse
jumpHeight = 40 #How high the player jumps each click
class safe(PyKeyboardEvent): #I named it safe because it has the failsafe
    def xtra(self):
        self.tog = False #Toggle
    def tap(self, keycode, character, press):
        """
        Subclass this method with your key event handler. It will receive
        the keycode associated with the key event, as well as string name for
        the key if one can be assigned (keyboard mask states will apply). The
        argument 'press' will be True if the key was depressed and False if the
        key was released.
        """
        if self.lookup_char_from_keycode(keycode) == "q" and press: #If the event is a press of the key "q"
            self.tog = not self.tog #Toggle the screenshot loop
        else:
            pass
click = (575, 450) #where on screen to click
e = safe() #Init keyboard event handler
e.xtra()
def checkClick(screen):
    lineY = [] #The Y axis of all the line pixels
    circP = [] #The pixels of the right side of the circle
    if e.tog: #Only execute if the safegaurd is off
        pX = 0 #Pos X
        pY = 0 #Pos Y
        width = len(screen[0]) #Width of the screenshot
        whiteFilter = [] #Init the white filter
        for w in range(width):
            whiteFilter.append(np.array([255,255,255])) #Fill the white filter
        for y in range(len(screen)): #For each Y layer
            if np.array_equal(whiteFilter, screen[y]): #If the layer is white, skip it
                #meh
                pass
            else:
                for x in range(len(screen[y])): #For each pixel on this layer
                    if screen[y][x][0] >= 30 and screen[y][x][0] <= 50 and screen[y][x][1] >= 50 and screen[y][x][1] <= 65 and screen[y][x][2] >= 130 and screen[y][x][2] <= 150:
                        lineY.append(pY) #Found a line pixel
                    if screen[y][x][0] >= 60 and screen[y][x][0] <= 70 and screen[y][x][1] >= 75 and screen[y][x][1] <= 85 and screen[y][x][2] >= 175 and screen[y][x][2] <= 185:
                        circP.append((pX, pY)) #Found a circle pixel
                    pX += 1 #Increment X pos
            pY += 1 #Increment Y pos
            pX = 0 #Reset X Pos
        pix = [] #Init pix array (this stores all circle pixels at X position 35 of the screenshot)
        for pos in circP:
            if pos[0] == 35:
                pix.append(pos)
        final = []
        found = False
        for p in pix: #This loop gets the two inner pixels of the circle at X position 35
            for P in pix:
                if found == False:
                    if abs(p[1] - P[1]) == 87:
                        final.append(p)
                        final.append(P)
                        found = True
        bottom = () #The bottom pixel
        if len(final) == 2: #Double check the length of final
            try: #Handle random exceptions if you turn off safeguard when not on the game
                if final[0][1] > final[1][1]: #Find the bottom pixel
                    bottom = final[1]
                else:
                    bottom = final[0]
                if max(lineY) - bottom[1] >= jumpHeight: #Detect if the program should click
                    print("click")
                    m.click(click[0], click[1])
            except:
                pass

def screenLoop():
    while True:
        if e.tog:
            screen = screenUtils.grab_screen(405,325,468,675) #Screenshot
            screena = np.array(screen)
            start = time()
            checkClick(screena)
            stop = time()
            print("Time: " + str(stop - start))

t = Thread(target=screenLoop)
t.daemon = True
t.start()
e.run()
EN

回答 1

Code Review用户

发布于 2019-02-17 22:45:22

你应该改变:

代码语言:javascript
复制
    found = False
    for p in pix: #This loop gets the two inner pixels of the circle at X position 35
        for P in pix:
            if found == False:
                if abs(p[1] - P[1]) == 87:
                    final.append(p)
                    final.append(P)
                    found = True

通过:

代码语言:javascript
复制
    for p in pix: #This loop gets the two inner pixels of the circle at X position 35
        for P in pix:
            if abs(p[1] - P[1]) == 87:
                final.append(p)
                final.append(P)
                break
        else: continue
        break

这会破坏这两个循环,而不是在找到循环之后毫无意义地运行它。

第二件事,您使用线程,由于GIL,它们不会并行执行,这可能是一个问题,如果您想要性能,考虑多处理(如果需要)。

这段代码效率低下,将screen[y][x]分配给变量以避免查找,您真的需要检查每个帧的每个像素吗?这将很难在不融化你的CPU的情况下实时运行,对于你链接的游戏,你可能只需要一列像素。而且看起来像素要么是白色的,要么不是白色的,所以这些大的条件有点多余。

代码语言:javascript
复制
            for x in range(len(screen[y])): #For each pixel on this layer
                if screen[y][x][0] >= 30 and screen[y][x][0] <= 50 and screen[y][x][1] >= 50 and screen[y][x][1] <= 65 and screen[y][x][2] >= 130 and screen[y][x][2] <= 150:
                    lineY.append(pY) #Found a line pixel
                if screen[y][x][0] >= 60 and screen[y][x][0] <= 70 and screen[y][x][1] >= 75 and screen[y][x][1] <= 85 and screen[y][x][2] >= 175 and screen[y][x][2] <= 185:
                    circP.append((pX, pY)) #Found a circle pixel

如果将代码分解为多个函数,并且使用了好的变量名(不是单/双字母、snake_case、PEP8兼容的),代码就会更容易阅读。

花时间研究for else表示法、GIL和python中的并行计算(让它变得简单:Thead在一个内核上运行,进程在多个核上运行)。screen[y][x]调用场景后面的多个函数,这就是为什么在这种情况下应该分配的原因。PEP8给出了关于如何编写可读代码的好建议(这是一个习惯问题,使用链接器,它可以帮助)。

票数 2
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/213677

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档