2014-08-25 19:02:13 l_jinxiong 阅读数 1688

按惯例,先上效果图


1、新建一个地形,导入terrrain asset,把地面设成草地。



2、新建一个光源,不然地图会很暗

3、导入角色模型,在inspector调整scale,使人物的大小适合屏幕

4、使相机跟随人物,即在人物模型的后上方,这部分要用脚本实现,新建一个MyCamera的c#脚本,然后把它拖给主相机,并把人物模型的tag改为player,


代码如下


using UnityEngine;
using System.Collections;

public class MyCamera : MonoBehaviour {
    public float m_distanceAway = 4.5f;
    public float m_distanceUp = 1.76f;
    public float m_smooth = 5;
    public Transform m_player;
    private Transform m_transsform;
	// Use this for initialization
	void Start () {
        m_transsform = this.transform;
        m_player = GameObject.FindGameObjectWithTag("Player").transform;
	}
	
	// Update is called once per frame
	void Update () {
        float m_wangtedRotationAngle = m_player.eulerAngles.y;
        float m_wangtedHeight = m_player.transform.position.y + m_distanceUp;
        float m_currentRotationAngle = m_transsform.eulerAngles.y;
        float m_currentHeight = m_transsform.position.y;

        m_currentRotationAngle = Mathf.LerpAngle(m_currentRotationAngle, m_wangtedRotationAngle, m_smooth * Time.deltaTime);
        m_currentHeight = Mathf.Lerp(m_currentHeight, m_wangtedHeight, m_smooth * Time.deltaTime);
        Quaternion m_currentRotation = Quaternion.Euler(0, m_currentRotationAngle, 0);
        Vector3 m_position = m_player.transform.position;
        m_position -= m_currentRotation * Vector3.forward * m_distanceAway;
        m_position = new Vector3(m_position.x, m_currentHeight, m_position.z);
        m_transsform.position = Vector3.Lerp(m_transsform.position, m_position, Time.time);
        m_transsform.LookAt(m_player);

        RaycastHit hit;
        if (Physics.Linecast(m_player.position + Vector3.up, m_transsform.position, out hit)) //这里开始主要是使相机不会穿透模型
        {
            string name = hit.collider.gameObject.tag;
            if (name != "MainCamera")
            {
                float currentDistance = Vector3.Distance(hit.point, m_player.position);
                if (currentDistance < m_distanceAway)
                {
                    m_transsform.position = hit.point;
                }
            }
        }
	}
}

到这里运代项目就可以看到相机跟着人物模型了,下面加入easy touch


5、前面已经导入了easy touch,新建一个虚拟摇杆

在Game窗口就可以看到虚拟摇杆了,不过现在还不能操作角色,同时在Hierarchy窗口多了一个EayTouch和New joystick

6、EasyTouch不用管它,改一下New joystick的属性,如图

这个一定要改,其他属性自己看着改吧

7、新建一个PlayerCtr的c#脚本,并拖给人物模型,代码如下


using UnityEngine;
using System.Collections;

public class PlayerCtr : MonoBehaviour {
    public Transform m_transform;

	// Use this for initialization
	void Start () {
        m_transform = this.transform;
	}
	
	// Update is called once per frame
	void Update () {
	
	}

    void OnEnable()
    {
        Debug.Log("OnEnable()");
        EasyJoystick.On_JoystickMove += OnJoystickMove;
        EasyJoystick.On_JoystickMoveEnd += OnJoystickMoveEnd;
//        EasyButton.On_ButtonUp += On_ButtonUp;
    }

    void OnDisable()
    {
        EasyJoystick.On_JoystickMove -= OnJoystickMove;
        EasyJoystick.On_JoystickMoveEnd -= OnJoystickMoveEnd;
//        EasyButton.On_ButtonUp -= On_ButtonUp;
    }

    void OnDestroy()
    {
        EasyJoystick.On_JoystickMove -= OnJoystickMove;
        EasyJoystick.On_JoystickMoveEnd -= OnJoystickMoveEnd;
//        EasyButton.On_ButtonUp -= On_ButtonUp;
    }

    void OnJoystickMoveEnd(MovingJoystick move)
    {
        Debug.Log("OnJoystickMoveEnd()");
        animation.CrossFade("Idle");
    }

    void OnJoystickMove(MovingJoystick move)
    {
        Debug.Log("-----------------------------");
        Debug.Log("OnJoystickMove()");
        float joyPositionX = move.joystickAxis.x;
        float joyPositionY = move.joystickAxis.y;

        if (joyPositionY != 0 || joyPositionX != 0)
        {
            //设置角色的朝向(朝向当前坐标+摇杆偏移量)
            m_transform.LookAt(new Vector3(m_transform.position.x - joyPositionX, m_transform.position.y, m_transform.position.z - joyPositionY));
            //移动玩家的位置(按朝向位置移动)
            m_transform.Translate(Vector3.forward * Time.deltaTime * 7.5F);
            //播放奔跑动画
            animation.CrossFade("Run");
        }
    }
}

8、已经完成了,可以跑起来试一下了


工程文件

2019-01-18 15:08:15 weixin_44486991 阅读数 362

Cocos Creator Touch 事件

cc.Node 有一套完整的事件监听和分发机制。在这套机制之上,提供了一些基础的节点相关的系统事件。因此,在cocos creator中touch事件是与Node节点息息相关的。

// 使用枚举类型来注册
node.on(cc.Node.EventType.TOUCH_START, function (event) {
 console.log('Touch Start');
 event.getID(); //Touch事件的ID
 event.getLocation(); //Touch事件的手指位置
 event.getLocationX(); //获取X轴位置
 event.getLocationY();	//获取触点的 Y 轴位置
 event.getPreviousLocation();	//获取触点上一次触发事件时的位置对象,对象包含 x 和 y 属性
 event.getStartLocation(); 	//获取触点初始时的位置对象,对象包含 x 和 y 属性
 event.getDelta();	//获取触点距离上一次事件移动的距离对象,对象包含 x 和 y 属性
}, this);


// 使用事件名来注册
node.on('touchstart', function (event) {
 console.log('Touch Start');
 event.getID(); //Touch事件的ID
 event.getLocation(); //Touch事件的手指位置
 event.getLocationX(); //获取X轴位置
 event.getLocationY();	//获取触点的 Y 轴位置
 event.getPreviousLocation();	//获取触点上一次触发事件时的位置对象,对象包含 x 和 y 属性
 event.getStartLocation(); 	//获取触点初始时的位置对象,对象包含 x 和 y 属性
 event.getDelta();	//获取触点距离上一次事件移动的距离对象,对象包含 x 和 y 属性
}, this);

系统提供的触摸事件类型如下:

  • cc.Node.EventType.TOUCH_START ‘touchstart’ 当手指触点落在目标节点区域内时
  • cc.Node.EventType.TOUCH_MOVE ‘touchmove’ 当手指在屏幕上目标节点区域内移动时
  • cc.Node.EventType.TOUCH_END ‘touchend’ 当手指在目标节点区域内离开屏幕时
  • cc.Node.EventType.TOUCH_CANCEL ‘touchcancel’ 当手指在目标节点区域外离开屏幕时

Unity3D Touch 事件

Unity3D中Touch事件是以屏幕为基准的,与某个节点无关,全局的Touch事件都统计在Input中,
可以在update 中监听事件,Unity3D商店中有不少再次封装的Touch事件插件,比如EasyTouch。示例代码来自官方文档

void Update()
    {
        // Handle screen touches.
        if (Input.touchCount > 0)
        {
            Touch touch = Input.GetTouch(0);

            // Move the cube if the screen has the finger moving.
            if (touch.phase == TouchPhase.Moved)
            {
                Vector2 pos = touch.position;
                pos.x = (pos.x - width) / width;
                pos.y = (pos.y - height) / height;
                position = new Vector3(-pos.x, pos.y, 0.0f);

                // Position the cube.
                transform.position = position;
            }

            if (Input.touchCount == 2)
            {
                touch = Input.GetTouch(1);

                if (touch.phase == TouchPhase.Began)
                {
                    // Halve the size of the cube.
                    transform.localScale = new Vector3(0.75f, 0.75f, 0.75f);
                }

                if (touch.phase == TouchPhase.Ended)
                {
                    // Restore the regular size of the cube.
                    transform.localScale = new Vector3(1.0f, 1.0f, 1.0f);
                }
            }
        }
    }

区别

  1. Cocos中Touch以节点为中心,每个节点自己单独处理事件,全局检测可以通过制作一个全屏的Node节点,注册监听Touch事件;Unity3D中把Touch事件作为一种全局输入事件,如果想分开节点处理只能自行记录处理;
  2. Cocos中的TOUCH_MOVE只有手指移动时才能监听到,判断长按事件时,最好设置阈值,因为手指不像鼠标那样精确;Unity3D种每个Touch都有一个TouchPhase属性,通过这个属性判断Touch所处的阶段,所以在Unity3D种的TouchMove是不管手指有没有移动都会有事件。

创建了一个小游戏交流群,加群或者有问题交流 可以加我微信 备注“微信小游戏”
在这里插入图片描述
推广一下自己做的简单的小游戏
在这里插入图片描述
在这里插入图片描述

2017-02-07 10:48:41 sakuraiike 阅读数 300

关于Touch 和 Event 的使用记录

using UnityEngine;
using System.Collections;
using UnityEngine.UI;


public class TouchEvent : MonoBehaviour
{

    // Use this for initialization
    void Start()
    {
        if(Input.touchSupported){
            Debug.Log("支持触摸");
        }
        if(Input.touchPressureSupported){
            Debug.Log("支持压感");
        }
        if(Input.stylusTouchSupported){
            Debug.Log("支持手写笔");
        }

        //Input.touches 返回touch列表 分配临时变量
        //Input.touchCount 几点触摸
        //Input.multiTouchEnabled 开启/关闭多点触摸
        //Input.simulateMouseWithTouches  开启/关闭触摸模拟鼠标
        //Input.GetTouch(0) 不分配临时变量

    }
	
    // Update is called once per frame
    void Update()
    {

        if(Input.touchCount==1)Debug.Log("单击3");
        if(Input.touchCount>1)Debug.Log("多点触摸");

        //Input.GetTouch(0).phase==TouchPhase.Moved;

        if(Input.touchCount>0||Input.GetMouseButtonDown(0)){
           
            Debug.Log("-------左键按下------");
            if(Input.GetTouch(0).phase==TouchPhase.Began){


               


            }else if(Input.GetTouch(0).phase==TouchPhase.Moved){
                Vector2 pos= Input.GetTouch(0).position;
                Vector2 deltaPos= Input.GetTouch(0).deltaPosition;
	            float  deltaTime=Input.GetTouch(0).deltaTime;
	            // Input.GetTouch(0).deltaPosition.x;//y magnitude sqrtMagnitude
                Touch touch=Input.GetTouch(0);
                TouchPhase phase=touch.phase;
                TouchType type=touch.type;



            }else if(Input.GetTouch(0).phase==TouchPhase.Stationary){
                
            }
            else if(Input.GetTouch(0).phase==TouchPhase.Ended){

            }

        }

	
    }
    Vector2 lastPos;
    void OnGUI(){
        if(Event.current.isKey){
            Debug.Log("<color=yellow>Event.current.KeyCode:"+Event.current.keyCode.ToString()+"</color>");
            Debug.Log("<color=cyan>Event.current.character:"+Event.current.character+"</color>");
            if(Event.current.keyCode==KeyCode.A){
                //判断按下哪个键 按下的是不是鼠标
                Debug.Log("aaaaaaaaaaaa");
            }
        }
        if(Event.current.isMouse){
           // Event.current.clickCount;鼠标点击次数
            Debug.Log("<color=green>Event.current.button:"+Event.current.button.ToString()+"</color>");
        if(Event.current.type==EventType.MouseDown){
            lastPos= Event.current.mousePosition;
        }
        if(Event.current.type==EventType.MouseDrag){
            Vector2 curPos=Event.current.mousePosition;
                Vector2 distance= Event.current.delta;
            if(curPos.x<lastPos.x){

            }else{


            }

            lastPos=curPos;
        }
        if(Event.current.type==EventType.MouseUp){
            if(Event.current.button==0){
                Debug.Log("======左键抬起========");
            }
            if(Event.current.button==1){
                Debug.Log("======右键抬起========");
            }
            if(Event.current.button==2){
                Debug.Log("======中键抬起========");
            }
            if(Event.current.button==3){
                Debug.Log("======其他键抬起========");
            }
        }
        }
        if(Event.current.alt){
            Debug.Log("按下alt");
        }
        if(Event.current.capsLock){
            Debug.Log("打开大写锁定键");
        }
        if(Event.current.command){
            Debug.Log("按下命令键");
        }
        if(Event.current.control){
            Debug.Log("按下control键");
        }
        if(Event.current.functionKey){
            Debug.Log("是功能键");
        }
        if(Event.current.shift){
            Debug.Log("按下shift键");
        }
        if(Event.current.numeric){
            Debug.Log("是小键盘键");
        }
        //Event.current.pressure

    }
    /**
     * 判断是否为单点触摸
     **/
    public static bool singleTouch()
    {
        if(Input.touchCount==1)
            return true;
        return false;
    }
    /**
     *判断是否为多点触摸 
     **/
    public static bool multipointTouch()
    {
        if (Input.touchCount > 1)
            return true;
        return false;
    }
}


2018-06-30 23:52:40 weixin_42552233 阅读数 1436

说实话可能不相信,学习easy touch的最大难关竟然是找到easy touch资源尴尬。我的pc端的坦克大战已经完成,准备导出到android上运行,就想着使用虚拟摇杆控制。后面发现多数人推荐easy touch插件就想着使用easy touch,结果花了两三个小时寻找资源。从各个博客到各个资源分享网站,从百度网盘搜索到迅雷种子搜索,走投无路到发布百度知道求资源大哭,惨!最后绝望情况下通过加入siki学院的一门课程获得了资源。

其实资源不难找,但是绝大数都不是免费的,比如官网商城的20美元,csdn上的资源很多,虽然也不贵,但是光是充值c币都是100多起步,这些对于穷学生党来说有些难以承受。考虑到绝大数easy touch5都是收费的,所以给后面找不到资源的苦逼学生党一个指向吧,可以通过siki学院的一门easy touch5的课程获得资源,也可以私信(避免引起不必要的麻烦,不公布链接)我分享给你以供学习交流之用,毕竟同为学生党深深了解找不到资源的痛苦。

需要注意的是easy touch3已经不适合现在的unity3d版本了(unity3d 2018.1.1以上,亲测),easy touch4没有试过,但估计不行。

因为今天晚上找资源花了很多时间,所以没有时间去实践,明天实践后再考虑是否添加一些自己的个人理解,因为很多帖子已经讲述地非常详细了。下面贴出一位大佬的总结帖子以供参考学习:

https://blog.csdn.net/q764424567/article/details/78426905

以上,祝好。

2018-04-16 23:00:16 Pg_dog 阅读数 1347

现在手游中出现了越多的定时通知的需求,因为是固定时间推送,所以不需要通过服务器进行推送,只需要利用各个平台自己的本地推送机制就可以实现这个功能。
在Unity3D官方提供的API中,UnityEngine.iOS中有一个类:LocalNotification
它只实现了iOS的本地推送,即仅适用于iphone/ipad/ipod Touch.
Unity3D API链接:https://docs.unity3d.com/ScriptReference/iOS.LocalNotification.html
之前看过一篇文章,有关iOS本地推送的文章,可以看看。
iOS本地推送通知链接:http://www.xuanyusong.com/archives/2632

对于Android端,Unity3D并没有提供现成的接口,所以使用GitHub上的第三方库中实现的接口
GitHub地址:https://github.com/Agasper/unity-android-notifications
我们将这个第三方库clone到本地的一个自建文件夹,打开后有两个文件夹:branches和trunk,使用Unity3D打开trunk中的UnityProject。然后打包,在手机上进行测试,可以实现本地推送。
下面看看其中的接口方法:

    public static int SendNotification(TimeSpan delay, string title, string message, Color32 bgColor, bool sound = true, bool vibrate = true, bool lights = true, string bigIcon = "", String soundName = null, string channel = "default", params Action[] actions)
    {
        int id = new System.Random().Next();
        return SendNotification(id, (long)delay.TotalSeconds * 1000, title, message, bgColor, sound, vibrate, lights, bigIcon, soundName, channel, actions);
    }

    public static int SendNotification(int id, TimeSpan delay, string title, string message, Color32 bgColor, bool sound = true, bool vibrate = true, bool lights = true, string bigIcon = "", String soundName = null, string channel = "default", params Action[] actions)
    {
        return SendNotification(id, (long)delay.TotalSeconds * 1000, title, message, bgColor, sound, vibrate, lights, bigIcon, soundName, channel, actions);
    }

    public static int SendNotification(int id, long delayMs, string title, string message, Color32 bgColor, bool sound = true, bool vibrate = true, bool lights = true, string bigIcon = "", String soundName = null, string channel = "default", params Action[] actions)
    {
#if UNITY_ANDROID && !UNITY_EDITOR
        AndroidJavaClass pluginClass = new AndroidJavaClass(fullClassName);
        if (pluginClass != null)
        {
            pluginClass.CallStatic("SetNotification", id, delayMs, title, message, message,
                sound ? 1 : 0, soundName, vibrate ? 1 : 0, lights ? 1 : 0, bigIcon, "notify_icon_small",
                ToInt(bgColor), bundleIdentifier, channel, PopulateActions(actions));
        }
        return id;
#elif UNITY_IOS && !UNITY_EDITOR
        iOSNotification notification = new iOSNotification();
        notification.identifier = id;
        notification.message = message;
        notification.delay = ((double) delayMs) / 1000.0;
        notification.repeat = 0;
        notification.category = channel;
        notification.sound = sound;
        notification.soundName = soundName;
        SetActions(ref notification, actions);
        scheduleNotification(ref notification);
        return id;
#else
        return 0;
#endif
    }

我们来看一下这三个重载方法:SendNotification,前两个是对第三个的封装,区别就只是参数:

int id //notification的编号
TimeSpan delay //延迟时间(5000,就是5秒后触发)
string title //推送内容标题
string message //推送内容
Color32 bgColor //Unity提供的API,以32位格式表示RGBA颜色
bool sound = true //声音
bool vibrate = true //颤动
bool lights = true //闪亮
string bigIcon = “” //缺省值
String soundName = null //声音文件名
string channel = “default” //都同意给false,表示本地推送(我理解的)
params Action[] actions //params表示函数的参数是可变个数的。一个table

我们来看项目中给到的测试代码(NotificationTest.cs):

using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class NotificationTest : MonoBehaviour
{
    public InputField m_input;

    void Awake()
    {
        LocalNotification.ClearNotifications();
    }

    public void OneTime()
    {
        long delay = long.Parse(m_input.text);   //string转换为long
        LocalNotification.SendNotification(1, delay, "Title", "Long message text", new Color32(0xff, 0x44, 0x44, 255));
    }

    public void Time()   //我自己加的,使用InputField输入时间戳,然后在指定时间推送
    {
        long delay = long.Parse(m_input.text);
        LocalNotification.notification(1, delay, "Title", "Long message text with big icon", new Color32(0xff, 0x44, 0x44, 255), true, true, true, "app_icon");
        m_input.text = "hello";
    }

    public void OneTimeBigIcon()
    {
        LocalNotification.SendNotification(1, 5000, "Title", "Long message text with big icon", new Color32(0xff, 0x44, 0x44, 255), true, true, true, "app_icon");
    }

    public void OneTimeWithActions()
    {
        LocalNotification.Action action1 = new LocalNotification.Action("background", "In Background", this);
        action1.Foreground = false;
        LocalNotification.Action action2 = new LocalNotification.Action("foreground", "In Foreground", this);
        LocalNotification.SendNotification(1, 5000, "Title", "Long message text with actions", new Color32(0xff, 0x44, 0x44, 255), true, true, true, null, "boing", "default", action1, action2);
    }

    public void Repeating()
    {
        LocalNotification.SendRepeatingNotification(1, 5000, 60000, "Title", "Long message text", new Color32(0xff, 0x44, 0x44, 255));
    }

    public void Stop()
    {
        LocalNotification.CancelNotification(1);
    }

    public void OnAction(string identifier)
    {
        Debug.Log("Got action " + identifier);
    }
}

LocalNotification.cs

using System;
using System.IO;
using UnityEngine;
#if UNITY_IOS
using System.Runtime.InteropServices;
#endif
using System.Collections.Generic;

public class LocalNotification
{
#if UNITY_ANDROID && !UNITY_EDITOR
    private static string fullClassName = "net.agasper.unitynotification.UnityNotificationManager";
    private static string actionClassName = "net.agasper.unitynotification.NotificationAction";
#endif

#if UNITY_5_6_OR_NEWER
    private static string bundleIdentifier { get { return Application.identifier; } }
#else
    private static string bundleIdentifier { get { return Application.bundleIdentifier; } }
#endif

    public static void notification(int id, long time, string title, string message,Color32 bgColor, bool sound = true, bool vibrate = true, bool lights = true, string bigIcon = "", String soundName = null, string channel = "default", params Action[] actions)
    {
        System.DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new System.DateTime(1970, 1, 1));  //当地时区
        DateTime dt = startTime.AddMilliseconds(time);
        TimeSpan Timespan = dt - DateTime.Now;
        long delay = Timespan.Days * 24 * 3600 * 1000 + Timespan.Hours * 3600 * 1000 + Timespan.Minutes * 60 * 1000 + Timespan.Seconds * 1000 + Timespan.Milliseconds;
        SendNotification(id, delay, title,message, bgColor, sound, vibrate, lights, bigIcon, soundName, channel, actions);
    }

    public static int SendNotification(TimeSpan delay, string title, string message, Color32 bgColor, bool sound = true, bool vibrate = true, bool lights = true, string bigIcon = "", String soundName = null, string channel = "default", params Action[] actions)
    {
        int id = new System.Random().Next();
        return SendNotification(id, (long)delay.TotalSeconds * 1000, title, message, bgColor, sound, vibrate, lights, bigIcon, soundName, channel, actions);
    }

    public static int SendNotification(int id, TimeSpan delay, string title, string message, Color32 bgColor, bool sound = true, bool vibrate = true, bool lights = true, string bigIcon = "", String soundName = null, string channel = "default", params Action[] actions)
    {
        return SendNotification(id, (long)delay.TotalSeconds * 1000, title, message, bgColor, sound, vibrate, lights, bigIcon, soundName, channel, actions);
    }

    public static int SendNotification(int id, long delayMs, string title, string message, Color32 bgColor, bool sound = true, bool vibrate = true, bool lights = true, string bigIcon = "", String soundName = null, string channel = "default", params Action[] actions)
    {
#if UNITY_ANDROID && !UNITY_EDITOR
        AndroidJavaClass pluginClass = new AndroidJavaClass(fullClassName);
        if (pluginClass != null)
        {
            pluginClass.CallStatic("SetNotification", id, delayMs, title, message, message,
                sound ? 1 : 0, soundName, vibrate ? 1 : 0, lights ? 1 : 0, bigIcon, "notify_icon_small",
                ToInt(bgColor), bundleIdentifier, channel, PopulateActions(actions));
        }
        return id;
#elif UNITY_IOS && !UNITY_EDITOR
        iOSNotification notification = new iOSNotification();
        notification.identifier = id;
        notification.message = message;
        notification.delay = ((double) delayMs) / 1000.0;
        notification.repeat = 0;
        notification.category = channel;
        notification.sound = sound;
        notification.soundName = soundName;
        SetActions(ref notification, actions);
        scheduleNotification(ref notification);
        return id;
#else
        return 0;
#endif
    }

    public static int SendRepeatingNotification(TimeSpan delay, TimeSpan timeout, string title, string message, Color32 bgColor, bool sound = true, bool vibrate = true, bool lights = true, string bigIcon = "", String soundName = null, string channel = "default", params Action[] actions)
    {
        int id = new System.Random().Next();
        return SendRepeatingNotification(id, (long)delay.TotalSeconds * 1000, (int)timeout.TotalSeconds, title, message, bgColor, sound, vibrate, lights, bigIcon, soundName, channel, actions);
    }

    public static int SendRepeatingNotification(int id, TimeSpan delay, TimeSpan timeout, string title, string message, Color32 bgColor, bool sound = true, bool vibrate = true, bool lights = true, string bigIcon = "", String soundName = null, string channel = "default", params Action[] actions)
    {
        return SendRepeatingNotification(id, (long)delay.TotalSeconds * 1000, (int)timeout.TotalSeconds, title, message, bgColor, sound, vibrate, lights, bigIcon, soundName, channel, actions);
    }

    public static int SendRepeatingNotification(int id, long delayMs, long timeoutMs, string title, string message, Color32 bgColor, bool sound = true, bool vibrate = true, bool lights = true, string bigIcon = "", String soundName = null, string channel = "default", params Action[] actions)
    {
#if UNITY_ANDROID && !UNITY_EDITOR
        AndroidJavaClass pluginClass = new AndroidJavaClass(fullClassName);
        if (pluginClass != null)
        {
            pluginClass.CallStatic("SetRepeatingNotification", id, delayMs, title, message, message, timeoutMs,
                sound ? 1 : 0, soundName, vibrate ? 1 : 0, lights ? 1 : 0, bigIcon, "notify_icon_small",
                ToInt(bgColor), bundleIdentifier, channel, PopulateActions(actions));
        }
        return id;
#elif UNITY_IOS && !UNITY_EDITOR
        iOSNotification notification = new iOSNotification();
        notification.identifier = id;
        notification.message = message;
        notification.delay = ((double) delayMs) / 1000.0;
        notification.repeat = CalculateiOSRepeat(timeoutMs);
        notification.category = channel;
        notification.sound = sound;
        notification.soundName = soundName;
        SetActions(ref notification, actions);
        scheduleNotification(ref notification);
        return id;
#else
        return 0;
#endif
    }

    public static void CancelNotification(int id)
    {
#if UNITY_ANDROID && !UNITY_EDITOR
        AndroidJavaClass pluginClass = new AndroidJavaClass(fullClassName);
        if (pluginClass != null) {
            pluginClass.CallStatic("CancelPendingNotification", id);
        }
#elif UNITY_IOS && !UNITY_EDITOR
        cancelNotification(id);
#endif
    }

    public static void ClearNotifications()
    {
#if UNITY_ANDROID && !UNITY_EDITOR
        AndroidJavaClass pluginClass = new AndroidJavaClass(fullClassName);
        if (pluginClass != null) {
            pluginClass.CallStatic("ClearShowingNotifications");
        }
#elif UNITY_IOS && !UNITY_EDITOR
        cancelAllNotifications();
#endif
    }

    /// This allows you to create a custom channel for different kinds of notifications.
    /// Channels are required on Android Oreo and above. If you don't call this method, a channel will be created for you with the configuration you give to SendNotification.
    public static void CreateChannel(string identifier, string name, string description, Color32 lightColor, bool enableLights = true, string soundName = null, Importance importance = Importance.Default, bool vibrate = true, long[] vibrationPattern = null)
    {
#if UNITY_ANDROID && !UNITY_EDITOR
        AndroidJavaClass pluginClass = new AndroidJavaClass(fullClassName);
        if (pluginClass != null)
        {
            pluginClass.CallStatic("CreateChannel", identifier, name, description, (int) importance, soundName, enableLights ? 1 : 0, ToInt(lightColor), vibrate ? 1 : 0, vibrationPattern, bundleIdentifier);
        }
#endif
    }

    public enum Importance
    {
        /// Default notification importance: shows everywhere, makes noise, but does not visually intrude.
        Default = 3,

        /// Higher notification importance: shows everywhere, makes noise and peeks. May use full screen intents.
        High = 4,

        /// Low notification importance: shows everywhere, but is not intrusive.
        Low = 2,

        /// Unused.
        Max = 5,

        /// Min notification importance: only shows in the shade, below the fold. This should not be used with Service.startForeground since a foreground service is supposed to be something the user cares about so it does not make semantic sense to mark its notification as minimum importance. If you do this as of Android version O, the system will show a higher-priority notification about your app running in the background.
        Min = 1,

        /// A notification with no importance: does not show in the shade.
        None = 0
    }

    public class Action
    {
        public Action(string identifier, string title, MonoBehaviour handler)
        {
            this.Identifier = identifier;
            this.Title = title;
            if (handler != null)
            {
                this.GameObject = handler.gameObject.name;
                this.HandlerMethod = "OnAction";
            }
        }

        public string Identifier;
        public string Title;
        public string Icon;
        public bool Foreground = true;
        public string GameObject;
        public string HandlerMethod;
    }

    private static int ToInt(Color32 color)
    {
        return color.r * 65536 + color.g * 256 + color.b;
    }

#if UNITY_ANDROID && !UNITY_EDITOR
    private static AndroidJavaObject PopulateActions(Action[] actions)
    {
        AndroidJavaObject actionList = null;
        if (actions.Length > 0)
        {
            actionList = new AndroidJavaObject("java.util.ArrayList");
            for (int i = 0; i < actions.Length; i++)
            {
                var action = actions[i];
                using (AndroidJavaObject notificationObject = new AndroidJavaObject(actionClassName))
                {
                    notificationObject.Call("setIdentifier", action.Identifier);
                    notificationObject.Call("setTitle", action.Title);
                    notificationObject.Call("setIcon", action.Icon);
                    notificationObject.Call("setForeground", action.Foreground);
                    notificationObject.Call("setGameObject", action.GameObject);
                    notificationObject.Call("setHandlerMethod", action.HandlerMethod);
                    actionList.Call<bool>("add", notificationObject);
                }
            }
        }
        return actionList;
    }
#endif

#if UNITY_IOS && !UNITY_EDITOR
    internal struct iOSNotification {
        public int identifier;
        public string message;
        public double delay;
        public UnityEngine.iOS.CalendarUnit repeat;
        public string category;
        public bool sound;
        public string soundName;
        public int actionCount;
        public iOSNotificationAction action1;
        public iOSNotificationAction action2;
        public iOSNotificationAction action3;
        public iOSNotificationAction action4;
    }

    internal struct iOSNotificationAction {
        public string identifier;
        public string title;
        public bool foreground;
        public string gameObject;
        public string handlerMethod;
    }

    [DllImport ("__Internal")] internal static extern void scheduleNotification(ref iOSNotification notification);
    [DllImport ("__Internal")] internal static extern void cancelNotification(int identifier);
    [DllImport ("__Internal")] internal static extern void cancelAllNotifications();

    internal static void SetActions(ref iOSNotification notification, Action[] actions)
    {
        notification.actionCount = actions.Length;
        if (actions.Length > 0)
            notification.action1 = CreateAction(actions[0]);
        if (actions.Length > 1)
            notification.action2 = CreateAction(actions[1]);
        if (actions.Length > 2)
            notification.action3 = CreateAction(actions[2]);
        if (actions.Length > 3)
            notification.action4 = CreateAction(actions[3]);
    }

    internal static iOSNotificationAction CreateAction(Action from)
    {
        iOSNotificationAction action;
        action.identifier = from.Identifier;
        action.title = from.Title;
        action.foreground = from.Foreground;
        action.gameObject = from.GameObject;
        action.handlerMethod = from.HandlerMethod;
        return action;
    }

    public static UnityEngine.iOS.CalendarUnit CalculateiOSRepeat(long timeoutMS)
    {
        if (timeoutMS == 0)
            return 0;

        long timeoutMinutes = timeoutMS / (1000 * 60);
        if (timeoutMinutes == 1)
            return UnityEngine.iOS.CalendarUnit.Minute;
        if (timeoutMinutes == 60)
            return UnityEngine.iOS.CalendarUnit.Hour;
        if (timeoutMinutes == 60 * 24)
            return UnityEngine.iOS.CalendarUnit.Day;
        if (timeoutMinutes >= 60 * 24 * 2 && timeoutMinutes <= 60 * 24 * 5)
            return UnityEngine.iOS.CalendarUnit.Weekday;
        if (timeoutMinutes == 60 * 24 * 7)
            return UnityEngine.iOS.CalendarUnit.Week;
        if (timeoutMinutes >= 60 * 24 * 28 && timeoutMinutes <= 60 * 24 * 31)
            return UnityEngine.iOS.CalendarUnit.Month;
        if (timeoutMinutes >= 60 * 24 * 91 && timeoutMinutes <= 60 * 24 * 92)
            return UnityEngine.iOS.CalendarUnit.Quarter;
        if (timeoutMinutes >= 60 * 24 * 365 && timeoutMinutes <= 60 * 24 * 366)
            return UnityEngine.iOS.CalendarUnit.Year;
        throw new ArgumentException("Unsupported timeout for iOS - must equal a minute, hour, day, 2-5 days (for 'weekday'), week, month, quarter or year but was " + timeoutMS);
    }
#endif
}

附加一个测试代码:

using UnityEngine;
using System.Collections;

#if UNITY_IPHONE
using NotificationServices = UnityEngine.iOS.NotificationServices;
using NotificationType = UnityEngine.iOS.NotificationType;
#endif

public class NewBehaviourScript : MonoBehaviour {
    //本地推送
    public static void NotificationMessage(string message,int hour ,bool isRepeatDay)
    {
        int year = System.DateTime.Now.Year;
        int month = System.DateTime.Now.Month;
        int day= System.DateTime.Now.Day;
        System.DateTime newDate = new System.DateTime(year,month,day,hour,0,0);
        NotificationMessage(message,newDate,isRepeatDay);
    }
    //本地推送 你可以传入一个固定的推送时间
    public static void NotificationMessage(string message,System.DateTime newDate,bool isRepeatDay)
    {
        #if UNITY_IPHONE
        //推送时间需要大于当前时间
        if(newDate > System.DateTime.Now)
        {
            UnityEngine.iOS.LocalNotification localNotification = new UnityEngine.iOS.LocalNotification();
            localNotification.fireDate =newDate;    
            localNotification.alertBody = message;
            localNotification.applicationIconBadgeNumber = 1;
            localNotification.hasAction = true;
            localNotification.alertAction = "这是notificationtest的标题";
            if(isRepeatDay)
            {
                //是否每天定期循环
                localNotification.repeatCalendar = UnityEngine.iOS.CalendarIdentifier.ChineseCalendar;
                localNotification.repeatInterval = UnityEngine.iOS.CalendarUnit.Day;
            }
            localNotification.soundName = UnityEngine.iOS.LocalNotification.defaultSoundName;
            UnityEngine.iOS.NotificationServices.ScheduleLocalNotification(localNotification);
        }
        #endif
        #if UNITY_ANDROID
        if (newDate > System.DateTime.Now) 
        {
            LocalNotification.SendNotification(1,10,"这是notificationtest的标题","这是notificationtest的消息",new Color32(0xff, 0x44, 0x44, 255));
            if (System.DateTime.Now.Hour >= 12) {
                //System.DateTime dataTimeNextNotify = new System.DateTime(
                long delay = 24 * 60 * 60 - ((System.DateTime.Now.Hour - 12)* 60 * 60 + System.DateTime.Now.Minute * 60 + System.DateTime.Now.Second);
                LocalNotification.SendRepeatingNotification(2,delay, 24 * 60 * 60,"这是notificationtest的标题","每天中午12点推送",new Color32(0xff, 0x44, 0x44, 255));
            }
            else 
            {
                long delay = (12 - System.DateTime.Now.Hour)* 60 * 60 - System.DateTime.Now.Minute * 60 - System.DateTime.Now.Second;
                LocalNotification.SendRepeatingNotification(2,delay,24 * 60 * 60 ,"这是notificationtest的标题","每天中午12点推送",new Color32(0xff, 0x44, 0x44, 255));  
            }
        }
        #endif
    }

    void Awake()
    {
        #if UNITY_IPHONE
        UnityEngine.iOS.NotificationServices.RegisterForNotifications (
            NotificationType.Alert |
            NotificationType.Badge |
            NotificationType.Sound);
        #endif
        //第一次进入游戏的时候清空,有可能用户自己把游戏冲后台杀死,这里强制清空
        CleanNotification();
    }

    void OnApplicationPause(bool paused)
    {
        //程序进入后台时
        if(paused)
        {
            //10秒后发送
            NotificationMessage("这是notificationtest的推送正文信息",System.DateTime.Now.AddSeconds(10),false);
            //每天中午12点推送
            NotificationMessage("每天中午12点推送",12,true);
        }
        else
        {
            //程序从后台进入前台时
            CleanNotification();
        }
    }

    //清空所有本地消息
    void CleanNotification()
    {
        #if UNITY_IPHONE
        UnityEngine.iOS.LocalNotification l = new UnityEngine.iOS.LocalNotification (); 
        l.applicationIconBadgeNumber = -1; 
        UnityEngine.iOS.NotificationServices.PresentLocalNotificationNow (l); 
        UnityEngine.iOS.NotificationServices.CancelAllLocalNotifications (); 
        UnityEngine.iOS.NotificationServices.ClearLocalNotifications (); 
        #endif
        #if UNITY_ANDROID
        LocalNotification.CancelNotification(1);
        LocalNotification.CancelNotification(2);
        #endif
    }
}

上面这个示例中,用UNITY_IPHONE包围起来的是iOS平台相关代码,用UNITY_ANDROID包围起来的是Android平台相关代码。除了以下代码外,推送还需要注意以下几点:

Android推送需要在manifest文件中加入一些权限,具体请参考Android第三方库中示例工程。
推送的时间点应该以服务器为主,当游戏采取全球发行时,就需要谨慎处理时区问题。

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