p5.js 中的角碰撞角度
Corner Collision angles in p5.js
总结:
试图在移动的矩形和下落的圆圈之间制作一个简单的碰撞检测系统,我想让它更真实。
主要问题:
-我想解决的主要问题是检测圆对象何时击中矩形的角以及 return 圆根据该角度反弹。
代码:
var balls = [];
var obstacle;
function setup() {
createCanvas(400, 400);
obstacle = new Obstacle();
}
function draw() {
background(75);
obstacle.display();
obstacle.update();
for (var i = 0; i < balls.length; i++) {
balls[i].display();
if (!RectCircleColliding(balls[i], obstacle)){
balls[i].update();
balls[i].edges();
}
//console.log(RectCircleColliding(balls[i], obstacle));
}
}
function mousePressed() {
balls.push(new Ball(mouseX, mouseY));
}
function Ball(x, y) {
this.x = x;
this.y = y;
this.r = 15;
this.gravity = 0.5;
this.velocity = 0;
this.display = function() {
fill(255, 0, 100);
stroke(255);
ellipse(this.x, this.y, this.r * 2);
}
this.update = function() {
this.velocity += this.gravity;
this.y += this.velocity;
}
this.edges = function() {
if (this.y >= height - this.r) {
this.y = height - this.r;
this.velocity = this.velocity * -1;
this.gravity = this.gravity * 1.1;
}
}
}
function Obstacle() {
this.x = width - width;
this.y = height / 2;
this.w = 200;
this.h = 25;
this.display = function() {
fill(0);
stroke(255);
rect(this.x, this.y, this.w, this.h);
}
this.update = function() {
this.x++;
if (this.x > width + this.w /2) {
this.x = -this.w;
}
}
}
function RectCircleColliding(Ball, Obstacle) {
// define obstacle borders
var oRight = Obstacle.x + Obstacle.w;
var oLeft = Obstacle.x;
var oTop = Obstacle.y;
var oBottom = Obstacle.y + Obstacle.h;
//compare ball's position (acounting for radius) with the obstacle's border
if (Ball.x + Ball.r > oLeft) {
if (Ball.x - Ball.r < oRight) {
if (Ball.y + Ball.r > oTop) {
if (Ball.y - Ball.r < oBottom) {
let oldY = Ball.y;
Ball.y = oTop - Ball.r;
Ball.velocity = Ball.velocity * -1;
if (Ball.gravity < 2.0){
Ball.gravity = Ball.gravity * 1.1;
} else {
Ball.velocity = 0;
Ball.y = oldY;
}
return (true);
}
}
}
}
return false;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.7.3/p5.js"></script>
预期输出:
我希望看到下落的圆圈相对于它们击中矩形的位置从矩形反弹。
如果圆圈击中角落,它们应该以不同的方式反弹,而不是击中死点。
先决条件
小球的速度必须是矢量(XY分量),不能只是一个数字。
1。确定圆圈是否会撞到边或角
获取从矩形中心到圆的向量的分量,并与矩形的尺寸进行比较:
// Useful temporary variables for later use
var hx = 0.5 * obstacle.w;
var hy = 0.5 * obstacle.h;
var rx = obstacle.x + hx;
var ry = obstacle.y + hy;
// displacement vector
var dx = ball.x - rx;
var dy = ball.y - ry;
// signs
var sx = dx < -hx ? -1 : (dx > hx ? 1 : 0);
var sy = dy < -hy ? -1 : (dy > hy ? 1 : 0);
如果sx, sy
都不为零,则球可能击中角,否则可能击中侧面。
2。判断圆是否碰撞
将每个符号乘以各自的半维数:
// displacement vector from the nearest point on the rectangle
var tx = sx * (Math.abs(dx) - hx);
var ty = sy * (Math.abs(dy) - hy);
// distance from p to the center of the circle
var dc = Math.hypot(tx, ty);
if (dc <= ball.r) {
/* they do collide */
}
3。确定碰撞法向量
(tx, ty)
是法向量的分量,但前提是球的中心在矩形之外:
// epsilon to account for numerical imprecision
const EPSILON = 1e-6;
var nx = 0, ny = 0, nl = 0;
if (sx == 0 && sy == 0) { // center is inside
nx = dx > 0 ? 1 : -1;
ny = dy > 0 ? 1 : -1;
nl = Math.hypot(nx, ny);
} else { // outside
nx = tx;
ny = ty;
nl = dc;
}
nx /= nl;
ny /= nl;
4。解决任何“渗透”
(请勿恶作剧)
这确保球永远不会穿透矩形的表面,从而提高碰撞的视觉质量:
ball.x += (ball.r - dc) * nx;
ball.y += (ball.r - dc) * ny;
5。解决冲突
如果圆在法线方向移动,不要解决碰撞,因为球可能会粘在表面上:
// dot-product of velocity with normal
var dv = ball.vx * nx + ball.vy * ny;
if (dv >= 0.0) {
/* exit and don't do anything else */
}
// reflect the ball's velocity in direction of the normal
ball.vx -= 2.0 * dv * nx;
ball.vy -= 2.0 * dv * ny;
工作 JS 片段
const GRAVITY = 250.0;
function Ball(x, y, r) {
this.x = x;
this.y = y;
this.r = r;
this.vx = 0;
this.vy = 0;
this.display = function() {
fill(255, 0, 100);
stroke(255);
ellipse(this.x, this.y, this.r * 2);
}
this.collidePage = function(b) {
if (this.vy > 0 && this.y + this.r >= b) {
this.y = b - this.r;
this.vy = -this.vy;
}
}
this.updatePosition = function(dt) {
this.x += this.vx * dt;
this.y += this.vy * dt;
}
this.updateVelocity = function(dt) {
this.vy += GRAVITY * dt;
}
}
function Obstacle(x, y, w, h) {
this.x = x;
this.y = y;
this.w = w;
this.h = h;
this.display = function() {
fill(0);
stroke(255);
rect(this.x, this.y, this.w, this.h);
}
this.update = function() {
this.x++;
if (this.x > width + this.w /2) {
this.x = -this.w;
}
}
}
var balls = [];
var obstacle;
function setup() {
createCanvas(400, 400);
obstacle = new Obstacle(0, height / 2, 200, 25);
}
const DT = 0.05;
function draw() {
background(75);
obstacle.update();
obstacle.display();
for (var i = 0; i < balls.length; i++) {
balls[i].updatePosition(DT);
balls[i].collidePage(height);
ResolveRectCircleCollision(balls[i], obstacle);
balls[i].updateVelocity(DT);
balls[i].display();
}
}
function mousePressed() {
balls.push(new Ball(mouseX, mouseY, 15));
}
const EPSILON = 1e-6;
function ResolveRectCircleCollision(ball, obstacle) {
var hx = 0.5 * obstacle.w, hy = 0.5 * obstacle.h;
var rx = obstacle.x + hx, ry = obstacle.y + hy;
var dx = ball.x - rx, dy = ball.y - ry;
var sx = dx < -hx ? -1 : (dx > hx ? 1 : 0);
var sy = dy < -hy ? -1 : (dy > hy ? 1 : 0);
var tx = sx * (Math.abs(dx) - hx);
var ty = sy * (Math.abs(dy) - hy);
var dc = Math.hypot(tx, ty);
if (dc > ball.r)
return false;
var nx = 0, ny = 0, nl = 0;
if (sx == 0 && sy == 0) {
nx = dx > 0 ? 1 : -1; ny = dy > 0 ? 1 : -1;
nl = Math.hypot(nx, ny);
} else {
nx = tx; ny = ty;
nl = dc;
}
nx /= nl; ny /= nl;
ball.x += (ball.r - dc) * nx; ball.y += (ball.r - dc) * ny;
var dv = ball.vx * nx + ball.vy * ny;
if (dv >= 0.0)
return false;
ball.vx -= 2.0 * dv * nx; ball.vy -= 2.0 * dv * ny;
return true;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.7.3/p5.min.js"></script>
我将尝试提出一个解决方案,该解决方案尽可能与原始代码保持一致。该解决方案旨在成为问题中提供的代码的演变。
给初始化为0的Ball
对象添加侧向移动(selv.sideV
):
function Ball(x, y) {
this.x = x;
this.y = y;
this.r = 15;
this.gravity = 0.5;
this.velocity = 0;
this.sideV = 0
// ...
}
将球移到update
的一侧,通过侧向运动减少侧向运动:
this.update = function() {
this.velocity += this.gravity;
this.y += this.velocity;
this.x += this.sideV;
this.sideV *= 0.98;
}
为 2 个框的相交测试创建函数:
function IsectRectRect(l1, r1, t1, b1, l2, r2, t2, b2) {
return l1 < r2 && l2 < r1 && t1 < b2 && t2 < b1;
}
还有一个函数可以计算入射向量V
到表面法向量N
的反射向量R
(像台球一样的反射):
function reflect( V, N ) {
R = V.copy().sub(N.copy().mult(2.0 * V.dot(N)));
return R;
}
当 Ball
与 Obstacle
发生碰撞时,您必须处理 3 种情况。
- 球完全击中
Obstacle
的顶部:IsectRectRect(oL, oR, oT, oB, Ball.x, Ball.x, bT, bB)
- 球击中
Obstacle
的左边缘:IsectRectRect(oL, oL, oT, oB, bL, bR, bT, bB)
- 球击中
Obstacle
的右边缘:IsectRectRect(oR, oR, oT, oB, bL, bR, bT, bB)
在每种情况下都必须计算反射的法向量。这是从 Obstacle
的顶部或边缘到 Ball
的中心的向量。
使用函数 reflect
将 Ball
弹回 Obstacle
:
function RectCircleColliding(Ball, Obstacle) {
let oL = Obstacle.x;
let oR = Obstacle.x + Obstacle.w;
let oT = Obstacle.y;
let oB = Obstacle.y + Obstacle.h;
let bL = Ball.x - Ball.r;
let bR = Ball.x + Ball.r;
let bT = Ball.y - Ball.r;
let bB = Ball.y + Ball.r;
let isect = false;
let hitDir = createVector(0, 1);
if ( IsectRectRect(oL, oR, oT, oB, Ball.x, Ball.x, bT, bB) ) {
isect = true;
} else if ( IsectRectRect(oL, oL, oT, oB, bL, bR, bT, bB) ) {
hitDir = createVector(Ball.x, Ball.y).sub(createVector(oL, oT))
isect = hitDir.mag() < Ball.r;
} else if ( IsectRectRect(oR, oR, oT, oB, bL, bR, bT, bB) ) {
hitDir = createVector(Ball.x, Ball.y).sub(createVector(oR, oT))
isect = hitDir.mag() < Ball.r;
}
if ( isect ) {
let dir = createVector(Ball.sideV, Ball.velocity);
R = reflect(dir, hitDir.normalize());
Ball.velocity = R.y;
Ball.sideV = R.x;
let oldY = Ball.y;
Ball.y = oT - Ball.r;
if (Ball.gravity < 2.0){
Ball.gravity = Ball.gravity * 1.1;
} else {
Ball.velocity = 0;
Ball.y = oldY;
}
return true;
}
return false;
}
查看示例,其中我将更改应用于您的原始代码:
var balls = [];
var obstacle;
function setup() {
createCanvas(400, 400);
obstacle = new Obstacle();
}
function draw() {
background(75);
obstacle.display();
obstacle.update();
for (var i = 0; i < balls.length; i++) {
balls[i].display();
if (!RectCircleColliding(balls[i], obstacle)){
balls[i].update();
balls[i].edges();
}
//console.log(RectCircleColliding(balls[i], obstacle));
}
}
function mousePressed() {
balls.push(new Ball(mouseX, mouseY));
}
function Ball(x, y) {
this.x = x;
this.y = y;
this.r = 15;
this.gravity = 0.5;
this.velocity = 0;
this.sideV = 0
this.display = function() {
fill(255, 0, 100);
stroke(255);
ellipse(this.x, this.y, this.r * 2);
}
this.update = function() {
this.velocity += this.gravity;
this.y += this.velocity;
this.x += this.sideV;
this.sideV *= 0.98;
}
this.edges = function() {
if (this.y >= height - this.r) {
this.y = height - this.r;
this.velocity = this.velocity * -1;
this.gravity = this.gravity * 1.1;
}
}
}
function Obstacle() {
this.x = width - width;
this.y = height / 2;
this.w = 200;
this.h = 25;
this.display = function() {
fill(0);
stroke(255);
rect(this.x, this.y, this.w, this.h);
}
this.update = function() {
this.x++;
if (this.x > width + this.w /2) {
this.x = -this.w;
}
}
}
function IsectRectRect(l1, r1, t1, b1, l2, r2, t2, b2) {
return l1 < r2 && l2 < r1 && t1 < b2 && t2 < b1;
}
function reflect( V, N ) {
R = V.copy().sub(N.copy().mult(2.0 * V.dot(N)));
return R;
}
function RectCircleColliding(Ball, Obstacle) {
let oL = Obstacle.x;
let oR = Obstacle.x + Obstacle.w;
let oT = Obstacle.y;
let oB = Obstacle.y + Obstacle.h;
let bL = Ball.x - Ball.r;
let bR = Ball.x + Ball.r;
let bT = Ball.y - Ball.r;
let bB = Ball.y + Ball.r;
let isect = false;
let hitDir = createVector(0, 1);
if ( IsectRectRect(oL, oR, oT, oB, Ball.x, Ball.x, bT, bB) ) {
isect = true;
} else if ( IsectRectRect(oL, oL, oT, oB, bL, bR, bT, bB) ) {
hitDir = createVector(Ball.x, Ball.y).sub(createVector(oL, oT))
isect = hitDir.mag() < Ball.r;
} else if ( IsectRectRect(oR, oR, oT, oB, bL, bR, bT, bB) ) {
hitDir = createVector(Ball.x, Ball.y).sub(createVector(oR, oT))
isect = hitDir.mag() < Ball.r;
}
if ( isect ) {
let dir = createVector(Ball.sideV, Ball.velocity);
R = reflect(dir, hitDir.normalize());
Ball.velocity = R.y;
Ball.sideV = R.x;
let oldY = Ball.y;
Ball.y = oT - Ball.r;
if (Ball.gravity < 2.0){
Ball.gravity = Ball.gravity * 1.1;
} else {
Ball.velocity = 0;
Ball.y = oldY;
}
return true;
}
return false;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.7.3/p5.js"></script>
总结:
试图在移动的矩形和下落的圆圈之间制作一个简单的碰撞检测系统,我想让它更真实。
主要问题:
-我想解决的主要问题是检测圆对象何时击中矩形的角以及 return 圆根据该角度反弹。
代码:
var balls = [];
var obstacle;
function setup() {
createCanvas(400, 400);
obstacle = new Obstacle();
}
function draw() {
background(75);
obstacle.display();
obstacle.update();
for (var i = 0; i < balls.length; i++) {
balls[i].display();
if (!RectCircleColliding(balls[i], obstacle)){
balls[i].update();
balls[i].edges();
}
//console.log(RectCircleColliding(balls[i], obstacle));
}
}
function mousePressed() {
balls.push(new Ball(mouseX, mouseY));
}
function Ball(x, y) {
this.x = x;
this.y = y;
this.r = 15;
this.gravity = 0.5;
this.velocity = 0;
this.display = function() {
fill(255, 0, 100);
stroke(255);
ellipse(this.x, this.y, this.r * 2);
}
this.update = function() {
this.velocity += this.gravity;
this.y += this.velocity;
}
this.edges = function() {
if (this.y >= height - this.r) {
this.y = height - this.r;
this.velocity = this.velocity * -1;
this.gravity = this.gravity * 1.1;
}
}
}
function Obstacle() {
this.x = width - width;
this.y = height / 2;
this.w = 200;
this.h = 25;
this.display = function() {
fill(0);
stroke(255);
rect(this.x, this.y, this.w, this.h);
}
this.update = function() {
this.x++;
if (this.x > width + this.w /2) {
this.x = -this.w;
}
}
}
function RectCircleColliding(Ball, Obstacle) {
// define obstacle borders
var oRight = Obstacle.x + Obstacle.w;
var oLeft = Obstacle.x;
var oTop = Obstacle.y;
var oBottom = Obstacle.y + Obstacle.h;
//compare ball's position (acounting for radius) with the obstacle's border
if (Ball.x + Ball.r > oLeft) {
if (Ball.x - Ball.r < oRight) {
if (Ball.y + Ball.r > oTop) {
if (Ball.y - Ball.r < oBottom) {
let oldY = Ball.y;
Ball.y = oTop - Ball.r;
Ball.velocity = Ball.velocity * -1;
if (Ball.gravity < 2.0){
Ball.gravity = Ball.gravity * 1.1;
} else {
Ball.velocity = 0;
Ball.y = oldY;
}
return (true);
}
}
}
}
return false;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.7.3/p5.js"></script>
预期输出:
我希望看到下落的圆圈相对于它们击中矩形的位置从矩形反弹。
如果圆圈击中角落,它们应该以不同的方式反弹,而不是击中死点。
先决条件
小球的速度必须是矢量(XY分量),不能只是一个数字。
1。确定圆圈是否会撞到边或角
获取从矩形中心到圆的向量的分量,并与矩形的尺寸进行比较:
// Useful temporary variables for later use
var hx = 0.5 * obstacle.w;
var hy = 0.5 * obstacle.h;
var rx = obstacle.x + hx;
var ry = obstacle.y + hy;
// displacement vector
var dx = ball.x - rx;
var dy = ball.y - ry;
// signs
var sx = dx < -hx ? -1 : (dx > hx ? 1 : 0);
var sy = dy < -hy ? -1 : (dy > hy ? 1 : 0);
如果sx, sy
都不为零,则球可能击中角,否则可能击中侧面。
2。判断圆是否碰撞
将每个符号乘以各自的半维数:
// displacement vector from the nearest point on the rectangle
var tx = sx * (Math.abs(dx) - hx);
var ty = sy * (Math.abs(dy) - hy);
// distance from p to the center of the circle
var dc = Math.hypot(tx, ty);
if (dc <= ball.r) {
/* they do collide */
}
3。确定碰撞法向量
(tx, ty)
是法向量的分量,但前提是球的中心在矩形之外:
// epsilon to account for numerical imprecision
const EPSILON = 1e-6;
var nx = 0, ny = 0, nl = 0;
if (sx == 0 && sy == 0) { // center is inside
nx = dx > 0 ? 1 : -1;
ny = dy > 0 ? 1 : -1;
nl = Math.hypot(nx, ny);
} else { // outside
nx = tx;
ny = ty;
nl = dc;
}
nx /= nl;
ny /= nl;
4。解决任何“渗透”
(请勿恶作剧)
这确保球永远不会穿透矩形的表面,从而提高碰撞的视觉质量:
ball.x += (ball.r - dc) * nx;
ball.y += (ball.r - dc) * ny;
5。解决冲突
如果圆在法线方向移动,不要解决碰撞,因为球可能会粘在表面上:
// dot-product of velocity with normal
var dv = ball.vx * nx + ball.vy * ny;
if (dv >= 0.0) {
/* exit and don't do anything else */
}
// reflect the ball's velocity in direction of the normal
ball.vx -= 2.0 * dv * nx;
ball.vy -= 2.0 * dv * ny;
工作 JS 片段
const GRAVITY = 250.0;
function Ball(x, y, r) {
this.x = x;
this.y = y;
this.r = r;
this.vx = 0;
this.vy = 0;
this.display = function() {
fill(255, 0, 100);
stroke(255);
ellipse(this.x, this.y, this.r * 2);
}
this.collidePage = function(b) {
if (this.vy > 0 && this.y + this.r >= b) {
this.y = b - this.r;
this.vy = -this.vy;
}
}
this.updatePosition = function(dt) {
this.x += this.vx * dt;
this.y += this.vy * dt;
}
this.updateVelocity = function(dt) {
this.vy += GRAVITY * dt;
}
}
function Obstacle(x, y, w, h) {
this.x = x;
this.y = y;
this.w = w;
this.h = h;
this.display = function() {
fill(0);
stroke(255);
rect(this.x, this.y, this.w, this.h);
}
this.update = function() {
this.x++;
if (this.x > width + this.w /2) {
this.x = -this.w;
}
}
}
var balls = [];
var obstacle;
function setup() {
createCanvas(400, 400);
obstacle = new Obstacle(0, height / 2, 200, 25);
}
const DT = 0.05;
function draw() {
background(75);
obstacle.update();
obstacle.display();
for (var i = 0; i < balls.length; i++) {
balls[i].updatePosition(DT);
balls[i].collidePage(height);
ResolveRectCircleCollision(balls[i], obstacle);
balls[i].updateVelocity(DT);
balls[i].display();
}
}
function mousePressed() {
balls.push(new Ball(mouseX, mouseY, 15));
}
const EPSILON = 1e-6;
function ResolveRectCircleCollision(ball, obstacle) {
var hx = 0.5 * obstacle.w, hy = 0.5 * obstacle.h;
var rx = obstacle.x + hx, ry = obstacle.y + hy;
var dx = ball.x - rx, dy = ball.y - ry;
var sx = dx < -hx ? -1 : (dx > hx ? 1 : 0);
var sy = dy < -hy ? -1 : (dy > hy ? 1 : 0);
var tx = sx * (Math.abs(dx) - hx);
var ty = sy * (Math.abs(dy) - hy);
var dc = Math.hypot(tx, ty);
if (dc > ball.r)
return false;
var nx = 0, ny = 0, nl = 0;
if (sx == 0 && sy == 0) {
nx = dx > 0 ? 1 : -1; ny = dy > 0 ? 1 : -1;
nl = Math.hypot(nx, ny);
} else {
nx = tx; ny = ty;
nl = dc;
}
nx /= nl; ny /= nl;
ball.x += (ball.r - dc) * nx; ball.y += (ball.r - dc) * ny;
var dv = ball.vx * nx + ball.vy * ny;
if (dv >= 0.0)
return false;
ball.vx -= 2.0 * dv * nx; ball.vy -= 2.0 * dv * ny;
return true;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.7.3/p5.min.js"></script>
我将尝试提出一个解决方案,该解决方案尽可能与原始代码保持一致。该解决方案旨在成为问题中提供的代码的演变。
给初始化为0的Ball
对象添加侧向移动(selv.sideV
):
function Ball(x, y) {
this.x = x;
this.y = y;
this.r = 15;
this.gravity = 0.5;
this.velocity = 0;
this.sideV = 0
// ...
}
将球移到update
的一侧,通过侧向运动减少侧向运动:
this.update = function() {
this.velocity += this.gravity;
this.y += this.velocity;
this.x += this.sideV;
this.sideV *= 0.98;
}
为 2 个框的相交测试创建函数:
function IsectRectRect(l1, r1, t1, b1, l2, r2, t2, b2) {
return l1 < r2 && l2 < r1 && t1 < b2 && t2 < b1;
}
还有一个函数可以计算入射向量V
到表面法向量N
的反射向量R
(像台球一样的反射):
function reflect( V, N ) {
R = V.copy().sub(N.copy().mult(2.0 * V.dot(N)));
return R;
}
当 Ball
与 Obstacle
发生碰撞时,您必须处理 3 种情况。
- 球完全击中
Obstacle
的顶部:IsectRectRect(oL, oR, oT, oB, Ball.x, Ball.x, bT, bB)
- 球击中
Obstacle
的左边缘:IsectRectRect(oL, oL, oT, oB, bL, bR, bT, bB)
- 球击中
Obstacle
的右边缘:IsectRectRect(oR, oR, oT, oB, bL, bR, bT, bB)
在每种情况下都必须计算反射的法向量。这是从 Obstacle
的顶部或边缘到 Ball
的中心的向量。
使用函数 reflect
将 Ball
弹回 Obstacle
:
function RectCircleColliding(Ball, Obstacle) {
let oL = Obstacle.x;
let oR = Obstacle.x + Obstacle.w;
let oT = Obstacle.y;
let oB = Obstacle.y + Obstacle.h;
let bL = Ball.x - Ball.r;
let bR = Ball.x + Ball.r;
let bT = Ball.y - Ball.r;
let bB = Ball.y + Ball.r;
let isect = false;
let hitDir = createVector(0, 1);
if ( IsectRectRect(oL, oR, oT, oB, Ball.x, Ball.x, bT, bB) ) {
isect = true;
} else if ( IsectRectRect(oL, oL, oT, oB, bL, bR, bT, bB) ) {
hitDir = createVector(Ball.x, Ball.y).sub(createVector(oL, oT))
isect = hitDir.mag() < Ball.r;
} else if ( IsectRectRect(oR, oR, oT, oB, bL, bR, bT, bB) ) {
hitDir = createVector(Ball.x, Ball.y).sub(createVector(oR, oT))
isect = hitDir.mag() < Ball.r;
}
if ( isect ) {
let dir = createVector(Ball.sideV, Ball.velocity);
R = reflect(dir, hitDir.normalize());
Ball.velocity = R.y;
Ball.sideV = R.x;
let oldY = Ball.y;
Ball.y = oT - Ball.r;
if (Ball.gravity < 2.0){
Ball.gravity = Ball.gravity * 1.1;
} else {
Ball.velocity = 0;
Ball.y = oldY;
}
return true;
}
return false;
}
查看示例,其中我将更改应用于您的原始代码:
var balls = [];
var obstacle;
function setup() {
createCanvas(400, 400);
obstacle = new Obstacle();
}
function draw() {
background(75);
obstacle.display();
obstacle.update();
for (var i = 0; i < balls.length; i++) {
balls[i].display();
if (!RectCircleColliding(balls[i], obstacle)){
balls[i].update();
balls[i].edges();
}
//console.log(RectCircleColliding(balls[i], obstacle));
}
}
function mousePressed() {
balls.push(new Ball(mouseX, mouseY));
}
function Ball(x, y) {
this.x = x;
this.y = y;
this.r = 15;
this.gravity = 0.5;
this.velocity = 0;
this.sideV = 0
this.display = function() {
fill(255, 0, 100);
stroke(255);
ellipse(this.x, this.y, this.r * 2);
}
this.update = function() {
this.velocity += this.gravity;
this.y += this.velocity;
this.x += this.sideV;
this.sideV *= 0.98;
}
this.edges = function() {
if (this.y >= height - this.r) {
this.y = height - this.r;
this.velocity = this.velocity * -1;
this.gravity = this.gravity * 1.1;
}
}
}
function Obstacle() {
this.x = width - width;
this.y = height / 2;
this.w = 200;
this.h = 25;
this.display = function() {
fill(0);
stroke(255);
rect(this.x, this.y, this.w, this.h);
}
this.update = function() {
this.x++;
if (this.x > width + this.w /2) {
this.x = -this.w;
}
}
}
function IsectRectRect(l1, r1, t1, b1, l2, r2, t2, b2) {
return l1 < r2 && l2 < r1 && t1 < b2 && t2 < b1;
}
function reflect( V, N ) {
R = V.copy().sub(N.copy().mult(2.0 * V.dot(N)));
return R;
}
function RectCircleColliding(Ball, Obstacle) {
let oL = Obstacle.x;
let oR = Obstacle.x + Obstacle.w;
let oT = Obstacle.y;
let oB = Obstacle.y + Obstacle.h;
let bL = Ball.x - Ball.r;
let bR = Ball.x + Ball.r;
let bT = Ball.y - Ball.r;
let bB = Ball.y + Ball.r;
let isect = false;
let hitDir = createVector(0, 1);
if ( IsectRectRect(oL, oR, oT, oB, Ball.x, Ball.x, bT, bB) ) {
isect = true;
} else if ( IsectRectRect(oL, oL, oT, oB, bL, bR, bT, bB) ) {
hitDir = createVector(Ball.x, Ball.y).sub(createVector(oL, oT))
isect = hitDir.mag() < Ball.r;
} else if ( IsectRectRect(oR, oR, oT, oB, bL, bR, bT, bB) ) {
hitDir = createVector(Ball.x, Ball.y).sub(createVector(oR, oT))
isect = hitDir.mag() < Ball.r;
}
if ( isect ) {
let dir = createVector(Ball.sideV, Ball.velocity);
R = reflect(dir, hitDir.normalize());
Ball.velocity = R.y;
Ball.sideV = R.x;
let oldY = Ball.y;
Ball.y = oT - Ball.r;
if (Ball.gravity < 2.0){
Ball.gravity = Ball.gravity * 1.1;
} else {
Ball.velocity = 0;
Ball.y = oldY;
}
return true;
}
return false;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.7.3/p5.js"></script>