Javascript 如何解决弹性碰撞?
我一直在做一个弹性碰撞演示,但似乎不能完全正确。circle1对象似乎从曲面的一侧正确碰撞 circle2对象,但如果它们从另一侧碰撞,则会穿过circle2 如何修改此弹性碰撞以使其更精确 这里有一个链接,链接到一个实时演示 main.tsJavascript 如何解决弹性碰撞?,javascript,typescript,game-physics,Javascript,Typescript,Game Physics,我一直在做一个弹性碰撞演示,但似乎不能完全正确。circle1对象似乎从曲面的一侧正确碰撞 circle2对象,但如果它们从另一侧碰撞,则会穿过circle2 如何修改此弹性碰撞以使其更精确 这里有一个链接,链接到一个实时演示 main.ts class DemoCanvas { canvasWidth: number = 500; canvasHeight: number = 500; canvas: HTMLCanvasElement = document.creat
class DemoCanvas {
canvasWidth: number = 500;
canvasHeight: number = 500;
canvas: HTMLCanvasElement = document.createElement('canvas');
constructor() {
this.canvas.width = this.canvasWidth;
this.canvas.height = this.canvasHeight;
this.canvas.style.border = '1px solid black';
this.canvas.style.position = 'absolute';
this.canvas.style.left = '50%';
this.canvas.style.top = '50%';
this.canvas.style.transform = 'translate(-50%, -50%)';
document.body.appendChild(this.canvas);
}
clear() {
this.canvas.getContext('2d').clearRect(0, 0, this.canvas.width, this.canvas.height);
}
getContext(): CanvasRenderingContext2D {
return this.canvas.getContext('2d');
}
getWidth(): number {
return this.canvasWidth;
}
getHeight(): number {
return this.canvasHeight;
}
getTop(): number {
return this.canvas.getBoundingClientRect().top;
}
getRight(): number {
return this.canvas.getBoundingClientRect().right;
}
getBottom(): number {
return this.canvas.getBoundingClientRect().bottom;
}
getLeft(): number {
return this.canvas.getBoundingClientRect().left;
}
}
class Circle {
x: number;
y: number;
dx: number;
dy: number;
xVelocity: number;
yVelocity: number;
radius: number;
color: string;
canvas: DemoCanvas;
context: CanvasRenderingContext2D;
constructor(x: number, y: number, xVelocity: number, yVelocity: number, color: string, gameCanvas: DemoCanvas) {
this.radius = 20;
this.x = x;
this.y = y;
this.xVelocity = xVelocity;
this.yVelocity = yVelocity;
this.color = color;
this.canvas = gameCanvas;
this.context = this.canvas.getContext();
}
public draw(): void {
this.context.fillStyle = this.color;
this.context.beginPath();
this.context.arc(this.x, this.y, this.radius, 0, 2 * Math.PI);
this.context.fill();
}
public move(): void {
this.x += this.xVelocity;
this.y += this.yVelocity;
}
checkWallCollision(gameCanvas: DemoCanvas): void {
let top = 0;
let right = 500;
let bottom = 500;
let left = 0;
if(this.y < top + this.radius) {
this.y = top + this.radius;
this.yVelocity *= -1;
}
if(this.x > right - this.radius) {
this.x = right - this.radius;
this.xVelocity *= -1;
}
if(this.y > bottom - this.radius) {
this.y = bottom - this.radius;
this.yVelocity *= -1;
}
if(this.x < left + this.radius) {
this.x = left + this.radius;
this.xVelocity *= -1;
}
}
}
let demoCanvas = new DemoCanvas();
let circle1: Circle = new Circle(250, 250, 5, 5, "#F77", demoCanvas);
let circle2: Circle = new Circle(250, 540, 5, 5, "#7FF", demoCanvas);
function detectCollisions():void {
if (circle1.x + circle1.radius + circle2.radius > circle2.x
&& circle1.x < circle2.x + circle1.radius + circle2.radius
&& circle1.y + circle1.radius + circle2.radius > circle2.y
&& circle1.y < circle2.y + circle1.radius + circle2.radius) {
if (distanceTo() < circle1.radius + circle2.radius) {
calculateNewVelocities();
}
}
}
function distanceTo():Number {
var distance = Math.sqrt(((circle1.x - circle2.x) * (circle1.x - circle2.x)) + ((circle1.y - circle2.y) * (circle1.y - circle2.y)));
if (distance < 0) {
distance = distance * -1;
}
return distance;
}
function calculateNewVelocities():void {
var mass1 = circle1.radius;
var mass2 = circle2.radius;
var velX1 = circle1.xVelocity;
var velX2 = circle2.xVelocity;
var velY1 = circle1.yVelocity;
var velY2 = circle2.yVelocity;
var newVelX1 = (velX1 * (mass1 - mass2) + (2 * mass2 * velX2)) / (mass1 + mass2);
var newVelY1 = (velY1 * (mass1 - mass2) + (2 * mass2 * velY2)) / (mass1 + mass2);
circle1.xVelocity = newVelX1;
circle1.yVelocity = newVelY1;
circle1.x = circle1.x + newVelX1;
circle1.y = circle1.y + newVelY1;
}
addEventListener('mousemove', function(e) {
let mouseX = e.clientX - demoCanvas.getLeft();
let mouseY = e.clientY - demoCanvas.getTop();
circle2.x = mouseX;
circle2.y = mouseY;
});
function loop() {
demoCanvas.clear();
circle1.draw();
circle2.draw();
circle1.move();
circle1.checkWallCollision(demoCanvas);
circle2.checkWallCollision(demoCanvas);
detectCollisions();
requestAnimationFrame(loop);
}
requestAnimationFrame(loop);
classdemocanvas{
画布宽度:编号=500;
画布高度:编号=500;
canvas:htmlcanvaseElement=document.createElement('canvas');
构造函数(){
this.canvas.width=this.canvasWidth;
this.canvas.height=this.canvasHeight;
this.canvas.style.border='1px纯黑';
this.canvas.style.position='absolute';
this.canvas.style.left='50%';
this.canvas.style.top='50%';
this.canvas.style.transform='translate(-50%,-50%);
document.body.appendChild(this.canvas);
}
清除(){
this.canvas.getContext('2d').clearRect(0,0,this.canvas.width,this.canvas.height);
}
getContext():CanvasRenderingContext2D{
返回此.canvas.getContext('2d');
}
getWidth():数字{
返回此参数。画布宽度;
}
getHeight():编号{
返回此参数。画布高度;
}
getTop():编号{
返回此.canvas.getBoundingClientRect().top;
}
getRight():数字{
返回此.canvas.getBoundingClientRect().right;
}
getBottom():数字{
返回此.canvas.getBoundingClientRect().bottom;
}
getLeft():数字{
返回此.canvas.getBoundingClientRect().left;
}
}
班级圈子{
x:数字;
y:数字;
dx:数字;
dy:数字;
xVelocity:数字;
yVelocity:数字;
半径:数字;
颜色:字符串;
画布:演示画布;
上下文:CanvasRenderingContext2D;
构造函数(x:number,y:number,xVelocity:number,yVelocity:number,color:string,gameCanvas:DemoCanvas){
这个半径=20;
这个.x=x;
这个。y=y;
这个.xVelocity=xVelocity;
this.yVelocity=yVelocity;
这个颜色=颜色;
this.canvas=gameCanvas;
this.context=this.canvas.getContext();
}
公开提款():无效{
this.context.fillStyle=this.color;
this.context.beginPath();
this.context.arc(this.x,this.y,this.radius,0,2*Math.PI);
this.context.fill();
}
公共移动():无效{
这个.x+=这个.x速度;
this.y+=this.yVelocity;
}
checkWallCollision(游戏画布:DemoCanvas):无效{
设top=0;
设右=500;
设底部=500;
设左=0;
if(此.yright-this.radius){
this.x=右-this.radius;
这是0.xVelocity*=-1;
}
if(this.y>底部-this.radius){
this.y=底部-this.radius;
这个。yVelocity*=-1;
}
if(此.x<左+此半径){
此.x=左+此.radius;
这是0.xVelocity*=-1;
}
}
}
让demoCanvas=新建demoCanvas();
设圆1:圆=新圆(250,250,5,5,“#F77”,demoCanvas);
设圆圈2:圆圈=新圆圈(250、540、5、5、“#7FF”,demoCanvas);
函数detectCollisions():void{
如果(圈1.x+圈1.radius+圈2.radius>圈2.x
&&圆1.x<圆2.x+圆1.radius+圆2.radius
&&圆1.y+圆1.radius+圆2.radius>圆2.y
&&圆1.y<圆2.y+圆1.radius+圆2.radius){
if(distanceTo()
嗯,我不确定你是从哪里得到的公式来更新圆圈1
与圆圈2
碰撞时的速度,但这取决于两个圆圈的相对位置(不仅是它们之间的距离,还有接触角)
如果我们假设circle2
是静止的(或如此巨大以至于circle1
不会影响它的运动),那么calculatenewvelociations()
中的代码应该是这样的:
var xd = circle1.x - circle2.x; // x displacement between circles
var yd = circle1.y - circle2.y; // y displacement between circles
var dsq = xd*xd + yd*yd; // square of distance between circles
var DV = 2*(velX1*xd + velY1*yd)/dsq; // velocity change factor
// EDIT
// fix to prevent orbiting... if circle1 is already rebounding,
// leave it alone
if (DV > 0) {
DV=0;
}
// velocity change is in the opposite direction of
// the displacement between circles
var newVelX1 = velX1 - DV * xd;
var newVelY1 = velY1 - DV * yd;
当碰撞来自外部时,这会给你一些模糊合理的解释。如果你发现圆圈重叠,这可能会导致circle1
环绕circle2
或类似的疯狂行为,因此你可能想调整它以防止此类事情发生