Cơ chế đảo ngược thời gian trong game


10

Tôi tự hỏi về cách các cơ chế thao tác thời gian trong các trò chơi thường được thiết kế. Tôi đặc biệt quan tâm đến việc đảo ngược thời gian (giống như trong SSX hoặc Prince of Persia mới nhất).

Trò chơi là một game bắn súng 2D từ trên xuống.

Cơ chế tôi đang cố gắng thiết kế / thực hiện có các yêu cầu sau:

1) Hành động của các thực thể ngoài nhân vật người chơi là hoàn toàn xác định.

  • Hành động mà một thực thể thực hiện dựa trên các khung được tiến hành kể từ khi bắt đầu cấp và / hoặc vị trí của trình phát trên màn hình
  • Các thực thể được sinh ra tại thời điểm thiết lập trong cấp độ.

2) Đảo ngược thời gian hoạt động bằng cách đảo ngược trở lại trong thời gian thực.

  • Hành động của người chơi cũng bị đảo ngược, nó phát lại ngược lại những gì người chơi thực hiện. Người chơi không có quyền kiểm soát trong thời gian đảo ngược.
  • Không có giới hạn về thời gian đảo ngược, chúng ta có thể đảo ngược tất cả các cách để bắt đầu cấp độ nếu muốn.

Ví dụ:

Khung 0-50: Người chơi di chuyển foward 20 đơn vị trong thời gian này Enemy 1 sinh ra ở khung 20 Enemy 1 di chuyển còn lại 10 đơn vị trong khung 30-40 Người chơi bắn đạn vào khung 45 Bullet đi 5 foward (45-50) và giết Enemy 1 tại khung 50

Đảo ngược điều này sẽ phát lại trong thời gian thực: Người chơi di chuyển lùi 20 đơn vị trong thời gian này Enemy 1 hồi sinh ở khung 50 Bullet xuất hiện lại ở khung 50 Bullet di chuyển lùi 5 và biến mất (50-45) Kẻ địch di chuyển sang trái 10 (40-30) Kẻ địch bị loại bỏ tại khung 20.

Chỉ cần nhìn vào chuyển động tôi đã có một số ý tưởng về cách đạt được điều này, tôi nghĩ rằng có một giao diện thay đổi hành vi khi thời gian đang tiến hoặc đảo ngược. Thay vì làm một cái gì đó như thế này:

void update()
{
    movement += new Vector(0,5);
}

Tôi sẽ làm một cái gì đó như thế này:

public interface movement()
{
    public void move(Vector v, Entity e);
}

public class advance() implements movement
{
    public void move(Vector v, Entity e)
    {
            e.location += v;
    }
}


public class reverse() implements movement
{
    public void move(Vector v, Entity e)
    { 
        e.location -= v;
    }
}

public void update()
{
    moveLogic.move(new vector(5,0));
}

Tuy nhiên tôi nhận ra rằng đây sẽ không phải là hiệu suất tối ưu khôn ngoan và sẽ nhanh chóng trở nên phức tạp đối với các hành động nâng cao hơn (chẳng hạn như chuyển động trơn tru dọc theo các đường cong, v.v.).


1
Tôi đã không xem tất cả những điều này (YouTube run rẩy, 1,5 giờ) , nhưng có lẽ có một số ý tưởng về Jonathan Blow đã làm việc này trong trò chơi Braid của anh ấy.
MichaelHouse

Câu trả lời:


9

Bạn có thể muốn xem mẫu Lệnh .

Về cơ bản, mọi hành động có thể đảo ngược mà các thực thể của bạn thực hiện đều được thực hiện như một đối tượng lệnh. Tất cả các đối tượng đó thực hiện ít nhất 2 phương thức: Execute () và Undo (), cộng với bất cứ thứ gì bạn cần, như thuộc tính tem thời gian để định thời gian chính xác.

Bất cứ khi nào thực thể của bạn thực hiện một hành động đảo ngược, trước tiên bạn tạo một đối tượng lệnh thích hợp. Bạn lưu nó trên ngăn xếp Hoàn tác, sau đó nạp vào công cụ trò chơi của bạn và thực hiện nó. Khi bạn muốn đảo ngược thời gian, bạn bật các hành động từ đầu ngăn xếp và gọi phương thức Undo () của chúng, điều này ngược lại với phương thức Execute (). Ví dụ: trong trường hợp nhảy từ điểm A đến điểm B, bạn thực hiện bước nhảy từ B đến A.

Sau khi bạn bật một hành động, hãy lưu nó vào ngăn xếp Làm lại nếu bạn muốn tiến lên và lùi lại theo ý muốn, giống như chức năng hoàn tác / làm lại trong trình soạn thảo văn bản hoặc chương trình vẽ. Tất nhiên, hình động của bạn cũng phải hỗ trợ chế độ "tua lại" để phát ngược chúng.

Để biết thêm các shenanigans thiết kế trò chơi, hãy để mọi thực thể lưu trữ các hành động của nó trên ngăn xếp của riêng nó, để bạn có thể hoàn tác / làm lại chúng một cách độc lập với nhau.

Một mẫu lệnh có các ưu điểm khác: Ví dụ, việc xây dựng một máy ghi phát lại khá đơn giản, vì bạn chỉ cần lưu tất cả các đối tượng trên ngăn xếp vào một tệp và vào thời gian phát lại, chỉ cần đưa nó vào công cụ trò chơi một.


2
Lưu ý rằng tính đảo ngược của các hành động trong trò chơi có thể là một điều rất cảm động, vì các vấn đề chính xác về dấu phẩy động, dấu thời gian thay đổi, v.v; An toàn hơn nhiều để cứu trạng thái đó hơn là xây dựng lại nó trong hầu hết các tình huống.
Steven Stadnicki

@StevenStadnicki Có thể, nhưng chắc chắn là có thể. Ngoài đỉnh đầu của tôi, các Tướng C & C làm theo cách này. Nó có các replay dài hàng giờ lên tới 8 người chơi, nặng nhất là vài trăm kB, và đó là cách tôi đoán nhất nếu không phải tất cả các trò chơi RTS đều chơi nhiều người: Bạn không thể truyền trạng thái trò chơi đầy đủ với hàng trăm của các đơn vị mỗi khung, bạn phải để động cơ thực hiện cập nhật. Vì vậy, yeah, nó chắc chắn khả thi.
Hackworth

3
Phát lại là một điều rất khác so với tua lại, bởi vì các thao tác có thể tái tạo liên tục về phía trước (ví dụ: tìm vị trí ở khung n, x_n, bằng cách bắt đầu bằng x_0 = 0 và thêm deltas v_n cho mỗi bước) không nhất thiết có thể lặp lại ; (x + v_n) -v_n không nhất quán bằng x trong toán học dấu phẩy động. Và thật dễ dàng để nói 'làm việc xung quanh nó' nhưng bạn đang nói về khả năng đại tu hoàn chỉnh, bao gồm cả việc không thể sử dụng nhiều thư viện bên ngoài.
Steven Stadnicki

1
Đối với một số trò chơi cách tiếp cận của bạn có thể là khả thi, nhưng AFAIK nhất trò chơi mà sử dụng thời gian đảo ngược như một thợ cơ khí đang sử dụng một cái gì đó gần gũi hơn với cách tiếp cận Memento OriginalDaemon, nơi tình trạng có liên quan được lưu lại cho mỗi khung.
Steven Stadnicki

2
Còn việc tua lại bằng cách tính toán lại các bước, nhưng lưu một khung chính cứ sau vài giây thì sao? Lỗi dấu phẩy động không có khả năng tạo ra sự khác biệt đáng kể chỉ trong vài giây (tất nhiên phụ thuộc vào độ phức tạp). Nó cũng được hiển thị để hoạt động trong nén video: P
Tharwen

1

Bạn có thể xem Mô hình Memento; Mục đích chính của nó là thực hiện các thao tác hoàn tác / làm lại bằng cách khôi phục trạng thái đối tượng, nhưng đối với một số loại trò chơi nhất định thì nó phải đủ.

Đối với một trò chơi trong một vòng lặp thời gian thực, bạn có thể coi mỗi khung hoạt động của mình là một thay đổi trạng thái và lưu trữ nó. Đây là một cách tiếp cận đơn giản để thực hiện. Cách khác là bẫy khi trạng thái của đối tượng bị thay đổi. Ví dụ, phát hiện khi các lực tác động lên một cơ thể cứng nhắc được thay đổi. Nếu bạn đang sử dụng các thuộc tính để nhận và đặt các biến, đây cũng có thể là một triển khai tương đối đơn giản, phần khó khăn là xác định khi nào quay lại trạng thái, vì điều này sẽ không đồng thời cho mọi đối tượng (bạn có thể lưu trữ thời gian quay lại dưới dạng đếm khung hình từ khi bắt đầu hệ thống).


0

Trong trường hợp cụ thể của bạn, xử lý rollback bằng cách tua lại chuyển động sẽ hoạt động tốt. Nếu bạn đang sử dụng bất kỳ hình thức tìm đường nào với các đơn vị AI, chỉ cần đảm bảo tính toán lại sau khi khôi phục để tránh các đơn vị chồng chéo.

Vấn đề là cách bạn tự xử lý chuyển động: Một công cụ vật lý tốt (một game bắn súng từ trên xuống 2D sẽ ổn với một thao tác rất đơn giản) theo dõi thông tin các bước trong quá khứ (bao gồm cả vị trí, lực net, v.v.) sẽ cung cấp một cơ sở vững chắc. Sau đó, quyết định rollback tối đa và độ chi tiết cho các bước rollback bạn sẽ nhận được kết quả bạn muốn.


0

Trong khi đây là một ý tưởng thú vị. Tôi sẽ tư vấn cho chống lại nó.

Phát lại trò chơi chuyển tiếp hoạt động tốt, bởi vì một hoạt động sẽ luôn có tác dụng tương tự đối với trạng thái trò chơi. Điều này không có nghĩa là hoạt động ngược cung cấp cho bạn trạng thái ban đầu. Ví dụ: đánh giá biểu thức sau trong bất kỳ ngôn ngữ lập trình nào (tắt tối ưu hóa)

(1.1 + 3 - 3) == 1.1

Trong C và C ++ ít nhất, nó trả về false. Mặc dù sự khác biệt có thể nhỏ, hãy tưởng tượng có bao nhiêu lỗi có thể tích lũy ở 60fps trong 10 giây của phút. Sẽ có trường hợp một người chơi chỉ bỏ lỡ một cái gì đó, nhưng đánh nó trong khi trò chơi được phát lại ngược.

Tôi sẽ khuyên bạn nên lưu trữ các khung hình chính mỗi nửa giây. Điều này sẽ không chiếm quá nhiều bộ nhớ. Sau đó, bạn có thể nội suy giữa các khung hình chính hoặc thậm chí tốt hơn, mô phỏng thời gian giữa hai khung hình chính và sau đó phát lại nó ngược lại.

Nếu trò chơi của bạn không quá phức tạp, chỉ cần lưu trữ các khung hình chính của trạng thái trò chơi 30 lần một giây và chơi ngược lại. Nếu bạn có 15 đối tượng với vị trí 2D, sẽ mất 1,5 phút để có được MB, mà không cần nén. Máy tính có bộ nhớ gigabyte.

Vì vậy, đừng quá phức tạp, nó sẽ không dễ dàng phát lại một trò chơi ngược và nó sẽ gây ra rất nhiều lỗi.

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.