简体   繁体   中英

JS Canvas - draw line at a specified angle

I'd like to make an app where a ball moves at the angle your mouse hits it. So if you swipe your mouse down from top left quadrant at 30 degrees (I guess that would be 180-30 = angle of 150 degrees), it will knock the ball that way. I've been drawing my lines as such:

        function drawAngles () {
            var d = 50; //start line at (10, 20), move 50px away at angle of 30 degrees
            var angle = 80 * Math.PI/180;
            ctx.beginPath();
            ctx.moveTo(300,0);
            ctx.lineTo(300,600); //x, y
            ctx.moveTo(0,300);
            ctx.lineTo(600,300);
            ctx.moveTo(300,300);
            ctx.lineTo(600,100);
            ctx.arc(300,300,300,0,2*Math.PI);
            ctx.stroke();
        }

But this doesn't give me an idea of what the angles are.

Then I move the ball at that angle (for now, I'm animating it without mouse interaction)

        function getAngleX (x) {
            return x = x + (50 * Math.cos(Math.PI/6));          
        }
        function getAngleY(y) {
            return  y = y + (50 * Math.sin(Math.PI/6));
        }

            //just animate this box to move at an angle from center down at 30 degrees
            $(".anotherBox").mouseenter(function(e) {
                pos =  $(this).position();
                box2X = pos.left;
                box2Y = pos.top;    

                $(this).animate({
                    //top : $(window).outerHeight(),
                    top : getAngleY(box2Y)+"px",
                    left: getAngleX(box2X)+"px",
                }, "slow");     
            });

So how can I draw a line at a specified angle? I'd like to make sure my ball is following along that path.

在此输入图像描述

If i guess right, i think you want the mouse act like a baseball bat, and you need to measure the current mouse angle, that is to store previous mouse position and do some math.

You have also to keep track if you allready handled current collision, to avoid the ball being 'sticky' and follow the mouse.

http://jsfiddle.net/gamealchemist/z3U8g/

var ctx = cv.getContext('2d');

var ball = {
    x:200, y:200, 
    r : 30,
    vx : 0.4, vy:0.4
}

// when mouse moved that distance, ball speed norm will be 1
var speedNorm = 10;

var collisionOnGoing = false;

function collide() {
    var dist = sq(ball.x - mx) + sq (ball.y-my); 
    // too far from ball ?
    if (dist > sq(ball.r)) { 
        collisionOnGoing = false;
        return;
    }
    // return if collision allready handled
    if (collisionOnGoing) return;
    var mouseDist =Math.sqrt( sq(mx-lastmx) + sq(my-lastmy) );
    // no collision if mouse too slow
    if (mouseDist<speedNorm/5) return;
    // launch the ball in current direction
    // with a speed relative to the mouse speed.
    var mouseAngle = Math.atan2(my-lastmy, mx-lastmx);
    ball.vx= (mouseDist / speedNorm ) * Math.cos(mouseAngle);
    ball.vy= (mouseDist / speedNorm ) * Math.sin(mouseAngle);
    collisionOnGoing = true;    
}

function animate() {
    requestAnimationFrame(animate);
    ctx.clearRect(0,0,400,400);
    // collide ball with mouse
    collide();
    // draw ball
    ctx.beginPath();
    ctx.arc(ball.x, ball.y, ball.r, 0, 6.3);
    ctx.fill();
    ctx.closePath();
    // move
    ball.x+=ball.vx;
    ball.y+=ball.vy;
    // collide with screen
    if (ball.x>400) ball.vx=-Math.abs(ball.vx);
    if (ball.x<0) ball.vx=Math.abs(ball.vx);
    if (ball.y>400) ball.vy=-Math.abs(ball.vy);
    if (ball.y<0) ball.vy=Math.abs(ball.vy);
}

animate();

//  ---  Mouse handling ---

addEventListener('mousemove', mouseMove);

var mx=-1, my=-1, lastmx=-1, lastmy=-1;
var cvRect = cv.getBoundingClientRect();
var cvLeft = cvRect.left;
var cvTop = cvRect.top;
function mouseMove(e) {
    lastmx = mx; lastmy=my;
    mx=e.clientX - cvLeft; 
    my=e.clientY - cvTop;
}

function sq(x) { return x*x;  }

You can use different approaches to achieve this but if you want to use the same basis to move and draw then this approach may suit well.

First we use a function to get step values for x and y based on the angle (in radians):

function getSteps(angle) {

    var cos = Math.cos(angle),
        sin = Math.sin(angle);

    return {
        x: cos -sin,
        y: sin + cos
    }
}

Then using these steps values we can scale them to get an end point, or scale them gradually to animate an object along the line. A simple loop could look like this (just for example):

function loop() {

    var x = i * step.x,  // scale using i
        y = i * step.y;

    ctx.fillRect(200 + x, 200 + y, 2, 2); // add to origin start point 200, 200

    i += 1;              // increase i

    if (i < length) requestAnimationFrame(loop);
}

Live demo

If you just want to draw a line at a certain angle you can do the following instead:

function lineAtAngle(x1, y1, length, angle) {
    ctx.moveTo(x1, y1);
    ctx.lineTo(x1 + length * Math.cos(angle), y1 + length * Math.sin(angle));
}

then stroke it.

Hope this helps!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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