387
Assets/Dice/Plugins/Dice.cs
Normal file
387
Assets/Dice/Plugins/Dice.cs
Normal file
@@ -0,0 +1,387 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2015, WyrmTale Games and Game Components
|
||||
* All rights reserved.
|
||||
* http://www.wyrmtale.com
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY WYRMTALE GAMES AND GAME COMPONENTS 'AS IS' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL WYRMTALE GAMES AND GAME COMPONENTS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
|
||||
/// <summary>
|
||||
/// This dice dupporting class has some 'static' methods to help you throwning dice
|
||||
/// and getting the rolling dice count, value or rolling state (asString)
|
||||
/// </summary>
|
||||
public class Dice : MonoBehaviour {
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
// public attributes
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
// constants for checking mouse button input
|
||||
public const int MOUSE_LEFT_BUTTON = 0;
|
||||
public const int MOUSE_RIGHT_BUTTON = 1;
|
||||
public const int MOUSE_MIDDLE_BUTTON = 2;
|
||||
|
||||
// rollSpeed determines how many seconds pass between rolling the single dice
|
||||
public float rollSpeed = 0.25F;
|
||||
|
||||
// rolling = true when there are dice still rolling, rolling is checked using rigidBody.velocity and rigidBody.angularVelocity
|
||||
public static bool rolling = true;
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
// protected and private attributes
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
// keep rolling time to determine when dice to be rolled, have to be instantiated
|
||||
protected float rollTime = 0;
|
||||
|
||||
// material cache
|
||||
private static ArrayList matNames = new ArrayList();
|
||||
private static ArrayList materials = new ArrayList();
|
||||
// reference to the dice that have to be rolled
|
||||
private static ArrayList rollQueue = new ArrayList();
|
||||
// reference to all dice, created by Dice.Roll
|
||||
private static ArrayList allDice = new ArrayList();
|
||||
// reference to the dice that are rolling
|
||||
private static ArrayList rollingDice = new ArrayList();
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
// public methods
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// This method will create/instance a prefab at a specific position with a specific rotation and a specific scale and assign a material
|
||||
/// </summary>
|
||||
public static GameObject prefab(string name, Vector3 position, Vector3 rotation, Vector3 scale, string mat)
|
||||
{
|
||||
// load the prefab from Resources
|
||||
Object pf = Resources.Load("Prefabs/" + name);
|
||||
if (pf!=null)
|
||||
{
|
||||
// the prefab was found so create an instance for it.
|
||||
GameObject inst = (GameObject) GameObject.Instantiate( pf , Vector3.zero, Quaternion.identity);
|
||||
if (inst!=null)
|
||||
{
|
||||
// the instance could be created so set material, position, rotation and scale.
|
||||
if (mat!="") inst.GetComponent<Renderer>().material = material(mat);
|
||||
inst.transform.position = position;
|
||||
inst.transform.Rotate(rotation);
|
||||
inst.transform.localScale = scale;
|
||||
// return the created instance (GameObject)
|
||||
return inst;
|
||||
}
|
||||
}
|
||||
else
|
||||
Debug.Log("Prefab "+name+" not found!");
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method will perform a quick lookup for a 'cached' material. If not found, the material will be loaded from the Resources
|
||||
/// </summary>
|
||||
public static Material material(string matName)
|
||||
{
|
||||
Material mat = null;
|
||||
// check if material is cached
|
||||
int idx = matNames.IndexOf(matName);
|
||||
if (idx<0)
|
||||
{
|
||||
// not cached so load it from Resources
|
||||
string[] a = matName.Split('-');
|
||||
if (a.Length>1)
|
||||
{
|
||||
a[0] = a[0].ToLower();
|
||||
if (a[0].IndexOf("d")==0)
|
||||
mat = (Material) Resources.Load("Materials/"+a[0]+"/"+matName);
|
||||
}
|
||||
if (mat==null) mat = (Material) Resources.Load("Materials/"+matName);
|
||||
if (mat!=null)
|
||||
{
|
||||
// add material to cache
|
||||
matNames.Add(matName);
|
||||
materials.Add(mat);
|
||||
}
|
||||
}
|
||||
else
|
||||
mat = (Material) materials[idx];
|
||||
// return material - null if not found
|
||||
return mat;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Log a text to the console
|
||||
/// </summary>
|
||||
public static void debug(string txt)
|
||||
{
|
||||
Debug.Log(txt);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Roll one or more dice with a specific material from a spawnPoint and give it a specific force.
|
||||
/// format dice : ({count}){die type} , exmpl. d6, 4d4, 12d8 , 1d20
|
||||
/// possible die types : d4, d6, d8 , d10, d12, d20
|
||||
/// </summary>
|
||||
public static void Roll(string dice, string mat, Vector3 spawnPoint, Vector3 force)
|
||||
{
|
||||
rolling = true;
|
||||
// sotring dice to lowercase for comparing purposes
|
||||
dice = dice.ToLower();
|
||||
int count = 1;
|
||||
string dieType = "d6";
|
||||
|
||||
// 'd' must be present for a valid 'dice' specification
|
||||
int p = dice.IndexOf("d");
|
||||
if (p>=0)
|
||||
{
|
||||
// check if dice starts with d, if true a single die is rolled.
|
||||
// dice must have a count because dice does not start with 'd'
|
||||
if (p>0)
|
||||
{
|
||||
// extract count
|
||||
string[] a = dice.Split('d');
|
||||
count = System.Convert.ToInt32(a[0]);
|
||||
// get die type
|
||||
if (a.Length>1)
|
||||
dieType = "d"+a[1];
|
||||
else
|
||||
dieType = "d6";
|
||||
}
|
||||
else
|
||||
dieType = dice;
|
||||
|
||||
// instantiate the dice
|
||||
for (int d=0; d<count; d++)
|
||||
{
|
||||
// randomize spawnPoint variation
|
||||
spawnPoint.x = spawnPoint.x - 1 + Random.value * 2;
|
||||
spawnPoint.y = spawnPoint.y - 1 + Random.value * 2;
|
||||
spawnPoint.y = spawnPoint.y - 1 + Random.value * 2;
|
||||
// create the die prefab/gameObject
|
||||
GameObject die = prefab(dieType, spawnPoint, Vector3.zero, Vector3.one, mat);
|
||||
// give it a random rotation
|
||||
die.transform.Rotate(new Vector3(Random.value * 360, Random.value * 360, Random.value * 360));
|
||||
// inactivate this gameObject because activating it will be handeled using the rollQueue and at the apropriate time
|
||||
die.active = false;
|
||||
// create RollingDie class that will hold things like spawnpoint and force, to be used when activating the die at a later stage
|
||||
RollingDie rDie = new RollingDie(die, dieType, mat, spawnPoint, force);
|
||||
// add RollingDie to allDices
|
||||
allDice.Add(rDie);
|
||||
// add RollingDie to the rolling queue
|
||||
rollQueue.Add(rDie);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get value of all ( dieType = "" ) dice or dieType specific dice.
|
||||
/// </summary>
|
||||
public static int Value(string dieType)
|
||||
{
|
||||
int v = 0;
|
||||
// loop all dice
|
||||
for (int d = 0; d < allDice.Count; d++)
|
||||
{
|
||||
RollingDie rDie = (RollingDie) allDice[d];
|
||||
// check the type
|
||||
if (rDie.name == dieType || dieType == "")
|
||||
v += rDie.die.value;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get number of all ( dieType = "" ) dice or dieType specific dice.
|
||||
/// </summary>
|
||||
public static int Count(string dieType)
|
||||
{
|
||||
int v = 0;
|
||||
// loop all dice
|
||||
for (int d = 0; d < allDice.Count; d++)
|
||||
{
|
||||
RollingDie rDie = (RollingDie)allDice[d];
|
||||
// check the type
|
||||
if (rDie.name == dieType || dieType == "")
|
||||
v++;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get rolling status of all ( dieType = "" ) dice or dieType specific dice.
|
||||
/// </summary>
|
||||
public static string AsString(string dieType)
|
||||
{
|
||||
// count the dice
|
||||
string v = ""+Count(dieType);
|
||||
if (dieType == "")
|
||||
v += " dice | ";
|
||||
else
|
||||
v += dieType + " : ";
|
||||
|
||||
if (dieType == "")
|
||||
{
|
||||
// no dieType specified to cumulate values per dieType ( if they are available )
|
||||
if (Count("d6") > 0) v += AsString("d6") + " | ";
|
||||
if (Count("d10") > 0) v += AsString("d10") + " | ";
|
||||
}
|
||||
else
|
||||
{
|
||||
// assemble status of specific dieType
|
||||
bool hasValue = false;
|
||||
for (int d = 0; d < allDice.Count; d++)
|
||||
{
|
||||
RollingDie rDie = (RollingDie)allDice[d];
|
||||
// check type
|
||||
if (rDie.name == dieType || dieType == "")
|
||||
{
|
||||
if (hasValue) v += " + ";
|
||||
// if the value of the die is 0 , no value could be determined
|
||||
// this could be because the die is rolling or is in a invalid position
|
||||
v += "" + ((rDie.die.value == 0) ? "?" : "" + rDie.die.value);
|
||||
hasValue = true;
|
||||
}
|
||||
}
|
||||
v += " = " + Value(dieType);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Clears all currently rolling dice
|
||||
/// </summary>
|
||||
public static void Clear()
|
||||
{
|
||||
for (int d=0; d<allDice.Count; d++)
|
||||
GameObject.Destroy(((RollingDie)allDice[d]).gameObject);
|
||||
|
||||
allDice.Clear();
|
||||
rollingDice.Clear();
|
||||
rollQueue.Clear();
|
||||
|
||||
rolling = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update is called once per frame
|
||||
/// </summary>
|
||||
void Update()
|
||||
{
|
||||
if (rolling)
|
||||
{
|
||||
// there are dice rolling so increment rolling time
|
||||
rollTime += Time.deltaTime;
|
||||
// check rollTime against rollSpeed to determine if a die should be activated ( if one available in the rolling queue )
|
||||
if (rollQueue.Count > 0 && rollTime > rollSpeed)
|
||||
{
|
||||
// get die from rolling queue
|
||||
RollingDie rDie = (RollingDie)rollQueue[0];
|
||||
GameObject die = rDie.gameObject;
|
||||
// activate the gameObject
|
||||
die.active = true;
|
||||
// apply the force impuls
|
||||
die.GetComponent<Rigidbody>().AddForce((Vector3) rDie.force, ForceMode.Impulse);
|
||||
// apply a random torque
|
||||
die.GetComponent<Rigidbody>().AddTorque(new Vector3(-50 * Random.value * die.transform.localScale.magnitude, -50 * Random.value * die.transform.localScale.magnitude, -50 * Random.value * die.transform.localScale.magnitude), ForceMode.Impulse);
|
||||
// add die to rollingDice
|
||||
rollingDice.Add(rDie);
|
||||
// remove the die from the queue
|
||||
rollQueue.RemoveAt(0);
|
||||
// reset rollTime so we can check when the next die has to be rolled
|
||||
rollTime = 0;
|
||||
}
|
||||
else
|
||||
if (rollQueue.Count == 0)
|
||||
{
|
||||
// roll queue is empty so if no dice are rolling we can set the rolling attribute to false
|
||||
if (!IsRolling())
|
||||
rolling = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if there all dice have stopped rolling
|
||||
/// </summary>
|
||||
private bool IsRolling()
|
||||
{
|
||||
int d = 0;
|
||||
// loop rollingDice
|
||||
while (d < rollingDice.Count)
|
||||
{
|
||||
// if rolling die no longer rolling , remove it from rollingDice
|
||||
RollingDie rDie = (RollingDie)rollingDice[d];
|
||||
if (!rDie.rolling)
|
||||
rollingDice.Remove(rDie);
|
||||
else
|
||||
d++;
|
||||
}
|
||||
// return false if we have no rolling dice
|
||||
return (rollingDice.Count > 0);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Supporting rolling die class to keep die information
|
||||
/// </summary>
|
||||
class RollingDie
|
||||
{
|
||||
|
||||
public GameObject gameObject; // associated gameObject
|
||||
public Die die; // associated Die (value calculation) script
|
||||
|
||||
public string name = ""; // dieType
|
||||
public string mat; // die material (asString)
|
||||
public Vector3 spawnPoint; // die spawnPoiunt
|
||||
public Vector3 force; // die initial force impuls
|
||||
|
||||
// rolling attribute specifies if this die is still rolling
|
||||
public bool rolling
|
||||
{
|
||||
get
|
||||
{
|
||||
return die.rolling;
|
||||
}
|
||||
}
|
||||
|
||||
public int value
|
||||
{
|
||||
get
|
||||
{
|
||||
return die.value;
|
||||
}
|
||||
}
|
||||
|
||||
// constructor
|
||||
public RollingDie(GameObject gameObject, string name, string mat, Vector3 spawnPoint, Vector3 force)
|
||||
{
|
||||
this.gameObject = gameObject;
|
||||
this.name = name;
|
||||
this.mat = mat;
|
||||
this.spawnPoint = spawnPoint;
|
||||
this.force = force;
|
||||
// get Die script of current gameObject
|
||||
die = (Die)gameObject.GetComponent(typeof(Die));
|
||||
}
|
||||
|
||||
// ReRoll this specific die
|
||||
public void ReRoll()
|
||||
{
|
||||
if (name != "")
|
||||
{
|
||||
GameObject.Destroy(gameObject);
|
||||
Dice.Roll(name, mat, spawnPoint, force);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
11
Assets/Dice/Plugins/Dice.cs.meta
Normal file
11
Assets/Dice/Plugins/Dice.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a6b4036603d212e4eae18e23b556ca9f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
133
Assets/Dice/Plugins/Die.cs
Normal file
133
Assets/Dice/Plugins/Die.cs
Normal file
@@ -0,0 +1,133 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2015, WyrmTale Games and Game Components
|
||||
* All rights reserved.
|
||||
* http://www.wyrmtale.com
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY WYRMTALE GAMES AND GAME COMPONENTS 'AS IS' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL WYRMTALE GAMES AND GAME COMPONENTS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
|
||||
/// <summary>
|
||||
/// Die base class to determine if a die is rolling and to calculate it's current value
|
||||
/// </summary>
|
||||
public class Die : MonoBehaviour {
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
// public attributes
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
// current value, 0 is undetermined (die is rolling) or invalid.
|
||||
public int value = 0;
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
// protected and private attributes
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
// normalized (hit)vector from die center to upper side in local space is used to determine what side of a specific die is up/down = value
|
||||
protected Vector3 localHitNormalized;
|
||||
// hitVector check margin
|
||||
protected float validMargin = 0.45F;
|
||||
|
||||
// true is die is still rolling
|
||||
public bool rolling
|
||||
{
|
||||
get
|
||||
{
|
||||
return !(GetComponent<Rigidbody>().velocity.sqrMagnitude < .1F && GetComponent<Rigidbody>().angularVelocity.sqrMagnitude < .1F);
|
||||
}
|
||||
}
|
||||
|
||||
// calculate the normalized hit vector and should always return true
|
||||
protected bool localHit
|
||||
{
|
||||
get
|
||||
{
|
||||
// create a Ray from straight above this Die , moving downwards
|
||||
Ray ray = new Ray(transform.position + (new Vector3(0, 2, 0) * transform.localScale.magnitude), Vector3.up * -1);
|
||||
RaycastHit hit = new RaycastHit();
|
||||
// cast the ray and validate it against this die's collider
|
||||
if (GetComponent<Collider>().Raycast(ray, out hit, 3 * transform.localScale.magnitude))
|
||||
{
|
||||
// we got a hit so we determine the local normalized vector from the die center to the face that was hit.
|
||||
// because we are using local space, each die side will have its own local hit vector coordinates that will always be the same.
|
||||
localHitNormalized = transform.InverseTransformPoint(hit.point.x, hit.point.y, hit.point.z).normalized;
|
||||
return true;
|
||||
}
|
||||
// in theory we should not get at this position!
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// calculate this die's value
|
||||
void GetValue()
|
||||
{
|
||||
// value = 0 -> undetermined or invalid
|
||||
value = 0;
|
||||
float delta = 1;
|
||||
// start with side 1 going up.
|
||||
int side = 1;
|
||||
Vector3 testHitVector;
|
||||
// check all sides of this die, the side that has a valid hitVector and smallest x,y,z delta (if more sides are valid) will be the closest and this die's value
|
||||
do
|
||||
{
|
||||
// get testHitVector from current side, HitVector is a overriden method in the dieType specific Die subclass
|
||||
// eacht dieType subclass will expose all hitVectors for its sides,
|
||||
testHitVector = HitVector(side);
|
||||
if (testHitVector != Vector3.zero)
|
||||
{
|
||||
// this side has a hitVector so validate the x,y and z value against the local normalized hitVector using the margin.
|
||||
if (valid(localHitNormalized.x, testHitVector.x) &&
|
||||
valid(localHitNormalized.y, testHitVector.y) &&
|
||||
valid(localHitNormalized.z, testHitVector.z))
|
||||
{
|
||||
// this side is valid within the margin, check the x,y, and z delta to see if we can set this side as this die's value
|
||||
// if more than one side is within the margin (especially with d10, d12, d20 ) we have to use the closest as the right side
|
||||
float nDelta = Mathf.Abs(localHitNormalized.x - testHitVector.x) + Mathf.Abs(localHitNormalized.y - testHitVector.y) + Mathf.Abs(localHitNormalized.z - testHitVector.z);
|
||||
if (nDelta < delta)
|
||||
{
|
||||
value = side;
|
||||
delta = nDelta;
|
||||
}
|
||||
}
|
||||
}
|
||||
// increment side
|
||||
side++;
|
||||
// if we got a Vector.zero as the testHitVector we have checked all sides of this die
|
||||
} while (testHitVector != Vector3.zero);
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
// determine the value is the die is not rolling
|
||||
if (!rolling && localHit)
|
||||
GetValue();
|
||||
}
|
||||
|
||||
|
||||
// validate a test value against a value within a specific margin.
|
||||
protected bool valid(float t, float v)
|
||||
{
|
||||
if (t > (v - validMargin) && t < (v + validMargin))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
// virtual method that to get a die side hitVector.
|
||||
// this has to be overridden in the dieType specific subclass
|
||||
protected virtual Vector3 HitVector(int side)
|
||||
{
|
||||
return Vector3.zero;
|
||||
}
|
||||
|
||||
}
|
||||
11
Assets/Dice/Plugins/Die.cs.meta
Normal file
11
Assets/Dice/Plugins/Die.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a7ca1acb51470bb44bd5b0c932c809a4
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user