2011-12-15 31 views
14

Tôi đã nghiên cứu và tạo ra các trò chơi nhỏ trong một thời gian, và gần đây tôi đã quyết định rằng tôi sẽ cố gắng phát triển trò chơi cho Android.Cách tốt nhất để tách logic trò chơi khỏi hiển thị cho trò chơi có nhịp độ nhanh cho Android bằng OpenGL?

Đối với tôi, việc nhảy từ mã C++ gốc sang Java Android không khó, nhưng nó khiến tôi đau đầu suy nghĩ về cách duy trì logic tách biệt khỏi hiển thị.

Tôi đã đọc ở đây và trên các trang web khác mà:

Nó là tốt hơn để không tạo ra thread khác cho nó, chỉ vì ý Android chắc chắn không có vấn đề để xử lý.

Ý nghĩa mã sẽ là một cái gì đó như thế này:

public void onDrawFrame(GL10 gl) { 
    doLogicCalculations(); 
    clearScreen(); 
    drawSprites(); 
} 

Nhưng tôi không chắc chắn nếu điều đó sẽ là phương pháp tốt nhất. Vì tôi không nghĩ tôi thích nó trông như thế nào nếu tôi đặt logic của mình vào phương thức GLRenderer::onDrawFrame. Theo như tôi biết, phương pháp này có nghĩa là chỉ cần vẽ, và tôi có thể làm chậm khung nếu tôi đặt logic ở đó. Chưa kể rằng nó làm tổn thương các khái niệm về POO trong sự hiểu biết của tôi.

Tôi nghĩ rằng việc sử dụng đề có thể là đường đi, đây là cách tôi đang lên kế hoạch:

Hoạt động chính:

public void onCreate(Bundle savedInstanceState) { 
    //set fullscreen, etc 

    GLSurfaceView view = new GLSurfaceView(this); 
    //Configure view 

    GameManager game = new GameManager(); 
    game.start(context, view); 

    setContentView(view); 
} 

GameManager:

OpenGLRenderer renderer; 
Boolean running; 
public void start(Context context, GLSurfaceView view) { 
    this.renderer = new OpenGLRenderer(context); 
    view.setRenderer(this.renderer); 

    //create Texturelib, create sound system... 

    running = true; 
    //create a thread to run GameManager::update() 
} 

public void update(){ 
    while(running){ 
     //update game logic here 
     //put, edit and remove sprites from renderer list 
     //set running to false to quit game 
    } 
} 

và cuối cùng, OpenGLRenderer:

ListOrMap toDraw; 
public void onDrawFrame(GL10 gl) { 
    for(sprite i : toDraw) 
    { 
     i.draw(); 
    } 
} 

Đây là một ý tưởng thô, không hoàn toàn đầy đủ. Mẫu này sẽ giữ cho tất cả được tách ra và trông đẹp hơn một chút, nhưng nó có phải là cách tốt nhất cho hiệu suất không?

Miễn là tôi đã nghiên cứu, hầu hết các ví dụ về trò chơi luồng đều sử dụng canvas hoặc surfaceview, những ví dụ này sẽ không phù hợp với trường hợp của tôi, bởi vì tôi đang sử dụng OpenGLES.

Vì vậy, đây là những câu hỏi của tôi:

Đó là cách tốt nhất để tách Logic trò chơi của tôi từ rendering khi sử dụng OpenGLES? Threading ứng dụng của tôi? Đặt logic trong một phương pháp riêng biệt và chỉ cần gọi nó từ phương pháp vẽ?

Trả lời

10

Vì vậy, tôi nghĩ có hai cách bạn có thể truy cập tại đây.

  1. Có phải tất cả cập nhật từ onDrawFrame(): này cũng tương tự như sử dụng dư thừa, và Android sẽ gọi hàm này càng nhiều càng tốt. (Tắt tính năng này với setRenderMode(RENDERMODE_WHEN_DIRTY).) Chức năng này được gọi trên chỉ riêng của nó (không phải là chuỗi giao diện người dùng) và điều đó có nghĩa là bạn gọi cập nhật logic của mình tại đây. Vấn đề ban đầu của bạn là điều này có vẻ hơi lộn xộn, và tôi đồng ý, nhưng chỉ vì chức năng được đặt tên là onDrawFrame(). Nếu nó được gọi là onUpdateScene(), thì việc cập nhật logic sẽ phù hợp với mô hình này. Nhưng nó không phải là điều tồi tệ nhất trên thế giới, nó được thiết kế theo cách này, và mọi người làm điều đó.

  2. Hãy cho Logic thread riêng của mình: này là phức tạp hơn vì bây giờ bạn đang làm việc với ba chủ đề: thread UI cho đầu vào, render chủ đề onDrawFrame() để vẽ các công cụ, và các chủ đề logic để tiếp tục làm việc với cả hai dữ liệu đầu vào và kết xuất. Sử dụng điều này nếu bạn cần phải có một mô hình thực sự chính xác về những gì đang xảy ra ngay cả khi tốc độ khung hình của bạn đang giảm (ví dụ, phản ứng va chạm chính xác). Điều này có thể là khái niệm một chút sạch hơn, nhưng không thực tế sạch hơn.

Tôi muốn giới thiệu # 1. Bạn thực sự không cần # 2. Nếu bạn làm, bạn có thể thêm nó sau này tôi đoán, nhưng hầu hết mọi người chỉ sử dụng tùy chọn đầu tiên vì phần cứng đủ nhanh để bạn không phải thiết kế xung quanh nó.

+0

Câu trả lời hay Steve, cảm ơn!Tôi nghĩ rằng ngay cả khi tôi không muốn làm hỏng thiết kế, tôi sẽ làm theo # 1. Trò chơi của tôi đang hoạt động, nhưng không có tính toán nặng về nó, như vật lý hoặc rất nhiều kiểm tra va chạm. Chỉ cần để chắc chắn về những suy nghĩ của tôi, cách tiếp cận của tôi về luồng trong câu hỏi sẽ là chính xác nếu tôi chọn nó (thread logic bằng văn bản trong một bản đồ đồng bộ và làm cho thread đọc nó)? –

+0

Ồ, một điều nữa. mọi người nói tôi giới hạn cập nhật logic của tôi thành 30 khung hình/giây, đây là trường hợp để hiển thị quá? Tôi có nên giới hạn toàn bộ chức năng để chờ 33ms cho mỗi lần cập nhật hay chỉ cập nhật logic nếu đã được thông qua 33ms kể từ lần cập nhật cuối cùng? –

+0

Tôi không nghĩ rằng bạn phải hạn chế nó, nhưng có lẽ không mong đợi tốt hơn so với một số điện thoại. Điều này là do tốc độ khung hình của một số điện thoại HDPI đầu tiên (tôi nghĩ vào khoảng thời gian của Droid 1) đã bị giới hạn, có nghĩa là chúng không thể vẽ một màn hình có nhiều pixel hơn khoảng 30 lần mỗi giây. Có lẽ GPU có thể quay khung hình nhanh hơn thế, nhưng CPU không thể di chuyển chúng đến màn hình đủ nhanh. Đây không phải là trường hợp trên điện thoại mới hơn tôi nghĩ. –

6

Giữ thiết kế của bạn như đơn giản càng tốt :) Tiêu chuẩn (và có thể là tốt nhất) tiếp cận được như sau:

public void update(){ 
    while(running){ 
     updateAll(); 
     renderAll(); 
    } 
} 

tôi sẽ chú ý vào một số khoảnh khắc:

  • bạn cần phải gọi theo thứ tự updaterender phương pháp, tránh gọi update hai lần một lần
  • nếu bạn thích m ultithreading (Tôi không), thiết kế các phương pháp của bạn để update ghi dữ liệu và render chỉ đọc
  • hãy nhớ rằng OpenGL có "chuỗi" riêng của nó, vì vậy khi bạn gọi hàm GL nó chỉ gửi một số lệnh tới OpenGL (trừ glFlush() - nó hoàn thành tất cả các lệnh)
+0

hmm, làm chủ đề cuối cùng của bạn, onDrawFrame từ OpenGLrenderer được gọi trên một chuỗi khác? hoặc chỉ gl.GLxxx() được gửi theo yêu cầu đến chủ đề khác phù hợp với GL? –

+0

@Gtoknu Khi bạn nhận được cuộc gọi 'onDrawFrame()', bạn đang ở trên một chủ đề khác. Xem tại đây: http://developer.android.com/reference/android/opengl/GLSurfaceView.Renderer.html –

+0

@SteveBlackwell Oh, cảm ơn, tôi đã không nhận ra điều đó. Nhưng làm thế nào brigadir có thể trả lời là đúng nếu tôi không thể gọi onDrawFrame() vì nó được tự động gọi bởi một thread? những người đang bối rối. –

Các vấn đề liên quan