Tag «Unity3D»

Ludum Dare 25: Tale of Scale – Post Mortem

On December 15th, Ludum Dare 25 started. As usual, this 48h game making compo was an interesting experience, as exciting and awesome as it was soul-crushing. But this might be just me.

Like before, I didn't have the right idea for the theme. This time it was "You are the Villain", which was a better theme than usual, but unfortunately it only triggered gameplay concepts for me which all belong into the "that was already made before" category. So the first thing coming into my mind was "Dungeon Keeper", and as much as I'd like to do a game similar to this awesome piece of gaming history, it just would be a clone without the right amount of innovation (or would it?). Among the other ideas I had were a "Pirates!" roguelike, a game where you control four bandits at once (robbing innocents and wandering around) and a board game creator where you're the dungeon master placing the monsters (think "HeroQuest" or so).

1

None of these ideas were the incentive for me to actually start developing (although I still like them). In my mind, I combined them, added features and the result got bigger and bigger, and after finally deciding that it would be too much of a hassle, I started at zero again. Then I came back to a thought I had days before, namely the thought that often, good ideas for games (mostly puzzle platformers) are those which are inspired by childrens' fantasies. So I imagined a bit what a child could think, and being able to grab the moon with the fingertips and move it around just like that, well, that seemed like a good candidate. At this point, the theme was still in the back of my head, but I tried to ignore it mostly as it obviously would just hinder me to actually develop anything. I never was good in the "Theme" category, and for that I'm sorry, but I don't think it's the category I want to shine, really.

I tried to create a Unity3D prototype out of that idea with the moon. Of course, prototypes become the real game eventually when doing a game jam, but first I wanted to see if I could actually create something like that. The main problem to begin with was the scale of the object currently grabbed, as it always has to be the same size for the player, no matter how far or near it would be away. I read something about the focal length of a camera before and I thought I had to factor this in in any case. I experimented (using some basecode I already announced in my "I'm in!" post) and searched on the internet, but it just wouldn't work right. The object's subjective size didn't stay constant, and being very frustrated, I stopped after a while.

Thus, I re-evaluated the idea of the four bandits. This one would follow the theme and I'd really like being able to control a group of (evil) adventurers - in first person perspective! In order to make it easier for myself, I started programming the movement (again in Unity3D), which would be along the cardinal directions only and also on a grid. Just like those age old games you might know, "Dungeon Master", "Eye of the Beholder" or "Legend of Grimrock". In the end, the movement worked somehow, and you could add NPCs to your party, and press a button to see all four viewports at once. Probably I could have made a more or less full game out of it, but at this point I didn't see how I could add "fun" easily and I stopped yet again.

prototype 2second prototype, no fun

With the thought of fun being the most important part of it and without really expecting any results for this Ludum Dare anymore, I got back to the first prototype, and suddenly, the old problem was gone. Thinking about the focal length was a dead-end, and just getting rid of it was the way to get it work. The only problem now was the collision detection of an object that would get bigger the further it goes. Using Unity3D's SphereCast() was the wrong direction, because the size of the collision sphere would be always the same. So now CheckSphere() gets called with a gradually increasing size of the radius parameter, and it does that a lot of times every frame - because of the simple nature of the rest of the game, this was possible without any noticable performance hits (at least on my computer). Of course, this means that every object basically has an additional bounding sphere, and that's why most objects sometimes don't behave as expected, especially those which don't have uniform dimensions.

prototype 1first prototype, working

I uploaded the first prototype of the game - just a simple demonstration of the gameplay - late in the night, and those who actually started it and "got it", said it could be awesome. Yay, motivation! Also, I earned myself some sleep. The next day I "only" had to make levels and fix any occuring bug. Also, story. Also, sound. Also, ...

I planned five levels at the beginning, and because of some very sad events before Ludum Dare, I didn't think about it too long when I realized that I wouldn't have time for all of them - as one of the levels would had have a kindergarten setting. So, three levels were made (in 3dsmax), and they describe how the protagonist is a kid with just an overly active imagination, and how this leads to an unfortunate outcome. I didn't have time for more, and the ones I made aren't really balanced/tested, so I am sorry for that. On the other side I am just relieved that the main gameplay works and can maybe be the foundation of a cool game; the Ludum Dare version of the finally named game "Tale of Scale" is mainly a sandbox game which happens to have a subtly communicated goal in each level.

2the end result: Tale of Scale

A short summarization of What-Went-Bad:

  • The start, or rather the theme. Either it is the start of a game for me, or it just stands in my way. Harumph. I squeezed the theme into the final game, but as most people won't play it through, they probably will wonder where it actually is. I got a bit inspired by the movie "Looper".
  • I still can't make music. I tried composing some once or twice before, but I'm always embarrassed by my own efforts, so I don't ever get over a certain point.
  • I don't have a cool base code which actually would free me of the burden to do some stupid and boring stuff again and again. At least that's a learning and can be helped ... some day.

And What-Went-Good?

  • The idea was cool enough to let people ignore the crude levels and graphics, hehe.
  • I actually managed to make three levels, even in the timeframe I wanted to make them. Seems like I finally get the hang on estimating such things, and this is one of the things a game jam really can help with.
  • I made most of the sounds myself with a microphone, and they sound okay enough. Nice.

That's it! Thanks for reading, and don't forget to play the game (here's the entry page) - or at least watch this gameplay video:

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!