autojs绘制玩家位置

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第6天,点击查看活动详情

牙叔教程 简单易懂

写教程的起因

有些新手不会用canvas, 一般画线和画框没问题, 但是不会擦除之前绘制的线,

最后屏幕上到处都是线, 到处都是框, 然后抱怨autojs写绘制一堆问题, 气死了, 之类的话

原因呢, 就是对canvas不熟悉, 下面我们来看看正确的绘制方法

绘制的正确流程

要绘制东西, 首先要有数据, 我们来构造数据,

直线

function Line(x1, y1, x2, y2) {
    this.x1 = x1;
    this.y1 = y1;
    this.x2 = x2;
    this.y2 = y2;
}

function Rectangle(x, y, width, height) {
    this.x = x;
    this.y = y;
    this.width = width;
    this.height = height;
}

编一些测试数据

第一: 计算屏幕宽高

let dw = device.width;
let dh = device.height;

第二:构造玩家

function Player(x, y, width, height, color) {
    this.x = x;
    this.y = y;
    this.width = width;
    this.height = height;
    this.color = color;
}

第三:编写玩家数据

let playerCount = 10;
let players = [];
for (var i = 0; i < playerCount; i++) {
    let playerWidth = random(30, 100);
    let playerHeight = 2 * playerWidth;
    let color = random(0, 1) ? "#ff0000" : "#00ff00";
    let player = new Player(
        random(0, dw),
        random(0, dh),
        playerWidth,
        playerHeight,
        color
    );
    players.push(player);
}
console.log(players);

生成的假数据

[ { x: 879, y: 200, width: 69, height: 138, color: '#ff0000' },
  { x: 299, y: 313, width: 80, height: 160, color: '#ff0000' },
  { x: 649, y: 507, width: 68, height: 136, color: '#ff0000' },
  { x: 194, y: 83, width: 65, height: 130, color: '#00ff00' },
  { x: 677, y: 76, width: 63, height: 126, color: '#00ff00' },
  { x: 573, y: 420, width: 40, height: 80, color: '#00ff00' },
  { x: 781, y: 429, width: 33, height: 66, color: '#00ff00' },
  { x: 309, y: 34, width: 77, height: 154, color: '#ff0000' },
  { x: 177, y: 418, width: 95, height: 190, color: '#00ff00' },
  { x: 468, y: 265, width: 36, height: 72, color: '#00ff00' } ] 

绘制数据

绘制的时候不能干扰屏幕操作, 所以要用悬浮窗;

扫描二维码关注公众号,回复: 14312817 查看本文章

绘制是全屏的, 有可能通知栏会影响高度, 这个根据实际情况调整, 我们只讲绘制的主要流程;

第一步:创建全屏悬浮窗画板

第一步: 创建悬浮窗

let w = floaty.rawWindow(
    <vertical id="root" bg="#ff0000" gravity="center">
        <button textSize="30sp">公众号: 牙叔教程</button>
    </vertical>
);
w.setSize(-1, -1);
setInterval(() => {}, 1000);

第二步:确认全屏以后, 把button改成canvas

let w = floaty.rawWindow(
    <vertical id="root" bg="#ff0000" gravity="center">
        <canvas id="board"></canvas>
    </vertical>
);

第三步:添加draw事件监听

w.board.on("draw", (canvas) => {
    canvas.drawColor(colors.parseColor("#0000ff"));
});

现在画板是全屏的了

第二步:绘制玩家

让玩家自己绘制吧, 给player添加一个draw方法

Player.prototype.draw = function (canvas) {
    let paint = new android.graphics.Paint();
    paint.setColor(this.color);
    paint.setStyle(android.graphics.Paint.Style.FILL);
    canvas.drawRect(
        this.x,
        this.y,
        this.x + this.width,
        this.y + this.height,
        paint
    );
};

这个 每次draw都创建一个画笔paint, 显然太浪费了, paint我们作为全局变量,

let paint = new android.graphics.Paint();
paint.setStyle(android.graphics.Paint.Style.Stroke);
Player.prototype.draw = function (canvas) {
    paint.setColor(this.color);
    canvas.drawRect(
        this.x,
        this.y,
        this.x + this.width,
        this.y + this.height,
        paint
    );
};

这个只是画了一个矩形, 我们再把线也画上

Player.prototype.draw = function (canvas) {
    paint.setColor(this.color);
    canvas.drawRect(
        this.x,
        this.y,
        this.x + this.width,
        this.y + this.height,
        paint
    );
    // 直线一律以屏幕顶部中心为起点
    canvas.drawLine(halfDw, 0, this.x + this.width / 2, this.y, paint);
};

很好, 看起来差不多了,我们现在就去绘制玩家

w.board.on("draw", (canvas) => {
    // canvas.drawColor(colors.parseColor("#0000ff"));
    var len = players.length;
    for (var i = 0; i < len; i++) {
        let player = players[i];
        player.draw(canvas);
    }
});

怎么是全红的呢? 不是应该一个框 一个线 吗?

我不理解

为什么全屏都是红色, 而不是框

经过三天两夜的排查, 发现问题是画笔设置颜色有问题;

一般设置画笔颜色是

paint.setColor(this.color);

要改成

paint.setColor(colors.parseColor(this.color));

因为setColor的颜色是整数, 而我们的颜色是字符串, 要转换一下颜色;

这个问题, 在日志中是看不出来的, 因为没有报错, 只能靠猜;

改完颜色, 测试一下, 绘制正常

\

绘制所有玩家

看上去像是那么回事了, 线条有点粗, 改细一点

paint.setStrokeWidth(3);

定时刷新数据

游戏中的数据一直在变动, 我们模拟一下变动,加个定时器修改数据

setInterval(() => {
    let newPlayers = [];
    for (var i = 0; i < playerCount; i++) {
        let playerWidth = random(30, 100);
        let playerHeight = 2 * playerWidth;
        let color = random(0, 1) ? "#ff0000" : "#00ff00";
        let player = new Player(
            random(0, dw),
            random(0, dh),
            playerWidth,
            playerHeight,
            color
        );
        newPlayers.push(player);
    }
    players = newPlayers;
}, 100);

可以看到, 直线和方框不停的绘制, 一会就啥都看不见了

我们把 清空画板 的命令加上去

可以看到, 现在绘制就正常了

接下来还有一个问题, 数据怎么更新

更新数据

前面我们更新数据使用的是 setInterval

这个是定时器, 是不阻塞的, 依靠的是js本身的循环机制去更新数据;

但是一般我们用的是同步的写法, 也就是一步两步三步四步五步, 这样的;

我们来用代码模拟一下同步更新数据的效果

for (var i = 0; i < 10; i++) {
    sleep(1000);
    log("i = " + i);
    let newPlayers = [];
    for (var i = 0; i < playerCount; i++) {
        let playerWidth = random(30, 100);
        let playerHeight = 2 * playerWidth;
        let color = random(0, 1) ? "#ff0000" : "#00ff00";
        let player = new Player(
            random(0, dw),
            random(0, dh),
            playerWidth,
            playerHeight,
            color
        );
        newPlayers.push(player);
    }
    players = newPlayers;
}

运行日志

06-23 09:58:12.271 Script-61 Main [remote://main.js]/V: 开始运行[remote://main.js] 
06-23 09:58:13.290 Script-61 Main [remote://main.js]/D: i = 0 
06-23 09:58:13.293 Script-61 Main [remote://main.js]/V: 
------------
[remote://main.js]运行结束,用时1.021000秒 

我是循环10次,每次1秒钟;

但是日志里面,脚本1秒就结束了;

这是为什么?

我不理解???

经过三天两夜的排查, 发现问题是 变量提升, 因为内外两个循环都使用了 变量 i ;

把外部循环的 i 改成 j , 再次测试, 就没问题了

for (var j = 0; j < 100; j++) {
    sleep(100);
    let newPlayers = [];
    for (var i = 0; i < playerCount; i++) {
        let playerWidth = random(30, 100);
        let playerHeight = 2 * playerWidth;
        let color = random(0, 1) ? "#ff0000" : "#00ff00";
        let player = new Player(
            random(0, dw),
            random(0, dh),
            playerWidth,
            playerHeight,
            color
        );
        newPlayers.push(player);
    }
    players = newPlayers;
}

需要多线程吗

我一开始还以为要用多线程, 看来不用, canvas的绘制是跑在UI线程的, 更新数据的for循环是跑在非UI线程的;

他们是不会阻塞对方的

环境
雷电模拟器: 4.0.63

Android版本: 7.1.2

Autojs版本: 8.8.20

名人名言
思路是最重要的, 其他的百度, bing, stackoverflow, github, 安卓文档, autojs文档, 最后才是群里问问 --- 牙叔教程


声明
部分内容来自网络 本教程仅用于学习, 禁止用于其他用途

微信公众号 牙叔教程

猜你喜欢

转载自juejin.im/post/7112260991227789325