Javascript Offscreencavas和touch事件

Javascript Offscreencavas和touch事件,javascript,canvas,html5-canvas,offscreen-canvas,Javascript,Canvas,Html5 Canvas,Offscreen Canvas,我正在尝试为OffScreenCanvas使用新的API。其想法是移动所有关于绘制和更新播放器数据的逻辑,但在主线程中保留一些其他逻辑,如触摸事件(因为工作人员无法到达窗口对象) 所以我有classPlayer.js export class Player { constructor() { this.width = 100; this.height = 100; this.posX = 0; this.posY = 0; } draw = (ctx

我正在尝试为OffScreenCanvas使用新的API。其想法是移动所有关于绘制和更新播放器数据的逻辑,但在主线程中保留一些其他逻辑,如触摸事件(因为工作人员无法到达窗口对象)

所以我有class
Player.js

export class Player {
  constructor() {
    this.width = 100;
    this.height = 100;
    this.posX = 0;
    this.posY = 0;
  }

  draw = (ctx) => {
    ctx.fillRect(this.posX, this.posY, this.width, this.height);
  }

  updatePos = (x, y) => {
    this.posX = x;
    this.posY = y;
  }
}
import { Player } from "./Player.js";

export const player = new Player();
我在另一个名为
playerObject.js的模块中生成播放器的实例

export class Player {
  constructor() {
    this.width = 100;
    this.height = 100;
    this.posX = 0;
    this.posY = 0;
  }

  draw = (ctx) => {
    ctx.fillRect(this.posX, this.posY, this.width, this.height);
  }

  updatePos = (x, y) => {
    this.posX = x;
    this.posY = y;
  }
}
import { Player } from "./Player.js";

export const player = new Player();
OffScreenCanvas是这样创建的

const canvas = document.querySelector('#myGame');
const offscreen = canvas.transferControlToOffscreen();
const worker = new Worker('offscreencanvas.js', { type: "module" });
worker.postMessage({ canvas: offscreen }, [offscreen]);
现在我将playerObject导入OffScreenCanvas worker

import {player} from "./playerObject.js";

addEventListener('message', (evt) => {
  const canvas = evt.data.canvas;
  const ctx = canvas.getContext("2d");

  const render = () => {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    player.draw(ctx);

    requestAnimationFrame(render);
  }

  render();
});
以及包含正在修改播放器位置的触摸事件的类(模块):

import {player} from "./playerObject.js";

export class Game {
  constructor() {
    this.touch();
  }

  touch = () => {
    window.addEventListener('touchstart', (e) => {
      player.updatePos(e.touches[0].clientX, e.touches[0].clientY);

    }, {passive: true});
  }
}
问题是OffScreenCanvas没有看到游戏类所做的更改。触摸本身正在工作(console.log显示事件和修改的玩家对象),但在OffScreenCanvas中,玩家仍有初始的协调

我仍然不确定那里发生了什么。工人正在创建一个新的类实例,这就是为什么它看不到来自触摸事件的更改


有没有办法做到这一点

有些事情你需要知道:

  • 每次从“/playerObject.js”导入{player}您将创建一个新的player实例。因此,它不会将CreenCanvasWorker模块与游戏模块连接起来
  • 与其在模块中创建玩家类的实例,不如全局创建它,然后将其放入游戏的构造函数参数和工作者的消息参数中
  • 我的意思是:

    播放器实例创建(全局) 屏幕外画布创作 内部屏幕外画布工作人员 内部游戏模块 如果您不喜欢这种方式,实际上有很多替代方法,但最重要的是您必须在模块中传输播放器实例对象,而不是它的类或新实例声明


    附加说明:以防万一你们不知道,在2020年,Offscreencavas仍处于试验阶段,若你们把它放到你们的在线广播网站上,那个将不是一个好主意。祝你好运

    有些事情你需要知道:

  • 每次从“/playerObject.js”导入{player}您将创建一个新的player实例。因此,它不会将CreenCanvasWorker模块与游戏模块连接起来
  • 与其在模块中创建玩家类的实例,不如全局创建它,然后将其放入游戏的构造函数参数和工作者的消息参数中
  • 我的意思是:

    播放器实例创建(全局) 屏幕外画布创作 内部屏幕外画布工作人员 内部游戏模块 如果您不喜欢这种方式,实际上有很多替代方法,但最重要的是您必须在模块中传输播放器实例对象,而不是它的类或新实例声明


    附加说明:以防万一你们不知道,在2020年,Offscreencavas仍处于试验阶段,若你们把它放到你们的在线广播网站上,那个将不是一个好主意。祝你好运

    您当前有两个不同的播放器实例,它们不会相互通信

    在草稿中,允许将一些事件从主线程传递到工作线程,但它实际上仍然只是一个草稿,我根本不确定它将在什么时候出现,也不确定它的具体形式

    目前,我们唯一的解决方案是在主线程和工作线程之间建立一座桥梁,以便主线程在事件发生时向工作线程发出所有事件。
    这有很多缺点,其中

    • 明显的延迟,因为在分派新的MessageEvent任务之前,我们必须等待主线程接收到事件
    • 对主线程的依赖性:它必须能够自由处理事件,这意味着OffscreenCanvas即使在主线程被锁定的情况下也可以顺利运行的承诺在这里被打破了
    • 难以维护(?)因为我们没有一个清晰的API来访问我们正在获取的目标,所以我们必须在主线程和工作线程中使用难看的硬编码值
    但是,我们仍然可以取得一些成就

    我刚刚花了一些时间写了一个粗略的游戏玩具,松散地基于我链接到的当前提议,有一些改动,没有测试,所以使用它作为基础来编写自己的,但不要期望它在任何情况下都能无缝工作

    基本逻辑是

    • 从主线程开始,我们增强了Worker接口,使其能够启动与Worker线程的私有通信通道(通过MessageChannel对象)
    • 我们还向该接口添加和
      addEventTarget(target,uuid)
      方法
    • 在工作线程中,当我们从主线程的脚本接收消息时,我们初始化一个接收器。从那里,我们保持MessageChannel并等待它说什么时候从主线程声明了新的delegatedTargets
    • 发生这种情况时,我们将触发一个新的eventtargetadded事件,工作线程中运行的用户脚本可以监听该事件,从而公开一个EventDelegate实例,该实例将在工作线程和主线程之间创建一个新的专用通信通道
    • 正是通过此EventDelegate的通道,主线程中的每个事件对象都将在经过清理后被克隆
    但是足够多的词汇和难以理解的解释,可能更清楚它的工作原理

    这是StackSnippet的实时版本,可能有点难读:

    //仅StackSnippet:建立工作脚本的内部路径
    const event_delegate_worker_script=document.getElementById('event delegate worker').textContent;
    const event_delegate_worker_url=generateScriptur(事件_delegate_worker_脚本);
    const user\u script\u worker\u script=document.getElementById('user script worker').textContent
    .replace(“event delegate worker.js”,event\u delegate\u worker\u url);
    const user_script_worker_url=generateScriptur(user_script_worker_script);
    函数生成器说明(内容){
    //Chrome拒绝导入cripts blob://URI。。。
    
    addEventListener('message', (evt) => {
      const canvas = evt.data.canvas;
      const player = evt.data.player;
      const ctx = canvas.getContext("2d");
    
      const render = () => {
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        player.draw(ctx);
    
        requestAnimationFrame(render);
      }
    
      render();
    });
    
    export class Game {
      constructor(player) {
        this.player = player;
        this.touch();
      }
    
      touch = () => {
        const player = this.player;
        window.addEventListener('touchstart', (e) => {
          player.updatePos(e.touches[0].clientX, e.touches[0].clientY);
    
        }, {passive: true});
      }
    }