Alejandro Santiago wrote:
Hey guys,
>
I know that this thread is a bit old… but is there any news on this subject? I have my Ouya and I would like to port one game also to this platform.
>
Thanks
Your game/app will likely run just fine after you follow downloading and preparing your android build in Eclipse from the ODK instructions. I believe you will need to add ouya-sdk.jar to the lib folder in order for it to work.
After you get the game to load and running you’ll have to then add support for the new interface. Controller buttons map to keys. But if you’re not using standard Android UI for your menus you’ll have to write code to handle pressing up/down/left/right to move from button to button and selecting the buttons. This is where the work porting to OUYA will be mostly focused. In-App purchases and a few other things will also be involved, including keeping game inside the safe area for the various TV size/resolutions.
See: https://devs.ouya.tv/developers/docs/controllers
I believe initial keyboard support is in the develop branch of cocos2d-x, but now that’s been hijacked for v3.x. I’m not sure how easy it would be to cherry pick the desired functionality, but I’d guess you’d just need to look in CCKeyboardDispatcher/CCKeyboardDelegate/CCEventDispatcher for the various platforms you need to support, copy the correct code to detect the platform key up/down and for example Android you’ll have to make sure the code passes through the JNI layer correctly, so there will likely be a little extra work for OUYA/Android.
So, here’s what I did for simple controller integration for testing I worked on today. Code could be improved, some stuff probably unnecessary, no error checking, etc. YMMV.
Changes to the engine:
cocos2dx/keypad_dispatcher/CCKeypadDelegate.h (46)
// The menu key clicked. only available on wophone & android
virtual void keypadDown(int keyCode) {};
cocos2dx/keypad_dispatcher/CCKeypadDispatcher.h (80)
/**
@brief dispatch the keydown event
*/
bool dispatchKeypadDown(int keyCode);
cocos2dx/keypad_dispatcher/CCKeypadDispatcher.cpp (175)
bool CCKeypadDispatcher::dispatchKeypadDown(int keyCode)
{
CCKeypadHandler* pHandler = NULL;
CCKeypadDelegate* pDelegate = NULL;
m_bLocked = true;
if (m_pDelegates->count() > 0)
{
CCObject* pObj = NULL;
CCARRAY_FOREACH(m_pDelegates, pObj)
{
CC_BREAK_IF(!pObj);
pHandler = (CCKeypadHandler*)pObj;
pDelegate = pHandler->getDelegate();
pDelegate->keypadDown(keyCode);
}
}
m_bLocked = false;
if (m_bToRemove)
{
m_bToRemove = false;
for (unsigned int i = 0; i < m_pHandlersToRemove->num; ++i)
{
forceRemoveDelegate((CCKeypadDelegate*)m_pHandlersToRemove->arr[i]);
}
ccCArrayRemoveAllValues(m_pHandlersToRemove);
}
if (m_bToAdd)
{
m_bToAdd = false;
for (unsigned int i = 0; i < m_pHandlersToAdd->num; ++i)
{
forceAddDelegate((CCKeypadDelegate*)m_pHandlersToAdd->arr[i]);
}
ccCArrayRemoveAllValues(m_pHandlersToAdd);
}
return true;
}
cocos2dx/layers_scenes_transitions_nodes/CCLayer.h (147)
virtual void keypadDown(int);
cocos2dx/layers_scenes_transitions_nodes/CCLayer.cpp (330)
void CCLayer::keypadDown(int)
{
}
cocos2dx/platform/android/jni/TouchesJni.cpp (85)
default:
if (pDirector->getKeypadDispatcher()->dispatchKeypadDown(keyCode))
return JNI_TRUE;
return JNI_FALSE;
If you have subclassed Cocos2dxGLSurfaceView in Java then you will probably want to override the keydown in your activity and might need access to the render to call the native methods.
cocos2dx/platform/android/java/src/org/cocos2dx/lib/Cocos2dxGLSurfaceView.java (58)
public Cocos2dxRenderer mCocos2dxRenderer;
Code in game project:
GAME_ACTIVITY_CLASS_NAME.java
import org.cocos2dx.lib.Cocos2dxActivity;
import org.cocos2dx.lib.Cocos2dxGLSurfaceView;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import android.view.MotionEvent;
import tv.ouya.console.api.OuyaController;
public class _GAME_ACTIVITY_CLASS_NAME_ extends Cocos2dxActivity {
private static final String TAG = _GAME_ACTIVITY_CLASS_NAME_.class.getSimpleName();
public Cocos2dxGLSurfaceView mGLView;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
OuyaController.init(this);
}
public Cocos2dxGLSurfaceView onCreateView() {
mGLView = new GameSurfaceView(this);
// should create stencil buffer
mGLView.setEGLConfigChooser(5, 6, 5, 0, 16, 8);
return mGLView;
}
@Override
public boolean onKeyDown(final int keyCode, KeyEvent event) {
boolean handled = false;
Log.d(TAG, "keycode = " + keyCode);
handled = OuyaController.onKeyDown(keyCode, event);
Log.d(TAG, "device id = " + event.getDeviceId());
if (keyCode == OuyaController.BUTTON_MENU) {
AlertDialog ad = new AlertDialog.Builder(this)
.setTitle("EXIT?")
.setMessage("Do you really want to exit?")
.setPositiveButton("YES",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
android.os.Process.killProcess(android.os.Process.myPid());
//myActivity.finish();
}
})
.setNegativeButton("NO",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
}
}).create();
ad.show();
}
Log.d(TAG, "try to send key " + keyCode + " to native");
this.mGLView.queueEvent(new Runnable() {
@Override
public void run() {
Log.d(TAG, "sending key " + keyCode + " down to native");
_GAME_ACTIVITY_CLASS_NAME_.this.mGLView.mCocos2dxRenderer.handleKeyDown(keyCode);
}
});
return handled || super.onKeyDown(keyCode, event);
}
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
boolean handled = false;
handled = OuyaController.onKeyUp(keyCode, event);
return handled || super.onKeyUp(keyCode, event);
}
//@Override
public boolean onGenericMotionEvent(MotionEvent event) {
boolean handled = false;
handled = OuyaController.onGenericMotionEvent(event);
OuyaController c = OuyaController.getControllerByDeviceId(event.getDeviceId());
if (c != null) {
//Log.d(TAG, "x = " + c.getAxisValue(OuyaController.AXIS_LS_X));
//Log.d(TAG, "y = " + c.getAxisValue(OuyaController.AXIS_LS_Y));
}
return handled;// || super.onGenericMotionEvent(event);
}
static {
System.loadLibrary("game");
}
}
class GameSurfaceView extends Cocos2dxGLSurfaceView {
private _GAME_ACTIVITY_CLASS_NAME_ myActivity;
public GameSurfaceView(Context context) {
super(context);
myActivity = (_GAME_ACTIVITY_CLASS_NAME_)context;
}
}
Finally integrate the keypad handling in your game code:
Declare the delegate methods in the header file.
// key pad
virtual void keyBackClicked();
virtual void keyMenuClicked();
virtual void keypadDown(int keyCode);
Define the methods in your class file
void CLASS_NAME::keyBackClicked()
{
CCLOG("back key pressed");
}
void CLASS_NAME::keyMenuClicked()
{
CCLOG("menu key pressed");
}
void CLASS_NAME::keypadDown(int keyCode)
{
CCLOG("[CLASS_NAME] Key with keycode %d pressed", keyCode);
static const int OUYA_KEY_O = 96;
static const int OUYA_KEY_U = 99;
static const int OUYA_KEY_Y = 100;
static const int OUYA_KEY_A = 97;
switch(keyCode)
{
case OUYA_KEY_O:
this->newGame(nullptr);
break;
case OUYA_KEY_U:
this->resumeGame(nullptr);
break;
default:
// etc
break;
}
}
Declare that you want to handle keypad events
void CLASS_NAME::init()
{
if ( !CCNode::init() )
{
return false;
}
setKeypadEnabled(true);
// more code here
}