Rất nhiều trò chơi Android thậm chí không đủ lớn trong phạm vi để biện minh cho việc lưu / tải hoặc tùy chọn / tùy chọn, không bao giờ bận tâm đến các nhân vật tùy chỉnh và tương tự chỉ vì chúng được chơi một cách tự do trong 10 phút trên tàu về nhà.
Đừng phạm sai lầm mà tôi đã làm khi bắt tay vào một cái gì đó với phạm vi rộng cho một trò chơi Android đầu tiên. Tạo ra một loạt các trò chơi nhỏ hơn sau đó tìm kiếm một cái gì đó lớn hơn
Thông tin cụ thể về Android:
Kết cấu:
Tôi khuyên bạn nên có hầu hết tất cả các trò chơi trong một lớp hoạt động. Android hoạt động dựa trên ý tưởng rằng mỗi hoạt động giống như một ứng dụng nhỏ, bán độc lập với các hoạt động khác trong ứng dụng. Ứng dụng về cơ bản là một chồng các hoạt động, với người dùng nhìn thấy cái nào đã từng đứng đầu.
Khi bạn bật một cái khỏi đầu, nó thường bị phá hủy và sẽ được tạo lại vào lần tới khi người dùng bắt đầu một hoạt động mới (ý định startActivity). Điều này khiến cho việc duy trì trạng thái giữa các hoạt động trở nên khó khăn và dẫn đến một kiến trúc hoạt động đơn lẻ
Bạn có thể muốn có một hoạt động loại Màn hình chính với menu "Trò chơi mới / Tải trò chơi / Tùy chọn" trên đó và thực hiện hoạt động khởi chạy đó. Tuy nhiên, cuối cùng bạn sẽ phải có một menu trong trò chơi cũng như trong hoạt động trò chơi của mình, nơi sẽ có hầu hết các chức năng tương tự trong đó
Ứng dụng của riêng tôi, tôi đã tạo một "MenuActivity" có các chức năng khởi chạy một trò chơi mới, lưu, tải, thay đổi tùy chọn. Sau đó, HomeActivity của tôi mở rộng điều đó, cũng như GameActivity của tôi.
Vì mọi thứ đều nằm trong một lớp Activity, tôi khuyên bạn nên tạo một kiểu thừa kế của các lớp hoạt động và sử dụng các lô phạm vi riêng tư, được bảo vệ và mặc định. Làm theo cách này, ít nhất bạn có thể chia mọi thứ thành các tệp khác nhau để ngăn không có một tệp Hoạt động không thể quản lý được. Ví dụ cho ứng dụng của riêng tôi:
GraphicsEngine extends MenuActivity
.
PhysicsEngine extends GraphicsEngine
.
GameLogicActivity extends PhysicsEngine
.
UIActivity extends GameLogicActivity
.
Vì ứng dụng của tôi là 3D opengl-es, rất nhiều thứ tôi làm không hoạt động chéo nên mọi thứ đều trong cùng một hoạt động, vì vậy có lẽ tôi thiên về sử dụng một kiến trúc hoạt động
-
Luồng
Đối với hoạt động trò chơi, Bạn có hai luồng (hoặc 3 nếu bạn đang thực hiện công cụ opengl 3D). Một luồng là UI / luồng chính. Đây là chủ đề mà hoạt động được bắt đầu và chạy trong và được đưa cho bạn bởi Android.
Chủ đề UI này là người duy nhất bạn có thể cập nhật các thành phần UI (chế độ xem, bố cục, v.v.). Đây cũng là một trong đó bất kỳ trình nghe nào cho đầu vào của người dùng sẽ chạy. Bạn không thấy bất kỳ cơ chế nào của luồng UI, chỉ là nó chạy trong một vòng lặp ở nền ở đâu đó.
Chủ đề thứ hai, bạn tự làm (tôi khuyên bạn nên sử dụng AsyncTask , mặc dù tất cả các thiếu sót của nó). Điều này thực hiện tất cả những thứ không phải UI mà bạn làm trong một vòng lặp trò chơi thông thường, chẳng hạn như cập nhật chuyển động, tính toán va chạm, tính toán chiến đấu, v.v.
Bạn tạo chủ đề / lớp AsyncTask này như một lớp bên trong của hoạt động. Bằng cách đó, bạn có thể có một số đối tượng phạm vi hoạt động ( Vector<Spaceship>
) có thể được truy cập bởi cả luồng UI và luồng vòng lặp trò chơi.
Vì logic trò chơi đang diễn ra trong chuỗi vòng lặp trò chơi, đó là luồng duy nhất cần thực sự thay đổi giá trị của các biến (cập nhật tốc độ xe tăng, giảm HP của người chơi). Chủ đề UI chỉ đọc các giá trị, do đó cần có các vấn đề tương tranh tối thiểu.
Một mẹo nhỏ là lấy luồng UI để cập nhật theo yêu cầu của chuỗi vòng lặp trò chơi. Có một vài cách để làm điều này. Nếu bạn đọc tài liệu AsyncTask, nó có phương thức PublishProTHER () / onProTHERUpdate (). Đây thực sự là thêm công cụ vào hàng đợi các luồng của giao diện người dùng để thực hiện vòng lặp tiếp theo.
Handler thực hiện chính xác điều tương tự, trong đó bạn triển khai phương thức handleMessage () và phương thức đó thực sự được thực hiện bởi luồng UI vòng lặp tiếp theo.
Cuối cùng, bất kỳ đầu vào nào của người dùng, nằm trong luồng UI, bạn có thể cập nhật các thành phần UI ngay lập tức từ nó (vì vậy bên trong việc thực hiện bất kỳ trình nghe onClick / onTouch nào). Nếu bạn cần cập nhật các đối tượng trò chơi, bạn có thể sử dụng những thứ như đồng bộ hóa hoặc bạn có thể triển khai hàng đợi cập nhật của riêng mình vào AsyncTask giống như luồng UI, nó sẽ đi qua lần tiếp theo thực hiện vòng lặp trò chơi
Hướng dẫn xử lý luồng Android .
-
Giao diện người dùng
Đối với cấu trúc UI thực tế trong một hoạt động, tôi khuyên bạn nên có bố cục khung làm bố cục cơ sở. Các phần tử con trong bố trí khung làm việc như một hàng đợi. Phần tử đầu tiên được vẽ đầu tiên, phần thứ hai được vẽ trên đầu tiên, thứ ba trên đầu thứ hai.
Theo cách này, bạn có thể có nhiều tệp bố cục XML và bằng cách quản lý các con của bố cục khung, có thể dễ dàng trao đổi các khung nhìn vào và ra.
Nếu bạn luôn có SurfaceView ở phía dưới (con đầu tiên trong bố cục khung), thì bạn có thể sử dụng tất cả các chế độ xem / tiện ích Android thông thường (nút, chế độ xem văn bản, chế độ xem cuộn), v.v. phần đồ họa của trò chơi.
Vì vậy, ví dụ, nếu có thứ gì đó đang tải, bạn có thể tạm dừng vòng lặp trò chơi / chỉ cần làm cho nó bỏ qua mọi thứ, thêm màn hình 'tải' mờ đục như là đứa trẻ cuối cùng vào bố cục khung và người dùng sẽ thấy 'đang tải' xuất hiện trên màn hình của họ , khá không biết rằng các quan điểm khác đằng sau nó. Bằng cách này, bạn không phải xóa các chế độ xem mất nhiều thời gian để thiết lập hoặc gây ra các biến chứng mỗi khi chúng được thêm / xóa.
Tôi cũng sẽ khuyên bạn nên sử dụng rất nhiều View.setVisibility. Ví dụ, bạn có thể thêm toàn bộ bố cục 'khoảng không quảng cáo vào bố cục khung cơ sở của mình và sau đó chỉ đặt setVisibility (View.Visible) trên đó khi người dùng nhấp để xem kho của họ và setVisibility (View.Gone) khi họ đóng lại. Bằng cách đó, bạn thậm chí không quản lý con cái của bố cục khung nhiều như chỉ thêm mọi thứ và làm cho mọi thứ hiển thị / vô hình và khi người dùng làm những việc khác nhau
Điều này giúp với luồng một lần nữa; khi người dùng nhấp để mở kho lưu trữ của họ, onCLickListener được xử lý trong luồng UI, kho lưu trữ được hiển thị trong đó và phương thức updateInventory được gọi, một lần nữa từ luồng UI, chỉ với getters trên tất cả các đối tượng trò chơi được gọi
Đây là sơ đồ tôi đã thực hiện cho một câu hỏi trước đó về ý tưởng bố cục hoạt động / khung đơn: