Game là sự mô phỏng một cách khái quát nào đó thế giới thực. Nhưng muốn mô phỏng được các tình huống như ở thế giới thực thì cần phải biết phát hiện va chạm, lực đàn hồi, độ đàn hồi, ma sát… Va chạm giữa hình tròn và hình chữ nhật là một trong những va chạm cơ bản các lập trình viên cần biết để phát triển việc học tập lập trình Game của bản thân.
Data Structure & Algorithm C/C++ Tran Khanh Nguyen 2015-11-23 22:03:47

Giới thiệu

Game là sự mô phỏng một cách khái quát nào đó thế giới thực. Nhưng muốn mô phỏng được các tình huống như ở thế giới thực thì cần phải biết phát hiện va chạm, lực đàn hồi, độ đàn hồi, ma sát… Trong bài viết này tôi sẽ giới thiệu cho các bạn một trong các tình huống đó là phát hiện va chạm mà cụ thể là va chạm giữa hình tròn và hình chữ nhật.

Thuật toán

Gọi C(Xc,Yc) là tâm hình tròn có bán kính là R. Ta tìm điểm A là điểm gần nhất thuộc hình chữ nhật đến tâm C. So sánh độ dài CA và R. Nếu CA<=R thì va chạm. CA>R thì không va chạm. (Khi C nằm trong HCN thì C trùng A).

Khoảng cách CA được biểu diễn như hình vẽ:

collision_detect_rect_circle

Để tính được CA thì ta xác định điểm A theo thuật toán sau:

  • B1: Gán A = C (Xa = Xc, Ya = Yc)
  • B2: Nếu Xc < rect.left thì Xa=rect.left
    • Xc > rect.right thì Xa = rect.right
    • Xc >= rect.left && Xc <= rect.right thì Xa = Xc
  • B3: Nếu Yc < rect.top thì Ya = rect.top
    • Nếu Yc > rect.bottom thì Ya = rect.bottom
    • Nếu Yc >= rect.top && Yc<= rect.right thì Ya = Yc 

(Ta làm như vậy vì trong màn hình điểm 0(0,0) nằm ở góc trên bên trái màn hình, trục tọa độ hướng xuống)

Có điểm A ta tính CA rồi so sánh với R.

Hiện thực

Khai báo các thành phần của hình tròn và hình chữ nhật

struct Point
{
      float x;
      float y;
};

struct Circle
{
      Point I; // I là tâm của hình tròn
      float radius; // bán kính
};

struct Rectangle
{
      float top;
      float bottom;
      float left;
      float right;
};

Hàm xét va chạm giữa hình chữ nhật và hình tròn

bool CheckCollision(Rectangle rect, Circle cir)
{
    float Ax = cir.I.x;
    float Ay = cir.I.y;

    if(cir.I.x < rect.left)
        Ax = rect.left;
    else if(cir.I.x > rect.right)
        Ax = rect.right;

    if(cir.I.y < rect.top)
        Ay = rect.top;
    else if(cir.I.y > rect.bottom)
        Ay = rect.bottom;

    float dx = cir.I.x - Ax;
    float dy = cir.I.y - Ay;

    return (dx * dx + dy * dy) <= cir.radius * cir.radius;
}

Download Demo

STDIO - CheckCollision