如何为在线 Flash 游戏构建机器人?

Posted

技术标签:

【中文标题】如何为在线 Flash 游戏构建机器人?【英文标题】:how to build a bot for on-line flash game? 【发布时间】:2011-05-13 04:10:07 【问题描述】:

有很多 Flash 游戏要求你做重复的动作。一个例子是 FarmVille 或获取在线扑克游戏的统计数据。

在屏幕上看到的内容、机器人算法和鼠标点击之间创建界面的最佳方式是什么?

所以基本上,当我在 Facebook 上玩德州扑克时,如果我获得 AA,我希望机器人点击全押。如果我没有得到 AA,我想弃牌。这只是一个例子,而不是实际的策略。或者另一个例子是在farmville中路由任务。

基本上是这样。它必须抓取屏幕的图片。识别模式并将它们转换为算法的输入。输出算法将点击其他一些(可能相同)模式。

有什么建议吗?

【问题讨论】:

这里有一个类似的帖子***.com/questions/1964529/online-trading-bot,其中包含构建扑克机器人codingthewheel.com/archives/how-i-built-a-working-poker-bot 的链接。显然我想做类似的 smtn 但我很好奇这些天是否有更好的工具。尽管查看发送和接收的数据更容易,但查看屏幕然后让计算机移动鼠标更为通用。 看起来这可能也是一种方法mjtnet.com/blog/2006/10/11/… 【参考方案1】:

我有为在线纸牌游戏构建基于计算机视觉的简单机器人的经验。

我使用了一个名为 autopy 的跨平台 Python 库来处理自动鼠标点击和键盘输入。机器人每 0.5 秒捕获一次屏幕,然后将捕获的屏幕转换为 numpy 数组进行分析。 Python 具有良好的图像处理(PIL、OpenCV python 绑定)和机器学习实用程序(scikit-learn)。对于简单的图像模式识别,机器人提取图像区域上像素亮度的平均值以做出决策。对于复杂的,使用OpenCV模板匹配和SVM分类器。

服务器第一次捕获了我的机器人,所以我猜有些服务器端检测到了机器人。在我添加更多随机性和灵活决策之后,该机器人绕过了服务器端机器人检测。

我度过了一个星期六,我很享受星期天。

【讨论】:

【参考方案2】:

在尝试解析屏幕图像并产生鼠标点击(这将非常困难)之前,首先查看游戏在浏览器和服务器之间实际发送/接收的数据。像往常一样与游戏互动,并使用WireShark 之类的东西来捕获数据包,看看它是否可以自动化。

这不太可能(因为他们特别希望人们做你想做的事情),但与服务器的通信可能只是带有参数的简单请求。 (我知道很久以前 MySpace 游戏就是这种情况,例如 Dragon Wars 和 Mafia Wars。)

如果数据是您可以解析和理解的,那么您可以完全跳过 Flash 界面,直接编写自己的界面。

【讨论】:

wireshark 听起来不错。我会调查的。但是我也很好奇 c 是否可以通过屏幕进行交互,因为它更通用,并且还可以节省尝试找出发送的值的时间。 @kirill_igum:可能有一些库可以以鼠标/键盘输入的形式将数据发送到屏幕。例如,WatiN 是一个不错的 .NET 库,用于与浏览器交互(html 元素,对于 Flash 来说不是很多,尽管可能还有其他元素)。但是,从屏幕读取数据将非常困难。即使有可能(可行可能是一个更准确的词)我认为它不会像您期望的那样通用。 如果您知道自己在寻找什么,我不明白这有多困难。例如:我午餐了一个程序,该程序拍摄了 Flash 游戏或浏览器或屏幕的屏幕截图。将其转换为矩阵,其中每个元素都是代表颜色的数字。一个代码会将一个子矩阵与我的库中的一个匹配(我正在寻找的预存模式)。如果匹配,则代码输出模式的位置。所以当我想使用它时,我只需要输入我正在寻找的模式。如果他们改变了。我将不得不手动更改它们 我仍然会调查 WatiN。我同意你的观点,在很多情况下直接处理数据会更简单,但我想探索或了解这两种方法。 @kirill_igum:听起来确实是一个非常可爱的开源库。您可能会在这样的项目中找到一些不错的社区兴趣,但我不是托管开源项目的专家。【参考方案3】:

我使用 c# 和一个简单的 webBrowser 控件制作了许多机器人。 但是,通常我会尝试在不使用实际模拟光标和调用点击的情况下自动执行元素上的“点击”功能。

示例:

webBrowser1.Document.GetElementById("elementid").InvokeMember("Click");

我发现这比实际模拟游标要容易得多,但是模拟游标也可以相对容易地实现,这是我通常使用的代码:

//Example of how to use it:
    Point controlLoc = this.PointToScreen(webbrowser1.Location);
    controlLoc.X = controlLoc.X + webbrowser1.Document.GetElementById("elementid").OffsetRectangle.Left;
    controlLoc.Y = controlLoc.Y + webbrowser1.Document.GetElementById("elementid").OffsetRectangle.Top;
    Cursor.Position = controlLoc;
    MouseSimulator.ClickLeftMouseButton();

public class MouseSimulator
 
[DllImport("user32.dll", SetLastError = true)]
static extern uint SendInput(uint nInputs, ref INPUT pInputs, int cbSize);

[StructLayout(LayoutKind.Sequential)]
struct INPUT

    public SendInputEventType type;
    public MouseKeybdhardwareInputUnion mkhi;

[StructLayout(LayoutKind.Explicit)]
struct MouseKeybdhardwareInputUnion

    [FieldOffset(0)]
    public MouseInputData mi;

    [FieldOffset(0)]
    public KEYBDINPUT ki;

    [FieldOffset(0)]
    public HARDWAREINPUT hi;

[StructLayout(LayoutKind.Sequential)]
struct KEYBDINPUT

    public ushort wVk;
    public ushort wScan;
    public uint dwFlags;
    public uint time;
    public IntPtr dwExtraInfo;

[StructLayout(LayoutKind.Sequential)]
struct HARDWAREINPUT

    public int uMsg;
    public short wParamL;
    public short wParamH;

struct MouseInputData

    public int dx;
    public int dy;
    public uint mouseData;
    public MouseEventFlags dwFlags;
    public uint time;
    public IntPtr dwExtraInfo;

[Flags]
enum MouseEventFlags : uint

    MOUSEEVENTF_MOVE = 0x0001,
    MOUSEEVENTF_LEFTDOWN = 0x0002,
    MOUSEEVENTF_LEFTUP = 0x0004,
    MOUSEEVENTF_RIGHTDOWN = 0x0008,
    MOUSEEVENTF_RIGHTUP = 0x0010,
    MOUSEEVENTF_MIDDLEDOWN = 0x0020,
    MOUSEEVENTF_MIDDLEUP = 0x0040,
    MOUSEEVENTF_XDOWN = 0x0080,
    MOUSEEVENTF_XUP = 0x0100,
    MOUSEEVENTF_WHEEL = 0x0800,
    MOUSEEVENTF_VIRTUALDESK = 0x4000,
    MOUSEEVENTF_ABSOLUTE = 0x8000

enum SendInputEventType : int

    InputMouse,
    InputKeyboard,
    InputHardware


public static void ClickLeftMouseButton()


    INPUT mouseDownInput = new INPUT();
    mouseDownInput.type = SendInputEventType.InputMouse;
    mouseDownInput.mkhi.mi.dwFlags = MouseEventFlags.MOUSEEVENTF_LEFTDOWN;
    SendInput(1, ref mouseDownInput, Marshal.SizeOf(new INPUT()));

    INPUT mouseUpInput = new INPUT();
    mouseUpInput.type = SendInputEventType.InputMouse;
    mouseUpInput.mkhi.mi.dwFlags = MouseEventFlags.MOUSEEVENTF_LEFTUP;
    SendInput(1, ref mouseUpInput, Marshal.SizeOf(new INPUT()));

这将左键单击加载的 webBrowser 控件中名为“elementid”的任何元素。注意其他可以轻松实现的 MouseEventFlags:

这是一个右键单击的例子:

public static void ClickRightMouseButton()

    INPUT mouseDownInput = new INPUT();
    mouseDownInput.type = SendInputEventType.InputMouse;
    mouseDownInput.mkhi.mi.dwFlags = MouseEventFlags.MOUSEEVENTF_RIGHTDOWN;
    SendInput(1, ref mouseDownInput, Marshal.SizeOf(new INPUT()));

    INPUT mouseUpInput = new INPUT();
    mouseUpInput.type = SendInputEventType.InputMouse;
    mouseUpInput.mkhi.mi.dwFlags = MouseEventFlags.MOUSEEVENTF_RIGHTUP;
    SendInput(1, ref mouseUpInput, Marshal.SizeOf(new INPUT()));

【讨论】:

以上是关于如何为在线 Flash 游戏构建机器人?的主要内容,如果未能解决你的问题,请参考以下文章

如何为机器学习和预测构建良好的训练数据集?

用于在线游戏的 Java 机器人

创建一个 Flash 游戏机器人

sikuli : 无法找到 Flash 弹出窗口中的图像

如何为文字游戏编写可拖动图块?

如何为不和谐机器人调用异步函数