Canvas/JS:计算倾斜斜坡碰撞中物体的新速度矢量?

2023-12-02

好吧,我正在 JS/Canvas 上开发弹球游戏,我想知道如何处理鳍状肢和球之间的碰撞。

我可以让脚蹼击球,但我对如何通过不同的脚蹼位置(角度)改变球的速度方向感到困惑。以下是我可以从脚蹼和球中使用的信息:

this.ballPosX = ballPosX;
this.ballPosY = ballPosY;
this.ballVelX = 0;
this.ballVelY = 0;

// thruster is a line shape with a variable end Y position
ctx.moveTo(125, 480);
ctx.lineTo(215, this.posY);

顺便说一句,我没有计算鳍状肢的速度。我只想知道如何根据线的斜率改变球速度矢量导向器。谢谢!


反射矢量

作为反射矢量的基本反弹很容易实现。

给定一条线

const line = {  // numbers are arbitrary
   p1 : { x : 0, y : 0 },
   p2 : { x : 0, y : 0 }
}

和一个球

const ball = {
   pos : { x : 0, y: 0},
   radius : 0,
   delta : { x : 0, y : 0},  // movement as vector
}

首先将线条转换为更易于管理的形式

 line.vec = {};  // get vector for the line
 line.vec.x = line.p2.x - line.p1.x;
 line.vec.y = line.p2.y - line.p1.y;
 // get line length
 line.len = Math.sqrt(line.vec.x * line.vec.x + line.vec.y * line.vec.y);
 // the normalised vector (1 unit long)
 line.vnorm = {};
 line.vnorm.x = line.vec.x / line.len;
 line.vnorm.y = line.vec.y / line.len;

同时标准化球增量

ball.speed = Math.sqrt(ball.delta.x * ball.delta.x + ball.delta.y * ball.delta.y);
ball.dnorm = {};
ball.dnorm.x = ball.delta.x / ball.speed;
ball.dnorm.y = ball.delta.y / ball.speed;

现在反射使用向量

// ball velocity vector line normal dot product times 2
var dd = (ball.dnorm.x * line.vnorm.x + ball.dnorm.y * line.vnorm.y) * 2
ball.ref = {}; // the balls reflected delta
ball.ref.x = line.vnorm.x * dd - ball.dnorm.x;
ball.ref.y = line.vnorm.y * dd - ball.dnorm.y;

反射矢量只需要标准化,然后乘以球速减去击球线时的任何能量损失。

var len = Math.sqrt(ball.ref.x * ball.ref.x + ball.ref.y * ball.ref.y);
ball.delta.x = (ball.ref.x / len) * ball.speed; // I have kept the same speed.
ball.delta.y = (ball.ref.y / len) * ball.speed;

Demo

由于我的数学计算不是 100% 正确,所以我认为最好通过演示进行检查。我忘了这有多复杂。

演示显示了移动的线,但该运动并未转移到球上。

var W,H; // canvas width and height
// get the canvas context
const ctx = canvas.getContext("2d");
const gravity = 0.19;
function vec(x,y){return {x,y}}

const line = {  
   p1 : { x : 0, y : 0 },
   p2 : { x : 0, y : 0 },
   vnorm : { x : 0, y : 0 }, // normalied vector
   vec : { x : 0, y : 0 }, // line as a vector
   len : 0,   
   update(){
     this.vec.x = this.p2.x - this.p1.x;
     this.vec.y = this.p2.y - this.p1.y;
     this.len = Math.sqrt(this.vec.x * this.vec.x + this.vec.y * this.vec.y);
     this.vnorm.x = this.vec.x / this.len;
     this.vnorm.y = this.vec.y / this.len;
   },
   draw(){
      ctx.beginPath();
      ctx.moveTo(this.p1.x,this.p1.y);
      ctx.lineTo(this.p2.x,this.p2.y);
      ctx.stroke();
   },
   testBall(ball){  // line must be updated befor this call
       // line is one sided and ball can only approch from the right
       // find line radius distance from line
       var x = this.p1.x + this.vnorm.y * ball.radius;
       var y = this.p1.y - this.vnorm.x * ball.radius;
       x = ball.pos.x - x;
       y = ball.pos.y - y;
       // get cross product to see if ball hits line
       var c = x * this.vec.y - y * this.vec.x;
       if(c <= 0){ // ball has hit the line

            // get perpendicular line away from line
            var ox = this.vnorm.y * ball.radius
            var oy = -this.vnorm.x * ball.radius
            // get relative ball pos
            var px = ball.pos.x - (this.p1.x + ox);
            var py = ball.pos.y - (this.p1.y + oy);
            // find ball position that contacts the line
            var ld = (px * this.vec.x + py * this.vec.y)/(this.len * this.len);
            ball.pos.x  = this.vec.x * ld + (this.p1.x+ox);
            ball.pos.y = this.vec.y * ld + (this.p1.y+oy);            
            // find the reflection delta (bounce direction)
            var dd = (ball.dnorm.x * this.vnorm.x + ball.dnorm.y * this.vnorm.y) * 2;
            ball.delta.x = this.vnorm.x * dd - ball.dnorm.x;
            ball.delta.y = this.vnorm.y * dd - ball.dnorm.y;
            
            // the ball has lost some speed (should not have but this is a fix)
            
           var m = Math.sqrt(ball.delta.x * ball.delta.x + ball.delta.y * ball.delta.y);
            ball.delta.x = (ball.delta.x / m) * ball.speed;
            ball.delta.y = (ball.delta.y / m) * ball.speed;
            
            ball.updateContact();
            ball.col = "red";
       
       }
   }
}



// create a ball
function createLine(x,y,x1,y1){
    var l = Object.assign({},line,{
       p1 : vec(x,y),
       p2 : vec(x1,y1),
       vec : vec(0,0),
       vnorm : vec(0,0),
    
    });
    l.update();
    return l;
}
const lines = {
   items : [],
   add(line){ lines.items.push(line); return line },
   update(){
        var i;
        for(i = 0; i < lines.items.length; i++){
            lines.items[i].update();
        }
        return lines;
    },
   draw(){
        var i;
        for(i = 0; i < lines.items.length; i++){
            lines.items[i].draw();
        }
        return lines;
    },
    testBall(ball){
        var i;
        for(i = 0; i < lines.items.length; i++){
            lines.items[i].testBall(ball);
        }
        return lines;
    }
    

};

var ball = {
   pos : { x : 0, y: 0},
   radius : 0,
   speed : 0,
   col : "black",
   delta : { x : 0, y : 0},  // movement as vector
   dnorm : { x : 0, y: 0},  // normalised delta
   updateContact(){ // update after ball hits wall
      this.speed = Math.sqrt(this.delta.x * this.delta.x + this.delta.y * this.delta.y);
      this.dnorm.x = this.delta.x / this.speed;
      this.dnorm.y = this.delta.y / this.speed;   
   },
   update(){
      this.col = "black";
      this.delta.y += gravity;
      this.pos.x += this.delta.x;
      this.pos.y += this.delta.y;
      this.speed = Math.sqrt(this.delta.x * this.delta.x + this.delta.y * this.delta.y);
      this.dnorm.x = this.delta.x / this.speed;
      this.dnorm.y = this.delta.y / this.speed;   
   },
   draw(){
      ctx.strokeStyle = this.col;
      ctx.beginPath();
      ctx.arc(this.pos.x,this.pos.y,this.radius,0,Math.PI*2);
      ctx.stroke();
   },
}
// create a ball
function createBall(x,y,r){
    var b = Object.assign({},ball,{
      pos : vec(x,y),
      radius : r,
      delta : vec(0,0),
      dnorm : vec(0,0),
    });
    return b;
}

const balls = {
    items : [],
    add(b){
        balls.items.push(b);
    },
    update(){
        var i;
        for(i = 0; i < balls.items.length; i++){
            balls.items[i].update();
            lines.testBall(balls.items[i]);
            if(balls.items[i].pos.y - balls.items[i].radius > canvas.height ||
              balls.items[i].pos.x < -50 || balls.items[i].pos.x - 50  > W){
                balls.items.splice(i--,1);
            }
        }
        return balls;
    },
    draw(){
        var i;
        for(i = 0; i < balls.items.length; i++){
            balls.items[i].draw();
        }
        return balls;
    }
}
    




const l1 = lines.add(createLine(0,0,100,100)); 
const l2 = lines.add(createLine(0,0,100,100)); 
const mouse = { x : 0, y : 0};
canvas.addEventListener("mousemove",(e)=>{
   mouse.x = e.pageX;
   mouse.y = e.pageY;
})


function mainLoop(time){
    // resize if needed
    if(canvas.width !== innerWidth || canvas.height !== innerHeight){ // resize canvas if window size has changed
        W = canvas.width = innerWidth;
        H = canvas.height = innerHeight;
    }
    // clear canvas 
    ctx.setTransform(1,0,0,1,0,0); // set default transform
    ctx.clearRect(0,0,W,H); // clear the canvas
    if(balls.items.length < 10){
        balls.add(createBall(Math.random() * W , Math.random() * 30, Math.random() * 20 + 10));

    }

    time /= 5;
    l1.p1.x = 0;
    l1.p2.x = W ;
    l2.p1.x = 0;
    l2.p2.x = W ;
    l1.p1.y = Math.sin(time / 1000) * H * 0.4 + H * 0.6;
    l1.p2.y = Math.cos(time / 1000) * H * 0.4 + H * 0.6;
    l2.p1.y = Math.sin(time / 500) * H * 0.4 + H * 0.6;
    l2.p2.y = Math.cos(time / 500) * H * 0.4 + H * 0.6;
    lines.update().draw(); 
    balls.update().draw();    


    // get next animation loop
    requestAnimationFrame(mainLoop);
}
requestAnimationFrame(mainLoop);
canvas {
    position : absolute;
    top : 0px;
    left : 0px;
    z-index : -10;
}
<canvas id=canvas></canvas>
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Canvas/JS:计算倾斜斜坡碰撞中物体的新速度矢量? 的相关文章

  • 使用 ReactJS 旋转图像预览

    我正在尝试使用 ReactJS 旋转图像的预览 因此 我首先允许渲染预览的上传功能 然后在用户点击上传之前 我希望他们可以选择根据自己的喜好旋转图像 这是我用来预览图像的 class ImageUpload extends React Co
  • HTML5 Canvas - 在画布上绘图、保存上下文并稍后恢复

    要求 现在 在画布上绘制 然后点击 保存 存储画布状态 离线绘制 但不作为图像 稍后 打开画布并显示之前保存的绘图 然后继续再次绘制 对于绘图 我们通常使用如下代码 canvas document getElementById can ct
  • 范围滑块 javascript 以小时和分钟为单位

    我试图分别以小时和分钟为单位显示滑块的值 我对 JS 还很陌生 并且仍在尝试了解它是如何工作的 到目前为止 我所拥有的是一个工作滑块 其最大值为 1440 24 小时内的分钟 在 JS 中 我尝试将其划分为小时和分钟 并使用 innerHt
  • 为什么 Bootstrap 按钮下拉菜单在 iOS 上不起作用?

    看起来甚至连引导演示在这里 http twitter github com bootstrap components html buttonDropdowns不适用于 iOS 您似乎无法在 iPhone 或 iPad 上从中选择项目 有解决
  • iPhone Web 应用程序禁用缓存

    我使用 PHP 构建了一个 iPhone 网络应用程序 主 也是唯一 页面包括苹果移动网络应用程序支持 and 苹果触摸全屏元标记 以便在添加到主屏幕后可以全屏运行 然而 似乎每次我从主屏幕启动应用程序时 都会使用页面的缓存版本而不是刷新页
  • 切换 Ag-Grid 中的浮动过滤器?

    我试图通过开关或按钮单击来确定浮动过滤器的显示 看起来很简单 我应该能够在 true 和 false 之间切换 将该值提供给网格选项中的浮动过滤器 然后刷新标题 对吗 不幸的是 网格似乎总是落后一步 当我第一次点击时 什么也没有发生 当我将
  • Karma Webpack - 错误:找不到模块“./test/utilities.js”

    我正在使用 Karma Webpack 进行项目的单元测试 当我跑步时karma start 我有这个错误 Error Cannot find module test utilities js at myproject test campa
  • 在浏览器开发工具中看不到SignalR流量

    我构建了使用 SignalR 的服务器和客户端代码 该网站运行完美 但我无法在任何浏览器 chrome IE Firefox 中看到网络流量 我知道网络流量在那里 因为该网站正在运行 有没有办法在浏览器中查看 SignalR 流量 如果不是
  • Array.from 的时间复杂度

    时间复杂度是多少Array from 例如 const set new Set set add car set add cat set add dog console log Array from set time complexity o
  • 如何在 Electron 中使窗口大小响应。 (打开应用程序时)

    我最近开始在 Electron 上制作一个应用程序 我想让窗口具有响应能力 例如 如果我在不同的屏幕上打开应用程序 它应该根据屏幕尺寸以全尺寸打开 我的代码 app on ready gt const htmlPath path join
  • 如何拆分字符串,在特定字符处断开?

    我有这个字符串 john smith 123 Street Apt 4 New York NY 12345 使用 JavaScript 将其解析为最快的方法是什么 var name john smith var street 123 Str
  • 链接index.html client.js 和 server.js

    我从 Node js 开始 我的第一个程序已经遇到了问题 下面是我正在使用的代码 索引 html
  • Backbone.View:delegateEvents 未将事件重新绑定到子视图

    我已将这个问题分解为尽可能小的示例 即 它只是为了演示问题 不一定代表现实世界的场景 假设我有一个父视图 此处为 MainView 其中包含一个子视图 此处为 SubView 如果在任何时候我需要重新渲染父视图 从而重新渲染子视图 我就会丢
  • 使用预先存在的数据库创建 PhoneGap iOS 应用程序

    我最近开始开发一个使用 PhoneGap 版本 2 8 0 作为药物查找器的应用程序 过去 我创建了该工具的 Web 版本 它使用 jQuery Mobile 和 PHP 来访问远程 SQL 数据库 PhoneGap 似乎是一个很有吸引力的
  • 如何使用 $.ajax 发送 JSON 而不是查询字符串?

    有人可以简单地解释一下如何让 jQuery 发送实际的 JSON 而不是查询字符串吗 ajax url url dataType json I was pretty sure this would do the trick data dat
  • ag-Grid 中的行格式

    我们需要有条件地将行文本设置为粗体 目前它仅适用于单个单元格 但我们需要在所有列单元格上应用文本粗体 应用格式设置后 isBold 列必须隐藏 删除 此列仅用于格式化 如何应用文本缩进 10px isBold 列包含真实值的第一列的 有可能
  • CORS:为什么我的浏览器不发送 OPTIONS 预检请求?

    从我读到的内容来看CORS https en wikipedia org wiki Cross origin resource sharing 我理解它应该按如下方式工作 客户端的脚本尝试获取资源从服务器不同的起源 浏览器拦截这个请求并首先
  • Firefox 本地主机上的 Twilio 屏幕共享?

    目前 Firefox 中本地主机上的屏幕共享会引发以下错误 The request is not allowed by the user agent or the platform in the current context 这是我的代码
  • jQuery:array[i].children() 不是函数

    以下代码的灵感来自http ignorethecode net blog 2010 04 20 footnotes http ignorethecode net blog 2010 04 20 footnotes 当您将光标移到脚注符号上时
  • 如何防止外部 CSS 添加和覆盖 ReactJS 组件样式

    我有一个自定义的 ReactJS 组件 我想以某种方式设置样式 并将其作为插件提供给许多不同的网站 但是 当网站使用全局样式 Twitter bootstrap 或其他 css 框架 时 它会添加并覆盖我的组件的样式 例如 全局 css l

随机推荐

  • 64 位 ALU 输出在 TestBench 波上显示高阻抗

    我必须制作一个 64 位 ALU 它接受 A 和 B 64 位输入 进位输入输入并输出 64 位结果以及 1 位进位输出 还有一个 5 位功能选择 FS 其中 FS 0 控制 B 是否反转 使用 2to1 多路复用器 F 1 对 A 执行相
  • Java GUI 应用程序控制器中的 ActionListener 是个好主意吗?

    我不想遵循 MVC 模式 在互联网上 我看到最著名的例子是计算器 例如here 我开始使用MVC模式的这种实现 但现在我对控制器中的动作侦听器有一些疑问 因为它们倾向于移动到视图 主要原因是有很多与视图相关的变化 字体 颜色 边框等 此外还
  • 使用中心插件将 jQuery 中心元素置于视口

    我目前正在使用 jQuery center 插件来居中我的 div 元素 到目前为止 它的工作范围已经达到了将其居中到包含父容器的位置 我想要它做的是将其居中到当前浏览器视口中心 那怎么办呢 我的设置是一个简单的链接 单击时会弹出一个 di
  • 在 Spring Boot 项目中启用 Multimap 的 json 序列化

    我想在 Spring Boot 应用程序中序列化一些 google guava Multimap public class SomeDTO JsonProperty Multimap
  • 错误 - ListenerManager 无法初始化 httpstransport 侦听器 - WSO2

    我启动了 WSO2 API Manager 1 8 的新副本 但无缘无故地出现以下错误 ERROR ListenerManager Couldn t initialize the httpstransport listener 我怎样才能解
  • 如何使表单(html、jsp)中的文本字段仅接受 dd/mm/yyyy 格式而不单击提交按钮

    我在 jsp 表单页面中有一个字段 它接受 起始日期 和 截止日期 现在我知道了可用于使用提交按钮验证这一点的脚本代码 但我的字段目前接受任何形式的 10 个字符 例如 28 07 2000 或 2807 2 00 它接受数字和任意数量的
  • 将 LINQ 结果送入 DataROW

    这有效 var Result from e in actual Elements select new Key e Key ValueNumber e Value ValueNumber ValueString e Value ValueS
  • 是否有支持默认属性值的 XML Schema 验证库?

    如果我读到默认属性值的 XML 模式规范正确的是 验证过程实际上应该更改 DOM 以填充默认值 default 指定该属性无条件出现在 模式验证后信息集中 这是对规范的正确解读吗 更重要的是 是否有任何库 Java C Python 等 支
  • 如何使用 __doPostBack()

    我正在尝试使用 ASP NET 创建异步回发 doPostBack 但我不知道该怎么做 我想使用普通 JavaScript 像单击按钮这样简单的事情可能会导致 doPostBack 触发事件 我只是想了解这个机制是如何运作的 您可以在 We
  • 将数据帧索引转换为日期时间

    如何将 pandas 字符串索引转换为日期时间格式 我的数据框df是这样的 value 2015 09 25 00 46 71 925000 2015 09 25 00 47 71 625000 2015 09 25 00 48 71 33
  • XmlTypeAttribute 仅适用于类中的属性

    我正在尝试使用 webservice 将其解析为 XML System Xml Serialization XmlTypeAttribute Namespace http www xx com zz Domain Public class
  • 如何在 FastAPI 中使用带有表单数据的 Pydantic 模型?

    我正在尝试从 HTML 表单提交数据并使用 Pydantic 模型对其进行验证 使用此代码 from fastapi import FastAPI Form from pydantic import BaseModel from starl
  • ggmap 400 错误请求

    我以前用过这个 而且一直有效 library ggmap newmap2 lt get openstreetmap bbox c left 71 2612362452596 bottom 42 3308503846824 right 71
  • 如何使Google电子表格的所有工作表在左上角显示A1?

    我有一个 72 页的 Google 电子表格 我正在尝试重置每个工作表 以便当您单击其选项卡时 它会在左上角显示 A1 也就是说 如果向下滚动一张工作表以致您看不到 A1 我希望它向后滚动以便您可以看到 我已经尝试过以下谷歌脚本 但没有任何
  • 创建独立的jar文件

    我已经建立了一个jar使用 Netbeans 创建文件 它在我的系统中运行良好 但我想做jar能够在所有具有 JRE 的系统中运行的文件 即使是classpath没有在该系统中设置 package circle import java aw
  • 使用静态成员变量时出现链接器错误

    我已经在这里浏览了与静态成员变量相关的所有线程 但不幸的是这无法帮助我找出原因 这就是问题 定义一个类名dvd db 包括以下成员 数据成员 DVD 名称 私有字符数组 大小 10 价格 私有双变量 数量 私有 int 变量 一个私有静态
  • 分析是什么以及如何分析我的 Java 程序?

    我听说过很多关于剖析的事情 这是怎么回事 据我了解 这是某种绩效衡量 但有人可以更清楚地阐述这一点 以便新手能够掌握这个想法 另外 我将 Eclipse IDE 用于我的 Java 程序 我可以使用 Eclipse IDE 分析我的程序吗
  • Pandas read_csv 在解析数字时忽略美元符号

    我有一个 csv 文件 其中一些单元格带有美元符号 例如 46 5 我强迫所有类型都是numpy float64在函数中pandas read csv 它抱怨ValueError could not convert string to fl
  • 如何修复 IE7 浮动清除组合

    我有一个 field wrapper 类 div 其中包含 3 个子 div field label field input 和 field error 我需要将 field label field input 并排放置 并将 field
  • Canvas/JS:计算倾斜斜坡碰撞中物体的新速度矢量?

    好吧 我正在 JS Canvas 上开发弹球游戏 我想知道如何处理鳍状肢和球之间的碰撞 我可以让脚蹼击球 但我对如何通过不同的脚蹼位置 角度 改变球的速度方向感到困惑 以下是我可以从脚蹼和球中使用的信息 this ballPosX ball