以下内容来自我制作的project on github,其中包含所有代码和信息。
纸飞机
这是一个简单的应用程序,可以在不使用 Eclipse 或 Ant 构建项目的情况下测试 libgdx 开发。主要关注点是将 libgdx 与我的无 Ant、仅命令行的开发环境集成。
过程
我将经历一个简单的项目,从开始到获得一个可运行的构建,它将结合我收集的知识,研究如何在不使用 Ant 或 Eclipse 的情况下设置 libgdx 项目。事后看来,一般过程是直截了当的,但我写这篇文章是因为我很难在网上找到答案,特别是针对 android 版本。
出于本指南的目的,项目名称将是 PaperPlanes,因为它比键入“TestGameLibGdx”更好。项目代码将包括将加载的纹理移动到单击/触摸点。该应用程序本身在很大程度上无关紧要,只是为某人省去了寻找一些代码来测试我使用的步骤的步骤。
我假设环境已经设置为使用 Ant 或 Eclipse 构建和部署 android 应用程序。目前您还需要 java 1.6,因为使用 1.7 和为 android 编译似乎存在一些问题。
制作目录结构
首先是在使用 libgdx 时像往常一样为不同的目标创建文件夹。稍后我们将单独处理每个文件夹。我没有 iOS 或 HTML5 目标的目录,因为我还没有尝试构建它们。
mkdir -v PaperPlanes
cd PaperPlanes
mkdir -v main desktop android assets
设置主目录
这是大部分代码的去向。
cd main
mkdir -pv libs src/com/jeff/paperplanes
设置桌面目录
非常简单,与 main 相同,但有一个 bin 目录。
cd desktop
mkdir -pv bin/classes libs src/com/jeff/bucket
设置安卓目录
我们将使用android 工具生成的骨架项目构建android 目录。或者,您可以按照源代码部分中提供的guide 自己创建目录结构。请注意 --target 和 --path 标志,因为它们特定于您的设置。
cd android
android create project --target 1 --name PaperPlanes --path /home/jeff/playground/PaperPlanes/android --activity PaperPlanesActivity --package com.jeff.paperplanes
mkdir -pv bin/classes bin/lib
删除我们不需要的文件。我删除了 progaurd 文件,因为这个项目不需要它。
rm build.xml local.properties project.properties ant.properties proguard-project.txt
获取 libgdx 库文件
每晚下载 libgdx 并将所需的库放在相关目录中。下面的 sn-p 是我更新库的方式。
LIBGDX_ZIP="libgdx-nightly-latest.zip"
wget http://libgdx.badlogicgames.com/nightlies/$LIBGDX_ZIP
unzip -o $LIBGDX_ZIP gdx.jar gdx-natives.jar gdx-backend-android.jar gdx-backend-lwjgl.jar gdx-backend-lwjgl-natives.jar extensions/gdx-tools.jar 'armeabi/*' 'armeabi-v7a/*'
rm -v $LIBGDX_ZIP
mv -v gdx.jar main/libs/
cp -Rv extensions main/libs
mv -v gdx-natives.jar gdx-backend-lwjgl.jar gdx-backend-lwjgl-natives.jar desktop/libs/
mv -v gdx-backend-android.jar android/libs/
cp -Rv armeabi-v7a armeabi android/libs/
rm -rf extensions armeabi armeabi-v7a
安装时 apk 需要包含 areabi* 目录。因此,在bin/lib 目录中创建一些指向这些文件夹的链接。您也可以只复制实际文件夹,但 libs 进入 libs 目录该死!
cd android/bin/lib
ln -s ../../libs/armeabi
ln -s ../../libs/armeabi-v7a
获取一些资产
与 Android 应用程序共享时,资产很奇怪。
桌面应用程序从应用程序的根目录开始查找资产,因此您可以像这样引用资产:
Gdx.files.internal( "assets/plane.png" )
但是,Android 应用程序会从 assets 目录开始查找资产。因此,上面的代码会导致它在文件夹ROOT/assets/assets/plane.png 中查找文件。
所以我们可以将所有资产分散在根目录中,也可以在ROOT/android/bin/assets/ 中创建指向ROOT/assets 文件夹的链接。它看起来很愚蠢,但使资产引用在整个平台上保持一致。
我确信有更好的方法可以做到这一点,但它确实有效。
无论如何,这个应用程序只使用一种名为assets/plane.png 的纹理。
写一些代码
您可以在 libgdx 存储库中找到大量示例。下面我将在编写本指南时转储我用来测试本指南的代码。
main/src/.../PaperPlanesGame.java
package com.jeff.paperplanes;
import com.badlogic.gdx.Game;
public class PaperPlanesGame extends Game {
private MainScreen ms;
@Override
public void create() {
ms = new MainScreen( this );
this.setScreen( ms );
}
}
main/src/.../MainScreen.java
package com.jeff.paperplanes;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.GL10;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.Screen;
public class MainScreen implements Screen {
PaperPlanesGame g;
Texture planeImage;
Rectangle planeRect;
SpriteBatch spb;
Vector3 touchPos;
OrthographicCamera cam;
public MainScreen( PaperPlanesGame g ) {
this.g = g;
// load assets
planeImage = new Texture( Gdx.files.internal( "assets/plane.png" ) );
// initialize rectangle
planeRect = new Rectangle();
// initialize spritebatch for drawing
spb = new SpriteBatch();
// initialize our camera
cam = new OrthographicCamera();
cam.setToOrtho( false, Gdx.graphics.getWidth(), Gdx.graphics.getHeight() );
cam.update( true );
// touch location
touchPos = new Vector3();
}
@Override
public void show() {
}
@Override
public void render( float delta ) {
// clear screen
Gdx.gl.glClear( GL10.GL_COLOR_BUFFER_BIT );
// update camera
cam.update();
// begin draw
spb.setProjectionMatrix( cam.combined );
spb.begin();
// move our plane and center it
spb.draw( planeImage, planeRect.x - ( planeImage.getWidth() / 2 ) , planeRect.y - ( planeImage.getHeight() / 2 ) );
//spb.draw( planeImage, planeRect.x, planeRect.y );
spb.end();
// update touch position
if( Gdx.input.isTouched() ) {
touchPos.set( Gdx.input.getX(), Gdx.input.getY(), 0 );
// only unproject if screen is touched duh!
cam.unproject( touchPos );
// converts the coord system of the touch units ( origin top left ) to camera coord ( origin bottom left )
planeRect.x = touchPos.x;
planeRect.y = touchPos.y;
}
Gdx.app.log( "X + Y", planeRect.x + " + " + planeRect.y );
}
@Override
public void resize( int width, int height ) {
}
@Override
public void hide() {
}
@Override
public void pause() {
}
@Override
public void resume() {
}
@Override
public void dispose() {
}
}
android/src/.../PaperPlanesActivity.java
package com.jeff.paperplanes;
import android.app.Activity;
import android.os.Bundle;
import com.badlogic.gdx.backends.android.AndroidApplication;
import com.badlogic.gdx.backends.android.AndroidApplicationConfiguration;
public class PaperPlanesActivity extends AndroidApplication {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
AndroidApplicationConfiguration cf = new AndroidApplicationConfiguration();
cf.useGL20 = true;
cf.useAccelerometer = true;
cf.useCompass = false;
initialize( new PaperPlanesGame(), cf );
}
}
desktop/src/.../PaperPlanesDesktop.java
package com.jeff.paperplanes;
import com.badlogic.gdx.backends.lwjgl.LwjglApplication;
import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration;
public class PaperPlanesDesktop {
public static void main( String[] args ) {
LwjglApplicationConfiguration cf = new LwjglApplicationConfiguration();
cf.title = "PaperPlanes";
cf.useGL20 = true;
cf.width = 800;
cf.height = 480;
new LwjglApplication( new PaperPlanesGame(), cf );
}
}
记住在处理android目标时要查看AndroidManifest.xml。
为桌面编译
这很简单。我们正在从ROOT 目录运行编译命令。
# Compile
javac -verbose -classpath "desktop/libs/*:main/libs/*:desktop/bin/classes" -sourcepath desktop/src/com/jeff/paperplanes:main/src/com/jeff/paperplanes -d desktop/bin/classes desktop/src/com/jeff/paperplanes/*.java main/src/com/jeff/paperplanes/*.java
# Run
java -classpath "desktop/libs/*:main/libs/*:desktop/bin/classes" com.jeff.paperplanes.PaperPlanesDesktop
编译安卓
比桌面复杂一点。我很大程度上抄袭了this guy 所做的工作。该指南非常有用,值得一读,以了解我将在下面执行的每个步骤。
我们正在从android 目录运行命令。
首先我们制作 R.java,我并没有真正使用其中的任何资产,因为这超过了跨平台点,但似乎我无法在运行时不出错的情况下删除它。
aapt package -v -f -m -M AndroidManifest.xml -I /opt/android-sdk/platforms/android-10/android.jar -S res -J src/
现在我们编译我们的源文件。请注意 -classpath 确保它与您的库所在的位置一致。
javac -verbose -d bin/classes -classpath "bin/classes:/opt/android-sdk/platforms/android-10/android.jar:bin/lib/*:../main/libs/*:libs/*" -target 1.6 `find ./src -iname "*.java"` `find ../main/src -iname "*.java"`
然后制作 Dalvik 字节码。包含代码中用到的所有库文件。
dx --dex --output bin/classes.dex bin/classes libs/gdx-backend-android.jar ../main/libs/gdx.jar
我们在这里创建未签名的 apk 文件。
aapt package -v -f -M AndroidManifest.xml -S res -I /opt/android-sdk/platforms/android-10/android.jar -F bin/paperplanes.unsigned.apk bin/
然后我们用密钥签名。
jarsigner -verbose -keystore debugkey.keystore -storepass debug123 -keypass debug123 -signedjar bin/paperplanes.signed.apk bin/paperplanes.unsigned.apk debugkey
如果您没有密钥,您可以生成一个。以下是制作方法(取自the guide I've mentioned far too often):
JAVA_HOME/bin/keytool
-genkeypair
-validity 10000
-dname "CN=company name,
OU=organisational unit,
O=organisation,
L=location,
S=state,
C=country code"
-keystore DEV_HOME/AndroidTest.keystore
-storepass password
-keypass password
-alias AndroidTestKey
-keyalg RSA
-v
最后我们运行 zipalign 并将其安装到设备上。
zipalign -v -f 4 bin/paperplanes.signed.apk bin/paperplanes.apk
# First time install
adb -d install bin/paperplanes.apk
# Reinstall
adb -d install -r bin/paperplanes.apk
来源
Building Android programs on the command line
An answer from SO that set me off
LibGDX github page
PaperPlanes (this project) github page
LibGDX API
LibGDX tutorial referenced when making the app
Another LibGDX tutorial referenced when making the app