简体   繁体   English

Unity3D使窗口透明并单击

[英]Unity3D make window transparent and click-through

Im looking for a way to make a Unity3D game and make the window transparent and click-through when I dont click some game stuff(like buttons or objects with colliders) 我正在寻找一种方法来制作Unity3D游戏,并在不单击某些游戏内容(例如按钮或带有碰撞体的对象)时使窗口透明并实现点击

I found this post: https://forum.unity.com/threads/solved-windows-transparent-window-with-opaque-contents-lwa_colorkey.323057/ 我发现了这篇文章: https : //forum.unity.com/threads/solved-windows-transparent-window-with-opaque-contents-lwa_colorkey.323057/

And that help me a lot. 那对我有很大帮助。 In fact there's an answer there to toggle between click-through and non-click-trough 实际上,有一个答案可以在点击型和非点击型之间切换

And there's my problem. 还有我的问题。 Using that script, when Im over an object with collider, the mouse position is inverted in the x axis: https://i.stack.imgur.com/70CdC.gif 使用该脚本,当将Im放在具有碰撞器的对象上时,鼠标位置将在x轴上反转: https : //i.stack.imgur.com/70CdC.gif

I tryed everything I could, but I dont really understand Windows api, so I cannot fix it. 我尽力了,但是我不太了解Windows api,因此无法修复。

Can someone tell me what should I fix? 有人可以告诉我该怎么解决?

Here's the code I'm using: 这是我正在使用的代码:

using System;
using System.Runtime.InteropServices;
using UnityEngine;

[RequireComponent (typeof (Camera))]
public class TransparentWindow : MonoBehaviour
{
[SerializeField]
private Material m_Material;

[SerializeField]
private Camera mainCamera;

private bool clickThrough = true;
private bool prevClickThrough = true;

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("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", EntryPoint = "SetWindowPos")]
private static extern int SetWindowPos(IntPtr hwnd, int hwndInsertAfter, int x, int y, int cx, int cy, int uFlags);

[DllImport("Dwmapi.dll")]
private static extern uint DwmExtendFrameIntoClientArea(IntPtr hWnd, ref MARGINS margins);

const int GWL_STYLE = -16;
const uint WS_POPUP = 0x80000000;
const uint WS_VISIBLE = 0x10000000;
const int HWND_TOPMOST = -1;

int fWidth;
int fHeight;
IntPtr hwnd;
MARGINS margins;

void Start()
{
    mainCamera = GetComponent<Camera> ();

    #if !UNITY_EDITOR // You really don't want to enable this in the editor..

    fWidth = Screen.width;
    fHeight = Screen.height;
    margins = new MARGINS() { cxLeftWidth = -1 };
    hwnd = GetActiveWindow();

    SetWindowLong(hwnd, GWL_STYLE, WS_POPUP | WS_VISIBLE);
    SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, fWidth, fHeight, 32 | 64); //SWP_FRAMECHANGED = 0x0020 (32); //SWP_SHOWWINDOW = 0x0040 (64)
    DwmExtendFrameIntoClientArea(hwnd, ref margins);

    Application.runInBackground = true;
    #endif
}

void Update ()
{
    // If our mouse is overlapping an object
    RaycastHit hit = new RaycastHit();
    clickThrough = !Physics.Raycast (mainCamera.ScreenPointToRay (Input.mousePosition).origin,
            mainCamera.ScreenPointToRay (Input.mousePosition).direction, out hit, 100,
            Physics.DefaultRaycastLayers);

    if (clickThrough != prevClickThrough) {
        if (clickThrough) {
            #if !UNITY_EDITOR
            SetWindowLong(hwnd, GWL_STYLE, WS_POPUP | WS_VISIBLE);
            SetWindowLong (hwnd, -20, (uint)524288 | (uint)32);//GWL_EXSTYLE=-20; WS_EX_LAYERED=524288=&h80000, WS_EX_TRANSPARENT=32=0x00000020L
            SetLayeredWindowAttributes (hwnd, 0, 255, 2);// Transparency=51=20%, LWA_ALPHA=2
            SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, fWidth, fHeight, 32 | 64); //SWP_FRAMECHANGED = 0x0020 (32); //SWP_SHOWWINDOW = 0x0040 (64)
            #endif
        } else {
            #if !UNITY_EDITOR
            SetWindowLong (hwnd, -20, ~((uint)524288) | ((uint)32));//GWL_EXSTYLE=-20; WS_EX_LAYERED=524288=&h80000, WS_EX_TRANSPARENT=32=0x00000020L
            SetWindowLong(hwnd, GWL_STYLE, WS_POPUP | WS_VISIBLE);
            SetLayeredWindowAttributes (hwnd, 0, 255, 2);
            SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, fWidth, fHeight, 32 | 64); //SWP_FRAMECHANGED = 0x0020 (32); //SWP_SHOWWINDOW = 0x0040 (64)
            #endif
        }
        prevClickThrough = clickThrough;
    }
}

void OnRenderImage(RenderTexture from, RenderTexture to)
{
    Graphics.Blit(from, to, m_Material);
}}

I hope someone here can help me! 我希望这里有人可以帮助我! :( Thanks! :( 谢谢!

This worked for me. 这对我有用。

First, you only need one call of SetWindowLong. 首先,您只需要调用一次SetWindowLong。
Then, use (-20) instead of GS_STYLE for the 'else' half of the statment. 然后,使用(-20)代替GS_STYLE作为语句的“ else”一半。 Like this: 像这样:

void Update ()
{    
    // Raycast stuff

    if (clickThrough != prevClickThrough) {
        if (clickThrough) {
            #if !UNITY_EDITOR
            SetWindowLong (hwnd, -20, (uint)524288 | (uint)32);
            //other code
            #endif
        } else {
            #if !UNITY_EDITOR
            SetWindowLong(hwnd, -20, WS_POPUP | WS_VISIBLE);
            //other code
            #endif
        }
        prevClickThrough = clickThrough;
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM