2012-03-28 41 views
7

Tôi muốn viết một số trò chơi đơn giản trong android bằng cách sử dụng es opengl nhưng ngay lập tức gặp rắc rối với vòng lặp trò chơi chính. Như tôi đã đọc ở đây: http://developer.android.com/resources/tutorials/opengl/opengl-es10.html cuộc gọi ứng dụng public void onDrawFrame(GL10 gl) mỗi khi cần vẽ lại bề mặt. Hoặc smth như thế. Vấn đề của tôi là - cách tạo một vòng lặp cập nhật độc lập với các cuộc gọi vẽ. Tôi có nghĩa là - nó không thể làm việc như thế, tôi không thể cập nhật logic trò chơi chỉ khi thiết bị (ứng dụng?) Muốn vẽ lại bề mặt (hoặc tôi sai?).Làm cách nào để tạo vòng lặp cập nhật/vẽ phù hợp với phiên bản android?

Sau khi một số googling tôi đi đến kết luận rằng tôi phải tạo một luồng khác cho vòng lặp cập nhật. Nhưng sau đó tôi đã có một vấn đề khác - với một chủ đề chăm sóc vẽ và một người khác chăm sóc cập nhật logic trò chơi tôi không biết làm thế nào để làm cho họ hợp tác. Đầu tiên, chúng là hai lớp riêng biệt (ít nhất là trong việc thực hiện của tôi) nên chúng không thể sử dụng cùng các biến và đối tượng trò chơi (sprites, timers, biến khác nhau, counters ...) công việc của họ). Bây giờ tôi nghĩ rằng tôi bằng cách nào đó có thể đóng gói cả hai thành một lớp. Nhưng - thứ hai, tôi cần phải đồng bộ hóa hai chủ đề bằng cách nào đó.

Cuối cùng, tôi bước ra với ý tưởng chung này:

  • 3 lớp:
    1. public class MyRenderer implements GLSurfaceView.Renderer với onSurfaceCreated() phương pháp chăm sóc vẽ
    2. public class UpdateThread implements Runnable với run()update() phương pháp. run() đã gọi phương thức update() chính xác 60 lần một giây (Tôi muốn có vòng lặp cố định)
    3. public class SpritesHolder được sử dụng làm vùng chứa cho tất cả các đối tượng trò chơi/biến/thứ (như sprites, giờ, biến trạng thái, v.v ...) với tất cả các trường công khai.
  • Vì vậy, về cơ bản lớp SpritesHolder là một hộp giữ tất cả các biến cần thiết ở một nơi, vì vậy MyRendererUpdateThread lớp có thể truy cập vào nó và sử dụng nó.
  • Đối với đồng bộ hóa - Tôi chỉ làm smth như thế này:

    public void update(float delta) 
    { 
        synchronized (spritesHolder) 
        { 
         // whole method code... 
        } 
    } 
    

    và:

    public void onDrawFrame(GL10 gl) 
    { 
        synchronized (spritesHolder) 
        { 
         // whole method code... 
        } 
    } 
    

    để cả hai chủ đề không sử dụng spritesHolder cùng một lúc. Vì vậy, cập nhật đã được thực hiện 60 lần mỗi giây và bản vẽ diễn ra bất cứ khi nào ứng dụng (thiết bị?) Cần thiết.

Rất nhiều nói chuyện, xin lỗi, tôi gần như đã hoàn thành viết bài đăng này. ;) Vì vậy, anyway - điều này (mô tả ở trên) hoạt động và tôi thậm chí đã viết một số trò chơi dựa trên 'mẫu' này nhưng tôi nghĩ rằng ý tưởng của tôi có thể điên và ai có thể desing nó tất cả tốt hơn rất nhiều. Tôi rất biết ơn mọi ý kiến ​​và lời khuyên.

+0

chỉ một từ: http://obviam.net/ :) – akonsu

Trả lời

1

Giải pháp của bạn có thể sẽ hoạt động, mặc dù giải pháp này có thể kém tối ưu cho hiệu suất. Nếu bạn nghĩ về nó, chuỗi kết xuất và chuỗi cập nhật không thực sự cần phải độc quyền 100%.

Gần đây tôi đã trải qua một thời gian suy nghĩ về vấn đề này cho trò chơi của tôi, và đây là những gì tôi đã kết thúc đến với (không nhất thiết phải tốt hơn, nhưng chỉ cần một cái gì đó để suy nghĩ về):

Đối với mỗi đối tượng renderable, tôi có một đối tượng thuộc sở hữu của chủ đề cập nhật và một đối tượng khác thuộc chủ đề kết xuất chỉ là một vùng chứa đơn giản chứa hướng dẫn cách vẽ đối tượng (ma trận mô hình, giá trị thống nhất, meshID, v.v.). Tôi chạy qua máy tính cập nhật tất cả các vị trí và giá trị cuối cùng cho các đối tượng có thể hiển thị của tôi, và sau đó tôi đồng bộ hóa cho một cửa sổ nhỏ, nơi tôi chuyển bất kỳ giá trị nào đã thay đổi trong khung đó đến các đối tượng trong chuỗi có thể hiển thị. Sau đó, ngay sau khi thông tin mới đã trôi qua, việc hiển thị khung hình bắt đầu trong khi khung cập nhật tiếp theo chạy đồng thời. Bởi vì chỉ có một cửa sổ loại trừ nhỏ, nó cho phép cập nhật và vẽ các chủ đề để chạy đồng thời hầu hết thời gian.

1

Tôi chưa sử dụng tính năng này với OpenGL, nhưng UpdateThread phải là TimerTask. Khi bạn khởi động hoạt động với

new Timer().schedule(new UpdateThread(view), 0, 15); //where view is your view, and 15 is the wait time 

trong TimerTask gọi chế độ xem bằng Trình xử lý. ví dụ (trong lớp nhìn của bạn)

Handler refreshHandler = new Handler() { 
    public void handleMessage(Message msg) { 
       //Handle it; e.g. for canvas invalidate() 
      }}; 

Trong phương pháp UpdateThread chạy của bạn làm điều này:

view.refreshHandler.sendMessage(new Message()); 

Bây giờ nó không phụ thuộc vào gameloop của bạn. Hơn nữa, gameloop của bạn không nên ở trong MainActivity nhưng trong một Thread (OO một chiều).

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