简体   繁体   English

Javascript画布-对角弹跳球

[英]Javascript Canvas - Bouncing ball diagonally

So basically I am trying to add bounce to a ball updating the x and y position rather than rotating the canvas. 因此,基本上,我正在尝试向球添加弹跳,以更新x和y位置,而不是旋转画布。

Is this possible, simply? 这可能吗?

Here is what I have, which does the up, down, left and right correctly. 这是我所拥有的,可以正确地上下左右移动。 But the diagonal ones obviously need a little bit more work. 但是对角线显然需要更多的工作。

kick: function(fps, dir, settings){

        var options = {
            speed: 15,
            gravity: .98,
            friction: .99,
            airDrag: .98,
            elasticity: .8,
            angle: 340,
            radius: this.sWidth
        }

        options = deepExtend(options, settings);

        var radians = options.angle * Math.PI/ 180,
            vx = Math.sin(radians) * options.speed,
            vy = Math.cos(radians) * options.speed;

        this.ballStartPosX = this.ball.pos[0];
        this.direc = dir;

        this.vx = vx;
        this.vy = vy;
        this.friction = options.friction;
        this.airDrag = options.airDrag;
        this.elasticity = options.elasticity;
        this.gravity = options.gravity;

        this.shootBall = setInterval(this.shoot.bind(this), fps);
    },

shoot: function () {
        this.ball.pos[0] += this.vx;

        switch(this.direc.toString()) {
            case 'up': this.ball.pos[1] -= this.vy;
            break;
            case 'down': this.ball.pos[1] += this.vy;
            break;
            case 'left': this.ball.pos[0] -= this.vy;
            break;
            case 'right': this.ball.pos[0] += this.vy;
            break;
            case 'up,right': this.ball.pos[1] -= this.vy; this.ball.pos[0] += this.vy;
            break;
            case 'up,left': this.ball.pos[1] -= this.vy; this.ball.pos[0] -= this.vy;
            break;
            case 'down,right': this.ball.pos[1] += this.vy; this.ball.pos[0] += this.vy;
            break;
            case 'down,left': this.ball.pos[1] += this.vy; this.ball.pos[0] -= this.vy;
            break;
        }

        if (this.ball.pos[0] > this.ballStartPosX) {
            this.ball.pos[0] = this.ballStartPosX;
            this.vx = -(this.vx)*this.elasticity;
        }

        this.vx += this.gravity;


        if (this.ball.pos[0] >= this.ballStartPosX) {
            this.vy *= this.friction;
        }


        var speed = Math.sqrt(this.vx*this.vx + this.vy*this.vy);

        if (speed < this.friction) {
            speed = 0;
            clearInterval(this.shootBall);
        }


    }

this is what i want to achieve 这就是我想要实现的

在此处输入图片说明

I was thinking maybe if I drew an invisible diagonal line and used that as the touch point. 我在想,如果我画一条不可见的对角线并将其用作接触点。 Would that work? 那行得通吗?

The simplest solution is to use a rotated quadratic curve. 最简单的解决方案是使用旋转的二次曲线。

BTW, why did you dismiss this simplest solution? 顺便说一句,您为什么不考虑这个最简单的解决方案?

Anyway... 无论如何...

The "manual" solution without canvas rotation can be done with simple math, but requires many small steps. 无需画布旋转的“手动”解决方案可以通过简单的数学来完成,但需要许多小步骤。

The solution involves calculating the 3 controls points of a quadratic curve and then animating your ball along that quadratic curve. 解决方案包括计算二次曲线的3个控制点,然后沿二次曲线对球进行动画处理。

Here's example annotated code and a Demo: http://jsfiddle.net/m1erickson/gQ8RC/ 这是带注释的示例代码和演示: http : //jsfiddle.net/m1erickson/gQ8RC/

This code does 1 bounce but is repeatable for multiple bounces. 此代码执行1次跳动,但可重复多次跳动。

// get references to the canvas and its context
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");

// save PI*2 to a variable since it's used often
var PI2=Math.PI*2;

// declare the starting and ending points of an imaginary line
var p1={x:20,y:250};
var p2={x:200,y:200};

// declare where a bounce will start & end along that line
// pct1==20%==bounce starts 20% of the way between p1 & p2
// pct2==60%==bounce ends 60% of the way between p1 & p2
var pct1=0.20;
var pct2=0.60;

// calculate deltaX & deltaY of an imaginary line
// containing starting point (p1) & ending point (p2)
var dx=p2.x-p1.x;
var dy=p2.y-p1.y;

// calculate starting point of bounce (20% from p1 towards p2)
var x1=p1.x+dx*pct1;
var y1=p1.y+dy*pct1;

// calculate ending point of bounce (60% from p1 towards p2)
var x2=p1.x+dx*pct2;
var y2=p1.y+dy*pct2;

// calculate mid point of bounce ((60-20)/2% from p1 towards p2)
var pctMidpoint=pct1+(pct2-pct1)/2;
var midX=p1.x+dx*pctMidpoint;
var midY=p1.y+dy*pctMidpoint;

// define a distance (d) for the control point of a quadratic curve
// d will indirectly determine how "high" the bounce will be
var d=75;

// calculate a quadratic curve control point on the tangent line at distance d
var ra=Math.atan2(dy,dx);  // radian angle of the imaginary line
var ta=ra-Math.PI/2;       // radian angle tangent to the imaginary line
var controlX=midX+d*Math.cos(ta);
var controlY=midY+d*Math.sin(ta);

// set up an animation that redraws a ball along 
// the calculated quadratic curve

// T will be an interval used to determine where on the quadratic curve 
// to calculate an x,y point
var T=0;

// just testing...tDirection will reverse the ball when it reaches the end of the curve
var tDirection=1;

// start the animation
requestAnimationFrame(animate);

// animate a ball along the quadratic curve
function animate(){

    // request another animation frame
    requestAnimationFrame(animate);

    ctx.clearRect(0,0,canvas.width,canvas.height);

    // calculate the balls next x,y along the curve
    var point=getQuadraticBezierXYatT(
        {x:x1,y:y1},
        {x:controlX,y:controlY},
        {x:x2,y:y2},
        T/100
    );

    // draw the ball
    ctx.beginPath();
    ctx.arc(point.x,point.y,5,0,PI2);
    ctx.closePath();
    ctx.fillStyle="blue";
    ctx.fill();

    // Move the ball to the next interval on the curve
    // Reverse direction when the ball reaches the start/end of the curve
    T+=tDirection;
    if(T<0 || T>100){
        tDirection*=-1;
        T+=tDirection;        
    }

}

// calculate an x,y point along a quadratic curve at interval T
function getQuadraticBezierXYatT(startPt,controlPt,endPt,T) {
    var x = Math.pow(1-T,2) * startPt.x + 2 * (1-T) * T * controlPt.x + Math.pow(T,2) * endPt.x; 
    var y = Math.pow(1-T,2) * startPt.y + 2 * (1-T) * T * controlPt.y + Math.pow(T,2) * endPt.y; 
    return( {x:x,y:y} );
}

(Just to mention that a ball rising along a slope will not physically behave as you have illustrated) (只需提及沿斜坡上升的球的物理行为就不会像您所说明的那样)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM