使用Unity制作一個Windows桌面寵物

示意

如下圖中的狐貍术羔,鼠標(biāo)左鍵按住可拖動赢赊,鼠標(biāo)右鍵按住可調(diào)整大小,鼠標(biāo)左鍵點擊可隨機播放一個動作级历。

桌寵.gif

思路

主要是2點

  1. 讓程序背景透明
    參考文章:Unity 制作萌系live2d桌寵:屏幕自適應(yīng)+交互
    將TablePetBackSample.cs掛在一個GameObject上释移。
    將MainCamera的ClearFlags改為SolidColor,Background的顏色改為透明:000000
using UnityEngine;
using System;
// 為了使用屬性:DllImport
using System.Runtime.InteropServices;

public class TablePetBackSample : MonoBehaviour
{
    private int currentX;
    private int currentY;
    #region Win函數(shù)常量
    private struct MARGINS
    {
        public int cxLeftWidth;
        public int cxRightWidth;
        public int cyTopHeight;
        public int cyBottomHeight;
    }

    [DllImport("user32.dll")]
    static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
    [DllImport("user32.dll")]
    static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);

    [DllImport("user32.dll")]
    static extern int GetWindowLong(IntPtr hWnd, int nIndex);

    [DllImport("user32.dll")]
    static extern int SetWindowPos(IntPtr hWnd, int hWndInsertAfter, int X, int Y, int cx, int cy, int uFlags);

    [DllImport("Dwmapi.dll")]
    static extern uint DwmExtendFrameIntoClientArea(IntPtr hWnd, ref MARGINS margins);
    [DllImport("user32.dll")]
    private static extern int SetWindowLong(IntPtr hWnd, int nIndex, uint dwNewLong);
    private const int GWL_EXSTYLE = -20;
    private const int GWL_STYLE = -16;
    private const int WS_EX_LAYERED = 0x00080000;
    private const int WS_BORDER = 0x00800000;
    private const int WS_CAPTION = 0x00C00000;
    private const int SWP_SHOWWINDOW = 0x0040;
    private const int LWA_COLORKEY = 0x00000001;
    private const int LWA_ALPHA = 0x00000002;
    private const int WS_EX_TRANSPARENT = 0x20;
    #endregion
    private IntPtr hwnd;

    void Awake()
    {
        var productName = Application.productName;
#if UNITY_EDITOR
#else
        hwnd = FindWindow(null, productName);
        int intExTemp = GetWindowLong(hwnd, GWL_EXSTYLE);
        SetWindowLong(hwnd, GWL_EXSTYLE, intExTemp | WS_EX_TRANSPARENT | WS_EX_LAYERED);
        SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) & ~WS_BORDER & ~WS_CAPTION);
        currentX = 0;
        currentY = 0;
        SetWindowPos(hwnd, -1, currentX, currentY, Screen.currentResolution.width, Screen.currentResolution.height, SWP_SHOWWINDOW);
        var margins = new MARGINS() { cxLeftWidth = -1 };
        DwmExtendFrameIntoClientArea(hwnd, ref margins);     
#endif
    }
}
  1. 關(guān)注鼠標(biāo)的位置和點擊
    將MyMouse.cs掛在一個GameObject上寥殖。
using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using UnityEngine;


public class MyMouse : MonoBehaviour
{

    [DllImport("user32.dll")]
    public static extern short GetAsyncKeyState(int vKey);
    private const int VK_LBUTTON = 0x01; //鼠標(biāo)左鍵
    private const int VK_RBUTTON = 0x02; //鼠標(biāo)右鍵
    private const int VK_MBUTTON = 0x04; //鼠標(biāo)中鍵

    private bool _isLeftDown;
    private bool _isRightDown;
    private bool _isMiddleDown;

    public event Action<MouseKey, Vector3> MouseKeyDownEvent;
    public event Action<MouseKey, Vector3> MouseKeyUpEvent;
    public event Action<MouseKey, Vector3> MouseDragEvent;
    public event Action<MouseKey> MouseKeyClickEvent;

    public Vector3 MousePos{ get; private set; }

    private bool _hasDragged;
    private Vector3 _leftDownPos;
    private Vector3 _rightDownPos;
    private Vector3 _middleDownPos;

    private void Start()
    {
        Init();
    }

    private void Update() 
    {
        // 按下左鍵
        if (GetAsyncKeyState(VK_LBUTTON) != 0)
        {
            if (!_isLeftDown)
            {
                _isLeftDown = true;
                _leftDownPos = MouseKeyDown(MouseKey.Left);
            }
            else if (MousePos != Input.mousePosition)
            {
                MouseKeyDrag(MouseKey.Left);
                if (!_hasDragged)
                {
                    _hasDragged = true;
                }
            }
        }
        // 按下右鍵
        if (GetAsyncKeyState(VK_RBUTTON) != 0)
        {
            if (!_isRightDown)
            {
                _isRightDown = true;
                _rightDownPos = MouseKeyDown(MouseKey.Right);
            }
            else if(MousePos != Input.mousePosition)
            {
                MouseKeyDrag(MouseKey.Right);
                if (!_hasDragged)
                {
                    _hasDragged = true;
                }
            }
        }
        // 按下中鍵
        if (GetAsyncKeyState(VK_MBUTTON) != 0)
        {
            if (!_isMiddleDown)
            {
                _isMiddleDown = true;
                _middleDownPos = MouseKeyDown(MouseKey.Middle);
            }
            else if(MousePos != Input.mousePosition)
            {
                MouseKeyDrag(MouseKey.Middle);
                if (!_hasDragged)
                {
                    _hasDragged = true;
                }
            }
        }
        // 抬起左鍵
        if (GetAsyncKeyState(VK_LBUTTON) == 0 && _isLeftDown)
        {
            _isLeftDown = false;
            MouseKeyUp(MouseKey.Left);

            if (!_hasDragged && _leftDownPos == MousePos)
            {
                MouseKeyClick(MouseKey.Left);
            }

            _hasDragged = false;
        }
        // 抬起右鍵
        if (GetAsyncKeyState(VK_RBUTTON) == 0 && _isRightDown)
        {
            _isRightDown = false;
            MouseKeyUp(MouseKey.Right);

            if (!_hasDragged && _rightDownPos == MousePos)
            {
                MouseKeyClick(MouseKey.Right);
            }

            _hasDragged = false;
        }
        // 抬起中鍵
        if (GetAsyncKeyState(VK_MBUTTON) == 0 && _isMiddleDown)
        {
            _isMiddleDown = false;
            MouseKeyUp(MouseKey.Middle);

            if (!_hasDragged && _middleDownPos == MousePos)
            {
                MouseKeyClick(MouseKey.Middle);
            }

            _hasDragged = false;
        }
    }

    private void OnDestroy()
    {
        Destroy();
    }
    
    public void Init()
    {
        _isLeftDown = false;
        _isRightDown = false;
        _isMiddleDown = false;
        _hasDragged = false;
    }
    
    public void Destroy()
    {
        
    }

    private Vector3 MouseKeyDown(MouseKey mouseKey)
    {
        RefreshMousePos();
        MouseKeyDownEvent?.Invoke(mouseKey, MousePos);
        // Log.Instance.ShowLog(string.Format("按下:" + mouseKey + "  "+MousePos));

        return MousePos;
    }
    private Vector3 MouseKeyUp(MouseKey mouseKey)
    {
        RefreshMousePos();
        MouseKeyUpEvent?.Invoke(mouseKey, MousePos);
        // Log.Instance.ShowLog(string.Format("抬起:" + mouseKey + "  " + MousePos));

        return MousePos;
    }

    private Vector3 MouseKeyDrag(MouseKey mouseKey)
    {
        RefreshMousePos();
        MouseDragEvent?.Invoke(mouseKey, MousePos);
        // Log.Instance.ShowLog(string.Format("拖動:" + mouseKey + "  " + MousePos));

        return MousePos;
    }

    private void MouseKeyClick(MouseKey mouseKey)
    {
        MouseKeyClickEvent?.Invoke(mouseKey);
        // Log.Instance.ShowLog(string.Format("點擊:" + mouseKey + "  " + MousePos));
    }

    private Vector3 RefreshMousePos()
    {
        MousePos = Input.mousePosition;
        return MousePos;
    }

    public Vector3 MousePosToWorldPos(Vector3 mousePos)
    {
        var screenInWorldPos = Camera.main.WorldToScreenPoint(mousePos);
        var refPos = new Vector3(mousePos.x, mousePos.y, screenInWorldPos.z);
        var pos = Camera.main.ScreenToWorldPoint(refPos);
        return pos;
    }
}

public enum MouseKey
{ 
    None,
    Left,
    Right,
    Middle
}

如何確認(rèn)是否點擊到桌寵玩讳?
關(guān)注鼠標(biāo)Down事件涩蜘,發(fā)生時,獲得當(dāng)前鼠標(biāo)位置mousePos

 var ray = Camera.main.ScreenPointToRay(mousePos);
 if (Physics.Raycast(ray, out RaycastHit hit))
 {
    // 判斷hit的是否是桌寵熏纯。
 }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末同诫,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子樟澜,更是在濱河造成了極大的恐慌误窖,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,290評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件往扔,死亡現(xiàn)場離奇詭異贩猎,居然都是意外死亡,警方通過查閱死者的電腦和手機萍膛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,107評論 2 385
  • 文/潘曉璐 我一進(jìn)店門吭服,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人蝗罗,你說我怎么就攤上這事艇棕。” “怎么了串塑?”我有些...
    開封第一講書人閱讀 156,872評論 0 347
  • 文/不壞的土叔 我叫張陵沼琉,是天一觀的道長。 經(jīng)常有香客問我桩匪,道長打瘪,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,415評論 1 283
  • 正文 為了忘掉前任傻昙,我火速辦了婚禮闺骚,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘妆档。我一直安慰自己僻爽,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,453評論 6 385
  • 文/花漫 我一把揭開白布贾惦。 她就那樣靜靜地躺著胸梆,像睡著了一般。 火紅的嫁衣襯著肌膚如雪须板。 梳的紋絲不亂的頭發(fā)上碰镜,一...
    開封第一講書人閱讀 49,784評論 1 290
  • 那天,我揣著相機與錄音习瑰,去河邊找鬼绪颖。 笑死,一個胖子當(dāng)著我的面吹牛杰刽,可吹牛的內(nèi)容都是我干的菠发。 我是一名探鬼主播,決...
    沈念sama閱讀 38,927評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼贺嫂,長吁一口氣:“原來是場噩夢啊……” “哼滓鸠!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起第喳,我...
    開封第一講書人閱讀 37,691評論 0 266
  • 序言:老撾萬榮一對情侶失蹤糜俗,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后曲饱,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體悠抹,經(jīng)...
    沈念sama閱讀 44,137評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,472評論 2 326
  • 正文 我和宋清朗相戀三年扩淀,在試婚紗的時候發(fā)現(xiàn)自己被綠了楔敌。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,622評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡驻谆,死狀恐怖卵凑,靈堂內(nèi)的尸體忽然破棺而出贝淤,到底是詐尸還是另有隱情好唯,我是刑警寧澤,帶...
    沈念sama閱讀 34,289評論 4 329
  • 正文 年R本政府宣布尽狠,位于F島的核電站象对,受9級特大地震影響黑忱,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜勒魔,卻給世界環(huán)境...
    茶點故事閱讀 39,887評論 3 312
  • 文/蒙蒙 一甫煞、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧沥邻,春花似錦危虱、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至邮利,卻和暖如春弥雹,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背延届。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工剪勿, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人方庭。 一個月前我還...
    沈念sama閱讀 46,316評論 2 360
  • 正文 我出身青樓厕吉,卻偏偏與公主長得像酱固,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子头朱,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,490評論 2 348

推薦閱讀更多精彩內(nèi)容