2015/01/16///


首先说一下,这个游戏是参加了MIAC第二届的比赛的一个作品,惨败,获得了优胜奖,在这记录整理一下开发的过程吧。

先来几张截图大体了解一下

unity 实现多级菜单 unity菜单界面_json

个人logo界面

unity 实现多级菜单 unity菜单界面_ide_02

游戏菜单界面

unity 实现多级菜单 unity菜单界面_unity 实现多级菜单_03

游戏加载界面

unity 实现多级菜单 unity菜单界面_ide_04

游戏主界面

unity 实现多级菜单 unity菜单界面_json_05

分享至新浪微博界面

大体就分这几个界面,接下来会详细介绍,这篇文章主要讲一下菜单界面,关于这个界面,真是要说很多,自我感觉杂乱无章,这个界面结合了eclipse做的一个NFC接口的SDK,起初对NFC是一点不懂,在图书馆借了本《Android传感器高级编程》的书才略知一二,了解后赶紧写了个NFC的SDK,关于这个SDK,技术不精的我愣是搞了好几天,各种吧bug,愁得要死要活的,不过就中还是实现了NFC的感应控制游戏,不知道为什么这样一个技术应用到游戏中也没有伯乐,市场几乎没有这种技术应用到游戏中的,好可惜,那么,这篇文章就写一下这个SDK吧。

我们用到了eclipse,安卓手游嘛,所以跟做安卓app类似了,先建一个工程吧,注意,这里的工程要求比较苛刻,我们必须保证这个包名跟签名与unity最后打包生成的包名签名一致,否则会出现程序已停止,就是根本无法启动,新建工程后,我需要导入unity的类库,

unity 实现多级菜单 unity菜单界面_unity 实现多级菜单_06

,至于这个库去哪找,我不多说了,在unity的安装的根目录里,不懂得请百度吧,导入之后,我们就可以写NFC底层了,直接贴代码了,代码中有详细注释

package com.XBW.nfcgame; 
 
 import java.io.IOException;  
 import java.nio.charset.Charset; 
 
 

  import org.json.JSONException; 
 
 import org.json.JSONObject; 
 
 

  import cn.sharesdk.framework.ShareSDK; 
 
 import cn.sharesdk.onekeyshare.OnekeyShare; 
 
 

  import com.XBW.nfcgame.R; 
 
 import com.unity3d.player.UnityPlayer;  
 import com.unity3d.player.UnityPlayerActivity; 
 
 

  import android.app.AlertDialog; 
 
 import android.app.PendingIntent;  
 import android.content.DialogInterface;  
 import android.content.Intent;  
 import android.content.IntentFilter;  
 import android.content.IntentFilter.MalformedMimeTypeException;  
 import android.nfc.NdefMessage;  
 import android.nfc.NdefRecord;  
 import android.nfc.NfcAdapter;  
 import android.nfc.Tag;  
 import android.nfc.tech.Ndef;  
 import android.nfc.tech.NdefFormatable;  
 import android.os.Bundle;  
 import android.os.Parcelable;  
 import android.view.WindowManager;  
 import android.widget.Toast; 
 
 

  public class MainActivity extends UnityPlayerActivity 
 
 {NfcAdapter mNfcAdapter;  
 PendingIntent mNfcPendingIntent;  
 IntentFilter[] mReadTagFilters;  
 IntentFilter[] mWriteTagFilters;  
 private boolean mWriteMode = false;  String mName;
 String reNFC=”N”; 
 

      @Override 
 
 public void onCreate(Bundle savedInstanceState)  
 {  
 super.onCreate(savedInstanceState); 
 
 

          // 得到一个实例的缓存NfcAdapter 
 
 mNfcAdapter = NfcAdapter.getDefaultAdapter(this);  
 //判断你的设备是否支持NFC功能  
 if (mNfcAdapter == null)  
 {  
 Toast.makeText(this,  
 “Your device does not support NFC. Cannot run demo.”,  
 Toast.LENGTH_LONG).show();  
 finish();  
 return;  
 }  
 //检查NFC是否能用  
 checkNfcEnabled();  
 //创建一个 PendingIntent 对象, 这样Android系统就能在一个tag被检测到时定位到这个对象  
 mNfcPendingIntent = PendingIntent.getActivity(this, 0, new Intent(this,  
 getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);  
 //创建意图过滤器来处理NDEF NFC标签检测到在我们的应用程序在“读模式”:  
 IntentFilter ndefDetected = new IntentFilter(  
 NfcAdapter.ACTION_NDEF_DISCOVERED);  
 try  
 {  
 ndefDetected.addDataType(“application/xbw.game.playground.nfc”);  
 } catch (MalformedMimeTypeException e)  
 {  
 throw new RuntimeException(“Could not add MIME type.”, e);  
 }  
 //创建意图过滤器,以发现任何NFC标记当试图写一个标签在“写模式”  
 IntentFilter tagDetected = new IntentFilter(  
 NfcAdapter.ACTION_TAG_DISCOVERED); 
 
 

          // 创建IntentFilter数组: 
 
 mWriteTagFilters = new IntentFilter[] { tagDetected };  
 mReadTagFilters = new IntentFilter[] { ndefDetected, tagDetected };  
 }  
 @Override  
 protected void onResume()  
 {  
 super.onResume();  
 //检查NFC是否能用  
 checkNfcEnabled();  
 if (getIntent().getAction() != null)  
 {  
 // 标签收到应用程序不运行时,没有在前台:  
 if (getIntent().getAction().equals(  
 NfcAdapter.ACTION_NDEF_DISCOVERED))  
 {  
 //NdefMessage[] msgs = getNdefMessagesFromIntent(getIntent());  
 //NdefRecord record = msgs[0].getRecords()[0];  
 //byte[] payload = record.getPayload();  
 //setTextFieldValues(new String(payload));  
 }  
 }  
 //禁用前景分派到给定的活动  
 mNfcAdapter.enableForegroundDispatch(this, mNfcPendingIntent,  
 mReadTagFilters, null);  
 }  
 @Override  
 protected void onPause()  
 {  
 super.onPause();  
 //禁用前景分派到给定的活动  
 mNfcAdapter.disableForegroundDispatch(this);  
 }  
 @Override  
 protected void onNewIntent(Intent intent)  
 {  
 if (!mWriteMode)  
 {  
 // 目前在标签阅读模式  
 if (intent.getAction().equals(NfcAdapter.ACTION_NDEF_DISCOVERED))  
 {  
 NdefMessage[] msgs = getNdefMessagesFromIntent(intent);  
 confirmDisplayedContentOverwrite(msgs[0]);  
 } else if (intent.getAction().equals(  
 NfcAdapter.ACTION_TAG_DISCOVERED))  
 {  
 Toast.makeText(this,  
 “This NFC tag currently has no inventory NDEF data.”,  
 Toast.LENGTH_LONG).show();  
 }  
 } else  
 {  
 // 目前在标签写入模式  
 if (intent.getAction().equals(NfcAdapter.ACTION_TAG_DISCOVERED))  
 {  
 Tag detectedTag = intent  
 .getParcelableExtra(NfcAdapter.EXTRA_TAG);  
 writeTag(createNdefFromJson(), detectedTag);  
 }  
 }  
 } 
 
 

     //NFC读取方法 
 
 NdefMessage[] getNdefMessagesFromIntent(Intent intent)  
 {  
 NdefMessage[] msgs = null;  
 String action = intent.getAction();  
 if (action.equals(NfcAdapter.ACTION_TAG_DISCOVERED)  
 || action.equals(NfcAdapter.ACTION_NDEF_DISCOVERED))  
 {  
 Parcelable[] rawMsgs = intent  
 .getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);  
 if (rawMsgs != null)  
 {  
 msgs = new NdefMessage[rawMsgs.length];  
 for (int i = 0; i < rawMsgs.length; i++)  
 {  
 msgs[i] = (NdefMessage) rawMsgs[i];  
 }  
 } else  
 {  
 // 未知的标签类型  
 byte[] empty = new byte[] {};  
 NdefRecord record = new NdefRecord(NdefRecord.TNF_UNKNOWN,  
 empty, empty, empty);  
 NdefMessage msg = new NdefMessage(new NdefRecord[] { record });  
 msgs = new NdefMessage[] { msg };  
 }  
 } else  
 {  
 finish();  
 }  
 return msgs;  
 } 
 
 

      private void confirmDisplayedContentOverwrite(final NdefMessage msg) 
 
 {  
 String payload = new String(msg.getRecords()[0]  
 .getPayload());setTextFieldValues(payload);  
 }   
 

      private void setTextFieldValues(String jsonString) 
 
 {  
 JSONObject inventory = null;  
 String name = “”;  
 try  
 {  
 inventory = new JSONObject(jsonString);  
 name = inventory.getString(“name”);  
 } catch (JSONException e)  
 {  
 }  
 //给unity调用的接口,需要挂载给Player物体,方法为NFC  
 UnityPlayer.UnitySendMessage(“Player”,”NFC”,name);  
 }  
 //NFC写入方法  
 //unity传进来需要写入的数据写入NFC  
 public void StartActivity0(String name)  
 {  
 mName=name;  
 //if(!mWriteMode)  
 //enableTagWriteMode();  
 enableTagWriteMode();  
 }  
 //关闭读取,打开写入  
 public void StartActivity1(String name)  
 {  
 //mName=name;  
 enableTagReadMode();  
 //mWriteMode=false;  
 }  
 //进入游戏后只有读取功能,关闭写入功能  
 //public void StartActivity2(String name)  
 //{  
 //mWriteMode=true;  
 //if(mWriteMode)  
 //enableTagReadMode();  
 //}  
 private NdefMessage createNdefFromJson()  
 {  
 // 创建一个JSON对象的值:  
 JSONObject computerSpecs = new JSONObject();  
 try  
 {  
 computerSpecs.put(“name”, mName);  
 } catch (JSONException e)  
 {}  
 //创建一个新的包含消息NDEF NDEF记录和使用应用程序的自定义MIME类型:  
 String mimeType = “application/xbw.game.playground.nfc”;  
 byte[] mimeBytes = mimeType.getBytes(Charset.forName(“UTF-8”));  
 String data = computerSpecs.toString();  
 byte[] dataBytes = data.getBytes(Charset.forName(“UTF-8”));  
 byte[] id = new byte[0];  
 NdefRecord record = new NdefRecord(NdefRecord.TNF_MIME_MEDIA,  
 mimeBytes, id, dataBytes);  
 NdefMessage m = new NdefMessage(new NdefRecord[] { record });   
 

          // 返回NDEF信息 
 
 return m;  
 } 
 
 

      private void enableTagWriteMode() 
 
 {  
 mWriteMode = true;  
 mNfcAdapter.enableForegroundDispatch(this, mNfcPendingIntent,  
 mWriteTagFilters, null);  
 } 
 
 

      private void enableTagReadMode() 
 
 {  
 mWriteMode = false;  
 mNfcAdapter.enableForegroundDispatch(this, mNfcPendingIntent,  
 mReadTagFilters, null);  
 } 
 
 

      boolean writeTag(NdefMessage message, Tag tag) 
 
 {  
 int size = message.toByteArray().length;  
 try  
 {  
 Ndef ndef = Ndef.get(tag);  
 if (ndef != null)  
 {  
 ndef.connect(); 
 
 

                  if (!ndef.isWritable()) 
 
 {  
 Toast.makeText(this,  
 “Cannot write to this tag. This tag is read-only.”,  
 Toast.LENGTH_LONG).show();  
 return false;  
 }  
 if (ndef.getMaxSize() < size)  
 {  
 Toast.makeText(  
 this,  
 “Cannot write to this tag. Message size (” + size  
 + ” bytes) exceeds this tag’s capacity of ”  
 + ndef.getMaxSize() + ” bytes.”,  
 Toast.LENGTH_LONG).show();  
 return false;  
 } 
 
 

                  ndef.writeNdefMessage(message); 
 
 UnityPlayer.UnitySendMessage(“Player”,”reNFC”,reNFC);  
 Toast.makeText(this,  
 “A pre-formatted tag was successfully updated.”,  
 Toast.LENGTH_LONG).show();  
 return true;  
 } else  
 {  
 NdefFormatable format = NdefFormatable.get(tag);  
 if (format != null)  
 {  
 try  
 {  
 format.connect();  
 format.format(message);  
 Toast.makeText(  
 this,  
 “This tag was successfully formatted and updated.”,  
 Toast.LENGTH_LONG).show();  
 return true;  
 } catch (IOException e)  
 {  
 Toast.makeText(  
 this,  
 “Cannot write to this tag due to I/O Exception.”,  
 Toast.LENGTH_LONG).show();  
 return false;  
 }  
 } else  
 {  
 Toast.makeText(  
 this,  
 “Cannot write to this tag. This tag does not support NDEF.”,  
 Toast.LENGTH_LONG).show();  
 return false;  
 }  
 }  
 } catch (Exception e)  
 {  
 Toast.makeText(this,  
 “Cannot write to this tag due to an Exception.”,  
 Toast.LENGTH_LONG).show();  
 } 
 
 

          return false; 
 
 } 
 
 

      //NFC检查方法 

 
 

      private void checkNfcEnabled() 
 
 {  
 Boolean nfcEnabled = mNfcAdapter.isEnabled();  
 if (!nfcEnabled)  
 {  
 new AlertDialog.Builder(MainActivity.this)  
 .setTitle(getString(R.string.warning_nfc_is_off))  
 .setMessage(getString(R.string.turn_on_nfc))  
 .setCancelable(false)  
 .setPositiveButton(“开启NFC”,  
 new DialogInterface.OnClickListener()  
 {  
 public void onClick(DialogInterface dialog,  
 int id)  
 {  
 startActivity(new Intent(  
 android.provider.Settings.ACTION_NFC_SETTINGS));  
 MainActivity.this.finish();  
 //这里改为ACTION_NFC_SETTINGS效果更好之前为//ACTION_WIRELESS_SETTINGS;  
 }  
 }  
 ).create().show();  
 }  
 } 
 

  } 

 

  //


大概就这样了,我们还需要在AndroidManifest.xml中添加NFC需要的权限,以及我们需要过滤的自定义NFC标签,


<?xml version=”1.0″ encoding=”utf-8″?> 
  
 < manifest xmlns:android=”http://schemas.android.com/apk/res/android”   
 package=”com.XBW.nfcgame”   
 android:versionCode=”1″   
 android:versionName=”1.0″ >      

       <uses-sdk 
  
 android:minSdkVersion=”14″   
 android:targetSdkVersion=”22″ />   
 < uses-feature   
 android:name=”android.hardware.nfc”   
 android:required=”true” />   
 < uses-permission android:name=”android.permission.NFC” /><uses-permission android:name=”android.permission.INTERNET” />   
 < uses-permission android:name=”android.permission.ACCESS_NETWORK_STATE” />   
 < uses-permission android:name=”android.permission.ACCESS_WIFI_STATE” />   
 < uses-permission android:name=”android.permission.READ_PHONE_STATE” />   
 < uses-permission android:name=”android.permission.WRITE_EXTERNAL_STORAGE” />   
 < uses-permission android:name=”android.permission.RESTART_PACKAGES” />   
 < uses-permission android:name=”android.permission.CHANGE_WIFI_STATE”/>   
 < uses-permission android:name=”android.permission.CAMERA”/>   
 < uses-permission android:name=”android.permission.ACCESS_FINE_LOCATION”/>   
 < uses-permission android:name=”android.permission.BATTERY_STATS”/>   
 < uses-permission android:name=”android.permission.CALL_PHONE”/>   
 < uses-permission android:name=”android.permission.VIBRATE”/>   
 < uses-permission android:name=”android.permission.FLASHLIGHT”/>   
 < uses-permission android:name=”android.permission.WRITE_SMS”/>   
 < uses-permission android:name=”android.permission.WAKE_LOCK”/>   
 < uses-permission android:name=”android.permission.EXPAND_STATUS_BAR”/>   
 < uses-permission android:name=”android.permission.MODIFY_AUDIO_SETTINGS”/>   
 < uses-permission android:name=”android.permission.RECORD_AUDIO”/>   
 < uses-permission android:name=”android.permission.GET_TASKS” />   
 < uses-permission android:name=”android.permission.INTERNET” />   
 < uses-permission android:name=”android.permission.ACCESS_WIFI_STATE” />   
 < uses-permission android:name=”android.permission.ACCESS_NETWORK_STATE” />   
 < uses-permission android:name=”android.permission.CHANGE_WIFI_STATE” />   
 < uses-permission android:name=”android.permission.WRITE_EXTERNAL_STORAGE” />   
 < uses-permission android:name=”android.permission.READ_PHONE_STATE” />   
 < uses-permission android:name=”android.permission.MANAGE_ACCOUNTS”/>   
 < uses-permission android:name=”android.permission.GET_ACCOUNTS”/>   
 < !– 蓝牙分享所需的权限 –>   
 < uses-permission android:name=”android.permission.BLUETOOTH” />   
 < uses-permission android:name=”android.permission.BLUETOOTH_ADMIN” />   
 < application   
 android:allowBackup=”true”   
 android:icon=”@drawable/ic_launcher”   
 android:label=”@string/app_name”   
 android:theme=”@style/AppTheme” >   
 < activity   
 android:name=”.test”   
 android:label=”@string/app_name”   
 >   
 < intent-filter>   
 < action android:name=”android.intent.action.MAIN” />       

                   <category android:name=”android.intent.category.LAUNCHER” /> 
  
 < /intent-filter>   
 < intent-filter>   
 < action android:name=”android.nfc.action.NDEF_DISCOVERED” />   
 < category android:name=”android.intent.category.DEFAULT” />   
 < data android:mimeType=”application/xbw.game.playground.nfc” />   
 < /intent-filter>   
 < /activity>   
 < activity   
 android:name=”.MainActivity”   
 android:label=”@string/app_name”   
 >< /activity>   
 < activity   
 android:name=”com.mob.tools.MobUIShell”   
 android:theme=”@android:style/Theme.Translucent.NoTitleBar”   
 android:configChanges=”keyboardHidden|orientation|screenSize”   
 android:windowSoftInputMode=”stateHidden|adjustResize” >   
 < intent-filter>   
 < data android:scheme=”tencent100371282″ />   
 < action android:name=”android.intent.action.VIEW” />   
 < category android:name=”android.intent.category.BROWSABLE” />   
 < category android:name=”android.intent.category.DEFAULT” />   
 < /intent-filter>   
 < /activity>   <!– 调用新浪原生SDK,需要注册的回调activity –>
 < activity
 android:name=”cn.sharesdk.sina.weibo.SinaActivity”
 android:theme=”@android:style/Theme.Translucent.NoTitleBar”>
 < intent-filter>
 < action android:name=”com.sina.weibo.sdk.action.ACTION_SDK_REQ_ACTIVITY” />
 < category android:name=”android.intent.category.DEFAULT” />
 < /intent-filter>
 < /activity></application>
    

   </manifest> 
 
  

   ///


直接在工程中找的,因为后期添加了新浪微博的SDK,需要添加更多的权限,我们后续再说,这个NFC的SDK就已经弄好了,我们导出工程为jar包就好了,下面就是在unity端调用接口了,先写一下接口具体怎么调用,


// 
 
  

    if (reNFC1 == “N”) 
   
 {    
 if (clo)    
 {    
 //GUI.skin = GUIskin;    
 if (GUI.Button(new Rect(Screen.width * 0.36f, Screen.height * 0.6f, Screen.width * 0.24f, Screen.height * 0.13f), “”))//点击确定进入游戏NFC为读取模式,进入游戏    
 {    
 music.PlayOneShot(beep1);    
 using (AndroidJavaClass jc = new AndroidJavaClass(“com.unity3d.player.UnityPlayer”))    
 {    
 using (AndroidJavaObject jo = jc.GetStatic<AndroidJavaObject>(“currentActivity”))    
 {    
 //调用Android插件中UnityTestActivity中StartActivity0方法,stringToEdit表示它的参数    
 jo.Call(“StartActivity0”, name1);    
 }    
 }    
 //Application.LoadLevel(“Loading”);    
 NFC2 = 0;    
 clo = false;    
 reNFC1 = “Y”;    
 }    
 if (GUI.Button(new Rect(Screen.width * 0.73f, Screen.height * 0.24f, Screen.width * 0.1f, Screen.height * 0.1f), “”))    
 {    
 music.PlayOneShot(beep1);    
 reNFC1 = “N”;    
 }    
 GUI.skin = GUIskin1;    
 if (GUI.Button(new Rect(0, 0, Screen.width, Screen.height), “”))    
 {         

                    } 
   
 }    
 else    
 {    
 //GUI.skin = GUIskin;    
 if (GUI.Button(new Rect(Screen.width * 0.36f, Screen.height * 0.6f, Screen.width * 0.24f, Screen.height * 0.13f), “”))//点击确定进入游戏NFC为读取模式,进入游戏    
 {    
 music.PlayOneShot(beep1);    
 using (AndroidJavaClass jc = new AndroidJavaClass(“com.unity3d.player.UnityPlayer”))    
 {    
 using (AndroidJavaObject jo = jc.GetStatic<AndroidJavaObject>(“currentActivity”))    
 {    
 //调用Android插件中UnityTestActivity中StartActivity0方法,stringToEdit表示它的参数    
 jo.Call(“StartActivity1”, name);    
 }    
 }    
 Application.LoadLevel(“Loading”);    
 }    
 if (GUI.Button(new Rect(Screen.width * 0.73f, Screen.height * 0.24f, Screen.width * 0.1f, Screen.height * 0.1f), “”))    
 {    
 music.PlayOneShot(beep1);    
 reNFC1 = “Y”;    
 }    
 GUI.skin = GUIskin1;    
 if (GUI.Button(new Rect(0, 0, Screen.width, Screen.height), “”))    
 {         

                    } 
   
 }    
 }         

            if (NFC2 == 0) 
   
 {    
 GUI.skin = GUIskin1;    
 if (GUI.Button(new Rect(0, 0, Screen.width, Screen.height), “”))    
 {         

                } 
   
 NFC = 1;    
 }      

    ///


依旧是比较杂乱,接口的调用都写在界面里了,我们在接下来的文章中继续讲解界面时再给大家贴出详细的代码。