当前位置: 代码网 > it编程>游戏开发>游戏引擎 > Unity-Demo游戏实现桌面小宠物

Unity-Demo游戏实现桌面小宠物

2025年08月17日 游戏引擎 我要评论
看到网上有用unity做的桌面小宠物,就自己搜了些资料自己做了一个小demo。核心功能实现简单说一下思路,有一个脚本跟一个shader,通过脚本和shader负责将unity运行时的背景调成透明色。这

看到网上有用unity做的桌面小宠物,就自己搜了些资料自己做了一个小demo。

核心功能实现

简单说一下思路,有一个脚本跟一个shader,通过脚本和shader负责将unity运行时的背景调成透明色。这个是通过调颜色来进行了。具体原理也不清楚,查了查资料大概是这样

  • 窗口透明化与无边框

    • 通过windows api调用setwindowlongdwmextendframeintoclientarea实现透明背景和隐藏边框,需在相机设置中将clear flags设为solid color且透明度为01。
    • 注意:背景色需与模型边缘颜色相近以避免毛边(如0x00bgr格式的colorref值)2。
  • 交互逻辑

    • 点击穿透‌:通过检测鼠标坐标与模型碰撞器实现交互(如点击播放挠痒动画)15。
    • 拖拽限制‌:动态计算模型碰撞器与屏幕边缘距离,使用mathf.clamp限制移动范围2。

代码部分

shader

shader "custom/maketransparent" {
  properties {
    _maintex ("base (rgb)", 2d) = "white" {}
    _transparentcolorkey ("transparent color key", color) = (0,1,0,1)
    _transparencymargin ("transparency margin", float) = 0.01 
  }
  subshader {
    pass {
      tags { "rendertype"="opaque" }
      lod 200
    
      cgprogram

      #pragma vertex vertexshaderfunction
      #pragma fragment pixelshaderfunction
    
      #include "unitycg.cginc"

      struct vertexdata
      {
        float4 position : position;
        float2 uv : texcoord0;
      };

      struct vertextopixeldata
      {
        float4 position : sv_position;
        float2 uv : texcoord0;
      };

      vertextopixeldata vertexshaderfunction(vertexdata input)
      {
        vertextopixeldata output;
        output.position = unityobjecttoclippos (input.position);
        output.uv = input.uv;
        return output;
      }
    
      sampler2d _maintex;
      float3 _transparentcolorkey;
      float _transparencymargin;

      float4 pixelshaderfunction(vertextopixeldata input) : sv_target
      {
        float4 color = tex2d(_maintex, input.uv);
      
        float deltar = abs(color.r - _transparentcolorkey.r);
        float deltag = abs(color.g - _transparentcolorkey.g);
        float deltab = abs(color.b - _transparentcolorkey.b);

        if (deltar < _transparencymargin && deltag < _transparencymargin && deltab < _transparencymargin)
        {
          return float4(0.0f, 0.0f, 0.0f, 0.0f);
        }

        return color;
      }
      endcg
    }
  }
}

c#

using system;
using system.runtime.interopservices;
using unityengine;

public class transparentwindow : monobehaviour
{
    [serializefield] private material m_material;

    private struct margins
    {
        public int cxleftwidth;
        public int cxrightwidth;
        public int cytopheight;
        public int cybottomheight;
    }

    [dllimport("user32.dll")]
    private static extern intptr getactivewindow();

    [dllimport("user32.dll")]
    private static extern int setwindowlong(intptr hwnd, int nindex, uint dwnewlong);

    [dllimport("dwmapi.dll")]
    private static extern uint dwmextendframeintoclientarea(intptr hwnd, ref margins margins);

    [dllimport("user32.dll", entrypoint = "setwindowpos")]
    private static extern int setwindowpos(intptr hwnd, intptr hwndinsertafter, int x, int y, int cx, int cy,
        int uflags);

    [dllimport("user32.dll")]
    static extern bool showwindowasync(intptr hwnd, int ncmdshow);

    [dllimport("user32.dll", entrypoint = "setlayeredwindowattributes")]
    static extern int setlayeredwindowattributes(intptr hwnd, int crkey, byte balpha, int dwflags);

    [dllimport("user32.dll")]
    private static extern bool setforegroundwindow(intptr hwnd);

    const int gwl_style = -16;
    const int gwl_exstyle = -20;
    const uint ws_popup = 0x80000000;
    const uint ws_visible = 0x10000000;

    const uint ws_ex_topmost = 0x00000008;
    const uint ws_ex_layered = 0x00080000;
    const uint ws_ex_transparent = 0x00000020;

    const int swp_framechanged = 0x0020;
    const int swp_showwindow = 0x0040;
    const int lwa_alpha = 2;

    private intptr hwnd_topmost = new intptr(-1);

    private intptr _hwnd;

    void start()
    {
#if !unity_editor
    margins margins = new margins() { cxleftwidth = -1 };
    _hwnd = getactivewindow();
    int fwidth = screen.width;
    int fheight = screen.height;
        setwindowlong(_hwnd, gwl_style, ws_popup | ws_visible);
        //setwindowlong(_hwnd, gwl_exstyle, ws_ex_topmost | ws_ex_layered | ws_ex_transparent);//若想鼠标穿透,则将这个注释恢复即可
        dwmextendframeintoclientarea(_hwnd, ref margins);
        setwindowpos(_hwnd, hwnd_topmost, 0, 0, fwidth, fheight, swp_framechanged | swp_showwindow); 
        showwindowasync(_hwnd, 3); //forces window to show in case of unresponsive app    // sw_showmaximized(3)
#endif
    }

    void onrenderimage(rendertexture from, rendertexture to)
    {
        graphics.blit(from, to, m_material);
    }
}

具体步骤

1.新建一个material(材质球),选择刚建立的shader:

2.将刚写的c#脚本挂在摄像机上,摄像机的clear flags模式选择solod color,并将刚建立的材质球挂在脚本上。

3.摄像机的background属性要和材质球的transparent color key属性一致:

4.这里要注意一个点,unity19以上的版本需要设置一个东西。在playersetting中将这个usedxgiflipmodelswapchainford3d11取消勾选。

这样就可以实现窗口透明了,然后在场景里加一个模型跟动作就好啦

总结

到此这篇关于unity-demo游戏实现桌面小宠物的文章就介绍到这了,更多相关unity-demo桌面小宠物内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com