Bài đăng phổ biến

Thứ Hai, 5 tháng 11, 2012

Vòng đời của AndEngine Game, Sự khác nhau giữa SimpleBaseGameActivity và BaseGameActivity

What is the different between extends SimpleBaseGameActivity and BaseGameActivity and BaseActivity?

SimpleBaseGameActivity có trong GLES2 nó giống với BaseGameActivity trong AndEngine GLES1 và nó chỉ moves 1 method loadComplete tới là chạy tự động.

BaseGameActivity trong GLES2 nó không giống BaseGameActivity trong GLES1. Trong GLES2 nó yêu cầu bạn sử dụng CallBack trước khi bạn chuyển từ method này tới method tiếp theo.


Launch Game
  1. onLoadEngine()
  2. onResume()
  3. onLoadResources()
  4. onLoadScene()
  5. onLoadComplete()
  6. onGameResumed()
Trong game trở về màn hình chính của device(HomeScreen)

  1. onPause()
Để trở lại game

  1. onResume()
  2. onGameResumed()
Exit game với this.finish()

  1. onPause()
  2. onDestroy()

hope! That's good for you.

Sửa lỗi Code 43 trên Win 7


cắm usb vô,

mở start > run > devmgmt.msc > tìm dòng unknown device

bấm chuột phải lên nó chọn uninstall.

rút usb cắm qua cổng khác cho nó nhận lại

sau đó tải file này về chạy

Code:
http://download.microsoft.com/download/5/2/3/52323091-3F94-4076-B544-F76B9B1247BD/Mats_Run.devices.exe

Chủ Nhật, 4 tháng 11, 2012

Tạo và quản lý Scenes

Như tôi đã đề cập trong bài trước http://opengles-android.blogspot.com/2012/11/thiet-ke-game-cua-ban-usefull-concept.html Để dễ dàng hơn chỉ cần tạo 1 activity với nhiều Scenes thay vì nhiều Activitys để xử lý những phần khác nhau của game. Tôi sẽ tư vấn theo cách sử dụng những Scenes như thế này giống như tôi đã posted trong diagram ở previous tutorial.

Và bây giờ phát sinh câu hỏi, làm như thế nào để quản lý tốt Scenes? Tốt nhất là các bạn nên tạo Enum với các kiểu Scenes.

Ví dụ bạn cần 4 cảnh:


  1. Splash Screen  (Shown while loading resource)
  2. Menu Scene (Xuất hiện sau khi load resource)
  3. Option Scene
  4. Game Scene
Vì vậy hãy tạo Enum với các kiểu Scenes: Ví dụ

  1. public enum SceneType
  2.  {
  3.        SPLASH,
  4.        MENU,
  5.        OPTIONS,
  6.        GAME,
  7.  }
  8.  
  9.  public SceneType currentScene = SceneType.SPLASH;



Và sau đó trong khi lựa chọn các Scenes khác nhau, luôn luôn nhớ rằng để thay đổi kiểu Enum của Scene. vì vậy chúng ta theo dõi kiểu nào Scene hiện thời được biểu diễn, Ví dụ sau sẽ lựa chọn từ Splash Screen tới Menu Screen.

     mEngine.setScene(menuScene);
     currentScene = SceneType.MENU;


Chúng ta có thể viết đè onKeyDown để dễ dàng điều khiển lựa chọn các Scenes trong khi phím Back được nhấn:


  1. @Override
  2. public boolean onKeyDown(int keyCode, KeyEvent event)
  3. {  
  4.      if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() ==KeyEvent.ACTION_DOWN)
  5.      {          
  6.           switch (currentScene)
  7.           {
  8.                case SPLASH:
  9.               break;
  10.                case MENU:
  11.                     System.exit(0);
  12.                     break;
  13.                case OPTIONS:
  14.                     mEngine.setScene(menuScene);
  15.                     currentScene = SceneType.MENU;
  16.                     break;
  17.                case GAME:
  18.                     mEngine.setScene(gameScene);
  19.                     currentScene = SceneType.MENU;
  20.                     break; 
  21.           }
  22.      }
  23.      return false;
  24. }

Đoạn code trên thực hiện những gì? nó kiểm tra nut Back được nhấn, và lựa chọn giữa các Scenes (Phụ thuộc trên những cảnh hiện thời) và trong trường hợp này:

  • Trong khi game đang loading (Splash Screen) thì không thực hiện sự kiện gì cả
  • Khi ở trong Menu Scenes, chúng ta đơn giản thoát từ game
  • Khi nó ở trong lựa chọn Options Scene, chúng ta lựa chọn trở lại tới Menu Scene
  • khi nó ở trong Game Scenes. giống như ở trên. 


Với cách này chúng ta dễ dàng theo dõi các Scenes. và lựa chọn chúng cho activity cuối cung.







Thiết kế Game của bạn (USEFULL concept "pattern"

nguồn: https://sites.google.com/site/matimdevelopment/how-to-design-your-game-useful-concept-pattern

Trong bài này tôi sẽ mô tả ý kiến chủ quan của tôi về việc làm thế nào để có kế hoạch và phát triển trò chơi của riêng bạn sử dụng AndEngine. Cái này rất hữu ích cho những người mới phát triển để bắt đầu. Tại sao tôi nghĩ rằng quan trọng là phải có kế hoạch ngắn hạn trước khi bắt đầu phát triển ứng dụng của bạn. Nếu bạn có kế hoạch thực hiện thì nó rễ dàng đoán trước được mọi việc ngay từ đầu. (Từ kinh nghiệm cá nhân tôi đã phát triển trò chơi mà không có kế hoạch gì cả -->Đó là sự đau đớn, và tôi phải cặm cụi viết lại nhiều bộ phận của game trong khi chỉ cần thêm một số tính năng quan trọng). Với một kế hoạch và cấu trúc dự án tốt sẽ rất hữu ích cho tương lại. Viết game đặc biệt một mình thực sự rất tốn thời gian, để làm cho nó dễ dàng hơn với project của bạn. Hãy tham khảo một số lời khuyên của tôi:

Vì vậy! Cho phép tôi nói rằng, bạn phải có 1 ý tưởng tuyệt vời với một trò chơi mới, và những gì phát triển tiếp theo trong tương lai. Theo tôi hãy suy nghĩ thật kỹ trước khi bắt đầu coding. Hãy nghĩ những gì và các lớp gì mà bạn cần thiết, những gì sẽ phải khởi tạo, Cấu trúc của dự án tốt là chìa khóa để thành công.


  • Write it somewhere, think about structure
  • Try to draw classes diagram, will be easier to imagine everything latter.
  • Explore Engine, for sure many things already implemented, just profit
  • Convert your ideas into code.

Many Activitys versus Scenes

Rõ dàng là không nhiều Activitys trong hầu hết các trường hợp

  • Menu Activity
  • Options Activity
  • Game Activity
Nhưng nó là cách tốt để tạo ra nhiều Activitys (Đây không phải là ý kiến của tôi). Đầu tiên là trong thời gian loading resource (thời gian giữa lúc game hoạt động, vì vậy bạn phải load tại nguyên) va nó khá khó giải quyết với nhiều Activitys bạn sẽ kết thúc với nhiều vấn để với việc truy cập tới các đối tượng và các phần game khác nhau. Điều đó giải thích tại sao thật tốt nếu có 1 Activity theo cách của mình, sẽ dễ dàng hơn để phát triển . Với cách này, bạn chỉ cần load tài nguyên một lần (Lúc khởi chạy ban đầu) từ kinh nghiệm nó có nhiều lợi thế như cần ít thời gian hơn để chuyển đổi, và bộ nhớ cũng ít hoạt động hơn. Bạn cũng có thể tái sử dụng các đối tượng theo cách này.

Lược đồ sau là cái nhìn tổng quát cho ứng dụng của bạn.




Lược đồ trên chỉ ra có 4 cảnh trong một Activity. Với cách này, chúng ta loadresource chỉ 1 lần, sau khi load xong chúng ta đơn giản tời Menu Scene và play.






























































AsyncTask Trong Android

Nguồn: http://www.24h-mobile.com/data/AsyncTask-Trong-Android.html

1. Giới thiệu


Một chương trình chạy trên Android có thể sẽ có cấu trúc phức tạp. Yêu cầu kết nối đến Server, CSDL, tải file … Nếu chúng ta xử lý các công việc đó trên Main Thread sẽ làm ứng dụng có vẻ chạy chậm hay treo vì chúng làm gián đoạn việc cập nhật, xử lý trên GUI. Có nhiều cách để giải quyết vấn đề này: sử dụng Service, Thread hay đơn giản hơn là dùng Async Task (Asynchronous Task).

2. Class AsyncTask

Class này cho phép chúng ta chạy tác vụ nền và sau đó trả lại kết quả cập nhật lên GUI mà không phải động đến Thread/handler khá rắc rối và đau đầu.

Sử dụng:

private class MyTask extends AsyncTask <Params, Progress, Result>{

    @Override
        protected void onPreExecute() {
            
        }
        
        @Override
        protected Result doInBackground(Params param) {
            
        }
        
        @Override
        protected void onProgressUpdate(Progress progress) {
          
        }
        
        @Override
        protected void onPostExecute(Result result) {
           
        }


Trong đó:

- Params: các parameters được truyền vào khi task được thực hiện
- Progress: Các thông tin về tiến độ task được trả về khi task chạy
- Result: Kết quả cuối cùng khi task xong.
- Không phải khi nào cũng phải sử dụng đầy đủ chúng. Để đánh dấu không dùng ta sử dụng kiểu Void

VD:

private class SearchSrv extends AsyncTask<Void, Void, PlacesList>


4 bước thực hiện task (Không nhất thiết phải đầy đủ)

onPreExecute()  báo thay đổi đến UI ngay khi task chạy, thường được dùng để hiện progressbar chẳng hạn.
doInBackground(Params...) Thực hiện khi bước 1 xong. Dùng để xử lý Task, có thể tốn nhiều thời gian. Kết quả trả về sẽ được đưa qua bước 4. 
onProgressUpdate(Progress...), cập nhật tiến độ Task
onPostExecute(Result), trả về kết quả cập nhật lên UI.

3. Chú ý

- Task instance và instance.execute() phải được tạo và chạy  trong UI Thread.
- Không gọi các phương thức onPreExecute, doInBackGround,onProgressUpdate, onPostExecute thủ công.
- Task chỉ có thể được chạy 1 lần (Nếu khởi chạy lần thứ 2 sẽ có exception)





Thứ Bảy, 3 tháng 11, 2012

Splash Creen trong android

Có rất nhiều ứng dụng, đặc biệt là Game. Khi khởi chạy game thì đầu tiên màn hình hiển thị thông thường là Splash Screen, mà màn hình hiển thị lúc này thường là giới thiệu tác giả hoặc giới thiệu logo của nhà sản xuất...

Bài này tôi sẽ hướng dẫn các bạn cài đặt Splash Screen một cách thật đơn giản, nó hiển thị lúc khởi động và sẽ chạy trong một khoảng thời gian ngắn nào đó.

OK! let's start

1. Create Launcher activity (Đây sẽ là SplashScreen của bạn)
2. Tạo main Activity của bạn (Màn hình chính của game)
3. Cài đặt Splash với một layout chứa 1 progressBar
4. Bắt đầu a Task để load Resource của bạn
5. Gọi lại Plash của bạn mà bạn vừa mới finish();
6. Start yout app
Đầu tiên chúng ta bắt đầu với SplashActivity. Cái này chưa ProgressBar mà biểu diễn ứng dụng của bạn loading.
SplashActivity.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
package com.blundell.tut.ui;
 
import com.blundell.tut.R;
import com.blundell.tut.task.LoadingTask;
import com.blundell.tut.task.LoadingTask.LoadingTaskFinishedListener;
 
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.widget.ProgressBar;
 
public class SplashActivity extends Activity implements LoadingTaskFinishedListener {
 
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // Show the splash screen
        setContentView(R.layout.activity_splash);
        // Find the progress bar
        ProgressBar progressBar = (ProgressBar) findViewById(R.id.activity_splash_progress_bar);
        // Start your loading
        new LoadingTask(progressBar, this).execute("www.google.co.uk"); // Pass in whatever you need a url is just an example we don't use it in this tutorial
    }
 
    // This is the callback for when your async task has finished
    @Override
    public void onTaskFinished() {
        completeSplash();
    }
 
    private void completeSplash(){
        startApp();
        finish(); // Don't forget to finish this Splash Activity so the user can't return to it!
    }
 
    private void startApp() {
        Intent intent = new Intent(SplashActivity.this, MainActivity.class);
        startActivity(intent);
    }
}


Bạn chú ý. Lớp trên cài đặt giao diện LoadingTaskFinishedListener sử dụng giao diện là 1 cách của việc giao tiếp giữa các lớp. Bạn đang nói "Tôi có khả năng nhận về một thông điệp mà trông giống ...this" Bởi vì ASyncTask có 1 trường mà là 1 đối tượng của giao diện đó nó có thể bất chợt phát ra những thông điệp đó và Activity của bạn sẽ nhận được chúng . Tiếp theo là ASyncTask

LoadingTask.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
package com.blundell.tut.task;
 
import android.os.AsyncTask;
import android.util.Log;
import android.widget.ProgressBar;
 
public class LoadingTask extends AsyncTask<String, Integer, Integer> {
 
    public interface LoadingTaskFinishedListener {
        void onTaskFinished(); // If you want to pass something back to the listener add a param to this method
    }
 
    // This is the progress bar you want to update while the task is in progress
    private final ProgressBar progressBar;
    // This is the listener that will be told when this task is finished
    private final LoadingTaskFinishedListener finishedListener;
 
    /**
     * A Loading task that will load some resources that are necessary for the app to start
     * @param progressBar - the progress bar you want to update while the task is in progress
     * @param finishedListener - the listener that will be told when this task is finished
     */
    public LoadingTask(ProgressBar progressBar, LoadingTaskFinishedListener finishedListener) {
        this.progressBar = progressBar;
        this.finishedListener = finishedListener;
    }
 
    @Override
    protected Integer doInBackground(String... params) {
        Log.i("Tutorial", "Starting task with url: "+params[0]);
        if(resourcesDontAlreadyExist()){
            downloadResources();
        }
        // Perhaps you want to return something to your post execute
        return 1234;
    }
 
    private boolean resourcesDontAlreadyExist() {
        // Here you would query your app's internal state to see if this download had been performed before
        // Perhaps once checked save this in a shared preference for speed of access next time
        return true; // returning true so we show the splash every time
    }
 
 
    private void downloadResources() {
        // We are just imitating some process thats takes a bit of time (loading of resources / downloading)
        int count = 10;
        for (int i = 0; i < count; i++) {
 
            // Update the progress bar after every step
            int progress = (int) ((i / (float) count) * 100);
            publishProgress(progress);
 
            // Do some long loading things
            try { Thread.sleep(1000); } catch (InterruptedException ignore) {}
        }
    }
 
    @Override
    protected void onProgressUpdate(Integer... values) {
        super.onProgressUpdate(values);
        progressBar.setProgress(values[0]); // This is ran on the UI thread so it is ok to update our progress bar ( a UI view ) here
    }
 
    @Override
    protected void onPostExecute(Integer result) {
        super.onPostExecute(result);
        finishedListener.onTaskFinished(); // Tell whoever was listening we have finished
    }
}


LoadingTask là bộ khung của ASyncTask, chúng ta cài đặt 1 callBack trong constructor. sau đó kiểm tra nếu Resources của ta tải về mà tồn tại,......nếu không. Một khi chúng ta tải về kết thúc chúng ta thông báo lại Listener.
Nhiệm vụ này bắt trước.....kiểu như giả loadding Nhưng ở bài này nó không phải là trọng tâm. Bạn nhận thấy mỗi vòng lặp được hoàn tất chúng sẽ update progressbar. Bạn hãy nhớ rằng 1 progressbar là 1 Android View Object. View Object là 1 phần của UI vì vậy có thể update trên UIThread. Vì vậy chúng ta sử dụng onProgressUpdate() method mà android cung cấp chắc chắn chạy trên UIThead.

Khi updating 1 progressbar bạn gửi nó giá trị từ 0-100 và giá trị này sẽ là progressbar của nó. Trong ví dụ này chúng ta chạy qua 1 vòng lặp đếm tới 10 do đó mỗi vòng lặp sẽ là 10% của progressbar.

VD: In AndEngine

  1. public class MainGameActivity extends BaseGameActivity {
  2.         // ===========================================================
  3.         // Final Fields
  4.         // ===========================================================
  5.         // ===========================================================
  6.         // Constants
  7.         // ===========================================================
  8.         private static final int CAMERA_WIDTH = 480;
  9.         private static final int CAMERA_HEIGHT = 800;
  10.         // ===========================================================
  11.         // Fields
  12.         // ===========================================================
  13.         protected Camera mCamera;
  14.         // splash scene
  15.         protected Scene mSplashScene;
  16.         private BitmapTextureAtlas mSplashBackgroundTextureAtlas;
  17.         private TextureRegion mSplashBackgroundTextureRegion;
  18.         // menu scene
  19.         protected Scene mMenuScene;
  20.         // ...
  21.         // ===========================================================
  22.         // Methods for/from SuperClass/Interfaces
  23.         // ===========================================================
  24.         @Override
  25.         public Engine onLoadEngine() {
  26.                 this.mCamera = new Camera(0, 0, CAMERA_WIDTH, CAMERA_HEIGHT);
  27.                 return new Engine(new EngineOptions(true, ScreenOrientation.PORTRAIT,new RatioResolutionPolicy(CAMERA_WIDTH, CAMERA_HEIGHT),this.mCamera).setNeedsSound(true));
  28.         }
  29.         @Override
  30.         public void onLoadResources() {
  31.                 BitmapTextureAtlasTextureRegionFactory.setAssetBasePath("gfx/");
  32.                 mSplashBackgroundTextureAtlas = new BitmapTextureAtlas(512, 1024, TextureOptions.NEAREST);
  33.                 mSplashBackgroundTextureRegion =BitmapTextureAtlasTextureRegionFactory.createFromAsset(mSplashBackgroundTextureAtlas,this"splash.jpg", 0, 0);
  34.                 mEngine.getTextureManager().loadTextures(mSplashBackgroundTextureAtlas);
  35.         }
  36.         @Override
  37.         public Scene onLoadScene() {
  38.                 mSplashScene = new Scene();
  39.                 mSplashScene.setBackgroundEnabled(false);
  40.                 mSplashScene.attachChild(new Sprite(0, 0, mSplashBackgroundTextureRegion));
  41.                 return this.mSplashScene;
  42.         }
  43.        
  44.         @Override
  45.         public void onLoadComplete() {
  46.                 mEngine.registerUpdateHandler(new TimerHandler(0.01f, newITimerCallback() {
  47.                         @Override
  48.                         public void onTimePassed(final TimerHandler pTimerHandler) {
  49.                                 mEngine.unregisterUpdateHandler(pTimerHandler);
  50.                                 loadResources();
  51.                                 loadScenes();
  52.                                 mEngine.setScene(mMenuScene);
  53.                         }
  54.                 }));
  55.         }
  56.         // ===========================================================
  57.         // Methods
  58.         // ===========================================================
  59.         public void loadResources() {
  60.                 // menu resources
  61.                 // help resources
  62.                 // pick level resources
  63.                 // game resources
  64.         }
  65.         public void loadScenes() {
  66.                 // menu scene
  67.                 // help scene
  68.                 // pick level scene
  69.                 // game scene
  70.         }
  71. }

ViDu:

The problem is most likely that you are running the splash screen (some sort of Dialog such asProgressDialog I assume) in the same thread as all the work being done. This will keep the view of the splash screen from being updated, which can keep it from even getting displayed to the screen. You need to display the splash screen, kick off an instance of AsyncTask to go download all your data, then hide the splash screen once the task is complete.
So your Activity's onCreate() method would simply create a ProgressDialog and show it. Then create the AsyncTask and start it. I would make the AsyncTask an inner class of your main Activity, so it can store the data it has downloaded to some variable in your Activity and close the ProgressDialog in its onPostExecute() method.
Not sure how to elaborate anymore without just showing the code, so here it is:

public class MyActivity extends Activity {
    private ProgressDialog pd = null;
    private Object data = null;

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        // Show the ProgressDialog on this thread
        this.pd = ProgressDialog.show(this, "Working..", "Downloading Data...", true, false);

        // Start a new thread that will download all the data
        new DownloadTask().execute("Any parameters my download task needs here");
    }

    private class DownloadTask extends AsyncTask<String, Void, Object> {
         protected Object doInBackground(String... args) {
             Log.i("MyApp", "Background thread starting");

             // This is where you would do all the work of downloading your data

             return "replace this with your data object";
         }

         protected void onPostExecute(Object result) {
             // Pass the result data back to the main activity
             MyActivity.this.data = result;

             if (MyActivity.this.pd != null) {
                 MyActivity.this.pd.dismiss();
             }
         }
    }    
}

Obviously there are some pieces you need to fill in there, but this code should run and give you a good starting point (forgive me if there is a code error, I don't have access to the Android SDK as I'm typing this currently).
Some more good reading on the subject of AsyncTasks in Android can be found here and here.


Hoac:

public class SplashScreen extends Activity{
   @Override
   public void onCreate(Bundle savedInstanceState){
      super.onCreate(savedInstanceState);
      // set the content view for your splash screen you defined in an xml file
      setContentView(R.layout.splashscreen);

      // perform other stuff you need to do

      // execute your xml news feed loader
      new AsyncLoadXMLFeed().execute();

   }

   private class AsyncLoadXMLFeed extends AsyncTask<Void, Void, Void>{
      @Override
      protected void onPreExecute(){
            // show your progress dialog

      }

      @Override
      protected Void doInBackground(Void... voids){
            // load your xml feed asynchronously
      }

      @Override
      protected void onPostExecute(Void params){
            // dismiss your dialog
            // launch your News activity
            Intent intent = new Intent(SplashScreen.this, News.class);
            startActivity(intent);

            // close this activity
            finish();
      }

   }
}