Skip to main content

A package used for writing ddtank game scripts.

Project description

DDTank

A package used for writing ddtank game scripts.

Contact the author: jugking6688@gmail.com

Video tutorial in bilibili: https://space.bilibili.com/3493127383943735

Examples are as follows:

from ddtank import Status, get_game

class ScriptStatus(Status):
    def task(self):
        while True:
            self.press('B')

if __name__ == '__main__':
    handle_list = get_game()
    handle = handle_list[0]
    my_status = ScriptStatus(handle)
    my_status.start()
    my_status.stop()

DDTank 非正式文档

Document for ddtank package

写在前面

本软件包的更新、规范全凭作者个人喜好而变动,请慎重使用!

作者邮箱: jugking6688@gmail.com

B站视频系列: https://space.bilibili.com/3493127383943735

QQ交流群:285669805


版本更新说明

  • version 1.1

引入了图形化界面,即脚本执行器ddtanker

from ddtank import DDTanker

ddtanker = DDTanker()
ddtanker有找色、截图、地图识别等功能,大大提高脚本编写的效率。
注意,如果你想编写一个ddtanker能够识别、执行的ddtank脚本,你需要将子类命名为ScriptStatus,
然后将.py文件放在./script文件夹中。
from ddtank import Status

class ScriptStatus(Status):
    def task(self):
        self.click('rfind', pos=(520, 57), rgb=(6, 104, 210))
        self.click('rfind', pos=(743, 141), rgb=(247, 75, 61))
        self.click('rfind', pos=(430, 278), rgb=(149, 86, 92))
        self.sleep(100)
        self.click('rfind', pos=(241, 373), rgb=(83, 244, 52))
一个能供ddtanker识别、执行的ddtank脚本,它的作用是:
假设人物位于大厅,他将会进入农场,然后扭蛋一次。

1. 获取游戏窗口信息 get_game()

from ddtank import get_game

hwnds = get_game()

上面的代码演示了如何获取当前已经运行了的,所有的弹弹堂游戏窗口的句柄,并保存到了列表hwnds中。

get_game()的本质就是遍历所有1000*600的,类名为'MacromediaFlashPlayerActiveX'的子窗口。
此方法绝对适用于中国弹弹堂官服,其他弹弹堂版本,如弹弹堂经典服、中国台湾淘米弹弹堂、越南、
马来西亚、巴西服务器弹弹堂不保证能够识别,请根据实际情况修改代码参数。

如果你想要同时获取游戏窗口的标题文本,那么设置get_title参数为True

from ddtank import get_game

hwnds, titles = get_game(get_title=True)

2.实例化角色对象 Status()

在弹弹堂中,每一个游戏窗口对应一个游戏角色。因此,每一个实例化的Status对象也对应每一个角色。

from ddtank import get_game, Status

hwnds = get_game()
hwnd = hwnds[0]
my_status = Status(hwnd)
如果你之前也获取了标题文本列表,那么可以在实例化Status时指定第二个参数title。

3.找图与找点 find()

存在以下场景:

  • 获取某点的像素值(RGB)
  • 判断某个(多个)点像素值是否符合条件
  • 重复判断直到某个点像素符合了条件
  • 获取某图片的位置

3.1 获取某点的像素值(RGB)

在下面的例子中,我们获取了游戏图像中(200, 200)处的像素值并储存在了变量pixel中。

from ddtank import get_game, Status

hwnds = get_game()
hwnd = hwnds[0]
my_status = Status(hwnd)
pixel = my_status.find('find', pos=(200, 200))
# 或者,你可以直接 find(pos=(200, 200)
获取像素值使用了win32gui的GetPixel方法,而不是先截图然后访问图片数组。

3.2 判断某个(多个)点像素值是否符合条件

在下面的例子中,我们判断了三个点是否符合条件,如果其中某个符合了条件, 那么就会返回它的参数名称(例如,cdt2)。

from ddtank import get_game, Status

hwnds = get_game()
hwnd = hwnds[0]
my_status = Status(hwnd)
rst = my_status.find('mfind', 
                     cdt1=((100, 100), (12, 23, 34)), 
                     cdt2=((200, 200), (34, 23, 12)), 
                     cdt3=((300, 300), (21, 32, 43)), )
'mfind'也可以简写为'mf'或者'm',取决于你的心情。
每一种method都有许多简写方式。

3.3 重复判断直到某个点像素符合了条件

在下面的例子中,我们重复判断游戏图像中(200, 200)处的像素值是否为(1, 2, 3), 在实际应用中,这种情况经常适用于进入某场景前的等待。

from ddtank import get_game, Status

hwnds = get_game()
hwnd = hwnds[0]
my_status = Status(hwnd)
my_status.find('rfind', pos=(200, 200), rgb=(1, 2, 3))
指定method为'rfind'时,还可以设置两个参数: 'el'和'period'。
'el'用于指定在找某点像素值不符合条件时,执行的方法。
'period'用于指定每次循环之间的等待时间,默认为100毫秒,这是为了避免资源占用过大。

3.4 获取某图片的位置

用于寻找的图片储存在self.image_path内(默认值为./image),其格式必须为png。 在下面的例子中,我们有图片路径为./image/temp.png,我们在游戏图像中查找它的位置:

from ddtank import get_game, Status

hwnds = get_game()
hwnd = hwnds[0]
my_status = Status(hwnd)
center_point_pos = my_status.find('find_image', img='temp')

返回值center_point_pos为图片的中心点位置。

指定method为'rfind'时,还可以设置一个参数: 'part'。
'part'用于指定寻找图片的范围。
'part'需要传递一个元组(x, y, w, h):
分别为左上角x坐标、左上角y坐标、宽度、高度,默认为(0, 0, 1000, 600)即整个窗口
在有的时候,整个游戏图像中有多个相同(或高度相似)的图片,
你可能希望仅仅在某一小片的区域内寻找图片。

4.模拟点击 click()

存在以下场景:

  • 点击某处

  • 某个点像素值符合条件才点击此处

  • 重复判断直到某个点像素符合了条件,然后点击此处

  • 获取某图片的位置,然后点击图片位置

  • 重复寻找某图片,直到图片出现,然后点击图片位置

    一般来说,click方法和find方法的method及参数都是对应的。

下面的代码基本完整展示了click的使用方法。如果你学会了find的使用,那么理解click将会是顺其自然的。

from ddtank import get_game, Status

hwnds = get_game()
hwnd = hwnds[0]
my_status = Status(hwnd)
my_status.click(pos=(200, 200))
my_status.click('find', pos=(200, 200), rgb=(255, 255, 255), el=lambda: print(my_status.find(pos=(200, 200))), period=1000)
my_status.click('rfind', pos=(200, 200), rgb=(255, 255, 255))
my_status.click('find_image', img='temp', part=(0, 300, 500, 300))

5.模拟按键 press()

下面的一个例子展示了press方法的使用:

from ddtank import get_game, Status

hwnds = get_game()
hwnd = hwnds[0]
my_status = Status(hwnd)
key_series = ('B', 1000, 'ESC', ('M', 1000))
my_status.press(key_series)
在上面的例子里,我们先模拟按下了B键,等待1秒(1000毫秒)后按下ESC键,然后持续按下M键1秒。

6.读取地图 read()

识别小地图,来获取各种信息。

风力:    {self.wind}
角度:    {self.angle}
小地图界限:    {self.map_pos}
白框位置:    {self.box_pos}
白框宽度:    {self.box_width}
蓝点:    {self.blues}
三角:    {self.cur_pos}
红点:    {self.reds}
光圈:    {self.circle}
read()方法有一个参数为is_circle,默认为False,代表是否进行光圈识别。
在副本中,我们识别当前出手的角色一般依赖三角,而在竞技中,我们依靠闪烁的光圈来定位。

对于风力和角度的识别,我们使用了深度学习的方法来识别数字,如果你玩的弹弹堂版本不是官服,
那么其识别的准确率不理想。如果你想要为你所在的服务器来训练一个独特的识别模型,你可以为我们提供数据集。

7.发射炮弹 shot()

不好用,以后改进。

综合模拟发射炮弹操作
注意,使用此方法前需要先执行self.read()方法,否则信息得不到及时更新
:param shot_angle: 发射的角度,若传递一个元组则执行变角操作
:param shot_strength: 发射的力度
:param shot_item: 使用的道具按键,多个道具之间用','分隔
:return: 无返回值

8.角色移动 move()


关于脚本的编写

我们建议您继承父类Status,然后重写task()方法,将脚本内容写在此方法内, 通过YourStatus.start()方法执行脚本,此方法会开辟一个子线程来执行脚本。并且, 你可以通过YourStatus.stop()方法来强制停止脚本的运行。

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

ddtank-1.1.3.tar.gz (19.1 kB view hashes)

Uploaded Source

Built Distribution

ddtank-1.1.3-py3-none-any.whl (18.6 kB view hashes)

Uploaded Python 3

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page