簡體   English   中英

球從地板上彈起

[英]ball bouncing off the floor

有一個球以自由落體的速度下落。 我無法編寫使球撞擊表面並反彈的邏輯。 我希望物理接近真實

請幫助解決問題。 先感謝您)

下面是代碼;)

 window.onload = () => { const out = document.getElementById('out') const ctx = document.getElementById('canvas').getContext('2d'); let metr = 0.1; let seconds = 1000; let speed = 9.8; const vector = { x: 0, y: 1} const position = {x: 300, y: 0} function draw(timeDelta) { ctx.clearRect(0, 0, 600, 600) const dX = (vector.x * (metr * (timeDelta / seconds) * speed) || 0) const dY = (vector.y * (metr * (timeDelta / seconds) * speed) || 0) position.x += dX position.y += dY out.innerText = `${position.x}, ${position.y}, ${dX}, ${dY}` ctx.beginPath(); ctx.arc(position.x, position.y, 5, 0, Math.PI * 2, true); ctx.fill(); ctx.lineWidth = 10; ctx.moveTo(0, 550); ctx.lineTo(600, 550); ctx.stroke(); window.requestAnimationFrame(draw) } draw(); }
 canvas { width: 100%; height: 80vh; background: gray }
 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width"> <title>JS Bin</title> </head> <body> <div id="out">Out</div> <canvas id="canvas" width="600" height="600"></canvas> </body> </html>

 var dropBall = new janvas.Canvas({ container: "#app", interval: 16, // animation loop interval props: { background: void (0), ball: void (0) // target object }, methods: { init: function () { this.background = new janvas.Rect(this.$ctx, 0, 0); // init background this.background.getStyle().setFillStyle("white").setLineWidth(10); // set style this.ball = new janvas.Arc(this.$ctx, 0, 50, 50); // init target ball this.ball.vy = 0; // velocity y this.ball.g = 1; // acceleration this.$raf.start(); // start the default animation with requestAnimationFrame }, update: function () { this.ball.vy += this.ball.g; // every loop velocity += acceleration this.ball.setStartY(this.ball.getStartY() + this.ball.vy); // set ball position if (this.ball.getStartY() + this.ball.getRadius() > this.$height) { this.ball.setStartY(this.$height - this.ball.getRadius()); this.ball.vy *= -1; // if ball touch the bottom, inverse velocity y } this.onPositionChange(this.ball.getStartX(), this.ball.getStartY()); // position callback }, draw: function () { this.background.fillStroke(); // draw the background and stroke this.ball.fill(); // draw the ball } }, events: { resize: function () { // change some props on resize this.ball.setStartX(this.$width / 2); this.background.setWidth(this.$width).setHeight(this.$height); }, onPositionChange: janvas.Utils.noop } }); var p = document.querySelector("p"); dropBall.onPositionChange = function (x, y) { p.innerHTML = x + "," + y; };
 html, body { margin: 0; padding: 0; width: 100%; height: 100%; }
 <script src="https://cdn.jsdelivr.net/npm/janvas/dist/janvas.min.js"></script> <p></p> <div id="app" style="width: 100%;height: 100%;"></div>

這是我不久前設置的一個小型物理模擬的碰撞檢測代碼。

在你的世界似乎由一個圓圈或球體和一個平面組成的地方,除了牆壁和天花板之外,我還有許多粒子。 我的所有 4 個平面都是軸對齊的,並且距離原點 0.75 個單位。

每個粒子都包含一些關於它們自己的信息,我用於邊界框的平面也是如此。

class particle
{
    constructor( pos=new vec2d(0,0), vel=new vec2d(0), restCoef=1 )
    {
        this.mPos = vec2d.clone(pos);
        this.mVel = vec2d.clone(vel);
        this.mCoefRest = restCoef;
    }
    get pos(){return this.mPos}
    set pos(newPos){this.mPos.setTo(newPos)}
    get vel(){return this.mVel}
    set pos(newVel){this.mVel.setTo(newVel)}
    get restCoef(){return this.mCoefRest;}
    set restCoef(newCoef){this.mCoefRest = newCoef;}
};

class plane
{
    constructor(normalX, normalY, distToOrigin)
    {
        this.mNormal = new vec2d(normalX,normalY);
        this.mDist = distToOrigin;
    }
    get dist(){return this.mDist;}
    set dist(newDist){this.mDist = newDist;}
    get normal(){return this.mNormal;}
    set normal(newNormal){this.mNormal.setTo(newNormal);}
}

更新循環完全是微不足道的,繪制移動和碰撞每一幀。

function update2()
{
    drawParts(partArray);
    move(partArray, 1/60);
    handleCollisions2(partArray);
    requestAnimationFrame(update2);
}

我想你會發現所有有趣的東西都存在於代碼中,用於移動和碰撞粒子。

function move(parts, timeStep)  // array, seconds
{
    parts.forEach(
        function(part)
        {
            var grav = new vec2d(0,-9.8);
            grav.timesEquals(1/60);     // should be timeStep, not 1/60 (I had timeStep = 1/60)                                                                                 
            part.vel.plusEquals(grav);
            var dist = part.vel.clone();
            dist.timesEquals(timeStep);
            part.pos.plusEquals(dist);
            part.vel.timesEquals(0.99);
        }
    )
}

你可以看到我從來沒有時間去實現我所有的想法。 我什至從不觸摸這里輸入的平面,而是像我一樣組成一個邊界框 go..

function handleCollisions2(parts, planes)
{
    var planeArray=[];
    planeArray.push( new plane(1,  0, 0.75) );
    planeArray.push( new plane(0, -1, 0.75) );
    planeArray.push( new plane(-1, 0, 0.75) );
    planeArray.push( new plane(0,  1, 0.75) );
    partArray.forEach(
        function(part,idx)
        {
            planeArray.forEach(
                function(plane)
                {
                    var N = plane.normal;
                    var dist = part.pos.dotProd(plane.normal) + plane.dist;
                    var dp = part.vel.dotProd(N);
                    if (dist<0 && dp < 0)   // wrong side of plane and penetrating further (not moving away)
                    {
                      // collision response, reflect particle
                      var nDotV = vec2d.clone(plane.normal);
                      //nDotV.timesEquals(2);
                      nDotV.timesEquals(1+part.restCoef);
                      nDotV.timesEquals(dp);
                      
                      part.vel.minusEquals(nDotV);
                      
                      var tmpN = plane.normal.clone();
                      part.pos.minusEquals( tmpN.timesEquals(dist) );
                      //V[i] -= 2*N*N•V[i];
                      //console.log('.');   
                    }
                }
            );
        }
    );
}

這是我的解決方案

 window.onload = () => { const out = document.getElementById('out') const ctx = document.getElementById('canvas').getContext('2d'); var dpi = (document.getElementById('dpi').offsetWidth * 2.54) const m = 1 / dpi; const w = 600, h = 600, r = 5; const box = [10, 10, h - 10, w - 10] const g = 9.8 * m; const speed = { x: -1350 * m, y: -560 * m } const friction = 0.95 const position = {x: (box[2] - box[0]) / 2, y: (box[2] - box[0]) / 2 } let i = 0; function draw(timeDelta) { ctx.clearRect(0, 0, 600, 600) ctx.strokeStyle = "black"; speed.y += (g * m * timeDelta) || 0 // speed.x += (m * timeDelta) || 0 position.y = Math.max(box[1] + r, Math.min(box[3] - r, position.y + speed.y)); position.x = Math.max(box[0] + r, Math.min(box[2] - r, position.x + speed.x)); if (position.y + r >= box[3] || position.y - r <= box[1]) { speed.y = -(speed.y * friction) speed.x = speed.x * friction } if (position.x + r >= box[2] || position.x - r <= box[0]) { out.innerText = ++i speed.y = speed.y * friction speed.x = -(speed.x * friction) } //out.innerText = `${Math.round(position.y)}, ${Math.round(position.x)}, ${Math.round(speed.y * 1000) / 1000}, ${Math.round(speed.x * 1000) / 1000}` ctx.beginPath(); ctx.arc(position.x, position.y, r, 0, Math.PI * 2, true); ctx.fill(); ctx.lineWidth = 1; ctx.moveTo(box[0], box[1]); ctx.lineTo(box[2], box[1]); ctx.lineTo(box[2], box[3]); ctx.lineTo(box[0], box[3]); ctx.lineTo(box[0], box[1]); ctx.strokeStyle = "white"; ctx.stroke(); window.requestAnimationFrame(draw) } draw(); }
 canvas { width: 100%; height: 80vh; background: gray }
 <:DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width"> <title>JS Bin</title> </head> <body> <div id="out">Out</div> <div id="dpi" style="height; 1in: width; 1in: left; 100%: position; fixed: top; 100%:pointer-events:none"></div> <canvas id="canvas" width="600" height="600"></canvas> </body> </html>

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM