머리말
여러 개체들은이 시리즈는 여기에 캔버스 케이스 부족에,이 문제를 해결하는 것입니다 나타납니다.
당신이 기본 앞에 누워하도록 요청하기 전에 본 설명서를 읽어주십시오.
그들은 비판을 가축 논의에 오신 것을 환영합니다 사람들에게 제한된 능력을 가지고있다.
국경 간 감지
이는 물체가 원형 인 것으로 가정한다, 즉,도 그 객체의 X 축 중심의 좌표와 y 축 좌표.
국경 간 시나리오는 일반적으로 두 국경 시나리오가, 공통 : 영역에서 먼저 전체 개체를 제 2 목적은 경계 영역을 터치. 우리는 예를 들면, 예를 들어 직사각형 경계를 캔버스 경계를 토론
let top = 0;
let bottom = canvas.height;
let left = 0;
let right = canvas.width;
객체의 전체 영역 중
다음 중 어떤 범위에 해당 결정되는 범위의 경계에서 전체 객체를 벗어나지 간주, 경계는 다음의 조건을 얻을 수있다.
// 右侧越界
object.x - object.width/2 > right
// 左侧越界
object.x + object.width/2 < left
// 上部越界
object.y + object.height/2 < top
// 下部越界
object.y - object.height/2 > bottom
개체의 경계 영역을 접촉
물체가 접촉 경계 영역의 경계에있는 경우에도 다음 중 어떤 범위에 해당 결정되는, 경계는 다음의 조건을 얻을 수있다.
// 右侧越界
object.x + object.width/2 > right
// 左侧越界
object.x - object.width/2 < left
// 上部越界
object.y - object.height/2 < top
// 下部越界
object.y + object.height/2 > bottom
국경을 수행하는 방법
철저하게 국경 조건을 이해 한 후 보통 4에 대해, 국경 간 접근 한 후, 다음 논의했다.
개체는 제거
이 범위를 벗어 간주 지역의 전체 몸 밖으로에 속하는 상황을 처리하는 가장 간단한 방법입니다.
다음의 예는 공을 먼저 배치를 만들 것이다 어레이에 저장 공 각 애니메이션주기 () 함수에 입력 연신 하였다 어레이를 통과 공의 위치를 변경하고 국경 여부를 검출한다. 다음은 () 함수 코드 무승부를 설명합니다.
전체 예제 : 클리어 라운드 경계
function draw(ball, pos) {
// 依据球的速度改变球的位置
ball.x += ball.vx;
ball.y += ball.vy;
// 检查是否越界
if (ball.x - ball.radius > canvas.width || ball.x + ball.radius < 0 || ball.y - ball.radius > canvas.height || ball.y + ball.radius < 0) {
// 在数组中清除越界的球
balls.splice(pos, 1);
// 打印提示
if (balls.length > 0) {
log.value += `Removed ${ball.id}\n`;
log.scrollTop = log.scrollHeight;
} else {
log.value += 'All gone!\n';
}
}
// 画球
ball.draw(context);
}
그것은 개체의 경계 내에 다시 설정
이 객체가 범위를 벗어 간주되는 지역에 속한다.
다음은 생성 된 배열 저장 공의 공 예 공의 검출 위치가 재설정되는 경우, 볼의 초기 위치가 범위 밖으로 공 캔버스의 하부의 중앙에있다. 다음은 () 함수 코드 무승부를 설명합니다.
전체 예제 : 컬러 분수
function draw(ball) {
// 依据球的速度改变球的位置,这里包含了伪重力
ball.vy += gravity;
ball.x += ball.vx;
ball.y += ball.vy;
// 检测是否越界
if (ball.x - ball.radius > canvas.width || ball.x + ball.radius < 0 || ball.y - ball.radius > canvas.height || ball.y + ball.radius < 0) {
// 重置ball的位置
ball.x = canvas.width / 2;
ball.y = canvas.height;
// 重置ball的速度
ball.vx = Math.random() * 6 - 3;
ball.vy = Math.random() * -10 - 10;
// 打印提示
log.value = `Reset ${ball.id}\n`;
}
// 画球
ball.draw(context);
}
화면 서라운드
이 객체가 범위를 벗어 간주되는 지역에 속한다.
화면 주위에이 물체가 화면의 왼쪽에서 제거하면 객체가 경계 내의 다른 위치에 동일하게 표시하는 것입니다, 그것은 화면의 오른쪽에 다시 나타나고, 그 반대의 경우도 마찬가지, 같은 이유는 수직이다.
다음과 같이 여기에 좀 더 이전의 점프 판정 대상 측보다 복잡는 의사 코드, 바운스된다 :
if(object.x - object.width/2 > right){
object.x = left - object.widht/2;
}else if(object.x + object.width/2 < left){
object.x = right + object.width/2;
}
if(object.y - object.height/2 > bottom){
object.y = top - object.height/2;
}else if(object.y + object.height/2 < top){
obejct.y = bottom + object.height/2;
}
리바운드 (거친 버전)
이것은 더 복잡한 경우가, 객체는 경계도 접촉 면적 경우 국경에 속한다. 기본적인 아이디어 :
- 객체는 임의의 경계에 걸쳐있는 경우;
- 국경 경우, 오브젝트의 경계에 즉시 세트 다시;
- 물체의 속도 벡터의 방향을 반전.
다음 예는 캔버스에 움직이는 공, 그것은 핵심 코드의 경계 바운스가 그대로 다음했다.
전체 예제 : 튀는 공 (거친 버전)
if (ball.x + ball.radius > right) {
ball.x = right - ball.radius;
vx *= -1;
} else if (ball.x - ball.radius < left) {
ball.x = left + ball.radius;
vx *= -1;
}
if (ball.y + ball.radius > bottom) {
ball.y = bottom - ball.radius;
vy *= -1;
} else if (ball.y - ball.radius < top) {
ball.y = top + ball.radius;
vy *= -1;
}
리바운드 (완벽한 버전)
눈에, 우리는이 객체의 경계를 다시 설정합니다처럼 정확 연습, 좋은 결과를 보이지만, 그것에 대해 생각?
답은 아래 그림과 같이 이상과 실제 반등 랠리는 다른, 아니입니다 :
우리가 알을 취소 할 수 있습니다 그림에서 볼 실제로 속도가 너무 큰 경우, 볼의 위치 계산이 "실제 바운스 점"에 도달하는 "이상적인 바운스 점"을 넘어 때문에, 이상적인 랠리 포인트 반등 할 가능성이 없습니다, 우리 단지 x가 간단하고 원유를 이동하는 경계에 공의 좌표가 여전히이 반등이 수행되지 않았 음을, "이상적인 바운스 포인트"가 될 수 없습니다.
그래서, 완벽한 바운스 아이디어는 명확하게, 우리는 "이상적인 바운스 점"을 찾을 필요가 있고, 공은 그 시점으로 설정됩니다. 좌측이 범위를 벗어날 경우, Y 축에서 "실제 낸 지점"및 "포인트 위에 바운스"계산, 상하의 범위이면 "지점 위에 바운스"를 계산하고, X 축에 대한 "실제 반송 포인트" 거리. 도시 된 바와 같이, 예로서, 국경의 아이디어의 좌우측 :
- 이것은 아크 각 오브젝트의 속도의 방향으로부터 얻을 수있다;
- x 축에서 거리 "바운스를 통해" "진짜 랠리 포인트"등을 계산하는 단계;
- 기반 접선 추구 y 축에서 "바운스를 통해" "진짜 랠리 포인트"및;
- 는 IS "바운스 동안" "진짜 랠리 포인트"플러스이 거리를 y 좌표.
너무 많은 계산을 할 필요가 없기 때문에 변환 후, 핵심 코드는 다음과 같이, 성능과 정밀도를 무게하는 것이 필요하다.
전체 예제 : 튀는 공 (완벽한 버전)
if (ball.x + ball.radius > right) {
const dx = ball.x - (right - ball.radius);
const dy = Math.tan(angle) * dx;
ball.x = right - ball.radius;
ball.y += dy;
vx *= bounce;
} else if (ball.x - ball.radius < left) {
const dx = ball.x - (left + ball.radius);
const dy = Math.tan(angle) * dx;
ball.x = left + ball.radius;
ball.y += dy;
vx *= bounce;
}
if (ball.y + ball.radius > bottom) {
const dy = ball.y - (bottom - ball.radius);
const dx = dy / Math.tan(angle);
ball.y = bottom - ball.radius;
ball.x += dx;
vy *= bounce;
} else if (ball.y - ball.radius < top) {
const dy = ball.y - (top + ball.radius);
const dx = dy / Math.tan(angle);
ball.y = top + ball.radius;
ball.x += dx;
vy *= bounce;
}
충돌 감지
그리고 같은 검사 범위, 우리는 일반적으로 다음과 같은 두 가지 방법으로 사용되는 두 개체 사이에 충돌 감지를 확장 할 수 있습니다.
기하학 기반 충돌 감지
일반적으로 사용된다 충돌 검출 사각형 결정할지 여부 원리 물체와 다른 물체 오버랩.
다음 두 가지 유틸리티 함수를 직접 감지 주어진다. 전체 예제 :
// 两个矩形碰撞检测
function intersects(rectA, rectB) {
return !(rectA.x + rectA.width < rectB.x ||
rectB.x + rectB.width < rectA.x ||
rectA.y + rectA.height < rectB.y ||
rectB.y + rectB.height < rectA.y);
};
// 矩形与点碰撞检测
function containsPoint(rect, x, y) {
return !(x < rect.x || x > rect.x + rect.width || y < rect.y || y > rect.y + rect.height);
};
거리에 따라 충돌 검출
일반적으로 사용된다 검출 원형 충돌 의 원리는 두 개의 충돌에 가까운만큼 개체 여부를 결정하는 것이다.
라운드 들어만큼 개의 중심 간 거리가 작은 원을 두 반경보다, 우리는 충돌이 있는지를 결정할 수있다. 에 의해 중심 거리 피타고라스의 정리 를 얻을 수있다. 다음 코어 코드 :
완전 예 : 두 라운드 거리 기반 충돌 데모
const dx = ballB.x - ballA.x;
const dy = ballB.y - ballA.y;
const dist = Math.sqrt(dx ** 2 + dy ** 2);
if (dist < ballA.radius + ballB.radius) {
log.value = 'Hit!';
} else {
log.value = '';
}