Tag «Unity3D»

Unity3D and Linux support via Wine

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

Hallo!

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.

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:

#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:

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!

Wunderworld post-mortem

 (This post was written for ludumdare.com originally.)

Ludum Dare 23, wow! This time, it was super-awesome, even though I was a little reluctant to even participate. One weekend before, we had made another 48h game ("The Sun Is Deadly" for the IndieBuskers game jam), and I wasn't sure if I would have some energy left to create something equally cool, or at least have fun making another game.

Thankfully, I did!

One of the primary reasons why I not only started cheerfully but also was in a pretty good mood throughout the whole jam was the fact that I made something I really wanted to create. I saw a video of "Delver" some time ago, and although – or because – I don't like how the combat is far-range only, it made me wanting to develop my own Ultima-inspired game. I played "Ultima Underworld I – Stygian Abyss" pretty late, but I bought the second part, "Labyrinth of Worlds", when it came out in Germany (with no understanding of English texts whatsoever), and it is still one of my favourite games.

As I didn't want to just rip off the Delver guy, I mixed my Ludum Dare entry with another passion of mine: game development, what a surprise! I was thinking for some years now about creating an easy-to-use level design tool; it should be very restricted regarding the basic elements, but possible to design some story-heavy games. The idea really started when I searched for a subject for my university diploma project, and I was always fascinated by the thought of it. For Ludum Dare 23, I didn't know if I could do something like this in just two days, but I knew that it could be very minimalistic this way and still cool. Another part of the reason was the theme, "Tiny World", as it made restricted size and small scope a very helpful design target.

So it became "Wunderworld", which is a mix of "Wunder" ("wonder" in German) and "Underworld". I even wanted to name it "Wultima's Wunderworld" at first, but I didn't find a good enough way to implement a protagonist named Wultima.

Perhaps the question arises, is Wunderworld even a game? I don't know! But I have to commemorate a quote from the book "Game Architecture and Design" by Rollings&Morris, which is:"Rule Number One isn't 'Make sure it's a game.' It's 'Make sure it's fun!'" Thus I didn't care much if my entry would fit perfectly into this (or any other) category. And really, Wunderworld is all about goals, and conflicts, and combat, and exploration – it's just that the player has to define these elements him-/herself. In a sense, it's more like a set of random Lego building blocks.

The fun part for me was the expandability of the concept. All it needs to function are only three things really: walls, fights, and a test mode. The walls were the easiest thing to do, although I had my own little problems with Unity's MeshCombine script. The test mode (became the "Play Mode" later) with a fully functional player character controller did cost me some hours, but it was worth the time (especially because the game was playable then, and never stopped being playable and fun afterwards). Last but not least came the fighting – after modelling some enemies, which make use of nearly the same character controller, adding some really basic AI was a nice finger exercise.

When I was done implementing these three things, the game was basically finished and I could just refine and add stuff, like a goal, horizontal windows, health potions or gates which open after the death of all enemies. Right after the compo, I added stairs and lava, which was a matter of minutes, not hours.

Another reason why I was so relaxed during the compo was that I didn't have to do levels. The levels were the cause of minor burnouts during my other Ludum Dare entries in 3D ("Tri" and "Soliloquy"), which were puzzle platformers and thus relied heavily on level design, which I had to do in a 3D modeling program. But this time the players would have to create the levels for themselves, and it would also be very easy and even fun to design them.

(By the way, if Wunderworld would have required me to make a level, I'd have done it right from the beginning this time around, instead of afterwards, hours before the deadline. This is a lesson I learned from the other Ludum Dares.)

The editor of Wunderworld is very basic. In order to keep me sane I resigned doing submenus and subscreens; instead, I've gone the KISS way. I initially planned to let the player adjust the enemies' damage, the potions' health values and so on, but it would be too much for the two days. And without too much options, everything fits nicely on one screen, too. All it consists now is a list of items the player can choose from, and a text area for the file name, and it's still enough to create some nice levels. Of course, there always will be people who will miss several things regarding settings and comfort, but they will have to live with that or just download Unity/UDK/whatever, hehe.

Another benefit of the "Tiny World" theme was my lack of urge to optimize the code. Sure, with a standard level of the size 10x10x10, you have 1000 blocks. But thanks to the MeshCombine script from Unity – I use it on every slice of blocks – the amount of draw calls is pretty low. Altogether the "think small" direction of the theme helped me to be content with a small, working base game, and diversify it from there – instead of trying to make a rich, broad game which would have needed much more work. So, remember to extend and refine certain gameplay elements, and not the whole gameplay in itself – it would be a bottomless pit.

On the other hand, Wunderworld is predestined to offer a very wide range of gameplay elements. It could be expanded in 1000 ways! Without much effort, one could make an FPS, an RPG, an Adventure or even a puzzle with it (or even a combination of those), if I would have the time/motivation to add the right block types. Of course, this would need more work overall, as for example an RPG isn't much without the ability to add NPCs with texts, or stats. But the general foundation is given for something like this, and I think that's exciting.

So, what went wrong, what did I really learn?

I already mentioned the character controller, which I created very quickly at the beginning and was working somehow; yet I was deeply dissatisfied with the way the jumping behaved. It then needed some hours of redoing the whole thing, but in the end it worked more than okay and now I'm comparatively sure how to do nice and predictable character movement for 48h game.

There was also a certain lack of time before the deadline, when I had more than enough stuff on my "would be nice to have" list, and preset levels was one of them. It should have been much higher on this list, because even though I really had a test level, I lost it in the process of deploying. And even if it would have survived, I had no way to fit it into the webplayer version, so it would have been for the standalone only (which only few Ludum Darers download nowadays, according to my experience).

My biggest weak point regarding the compo is music. I managed to make some decent sounds via bfxr, but I still don't know how to create non-generic music via a sophisticated tool. And although I used inudge.net for my older Ludum Dare entries, I want a more fulfillling experience in this regard nowadays. Thus I got FL Studio now and look forward to learn a bit about it, but I don't know when I will have the time. Meh.

There were several other problems, which are more technical tidbits but nonetheless interesting details. For example, while the navigating through the level slices via Q and E is pretty straightforward, people complained about the lack of overview – they have to remember how the slice above the current slice looks, which isn't very userfriendly. I still don't know how to circumvent this problem in an elegant way. Also, the possibility to resize the level would be nice, or the support for an improved AI with far-range combat.

Until recently I also had no idea how to allow sharing levels via the webplayer version, thanks to the security problems. The standalone has a separate folder with simple text files which contain the level data, so you can trade them with others. But the webplayer saves its data in the PlayerPrefs (being the registry under Windows), which means that sharing levels is much more work there. Thanks to the idea of a friend I added level sharing by copy&paste in the post compo version – just press "Export", get a string and post it. Or press "Import" and paste the string from someone else.

On the art side one could argue that 8x8 pixel textures aren't really perfect for a block of 2x2 meters, but somehow it emphasized the "Tiny World" theme once again, I think. What I really would want here is the support for custom textures, which needs some thinking about the internal workings of Wunderworld. Another friend (Björn Grunewald) already tried to create 16x16 versions of some of the textures.

And what's the conclusion?

Until now, this was the most satisfying and fun Ludum Dare for me. I wasn't overly stressed, and never had the feeling of not doing enough or doing too much. Even shortly after the IndieBuskers jam my motivation was really high, and that means that there can't be too much game jams in general!

Also, there were no really negative reactions so far, with the complaint of lacking preset levels here and there. Of course, there was the uninformed Kongregate commenter who wrote "guys forget this play minecraft this is a copy of minecraft so play minecraft its way better" (actual hilarious quote), but he apologized later, so it doesn't count anymore, hehe. And, yeah, my game isn't anything like Minecraft, you can't mine and you can't craft – instead, you can build and play, so perhaps should I call it Buildplay. The main difference probably is the possibility to be not only a level designer, but also a game designer in Wunderworld.

As mentioned before, in the new post-compo version you can now import and export levels easily – so it would be awesome if you, dear reader, would make a level and post it in the comments! Lockstep80 and others on Kongregate already made some really great levels, and the creativity in them honestly surprised me.

It must be just a tiny fraction of what Notch feels when he sees all those videos of people showing what they build inside Minecraft, and even this tiny little fraction is so awesome, and exactly the reason why creating Wunderworld was totally worth it.

Oh, and here is a video, showing the gameplay:

Ludum Dare #23: Wunderworld, by Friedrich

(YouTube videos try to set cookies and contact Third Party servers!)

Yout may also want visit the entry page of Wunderworld on Ludum Dare and the project page, with levels created by fans!

LD #22: SOLILOQUY – Post Mortem

(This post mortem can also be found on the official Ludum Dare blog!)

Ludum Dare 22 was somehow pretty exhausting for me, and kind of depressing. I don't exactly know why, but I think that multiple factors brought in.

The weekend before the compo I made a "warm-up game", even though I planned to do it long before PoV announced this kind of thing. I just wanted to make a game in 48 hours in order to help a friend (a 3D artist), who needed a programmer for his university project. The programming part wasn't wasting, but the fact that the game didn't get finished at this weekend (mostly because of my friend :P) left feelings of "incompleteness" inside me, which I hate.

Another thing: I didn't like the theme "Alone", and I still don't think it was the best or even a good theme of the ones in the final voting round. But, as I always have to live up to my own standards I wanted to follow the theme AND make a good game. And this often leads to a status-quo - as long as I don't have the right ideas I won't start, and as long as I don't start I won't have the right ideas. Or something like that. My mind was blocked and I did other things, like playing Skyrim and chatting on IRC (not in #ludumdare, though, that place was CROWDED). Later, I started Unity3D and tried to play out another idea I had days before, about some time manipulation gameplay. It wasn't feasible to do it in Unity3D, but due to the fact I did something concrete (game with 3D environment and FPS controls) I could develop another idea in my brain, which became the concept of the final SOLILOQUY.


I still think the best part of my game is this name! I thought of it before I thought of the gameplay (but it didn't give me any directions), and I liked it so much, I wanted to use it in any case. I'm quite happy nobody else named his/her game the same, too.

Even though I have some experience by participating at Ludum Dare before, I still don't really know how to cut back optimally. The concept of SOLILOQUY demands levels, and levels demand content and art and story and design and choosing colours and making 3D models ... but I knew this would be hard for me, as it was when I made my Ludum Dare 20 game, "TRI". So I decided to do NO textures this time, and it didn't hurt much (on the game's side), but the benefits weren't that great either. I mainly put the levels together in Unity3D instead of 3dsmax (in contrast to TRI), but this didn't help me much, either. Altogether I have six levels now, where I really wanted ten, but at least seven.
The levels don't look that bad (abstract style for the win), even though I chose the colours quite randomly. On the other side, what I don't like much, the levels are all tutorial missions only. You just jump around in the first two, learn using your souls in the levels after that, press some buttons and work together with yourself. After this, the real levels should come, but I didn't have time to do any more content.

I finished the last level three hours before the deadline, and I couldn't do any more creative stuff. I especially failed in doing sounds or anything like music, unfortunately. I thought about using inudge.net again, but it would sound like my other two Ludum Dare games, so I dropped that idea. At least this frustration encourages me to actually learn how to make simple songs with real tools. (Wish me luck.)
The reason why I couldn't do more creative work: This time, Unity3D was my enemy. Sometimes I really had to fight the engine, mostly when it came to the text you see in the game (story & hints) - Unity's GUI system still is awkward to look at, and it has bad effects on the performance. So I used someone's code which displays bitmap fonts via SpriteManager (the original one), but it didn't work out of the box with all my bitmap font generator tools (I decided to use "TWL Theme editor"). After those problems were resolved, at the very end of the process, suddenly my white text became gray in the webplayer version. Argh! I needed nearly an hour to find out why that happened - a plane with alpha (the dark overlay) had the same distance to the camera as the text, and somehow the editor sorted it differently than the webplayer. Whyever that is.

After the mixed (or even bad) feelings I had about my own game, I'm really relieved that people actually liked it! The current feedback is mainly positive, and some things that were criticized are fixed in a post-compo version (on Kongregate, for more attention)! Other things, like the jumping height / range being too crass, are somewhat subjective and unfortunately can't be changed without rearranging some of the levels.
Of course, many people complain about the brain-hurting aspect of the game (gameplay and visuals alike), but that was expected. I could have done the double-soul mechanic with just a picture-in-picture style or something like that, but then the game would lose its uniqueness pretty fast IMHO. Also, as soon as dogbomb does his "I play your game drunk!" video, the whole game visuals will make much more sense, haha.

BTW, if you have a look at the source you will need Unity3D. The indie version should suffice for just reading the C# files and so on, but you need Unity Pro (or its 30 day test version) in order to actually start the game, because I used Render To Texture. Sorry!

Thanks for reading this wall of text, and don't forget to PLAY THE DARN THING!

PS: There also is a video now!

Ludum Dare #22: Soliloquy

(YouTube videos try to set cookies and contact Third Party servers!)