2016-03-31 15:05:42 nicepainkiller 阅读数 8397

Unity3D内部已经集成了对 GameCenter的支持 在

UnityEngine.SocialPlatforms命名空间下,基本已经满足目前需求

 http://wiki.ceeger.com/manual:social_api?s[]=socialplatforms


C#:

using UnityEngine;
using System.Collections;
using UnityEngine.SocialPlatforms;
using UnityEngine.SocialPlatforms.GameCenter;

public class IOSManager : MonoBehaviour {
	
	public bool   GameCenterState;
	public string userInfo;
	/// <summary>
	/// 初始化 GameCenter 登陆
	/// </summary>
	void Start () {
		Social.localUser.Authenticate(HandleAuthenticated);
	}
		
	/// <summary>
	/// 初始化 GameCenter 结果回调函数
	/// </summary>
	/// <param name="success">If set to <c>true</c> success.</param>
	private void HandleAuthenticated(bool success)
	{
		GameCenterState = success;
		Debug.Log("*** HandleAuthenticated: success = " + success);
		///初始化成功
		if (success) { 
			userInfo = "Username: " + Social.localUser.userName + 
				"\nUser ID: " + Social.localUser.id + 
				"\nIsUnderage: " + Social.localUser.underage;
			Debug.Log (userInfo);
		} else {
		///初始化失败
		
		}
	}
		

	void OnGUI(){

		GUI.TextArea ( new Rect( Screen.width -200, 0, 200, 100), "GameCenter:"+GameCenterState  );
		GUI.TextArea ( new Rect( Screen.width -200, 100, 200, 100), "userInfo:"+userInfo  );

		if (GUI.Button (new Rect (0, 0, 110, 75), "打开成就")) {

			if (Social.localUser.authenticated) {
				Social.ShowAchievementsUI();
			}
		}

		if (GUI.Button (new Rect (0, 150, 110, 75), "打开排行榜")) {

			if (Social.localUser.authenticated) {
				Social.ShowLeaderboardUI();
			}
		}

		if (GUI.Button (new Rect (0, 300, 110, 75), "排行榜设置分数")) {

			if (Social.localUser.authenticated) {
				Social.ReportScore(1000, "XXXX", HandleScoreReported);
			}
		}

		if (GUI.Button (new Rect (0, 300, 110, 75), "设置成就")) {

			if (Social.localUser.authenticated) {
				Social.ReportProgress("XXXX", 15, HandleProgressReported); 
			}
		}

	}

 
	//上传排行榜分数
	public void HandleScoreReported(bool success)
	{
		Debug.Log("*** HandleScoreReported: success = " + success);
	}
	//设置 成就
	private void HandleProgressReported(bool success)
	{
		Debug.Log("*** HandleProgressReported: success = " + success);
	}

	/// <summary>
	/// 加载好友回调
	/// </summary>
	/// <param name="success">If set to <c>true</c> success.</param>
	private void HandleFriendsLoaded(bool success)
	{
		Debug.Log("*** HandleFriendsLoaded: success = " + success);
		foreach(IUserProfile friend in Social.localUser.friends)
		{
			Debug.Log("* friend = " + friend.ToString());
		}
	}

	/// <summary>
	/// 加载成就回调
	/// </summary>
	/// <param name="achievements">Achievements.</param>
	private void HandleAchievementsLoaded(IAchievement[] achievements)
	{
		Debug.Log("* HandleAchievementsLoaded");
		foreach(IAchievement achievement in achievements)
		{
			Debug.Log("* achievement = " + achievement.ToString());
		}
	}

	/// <summary>
	/// 
	/// 成就回调描述
	/// </summary>
	/// <param name="achievementDescriptions">Achievement descriptions.</param>
	private void HandleAchievementDescriptionsLoaded(IAchievementDescription[] achievementDescriptions)
	{
		Debug.Log("*** HandleAchievementDescriptionsLoaded");
		foreach(IAchievementDescription achievementDescription in achievementDescriptions)
		{
			Debug.Log("* achievementDescription = " + achievementDescription.ToString());
		}
	}


 


}
 别着急此时你要是在真机运行估计还不可以,你还需要在 ITunes Connect 里面设置排行榜单成就

当然此时你的APP 应该是已经申请好的咯,并且 “GameCenter” 功能应该是开启的



然后就是 设置你的 排行榜ID  和  成就ID


代码中的“XXXX” 的地方就是 填这两个东西


完事了然后你就可以在你的 游戏中用 GameCenter 了!

2017-02-28 16:54:09 dark00800 阅读数 1216

最近有个项目中需要实现一个排行榜系统,只需显示排名和分数,一开始想用sqlite做一个简单的数据库,但是在写文件的时候发现,由于sqlite只支持单线程的写操作,所以在更新排行榜的时候会出现数据库lock的现象。由于排行榜十分简单,所以想着不如用ScriptableObject来实现。当然设计一下感觉ScriptableObject也是可以用来实现数据库的功能的:-D。

ScriptableObject是一个可继承且不需要挂载在游戏物体上的类,我们可以使用继承了ScriptableObject的类来存储程序数据,例如配置,游戏中的角色信息等等,也可以存储一些预置方案来供程序选择。ScriptableObject会对数据进行序列化存储,如果我们需要设计一些比较复杂的类来存储信息,我们可以加上[Serializable]标记来对类指定的类进行序列化,同时也可以使用[NonSerialized]对特定的变量取消序列化,加了次标记的变量也不会出现在编辑面板上。有些类型如Dictionary是不能序列化的。

[Serializable]
public class DataBase
{
    public string key;
    public string[] values;

    [NonSerialized]
    public int index;
}

首先新建一个Class,继承ScriptableObject,这个类有一个int类型的数组变量scores用来存储排行榜中的分钟。项目需要显示前20名,所以我申请了一个长度为20的数组变量。代码如下:

public class HMDataBase : ScriptableObject
{
    public int[] scores = new int[20];
}

然后重写HMDataBase类的Editor,代码如下:

[CustomEditor(typeof(HMDataBase))]
public class HMDataBaseEditor : Editor {

    public override void OnInspectorGUI()
    {
        base.OnInspectorGUI();
    }
}

public class HMDataBaseAsset
{
    [MenuItem("Assets/Create/HM DataBase", false, 0)]
    public static void CreateAsset()
    {
        HMDataBase asset = ScriptableObject.CreateInstance<HMDataBase>();

        string path = AssetDatabase.GetAssetPath(Selection.activeObject);
        string fileName = "New HM DataBase";
        string assetPathAndName = AssetDatabase.GenerateUniqueAssetPath(path + "/" + fileName + ".asset");
        AssetDatabase.CreateAsset(asset, assetPathAndName);
        AssetDatabase.SaveAssets();
        EditorUtility.FocusProjectWindow();
        Selection.activeObject = asset;
    }
}

这样我们右键Project视图的Assets目录下的地方就能新建HMDataBase类型的asset文件,这个文件会被序列化,可以用来改修和存储项目中的排行榜信息:
新建 这里写图片描述
然后我们在程序中定义一个HMDataBase的变量,就能对chart中的scores进行读写操作了。

public HMDataBase chart;

public int ReadChartByID(int id)
{
    if(id < 0 || id > 20)
    {
        Debug.Log(id out of range);
        return -1;
    }

    return chart.scores[id];
}

public void UpdateChart(int id, int score)
{
    if(id < 0 || id > 20)
    {
        Debug.Log(id out of range);
        return;
    }

    chart.scores[id] = socre;
}

我们可以为HMDataBase添加更多的方法以便进行数据的操作。

其实ScriptableObject可以实现的功能远不止这么简单,有时间我会设计一个复杂一点的类数据库系统,也方便以后程序的编写。之后会继续分享关于ScriptableObject的一些使用心得。
by:蒋志杰

2016-02-19 09:34:26 CodeKsky 阅读数 8472

       大家在玩游戏的时候,无论是大型的网游还是普通的手游都会遇见游戏结束时的排行榜,那么这个排行榜是怎么实现的,最近研究了一番。下面让大家看看效果,没有UI,就是简单的Image与Text。

第一个是名次,第二个是名字,第三个是分数,第四个是时间。上面那个是添加新的记录。名字是在前面的场景中拿到的,如果测试,可以在当前的场景中直接把Text改为InputField即可。

下面是我用到的代码。

1.先搭建基本的UI。大家可以自由发挥。

2.这是基本的声明。

    public InputField inputField;
    public Button button;
    public GameObject PrefabShow;
    public Image ParentsShow;
    public Image ParentsShowUI;
    public Text textName;

 3.在初始化时我们拿到玩家的名字和对事件绑定。就是提交按钮触发的事件。

 void Start ()
 {
     textName.text = Global.PlayerName;
     button.GetComponent<Button>().onClick.AddListener(InputOK);
 }

 void InputOK()
     {
         Global.SkillCount = int.Parse(inputField.text);
        string PlayerResultDate = ResultToJson(Global.PlayerName, Global.SkillCount);
        SaveString(PlayerResultDate);
        DictionarySort(GetJsonDate()); 
    }

2.首先需要知道,既然是排行榜,一定涉及到了数据持久化,那么,在这我用的是Json,对于Json的操作我就不在这里赘述了。我存取的方式是将名字分数以及时间存在本地。

//将数据转化成Json

    public string ResultToJson(string Name, int NowCount)
    {
        StringBuilder sb = new StringBuilder();
        JsonWriter WriteDate = new JsonWriter(sb);
        WriteDate.WriteObjectStart();
        WriteDate.WritePropertyName("Name");
        WriteDate.Write(Name + "|" + DateTime.Now.ToShortTimeString());
        WriteDate.WritePropertyName("Count");
        WriteDate.Write(NowCount);
        WriteDate.WriteObjectEnd();
        return sb.ToString();
    }

//下面的方法就是保存在本地

    private void SaveString(string str)
    {
        FileInfo fi = new FileInfo(Application.dataPath + "/Resources/Json.txt");
        StreamWriter sw = null;
        if (fi.Exists)
        {
            sw = fi.AppendText();
        }
        else
        {
            sw = fi.CreateText();
        }
        sw.WriteLine(str);
        sw.Close();
    }

//下面的方法是获取Json数据

   public Dictionary<string, int> GetJsonDate()
    {

        FileStream fi = new FileStream(Application.dataPath + "/Resources/Json.txt", FileMode.Open);
        Dictionary<string, int> jsonDate = new Dictionary<string, int>();
        if (fi.CanRead)
        {
            StreamReader sw = new StreamReader(fi);
            string jsonStr;
            while ((jsonStr = sw.ReadLine()) != null)
            {
                JsonData data = JsonMapper.ToObject(jsonStr);
                jsonDate.Add(data["Name"].ToString(), int.Parse(data["Count"].ToString()));
            }
        }
        return jsonDate;
    }

//这个方法是把获取的Json数据排序并且显示出来

   private void DictionarySort(Dictionary<string, int> dic)
    {
        if (dic.Count > 0)
        {
            List<KeyValuePair<string, int>> lst = new List<KeyValuePair<string, int>>(dic);
            lst.Sort(delegate(KeyValuePair<string, int> s1, KeyValuePair<string, int> s2)
            {
                return s2.Value.CompareTo(s1.Value);
            });
            //ParentsShow.rectTransform.sizeDelta = new Vector2(600, lst.Count * 100);
            //ParentsShowUI.GetComponent<Mask>().enabled = true;
            //ParentsShowUI.GetComponentInChildren<Scrollbar>().value = 1;
            dic.Clear();
            float i = 1, r = 1, g = 1, b = 0;
            foreach (KeyValuePair<string, int> kvp in lst)
            {
                if (i <= 3)
                {
                    string[] Key = kvp.Key.Split('|');
                    GameObject ga = Instantiate(PrefabShow, ParentsShow.transform.position, Quaternion.identity) as GameObject;
                    ga.transform.parent = ParentsShow.transform;
                    r -= 0.2f;
                    g -= 0.2f;
                    b -= 0.2f;
                    Debug.Log(r + g + b);
                    Text[] Children = ga.GetComponentsInChildren<Text>();
                    Children[0].color = new Color(r, g, b);
                    Children[1].color = new Color(r, g, b);
                    Children[2].color = new Color(r, g, b);                
                    Children[3].color = new Color(r, g, b);
                  
                 
                    Children[1].text = Key[0];
                    Children[3].text = kvp.Value.ToString();
                    Children[2].text = Key[1];
                    Children[0].text = (i++).ToString();
                }
                else
                {
                    string[] Key = kvp.Key.Split('|');
                    GameObject ga = Instantiate(PrefabShow, ParentsShow.transform.position, Quaternion.identity) as GameObject;
                    ga.transform.parent = ParentsShow.transform;
                    Text[] Children = ga.GetComponentsInChildren<Text>();
                    Children[1].text = Key[0];
                    Children[3].text = kvp.Value.ToString();
                    Children[2].text = Key[1];
                    Children[0].text = (i++).ToString();
                }      
            }
        }
    }

好了,这个排行榜的功能就完了,如果有什么写得不对的地方 ,希望大家在下方留言,一起进步与提升。


2016-05-09 10:40:09 u014261855 阅读数 4691

Unity3d本地上传并且裁剪图片-----Android平台

注:引擎版本unity4.x

最近项目需求,需要做用户头像,要求:

1.  可以从本地上传

2.  本地裁剪

3.  压缩控制大小

4.  在三个平台实现PC/Android/IOS

弄了好几天总是搞完了总结一下

 

从本地上传会用到Android系统功能,打开相册和用摄像机拍照,因此unity和Android的交互是必须要会的。

Unity-android可参考到宣雨松的博客http://www.xuanyusong.com/archives/676package com.cheerflame.sdrn;



我参考过一些博文之后整理了一个图片处理类,直接导入这个类调用它的方法就可以了

用法(3步):
1.//在MainActivity中创建图片处理对象

ImgManage = new HeadImgManage(this);

2.//在unity中调用此接口,在接口中调用图片处理类的TakePhoto方法,当choose = 0 的时候打开相机拍照,choose=1的时候打开相册

public void TakePhoto(int choose){
        ImgManage.TakePhoto(choose);
}

3.//在MainActivity中接收事件请求回调

protected void onActivityResult(int requestCode, int resultCode, Intent data) {
	    	Log.i("TEST", "requestCode = " + requestCode);
	        if (resultCode == NONE){
	        	Log.i("TEST", "resultCode == NONE ");
	         	return;
	        }
	            
	        if (requestCode == PHOTOHRAPH) {
	        	Log.i("TEST", "拍照完成");
	            File picture = new File(Environment.getExternalStorageDirectory() + "/temp.jpg");
	            ImgManage.startPhotoZoom(Uri.fromFile(picture));
	        }  

	        if (data == null)
	        {
	        	Log.i("TEST", "data == null");
	        	return;
	        }
	              

	        // 读取相册缩放图片
	        if (requestCode == PHOTOZOOM) {
	        	Log.i("TEST", "读取相册完成");
	        	ImgManage.startPhotoZoom(data.getData());
	        }
	        // 处理结果
	        if (requestCode == PHOTORESOULT) {
	            Bundle extras = data.getExtras();
	            if (extras != null) 
	            {  
		            Bitmap photo = extras.getParcelable("data");
		            try {
		            	ImgManage.SaveBitmap(photo);       
		            } 
		            catch (IOException e) 
		            {                   
		            	// TODO Auto-generated catch block               
		            	e.printStackTrace();           
		            }
	            }  
	        }  
	        super.onActivityResult(requestCode, resultCode, data);
	    }  

处理类:

package com.cheerflame.sdrn;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import com.unity3d.player.UnityPlayer;
import com.unity3d.player.UnityPlayerActivity;

import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Environment;
import android.provider.MediaStore;
import android.util.Log;

public class HeadImgManage{
	UnityPlayerActivity unityActivity;
	
	public static final int NONE = 0;
    public static final int PHOTOHRAPH = 1;// 拍照
    public static final int PHOTOZOOM = 2; // 缩放
    public static final int PHOTORESOULT = 3;// 结果  
    public static final String IMAGE_UNSPECIFIED = "image/*";  

    public final static String FILE_NAME = "image.jpg";
    public final static String DATA_URL = "/data/data/";
    
    public HeadImgManage(UnityPlayerActivity activity){
		unityActivity = activity;
	}
    
    public void TakePhoto(int choose)
    {
    	if(choose == 0)
        {
            Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
            intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File(Environment.getExternalStorageDirectory(), "temp.jpg")));
            unityActivity.startActivityForResult(intent, PHOTOHRAPH);
        }
    	else
        {
            Intent intent = new Intent(Intent.ACTION_PICK, null);
            intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, IMAGE_UNSPECIFIED);
            unityActivity.startActivityForResult(intent, PHOTOZOOM);
        }
    }
    
    public void startPhotoZoom(Uri uri) {
    	Log.i("TEST", "开始裁剪" + uri);
    	
        Intent intent = new Intent("com.android.camera.action.CROP");
        intent.setDataAndType(uri, IMAGE_UNSPECIFIED);
        intent.putExtra("crop", "true");
        // aspectX aspectY 是宽高的比例
        intent.putExtra("aspectX", 1);
        intent.putExtra("aspectY", 1);
        // outputX outputY 是裁剪图片宽高
        intent.putExtra("outputX", 300);
        intent.putExtra("outputY", 300);
        intent.putExtra("return-data", true);
        unityActivity.startActivityForResult(intent, PHOTORESOULT);
    }  

    public void SaveBitmap(Bitmap bitmap) throws IOException {
    	Log.i("TEST", "保存文件");
                FileOutputStream fOut = null;

                //注解
                String path = "/mnt/sdcard/Android/data/com.cheerflame.sdrn/files";
                try {
                          //查看这个路径是否存在,
                          //如果并没有这个路径,
                          //创建这个路径
                          File destDir = new File(path);
                          if (!destDir.exists())
                          {
                                  destDir.mkdirs();
                          }

                        fOut = new FileOutputStream(path + "/" + FILE_NAME) ;
                        Log.i("TEST", "保存路径:" + path + "/" + FILE_NAME);
                        UnityPlayer.UnitySendMessage("Camera", "HeadImage","success!");
                        Log.i("TEST", "success");
                } catch (FileNotFoundException e) {
                        e.printStackTrace();
                }
                //将Bitmap对象写入本地路径中,Unity在去相同的路径来读取这个文件
                bitmap.compress(Bitmap.CompressFormat.JPEG, 10, fOut);
                try {
                        fOut.flush();
                } catch (IOException e) {
                        e.printStackTrace();
                }
                try {
                        fOut.close();
                } catch (IOException e) {
                        e.printStackTrace();
                }
        }

}

"/mnt/sdcard/Android/data/com.xxxx.xxx/files"目录和unity中UnityEngine.Application.persistentDataPath获得路径是一样的,也就是沙盒文件,对沙盒文件操作网上介绍蛮多,我这里就不多说了

bitmap.compress(Bitmap.CompressFormat.JPEG, 10, fOut);这个参数10,是0-100选取图片质量的函数,一般从相册截取完图片之后,图片大小大约是30-40k,显然太大了,10的话大约压缩到原来的1/10,也就是3-4k就很小了


ios的博客之后添加

没有更多推荐了,返回首页