• Register

Studied multimedia design, dreamed of making games since decades - now makes them for a living. I like to experiment with traditional gameplay in order to create something unique. Chocolate is my coffee.

Latest Media

We're sorry, but no images, videos or audio files have been added to this gallery.

If you would like to share media with the community, sign up and you can.

Blog RSS Feed Report abuse Latest Blog: Unity3D and Linux support via Wine

0 comments by kaskade on Jun 7th, 2012

I wrote this article for the Seven Day FPS challenge originally.

I guess a lot of you will use Unity3D, as it is a nice tool and making an FPS with it is pretty easy. I would use it, too, if I would have time to participate. Nonetheless, here is a little gem of wisdom I'd like to share: Unity works in Linux via Wine, but not perfectly. If you don't need mouse movement, I guess you're fine, but as soon as you want that funky look around camera control via mouse you love in your modern FPSes, the bad news is that under Wine the following code (C#) doesn't do what you expect:
transform.RotateAround(Vector3.up, Input.GetAxis("Mouse X") * horizontalSpeed * sensitivity);
It won't rotate, as Input.GetAxis("Mouse X") (and "Mouse Y", too) will always return 0. Okay, you say, perhaps I just want to use Input.mousePosition and calculate the delta between the mouse position from last frame to this frame? Well, that works, but only if you don't use Screen.lockCursor = true - which unfortunately is the only way in Unity to reposition the cursor (it transfers it to the center of the game window every frame). You could also use Screen.showCursor = false, but of course it has the problem that the cursor sooner or later will drop out of the window or hit the screen's borders.

So, what is the solution here? The one I found lies in this forum thread (Unity3D support forum) - but if you know a better and simpler one, please share! Anyway, this is what's going on:

  • Get the mouse position via the user32.dll (so be careful to only use this code for the Windows version - use #if UNITY_STANDALONE_WIN for that).
  • Get the delta mouse movement by subtracting the last mouse position from the screen center.
  • Reposition the cursor to the screen  center via user32.dll.
  • Hide the mouse cursor via Screen.showCursor = false.

One little problem with this approach is the fact that I didn't find a way to get the exact center of the game window in the Unity editor (because you can move it around), so sometimes the "center" is outside of this window, but I guess you can circumvent that by using the normal Input.GetAxis("Mouse X") in the editor. Nonetheless, here is the code I use:

First, the WindowsCursorHandling.cs (most parts blindly copied from the aforementioned thread) - you have to add that component to a gameobject in the scene.

csharp code:
using UnityEngine;

#if UNITY_STANDALONE_WIN
using System.Collections;
using System.Runtime.InteropServices;

public class WindowsCursorHandling : MonoBehaviour
{
 [DllImport( "user32.dll", CharSet = CharSet.Auto, ExactSpelling = true )]
 [return: MarshalAs( UnmanagedType.Bool )]
 public static extern bool ClipCursor( ref RECT rcClip );
 [DllImport( "user32.dll" )]
 [return: MarshalAs( UnmanagedType.Bool )]
 public static extern bool GetClipCursor( out RECT rcClip );
 [DllImport( "user32.dll" )]
 static extern int GetForegroundWindow( );
 [DllImport("user32.dll")]
 [return: MarshalAs( UnmanagedType.Bool )]
 static extern bool GetWindowRect( int hWnd, ref RECT lpRect );
 [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
 public static extern int SetCursorPos(int x, int y);
 [DllImport("user32.dll")]
 [return: MarshalAs( UnmanagedType.Bool )]
 public static extern bool GetCursorPos(out POINT point);

 private static RECT currentClippingRect;
 private static RECT originalClippingRect = new RECT( );
 private static bool isClipped = false;

 public static int centerX;
 public static int centerY;

 [StructLayout( LayoutKind.Sequential )]
 public struct RECT
 {
  public int Left;
  public int Top;
  public int Right;
  public int Bottom;
  public RECT( int left, int top, int right, int bottom )
  {
   Left = left;
   Top = top;
   Right = right;
   Bottom = bottom;
  }
 }

 [StructLayout( LayoutKind.Sequential )]
 public struct POINT
 {
  public int x;
  public int y;
  public POINT( int X, int Y )
  {
   x = X;
   y = Y;
  }
 }

 void Start()
 {
  GetClipCursor( out originalClippingRect );
  centerX = originalClippingRect.Left + (originalClippingRect.Right - originalClippingRect.Left) / 2;
  centerY = originalClippingRect.Top + (originalClippingRect.Bottom - originalClippingRect.Top) / 2;
 }

 public static void StartClipping()
 {
  if (isClipped)
   return;

  var hndl = GetForegroundWindow( );
  GetWindowRect( hndl, ref currentClippingRect );
  ClipCursor( ref currentClippingRect);

#if UNITY_EDITOR
  centerX = Screen.width / 2;
  centerY = Screen.height / 2;
#else
  centerX = currentClippingRect.Left + (currentClippingRect.Right - currentClippingRect.Left) / 2;
  centerY = currentClippingRect.Top + (currentClippingRect.Bottom - currentClippingRect.Top) / 2;
#endif
  isClipped = true;
 }

 static public void CenterCursor()
 {
  SetCursorPos(centerX, centerY);
 }

 void OnApplicationQuit()
 {
  StopClipping();
 }
 public static void StopClipping()
 {
  isClipped = false;
  ClipCursor(ref originalClippingRect);
 }
}
#else
public class WindowsCursorHandling : MonoBehaviour
{
}
#endif

And this is how it then looks in my Camera Controller for FPS mouse movement:

csharp code:
#if UNITY_STANDALONE_WIN
 WindowsCursorHandling.POINT p;
 WindowsCursorHandling.GetCursorPos(out p);
 float factorX = 40.0f * (p.x - WindowsCursorHandling.centerX) / (float)Screen.width;
 float factorY = -40.0f * (p.y - WindowsCursorHandling.centerY) / (float)Screen.width;
 WindowsCursorHandling.CenterCursor();
 transform.RotateAround(Vector3.up, factorX * horizontalSpeed);
#else
 transform.RotateAround(Vector3.up, Input.GetAxis("Mouse X") * horizontalSpeed);
#endif
// do similar stuff with "Mouse Y" movement

The magic number 40.0f was found by trial-and-error, so I don't know if it's really the best value for every PC configuration. You still need the cursor hiding stuff somewhere, and of course call WindowsCursorHandling.StartClipping() at initialization. Whenever I wanted to just call Screen.lockCursor I now call this function instead:

csharp code:
static public void SetCursorHidden(bool hide)
{
#if UNITY_STANDALONE_WIN
 Screen.showCursor = !hide;
 if (hide)
  WindowsCursorHandling.StartClipping();
 else
  WindowsCursorHandling.StopClipping();
#else
 Screen.lockCursor = hide;
#endif
}

That's it!

Groups
Bundeals

Bundeals

Entertainment & Press group with 210 members, open to all members

Keep up with the latest news on the ever-growing number of game bundles, bargains and deals across the interwebs. Know of a deal we don't? Let us know...

Rat King Entertainment

Rat King Entertainment

Developer with 2 members, invitation only

Hi there. So, this is “Rat King Entertainment”, the game development company by Jana Reinhardt and Friedrich Hanisch. We had a hobby team named SONEN...

Post a Comment
click to sign in

You are not logged in, your comment will be anonymous unless you join the community today (totally free - or sign in with your social account on the right) which we encourage all contributors to do.

2000 characters limit; HTML formatting and smileys are not supported - text only

Level
Avatar
Avatar
Offline Since
May 23, 2013
Country
Germany Germany
Gender
Male
Age
30
Member Watch
Track this member
Statistics
Activity Points
252
Rank
7,620 of 328,176
Watchers
1 member
Time Online
1 second
Comments
41
Site Visits
3,611
Profile Visitors
1,779 (2 today)
Contact
Homepage
Fholio.de
Private Message
Send Now
Email
Members Only
Twitter

Latest tweets from @ratkingslair

@Seemo No problems, thanks for creating the game! ;-)

May 22 2013, 4:22pm

. @zapakitul Only one month later ... here's the transcript! T.co ;-)

May 22 2013, 6:49am

rottenhedgehog
rottenhedgehog friends since Feb 8, 2012
PsySal
PsySal friends since Nov 21, 2012
dcgc
dcgc friends since Jan 17, 2013
qubodup
qubodup friends since Dec 5, 2012
Sosowski
Sosowski friends since Jun 20, 2012
pekuja
pekuja friends since Jun 20, 2012
Tangrin
Tangrin friends since Dec 28, 2012
LegacyCrono
LegacyCrono friends since Aug 17, 2012