Chủ Nhật, 28 tháng 2, 2021

Tích vô hướng (Dot Product) là gì? Làm sao để ứng dụng trong lập trình game?

 Hello mụi người, cũng hơn 40 ngày nghỉ tết thì cũng bắt đầu trở lại trường rồi, tranh thủ rảnh rỗi mấy ngày cuối giới thiệu cho mấy bạn thấy được sức mạnh của Tích Vô Hướng chứ thấy mấy bạn if else hơi cực, chưa kể if else mà sai logic thì lại hư các game.

 Tích vô hướng cũng chả xa lạ gì đối với các bạn vì nó đã được dạy trong chương trình phổ thông, cụ thể là sách toán lớp 10. Cũng nhớ hồi đó lười học mà tơi chương Vector chả hiểu sao ham học nên giờ cũng còn nhớ sơ sơ :))

Đây là một bài rất nặng lý thuyết, các bạn nhớ trang bị kĩ kiến thức toán khi đọc nhé

Tích vô hướng là cái vẹo gì?

Tích vô hướng (tên tiếng Anh: dot product hoặc scalar product) là một phép toán đại số lấy hai chuỗi số có độ dài bằng nhau (thường là các vectơ tọa độ) và cho kết quả là một số. Trong hình học Euclid, tích vô hướng với tọa độ Descartes của hai vectơ thường được sử dụng. Tích vô hướng cũng thường được gọi là tích trong Euclid dù nó không phải là loại tích trong duy nhất có thể được định nghĩa trong không gian Euclid (xem thêm tại Không gian tích trong).  (Theo wikipedia)

Đọc xong cái định nghĩa tắt mẹ cái blog đi ngủ cho khỏe, hù chút thôi chứ mình cũng có hiểu mẹ gì đâu, tuy nhiên phát biểu đại số của nó sẽ dễ hiểu hơn thế này

ab=i=1naibi=a1b1+a2b2+...+anbn

Ví dụ:

Đây là phát biểu kiểu công thức xưa mình hay dùng. Tuy nhiên đối với mình tích vô hướng là độ lớn của vector VÀ độ lớn của phép chiếu của vector còn lại lên lên nó

được phát biểu công thức dưới dạng

(bản chất của Tích Vô Hướng)


Ứng dụng trong Đường Tròn Lượng Giác

Và đặc biệt hơn Chúng ta thường áp dụng Dot Product trong đường tròn lượng giác hay Unit Circle (Có bán kính = 1) hơn thay vì các trường hợp tổng quát



Khi áp dụng trong Unit Circle, ta sẽ có hình chiếu của vector lên vector còn lại cũng chính là tích vô hướng của 2 vector (bạn có thể chứng minh từ công thức trên)

Trong gif trên, đường màu tím chiếu vuông góc từ vector quay chính là tích vô hướng của 2 vector đó

Ứng dụng trong lập trình game

Trong unity đã implement công thức tích vô hướng, chúng ta chỉ việc lấy ra xài thôi. Đó chính là Vector2.Dot or Vector3.Dot

Sau đây mình sẽ liệt kê 2 cách mình hay dùng khi ứng dụng Dot, đây chỉ là ứng dụng rất rất nhỏ của Dot Product

1.Xác định vị trí vật thể

Các bạn thử suy nghĩ, có 2 object như hình sau, với player là khối chữ nhất màu xanh và enemy là hình tròn màu đỏ. Vậy làm sao để kiểm tra khi nào enemy nằm ở: trước, sau, trái, phải của Player.



Mình sẽ chắc chắn trong đầu các bạn sẽ là 1 loạt các dòng if else dài ngoằn chỉ để check. Player nằm vậy còn đơn giản nhé, chứ nó mà xoay ngang, xoay dọc thì bạn if else hồi loạn xì ngầu lên á :))

Dot Product hỗ trợ ta làm việc này cực tốt. Quay lại gif trên, để ý vector hướng lên trên là vector hướng của player, và vector quay là vector từ player tới enemy. Khi đó ta có Dot > 0 => nó nằm ở phía trước của player và ngược lại Dot < 0 ta có nó nằm phía sau player.

Tiếp tục check trái phải. Để ý khi chiếu vector xoay lên trục hoành (trục Cos) thì khi Dot >0 thì enemy nằm bên phải và khi Dot < 0 thì enemy nằm bên trái. Very easy.

[SerializeFieldTransform enemy = default;
 
private void Update()
{
    //DOT PRODUCT
    Vector2 playerToEnemy = enemy.position - this.transform.position;
    float dotProduct;
 
    //FRONT , BEHIND
    dotProduct = Vector2.Dot(transform.up, playerToEnemy);
    if (dotProduct > 0Debug.Log("Front");
    else if (dotProduct < 0Debug.Log("Behind");
    else Debug.Log("Middle");
 
    //LEFT , RIGHT
    dotProduct = Vector2.Dot(transform.right, playerToEnemy);
    if (dotProduct > 0Debug.Log("Right");
    else if (dotProduct < 0Debug.Log("Left");
    else Debug.Log("Middle");
}

2.Điều chỉnh âm thanh khi va chạm

Vấn đề là khi player va chạm với một vật thể nào đó, để chân thật nhất chúng ta phải tính volume sao cho to nhỏ hợp lý với lực tác động.





Trong hình trên, hình tròn là player, di chuyển với v = 10m/s hướng xuống đất.


Nhiều bạn nhanh lẹ sẽ suy nghĩ rằng. Đặt volume = độ lớn vận tốc. Ok tạm chấp nhận được, nhưng hay xét đến trường hợp dưới đây







Trong TH2 ta thấy quả bóng gần như là chạm mặt đất nhưng vẫn di chuyển với v = 10 m/s. => Khi chạm đất volume nó sẽ ngang quả bóng thả thẳng từ trên cao xuống => sai logic

Dot Product sẽ hỗ trợ ta giải quyết chuyện này nhanh gọn, xem hình dưới đây (Lưu ý: vector hướng mình vẽ là vector vận tốc (v) đấy nhé)








Chỉ cần lấy Dot Product giữa Vector vận tốc và vector hướng lên (Vector2.Up) là xong => Dot Product = khoảng cách màu đỏ như hình vẽ (do Vector2.Up có độ lớn = 1)


Đây là cách mà mình Implement

[SerializeFieldAudioSource _audio;
[SerializeFieldRigidbody2D _rig;
 
private void OnValidate()
{
    _audio = GetComponent<AudioSource>();
    _rig = GetComponent<Rigidbody2D>();
}
 
 
private void OnCollisionEnter2D(Collision2D collision)
{
    _audio.volume = Mathf.Abs(Vector2.Dot(transform.up, _rig.velocity))/ 10f;
    _audio.Play();
}


Tổng kết

Sức mạnh của Dot Product vẫn còn rất nhiều, đó là mình chỉ demo sơ sơ cho bạn xem thôi đó. Đại đa số các game developer tận dụng sức mạnh của Dot Product rất triệt để. Oke, bài này hơi nặng lý thuyết nhưng mong các bạn cố hiểu và nếu có gì thắc mắc nhớ để lại comment để mình giải đáp nhé.


Share:

2 nhận xét:

  1. Một trang hữu ích ad ạ. Uptade thêm vè des game online thì good

    Trả lờiXóa