mardi 7 mai 2013

Personnal project : Level generator

Currently, I am trying a lot of rogue-like and rogue-inspired games.
These games most of the time offer a fresh gameplay when they are mostly based on generation.
I love random generation in games. They give the most surprises, force you to play some different ways and teach you to improvise. You can't know a generated game by heart.
The balance has to be good between what is generated, and what is always the same.

But there is one thing that seem to always please the player : level generation at runtime.

So I gave it a shot. My goal was a "as modulable as possible" generator for Unity.

I'm not giving the code this time, but I'm going to give an example, cons, and explain.


First, the example (in a 20x20 grid) :

These levels are generated by using blocks either fully open (floor) or fully closed (wall)




How it works :
We have :
  • a list of blocks that can be placed. Each block has a list of doors (can I go out by going north ? west ? east ? and south ?) and a probability to be picked.
  • a grid of booleans to know if a position is used or not.


We pick a starting block that is placed at the center of the level.
Then, for each door this block has (north, west, east and/or south), we pick a new random block, and we rotate this block so the two doors are communicating.

Do this again for your new block, and do this again for your new new block, etc... until there are no new block needed.


Cons :
  • It's slow. It takes about 30 seconds to generate a level in a 50x50 grid. So you must find a way to take this time from the player without him noticing.
  • A block HAS to be squared, because of the rotation, a recangle shape will provoke empty spaces.


Pros :
  • It can be used as a coroutine (as shown above) so you can generate the next level while the player plays the current level.
  • You can put an element of a room or a full room in a block ; there is no size limit, so you can use prebuilt rooms instead of generating a labyrinth.
  • Ease-of-use thanks to the editor.
With the first version of the editor, the user can easily change the probability of each block, and create new blocks.

What's next ?

Now that I'm writing this, I realize that some features could be added.
I could allow the user to disable the rotation of the blocks, so they can use rectangular blocks.
It would also be interesting to be able to add bigger blocks, that takes several places in the grid. So the user can used both prefab rooms AND generate labyrinths. (Half-way done here, I need to add the rotations)
It would be really interesting to add a third dimension to the levels generated.



jeudi 2 mai 2013

Low cost special effect : Shaking the camera

Ouya isn't powerful.
It's small, it's pretty, it's cheap, and it's very interesting for developers and curious players, but don't expect groundbreaking graphics compared to other consoles. That's not what it is for.

So, when you are afraid of using particles or shaders, you are looking for any low-cost effect possible.

My personnal favorite is shaking the camera.
It's easy, it's simple, and it just works.

So today, I'm offering you my own easy-to-implement camera shaker.
Just attach it to the camera, disable the script, and when you want to shake it, set magnitude, duration, and enable it.

Plus, it tries not to interfere with your camera controller !


using UnityEngine;
using System.Collections;

[AddComponentMenu("Scripts/Camera/Shaker")]
public class Shaker : MonoBehaviour {
public float Magnitude;
public float Duration;
private float CurrentMagnitude;
private float startTime;

private Vector3 OriginalPosition;
private Vector2 ShakerVector=Vector2.one;
private float facteur;
// Update is called once per frame
void OnEnable()
{
startTime=Time.time;
CurrentMagnitude=Magnitude;
facteur=-Magnitude/Duration;
OriginalPosition=transform.position;
}
//Avant de lancer les prochaines updates
void OnPostRender()
{
transform.position=OriginalPosition;
if(CurrentMagnitude<=0) 
{
enabled=false;
}
}

//after the camera controller has done its job
void LateUpdate()
{
CurrentMagnitude = facteur*(Time.time-startTime)+Magnitude;
OriginalPosition=transform.position;
transform.position+=new Vector3(ShakerVector.x*CurrentMagnitude*Random.Range(-1f,1.01f),ShakerVector.y*CurrentMagnitude*Random.Range(-1f,1.01f),0f);
}

public void Shake(float Magnitude,float Duration)
{
this.Magnitude = Magnitude;
this.Duration=Duration;
enabled=true;
}
}