Android PC用ゲームコントローラー

みなさんこんにちは! この記事では、通常のPC、つまりステアリングホイール用のAdndroidスマートフォンからゲームコントローラー(一般の人々-ジョイスティック)を作成する方法について説明します。



タスクの説明



ステアリング動作は、加速度計を使用してエミュレートされます。 これを行うために、空間座標の連続スキャンが実行され、運動の各方向に対して経験的に選択された境界が選択されます。 このデータに基づいて、ゲームキーの組み合わせがリアルタイムで生成されます。 例:W-前方、WA-前方および左など。



このデータをPCに配信するには、受信コマンドを受け入れ、対応するキーストロークをエミュレートするサーバーが実行されている必要があります。 サーバーは、1つのスマートフォンのみが接続されるようにシングルスレッドにすることができます。 接続はWi-Fi経由になります。



そして今、最も興味深い...



サーバー



サーバーは、WindowsのC ++で実装されます。 その主なタスクは、着信メッセージを継続的に受信し、キーを押すことです。 以下は、このタスクの基本的でシンプルなコードです。



Copy Source | Copy HTML while ( true ) { std::cout << "Wait for connection...\n" ; try { socket = server.Accept(); } catch ( const char *error ) { std::cout << error << std:: endl ; exit( 0 ); } bool keepAlive = true; int timeout = 10000 ; setsockopt( server.getSocket( ), SOL_SOCKET, SO_KEEPALIVE, ( char* )&keepAlive, size of( bool )); setsockopt( server.getSocket( ), SOL_SOCKET, SO_RCVTIMEO, ( char* )&timeout, size of( int )); std::cout << "Connected!\n" ; while ( true ) { std: :string msg = socket->ReceiveLine(); if ( msg.empty( )) break; processKeys( msg.c_str( )); } std::cout << "Disconnected.\n\n\n" ; }



  1. Copy Source | Copy HTML while ( true ) { std::cout << "Wait for connection...\n" ; try { socket = server.Accept(); } catch ( const char *error ) { std::cout << error << std:: endl ; exit( 0 ); } bool keepAlive = true; int timeout = 10000 ; setsockopt( server.getSocket( ), SOL_SOCKET, SO_KEEPALIVE, ( char* )&keepAlive, size of( bool )); setsockopt( server.getSocket( ), SOL_SOCKET, SO_RCVTIMEO, ( char* )&timeout, size of( int )); std::cout << "Connected!\n" ; while ( true ) { std: :string msg = socket->ReceiveLine(); if ( msg.empty( )) break; processKeys( msg.c_str( )); } std::cout << "Disconnected.\n\n\n" ; }



  2. Copy Source | Copy HTML while ( true ) { std::cout << "Wait for connection...\n" ; try { socket = server.Accept(); } catch ( const char *error ) { std::cout << error << std:: endl ; exit( 0 ); } bool keepAlive = true; int timeout = 10000 ; setsockopt( server.getSocket( ), SOL_SOCKET, SO_KEEPALIVE, ( char* )&keepAlive, size of( bool )); setsockopt( server.getSocket( ), SOL_SOCKET, SO_RCVTIMEO, ( char* )&timeout, size of( int )); std::cout << "Connected!\n" ; while ( true ) { std: :string msg = socket->ReceiveLine(); if ( msg.empty( )) break; processKeys( msg.c_str( )); } std::cout << "Disconnected.\n\n\n" ; }



  3. Copy Source | Copy HTML while ( true ) { std::cout << "Wait for connection...\n" ; try { socket = server.Accept(); } catch ( const char *error ) { std::cout << error << std:: endl ; exit( 0 ); } bool keepAlive = true; int timeout = 10000 ; setsockopt( server.getSocket( ), SOL_SOCKET, SO_KEEPALIVE, ( char* )&keepAlive, size of( bool )); setsockopt( server.getSocket( ), SOL_SOCKET, SO_RCVTIMEO, ( char* )&timeout, size of( int )); std::cout << "Connected!\n" ; while ( true ) { std: :string msg = socket->ReceiveLine(); if ( msg.empty( )) break; processKeys( msg.c_str( )); } std::cout << "Disconnected.\n\n\n" ; }



  4. Copy Source | Copy HTML while ( true ) { std::cout << "Wait for connection...\n" ; try { socket = server.Accept(); } catch ( const char *error ) { std::cout << error << std:: endl ; exit( 0 ); } bool keepAlive = true; int timeout = 10000 ; setsockopt( server.getSocket( ), SOL_SOCKET, SO_KEEPALIVE, ( char* )&keepAlive, size of( bool )); setsockopt( server.getSocket( ), SOL_SOCKET, SO_RCVTIMEO, ( char* )&timeout, size of( int )); std::cout << "Connected!\n" ; while ( true ) { std: :string msg = socket->ReceiveLine(); if ( msg.empty( )) break; processKeys( msg.c_str( )); } std::cout << "Disconnected.\n\n\n" ; }



  5. Copy Source | Copy HTML while ( true ) { std::cout << "Wait for connection...\n" ; try { socket = server.Accept(); } catch ( const char *error ) { std::cout << error << std:: endl ; exit( 0 ); } bool keepAlive = true; int timeout = 10000 ; setsockopt( server.getSocket( ), SOL_SOCKET, SO_KEEPALIVE, ( char* )&keepAlive, size of( bool )); setsockopt( server.getSocket( ), SOL_SOCKET, SO_RCVTIMEO, ( char* )&timeout, size of( int )); std::cout << "Connected!\n" ; while ( true ) { std: :string msg = socket->ReceiveLine(); if ( msg.empty( )) break; processKeys( msg.c_str( )); } std::cout << "Disconnected.\n\n\n" ; }



  6. Copy Source | Copy HTML while ( true ) { std::cout << "Wait for connection...\n" ; try { socket = server.Accept(); } catch ( const char *error ) { std::cout << error << std:: endl ; exit( 0 ); } bool keepAlive = true; int timeout = 10000 ; setsockopt( server.getSocket( ), SOL_SOCKET, SO_KEEPALIVE, ( char* )&keepAlive, size of( bool )); setsockopt( server.getSocket( ), SOL_SOCKET, SO_RCVTIMEO, ( char* )&timeout, size of( int )); std::cout << "Connected!\n" ; while ( true ) { std: :string msg = socket->ReceiveLine(); if ( msg.empty( )) break; processKeys( msg.c_str( )); } std::cout << "Disconnected.\n\n\n" ; }



  7. Copy Source | Copy HTML while ( true ) { std::cout << "Wait for connection...\n" ; try { socket = server.Accept(); } catch ( const char *error ) { std::cout << error << std:: endl ; exit( 0 ); } bool keepAlive = true; int timeout = 10000 ; setsockopt( server.getSocket( ), SOL_SOCKET, SO_KEEPALIVE, ( char* )&keepAlive, size of( bool )); setsockopt( server.getSocket( ), SOL_SOCKET, SO_RCVTIMEO, ( char* )&timeout, size of( int )); std::cout << "Connected!\n" ; while ( true ) { std: :string msg = socket->ReceiveLine(); if ( msg.empty( )) break; processKeys( msg.c_str( )); } std::cout << "Disconnected.\n\n\n" ; }



  8. Copy Source | Copy HTML while ( true ) { std::cout << "Wait for connection...\n" ; try { socket = server.Accept(); } catch ( const char *error ) { std::cout << error << std:: endl ; exit( 0 ); } bool keepAlive = true; int timeout = 10000 ; setsockopt( server.getSocket( ), SOL_SOCKET, SO_KEEPALIVE, ( char* )&keepAlive, size of( bool )); setsockopt( server.getSocket( ), SOL_SOCKET, SO_RCVTIMEO, ( char* )&timeout, size of( int )); std::cout << "Connected!\n" ; while ( true ) { std: :string msg = socket->ReceiveLine(); if ( msg.empty( )) break; processKeys( msg.c_str( )); } std::cout << "Disconnected.\n\n\n" ; }



  9. Copy Source | Copy HTML while ( true ) { std::cout << "Wait for connection...\n" ; try { socket = server.Accept(); } catch ( const char *error ) { std::cout << error << std:: endl ; exit( 0 ); } bool keepAlive = true; int timeout = 10000 ; setsockopt( server.getSocket( ), SOL_SOCKET, SO_KEEPALIVE, ( char* )&keepAlive, size of( bool )); setsockopt( server.getSocket( ), SOL_SOCKET, SO_RCVTIMEO, ( char* )&timeout, size of( int )); std::cout << "Connected!\n" ; while ( true ) { std: :string msg = socket->ReceiveLine(); if ( msg.empty( )) break; processKeys( msg.c_str( )); } std::cout << "Disconnected.\n\n\n" ; }



  10. Copy Source | Copy HTML while ( true ) { std::cout << "Wait for connection...\n" ; try { socket = server.Accept(); } catch ( const char *error ) { std::cout << error << std:: endl ; exit( 0 ); } bool keepAlive = true; int timeout = 10000 ; setsockopt( server.getSocket( ), SOL_SOCKET, SO_KEEPALIVE, ( char* )&keepAlive, size of( bool )); setsockopt( server.getSocket( ), SOL_SOCKET, SO_RCVTIMEO, ( char* )&timeout, size of( int )); std::cout << "Connected!\n" ; while ( true ) { std: :string msg = socket->ReceiveLine(); if ( msg.empty( )) break; processKeys( msg.c_str( )); } std::cout << "Disconnected.\n\n\n" ; }



  11. Copy Source | Copy HTML while ( true ) { std::cout << "Wait for connection...\n" ; try { socket = server.Accept(); } catch ( const char *error ) { std::cout << error << std:: endl ; exit( 0 ); } bool keepAlive = true; int timeout = 10000 ; setsockopt( server.getSocket( ), SOL_SOCKET, SO_KEEPALIVE, ( char* )&keepAlive, size of( bool )); setsockopt( server.getSocket( ), SOL_SOCKET, SO_RCVTIMEO, ( char* )&timeout, size of( int )); std::cout << "Connected!\n" ; while ( true ) { std: :string msg = socket->ReceiveLine(); if ( msg.empty( )) break; processKeys( msg.c_str( )); } std::cout << "Disconnected.\n\n\n" ; }



  12. Copy Source | Copy HTML while ( true ) { std::cout << "Wait for connection...\n" ; try { socket = server.Accept(); } catch ( const char *error ) { std::cout << error << std:: endl ; exit( 0 ); } bool keepAlive = true; int timeout = 10000 ; setsockopt( server.getSocket( ), SOL_SOCKET, SO_KEEPALIVE, ( char* )&keepAlive, size of( bool )); setsockopt( server.getSocket( ), SOL_SOCKET, SO_RCVTIMEO, ( char* )&timeout, size of( int )); std::cout << "Connected!\n" ; while ( true ) { std: :string msg = socket->ReceiveLine(); if ( msg.empty( )) break; processKeys( msg.c_str( )); } std::cout << "Disconnected.\n\n\n" ; }



  13. Copy Source | Copy HTML while ( true ) { std::cout << "Wait for connection...\n" ; try { socket = server.Accept(); } catch ( const char *error ) { std::cout << error << std:: endl ; exit( 0 ); } bool keepAlive = true; int timeout = 10000 ; setsockopt( server.getSocket( ), SOL_SOCKET, SO_KEEPALIVE, ( char* )&keepAlive, size of( bool )); setsockopt( server.getSocket( ), SOL_SOCKET, SO_RCVTIMEO, ( char* )&timeout, size of( int )); std::cout << "Connected!\n" ; while ( true ) { std: :string msg = socket->ReceiveLine(); if ( msg.empty( )) break; processKeys( msg.c_str( )); } std::cout << "Disconnected.\n\n\n" ; }



  14. Copy Source | Copy HTML while ( true ) { std::cout << "Wait for connection...\n" ; try { socket = server.Accept(); } catch ( const char *error ) { std::cout << error << std:: endl ; exit( 0 ); } bool keepAlive = true; int timeout = 10000 ; setsockopt( server.getSocket( ), SOL_SOCKET, SO_KEEPALIVE, ( char* )&keepAlive, size of( bool )); setsockopt( server.getSocket( ), SOL_SOCKET, SO_RCVTIMEO, ( char* )&timeout, size of( int )); std::cout << "Connected!\n" ; while ( true ) { std: :string msg = socket->ReceiveLine(); if ( msg.empty( )) break; processKeys( msg.c_str( )); } std::cout << "Disconnected.\n\n\n" ; }



  15. Copy Source | Copy HTML while ( true ) { std::cout << "Wait for connection...\n" ; try { socket = server.Accept(); } catch ( const char *error ) { std::cout << error << std:: endl ; exit( 0 ); } bool keepAlive = true; int timeout = 10000 ; setsockopt( server.getSocket( ), SOL_SOCKET, SO_KEEPALIVE, ( char* )&keepAlive, size of( bool )); setsockopt( server.getSocket( ), SOL_SOCKET, SO_RCVTIMEO, ( char* )&timeout, size of( int )); std::cout << "Connected!\n" ; while ( true ) { std: :string msg = socket->ReceiveLine(); if ( msg.empty( )) break; processKeys( msg.c_str( )); } std::cout << "Disconnected.\n\n\n" ; }



  16. Copy Source | Copy HTML while ( true ) { std::cout << "Wait for connection...\n" ; try { socket = server.Accept(); } catch ( const char *error ) { std::cout << error << std:: endl ; exit( 0 ); } bool keepAlive = true; int timeout = 10000 ; setsockopt( server.getSocket( ), SOL_SOCKET, SO_KEEPALIVE, ( char* )&keepAlive, size of( bool )); setsockopt( server.getSocket( ), SOL_SOCKET, SO_RCVTIMEO, ( char* )&timeout, size of( int )); std::cout << "Connected!\n" ; while ( true ) { std: :string msg = socket->ReceiveLine(); if ( msg.empty( )) break; processKeys( msg.c_str( )); } std::cout << "Disconnected.\n\n\n" ; }



  17. Copy Source | Copy HTML while ( true ) { std::cout << "Wait for connection...\n" ; try { socket = server.Accept(); } catch ( const char *error ) { std::cout << error << std:: endl ; exit( 0 ); } bool keepAlive = true; int timeout = 10000 ; setsockopt( server.getSocket( ), SOL_SOCKET, SO_KEEPALIVE, ( char* )&keepAlive, size of( bool )); setsockopt( server.getSocket( ), SOL_SOCKET, SO_RCVTIMEO, ( char* )&timeout, size of( int )); std::cout << "Connected!\n" ; while ( true ) { std: :string msg = socket->ReceiveLine(); if ( msg.empty( )) break; processKeys( msg.c_str( )); } std::cout << "Disconnected.\n\n\n" ; }



  18. Copy Source | Copy HTML while ( true ) { std::cout << "Wait for connection...\n" ; try { socket = server.Accept(); } catch ( const char *error ) { std::cout << error << std:: endl ; exit( 0 ); } bool keepAlive = true; int timeout = 10000 ; setsockopt( server.getSocket( ), SOL_SOCKET, SO_KEEPALIVE, ( char* )&keepAlive, size of( bool )); setsockopt( server.getSocket( ), SOL_SOCKET, SO_RCVTIMEO, ( char* )&timeout, size of( int )); std::cout << "Connected!\n" ; while ( true ) { std: :string msg = socket->ReceiveLine(); if ( msg.empty( )) break; processKeys( msg.c_str( )); } std::cout << "Disconnected.\n\n\n" ; }



  19. Copy Source | Copy HTML while ( true ) { std::cout << "Wait for connection...\n" ; try { socket = server.Accept(); } catch ( const char *error ) { std::cout << error << std:: endl ; exit( 0 ); } bool keepAlive = true; int timeout = 10000 ; setsockopt( server.getSocket( ), SOL_SOCKET, SO_KEEPALIVE, ( char* )&keepAlive, size of( bool )); setsockopt( server.getSocket( ), SOL_SOCKET, SO_RCVTIMEO, ( char* )&timeout, size of( int )); std::cout << "Connected!\n" ; while ( true ) { std: :string msg = socket->ReceiveLine(); if ( msg.empty( )) break; processKeys( msg.c_str( )); } std::cout << "Disconnected.\n\n\n" ; }



  20. Copy Source | Copy HTML while ( true ) { std::cout << "Wait for connection...\n" ; try { socket = server.Accept(); } catch ( const char *error ) { std::cout << error << std:: endl ; exit( 0 ); } bool keepAlive = true; int timeout = 10000 ; setsockopt( server.getSocket( ), SOL_SOCKET, SO_KEEPALIVE, ( char* )&keepAlive, size of( bool )); setsockopt( server.getSocket( ), SOL_SOCKET, SO_RCVTIMEO, ( char* )&timeout, size of( int )); std::cout << "Connected!\n" ; while ( true ) { std: :string msg = socket->ReceiveLine(); if ( msg.empty( )) break; processKeys( msg.c_str( )); } std::cout << "Disconnected.\n\n\n" ; }



  21. Copy Source | Copy HTML while ( true ) { std::cout << "Wait for connection...\n" ; try { socket = server.Accept(); } catch ( const char *error ) { std::cout << error << std:: endl ; exit( 0 ); } bool keepAlive = true; int timeout = 10000 ; setsockopt( server.getSocket( ), SOL_SOCKET, SO_KEEPALIVE, ( char* )&keepAlive, size of( bool )); setsockopt( server.getSocket( ), SOL_SOCKET, SO_RCVTIMEO, ( char* )&timeout, size of( int )); std::cout << "Connected!\n" ; while ( true ) { std: :string msg = socket->ReceiveLine(); if ( msg.empty( )) break; processKeys( msg.c_str( )); } std::cout << "Disconnected.\n\n\n" ; }







キーストローク:



Copy Source | Copy HTML



  1. void pressKeys( char key1 、char key2 ){
  2. //前のキーを押します
  3. for( std :: map <char、int> :: iterator it = scanCodes.begin( ); it!= scanCodes.end(); it ++){
  4. char curKey = it-> first;
  5. if( curKey!= key1 && curKey!= key2
  6. upKey( curKey );
  7. }
  8. downKey(key1);
  9. downKey( key2 );
  10. }
  11. void downKey( char key ){
  12. keybd_event( VkKeyScan(key )、scanCodes [key]、 0、0 );
  13. }
  14. void upKey( char key ){
  15. keybd_event( VkKeyScan(key )、scanCodes [key]、KEYEVENTF_KEYUP、 0 );
  16. }




お客様



クライアントのタスクは、サーバーに接続し、押すためのキーの組み合わせを送信することです。 このために、加速度計が使用されます。 私たちのタスクは、電話の空間座標を取得することです。 これは次のように行われます。

Copy Source | Copy HTML



  1. パブリッククラス MainActivityは、ActivityがSensorEventListener {
  2. @Override
  3. public void onCreate(バンドルsavedInstanceState){
  4. // ...
  5. sensorManager =(SensorManager)getSystemService(SENSOR_SERVICE);
  6. accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
  7. // ...
  8. }
  9. @Override
  10. public void onSensorChanged(SensorEvent event ){
  11. ifevent .sensor.getType()== Sensor.TYPE_ACCELEROMETER){
  12. long curTime = System.currentTimeMillis();
  13. // 100ミリ秒ごとにデータを読み取ります。そうしないと、電話はガベージコレクターから曲がります。
  14. if (lastUpdate ==- 1 ||(curTime-lastUpdate)> 100 ){
  15. lastUpdate = curTime;
  16. x = event .values [DATA_X];
  17. y = event .values [DATA_Y];
  18. z = event .values [DATA_Z];
  19. xLabel.setText(String.format( "X:%+ 2.5f" 、x));
  20. yLabel.setText(String.format( "Y:%+ 2.5f" 、y));
  21. zLabel.setText(String.format( "Z:%+ 2.5f" 、z));
  22. {
  23. sendKeys(); //サーバーにキーを送信するための座標の分析
  24. } catch (例外e){
  25. e.printStackTrace();
  26. }
  27. }
  28. }
  29. }
  30. }




重要な点は、一定の間隔で加速度計からデータを読み取る必要があることです。そうしないと、プログラムはセンサーへの継続的な要求から即座に中断されます。 また、折り畳むときは、システムリソースとバッテリーが無駄にならないように、リスナーを加速度計から外す必要があります。 これを行うために、onResumeおよびonPauseメソッドは以下を実行します。



Copy Source | Copy HTML



  1. @Override
  2. protected void onResume(){
  3. super.onResume();
  4. sensorManager.registerListener( this 、加速度計、SENSOR_DELAY_NORMAL);
  5. }
  6. @Override
  7. protected void onPause(){
  8. super.onPause();
  9. sensorManager.unregisterListener( this );
  10. }




キーを生成するためのコードは非常に簡単です。 すべての境界は実験的に決定されました。

Copy Source | Copy HTML



  1. private String getKeys(){
  2. 文字列キー= "" ;
  3. if (z> 7.5
  4. キー+ = "W" ;
  5. 他に
  6. キー+ = "S" ;
  7. if (y < -3
  8. キー+ = "A" ;
  9. else if (y> 3
  10. キー+ = "D" ;
  11. リターンキー;
  12. }


すべての仕組み



Need For Speed Most Wantedですべてを体験しました。 もちろん、実際のステアリングホイールとは違うように感じますが、再生することはできますが、残念ながら、ビデオを撮影できませんでした-家にカメラが1台あり、テストした携帯電話にあります。 近いうちに間違いなく投稿します。 PCとスマートフォンでの外観は次のとおりです。



画像



画像



おわりに



これまでのところ、サーバーの主な欠点は、アプリケーションに依存しないグローバルキーストロークです。 将来、やるべきことがあるでしょう。 私が遭遇した別の問題は、絶え間ない切断です。 接続が切断されたときに絶えず再接続するよりも良い解決策は見つかりませんでした。



何を読む



加速度計を使用する:

github.com/eburke/android_game_examples/blob/9d65f96aff5d60a2e765d8db894b7eb3fd02c315/GameExamples/src/com/stuffthathappens/games/Accel.java



キープレスエミュレーション:

www.codeproject.com/kb/system/keyboard.aspx



そして最も重要なこと-ソース:

dl.dropbox.com/u/5636452/game_controller.zip



All Articles