微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

碰撞检测,鼠标控制

如何解决碰撞检测,鼠标控制

我有一个简单的物理引擎来检测圆圈和桨之间的碰撞,现在我可以设置桨是否由鼠标控制。但我希望能够通过鼠标控制其中一个圆圈。在底部 bat[i].update() 将通过该索引控制指定的桨。但我希望能够通过鼠标控制圆圈来进一步扩展这个引擎。有什么办法可以做到这一点吗?

const canvas = document.querySelector('canvas')
const ctx = canvas.getContext("2d");
const mouse = { x: 0,y: 0,button: false }

function mouseEvents(e) {
    mouse.x = e.pageX;
    mouse.y = e.pageY;
    mouse.button = e.type === "mousedown" ? true : e.type === "mouseup" ? false : mouse.button;
}
["down","up","move"].forEach(name => document.addEventListener("mouse" + name,mouseEvents));

// short cut vars 
var w = canvas.width;
var h = canvas.height;
var cw = w / 2; // center 
var ch = h / 2;
const gravity = 0;
var balls = []
var bats = []

// constants and helpers
const PI2 = Math.PI * 2;
const setStyle = (ctx,style) => { Object.keys(style).forEach(key => ctx[key] = style[key]) };

function random(min,max) {
    return Math.floor(Math.random() * (max - min + 1)) + min;
}

function distance(x1,y1,x2,y2) {
    const xdist = x2 - x1;
    const ydist = y2 - y1;
    return Math.sqrt(Math.pow(xdist,2) + Math.pow(ydist,2));
}

// the ball
class ball {
    constructor() {
        this.r = 25
        this.x = random(50,1500)
        this.y = random(50,1500)
        this.dx = 15
        this.dy = 15
        this.mass = 1
        this.maxSpeed = 15
        this.style = {
            linewidth: 12,strokeStyle: "green"
        }
    }
    draw(ctx) {
        setStyle(ctx,this.style);
        ctx.beginPath();
        ctx.arc(this.x,this.y,this.r - this.style.linewidth * 0.45,PI2);
        ctx.stroke();
    }
    update() {
        this.dy += gravity;
        var speed = Math.sqrt(this.dx * this.dx + this.dy * this.dy);
        var x = this.x + this.dx;
        var y = this.y + this.dy;

        if (y > canvas.height - this.r) {
            y = (canvas.height - this.r) - (y - (canvas.height - this.r));
            this.dy = -this.dy;
        }
        if (y < this.r) {
            y = this.r - (y - this.r);
            this.dy = -this.dy;
        }
        if (x > canvas.width - this.r) {
            x = (canvas.width - this.r) - (x - (canvas.width - this.r));
            this.dx = -this.dx;
        }
        if (x < this.r) {
            x = this.r - (x - this.r);
            this.dx = -this.dx;
        }
        this.x = x;
        this.y = y;
        if (speed > this.maxSpeed) { // if over speed then slow the ball down gradualy
            var reduceSpeed = this.maxSpeed + (speed - this.maxSpeed) * 0.9; // reduce speed if over max speed
            this.dx = (this.dx / speed) * reduceSpeed;
            this.dy = (this.dy / speed) * reduceSpeed;
        }
        for (var i = 0; i < balls.length; i++) {
            if (this === balls[i]) continue
            if (distance(this.x,balls[i].x,balls[i].y) < this.r * 2) {
                resolveCollision(this,balls[i])
            }
        }

    }
}
class player {
    constructor() {
        this.r = 50
        this.x = random(50,1500)
        this.dx = 0.2
        this.dy = 0.2
        this.mass = 1
        this.maxSpeed = 1000
        this.style = {
            linewidth: 12,strokeStyle: "blue"
        }
    }
    draw(ctx) {
        setStyle(ctx,PI2);
        ctx.stroke();
    }
    update() {
        this.dx = mouse.x - this.x;
        this.dy = mouse.y - this.y;
        var x = this.x + this.dx;
        var y = this.y + this.dy;
        x < this.width / 2 && (x / 2);
        y < this.height / 2 && (y / 2);
        x > canvas.width / 2 && (x = canvas.width / 2);
        y > canvas.height / 2 && (y = canvas.height / 2);
        this.dx = x - this.x;
        this.dy = y - this.y;
        this.x = x;
        this.y = y;
        for (var i = 0; i < balls.length; i++) {
            if (this === balls[i]) continue
            if (distance(this.x,balls[i])
            }
        }

    }
}
const ballShadow = { 
        r: 50,x: 50,y: 50,dx: 0.2,dy: 0.2,}
//bat
class bat {
    constructor(x,y,w,h) {
        this.x = x
        this.y = y
        this.dx = 0
        this.dy = 0
        this.width = w
        this.height = h
        this.style = {
            linewidth: 2,strokeStyle: "black",}
    }
    draw(ctx) {
        setStyle(ctx,this.style);
        ctx.strokeRect(this.x - this.width / 2,this.y - this.height / 2,this.width,this.height);
    }

    update() {
        this.dx = mouse.x - this.x;
        this.dy = mouse.y - this.y;
        var x = this.x + this.dx;
        var y = this.y + this.dy;
        x < this.width / 2 && (x = this.width / 2);
        y < this.height / 2 && (y = this.height / 2);
        x > canvas.width - this.width / 2 && (x = canvas.width - this.width / 2);
        y > canvas.height - this.height / 2 && (y = canvas.height - this.height / 2);
        this.dx = x - this.x;
        this.dy = y - this.y;
        this.x = x;
        this.y = y;

    }
}

function dobatBall(bat,ball) {
    var mirrorX = 1;
    var mirrorY = 1;

    const s = ballShadow; // alias
    s.x = ball.x;
    s.y = ball.y;
    s.dx = ball.dx;
    s.dy = ball.dy;
    s.x -= s.dx;
    s.y -= s.dy;

    // get the bat half width height
    const batW2 = bat.width / 2;
    const batH2 = bat.height / 2;

    // and bat size plus radius of ball
    var batH = batH2 + ball.r;
    var batW = batW2 + ball.r;

    // set ball position relative to bats last pos
    s.x -= bat.x;
    s.y -= bat.y;

    // set ball delta relative to bat
    s.dx -= bat.dx;
    s.dy -= bat.dy;

    // mirror x and or y if needed
    if (s.x < 0) {
        mirrorX = -1;
        s.x = -s.x;
        s.dx = -s.dx;
    }
    if (s.y < 0) {
        mirrorY = -1;
        s.y = -s.y;
        s.dy = -s.dy;
    }


    // bat Now only has a bottom,right sides and bottom right corner
    var distY = (batH - s.y); // distance from bottom 
    var distX = (batW - s.x); // distance from right

    if (s.dx > 0 && s.dy > 0) { return } // ball moving away so no hit

    var ballSpeed = Math.sqrt(s.dx * s.dx + s.dy * s.dy) // get ball speed relative to bat

    // get x location of intercept for bottom of bat
    var bottomX = s.x + (s.dx / s.dy) * distY;

    // get y location of intercept for right of bat
    var rightY = s.y + (s.dy / s.dx) * distX;

    // get distance to bottom and right intercepts
    var distB = Math.hypot(bottomX - s.x,batH - s.y);
    var distR = Math.hypot(batW - s.x,rightY - s.y);
    var hit = false;

    if (s.dy < 0 && bottomX <= batW2 && distB <= ballSpeed && distB < distR) { // if hit is on bottom and bottom hit is closest
        hit = true;
        s.y = batH - s.dy * ((ballSpeed - distB) / ballSpeed);
        s.dy = -s.dy;
    }
    if (!hit && s.dx < 0 && rightY <= batH2 && distR <= ballSpeed && distR <= distB) { // if hit is on right and right hit is closest
        hit = true;
        s.x = batW - s.dx * ((ballSpeed - distR) / ballSpeed);;
        s.dx = -s.dx;
    }
    if (!hit) { // if no hit may have intercepted the corner. 
        // find the distance that the corner is from the line segment from the balls pos to the next pos
        const u = ((batW2 - s.x) * s.dx + (batH2 - s.y) * s.dy) / (ballSpeed * ballSpeed);

        // get the closest point on the line to the corner
        var cpx = s.x + s.dx * u;
        var cpy = s.y + s.dy * u;

        // get ball radius squared
        const radSqr = ball.r * ball.r;

        // get the distance of that point from the corner squared
        const dist = (cpx - batW2) * (cpx - batW2) + (cpy - batH2) * (cpy - batH2);

        // is that distance greater than ball radius
        if (dist > radSqr) { return } // no hit

        // solves the triangle from center to closest point on balls trajectory
        var d = Math.sqrt(radSqr - dist) / ballSpeed;

        // intercept point is closest to line start
        cpx -= s.dx * d;
        cpy -= s.dy * d;

        // get the distance from the ball current pos to the intercept point
        d = Math.hypot(cpx - s.x,cpy - s.y);

        // is the distance greater than the ball speed then its a miss
        if (d > ballSpeed) { return } // no hit return

        s.x = cpx; // position of contact
        s.y = cpy;

        // find the normalised tangent at intercept point 
        const ty = (cpx - batW2) / ball.r;
        const tx = -(cpy - batH2) / ball.r;

        // calculate the reflection vector
        const bsx = s.dx / ballSpeed; // normalise ball speed
        const bsy = s.dy / ballSpeed;
        const dot = (bsx * tx + bsy * ty) * 2;

        // get the distance the ball travels past the intercept
        d = ballSpeed - d;

        // the reflected vector is the balls new delta (this delta is normalised)
        s.dx = (tx * dot - bsx);
        s.dy = (ty * dot - bsy);

        // move the ball the remaining distance away from corner
        s.x += s.dx * d;
        s.y += s.dy * d;

        // set the ball delta to the balls speed
        s.dx *= ballSpeed
        s.dy *= ballSpeed
        hit = true;
    }

    // if the ball hit the bat restore absolute position
    if (hit) {
        // reverse mirror
        s.x *= mirrorX;
        s.dx *= mirrorX;
        s.y *= mirrorY;
        s.dy *= mirrorY;

        // remove bat relative position
        s.x += bat.x;
        s.y += bat.y;

        // remove bat relative delta
        s.dx += bat.dx;
        s.dy += bat.dy;

        // set the balls new position and delta
        ball.x = s.x;
        ball.y = s.y;
        ball.dx = s.dx;
        ball.dy = s.dy;
    }
}

function rotate(veLocity,angle) {
    const rotatedVeLocities = {
        x: veLocity.x * Math.cos(angle) + veLocity.y * Math.sin(angle),y: -veLocity.x * Math.sin(angle) + veLocity.y * Math.cos(angle)
    };

    return rotatedVeLocities;
}

function resolveCollision(particle,otherParticle) {
    const xVeLocityDiff = particle.dx - otherParticle.dx;
    const yVeLocityDiff = particle.dy - otherParticle.dy;

    const xdist = otherParticle.x - particle.x;
    const ydist = otherParticle.y - particle.y;

    if (xVeLocityDiff * xdist + yVeLocityDiff * ydist >= 0) {

        const angle = Math.atan2(otherParticle.y - particle.y,otherParticle.x - particle.x);
        const m1 = particle.mass;
        const m2 = otherParticle.mass;

        const u1 = rotate({ x: particle.dx,y: particle.dy },angle);
        const u2 = rotate({ x: otherParticle.dx,y: otherParticle.dy },angle);

        const v1 = {
            x: u1.x * (m1 - m2) / (m1 + m2) + u2.x * 2 * m2 / (m1 + m2),y: u1.y
        };
        const v2 = {
            x: u2.x * (m1 - m2) / (m1 + m2) + u1.x * 2 * m2 / (m1 + m2),y: u2.y
        };

        const vFinal1 = rotate(v1,-angle);
        const vFinal2 = rotate(v2,-angle);

        particle.dx = vFinal1.x;
        particle.dy = vFinal1.y;

        otherParticle.dx = vFinal2.x;
        otherParticle.dy = vFinal2.y;
    }
}

for (let i = 0; i < 10; i++) {
    balls.push(new ball())
}
balls.push(new player())
    //x,h
bats.push(new bat((window.innerWidth / 2) - 150,window.innerHeight / 2,10,100))
bats.push(new bat((window.innerWidth / 2) + 150,100))

// main update function
function update(timer) {

    if (w !== innerWidth || h !== innerHeight) {
        cw = (w = canvas.width = innerWidth) / 2;
        ch = (h = canvas.height = innerHeight) / 2;
    }



    ctx.setTransform(1,1,0); // reset transform
    ctx.globalAlpha = 1; // reset alpha
    ctx.clearRect(0,h);

    // move bat and ball
    for (var i = 0; i < balls.length; i++) {
        for (var j = 0; j < bats.length; j++) {
            dobatBall(bats[j],balls[i])
        }
        balls[i].update()
        balls[i].draw(ctx)
    }
    bats.forEach(bat => {
        //bat.update();
        bat.draw(ctx);
    })

    // check for bal bat contact and change ball position and trajectory if needed

    // draw ball and bat

    requestAnimationFrame(update);

}
requestAnimationFrame(update);
<body>
    <canvas></canvas>
</body>

解决方法

将您的球员添加到球阵列中并不是您想要做的。将该对象分开。将您的播放器创建为变量,然后在您的循环中绘制和更新播放器

let player = new Player();

function update(timer) {
  ...
player.update();
player.draw(ctx);
  ...
}

const canvas = document.querySelector('canvas')
const ctx = canvas.getContext("2d");
const mouse = { x: 0,y: 0,button: false }

function mouseEvents(e) {
    mouse.x = e.x;
    mouse.y = e.y;
    mouse.button = e.type === "mousedown" ? true : e.type === "mouseup" ? false : mouse.button;
}
["down","up","move"].forEach(name => document.addEventListener("mouse" + name,mouseEvents));

// short cut vars 
var w = canvas.width;
var h = canvas.height;
var cw = w / 2; // center 
var ch = h / 2;
const gravity = 0;
var balls = []
var bats = []

// constants and helpers
const PI2 = Math.PI * 2;
const setStyle = (ctx,style) => { Object.keys(style).forEach(key => ctx[key] = style[key]) };

function random(min,max) {
    return Math.floor(Math.random() * (max - min + 1)) + min;
}

function distance(x1,y1,x2,y2) {
    const xDist = x2 - x1;
    const yDist = y2 - y1;
    return Math.sqrt(Math.pow(xDist,2) + Math.pow(yDist,2));
}

// the ball
class ball {
    constructor() {
        this.r = 25
        this.x = random(50,1500)
        this.y = random(50,1500)
        this.dx = 15
        this.dy = 15
        this.mass = 1
        this.maxSpeed = 15
        this.style = {
            lineWidth: 12,strokeStyle: "green"
        }
    }
    draw(ctx) {
        setStyle(ctx,this.style);
        ctx.beginPath();
        ctx.arc(this.x,this.y,this.r - this.style.lineWidth * 0.45,PI2);
        ctx.stroke();
    }
    update() {
        this.dy += gravity;
        var speed = Math.sqrt(this.dx * this.dx + this.dy * this.dy);
        var x = this.x + this.dx;
        var y = this.y + this.dy;

        if (y > canvas.height - this.r) {
            y = (canvas.height - this.r) - (y - (canvas.height - this.r));
            this.dy = -this.dy;
        }
        if (y < this.r) {
            y = this.r - (y - this.r);
            this.dy = -this.dy;
        }
        if (x > canvas.width - this.r) {
            x = (canvas.width - this.r) - (x - (canvas.width - this.r));
            this.dx = -this.dx;
        }
        if (x < this.r) {
            x = this.r - (x - this.r);
            this.dx = -this.dx;
        }
        this.x = x;
        this.y = y;
        if (speed > this.maxSpeed) { // if over speed then slow the ball down gradualy
            var reduceSpeed = this.maxSpeed + (speed - this.maxSpeed) * 0.9; // reduce speed if over max speed
            this.dx = (this.dx / speed) * reduceSpeed;
            this.dy = (this.dy / speed) * reduceSpeed;
        }
        for (var i = 0; i < balls.length; i++) {
            if (this === balls[i]) continue
            if (distance(this.x,balls[i].x,balls[i].y) < this.r * 2) {
                resolveCollision(this,balls[i])
            }
        }

    }
}
class Player {
    constructor() {
        this.r = 50
        this.x = random(50,1500)
        this.dx = 0.2
        this.dy = 0.2
        this.mass = 1
        this.maxSpeed = 1000
        this.style = {
            lineWidth: 12,strokeStyle: "blue"
        }
    }
    draw(ctx) {
        setStyle(ctx,PI2);
        ctx.stroke();
    }
    update() {
        this.dx = mouse.x - this.x;
        this.dy = mouse.y - this.y;
        var x = this.x + this.dx;
        var y = this.y + this.dy;
        /*x < this.width / 2 && (x / 2);
        y < this.height / 2 && (y / 2);
        x > canvas.width / 2 && (x = canvas.width / 2);
        y > canvas.height / 2 && (y = canvas.height / 2);*/
        this.dx = x - this.x;
        this.dy = y - this.y;
        this.x = x;
        this.y = y;
        for (var i = 0; i < balls.length; i++) {
            //if (this === balls[i]) continue
            if (distance(this.x,balls[i])
            }
        }

    }
}
const ballShadow = { 
        r: 50,x: 50,y: 50,dx: 0.2,dy: 0.2,}
//bat
class bat {
    constructor(x,y,w,h) {
        this.x = x
        this.y = y
        this.dx = 0
        this.dy = 0
        this.width = w
        this.height = h
        this.style = {
            lineWidth: 2,strokeStyle: "black",}
    }
    draw(ctx) {
        setStyle(ctx,this.style);
        ctx.strokeRect(this.x - this.width / 2,this.y - this.height / 2,this.width,this.height);
    }

    update() {
        this.dx = mouse.x - this.x;
        this.dy = mouse.y - this.y;
        var x = this.x + this.dx;
        var y = this.y + this.dy;
        x < this.width / 2 && (x = this.width / 2);
        y < this.height / 2 && (y = this.height / 2);
        x > canvas.width - this.width / 2 && (x = canvas.width - this.width / 2);
        y > canvas.height - this.height / 2 && (y = canvas.height - this.height / 2);
        this.dx = x - this.x;
        this.dy = y - this.y;
        this.x = x;
        this.y = y;

    }
}

function doBatBall(bat,ball) {
    var mirrorX = 1;
    var mirrorY = 1;

    const s = ballShadow; // alias
    s.x = ball.x;
    s.y = ball.y;
    s.dx = ball.dx;
    s.dy = ball.dy;
    s.x -= s.dx;
    s.y -= s.dy;

    // get the bat half width height
    const batW2 = bat.width / 2;
    const batH2 = bat.height / 2;

    // and bat size plus radius of ball
    var batH = batH2 + ball.r;
    var batW = batW2 + ball.r;

    // set ball position relative to bats last pos
    s.x -= bat.x;
    s.y -= bat.y;

    // set ball delta relative to bat
    s.dx -= bat.dx;
    s.dy -= bat.dy;

    // mirror x and or y if needed
    if (s.x < 0) {
        mirrorX = -1;
        s.x = -s.x;
        s.dx = -s.dx;
    }
    if (s.y < 0) {
        mirrorY = -1;
        s.y = -s.y;
        s.dy = -s.dy;
    }


    // bat now only has a bottom,right sides and bottom right corner
    var distY = (batH - s.y); // distance from bottom 
    var distX = (batW - s.x); // distance from right

    if (s.dx > 0 && s.dy > 0) { return } // ball moving away so no hit

    var ballSpeed = Math.sqrt(s.dx * s.dx + s.dy * s.dy) // get ball speed relative to bat

    // get x location of intercept for bottom of bat
    var bottomX = s.x + (s.dx / s.dy) * distY;

    // get y location of intercept for right of bat
    var rightY = s.y + (s.dy / s.dx) * distX;

    // get distance to bottom and right intercepts
    var distB = Math.hypot(bottomX - s.x,batH - s.y);
    var distR = Math.hypot(batW - s.x,rightY - s.y);
    var hit = false;

    if (s.dy < 0 && bottomX <= batW2 && distB <= ballSpeed && distB < distR) { // if hit is on bottom and bottom hit is closest
        hit = true;
        s.y = batH - s.dy * ((ballSpeed - distB) / ballSpeed);
        s.dy = -s.dy;
    }
    if (!hit && s.dx < 0 && rightY <= batH2 && distR <= ballSpeed && distR <= distB) { // if hit is on right and right hit is closest
        hit = true;
        s.x = batW - s.dx * ((ballSpeed - distR) / ballSpeed);;
        s.dx = -s.dx;
    }
    if (!hit) { // if no hit may have intercepted the corner. 
        // find the distance that the corner is from the line segment from the balls pos to the next pos
        const u = ((batW2 - s.x) * s.dx + (batH2 - s.y) * s.dy) / (ballSpeed * ballSpeed);

        // get the closest point on the line to the corner
        var cpx = s.x + s.dx * u;
        var cpy = s.y + s.dy * u;

        // get ball radius squared
        const radSqr = ball.r * ball.r;

        // get the distance of that point from the corner squared
        const dist = (cpx - batW2) * (cpx - batW2) + (cpy - batH2) * (cpy - batH2);

        // is that distance greater than ball radius
        if (dist > radSqr) { return } // no hit

        // solves the triangle from center to closest point on balls trajectory
        var d = Math.sqrt(radSqr - dist) / ballSpeed;

        // intercept point is closest to line start
        cpx -= s.dx * d;
        cpy -= s.dy * d;

        // get the distance from the ball current pos to the intercept point
        d = Math.hypot(cpx - s.x,cpy - s.y);

        // is the distance greater than the ball speed then its a miss
        if (d > ballSpeed) { return } // no hit return

        s.x = cpx; // position of contact
        s.y = cpy;

        // find the normalised tangent at intercept point 
        const ty = (cpx - batW2) / ball.r;
        const tx = -(cpy - batH2) / ball.r;

        // calculate the reflection vector
        const bsx = s.dx / ballSpeed; // normalise ball speed
        const bsy = s.dy / ballSpeed;
        const dot = (bsx * tx + bsy * ty) * 2;

        // get the distance the ball travels past the intercept
        d = ballSpeed - d;

        // the reflected vector is the balls new delta (this delta is normalised)
        s.dx = (tx * dot - bsx);
        s.dy = (ty * dot - bsy);

        // move the ball the remaining distance away from corner
        s.x += s.dx * d;
        s.y += s.dy * d;

        // set the ball delta to the balls speed
        s.dx *= ballSpeed
        s.dy *= ballSpeed
        hit = true;
    }

    // if the ball hit the bat restore absolute position
    if (hit) {
        // reverse mirror
        s.x *= mirrorX;
        s.dx *= mirrorX;
        s.y *= mirrorY;
        s.dy *= mirrorY;

        // remove bat relative position
        s.x += bat.x;
        s.y += bat.y;

        // remove bat relative delta
        s.dx += bat.dx;
        s.dy += bat.dy;

        // set the balls new position and delta
        ball.x = s.x;
        ball.y = s.y;
        ball.dx = s.dx;
        ball.dy = s.dy;
    }
}

function rotate(velocity,angle) {
    const rotatedVelocities = {
        x: velocity.x * Math.cos(angle) + velocity.y * Math.sin(angle),y: -velocity.x * Math.sin(angle) + velocity.y * Math.cos(angle)
    };

    return rotatedVelocities;
}

function resolveCollision(particle,otherParticle) {
    const xVelocityDiff = particle.dx - otherParticle.dx;
    const yVelocityDiff = particle.dy - otherParticle.dy;

    const xDist = otherParticle.x - particle.x;
    const yDist = otherParticle.y - particle.y;

    if (xVelocityDiff * xDist + yVelocityDiff * yDist >= 0) {

        const angle = Math.atan2(otherParticle.y - particle.y,otherParticle.x - particle.x);
        const m1 = particle.mass;
        const m2 = otherParticle.mass;

        const u1 = rotate({ x: particle.dx,y: particle.dy },angle);
        const u2 = rotate({ x: otherParticle.dx,y: otherParticle.dy },angle);

        const v1 = {
            x: u1.x * (m1 - m2) / (m1 + m2) + u2.x * 2 * m2 / (m1 + m2),y: u1.y
        };
        const v2 = {
            x: u2.x * (m1 - m2) / (m1 + m2) + u1.x * 2 * m2 / (m1 + m2),y: u2.y
        };

        const vFinal1 = rotate(v1,-angle);
        const vFinal2 = rotate(v2,-angle);

        particle.dx = vFinal1.x;
        particle.dy = vFinal1.y;

        otherParticle.dx = vFinal2.x;
        otherParticle.dy = vFinal2.y;
    }
}

for (let i = 0; i < 10; i++) {
    balls.push(new ball())
}
let player = new Player();
    //x,h
bats.push(new bat((window.innerWidth / 2) - 150,window.innerHeight / 2,10,100))
bats.push(new bat((window.innerWidth / 2) + 150,100))

// main update function
function update(timer) {

    if (w !== innerWidth || h !== innerHeight) {
        cw = (w = canvas.width = innerWidth) / 2;
        ch = (h = canvas.height = innerHeight) / 2;
    }

    ctx.setTransform(1,1,0); // reset transform
    ctx.globalAlpha = 1; // reset alpha
    ctx.clearRect(0,h);

    // move bat and ball
    for (var i = 1; i < balls.length; i++) {
        for (var j = 0; j < bats.length; j++) {
            doBatBall(bats[j],balls[i])
        }
        balls[i].update()
        balls[i].draw(ctx)
    }
    player.update();
    player.draw(ctx);
    bats.forEach(bat => {
        //bat.update();
        bat.draw(ctx);
    })

    // check for bal bat contact and change ball position and trajectory if needed

    // draw ball and bat

    requestAnimationFrame(update);

}
update();
 <canvas></canvas>

请记住,鼠标并不完全位于圆的中心,因为您没有考虑 mousemove 函数中的画布位置。此外,您还有一些限制玩家对象在整个画布上移动的能力。

编辑:

这就是导致您的播放器无法在整个画布上移动的原因,因此请将其注释掉。

/* x < this.width / 2 && (x / 2);
y < this.height / 2 && (y / 2);
x > canvas.width / 2 && (x = canvas.width / 2);
y > canvas.height / 2 && (y = canvas.height / 2);*/

并且您的碰撞稍微偏离,因为在您的播放器类中,您正在检查与 this.r * 2 的距离。我会把它改成

 for (var i = 0; i < balls.length; i++) {
            //if (this === balls[i]) continue //not really needed
            if (distance(this.x,balls[i].y) < this.r + balls[i].r) {
                resolveCollision(this,balls[i])
            }
,

球的速度不能为 0,但玩家可以。因此,它无法除以零:

        const u = ((batW2 - s.x) * s.dx + (batH2 - s.y) * s.dy) / (ballSpeed * ballSpeed);

只需在行尾添加 || 1 即可修复。

const canvas = document.querySelector('canvas')
const ctx = canvas.getContext("2d");
const mouse = { x: 0,button: false }

function mouseEvents(e) {
    mouse.x = e.pageX;
    mouse.y = e.pageY;
    mouse.button = e.type === "mousedown" ? true : e.type === "mouseup" ? false : mouse.button;
}
["down",balls[i])
            }
        }

    }
}
class player {
    constructor() {
        this.r = 50
        this.x = random(50,1500)
        this.dx = 0.2
        this.dy = 0.2
        this.mass = 1
        this.maxSpeed = 1000
        this.width = this.r
        this.height = this.r
        this.style = {
            lineWidth: 12,PI2);
        ctx.stroke();
    }
    update() {
        this.dx = mouse.x - this.x;
        this.dy = mouse.y - this.y;
        var x = this.x + this.dx;
        var y = this.y + this.dy;
/* change */
/*
        x < this.width / 2 && (x / 2);
        y < this.height / 2 && (y / 2);
        x > canvas.width / 2 && (x = canvas.width / 2);
        y > canvas.height / 2 && (y = canvas.height / 2);
*/
        x < this.width && (x = this.width);
        y < this.height && (y = this.height);
        x > canvas.width - this.width && (x = canvas.width - this.width);
        y > canvas.height - this.height && (y = canvas.height - this.height);
/* end change */
        this.dx = x - this.x;
        this.dy = y - this.y;
        this.x = x;
        this.y = y;
        for (var i = 0; i < balls.length; i++) {
            if (this === balls[i]) continue
            if (distance(this.x,rightY - s.y);
    var hit = false;

    if (s.dy < 0 && bottomX <= batW2 && distB <= ballSpeed && distB < distR) { // if hit is on bottom and bottom hit is closest
        hit = true;
        s.y = batH - s.dy * ((ballSpeed - distB) / ballSpeed);
        s.dy = -s.dy;
    }
    if (!hit && s.dx < 0 && rightY <= batH2 && distR <= ballSpeed && distR <= distB) { // if hit is on right and right hit is closest
        hit = true;
        s.x = batW - s.dx * ((ballSpeed - distR) / ballSpeed);;
        s.dx = -s.dx;
    }
    if (!hit) { // if no hit may have intercepted the corner. 
        // find the distance that the corner is from the line segment from the balls pos to the next pos
/* change */
//        const u = ((batW2 - s.x) * s.dx + (batH2 - s.y) * s.dy) / (ballSpeed * ballSpeed);
        const u = ((batW2 - s.x) * s.dx + (batH2 - s.y) * s.dy) / (ballSpeed * ballSpeed) || 1;
/* end change */
        // get the closest point on the line to the corner
        var cpx = s.x + s.dx * u;
        var cpy = s.y + s.dy * u;

        // get ball radius squared
        const radSqr = ball.r * ball.r;

        // get the distance of that point from the corner squared
        const dist = (cpx - batW2) * (cpx - batW2) + (cpy - batH2) * (cpy - batH2);

        // is that distance greater than ball radius
        if (dist > radSqr) { return } // no hit

        // solves the triangle from center to closest point on balls trajectory
        var d = Math.sqrt(radSqr - dist) / ballSpeed;

        // intercept point is closest to line start
        cpx -= s.dx * d;
        cpy -= s.dy * d;

        // get the distance from the ball current pos to the intercept point
        d = Math.hypot(cpx - s.x,-angle);

        particle.dx = vFinal1.x;
        particle.dy = vFinal1.y;

        otherParticle.dx = vFinal2.x;
        otherParticle.dy = vFinal2.y;
    }
}

for (let i = 0; i < 10; i++) {
    balls.push(new ball())
}
balls.push(new player())
    //x,100))

// main update function
function update(timer) {

    if (w !== innerWidth || h !== innerHeight) {
        cw = (w = canvas.width = innerWidth) / 2;
        ch = (h = canvas.height = innerHeight) / 2;
    }



    ctx.setTransform(1,h);

    // move bat and ball
    for (var i = 0; i < balls.length; i++) {
        for (var j = 0; j < bats.length; j++) {
            doBatBall(bats[j],balls[i])
        }
        balls[i].update()
        balls[i].draw(ctx)
    }
    bats.forEach(bat => {
        //bat.update();
        bat.draw(ctx);
    })

    // check for bal bat contact and change ball position and trajectory if needed

    // draw ball and bat

    requestAnimationFrame(update);

}
requestAnimationFrame(update);
<body>
    <canvas></canvas>
</body>

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。