2021-09-04

SikuliXを管理者権限で実行する

 SikuliXで操作をしようとしらた以下エラーが発生。どうも対象ウィンドウを操作するための権限がない模様。 SikuliXを管理者で実行することで解決できたので手順を残しておきます。

[error] RobotDesktop: checkMousePosition: should be L[719,118]@S(0) - but is not!

Possible cause in case you did not touch the mouse while script was running:

 Mouse actions are blocked generally or by the frontmost application.

You might try to run the SikuliX stuff as admin.




手順は以下

  1. コマンドプロンプトを管理者権限で起動
  2. コマンドプロンプトからSikuliXを起動
この手順で起動するとSikuliXが管理者権限で起動でき、上記エラーが解消できました。
以下でそれぞれの手順をまとめます。

コマンドプロンプトを管理者権限で起動

コマンドプロンプトを管理者権限で起動する手順はいくつかあります。

方法1.コマンドプロンプトのショートカット右クリックメニューから「管理者として実行」を選択して起動する


方法2.コマンドプロンプトのショートカットプロパティから管理者として実行されるようにオプションを設定してから起動する


この手順で起動すると管理者権限をもったコマンドプロンプトが立ち上がります。このコマンドプロンプトからSikuliXを起動すると管理者権限で動作します。



コマンドプロンプトからSikuliXを起動

コマンドプロンプトからSikuliXを起動するには、sikulixide-*.jarがあるディレクトリに移動して以下コマンドを実行で起動します。

java -jar sikulixide-2.0.4.jar


まとめ 

SikuliXで「[error] RobotDesktop: checkMousePosition」のエラーがでたら管理者権限で実行すると解消するかもしれません。








2021-04-21

SikuliXの汎用的な自動周回用スクリプト・改

 クリック位置をブレさせることやタイミングを変える関数作りましたので周回用スクリプトをアップデートしました。細かい説明は以下参照。

SikuliXの汎用的な自動周回用スクリプト

SikuliXでクリック間隔を調整する

SikuliXの動作に不規則性を持たせる(クリック位置、タイミング)

汎用周回スクリプト改

import random
import math
from datetime import datetime
global DEBUG
global CLICK_DELAY_MIN
global CLICK_DELAY_MAX


#########################################
#  検索設定
#########################################
DEBUG = 1		# デバッグ表示 クリックしないでハイライト
DEBUG = 0		# デバッグ無効 クリックする

# クリック実行するまの遅延時間 sec
CLICK_DELAY_MIN = 0
CLICK_DELAY_MAX = 1

# 検索範囲とするウインドウ名
WINDOW_NAME = ""

IMGS = [
	# ここに検索対象のイメージパターンを追加する
]

#########################################
#  動作設定
#########################################
# 最小一致閾値 デフォルト 0.7
Settings.MinSimilarity = 0.80
# マウス移動のディレイ:0 = アニメーションなし
Settings.MoveMouseDelay = 0.1
# マウスダウンからアップするときの遅延時間 0.0 ~ 1.0
#Settings.ClickDelay = 0.1

#########################################
#  処理
#########################################
# タップ処理 m:Match or Region オブジェクト sec:マウスダウン時間(秒)
def tap(m, sec):

	# クリック位置を検索画像の範囲内でランダムに動かす
	# クリック位置が検索画像内にない場合は変更しない
	if math.fabs((m.x + (m.w/2))-m.getTarget().x) < 2:
		m.x = m.x + random.randint(-1*(m.w/2), (m.w/2))
	if math.fabs((m.y + (m.h/2))-m.getTarget().y) < 2:
		m.y = m.y + random.randint(-1*(m.h/2), (m.h/2))
	print("{} index:{} ({},{})".format(datetime.now().strftime("%H:%M:%S"),m.getIndex(), m.x, m.y))

	# 0~3秒ランダムな遅延
	sleep(random.randint(CLICK_DELAY_MIN, CLICK_DELAY_MAX))

	if DEBUG:
		m.highlight(1,"blue")
		return
	
	mouseMove(m)
	mouseDown(Button.LEFT)
	sleep(sec)
	mouseUp(Button.LEFT)

# タップ
def tap_s(m):
	tap(m, 0.03)

# ロングタップ
def tap_l(m):
	tap(m, 1.0)

# APPNAMEのウインドウを探してRegion(検索範囲)に設定
app = App.focus(WINDOW_NAME)
reg = Region(App.focusedWindow())
reg.highlight(1,"green")

# ループ
while True:
	# 検索
	ms = reg.findAnyList(IMGS) 
	# 結果msはIMGSの順で見つかったものが格納される
	for m in ms:
		# クリック
		tap_s(m)
		# 最初に見つかったものだけ処理して終了
		break
	sleep(1)

SikuliXの動作に不規則性を持たせる(クリック位置、タイミング)

SikuliXで操作を自動化する場合に、不規則な操作を実現したい場合があるはず・・・

以下2点で操作に不規則性・ブレを実現できないか検討しました。

  • クリック位置
  • 反応速度

以前作ったマウスのアップダウン間隔を調整するクリック関数を改造します。

https://taidadesu.blogspot.com/2021/01/sikulix_5.html


改造版クリック関数

改造したクリック関数は以下です。(元の関数がスマホ操作の用途のためタップとしています)

import random
import math
from datetime import datetime

# タップ処理 m:Match or Region オブジェクト sec:マウスダウン時間(秒)
def tap(m, sec):
	# クリック位置を検索画像の範囲内でランダムに動かす
	# クリック位置が検索画像内にない場合は変更しない
	if math.fabs((m.x + (m.w/2))-m.getTarget().x) < 2:
		m.x = m.x + random.randint(-1*(m.w/2), (m.w/2))
	if math.fabs((m.y + (m.h/2))-m.getTarget().y) < 2:
		m.y = m.y + random.randint(-1*(m.h/2), (m.h/2))

	# 0~3秒ランダムな遅延
	sleep(random.randint(0, 3))
	
	mouseMove(m)
	mouseDown(Button.LEFT)
	sleep(sec)
	mouseUp(Button.LEFT)

# タップ
def tap_s(m):
	tap(m, 0.05)

# ロングタップ
def tap_l(m):
	tap(m, 1.0)


# 使用例
m = find("1609741390982.png")
tap_l(m)
tap_s(m)


クリック位置のオフセットを設定していない場合は、検索画像の中心がクリック位置になります。以下の処理で、クリック位置が画像内にあるか判定します。通常、画像の中心座標「m.x + (m.w/2)」とクリック位置「m.getTarget().x」は同値になるので差は0になりますが、若干のずれは許容するよう2より小さければ対象としました。

if math.fabs((m.x + (m.w/2))-m.getTarget().x) < 2:

以下処理で検索画像の中心位置を画像内の範囲でランダムに動かしています。

m.x = m.x + random.randint(-1*(m.w/2), (m.w/2))

以下で0~3秒の範囲でランダムなディレイをしています。

sleep(random.randint(0, 3))

まとめ

ここで紹介したタップ関数(クリック関数)を標準のClick関数から変更することで、クリック位置、クリックタイミングに不規則性を持たせることができました。あとは定期的な停止期間を作れば、より人間らしい操作になるのかと思います。

2021-03-25

ウマ娘 リセマラの高効率化を試みる

ウマ娘が話題になってるのでやってみることに。

はじめてなので最初はリセマラから。1回チュートリアルクリアで、以降チュートリアルのスキップが可能(ゲーム内メニューからユーザデータ削除する)。リセマラに時間がかからない仕様だけど、時間をかけずに終わらせたい。

なので、リセマラの高効率化を実施しました。

内容は以下。エミュレータを使って複数のウマ娘を同時操作して効率を上げます。

  1. Noxでウマ娘を複数起動して
  2. 操作を同期させて
  3. 1回の操作で複数台分のガチャを引く



0:準備

Noxを1つ立ち上げてウマ娘を入れる。あとはチュートリアルをクリアで準備完了。

1:Noxを複数起動する

チューリアルが完了した環境ができたら次は複製。
まずはマルチインスタンスの複製ボタンから複製した環境の設定をする。
以下では、
  • フレームレート:20
  • サウンドオフ:チェック
  • バッチコピー:8
  • 種類:携帯電話 540x960
とした。

設定を保存し、マルチインスタンスマネージャに戻ったら、
  1. コピー元の環境にチェックを入れる
  2. バッチ処理のプルダウンからコピーを選択
これで、環境が複製される。

あとは起動するだけ。
起動するNoxPlayerをチェックし、バッチ処理から開始を選択する。これでチェックされたPlayerが起動される。

「マルチインスタンスのアレンジ」を開き、ウィンドウの並びを指定して「アレンジ」ボタンを押すときれいに整列してくれる。



2:操作を同期する

基準となるPlayerの右側メニュー「・・・」→「=」(マルチ同期)を選択。
マルチ同期画面で再生ボタンを押すと同期が始まる。



3:ガチャを引く

あとはガチャを引く → ユーザデータ削除 → ガチャ の繰り返し


良いのが引けた場合

良い結果が得られたら、そのNoxだけを終了させる。
停止処理が完了したらNoxの複製が可能になる。そしたら複製を実行しよう。
これでよいガチャ結果の出たNoxのデータのバックアップは完了した。
ガチャを再開する場合は終了したNoxを起動するだけ。

ガチャの終わり

なっとくする結果がでたらNoxのままゲームを継続するもよし。データ連携を設定してメインで遊ぶスマホに移行するもよし。
あとは遊ぶだけ。

複数起動の目安

NoxはAndroidをエミュレートしているので結構マシンパワーを使う。
1つのNoxを動かすのに最低必要なのはCPUコア1、メモリ2Gくらい。

確認環境
CPU:Ryzen 7 3700X (8コア)
メモリ:32G

これで安定して動作したのが8つ同期起動でした。


ウマ娘以外のリセマラ

Noxで動作するゲームなら同じやり方でリセマラ可能でした。
昔やったものはっときます。

ロマサガRS


D2




2021-03-04

ドラクエウォーク 財宝の洞窟 自動化やってみた

ドラクエウォークのイベント「海賊アロン航海記」がもうすぐ終わります。が、「財宝の洞窟」が面倒なので手つかずになってます。

なので、自動化やってみました。

自動化をやった環境

ほかの自動化と同じようにWindows PCからスマホを操作し、Sikulixの画像認識をつかって自動化させました。


WindowsからAndroidスマホの操作はこちら

Sikulixについてはこちら


自動化スクリプト

自動化スクリプトはこちら

いつもの自動化スクリプトに画像を登録して自動化を実現しました。

登録した画像はこちら。


基本的には見つかった画像をタップするだけの簡単なお仕事です。

洞窟探検には難易度を選べるものがありました。なるべくスコアを稼ぎたい、でも自動で処理したい。なので、MP回復なしでそこそこ放置できる中級を自動で選ぶように細工します。

そこでターゲットオフセット。
初級の画像があったら、「+」ボタンをタップするようにしました。


続いて中級の画像あったら「探索する」をタップするように。


これで、初級→中級に切り替えて探索するようになりました。

ただ、中には難易度が選べないものがあって、初級から変更できないものもあります。


この時ように、「+」がグレーアウトしてる場合は「探索する」を選ぶようにしました。


あとは、それぞれのシーンでタップするための画像を登録するだけ。

まとめ

今回のドラクエウォークの洞窟探検は画像を選んでタップの繰り返しで何とかなりました。

2021-01-24

SikuliXの勉強 FFRK ラビリンスダンジョン自動化実験

SikuliXの勉強のため、FFRK(FINAL FANTASY Record Keeper)のラビリンスダンジョンの操作を自動化してみました。いろいろ課題はありますが、以前投稿した汎用スクリプトで自動操作できました。

スクリプト

スクリプトは以前の汎用スクリプトそのまま。

Settings.MinSimilarity = 0.80
Settings.MoveMouseDelay = 0
Settings.ClickDelay = 0.4

IMGS = [
]

reg = Region(App.focusedWindow())
reg.highlight(1,"green")

while True:
	ms = reg.findAnyList(IMGS) 
	for m in ms:
		m.click()
		break
	sleep(0.5)


動作

使い方はIMGSに操作対象の画像を登録していくのみ。

同じ画面に複数の検索対象がある場合は、画像の並びを調整することで対応できました。

実際の流れは以下の動作を参照。



課題

現状のスクリプトでは1場面1クリックを想定しており、クリックすると場面が変わりクリックした画像がなくなる事を期待しています。なくならず残り続けるシーンだと永遠にその画像をクリックし続ける動きになります。

このため、1つの場面でクリック対象を順番に切り替えるような場面はやり方を考えなければなりません。

今回のFFRKの場合は、出撃するパーティを選択するシーンになります。一番消耗していないパーティを選択した後、Goボタンをクリックする処理になります。

クリックした画像の情報を残す(フラグを立てる)など実装すると実現可能ですが、コードが複雑化しそうです。

より簡単かつすっきりする方法を検討したいと思います。


2021-01-05

SikuliXでクリック間隔を調整する

SikuliXで操作するアプリケーションの中には、デフォルトのクリック速度(マウスダウンからアップまでの時間)だとクリックを認識できない場合があります。また、スマートフォンを操作する場合、タップやロングタップをしたいケースもあります。

これらの実現方法についてまとめます。


システム変数「Settings.ClickDelay」

クリック速度の微調整だけであれば、システム変数「Settings.ClickDelay」で調整できます。

# マウスダウンからアップするときの遅延時間 0.0 ~ 1.0(秒)
Settings.ClickDelay = 0.1

0~1秒の範囲で調整可能。1秒以上のクリックは次のmouseDown、mouseUpを使用したクリック処理を使うことで対応可能です。

タップ・ロングタップ処理

クリックを自由に調整したい場合、mouseDown、mouseUpを使用してクリック処理を実装することで実現可能。

# タップ処理 m:Match or Region オブジェクト sec:マウスダウン時間(秒)
def tap(m, sec):
	mouseMove(m)
	mouseDown(Button.LEFT)
	sleep(sec)
	mouseUp(Button.LEFT)

# タップ
def tap_s(m):
	tap(m, 0.05)

# ロングタップ
def tap_l(m):
	tap(m, 1.0)


# 使用例
m = find("1609741390982.png")
tap_l(m)
tap_s(m)

リモートでスマホ操作した時に作成した処理です。クリックメソッドを使わず、マウス移動、マウスダウン、アップを実装してタップとロングタップを実現しています。

2021-01-04

SikuliX 任意の場所をクリックする方法

 SikuliXで検索結果ではなく、任意の場所をクリックする必要があり、調べたのでメモを残します。

クリック機能などはRegionクラスのメソッドになります。なので、クリック対象の座標を指定したRegionのオブジェクトを作成することで任意の場所をクリックできます。

findなどで検索した結果は、Matchクラスのオブジェクトで返ってきますが、このMatchクラスはRegionクラスの派生のようです。


任意の場所をクリックする方法

Regionのオブジェクトを作成して任意の場所(50,50)の位置をクリックするコードは以下。

	
# Region(x座標,y座標,幅,高さ)
r = Region(50,50,1,1)
r.click()

クリック位置は矩形の中心になる模様。幅と高さ大きくするとその分ずれるのでピンポイント座標を指定する場合は、幅と高さを1に設定したほうがよさそう。