- Home /
What happened to the Slender Guide by alucardj
How to make a Survival Horror game like Slender - Slenderman and Collecting Papers
Hi. Im a big fan of the horror survival game genre, especially the still popular Slender game.
Is there a guide that can help me write my own horror survival game.
I have seen a guide by Jay Kay (alucardj) , but I really need help with understanding how to :
Have a first person character controller on a terrain
set the ambience of the scene
Be able to raycast to pick up objects (like papers)
Have some type of enemy with some simple AI
Have interaction between the character and enemy scripts
Simply load different scenes
include running and having different footstep sounds for walking and running
have a full screen effect like the static in Slender
Would the person who negatively voted me for trying to clean up the constant stream of questions to my scripts kindly explain why you would down vote this my solution to fixing the problem and directing all traffic to one page on the forum ?
Please Explain !
Thanks for P***ing me off and feeling like doing those videos and all this work was a complete waste of time. I saw your vendetta of going through and downvoting all these questions.
This is certainly Not the only and definitive answer for all things Slender.
You should always try and look at a problem from every possible angle (that way you usually find all the ways that things could go wrong too).
Here is a list of links that I made at the time just before writing my guide : CHEC$$anonymous$$ THE FORU$$anonymous$$ PAGE .... SEE THIS IS HOW THIS THING IS GOING TO WOR$$anonymous$$.
Just so that when people cross this page:
I personally did my first steps (and much more) with Alucardjs Slender Guide and I learnt all the basics to what I know now from doing that guide. I've made a few horror games myself now and didn't have to look further than his guide to make them.
Thanks Alucardj for your time and effort. I love horror games, and being able to make my own thanks to you was a great gift.
Hyper.
Answer by AlucardJay · Mar 02, 2013 at 12:55 AM
Well Jay, you should know, as you (that's me!) just finished making a video series of me following my own guide starting with a blank project, so everyone can follow along and see why it works for me and not other people. Some people like myself are visual and aural people, who need a demonstration in more than one dimension to help you understand where you may be going wrong with the guide.
As well as the videos, I am starting a Unity Forum page, where people can come together and help each other with their Survival Horror genre games.
The original guide has nearly 17 000 views, and it keeps growing. With different comments posted over 2 of my main answers, and the explosion of answers to questions that came after my packages were made availabe, it is now almost impossible to follow in a linear way.
So those questions will be closed now, and I shall Not be responding to any more posts there. I am going to post all the latest scripts here, but then am not going to answer any comments on this question either. All future traffic to my 'Slender' Guide is going to be solely through the forum page. Any questions that appear on Unity Answers will also be closed an redirected to the forum page.
While this may seem a little unfair, it is actually a good thing for all of your benefit. Every comment, change and update will appear there, for everyone to read and contribute to. No more searching through different questions just to get different parts of functionality, but everything you could need for starting your own horror survival game will be in one place. Doesn't that sound convenient ?!
But just to start off, and as promised in the videos, I am posting all of the latest scripts here with a link to the Forum page and the Videos. After that, this is the very last time, I shall not respond to any question that has my scripts appearing on Unity Answers. Instead you will feel my wrath for not being able to follow a simple instruction. If you have a problem with one of my scripts, #only ask on the Forum Page# . That is all. I hope everyone (that can happily follow this rule) learns something, expands their knowledge, and begins their own adventure in learning to code and write logic for games.
Have Fun, and Happy Coding.
This is now the only place I shall write answers to problems with my scripts : http://forum.unity3d.com/threads/172415-Slender-Guide-by-alucardj
Here is the body of my guide in written form (link to another post for now with scripts removed) : http://answers.unity3d.com/questions/296068/how-to-make-a-slender-man-follow-character-script.html
Now here are all my current scripts. These are the only scripts I will be posting and keeping up to date. Basically, these are the latest and greatest !
Do Not post a new question on Unity Answers with my scripts
Simply go to the forum thread, and then ask anything you like =]
Here it is again : http://forum.unity3d.com/threads/172415-Slender-Guide-by-alucardj
If you post a new question on Unity Answers with my scripts, I shall bring the hammer down !
Fair warning, ok. now ....
All Current Slender Scripts
Collect Papers - CollectPapers.js
#pragma strict
@script RequireComponent( AudioSource )
var papers : int = 0;
var papersToWin : int = 8;
var distanceToPaper : float = 2.5;
public var paperPickup : AudioClip;
var theEnemy : EnemyScript;
function Start()
{
Screen.lockCursor = true;
// find and store a reference to the enemy script (to reduce distance after each paper is collected)
if ( theEnemy == null )
{
var nme : GameObject = GameObject.Find( "Enemy" );
if ( nme )
{
theEnemy = nme.GetComponent( EnemyScript );
}
}
}
function Update()
{
//if ( Input.GetMouseButtonUp(0) ) // use E in editor as LockCursor breaks with left mouseclick
if ( Input.GetMouseButtonDown(0) || Input.GetKeyDown(KeyCode.E) )
{
//var ray = Camera.main.ScreenPointToRay( Input.mousePosition ); // always cast ray from center of screen
var ray = Camera.main.ScreenPointToRay( Vector3( Screen.width * 0.5, Screen.height * 0.5, 0.0 ) );
var hit : RaycastHit;
if ( Physics.Raycast( ray, hit, distanceToPaper ) )
{
//if ( hit.collider.gameObject.tag == "Paper" )
if ( hit.collider.gameObject.name == "Paper" )
{
papers += 1;
//Debug.Log( "A paper was picked up. Total papers = " + papers );
audio.PlayClipAtPoint( paperPickup, transform.position );
Destroy( hit.collider.gameObject );
// make enemy follow closer
//theEnemy.ReduceDistance();
// make enemy follow closer
if ( papers == 1 )
{
theEnemy.SetFirstPaperDistance();
}
else
{
theEnemy.ReduceDistance();
}
}
}
}
}
function OnGUI()
{
if ( papers < papersToWin )
{
GUI.Box( Rect( (Screen.width * 0.5) - 60, 10, 120, 25 ), "" + papers.ToString() + " Papers" );
}
else
{
GUI.Box( Rect( (Screen.width/2)-100, 10, 200, 35 ), "All Papers Collected!" );
Application.LoadLevel( "SceneWin" );
}
}
Enemy Script - EnemyScript.js
#pragma strict
@script RequireComponent( AudioSource )
public var thePlayer : Transform;
private var theEnemy : Transform;
public var speed : float = 5.0;
var isOffScreen : boolean = false;
public var offscreenDotRange : float = 0.7;
var isVisible : boolean = false;
public var visibleDotRange : float = 0.8; // ** between 0.75 and 0.85 (originally 0.8172719)
var isInRange : boolean = false;
public var followDistance : float = 24.0;
public var maxVisibleDistance : float = 25.0;
public var reduceDistAmt : float = 3.1;
public var startingDistance : float = 2000.0;
private var firstPaperDistance : float = 24.0;
private var sqrDist : float = 0.0;
public var health : float = 100.0;
public var damage : float = 20.0;
public var enemySightedSFX : AudioClip;
private var hasPlayedSeenSound : boolean = false;
private var colDist : float = 5.0; // raycast distance in front of enemy when checking for obstacles
function Start()
{
if ( thePlayer == null )
{
thePlayer = GameObject.Find( "Player" ).transform;
}
theEnemy = transform;
firstPaperDistance = followDistance;
followDistance = startingDistance;
InvokeRepeating( "TeleportEnemy", 1, 10 );
}
function Update()
{
// Movement : check if out-of-view, then move
CheckIfOffScreen();
// if is Off Screen, move
if ( isOffScreen )
{
MoveEnemy();
// restore health
RestoreHealth();
}
else
{
// check if Player is seen
CheckIfVisible();
if ( isVisible )
{
// deduct health
DeductHealth();
// stop moving
StopEnemy();
// play sound only when the Man is first sighted
if ( !hasPlayedSeenSound )
{
audio.PlayClipAtPoint( enemySightedSFX, thePlayer.position );
}
hasPlayedSeenSound = true; // sound has now played
}
else
{
// check max range
CheckMaxVisibleRange();
// if far away then move, else stop
if ( !isInRange )
{
MoveEnemy();
}
else
{
StopEnemy();
}
// reset hasPlayedSeenSound for next time isVisible first occurs
hasPlayedSeenSound = false;
}
}
}
function DeductHealth()
{
// deduct health
health -= damage * Time.deltaTime;
// check if no health left
if ( health <= 0.0 )
{
health = 0.0;
Debug.Log( "YOU ARE OUT OF HEALTH !" );
// Restart game here!
Application.LoadLevel( "SceneLose" );
}
}
function RestoreHealth()
{
// deduct health
health += damage * Time.deltaTime;
// check if no health left
if ( health >= 100.0 )
{
health = 100.0;
//Debug.Log( "HEALTH is FULL" );
}
}
function CheckIfOffScreen()
{
var fwd : Vector3 = thePlayer.forward.normalized;
var other : Vector3 = (theEnemy.position - thePlayer.position).normalized;
var theProduct : float = Vector3.Dot( fwd, other );
if ( theProduct < offscreenDotRange )
{
isOffScreen = true;
}
else
{
isOffScreen = false;
}
}
function MoveEnemy()
{
// Check the Follow Distance
CheckDistance();
// if not too close, move
if ( !isInRange )
{
rigidbody.velocity = Vector3( 0, rigidbody.velocity.y, 0 ); // maintain gravity
// --
// Old Movement
//transform.LookAt( thePlayer );
//transform.position += transform.forward * speed * Time.deltaTime;
// --
// New Movement - with obstacle avoidance
var dir : Vector3 = ( thePlayer.position - theEnemy.position ).normalized;
var hit : RaycastHit;
if ( Physics.Raycast( theEnemy.position, theEnemy.forward, hit, colDist ) )
{
//Debug.Log( " obstacle ray hit " + hit.collider.gameObject.name );
if ( hit.collider.gameObject.name != "Player" && hit.collider.gameObject.name != "Terrain" )
{
dir += hit.normal * 20;
}
}
var rot : Quaternion = Quaternion.LookRotation( dir );
theEnemy.rotation = Quaternion.Slerp( theEnemy.rotation, rot, Time.deltaTime );
theEnemy.position += theEnemy.forward * speed * Time.deltaTime;
// --
}
else
{
StopEnemy();
}
}
function StopEnemy()
{
transform.LookAt( thePlayer );
rigidbody.velocity = Vector3.zero;
}
function CheckIfVisible()
{
var fwd : Vector3 = thePlayer.forward.normalized;
var other : Vector3 = ( theEnemy.position - thePlayer.position ).normalized;
var theProduct : float = Vector3.Dot( fwd, other );
if ( theProduct > visibleDotRange )
{
// Check the Max Distance
CheckMaxVisibleRange();
if ( isInRange )
{
// Linecast to check for occlusion
var hit : RaycastHit;
if ( Physics.Linecast( theEnemy.position + (Vector3.up * 1.75) + theEnemy.forward, thePlayer.position, hit ) )
{
Debug.Log( "Enemy sees " + hit.collider.gameObject.name );
if ( hit.collider.gameObject.name == "Player" )
{
isVisible = true;
}
}
}
else
{
isVisible = false;
}
}
else
{
isVisible = false;
}
}
function CheckDistance()
{
var sqrDist : float = (theEnemy.position - thePlayer.position).sqrMagnitude;
var sqrFollowDist : float = followDistance * followDistance;
if ( sqrDist < sqrFollowDist )
{
isInRange = true;
}
else
{
isInRange = false;
}
}
function ReduceDistance()
{
followDistance -= reduceDistAmt;
}
function CheckMaxVisibleRange()
{
var sqrDist : float = (theEnemy.position - thePlayer.position).sqrMagnitude;
var sqrMaxDist : float = maxVisibleDistance * maxVisibleDistance;
if ( sqrDist < sqrMaxDist )
{
isInRange = true;
}
else
{
isInRange = false;
}
}
function SetFirstPaperDistance()
{
followDistance = firstPaperDistance;
}
function TeleportEnemy()
{
// Movement : check if out-of-view, then move
CheckIfOffScreen();
// if is Off Screen, check for Teleport
if ( isOffScreen )
{
// Check the Follow Distance
CheckDistance();
// if not too close, Teleport
if ( !isInRange )
{
// determine a position to teleport to
var teleportDistance : float = 50.0; // teleport 50 units to the right of the player (thePlayer.right)
var rndPos : int = -1;
if ( Random.Range( 0, 2 ) == 1 )
{
rndPos = 1;
}
var newPos : Vector3 = thePlayer.position + ( rndPos * thePlayer.right * teleportDistance );
newPos.y = 1000.0;
// raycast to that position
var hit : RaycastHit;
if ( Physics.Raycast( newPos, -Vector3.up, hit, 1000.0 ) )
{
// check if it hit the terrain
if ( hit.collider.gameObject.name == "Terrain" )
{
// move the enemy to the new position (add a little to the y so it doesn't fall through)
theEnemy.position = hit.point + ( Vector3.up * 0.5 );
theEnemy.LookAt( thePlayer );
}
}
}
}
}
function OnGUI()
{
GUI.Box( Rect( (Screen.width * 0.5) - 60, Screen.height - 35, 120, 25 ), "Health : " + parseInt( health ).ToString() );
}
Flickering Flashlight - FlickeringFlashlight.js
#pragma strict
var minWorkingTime : float = 60.0;
var maxWorkingTime : float = 120.0;
var minLightIntensity : float = 0.5;
var maxLightIntensity : float = 2.5;
private var startIntensity : float = 1.85;
enum flashlightState { IsWorking, Flickering, Resetting }
var currentState : flashlightState;
private var workingTimer : float = 0.0;
private var workingTimeLimit : float = 90.0;
var minFlickerSpeed : float = 0.05;
var maxFlickerSpeed : float = 0.2;
private var flickerCounter : float = 0.0;
private var resetTimer : float = 0.0;
function Start()
{
workingTimeLimit = Random.Range( minWorkingTime, maxWorkingTime );
light.enabled = true;
startIntensity = light.intensity;
currentState = flashlightState.IsWorking;
}
function Update()
{
switch( currentState )
{
case flashlightState.IsWorking :
IsWorking();
break;
case flashlightState.Flickering :
FlickerFlashlight();
CheckForInput();
break;
case flashlightState.Resetting :
Resetting();
break;
}
}
function IsWorking()
{
workingTimer += Time.deltaTime;
if ( workingTimer > workingTimeLimit )
{
flickerCounter = Time.time + Random.Range( minFlickerSpeed, maxFlickerSpeed );
currentState = flashlightState.Flickering;
}
}
function FlickerFlashlight()
{
if ( flickerCounter < Time.time )
{
if (light.enabled)
{
light.enabled = false;
}
else
{
light.enabled = true;
light.intensity = Random.Range(minLightIntensity, maxLightIntensity);
}
flickerCounter = Time.time + Random.Range( minFlickerSpeed, maxFlickerSpeed );
}
}
function CheckForInput()
{
if (Input.GetKeyDown(KeyCode.F))
{
currentState = flashlightState.Resetting;
}
}
function Resetting()
{
resetTimer += Time.deltaTime;
if ( resetTimer > 0.75 )
{
resetTimer = 0.0;
workingTimer = 0.0;
workingTimeLimit = Random.Range( minWorkingTime, maxWorkingTime );
light.enabled = true;
light.intensity = startIntensity;
currentState = flashlightState.IsWorking;
}
else if ( resetTimer > 0.65 )
{
light.enabled = false;
}
else if ( resetTimer > 0.55 )
{
light.enabled = true;
light.intensity = startIntensity;
}
else if ( resetTimer > 0.25 )
{
light.enabled = false;
}
else if ( resetTimer > 0.15 )
{
light.enabled = true;
light.intensity = startIntensity;
}
else if ( resetTimer > 0.05 )
{
light.enabled = false;
}
}
Footstep Script - FootstepScript.js
#pragma strict
@script RequireComponent( AudioSource )
var walk : AudioClip;
var run : AudioClip;
var walkAudioSpeed : float = 0.4;
var runAudioSpeed : float = 0.2;
private var walkAudioTimer : float = 0.0;
private var runAudioTimer : float = 0.0;
var isWalking : boolean = false;
var isRunning : boolean = false;
var walkSpeed: float = 7; // regular speed
var runSpeed: float = 20; // run speed
private var chCtrl: CharacterController;
private var chMotor: CharacterMotor;
function Start()
{
chCtrl = GetComponent(CharacterController);
chMotor = GetComponent(CharacterMotor);
}
function Update()
{
SetSpeed();
if ( chCtrl.isGrounded )
{
PlayFootsteps();
}
else
{
walkAudioTimer = 0.0;
runAudioTimer = 0.0;
}
}
function SetSpeed()
{
var speed = walkSpeed;
if ( chCtrl.isGrounded && Input.GetKey("left shift") || Input.GetKey("right shift") )
{
speed = runSpeed;
}
chMotor.movement.maxForwardSpeed = speed;
}
function PlayFootsteps()
{
if ( Input.GetAxis( "Horizontal" ) || Input.GetAxis( "Vertical" ) )
{
if ( Input.GetKey( "left shift" ) || Input.GetKey( "right shift" ) )
{
// Running
isWalking = false;
isRunning = true;
}
else
{
// Walking
isWalking = true;
isRunning = false;
}
}
else
{
// Stopped
isWalking = false;
isRunning = false;
}
// Play Audio
if ( isWalking )
{
if ( audio.clip != walk )
{
audio.Stop();
audio.clip = walk;
}
//if ( !audio.isPlaying )
if ( walkAudioTimer > walkAudioSpeed )
{
audio.Stop();
audio.Play();
walkAudioTimer = 0.0;
}
}
else if ( isRunning )
{
if ( audio.clip != run )
{
audio.Stop();
audio.clip = run;
}
//if ( !audio.isPlaying )
if ( runAudioTimer > runAudioSpeed )
{
audio.Stop();
audio.Play();
runAudioTimer = 0.0;
}
}
else
{
audio.Stop();
}
// increment timers
walkAudioTimer += Time.deltaTime;
runAudioTimer += Time.deltaTime;
}
Scene Lose - SceneLose.js
#pragma strict
function Start()
{
Screen.lockCursor = false;
}
function OnGUI()
{
if ( GUI.Button( Rect( (Screen.width * 0.5) - 75, 10, 150, 50 ), "Lost Your Mind" ) )
{
Application.LoadLevel( "SceneMainMenu" );
}
}
Scene Main Menu - SceneMainMenu.js
#pragma strict
function Start()
{
Screen.lockCursor = false;
}
function OnGUI()
{
if ( GUI.Button( Rect( (Screen.width * 0.5) - 75, 10, 150, 50 ), "Play Me !" ) )
{
Application.LoadLevel( "Level0" );
}
}
Scene Win - SceneWin.js
#pragma strict
function Start()
{
Screen.lockCursor = false;
}
function OnGUI()
{
if ( GUI.Button( Rect( (Screen.width * 0.5) - 75, 10, 150, 50 ), "You Won !" ) )
{
Application.LoadLevel( "SceneMainMenu" );
}
}
**Static Script** - StaticScript.js
// Static Script
// Nov 9 2012
// Jay Kay (alucardj)
// This script creates a full screen static effect
#pragma strict
@script RequireComponent(MeshFilter, MeshRenderer)
var theAlpha : float = 0.0;
var theCamera : Camera;
var cameraTransform : Transform;
private var mesh : Mesh;
private var uv : Vector2[];
private var verts : Vector3[];
private var tris : int[];
private var normals : Vector3[];
public var distance : float = 1.0;
private var theMaterial : Material;
var theEnemy : EnemyScript;
function Start()
{
Startup();
// find and store a reference to the enemy script (to use health as alpha for texture)
if ( theEnemy == null )
{
theEnemy = GameObject.Find( "Enemy" ).GetComponent( EnemyScript );
}
}
function Update()
{
SetAlpha();
ScrollUVs();
}
function SetAlpha()
{
theAlpha = ( 100.0 - theEnemy.health ) * 0.01;
theMaterial.color = Color( theMaterial.color.r, theMaterial.color.g, theMaterial.color.b, theAlpha );
}
function ScrollUVs()
{
var scrollX : float = Random.Range( -0.5, 0.5 );
var scrollY : float = Random.Range( -0.5, 0.5 );
// UVs
for ( var i:int = 0; i < 4; i ++ )
{
uv[i] = new Vector2( uv[i].x + scrollX, uv[i].y + scrollY );
}
mesh.uv = uv;
}
// ----
function Startup()
{
if ( theCamera == null )
{
theCamera = Camera.main;
}
cameraTransform = theCamera.transform;
theMaterial = gameObject.renderer.material;
theMaterial.color = Color.white;
if ( !mesh )
{
GetComponent(MeshFilter).mesh = mesh = new Mesh();
mesh.name = "ScreenMesh";
}
Construct();
//DebugVerts();
}
function Construct()
{
mesh.Clear();
verts = new Vector3[4];
uv = new Vector2[4];
tris = new int[6];
normals = new Vector3[4];
// calculate verts based on camera FOV
var pos : Vector3 = cameraTransform.position - transform.position;
var halfFOV : float = ( theCamera.fieldOfView * 0.5 ) * Mathf.Deg2Rad;
var aspect : float = theCamera.aspect;
//Debug.Log( " Screen.width " + Screen.width + " : Screen.height " + Screen.height + " : aspect " + aspect );
var height : float = distance * Mathf.Tan( halfFOV );
var width : float = height * aspect;
//Debug.Log( " fieldOfView " + theCamera.fieldOfView + " : aspect " + aspect );
// UpperLeft
verts[0] = pos - (cameraTransform.right * width);
verts[0] += cameraTransform.up * height;
verts[0] += cameraTransform.forward * distance;
// UpperRight
verts[1] = pos + (cameraTransform.right * width);
verts[1] += cameraTransform.up * height;
verts[1] += cameraTransform.forward * distance;
// LowerLeft
verts[2] = pos - (cameraTransform.right * width);
verts[2] -= cameraTransform.up * height;
verts[2] += cameraTransform.forward * distance;
// LowerRight
verts[3] = pos + (cameraTransform.right * width);
verts[3] -= cameraTransform.up * height;
verts[3] += cameraTransform.forward * distance;
// UVs
uv[0] = new Vector2( 0.0, 1.0 );
uv[1] = new Vector2( 1.0, 1.0 );
uv[2] = new Vector2( 0.0, 0.0 );
uv[3] = new Vector2( 1.0, 0.0 );
// Triangles
tris[0] = 0;
tris[1] = 1;
tris[2] = 2;
tris[3] = 2;
tris[4] = 1;
tris[5] = 3;
// Normals
normals[0] = -Vector3.forward;
normals[1] = -Vector3.forward;
normals[2] = -Vector3.forward;
normals[3] = -Vector3.forward;
// assign mesh
mesh.vertices = verts;
mesh.uv = uv;
mesh.triangles = tris;
mesh.normals = normals;
mesh.RecalculateBounds();
mesh.RecalculateNormals();
}
/*
function DebugVerts()
{
// Debug Positions
Debug.Log( " UL " + verts[0] + " : UR " + verts[1] );
Debug.Log( " LL " + verts[2] + " : LR " + verts[3] );
}
*/
Your answer
Follow this Question
Related Questions
Array index is out of range 1 Answer
Music Wont Stop From Page Script+ Extra Problom 1 Answer
Help. how to die by looking at an enemy. 0 Answers
Making an Enemy stop when visible to Player... 3 Answers
Slender type game need help 0 Answers