Thật là một câu hỏi mẹ! Tôi có thể lúng túng khi thử cái này với những suy nghĩ kỳ quặc của mình (và tôi rất thích nghe những lời đề nghị nếu tôi thực sự tắt). Nhưng đối với tôi, điều hữu ích nhất tôi đã học được gần đây trong miền của mình (bao gồm cả chơi game trước đây, bây giờ là VFX) là thay thế các tương tác giữa các giao diện trừu tượng với dữ liệu như một cơ chế tách rời (và cuối cùng giảm lượng thông tin cần thiết giữa mọi thứ và về nhau đến mức tối thiểu tuyệt đối). Điều này nghe có vẻ hoàn toàn điên rồ (và tôi có thể đang sử dụng tất cả các loại thuật ngữ kém).
Tuy nhiên, hãy nói rằng tôi cung cấp cho bạn một công việc hợp lý có thể quản lý. Bạn có tập tin này chứa dữ liệu cảnh và hoạt hình để kết xuất. Có tài liệu bao gồm định dạng tập tin. Công việc duy nhất của bạn là tải tệp, hiển thị hình ảnh đẹp cho hoạt hình bằng cách sử dụng theo dõi đường dẫn và xuất kết quả ra tệp hình ảnh. Đó là một ứng dụng quy mô khá nhỏ mà có lẽ sẽ không vượt quá hàng chục nghìn LỘC ngay cả đối với một trình kết xuất khá tinh vi (chắc chắn không phải hàng triệu).
Bạn có thế giới riêng biệt nhỏ bé của riêng mình cho trình kết xuất này. Nó không bị ảnh hưởng bởi thế giới bên ngoài. Nó cô lập sự phức tạp của chính nó. Ngoài những lo ngại về việc đọc tệp cảnh này và xuất kết quả của bạn thành tệp hình ảnh, bạn có thể tập trung hoàn toàn vào chỉ hiển thị. Nếu có lỗi xảy ra trong quá trình, bạn biết đó là trong trình kết xuất và không có gì khác, vì không có gì khác liên quan đến bức ảnh này.
Trong khi đó, giả sử thay vào đó bạn phải làm cho trình kết xuất của mình hoạt động trong bối cảnh của một phần mềm hoạt hình lớn thực sự có hàng triệu LỘC. Thay vì chỉ đọc một định dạng tệp được sắp xếp hợp lý, tài liệu để lấy dữ liệu cần thiết để kết xuất, bạn phải trải qua tất cả các loại giao diện trừu tượng để lấy tất cả dữ liệu bạn cần để thực hiện:
Đột nhiên trình kết xuất của bạn không còn trong thế giới biệt lập nhỏ bé của riêng nó. Điều này cảm thấy như vậy, phức tạp hơn nhiều. Bạn phải hiểu thiết kế tổng thể của toàn bộ phần mềm như một tổng thể hữu cơ với nhiều bộ phận chuyển động và thậm chí đôi khi phải suy nghĩ về việc triển khai những thứ như mắt lưới hoặc máy ảnh nếu bạn gặp phải nút cổ chai hoặc lỗi trong một chức năng.
Chức năng so với dữ liệu được sắp xếp hợp lý
Và một trong những lý do là vì chức năng phức tạp hơn nhiều so với dữ liệu tĩnh. Cũng có rất nhiều cách mà một lệnh gọi hàm có thể sai theo cách mà việc đọc dữ liệu tĩnh không thể. Có rất nhiều tác dụng phụ tiềm ẩn có thể xảy ra khi gọi các chức năng đó mặc dù về mặt khái niệm nó chỉ lấy dữ liệu chỉ đọc để kết xuất. Nó cũng có thể có rất nhiều lý do để thay đổi. Vài tháng sau, bạn có thể thấy giao diện lưới hoặc kết cấu thay đổi hoặc không dùng các bộ phận theo cách yêu cầu bạn viết lại các phần lớn của trình kết xuất và theo kịp các thay đổi đó, mặc dù bạn đang tìm nạp cùng một dữ liệu đầu vào dữ liệu cho trình kết xuất của bạn không thay đổi bất cứ điều gì (chỉ có chức năng cần thiết để cuối cùng truy cập tất cả).
Vì vậy, khi có thể, tôi đã thấy rằng dữ liệu được sắp xếp hợp lý là một cơ chế tách riêng rất tốt, thực sự cho phép bạn tránh phải suy nghĩ về toàn bộ hệ thống và cho phép bạn chỉ tập trung vào một phần rất cụ thể của hệ thống để thực hiện cải tiến, thêm các tính năng mới, sửa chữa mọi thứ, v.v ... Đó là một suy nghĩ rất I / O cho các phần cồng kềnh tạo nên phần mềm của bạn. Nhập cái này, làm việc của bạn, xuất cái đó, và không trải qua hàng tá giao diện trừu tượng kết thúc các cuộc gọi chức năng vô tận trên đường đi. Và nó bắt đầu giống với một mức độ nào đó, lập trình chức năng.
Vì vậy, đây chỉ là một chiến lược và nó có thể không áp dụng cho tất cả mọi người. Và tất nhiên nếu bạn đang bay một mình, bạn vẫn phải duy trì mọi thứ (bao gồm cả định dạng của dữ liệu), nhưng điều khác biệt là khi bạn ngồi xuống để cải thiện trình kết xuất đó, bạn thực sự có thể chỉ tập trung vào trình kết xuất phần lớn và không có gì khác Nó trở nên quá cô lập trong thế giới nhỏ bé của chính nó - về sự cô lập nhất có thể với dữ liệu mà nó yêu cầu cho đầu vào được sắp xếp hợp lý.
Và tôi đã sử dụng ví dụ về định dạng tệp nhưng nó không phải là tệp cung cấp dữ liệu quan tâm hợp lý cho đầu vào. Nó có thể là một cơ sở dữ liệu trong bộ nhớ. Trong trường hợp của tôi, đó là một hệ thống thành phần thực thể với các thành phần lưu trữ dữ liệu quan tâm. Tuy nhiên, tôi đã tìm thấy nguyên tắc cơ bản này để tách rời dữ liệu được sắp xếp hợp lý (tuy nhiên bạn làm điều đó) nên đánh thuế vào khả năng tinh thần của tôi ít hơn nhiều so với các hệ thống trước đây mà tôi đã làm việc xoay quanh sự trừu tượng và rất nhiều và rất nhiều tương tác đang diễn ra giữa tất cả những điều này giao diện trừu tượng khiến bạn không thể chỉ ngồi xuống với một thứ và chỉ nghĩ về điều đó và những thứ khác. Não tôi tràn ngập bờ vực với những loại hệ thống trước đó và muốn bùng nổ vì có quá nhiều tương tác đang diễn ra giữa rất nhiều thứ,
Tách
Nếu bạn muốn giảm thiểu mức độ mã hóa lớn hơn cho bộ não của mình, thì hãy làm cho nó thành từng phần lớn của phần mềm (toàn bộ hệ thống kết xuất, toàn bộ hệ thống vật lý, v.v.) sống trong thế giới biệt lập nhất có thể. Giảm thiểu lượng giao tiếp và tương tác đi đến mức tối thiểu thông qua dữ liệu được sắp xếp hợp lý nhất. Bạn thậm chí có thể chấp nhận một số dự phòng (một số công việc dư thừa cho bộ xử lý hoặc thậm chí cho chính mình) nếu trao đổi là một hệ thống tách biệt hơn nhiều mà không phải nói chuyện với hàng tá thứ khác trước khi nó có thể thực hiện công việc của mình.
Và khi bạn bắt đầu làm điều đó, có cảm giác như bạn đang duy trì hàng tá ứng dụng quy mô nhỏ thay vì một ứng dụng khổng lồ. Và tôi thấy điều đó cũng vui hơn rất nhiều. Bạn có thể ngồi xuống và chỉ làm việc trên một hệ thống theo nội dung trái tim của bạn mà không liên quan đến bản thân với thế giới bên ngoài. Nó chỉ trở thành nhập dữ liệu đúng và xuất dữ liệu đúng ở cuối đến một nơi mà các hệ thống khác có thể lấy được (lúc đó một số hệ thống khác có thể nhập dữ liệu đó và thực hiện việc đó, nhưng bạn không cần phải quan tâm đến điều đó khi làm việc trên hệ thống của bạn). Tất nhiên, bạn vẫn phải suy nghĩ về cách mọi thứ tích hợp trong giao diện người dùng, chẳng hạn (tôi vẫn thấy mình phải suy nghĩ về toàn bộ thiết kế cho GUI), nhưng ít nhất là không phải khi bạn ngồi xuống và làm việc trên hệ thống hiện có đó hoặc quyết định thêm một cái mới.
Có lẽ tôi đang mô tả một cái gì đó rõ ràng cho những người luôn cập nhật các phương pháp kỹ thuật mới nhất. Tôi không biết. Nhưng nó không rõ ràng đối với tôi. Tôi muốn tiếp cận thiết kế phần mềm xung quanh các đối tượng tương tác với nhau và các chức năng được gọi cho phần mềm quy mô lớn. Và những cuốn sách tôi đọc ban đầu về thiết kế phần mềm quy mô lớn tập trung vào thiết kế giao diện bên trên những thứ như triển khai và dữ liệu (câu thần chú hồi đó là việc triển khai không quan trọng lắm, chỉ giao diện, bởi vì trước đây có thể dễ dàng thay thế hoặc thay thế ). Ban đầu, tôi không nghĩ đến việc tương tác với phần mềm khi sôi sục chỉ nhập và xuất dữ liệu giữa các hệ thống con lớn hầu như không nói chuyện với nhau ngoại trừ thông qua dữ liệu được sắp xếp hợp lý này. Tuy nhiên, khi tôi bắt đầu chuyển trọng tâm sang thiết kế xung quanh khái niệm đó, nó khiến mọi thứ trở nên dễ dàng hơn nhiều. Tôi có thể thêm rất nhiều mã mà không cần nổ não. Cảm giác như tôi đang xây dựng một trung tâm mua sắm thay vì một tòa tháp có thể đổ xuống nếu tôi thêm quá nhiều hoặc nếu có một vết nứt ở bất kỳ phần nào.
Triển khai phức tạp so với tương tác phức tạp
Đây là một điều khác tôi nên đề cập bởi vì tôi đã dành một phần tốt trong phần đầu của sự nghiệp để tìm kiếm những triển khai đơn giản nhất. Vì vậy, tôi đã phân tách mọi thứ thành các bit và mảnh nhỏ nhất và đơn giản nhất, nghĩ rằng tôi đang cải thiện khả năng bảo trì.
Nhìn lại, tôi không nhận ra mình đang trao đổi một loại phức tạp khác. Để giảm tất cả mọi thứ xuống các bit và phần đơn giản nhất, các tương tác diễn ra giữa các phần thiếu niên đó đã biến thành một mạng lưới tương tác phức tạp nhất với các lệnh gọi chức năng đôi khi đi sâu 30 bậc vào bảng gọi. Và tất nhiên, nếu bạn nhìn vào bất kỳ một chức năng nào, thì thật đơn giản và dễ dàng để biết nó làm gì. Nhưng bạn không nhận được nhiều thông tin hữu ích tại thời điểm đó vì mỗi chức năng hoạt động rất ít. Sau đó, bạn cuối cùng phải theo dõi tất cả các loại chức năng và nhảy qua tất cả các loại vòng để thực sự tìm ra những gì tất cả chúng làm theo cách có thể khiến não bạn muốn nổ tung nhiều hơn một,
Đó không phải là đề nghị các đối tượng thần hoặc bất cứ điều gì như thế. Nhưng có lẽ chúng ta không cần phải xé các vật thể lưới của chúng ta thành những thứ nhỏ nhất như một vật thể đỉnh, vật thể cạnh, vật thể mặt. Có lẽ chúng ta chỉ có thể giữ nó ở "lưới" với việc triển khai phức tạp hơn vừa phải đằng sau nó để đổi lấy các tương tác mã ít hơn. Tôi có thể xử lý một triển khai phức tạp vừa phải ở đây và đó. Tôi không thể xử lý một lượng lớn các tương tác với các tác dụng phụ xảy ra với những người hiểu biết ở đâu và theo thứ tự nào.
Ít nhất tôi thấy rằng việc đánh thuế vào não rất nhiều, ít hơn nhiều, bởi vì đó là những tương tác khiến não tôi bị tổn thương trong một cơ sở mã lớn. Không phải bất kỳ một điều cụ thể.
Tính tổng quát so với tính đặc hiệu
Có lẽ gắn liền với những điều trên, tôi đã từng yêu thích việc sử dụng lại tính tổng quát và mã, và từng nghĩ rằng thách thức lớn nhất của việc thiết kế một giao diện tốt là đáp ứng nhiều nhu cầu nhất vì giao diện sẽ được sử dụng bởi tất cả các loại khác nhau với các nhu cầu khác nhau. Và khi bạn làm điều đó, chắc chắn bạn phải nghĩ về hàng trăm thứ cùng một lúc, bởi vì bạn đang cố gắng cân bằng nhu cầu của một trăm thứ cùng một lúc.
Tổng quát hóa mọi thứ mất rất nhiều thời gian. Chỉ cần nhìn vào các thư viện tiêu chuẩn đi kèm với ngôn ngữ của chúng tôi. Thư viện chuẩn C ++ chứa rất ít chức năng, nhưng nó đòi hỏi các nhóm người phải duy trì và điều chỉnh với toàn bộ ủy ban của mọi người tranh luận và đưa ra các đề xuất về thiết kế của nó. Đó là bởi vì một chút chức năng nhỏ bé đó đang cố gắng xử lý toàn bộ nhu cầu của thế giới.
Có lẽ chúng ta không cần phải mang mọi thứ cho đến nay. Có lẽ không sao khi chỉ có một chỉ số không gian chỉ được sử dụng để phát hiện va chạm giữa các mắt lưới được lập chỉ mục và không có gì khác. Có lẽ chúng ta có thể sử dụng một cái khác cho các loại bề mặt khác, và một cái khác để kết xuất. Tôi đã từng rất tập trung vào việc loại bỏ các loại dư thừa này, nhưng một phần lý do là vì tôi đang phải đối phó với các cấu trúc dữ liệu rất kém hiệu quả được thực hiện bởi một loạt người. Đương nhiên, nếu bạn có một octree chỉ mất 1 gigabyte cho một lưới tam giác 300k, bạn không muốn có thêm một bộ nhớ nữa.
Nhưng tại sao các octrees không hiệu quả ngay từ đầu? Tôi có thể tạo các quãng tám chỉ mất 4 byte cho mỗi nút và mất ít hơn một megabyte để làm điều tương tự như phiên bản gigabyte đó trong khi xây dựng trong một phần nhỏ thời gian và thực hiện các truy vấn tìm kiếm nhanh hơn. Tại thời điểm đó một số dư thừa là hoàn toàn chấp nhận được.
Hiệu quả
Vì vậy, điều này chỉ liên quan đến các lĩnh vực quan trọng về hiệu suất nhưng bạn càng có được những thứ như hiệu quả bộ nhớ, bạn càng có khả năng lãng phí nhiều hơn một chút (có thể chấp nhận dư thừa một chút để đổi lấy việc giảm tính tổng quát hoặc tách rời) theo năng suất . Và nó giúp tôi khá tốt và thoải mái với các trình biên dịch của bạn và tìm hiểu về kiến trúc máy tính và hệ thống phân cấp bộ nhớ, bởi vì sau đó bạn có thể hy sinh nhiều hơn để đạt được hiệu quả để đổi lấy năng suất vì mã của bạn đã rất hiệu quả và đủ khả năng để có được kém hiệu quả hơn một chút ngay cả trong các lĩnh vực quan trọng trong khi vẫn vượt trội so với đối thủ. Tôi đã thấy rằng việc cải thiện trong lĩnh vực này cũng đã cho phép tôi thoát khỏi những triển khai đơn giản và đơn giản hơn,
độ tin cậy
Đây là loại hiển nhiên nhưng cũng có thể đề cập đến nó. Những điều đáng tin cậy nhất của bạn đòi hỏi chi phí trí tuệ tối thiểu. Bạn không cần phải suy nghĩ nhiều về họ. Họ chỉ làm việc. Kết quả là bạn càng phát triển danh sách các bộ phận cực kỳ đáng tin cậy cũng "ổn định" (không cần thay đổi) thông qua thử nghiệm kỹ lưỡng, bạn càng ít phải suy nghĩ.
Cụ thể
Vì vậy, tất cả những điều trên bao gồm một số điều chung có ích cho tôi, nhưng hãy chuyển sang các khía cạnh cụ thể hơn cho khu vực của bạn:
Trong các dự án nhỏ hơn của tôi, thật dễ dàng để nhớ một bản đồ tinh thần về cách mọi phần của chương trình hoạt động. Làm điều này, tôi có thể nhận thức đầy đủ về bất kỳ thay đổi nào sẽ ảnh hưởng đến phần còn lại của chương trình và tránh các lỗi rất hiệu quả cũng như xem chính xác cách một tính năng mới phù hợp với cơ sở mã. Tuy nhiên, khi tôi cố gắng tạo ra các dự án lớn hơn, tôi thấy không thể giữ một bản đồ tinh thần tốt dẫn đến mã rất lộn xộn và nhiều lỗi không lường trước được.
Đối với tôi điều này có xu hướng liên quan đến các tác dụng phụ phức tạp và các luồng điều khiển phức tạp. Đó là một cái nhìn khá thấp về mọi thứ nhưng tất cả các giao diện đẹp nhất và tất cả sự tách rời từ cụ thể đến trừu tượng không thể làm cho mọi lý do dễ dàng hơn về các tác dụng phụ phức tạp xảy ra trong các luồng điều khiển phức tạp.
Đơn giản hóa / giảm các tác dụng phụ và / hoặc đơn giản hóa các luồng điều khiển, lý tưởng là cả hai. và nói chung bạn sẽ thấy dễ dàng hơn nhiều để suy luận về những gì các hệ thống lớn hơn làm và cả những gì sẽ xảy ra để đáp ứng với những thay đổi của bạn.
Ngoài vấn đề "bản đồ tinh thần" này, tôi thấy khó có thể giữ mã của mình tách rời khỏi các phần khác của chính nó. Ví dụ: nếu trong trò chơi nhiều người chơi có một lớp để xử lý vật lý chuyển động của người chơi và một lớp khác để xử lý kết nối mạng, thì tôi thấy không có cách nào để một trong các lớp này không dựa vào lớp kia để đưa dữ liệu chuyển động của người chơi vào hệ thống mạng để gửi nó qua mạng. Sự ghép nối này là một nguồn đáng kể của sự phức tạp can thiệp vào một bản đồ tinh thần tốt.
Về mặt khái niệm bạn phải có một số khớp nối. Khi mọi người nói về việc tách rời, họ thường có nghĩa là thay thế một loại bằng một loại khác, mong muốn hơn (thường là hướng tới sự trừu tượng). Đối với tôi, với miền của tôi, cách thức hoạt động của bộ não, v.v. loại mong muốn nhất để giảm các yêu cầu "bản đồ tinh thần" xuống mức tối thiểu là dữ liệu được sắp xếp hợp lý ở trên. Một hộp đen phun ra dữ liệu được đưa vào một hộp đen khác và cả hai hoàn toàn không biết gì về sự tồn tại của nhau. Họ chỉ biết một số vị trí trung tâm nơi dữ liệu được lưu trữ (ví dụ: hệ thống tệp trung tâm hoặc cơ sở dữ liệu trung tâm) thông qua đó họ tìm nạp dữ liệu đầu vào, làm một cái gì đó và nhổ ra một đầu ra mới mà một số hộp đen khác có thể nhập vào.
Nếu bạn làm theo cách này, hệ thống vật lý sẽ phụ thuộc vào cơ sở dữ liệu trung tâm và hệ thống mạng sẽ phụ thuộc vào cơ sở dữ liệu trung tâm, nhưng họ sẽ không biết gì về nhau. Họ thậm chí sẽ không biết nhau tồn tại. Họ thậm chí sẽ không biết rằng các giao diện trừu tượng cho nhau tồn tại.
Cuối cùng, tôi thường thấy mình đến với một hoặc nhiều lớp "người quản lý" điều phối các lớp khác. Ví dụ, trong một trò chơi, một lớp sẽ xử lý vòng lặp đánh dấu chính và sẽ gọi các phương thức cập nhật trong các lớp người chơi và mạng. Điều này đi ngược lại triết lý về những gì tôi đã tìm thấy trong nghiên cứu của mình rằng mỗi lớp nên có thể kiểm tra đơn vị và có thể sử dụng độc lập với các lớp khác, vì bất kỳ lớp quản lý nào như vậy bởi mục đích của nó phụ thuộc vào hầu hết các lớp khác trong dự án. Ngoài ra, một lớp quản lý phối hợp các phần còn lại của chương trình là một nguồn đáng kể về độ phức tạp không thể ánh xạ.
Bạn có xu hướng cần một cái gì đó để phối hợp tất cả các hệ thống trong trò chơi của bạn. Trung tâm có thể ít nhất là ít phức tạp và dễ quản lý hơn giống như một hệ thống vật lý gọi một hệ thống kết xuất sau khi nó được thực hiện. Nhưng ở đây chắc chắn chúng ta cần một số chức năng được gọi, và tốt nhất là chúng trừu tượng.
Vì vậy, bạn có thể tạo một giao diện trừu tượng cho một hệ thống có update
chức năng trừu tượng . Sau đó, nó có thể tự đăng ký với công cụ trung tâm và hệ thống mạng của bạn có thể nói, "Này, tôi là một hệ thống và đây là chức năng cập nhật của tôi. Thỉnh thoảng hãy gọi cho tôi." Và sau đó công cụ của bạn có thể lặp qua tất cả các hệ thống như vậy và cập nhật chúng mà không cần gọi chức năng mã hóa cứng đến các hệ thống cụ thể.
Điều đó cho phép các hệ thống của bạn sống nhiều hơn trong thế giới biệt lập của riêng chúng. Công cụ trò chơi không cần phải biết về chúng một cách cụ thể (một cách cụ thể) nữa. Và sau đó, hệ thống vật lý của bạn có thể có chức năng cập nhật được gọi, tại thời điểm đó, nó nhập dữ liệu cần thiết từ cơ sở dữ liệu trung tâm cho mọi chuyển động, áp dụng vật lý, sau đó đưa ra chuyển động kết quả trở lại.
Sau đó, hệ thống mạng của bạn có thể có chức năng cập nhật được gọi, tại thời điểm đó, nó nhập dữ liệu cần thiết từ cơ sở dữ liệu trung tâm và đầu ra, giả sử, dữ liệu ổ cắm cho máy khách. Một lần nữa, mục tiêu mà tôi thấy là cô lập từng hệ thống càng nhiều càng tốt để nó có thể sống trong thế giới nhỏ bé của riêng mình với kiến thức tối thiểu về thế giới bên ngoài. Về cơ bản, đó là cách tiếp cận được áp dụng trong ECS phổ biến trong các công cụ trò chơi.
ECS
Tôi đoán rằng tôi nên đề cập đến ECS một chút vì rất nhiều suy nghĩ của tôi ở trên xoay quanh ECS và cố gắng hợp lý hóa lý do tại sao cách tiếp cận hướng dữ liệu này để bảo trì dễ dàng hơn nhiều so với các hệ thống dựa trên đối tượng và COM mà tôi duy trì trong quá khứ mặc dù vi phạm chỉ về tất cả mọi thứ tôi giữ thiêng liêng ban đầu mà tôi đã học về SE. Ngoài ra, nó có thể có ý nghĩa với bạn nếu bạn đang cố gắng xây dựng các trò chơi quy mô lớn hơn. Vì vậy, ECS hoạt động như thế này:
Và như trong sơ đồ trên, MovementSystem
có thể có update
chức năng của nó được gọi. Tại thời điểm này, nó có thể truy vấn cơ sở dữ liệu trung tâm cho PosAndVelocity
các thành phần dưới dạng dữ liệu cần nhập (các thành phần chỉ là dữ liệu, không có chức năng). Sau đó, nó có thể lặp qua các vị trí đó, sửa đổi vị trí / vận tốc và đưa ra kết quả mới một cách hiệu quả. Sau đó, RenderingSystem
có thể có chức năng cập nhật của nó được gọi, tại đó nó truy vấn cơ sở dữ liệu PosAndVelocity
và Sprite
các thành phần, và xuất hình ảnh ra màn hình dựa trên dữ liệu đó.
Tất cả các hệ thống hoàn toàn không biết gì về sự tồn tại của nhau và thậm chí chúng không cần phải hiểu những gì Car
Là. Họ chỉ cần biết các thành phần cụ thể về sở thích của mỗi hệ thống tạo nên dữ liệu cần thiết để đại diện cho một. Mỗi hệ thống giống như một hộp đen. Nó nhập dữ liệu và xuất dữ liệu với kiến thức tối thiểu về thế giới bên ngoài và thế giới bên ngoài cũng có kiến thức tối thiểu về nó. Có thể có một số sự kiện đẩy từ một hệ thống và xuất hiện từ một hệ thống khác, do đó, sự va chạm của hai thực thể trong hệ thống vật lý có thể khiến âm thanh nhìn thấy một sự kiện va chạm khiến nó phát ra âm thanh, nhưng các hệ thống vẫn có thể bị lãng quên về nhau. Và tôi đã tìm thấy những hệ thống như vậy dễ dàng hơn nhiều để lý do. Chúng không khiến não tôi muốn nổ tung ngay cả khi bạn có hàng tá hệ thống, bởi vì mỗi hệ thống đều bị cô lập. Bạn không' Không phải suy nghĩ về sự phức tạp của tất cả mọi thứ khi bạn phóng to và làm việc trên bất kỳ cái nào. Và do đó, rất dễ dàng để dự đoán kết quả của những thay đổi của bạn.