Làm cách nào tôi có thể hạn chế chuyển động của người chơi lên bề mặt của vật thể 3D bằng Unity?


16

Tôi đang cố gắng tạo hiệu ứng tương tự như Mario Galaxy hoặc Geometry Wars 3 khi người chơi đi vòng quanh "hành tinh" trọng lực dường như điều chỉnh và họ không rơi ra khỏi rìa của vật thể như khi trọng lực đã được cố định theo một hướng duy nhất.

nhập mô tả hình ảnh ở đây
(nguồn: gameskinny.com )

Cuộc chiến hình học 3

Tôi đã xoay sở để thực hiện một cái gì đó gần với những gì tôi đang tìm kiếm bằng cách sử dụng một phương pháp trong đó vật thể có lực hấp dẫn sẽ thu hút các vật thể cứng nhắc khác về phía nó, nhưng bằng cách sử dụng công cụ vật lý tích hợp cho Unity, áp dụng chuyển động với AddForce và những thứ tương tự, Tôi không thể có được phong trào để cảm thấy đúng. Tôi không thể khiến người chơi di chuyển đủ nhanh mà không cần người chơi bắt đầu bay khỏi bề mặt của vật thể và tôi không thể tìm thấy sự cân bằng tốt về lực và trọng lực được áp dụng để phù hợp với điều này. Triển khai hiện tại của tôi là một bản phóng tác của những gì được tìm thấy ở đây

Tôi cảm thấy như giải pháp có thể vẫn sử dụng vật lý để khiến người chơi tiếp đất với vật thể nếu họ rời khỏi bề mặt, nhưng một khi người chơi đã được nối đất, sẽ có cách để người chơi chạm vào bề mặt và tắt vật lý và điều khiển người chơi thông qua các phương tiện khác nhưng tôi thực sự không chắc chắn.

Tôi nên làm theo cách tiếp cận nào để đưa người chơi lên bề mặt vật thể? Lưu ý rằng giải pháp sẽ hoạt động trong không gian 3D (trái ngược với 2D) và có thể được triển khai bằng phiên bản Unity miễn phí.



Tôi thậm chí không nghĩ đến việc tìm kiếm đi bộ trên tường. Tôi sẽ xem và xem nếu những giúp đỡ này.
SpartanDovy

1
Nếu câu hỏi này cụ thể về việc thực hiện điều này trong 3D trong Unity, thì nó sẽ được làm rõ hơn với các chỉnh sửa. (Nó sẽ không phải là một bản sao chính xác của cái hiện có sau đó.)
Anko

Đó cũng là cảm nhận chung của tôi - Tôi sẽ xem liệu tôi có thể điều chỉnh giải pháp đó thành 3D hay không và đăng nó dưới dạng câu trả lời (hoặc nếu ai đó có thể đánh bại tôi với cú đấm tôi cũng sẽ ổn với điều đó). Tôi sẽ thử và cập nhật câu hỏi của tôi để rõ hơn về điều đó.
SpartanDovy

Có khả năng hữu ích: youtube.com/watch?v=JMWnufriQx4
ssb

Câu trả lời:


7

Tôi đã xoay sở để hoàn thành những gì tôi cần, chủ yếu là với sự hỗ trợ của bài đăng trên blog này cho mảnh ghép bề mặt của câu đố và đưa ra ý tưởng của riêng tôi cho chuyển động của người chơi và máy ảnh.

Đưa người chơi lên bề mặt của một vật thể

Thiết lập cơ bản bao gồm một quả cầu lớn (thế giới) và một quả cầu nhỏ hơn (người chơi) cả với các máy va chạm hình cầu gắn liền với chúng.

Phần lớn công việc đang được thực hiện là theo hai phương pháp sau:

private void UpdatePlayerTransform(Vector3 movementDirection)
{                
    RaycastHit hitInfo;

    if (GetRaycastDownAtNewPosition(movementDirection, out hitInfo))
    {
        Quaternion targetRotation = Quaternion.FromToRotation(Vector3.up, hitInfo.normal);
        Quaternion finalRotation = Quaternion.RotateTowards(transform.rotation, targetRotation, float.PositiveInfinity);

        transform.rotation = finalRotation;
        transform.position = hitInfo.point + hitInfo.normal * .5f;
    }
}

private bool GetRaycastDownAtNewPosition(Vector3 movementDirection, out RaycastHit hitInfo)
{
    Vector3 newPosition = transform.position;
    Ray ray = new Ray(transform.position + movementDirection * Speed, -transform.up);        

    if (Physics.Raycast(ray, out hitInfo, float.PositiveInfinity, WorldLayerMask))
    {
        return true;
    }

    return false;
}

Các Vector3 movementDirectionthông số chỉ là như âm thanh, hướng chúng ta sẽ được di chuyển máy nghe nhạc của chúng tôi trong khung này, và tính toán vector rằng, trong khi kết thúc tương đối đơn giản trong ví dụ này, là một chút khó khăn cho tôi để tìm ra lúc đầu. Nhiều hơn về điều đó sau, nhưng hãy nhớ rằng đó là một vectơ chuẩn hóa theo hướng người chơi đang di chuyển khung này.

Bước qua, điều đầu tiên chúng ta làm là kiểm tra xem một tia, xuất phát từ vị trí tương lai giả định hướng về phía người chơi vectơ (-transform.up) tấn công thế giới bằng WorldLayerMask, một thuộc tính LayerMask công khai của tập lệnh. Nếu bạn muốn va chạm phức tạp hơn hoặc nhiều lớp, bạn sẽ phải xây dựng mặt nạ lớp của riêng mình. Nếu raycast tấn công thành công thứ gì đó, hitInfo sẽ được sử dụng để lấy điểm bình thường và điểm nhấn để tính toán vị trí và góc quay mới của trình phát cần ở ngay trên đối tượng. Bù đắp vị trí của người chơi có thể được yêu cầu tùy thuộc vào kích thước và nguồn gốc của đối tượng người chơi được đề cập.

Cuối cùng, điều này thực sự chỉ được thử nghiệm và có khả năng chỉ hoạt động tốt trên các đối tượng đơn giản như hình cầu. Khi bài đăng trên blog tôi dựa trên giải pháp của tôi gợi ý, bạn có thể muốn thực hiện nhiều chương trình phát sóng và lấy trung bình chúng cho vị trí và xoay của mình để có được sự chuyển tiếp đẹp hơn khi di chuyển trên địa hình phức tạp hơn. Cũng có thể có những cạm bẫy khác mà tôi không nghĩ đến vào thời điểm này.

Máy ảnh và chuyển động

Khi người chơi đã bám vào bề mặt của vật thể, nhiệm vụ tiếp theo cần giải quyết là chuyển động. Ban đầu tôi đã bắt đầu với chuyển động liên quan đến người chơi nhưng tôi bắt đầu gặp vấn đề ở các cực của quả cầu nơi các hướng đột nhiên thay đổi khiến người chơi của tôi nhanh chóng thay đổi hướng đi và không cho phép tôi vượt qua các cực. Những gì tôi cố gắng làm là làm cho các cầu thủ của tôi chuyển động liên quan đến máy ảnh.

Điều làm việc tốt cho nhu cầu của tôi là có một chiếc máy ảnh tuân thủ nghiêm ngặt người chơi chỉ dựa trên vị trí người chơi. Kết quả là, mặc dù máy ảnh đã quay kỹ thuật, nhấn lên luôn di chuyển người chơi về phía trên màn hình, xuống phía dưới, và cứ thế với trái và phải.

Để thực hiện việc này, các thao tác sau được thực hiện trên máy ảnh có đối tượng mục tiêu là trình phát:

private void FixedUpdate()
{
    // Calculate and set camera position
    Vector3 desiredPosition = this.target.TransformPoint(0, this.height, -this.distance);
    this.transform.position = Vector3.Lerp(this.transform.position, desiredPosition, Time.deltaTime * this.damping);

    // Calculate and set camera rotation
    Quaternion desiredRotation = Quaternion.LookRotation(this.target.position - this.transform.position, this.target.up);
    this.transform.rotation = Quaternion.Slerp(this.transform.rotation, desiredRotation, Time.deltaTime * this.rotationDamping);
}

Cuối cùng, để di chuyển trình phát, chúng tôi đã tận dụng sự biến đổi của camera chính để với các điều khiển của chúng tôi di chuyển lên, di chuyển xuống, v.v. Và ở đây chúng tôi gọi là UpdatePlayerTransform sẽ đưa vị trí của chúng tôi vào vị trí của thế giới.

void Update () 
{        
    Vector3 movementDirection = Vector3.zero;
    if (Input.GetAxisRaw("Vertical") > 0)
    {
        movementDirection += cameraTransform.up;
    }
    else if (Input.GetAxisRaw("Vertical") < 0)
    {
        movementDirection += -cameraTransform.up;
    }

    if (Input.GetAxisRaw("Horizontal") > 0)
    {
        movementDirection += cameraTransform.right;
    }
    else if (Input.GetAxisRaw("Horizontal") < 0)
    {
        movementDirection += -cameraTransform.right;
    }

    movementDirection.Normalize();

    UpdatePlayerTransform(movementDirection);
}

Để thực hiện một máy ảnh thú vị hơn nhưng các điều khiển giống như những gì chúng tôi có ở đây, bạn có thể dễ dàng thực hiện một máy ảnh không được kết xuất hoặc chỉ là một đối tượng giả khác để di chuyển khỏi cơ sở và sau đó sử dụng máy ảnh thú vị hơn để hiển thị những gì bạn muốn trò chơi trông như thế nào Điều này sẽ cho phép chuyển đổi camera đẹp khi bạn đi xung quanh các đối tượng mà không phá vỡ các điều khiển.


3

Tôi nghĩ ý tưởng này sẽ hoạt động:

Giữ một bản sao phía CPU của lưới hành tinh. Có các đỉnh lưới cũng có nghĩa là bạn có các vectơ bình thường cho mỗi điểm trên hành tinh. Sau đó, vô hiệu hóa hoàn toàn trọng lực cho tất cả các thực thể, thay vào đó áp dụng một lực theo hướng ngược lại hoàn toàn với một vectơ bình thường.

Bây giờ, dựa vào điểm nào mà vectơ bình thường của hành tinh được tính?

Câu trả lời đơn giản nhất (mà tôi khá chắc chắn sẽ hoạt động tốt) là gần giống với phương pháp của Newton : Khi các vật thể lần đầu tiên sinh sản, bạn biết tất cả các vị trí ban đầu của chúng trên hành tinh. Sử dụng vị trí ban đầu để xác định upvéc tơ của từng đối tượng . Rõ ràng trọng lực sẽ ở hướng ngược lại (về phía down). Trong khung tiếp theo, trước khi áp dụng trọng lực, chiếu một tia từ vị trí mới của vật thể về phía downvectơ cũ . Sử dụng giao điểm của tia đó với hành tinh làm tham chiếu mới để xác định upvectơ. Trường hợp hiếm hoi của tia đánh không có nghĩa là có gì đó không ổn và bạn nên di chuyển vật thể của mình trở lại vị trí của nó trong khung trước đó.

Cũng lưu ý rằng sử dụng phương pháp này, nguồn gốc người chơi càng xa từ hành tinh, sự gần đúng càng trở nên tồi tệ. Do đó, tốt hơn là sử dụng một nơi nào đó xung quanh chân của mỗi người chơi làm nguồn gốc của họ. Tôi đoán, nhưng tôi nghĩ sử dụng chân làm nguồn gốc cũng sẽ giúp xử lý và điều hướng người chơi dễ dàng hơn.


Lưu ý cuối cùng: Để có kết quả tốt hơn, bạn thậm chí có thể thực hiện các thao tác sau: theo dõi chuyển động của người chơi trong mỗi khung hình (ví dụ: sử dụng current_position - last_position). Sau đó kẹp movement_vectorsao cho chiều dài của nó đối với vật upbằng không. Hãy gọi vector mới này reference_movement. Di chuyển điểm trước reference_pointbằng reference_movementvà sử dụng điểm mới này làm nguồn gốc dò tia. Sau khi (và nếu) tia tới hành tinh, di chuyển reference_pointđến điểm nhấn đó. Cuối cùng, tính toán upvectơ mới , từ mới này reference_point.

Một số mã giả để tổng hợp nó:

update_up_vector(player:object, planet:mesh)
{
    up_vector        = normalize(planet.up);
    reference_point  = ray_trace (object.old_position, -up_vector, planet);
    movement         = object.position - object.old_position;
    movement_clamped = movement - up_vector * dot (movement, up_vector);

    reference_point  += movement_clamped;
    reference_point  = ray_trace (reference_point, -up_vector, planet);
    player.up        = normal_vector(mesh, reference_point);
}

2

Bài này có thể hữu ích. Ý chính của nó là, bạn không sử dụng bộ điều khiển nhân vật, mà hãy tự tạo bằng cách sử dụng công cụ vật lý. Sau đó, bạn sử dụng các quy tắc được phát hiện bên dưới trình phát để định hướng chúng đến bề mặt của lưới.

Đây là một tổng quan tốt đẹp của kỹ thuật. Có nhiều tài nguyên hơn với các cụm từ tìm kiếm trên web như "unity walk on 3d object mario galaxy".

Ngoài ra còn có một dự án demo từ unity 3.x có động cơ đi bộ, với một người lính và một con chó và trong một trong những cảnh. Nó đã chứng minh đi bộ trên các đối tượng 3d Galaxy -style. Nó được gọi là hệ thống đầu máy bằng cách sửa đổi.


1
Thoạt nhìn bản demo không hoạt động tốt và gói Unity có lỗi xây dựng. Tôi sẽ xem liệu tôi có thể thực hiện công việc này không nhưng một câu trả lời đầy đủ hơn sẽ được đánh giá cao.
SpartanDovy

2

Vòng xoay

Kiểm tra câu trả lời cho câu hỏi này trên answer.unity3d.com (thực sự do chính tôi hỏi). Trích dẫn:

Nhiệm vụ đầu tiên là lấy một vectơ xác định. Từ bản vẽ của bạn, bạn có thể làm điều đó theo một trong hai cách. Bạn có thể coi hành tinh này như một hình cầu và sử dụng (object.poseition - Planet.poseition). Cách thứ hai là sử dụng Collider.Raycast () và sử dụng 'hit.n normal' mà nó trả về.

Đây là đoạn mã mà anh ấy gợi ý cho tôi:

var up : Vector3 = transform.position - planet.position;
transform.rotation = Quaternion.FromToRotation(transform.up, up) * transform.rotation;

Gọi rằng mỗi bản cập nhật, và bạn sẽ làm cho nó hoạt động. (lưu ý rằng mã nằm trong UnityScript ).
Mã tương tự trong C # :

Vector3 up = transform.position - planet.position;
transform.rotation = Quaternion.FromToRotation(transform.up, up) * transform.rotation;

Trọng lực

Đối với trọng lực, bạn có thể sử dụng "kỹ thuật vật lý hành tinh" của tôi, mà tôi đã mô tả trong câu hỏi của mình, nhưng nó không thực sự được tối ưu hóa. Nó chỉ là một cái gì đó tôi có trong tâm trí của tôi.
Tôi đề nghị bạn tạo ra hệ thống của riêng bạn cho trọng lực.

Đây là một hướng dẫn Youtube của Sebastian Lague . Đó là một giải pháp rất tốt.

EDIT: Để thống nhất, đi tới Chỉnh sửa > Cài đặt dự án > Vật lý và đặt tất cả các giá trị cho Gravity thành 0 (Hoặc xóa Rigidbody khỏi tất cả các đối tượng), để ngăn trọng lực tích hợp (chỉ kéo người chơi xuống) xung đột với các giải pháp tùy chỉnh. (tắt nó đi)


Hấp dẫn người chơi đến trung tâm của một hành tinh (và xoay chúng theo đó) hoạt động tốt đối với các hành tinh gần hình cầu, nhưng tôi có thể tưởng tượng nó sẽ thực sự sai đối với các vật thể ít hình cầu hơn, giống như Mario hình dạng tên lửa đang nhảy lên trong GIF đầu tiên.
Anko

Bạn có thể tạo một khối lập phương bị hạn chế chỉ di chuyển quanh trục X, ví dụ, bên trong vật thể không phải hình cầu và di chuyển nó khi người chơi di chuyển, để nó luôn nằm thẳng dưới người chơi, sau đó kéo người chơi xuống khối lập phương. Thử nó.
Daniel Kvist
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.