[30 분] 완성 애니메이션 캔버스 | 게임 단위 (4)의 경계와 충돌

머리말

여러 개체들은이 시리즈는 여기에 캔버스 케이스 부족에,이 문제를 해결하는 것입니다 나타납니다.
당신이 기본 앞에 누워하도록 요청하기 전에 본 설명서를 읽어주십시오.
그들은 비판을 가축 논의에 오신 것을 환영합니다 사람들에게 제한된 능력을 가지고있다.

국경 간 감지

이는 물체가 원형 인 것으로 가정한다, 즉,도 그 객체의 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;
}

리바운드 (거친 버전)

이것은 더 복잡한 경우가, 객체는 경계도 접촉 면적 경우 국경에 속한다. 기본적인 아이디어 :

  1. 객체는 임의의 경계에 걸쳐있는 경우;
  2. 국경 경우, 오브젝트의 경계에 즉시 세트 다시;
  3. 물체의 속도 벡터의 방향을 반전.

다음 예는 캔버스에 움직이는 공, 그것은 핵심 코드의 경계 바운스가 그대로 다음했다.
전체 예제 : 튀는 공 (거친 버전)

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 축에 대한 "실제 반송 포인트" 거리. 도시 된 바와 같이, 예로서, 국경의 아이디어의 좌우측 :

이상적인 포인트 랠리를 찾는

  1. 이것은 아크 각 오브젝트의 속도의 방향으로부터 얻을 수있다;
  2. x 축에서 거리 "바운스를 통해" "진짜 랠리 포인트"등을 계산하는 단계;
  3. 기반 접선 추구 y 축에서 "바운스를 통해" "진짜 랠리 포인트"및;
  4. 는 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 = '';
}

추천

출처www.cnblogs.com/baimeishaoxia/p/11962552.html