2013-04-08 19 views
15

Jestem nowy w Libgdx i mam problemy z używaniem bazy danych w mojej grze.Używanie bazy danych SQLite w Libgdx

Szukałem poradnika, jak sprawić, aby SQLite działało zarówno na Androida, jak i na komputerach stacjonarnych przy użyciu Libgdx, ale nie znalazłem łatwego.

Kiedy ostatnio używałem bazy danych w systemie Android, utworzyłem klasę, która rozciąga się od SQLiteOpenHelper.

Czy istnieje prosty sposób, aby zrobić to samo za pomocą Libgdx? A może ktoś może wskazać mi samouczek krok po kroku lub coś podobnego?

EDIT

zapomniałem powiedzieć, że szukam czegoś, co pozwoli mi zarządzać wersjami jak SQLiteOpenHelper. Innymi słowy, chcę odtworzyć moją bazę danych w systemie Android podczas instalacji apk, kiedy zmieniam wersję mojego DB na kodzie.

ROZWIĄZANIE

Po @42n4 odpowiedź, udało mi jak podłączyć do SQLite Database przy użyciu SQLiteOpenHelper na Android i JDBC na pulpicie aplikacji.

Najpierw stworzyłem "wspólną klasę" zarówno dla komputerów i Android Aplikacje:

//General class that needs to be implemented on Android and Desktop Applications 
public abstract class DataBase { 

    protected static String database_name="recycling_separation"; 
    protected static DataBase instance = null; 
    protected static int version=1; 

    //Runs a sql query like "create". 
    public abstract void execute(String sql); 

    //Identical to execute but returns the number of rows affected (useful for updates) 
    public abstract int executeUpdate(String sql); 

    //Runs a query and returns an Object with all the results of the query. [Result Interface is defined below] 
    public abstract Result query(String sql); 

    public void onCreate(){ 
     //Example of Highscore table code (You should change this for your own DB code creation) 
     execute("CREATE TABLE 'highscores' ('_id' INTEGER PRIMARY KEY NOT NULL , 'name' VARCHAR NOT NULL , 'score' INTEGER NOT NULL);"); 
     execute("INSERT INTO 'highscores'(name,score) values ('Cris',1234)"); 
     //Example of query to get DB data of Highscore table 
     Result q=query("SELECT * FROM 'highscores'"); 
     if (!q.isEmpty()){ 
      q.moveToNext(); 
      System.out.println("Highscore of "+q.getString(q.getColumnIndex("name"))+": "+q.getString(q.getColumnIndex("score"))); 
     } 
    } 

    public void onUpgrade(){ 
     //Example code (You should change this for your own DB code) 
     execute("DROP TABLE IF EXISTS 'highscores';"); 
     onCreate(); 
     System.out.println("DB Upgrade maded because I changed DataBase.version on code"); 
    } 

    //Interface to be implemented on both Android and Desktop Applications 
    public interface Result{ 
     public boolean isEmpty(); 
     public boolean moveToNext(); 
     public int getColumnIndex(String name); 
     public float getFloat(int columnIndex); 
     [...] 
    } 
} 

Potem stworzył DatabaseDesktop Class for Desktop Zastosowanie:

public class DatabaseDesktop extends DataBase{ 
    protected Connection db_connection; 
    protected Statement stmt; 
    protected boolean nodatabase=false; 

    public DatabaseDesktop() { 
     loadDatabase(); 
     if (isNewDatabase()){ 
      onCreate(); 
      upgradeVersion(); 
     } else if (isVersionDifferent()){ 
      onUpgrade(); 
      upgradeVersion(); 
     } 

    } 

    public void execute(String sql){ 
     try { 
      stmt.execute(sql); 
     } catch (SQLException e) { 
      e.printStackTrace(); 
     } 
    } 

    public int executeUpdate(String sql){ 
     try { 
      return stmt.executeUpdate(sql); 
     } catch (SQLException e) { 
      e.printStackTrace(); 
     } 
     return 0; 
    } 

    public Result query(String sql) { 
     try { 
      return new ResultDesktop(stmt.executeQuery(sql)); 
     } catch (SQLException e) { 
      e.printStackTrace(); 
     } 
     return null; 
    } 

    private void loadDatabase(){ 
     File file = new File (database_name+".db"); 
     if(!file.exists()) 
      nodatabase=true; 
     try { 
      Class.forName("org.sqlite.JDBC"); 
      db_connection = DriverManager.getConnection("jdbc:sqlite:"+database_name+".db"); 
      stmt = db_connection.createStatement(); 
     } catch (ClassNotFoundException e) { 
      e.printStackTrace(); 
     } catch (SQLException e) { 
      e.printStackTrace(); 
     } 
    } 

    private void upgradeVersion() { 
     execute("PRAGMA user_version="+version); 
    } 

    private boolean isNewDatabase() { 
     return nodatabase; 
    } 

    private boolean isVersionDifferent(){ 
     Result q=query("PRAGMA user_version"); 
     if (!q.isEmpty()) 
      return (q.getInt(1)!=version); 
     else 
      return true; 
    } 

    public class ResultDesktop implements Result{ 

     ResultSet res; 
     boolean called_is_empty=false; 

     public ResultDesktop(ResultSet res) { 
      this.res = res; 
     } 

     public boolean isEmpty() { 
      try { 
       if (res.getRow()==0){ 
        called_is_empty=true; 
        return !res.next(); 
       } 
       return res.getRow()==0; 
      } catch (SQLException e) { 
       e.printStackTrace(); 
      } 
      return false; 
     } 

     public boolean moveToNext() { 
      try { 
       if (called_is_empty){ 
        called_is_empty=false; 
        return true; 
       } else 
        return res.next(); 
      } catch (SQLException e) { 
       e.printStackTrace(); 
      } 
      return false; 
     } 

     public int getColumnIndex(String name) { 
      try { 
       return res.findColumn(name); 
      } catch (SQLException e) { 
       e.printStackTrace(); 
      } 
      return 0; 
     } 

     public float getFloat(int columnIndex) { 
      try { 
       return res.getFloat(columnIndex); 
      } catch (SQLException e) { 
       e.printStackTrace(); 
      } 
      return 0; 
     } 

     [...] 

    } 

} 

I DatabaseAndroid dla Androida Aplikacja

public class DatabaseAndroid extends DataBase{ 
    protected SQLiteOpenHelper db_connection; 
    protected SQLiteDatabase stmt; 

    public DatabaseAndroid(Context context) { 
     db_connection = new AndroidDB(context, database_name, null, version); 
     stmt=db_connection.getWritableDatabase(); 
    } 

    public void execute(String sql){ 
     stmt.execSQL(sql); 
    } 

    public int executeUpdate(String sql){ 
     stmt.execSQL(sql); 
     SQLiteStatement tmp = stmt.compileStatement("SELECT CHANGES()"); 
     return (int) tmp.simpleQueryForLong(); 
    } 

    public Result query(String sql) { 
     ResultAndroid result=new ResultAndroid(stmt.rawQuery(sql,null)); 
     return result; 
    } 

    class AndroidDB extends SQLiteOpenHelper { 

     public AndroidDB(Context context, String name, CursorFactory factory, 
       int version) { 
      super(context, name, factory, version); 
     } 

     public void onCreate(SQLiteDatabase db) { 
      stmt=db; 
      DatabaseAndroid.this.onCreate(); 
     } 

     public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 
      stmt=db; 
      DatabaseAndroid.this.onUpgrade(); 
     } 

    } 

    public class ResultAndroid implements Result{ 
     Cursor cursor; 

     public ResultAndroid(Cursor cursor) { 
      this.cursor=cursor; 
     } 

     public boolean isEmpty() { 
      return cursor.getCount()==0; 
     } 

     public int getColumnIndex(String name) { 
      return cursor.getColumnIndex(name); 
     } 

     public String[] getColumnNames() { 
      return cursor.getColumnNames(); 
     } 

     public float getFloat(int columnIndex) { 
      return cursor.getFloat(columnIndex); 
     } 

     [...] 

    } 

} 

Wreszcie, ja cha nged główne grupy Obie aplikacje Android i stacjonarnym:

public class Main extends AndroidApplication { 

    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     initialize(new MyGame(new DatabaseAndroid(this.getBaseContext())), false); 
    } 
} 

public class Main { 

    public static void main(String[] args) { 
     new LwjglApplication(new MyGame(new DatabaseDesktop()), "Example", MyGame.SCREEN_WIDTH, MyGame.SCREEN_HEIGHT,false); 
    } 

} 

zauważyć, że:

Zrobiłem zarządzania wersji jak ta, która dzieje się w SQLiteOpenHelper pomocą PRAGMA user_version. W ten sposób zmieniam wersję klasy DataBase, kiedy muszę ją zaktualizować.

Nie umieściłem wszystkich metod, które wykonałem na Result, ale umieszczam te, które moim zdaniem są ważniejsze. Są ważniejsze.

Odpowiedz

3

http://marakana.com/techtv/android_bootcamp_screencast_series.html klasa 4, część 1: Android Bootcamp - statusData dla libgdx: http://code.google.com/p/libgdx-users/wiki/SQLite

EDIT: należy wspomnieć o dwóch nowych kursów o libgdx gier w witrynie Udacity: https://github.com/udacity/ud405

https://github.com/udacity/ud406

+0

Tak więc, zarówno dla systemu Android, jak i pulpitu, tworzę klasę o nazwie "StatusData", prawda? W systemie Android mogę używać 'SQLiteOpenHelper', tak jak poprzednio. Ale co z aplikacją Desktop? W jaki sposób mogę, na przykład, spowodować, że aplikacja Desktop odtwarza DB, gdy wersja DB zmienia się na "StatusData"? –

+0

Może to pomoże: http://code.google.com/p/libgdx-users/wiki/SQLite – 42n4

+0

Więc, dla jasności, mogę użyć 'SQLiteOpenHelper' na Androidzie i na Pulpicie mogę zrobić to samo rzecz używająca 'JDBC' i obie są tworzone na klasie o nazwie' StatusData' lub coś podobnego. Dobrze? –

6

Istnieje rozszerzenie (zwane gdx-sqlite), które napisałem, które wykona większość pracy, której potrzebujesz. Najnowszą wersję tego rozszerzenia można pobrać z here.Kod źródłowy i przeczytać mnie znajdują się pod adresem: https://github.com/mrafayaleem/gdx-sqlite

To rozszerzenie obsługuje obecnie platformy Android i Desktop. Ponadto nie ma obsługi otwierania baz danych znajdujących się w folderze zasobów aplikacji na Androida. Jest to jednak funkcja oczekująca i zostanie wkrótce dodana.

Postępuj zgodnie z instrukcjami w przeczytaniu mnie, aby skonfigurować swoje projekty do obsługi bazy danych. Poniżej znajduje się przykładowy kod:

package com.mrafayaleem.gdxsqlitetest; 

import com.badlogic.gdx.Gdx; 
import com.badlogic.gdx.sql.Database; 
import com.badlogic.gdx.sql.DatabaseCursor; 
import com.badlogic.gdx.sql.DatabaseFactory; 
import com.badlogic.gdx.sql.SQLiteGdxException; 

public class DatabaseTest { 

    Database dbHandler; 

    public static final String TABLE_COMMENTS = "comments"; 
    public static final String COLUMN_ID = "_id"; 
    public static final String COLUMN_COMMENT = "comment"; 

    private static final String DATABASE_NAME = "comments.db"; 
    private static final int DATABASE_VERSION = 1; 

    // Database creation sql statement 
    private static final String DATABASE_CREATE = "create table if not exists " 
      + TABLE_COMMENTS + "(" + COLUMN_ID 
      + " integer primary key autoincrement, " + COLUMN_COMMENT 
      + " text not null);"; 

    public DatabaseTest() { 
     Gdx.app.log("DatabaseTest", "creation started"); 
     dbHandler = DatabaseFactory.getNewDatabase(DATABASE_NAME, 
       DATABASE_VERSION, DATABASE_CREATE, null); 

     dbHandler.setupDatabase(); 
     try { 
      dbHandler.openOrCreateDatabase(); 
      dbHandler.execSQL(DATABASE_CREATE); 
     } catch (SQLiteGdxException e) { 
      e.printStackTrace(); 
     } 

     Gdx.app.log("DatabaseTest", "created successfully"); 

     try { 
      dbHandler 
        .execSQL("INSERT INTO comments ('comment') VALUES ('This is a test comment')"); 
     } catch (SQLiteGdxException e) { 
      e.printStackTrace(); 
     } 

     DatabaseCursor cursor = null; 

     try { 
      cursor = dbHandler.rawQuery("SELECT * FROM comments"); 
     } catch (SQLiteGdxException e) { 
      e.printStackTrace(); 
     } 
     while (cursor.next()) { 
      Gdx.app.log("FromDb", String.valueOf(cursor.getString(1))); 
     } 

     try { 
      dbHandler.closeDatabase(); 
     } catch (SQLiteGdxException e) { 
      e.printStackTrace(); 
     } 
     dbHandler = null; 
     Gdx.app.log("DatabaseTest", "dispose"); 
    } 
}