如何在LibGDX中实现Sugar ORM
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何在LibGDX中实现Sugar ORM相关的知识,希望对你有一定的参考价值。
我们是一群法国学生。我们正在开发一种需要数据库的游戏。为简化代码,我们使用LibGdx。但是,似乎Sugar ORM不受应用程序的约束。我们无法扩展SugarRecord。
我把androidManifest.xml的代码和build.gradle(Module:Android)放在一起。我们如何解决这个问题呢?
编辑:我们在Android文件夹中创建我们的类。 Sugar Orm没有在核心中定义。
<application
android:name="com.orm.SugarApp"
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/GdxTheme">
<meta-data
android:name="DATABASE"
android:value="AppName.db" />
<meta-data
android:name="VERSION"
android:value="1" />
<meta-data
android:name="QUERY_LOG"
android:value="true" />
<meta-data
android:name="DOMAIN_PACKAGE_NAME"
android:value="com.AppName" />
build.gradle(模块:Android):
dependencies {
compile 'com.github.satyan:sugar:1.3'
//other dependencies
}
谢谢!
你好!我将做一些假设(纠正我,如果他们错了,我们将改进下面的答案):
- 问题是你正在尝试扩展
SugarRecord<T>
,你的编译器/ IDE无法看到该类。 - 你试图扩展
SugarRecord<T>
的班级位于core/src/...
,而不是android/src/...
What is the problem?
当你编写软件时(如果它是游戏无关紧要),你需要注意如何将软件划分为多个部分以及这些部分如何交互。特别是,您希望能够知道一个部件的更改何时会破坏另一个部件。
libGDX将其代码分成基于平台的部分(这就是为什么你有一个核心项目和一个桌面项目和一个android项目)。核心应该具有与平台无关的所有代码(即,无论您是在PC还是移动设备上都是相同的东西),而您的其他项目会处理特定于平台的内容。
Sugar ORM是一个特定于android的东西,所以你(正确地)把它放到你的android gradle项目依赖项中。但是,这意味着只有android/src
文件夹下的代码才知道Sugar ORM并且可以使用它。我很确定这是导致你的问题的原因。问题是,你要保存的类几乎肯定是在core/src
下,它们属于那里,所以我们如何解决它?
The Easy Way to Fix
如果您只打算让您的程序在Android上运行(并且您的项目有一个紧迫的截止日期:wink :),您可以将依赖项从Android gradle项目移动到Core gradle项目。这将允许您在任何地方使用这些类,但是当您尝试构建Desktop / ios / html项目时,这将意味着麻烦。
The Right Way to Fix
如果你想以正确的方式解决它(并且可能会用你疯狂的编码能力给你的教授留下深刻的印象),你需要使用一种叫做依赖注入的东西。依赖注入是指我们采用代码所需的东西,并在运行时将它提供给代码。这意味着我们可以动态决定是否通过Android数据库或iOS数据库。就像@ Arctic45在评论中所说,libGDX Wiki简要介绍了这种技术,但我们将详细介绍一下。
对于这个例子,我将假设一个简单的游戏与Monster
类看起来像这样:
// Lives in core
public class Monster {
public String name; // prénom
public int hitpoints; // points de dommage
public Monster() {
this.name = "Tim the Unnamed";
this.hitpoints = 1;
}
public Monster(String name, int hitpoints) {
this.name = name;
this.hitpoints = hitpoints;
}
@Override
public String toString() {
return String.format("{name: '%s', hitpoints: %n}", this.name, this.hitpoints);
}
public void attack(Monster other) {
// Game specific logic...
}
}
现在我们希望能够将其保存到数据库中,但我们不知道它是Android数据库还是iOS数据库,甚至可能是某个地方(如Firebase)的数据库。我们如何处理?
我们所做的是为核心提供DatabaseWrapper
界面。这个接口提供了我们需要的方法,但不包括它们的实现方式 - 它就像一个承诺。核心可以计划使用这些方法,然后我们将在我们知道我们所处的平台后提供它们。下面是一个示例应用程序,它说明了这种技术:
// Lives in core
// Replace with your application
public class LibGDXTestbed extends ApplicationAdapter {
DatabaseWrapper database;
public LibGDXTestbed() { } // For platforms that don't have databases to inject.
public LibGDXTestbed(DatabaseWrapper database) {
this.database = database;
}
/**
* For demo purposes, add a new randomized monster to the database, then log a list of all the
* monsters created to date.
*/
@Override
public void create () {
if(database != null) {
createMonster();
printMonsters();
} else {
Gdx.app.error("WARNING", "No database provided. Load/Save Functionality Disabled.");
}
}
// Helper method
private void createMonster() {
// Create a set of names we can use for new monsters.
String[] names = {"Fred", "Mary", "Jean", "Tim"};
String randomName = new Array<String>(names).random();
int randomHP = MathUtils.random(100);
database.saveMonster(new Monster(randomName, randomHP));
}
// Helper method
private void printMonsters() {
for(Monster monster : database.getMonsters()) {
Gdx.app.log("DEBUG", monster.toString());
}
}
}
请注意,上述内容对Sugar ORM一无所知或对数据库的工作方式做出任何假设。
包装器本身看起来像这样:
// Located in core
public interface DatabaseWrapper {
public void saveMonster(Monster monster);
public List<Monster> getMonsters();
}
现在这有点人为(并且可以重构为更通用),但它说明了这一点。
接下来,我们创建实现此数据库所需的特定于android的代码。首先,我们将创建一个SugarMonster
类,它扩展了SugarRecord
(因为我们不希望用我们的核心Monster
类本身这样做):
// Lives in android/src
public class SugarMonster extends SugarRecord<SugarMonster> {
public String name; // prénom
public int hitpoints; // points de dommage
public SugarMonster() {
}
public SugarMonster(Monster monster) {
this.name = monster.name;
this.hitpoints = monster.hitpoints;
}
}
我们还需要一个SugarWrapper
类,它在幕后使用Sugar ORM实现我们的DatabaseWrapper
类:
// Lives in android/src
public class SugarWrapper implements DatabaseWrapper {
@Override
public void saveMonster(Monster monster) {
SugarMonster data = new SugarMonster(monster);
data.save();
}
@Override
public List<Monster> getMonsters() {
List<SugarMonster> records = SugarMonster.listAll(SugarMonster.class);
ArrayList<Monster> monsters = new ArrayList<>();
for(SugarMonster record : records) {
monsters.add(new Monster(record.name, record.hitpoints));
}
return monsters;
}
}
最后,我们需要更新我们的AndroidLauncher
类来注入我们的数据库包装器:
// Lives in android/src
public class AndroidLauncher extends AndroidApplication {
@Override
protected void onCreate (Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
AndroidApplicationConfiguration config = new AndroidApplicationConfiguration();
initialize(new LibGDXTestbed(new SugarWrapper()), config);
}
}
Bonus
另一个很酷的事情是,如果你以“正确”的方式实现这一点,它可以为测试提供一些很酷的可能性。如果要根据代码编写单元测试,可以创建一个TestWrapper
,它实现DatabaseWrapper
并使用静态数据模拟数据库功能:
public class TestWrapper implements DatabaseWrapper {
List<Monster> monsters;
public TestWrapper() {
this.monsters = new ArrayList<>();
this.monsters.add(new Monster("Tim the Tester", 123));
}
@Override
public void saveMonster(Monster monster) {
this.monsters.add(monster);
}
@Override
public List<Monster> getMonsters() {
return this.monsters;
}
}
以上是关于如何在LibGDX中实现Sugar ORM的主要内容,如果未能解决你的问题,请参考以下文章