well i have read a lot of threads.
first, id ilke to say im studying ni and might be able to help, but i would like to ask first. is the problem of standalone apk resolved? if not i might have a look at it, i just compiled the ndk sources, and love looks like such a cool engine that i have been wanting to mess with.
just bare with me since i am veeeryyyyy rusty with jni and NDK =)
thanks!
help on standalone game
Re: help on standalone game
I don't think anyone has actually managed to get a stand alone apk yet. But it is theoretically possible. Maybe not in this version though.
My game called Hat Cat and the Obvious Crimes Against the Fundamental Laws of Physics is out now!
Re: help on standalone game
ok i compiled my version, unfortunately it doesnt run, im using android-ndk-r8b and android sdk 4.0.3(im having exactly this error)
http://stackoverflow.com/questions/1217 ... ad-library
well anyway ill outline my path so anyone who can compile can test if it works or not:
1)find apk path on java:
2)PHYSFS_AddToSearchPath(apkPath, 1);i think this is done on lua level, especifically on boot.lua right where it boots the game source.. so you should access the filesystem from there and add the apkpath
from there on its just a matter of loading the .love file (hopefullly)
for example, create a folder assets and put your .love file there lets game.love, step 2) should make it visible to physfs so yuo can replace the boot code to load game.love instead of the argument
http://stackoverflow.com/questions/1217 ... ad-library
well anyway ill outline my path so anyone who can compile can test if it works or not:
1)find apk path on java:
Code: Select all
String retrieveApkPath() {
String apkFilePath = null;
ApplicationInfo appInfo = null;
PackageManager packMgmr = getPackageManager();
try {
appInfo = packMgmr.getApplicationInfo(getPackageName(), 0);
} catch (NameNotFoundException e) {
e.printStackTrace();
throw new RuntimeException("Unable to locate assets, aborting...");
}
apkFilePath = appInfo.sourceDir;
return (apkFilePath);
}
from there on its just a matter of loading the .love file (hopefullly)
for example, create a folder assets and put your .love file there lets game.love, step 2) should make it visible to physfs so yuo can replace the boot code to load game.love instead of the argument
Re: help on standalone game
here is my progress so far
the problem is that its a zip inside another zip, and even worse, assets is a folder, so finding main.lua has been a hell for LOVE so far
------------------------------------------------------
meanwhile i found this hack that doenst require messing with NDK code, only java:
http://stackoverflow.com/questions/4447 ... -to-sdcard
the idea is to copy the .love game to assets folder then use that code to copy to sdcard and pass its location to JNI. the obvious fallback is that requires sdcard, also duplicates the game in memory..
Code: Select all
love.filesystem.addToSearchPath(apkDir); -- apkDir sent via Java code, i also added addToSearchPath to lua-glue code.
print(love.filesystem.exists("/assets/game.love")) -- works :D, if you have copied game.love to assets folder
------------------------------------------------------
meanwhile i found this hack that doenst require messing with NDK code, only java:
http://stackoverflow.com/questions/4447 ... -to-sdcard
the idea is to copy the .love game to assets folder then use that code to copy to sdcard and pass its location to JNI. the obvious fallback is that requires sdcard, also duplicates the game in memory..
Re: help on standalone game
It doesn't require a physical sd card though. Many phones without them still have the folder /mnt/sdcard for compatability. And Environment.getExternalStorageDirectory() should still work either way.
My game called Hat Cat and the Obvious Crimes Against the Fundamental Laws of Physics is out now!
Re: help on standalone game
yes, only older phones would have issues..
mine doesnt have any problem (galaxy s2).. but still pretty hacky isnt it?
mine doesnt have any problem (galaxy s2).. but still pretty hacky isnt it?
Re: help on standalone game
ok i have tested the "hack" and it works
DOWNLOAD: http://gjteam.com.br/love-native-android.apk
here are the files that I changed (i dont have git client here to make patches, if anyone knows a good client for windows..)
make sure you create a folder called "assets" inside the root of java project and copy your game to there, name it "game.love"
AndroidManifest.xml
LoveNative.java
DOWNLOAD: http://gjteam.com.br/love-native-android.apk
here are the files that I changed (i dont have git client here to make patches, if anyone knows a good client for windows..)
make sure you create a folder called "assets" inside the root of java project and copy your game to there, name it "game.love"
AndroidManifest.xml
Code: Select all
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="net.schattenkind.nativelove"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="8" />
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.DELETE_CACHE_FILES"/>
<uses-permission android:name="android.permission.READ_FRAME_BUFFER"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
<activity
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
android:label="@string/app_name"
android:name="LoveNative"
android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|fontScale">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
LoveNative.java
Code: Select all
package net.schattenkind.nativelove;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.LinkedList;
import android.app.Activity;
import android.content.res.AssetManager;
import android.content.res.Configuration;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.media.AudioManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import android.view.MotionEvent;
public class LoveNative extends Activity implements SensorEventListener {
/** Called when the activity is first created. */
private LoveRenderView mGLView;
private float mOldVolume = 1.f;
//TODO: Add
/*
* getSystemService(Context.SENSOR_SERVICE); and SensorManager
* getSystemService(Context.STORAGE_SERVICE); and all file stuff
* finish android_sensors in love.cpp (in real love)
* */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
copyAssets();
setVolumeControlStream(AudioManager.STREAM_MUSIC);
mSensorManager = (SensorManager)getSystemService(SENSOR_SERVICE);
mSensorList = new LinkedList<Sensor>();
String filePath = "/mnt/sdcard/game.love";
//setContentView(R.layout.main);
LoveJNI.setActivity(this);
mGLView = new LoveRenderView(this, filePath);
setContentView(mGLView);
//LoveJNI.step();
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event)
{
// hardware sound button handling
if (keyCode == KeyEvent.KEYCODE_MUTE)
{
LoveJNI.setDeviceAudioVolume(0f);
}
if (keyCode == KeyEvent.KEYCODE_VOLUME_UP)
{
LoveJNI.setDeviceAudioVolume(LoveJNI.getDeviceAudioVolume() + 0.1f);
}
if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN)
{
LoveJNI.setDeviceAudioVolume(LoveJNI.getDeviceAudioVolume() - 0.1f);
}
//Temporary fix for exiting the application
//TODO Remove this when implemented into Love.cpp instead
if (keyCode == KeyEvent.KEYCODE_BACK) {
return super.onKeyDown(keyCode, event);
}
if(LoveJNI.onKeyDown(keyCode))
return true;
return super.onKeyDown(keyCode, event);
}
@Override
public boolean onKeyUp(int keyCode, KeyEvent event)
{
//Temporary fix for exiting the application
//TODO Remove this when implemented into Love.cpp instead
if (keyCode == KeyEvent.KEYCODE_BACK) {
return super.onKeyUp(keyCode, event);
}
if(LoveJNI.onKeyUp(keyCode))
return true;
return super.onKeyUp(keyCode, event);
}
@Override
public boolean onTouchEvent(MotionEvent event)
{
boolean processed = false;
if(event.getAction() == MotionEvent.ACTION_DOWN)
{
LoveJNI.onMouseDown((int)event.getX(), (int)event.getY());
processed = true;
}
else if(event.getAction() == MotionEvent.ACTION_UP)
{
LoveJNI.onMouseUp((int)event.getX(), (int)event.getY());
processed = true;
}
else if (event.getAction() == MotionEvent.ACTION_MOVE)
{
LoveJNI.onMouseMove((int)event.getX(), (int)event.getY());
processed = true;
}
int count = event.getPointerCount();
if(count > 0)
{
int x[] = new int[count];
int y[] = new int[count];
for(int i = 0; i < count; ++i)
{
x[i] = (int)event.getX(i);
y[i] = (int)event.getY(i);
}
if(event.getAction() == MotionEvent.ACTION_DOWN)
{
if(Build.VERSION.SDK_INT >= 8)
LoveJNI.onTouchDown(count, event.getActionIndex(), x, y);
else
LoveJNI.onTouchDown(count, -1, x, y);
processed = true;
}
else if(event.getAction() == MotionEvent.ACTION_UP)
{
if(Build.VERSION.SDK_INT >= 8)
LoveJNI.onTouchUp(count, event.getActionIndex(), x, y);
else
LoveJNI.onTouchUp(count, -1, x, y);
processed = true;
}
else if (event.getAction() == MotionEvent.ACTION_MOVE)
{
if(Build.VERSION.SDK_INT >= 8)
LoveJNI.onTouchMove(count, event.getActionIndex(), x, y);
else
LoveJNI.onTouchMove(count, -1, x, y);
processed = true;
}
}
if(processed)
return true;
return super.onTouchEvent(event);
}
@Override
public void onBackPressed()
{
super.onBackPressed();
// LoveJNI.deinit();
mGLView.onPause();
}
@Override
public boolean onKeyLongPress(int keyCode, KeyEvent event)
{
// TODO Auto-generated method stub
return super.onKeyLongPress(keyCode, event);
}
// clean up love at onPause call - native memory is not protected afterwards
// we need a solution to store the game state at that moment
@Override
public void onPause()
{
//mGLView.onPause(); // TODO: FIX OpenGL cleanup
mGLView.stopRendering();
mOldVolume = LoveJNI.getDeviceAudioVolume();
LoveJNI.setDeviceAudioVolume(0.f);
mSensorManager.unregisterListener(this);
super.onPause();
}
@Override
protected void onResume() {
super.onResume();
mGLView.continueRendering();
LoveJNI.setDeviceAudioVolume(mOldVolume);
for(int i = 0; i < mSensorList.size(); ++i)
mSensorManager.registerListener(this, mSensorList.get(i), SensorManager.SENSOR_DELAY_GAME);
//mGLView.onResume(); // TODO: FIX OpenGL cleanup
}
@Override
public void onConfigurationChanged(Configuration newConfig)
{
super.onConfigurationChanged(newConfig);
}
@Override
public void onDestroy()
{
Log.i("LoveNative", "onDestroy");
LoveJNI.deinit();
super.onDestroy();
}
private int strToSensor(String name)
{
if(name.equals("TYPE_ACCELEROMETER"))
return Sensor.TYPE_ACCELEROMETER;
else if(name.equals("TYPE_ALL"))
return Sensor.TYPE_ALL;
else if(Build.VERSION.SDK_INT >= 14 && name.equals("TYPE_AMBIENT_TEMPERATURE "))
return 0xd; //Sensor.TYPE_AMBIENT_TEMPERATURE
else if(Build.VERSION.SDK_INT >= 9 && name.equals("TYPE_GRAVITY"))
return 0x9; //Sensor.TYPE_GRAVITY
else if(name.equals("TYPE_GYROSCOPE"))
return Sensor.TYPE_GYROSCOPE;
else if(name.equals("TYPE_LIGHT"))
return Sensor.TYPE_LIGHT;
else if(Build.VERSION.SDK_INT >= 9 && name.equals("TYPE_LINEAR_ACCELERATION"))
return 0xa; //Sensor.TYPE_LINEAR_ACCELERATION
else if(name.equals("TYPE_MAGNETIC_FIELD"))
return Sensor.TYPE_MAGNETIC_FIELD;
else if(name.equals("TYPE_ORIENTATION"))
return Sensor.TYPE_ORIENTATION;
else if(name.equals("TYPE_PRESSURE"))
return Sensor.TYPE_PRESSURE;
else if(name.equals("TYPE_PROXIMITY"))
return Sensor.TYPE_PROXIMITY;
else if(Build.VERSION.SDK_INT >= 14 && name.equals("TYPE_RELATIVE_HUMIDITY"))
return 0xc; //Sensor.TYPE_RELATIVE_HUMIDITY
else if(Build.VERSION.SDK_INT >= 9 && name.equals(" TYPE_ROTATION_VECTOR"))
return 0xb; //Sensor.TYPE_ROTATION_VECTOR
else if(name.equals("TYPE_TEMPERATURE"))
return Sensor.TYPE_TEMPERATURE ;
else
return Sensor.TYPE_ALL;
}
private String SensorToStr(int type)
{
switch(type)
{
case Sensor.TYPE_ACCELEROMETER:
return "TYPE_ACCELEROMETER";
case Sensor.TYPE_ALL:
return "TYPE_ALL";
case 0xd:
return "TYPE_AMBIENT_TEMPERATURE";
case 0x9:
return "TYPE_GRAVITY";
case Sensor.TYPE_GYROSCOPE:
return "TYPE_GYROSCOPE";
case Sensor.TYPE_LIGHT:
return "TYPE_LIGHT";
case 0xa:
return "TYPE_LINEAR_ACCELERATION";
case Sensor.TYPE_MAGNETIC_FIELD:
return "TYPE_MAGNETIC_FIELD";
case Sensor.TYPE_ORIENTATION:
return "TYPE_ORIENTATION";
case Sensor.TYPE_PRESSURE:
return "TYPE_PRESSURE";
case Sensor.TYPE_PROXIMITY:
return "TYPE_PROXIMITY";
case 0xc:
return "TYPE_RELATIVE_HUMIDITY";
case 0xb:
return "TYPE_ROTATION_VECTOR";
case Sensor.TYPE_TEMPERATURE:
return "TYPE_TEMPERATURE";
default:
return "UNKNOWN";
}
}
private SensorManager mSensorManager;
private LinkedList<Sensor> mSensorList;
public void disableSensor(String name)
{
int type = strToSensor(name);
Sensor sensor = mSensorManager.getDefaultSensor(type);
mSensorManager.unregisterListener(this, sensor);
mSensorList.remove(sensor);
}
public void enableSensor(String name)
{
int type = strToSensor(name);
Sensor sensor = mSensorManager.getDefaultSensor(type);
mSensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_GAME);
mSensorList.add(sensor);
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy)
{
// should not happen...
// TODO: check if it does not happen :D
}
@Override
public void onSensorChanged(SensorEvent event)
{
LoveJNI.onSensorChanged(event.sensor.getName(), SensorToStr(event.sensor.getType()), event.values);
}
private void copyAssets() {
AssetManager assetManager = getAssets();
String[] files = null;
try {
files = assetManager.list("");
} catch (IOException e) {
Log.e("tag", "Failed to get asset file list.", e);
}
for(String filename : files) {
InputStream in = null;
OutputStream out = null;
try {
in = assetManager.open(filename);
out = new FileOutputStream("/sdcard/" + filename);
copyFile(in, out);
in.close();
in = null;
out.flush();
out.close();
out = null;
} catch(IOException e) {
Log.e("tag", "Failed to copy asset file: " + filename, e);
}
}
}
private void copyFile(InputStream in, OutputStream out) throws IOException {
byte[] buffer = new byte[1024];
int read;
while((read = in.read(buffer)) != -1){
out.write(buffer, 0, read);
}
}
// @Override
// public void onStop()
// {
// android.os.Process.killProcess(android.os.Process.myPid());
// }
}
Re: help on standalone game
Dude, you're awesome!
Sorry, English isn't my native language, but I wanted to ask if I understood correctly.
You got it working, so a stand alone *.apk of your game would be playable on the phone, without "Browse for game" before?
If so, may I ask for a little little tutorial on how to do that? Because I get errors when changing the LoveNative.java.
Sorry, English isn't my native language, but I wanted to ask if I understood correctly.
You got it working, so a stand alone *.apk of your game would be playable on the phone, without "Browse for game" before?
If so, may I ask for a little little tutorial on how to do that? Because I get errors when changing the LoveNative.java.
"Docendo discimus" - Lucius Annaeus Seneca
Re: help on standalone game
Petunien wrote:Dude, you're awesome!
Sorry, English isn't my native language, but I wanted to ask if I understood correctly.
You got it working, so a stand alone *.apk of your game would be playable on the phone, without "Browse for game" before?
If so, may I ask for a little little tutorial on how to do that? Because I get errors when changing the LoveNative.java.
hey man! thanks!
exacty thats the idea, if you wanna check just download the apk
whats the erros you get?
Re: help on standalone game
Also you could test just replacing the .love file file by your game in my APK (in the other post)
of course the apk is signed by me, so it might not be interesting for sellin purposes, just for tests. you should want package yourself with the changes provided
of course the apk is signed by me, so it might not be interesting for sellin purposes, just for tests. you should want package yourself with the changes provided
Who is online
Users browsing this forum: No registered users and 1 guest