So I have a script that shoots an arrow when you click and drag, kinda like Angry Birds.
I want it to work with the 2D RigidBody and 2D collider but when I change the rigidbody.AddForce to rigidbody2D.AddForce, It doesn't work.
How can I fix this to work for 2D?
I also want the arrow to rotate in 2D space either up or down depending on where mouse is pulled back. When I try the mouse look script, it rotates it in the z axis (I think) and distorts the arrow. Any easy solution to fix this??
Thanks guys. I'm new to game making and I've been trying to figure this stuff out for like the last 10 hours. I need some pros to help!
Thanks!!!
Heres my script
using UnityEngine;
using System.Collections;
public class DragShotMover2 : MonoBehaviour {
public float maxDragLength = 2; // this is the base magnitude and the maximum length of the line drawn in the user interface
public float maxMultiplier = 5; // multiply the line length by this to allow for higher force values to be represented by shorter lines
public Vector3 dragPlaneNormal = Vector3.up; // a vector describing the orientation of the drag plan relative to world-space but centered on the target
public SnapDir snapDirection = SnapDir.away; // force is applied either toward or away from the mouse on release
public ForceMode forceTypeToApply = ForceMode.VelocityChange;
public bool overrideVelocity = true; // cancel the existing velocity before applying the new force
public bool pauseOnDrag = true; // causes the simulation to pause when the object is clicked and unpause when released
public Color noForceColor = Color.yellow; // color of the visualization helpers at force 0
public Color maxForceColor = Color.red; // color of the visualization helpers at maximum force
public enum SnapDir {toward, away}
private Vector3 forceVector;
private float magPercent = 0;
private bool mouseDragging = false;
private Vector3 mousePos3D;
private float dragDistance;
private Plane dragPlane;
private Ray mouseRay;
private GameObject dragZone;
private string shaderString = "Transparent/Diffuse";
private Material dzMat;
void Start (){
Color currentColor = noForceColor;
dzMat = new Material(Shader.Find(shaderString));
// create the dragzone visual helper
dragZone = new GameObject("dragZone_" + gameObject.name);
dragZone.AddComponent<MeshFilter>().mesh = MakeDiscMeshBrute(maxDragLength/4);
//dragZone.GetComponent.MeshFilter.
dragZone.AddComponent<MeshRenderer>();
dragZone.renderer.enabled = false;
dragZone.name = "dragZone_" + gameObject.name;
dragZone.transform.localScale = new Vector3(maxDragLength*2, 0.025f, maxDragLength*2);
dragZone.renderer.material = dzMat;
dragZone.renderer.material.color = currentColor * new Color(1,1,1,0.2f);
// create the dragplane
dragPlane = new Plane(dragPlaneNormal, transform.position);
// orient the drag plane
if (dragPlaneNormal != Vector3.zero) {
dragZone.transform.rotation = Quaternion.LookRotation(dragPlaneNormal) * new Quaternion(1, 0, 0, 1);
}
else Debug.LogError("Drag plane normal cannot be equal to Vector3.zero.");
//update the position of the dragzone
dragZone.transform.position = transform.position;
}
void OnMouseDown (){
mouseDragging = true;
if (pauseOnDrag) {
// pause the simulation
Time.timeScale = 0;
}
// update the dragplane
dragPlane = new Plane(dragPlaneNormal, transform.position);
// orient the drag plane
if (dragPlaneNormal != Vector3.zero) {
dragZone.transform.rotation = Quaternion.LookRotation(dragPlaneNormal) * new Quaternion(1, 0, 0, 1);
}
else Debug.LogError("Drag plane normal cannot be equal to Vector3.zero.");
//update the position of the dragzone
dragZone.transform.position = transform.position;
dragZone.renderer.enabled = true;
}
void OnMouseDrag (){
Color currentColor = noForceColor;
// update the plane if the target object has left it
if (dragPlane.GetDistanceToPoint(transform.position) != 0) {
// update dragplane by constructing a new one -- I should check this with a profiler
dragPlane = new Plane(dragPlaneNormal, transform.position);
}
// create a ray from the camera, through the mouse position in 3D space
mouseRay = Camera.main.ScreenPointToRay(Input.mousePosition);
// if mouseRay intersects with dragPlane
float intersectDist = 0.0f;
if (dragPlane.Raycast(mouseRay, out intersectDist)) {
// update the world space point for the mouse position on the dragPlane
mousePos3D = mouseRay.GetPoint(intersectDist);
// calculate the distance between the 3d mouse position and the object position
dragDistance = Mathf.Clamp((mousePos3D - transform.position).magnitude, 0, maxDragLength);
// calculate the force vector
if (dragDistance*maxMultiplier < 1) dragDistance = 0; // this is to allow for a "no move" buffer close to the object
forceVector = mousePos3D - transform.position;
forceVector.Normalize();
forceVector *= dragDistance * maxMultiplier;
// update color the color
// calculate the percentage value of current force magnitude out of maximum
magPercent = (dragDistance * maxMultiplier) / (maxDragLength * maxMultiplier);
// choose color based on how close magPercent is to either 0 or max
currentColor = noForceColor * (1-magPercent) + maxForceColor * magPercent;
// dragzone color
dragZone.renderer.material.color = currentColor * new Color(1,1,1,0.2f);
// draw the line
Debug.DrawRay(transform.position, forceVector / maxMultiplier, currentColor);
}
//update the position of the dragzone
dragZone.transform.position = transform.position;
}
void OnMouseUp (){
mouseDragging = false;
if (overrideVelocity) {
// cancel existing velocity
rigidbody.AddForce(-rigidbody.velocity, ForceMode.VelocityChange);
}
// add new force
int snapD = 1;
if (snapDirection == SnapDir.away) snapD = -1; // if snapdirection is "away" set the force to apply in the opposite direction
rigidbody.AddForce(snapD * forceVector, forceTypeToApply);
// cleanup
dragZone.renderer.enabled = false;
if (pauseOnDrag) {
// un-pause the simulation
Time.timeScale = 1;
}
}
void OnGUI (){
if (mouseDragging) {
Vector2 guiMouseCoord = GUIUtility.ScreenToGUIPoint(Input.mousePosition);
GUI.Box ( new Rect(guiMouseCoord.x-30, Screen.height-guiMouseCoord.y+15, 100, 20), "force: "+Mathf.Round((forceVector).magnitude));
}
}
Mesh MakeDiscMeshBrute ( float r ){
Mesh discMesh;
Vector3[] dmVerts = new Vector3[18];
Vector3[] dmNorms = new Vector3[18];
Vector2[] dmUVs = new Vector2[18];
int[] dmTris = new int[48];
int i = 0;
discMesh = new Mesh();
dmVerts[0] = new Vector3(0,0,0);
dmVerts[1] = new Vector3(0,0,r);
dmVerts[2] = new Vector3(1,0,1).normalized * r; // find the vector at the correct distance the hacky-hillbilly way!
dmVerts[3] = new Vector3(r,0,0);
dmVerts[4] = new Vector3(1,0,-1).normalized * r;
dmVerts[5] = new Vector3(0,0,-r);
dmVerts[6] = new Vector3(-1,0,-1).normalized * r;
dmVerts[7] = new Vector3(-r,0,0);
dmVerts[8] = new Vector3(-1,0,1).normalized * r;
// set the other side to the same points
for (i = 0; i<dmVerts.Length/2; i++) {
dmVerts[dmVerts.Length/2 + i] = dmVerts[i];
}
for (i = 0; i<dmNorms.Length; i++) {
if (i<dmNorms.Length/2) dmNorms[i] = Vector3.up; // set side one to face up
else dmNorms[i] = -Vector3.up; // set side two to face down
}
dmUVs[0] = new Vector2(0,0);
dmUVs[1] = new Vector2(0,r);
dmUVs[2] = new Vector2(1,1).normalized * r;;
dmUVs[3] = new Vector2(r,0);
dmUVs[4] = new Vector2(1,-1).normalized * r;;
dmUVs[5] = new Vector2(0,-r);
dmUVs[6] = new Vector2(-1,-1).normalized * r;;
dmUVs[7] = new Vector2(-r,0);
dmUVs[8] = new Vector2(-1,1).normalized * r;;
// set the other side to the same points
for (i = 0; i<dmUVs.Length/2; i++) {
dmUVs[dmUVs.Length/2 + i] = dmUVs[i];
}
dmTris[0] = 0;
dmTris[1] = 1;
dmTris[2] = 2;
dmTris[3] = 0;
dmTris[4] = 2;
dmTris[5] = 3;
dmTris[6] = 0;
dmTris[7] = 3;
dmTris[8] = 4;
dmTris[9] = 0;
dmTris[10] = 4;
dmTris[11] = 5;
dmTris[12] = 0;
dmTris[13] = 5;
dmTris[14] = 6;
dmTris[15] = 0;
dmTris[16] = 6;
dmTris[17] = 7;
dmTris[18] = 0;
dmTris[19] = 7;
dmTris[20] = 8;
dmTris[21] = 0;
dmTris[22] = 8;
dmTris[23] = 1;
// side two
dmTris[24] = 9;
dmTris[25] = 11;
dmTris[26] = 10;
dmTris[27] = 9;
dmTris[28] = 12;
dmTris[29] = 11;
dmTris[30] = 9;
dmTris[31] = 13;
dmTris[32] = 12;
dmTris[33] = 9;
dmTris[34] = 14;
dmTris[35] = 13;
dmTris[36] = 9;
dmTris[37] = 15;
dmTris[38] = 14;
dmTris[39] = 9;
dmTris[40] = 16;
dmTris[41] = 15;
dmTris[42] = 9;
dmTris[43] = 17;
dmTris[44] = 16;
dmTris[45] = 9;
dmTris[46] = 10;
dmTris[47] = 17;
discMesh.vertices = dmVerts;
discMesh.uv = dmUVs;
discMesh.normals = dmNorms;
discMesh.triangles = dmTris;
return discMesh;
}
}
If you want to keep using the 3D Rigidbody, I'd suggest just using RigidbodyConstraints, so you can lock the z (or whatever) axis/rotation, and it will perform exactly the same as a 2D platformer.
Related
I'm working on a unity project involving deformable terrain based on marching-cubes. It works by generating a map of density over the 3-dimensional coordinates of a terrain chunk and using that data to create a mesh representing the surface of the terrain. It has been working, however the process is very slow. I'm attempting to introduce multithreading to improve performance, but I've run into a problem that's left me scratching my head.
When I run CreateMeshData() and try to pass my density map terrainMap into the MarchCubeJob struct, it recognizes it as a reference type, not a value type. I've seemed to whittle down the errors to this one, but I've tried to introduce the data in every way I know how and I'm stumped. I thought passing a reference like this was supposed to create a copy of the data disconnected from the reference, but my understanding must be flawed. My goal is to pass each marchingcube cube into a job and have them run concurrently.
I'm brand new to multithreading, so I've probably made some newbie mistakes here and I'd appreciate if someone would help me out with a second look. Cheers!
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Unity.Jobs;
using Unity.Collections;
using Unity.Burst;
public class Chunk
{
List<Vector3> vertices = new List<Vector3>();
List<int> triangles = new List<int>();
public GameObject chunkObject;
MeshFilter meshFilter;
MeshCollider meshCollider;
MeshRenderer meshRenderer;
Vector3Int chunkPosition;
public float[,,] terrainMap;
// Job system
NativeList<Vector3> marchVerts;
NativeList<Vector3> marchTris;
MarchCubeJob instanceMarchCube;
JobHandle instanceJobHandle;
int width { get { return Terrain_Data.chunkWidth;}}
int height { get { return Terrain_Data.chunkHeight;}}
static float terrainSurface { get { return Terrain_Data.terrainSurface;}}
public Chunk (Vector3Int _position){ // Constructor
chunkObject = new GameObject();
chunkObject.name = string.Format("Chunk x{0}, y{1}, z{2}", _position.x, _position.y, _position.z);
chunkPosition = _position;
chunkObject.transform.position = chunkPosition;
meshRenderer = chunkObject.AddComponent<MeshRenderer>();
meshFilter = chunkObject.AddComponent<MeshFilter>();
meshCollider = chunkObject.AddComponent<MeshCollider>();
chunkObject.transform.tag = "Terrain";
terrainMap = new float[width + 1, height + 1, width + 1]; // Weight of each point
meshRenderer.material = Resources.Load<Material>("Materials/Terrain");
// Generate chunk
PopulateTerrainMap();
CreateMeshData();
}
void PopulateTerrainMap(){
...
}
void CreateMeshData(){
ClearMeshData();
vertices = new List<Vector3>();
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
for (int z = 0; z < width; z++) {
Debug.Log(x + ", " + y + ", " + z + ", begin");
Vector3Int position = new Vector3Int(x, y, z);
// Set up memory pointers
NativeList<Vector3> marchVerts = new NativeList<Vector3>(Allocator.TempJob);
NativeList<int> marchTris = new NativeList<int>(Allocator.TempJob);
NativeList<float> mapSample = new NativeList<float>(Allocator.TempJob);
// Split marchcube into jobs by cube
instanceMarchCube = new MarchCubeJob(){
position = position,
marchVerts = marchVerts,
marchTris = marchTris,
mapSample = terrainMap
};
// Run job for each cube in a chunk
instanceJobHandle = instanceMarchCube.Schedule();
instanceJobHandle.Complete();
// Copy data from job to mesh data
//instanceMarchCube.marchVerts.CopyTo(vertices);
vertices.AddRange(marchVerts);
triangles.AddRange(marchTris);
// Dispose of memory pointers
marchVerts.Dispose();
marchTris.Dispose();
mapSample.Dispose();
Debug.Log(x + ", " + y + ", " + z + ", end");
}
}
}
BuildMesh();
}
public void PlaceTerrain (Vector3 pos, int radius, float speed){
...
CreateMeshData();
}
public void RemoveTerrain (Vector3 pos, int radius, float speed){
...
CreateMeshData();
}
void ClearMeshData(){
vertices.Clear();
triangles.Clear();
}
void BuildMesh(){
Mesh mesh = new Mesh();
mesh.vertices = vertices.ToArray();
mesh.triangles = triangles.ToArray();
mesh.RecalculateNormals();
meshFilter.mesh = mesh;
meshCollider.sharedMesh = mesh;
}
private void OnDestroy(){
marchVerts.Dispose();
marchTris.Dispose();
}
}
// Build a cube as a job
[BurstCompile]
public struct MarchCubeJob: IJob{
static float terrainSurface { get { return Terrain_Data.terrainSurface;}}
public Vector3Int position;
public NativeList<Vector3> marchVerts;
public NativeList<int> marchTris;
public float[,,] mapSample;
public void Execute(){
//Sample terrain values at each corner of cube
float[] cube = new float[8];
for (int i = 0; i < 8; i++){
cube[i] = SampleTerrain(position + Terrain_Data.CornerTable[i]);
}
int configIndex = GetCubeConfiguration(cube);
// If done (-1 means there are no more vertices)
if (configIndex == 0 || configIndex == 255){
return;
}
int edgeIndex = 0;
for (int i = 0; i < 5; i++){ // Triangles
for (int p = 0; p < 3; p++){ // Tri Vertices
int indice = Terrain_Data.TriangleTable[configIndex, edgeIndex];
if (indice == -1){
return;
}
// Get 2 points of edge
Vector3 vert1 = position + Terrain_Data.CornerTable[Terrain_Data.EdgeIndexes[indice, 0]];
Vector3 vert2 = position + Terrain_Data.CornerTable[Terrain_Data.EdgeIndexes[indice, 1]];
Vector3 vertPosition;
// Smooth terrain
// Sample terrain values at either end of current edge
float vert1Sample = cube[Terrain_Data.EdgeIndexes[indice, 0]];
float vert2Sample = cube[Terrain_Data.EdgeIndexes[indice, 1]];
// Calculate difference between terrain values
float difference = vert2Sample - vert1Sample;
if (difference == 0){
difference = terrainSurface;
}
else{
difference = (terrainSurface - vert1Sample) / difference;
}
vertPosition = vert1 + ((vert2 - vert1) * difference);
marchVerts.Add(vertPosition);
marchTris.Add(marchVerts.Length - 1);
edgeIndex++;
}
}
}
static int GetCubeConfiguration(float[] cube){
int configurationIndex = 0;
for (int i = 0; i < 8; i++){
if (cube[i] > terrainSurface){
configurationIndex |= 1 << i;
}
}
return configurationIndex;
}
public float SampleTerrain(Vector3Int point){
return mapSample[point.x, point.y, point.z];
}
}
If the grid is 10x10 or 23x7 it's working fine but when the grid have 1.5 spaces between the cubes the directions sometimes are wrong.
This is the grid script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GridGenerator : MonoBehaviour
{
public GameObject gridBlock;
public int gridWidth = 10;
public int gridHeight = 10;
public GameObject[] allBlocks;
private GameObject[] wallsParents = new GameObject[4];
void Start()
{
wallsParents[0] = GameObject.Find("Top Wall");
wallsParents[1] = GameObject.Find("Left Wall");
wallsParents[2] = GameObject.Find("Right Wall");
wallsParents[3] = GameObject.Find("Bottom Wall");
GenerateGrid();
allBlocks = GameObject.FindGameObjectsWithTag("Blocks");
var findpath = GetComponent<PathFinder>();
findpath.FindPath();
}
public void AutoGenerateGrid()
{
allBlocks = GameObject.FindGameObjectsWithTag("Blocks");
for (int i = 0; i < allBlocks.Length; i++)
{
DestroyImmediate(allBlocks[i]);
}
var end = GameObject.FindGameObjectWithTag("End");
DestroyImmediate(end);
GenerateGrid();
allBlocks = GameObject.FindGameObjectsWithTag("Blocks");
var findpath = GetComponent<PathFinder>();
findpath.FindPath();
}
public void GenerateGrid()
{
for (int x = 0; x < gridWidth; x++)
{
for (int z = 0; z < gridHeight; z++)
{
GameObject block = Instantiate(gridBlock, Vector3.zero, gridBlock.transform.rotation) as GameObject;
block.transform.parent = transform;
block.transform.name = "Block";
block.transform.tag = "Blocks";
block.transform.localPosition = new Vector3(x * 1.5f, 0, z * 1.5f);
block.GetComponent<Renderer>().material.color = new Color(241, 255, 0, 255);
if (x == 0)//TOP
{
block.transform.parent = wallsParents[0].transform;
block.transform.name = "TopWall";
block.transform.tag = "Blocks";
}
else if (z == 0)//LEFT
{
block.transform.parent = wallsParents[1].transform;
block.transform.name = "LeftWall";
block.transform.tag = "Blocks";
}
else if (z == gridHeight - 1)//RIGHT
{
block.transform.parent = wallsParents[2].transform;
block.transform.name = "RightWall";
block.transform.tag = "Blocks";
}
else if (x == gridWidth - 1)//BOTTOM
{
block.transform.parent = wallsParents[3].transform;
block.transform.name = "BottomWall";
block.transform.tag = "Blocks";
}
}
}
}
}
On this line i'm adding the spaces between the cubes:
block.transform.localPosition = new Vector3(x * 1.5f, 0, z * 1.5f);
Then in another script i'm trying to find what directions next are possible to move to.
private void Directions()
{
GridGenerator gridgenerator = GetComponent<GridGenerator>();
Vector3 playerPosition;
playerPosition = player.localPosition;
if (playerPosition.x > 0)
{
// can go left
possibleDirections[0] = "Can go left";
}
else
{
possibleDirections[0] = "Can't go left";
}
if (playerPosition.x + 1 < gridgenerator.gridWidth * 1.5f)
{
// can go right
possibleDirections[1] = "Can go right";
}
else
{
possibleDirections[1] = "Can't go right";
}
if (playerPosition.z > 0)
{
// can go backward
possibleDirections[2] = "Can go backward";
}
else
{
possibleDirections[2] = "Can't go backward";
}
if (playerPosition.z + 1 < gridgenerator.gridHeight * 1.5f)
{
// can go backward
possibleDirections[3] = "Can go forward";
}
else
{
possibleDirections[3] = "Can't go forward";
}
}
possibleDirections is array string type
When the grid size is 10x10 without spaces between cubes this two lines:
if (playerPosition.x + 1 < gridgenerator.gridWidth * 1.5f)
if (playerPosition.z + 1 < gridgenerator.gridHeight * 1.5f)
Was:
if (playerPosition.x + 1 < gridgenerator.gridWidth)
if (playerPosition.z + 1 < gridgenerator.gridHeight)
But when i added the spaces between the cubes i tried to add to the gridgenerator.gridWidth and gridgenerator.gridHeight the * 1.5
But it didn't work so i tried also:
if (playerPosition.x + 1 < gridgenerator.gridWidth * (1 + 1.5))
if (playerPosition.z + 1 < gridgenerator.gridHeight * (1 + 1.5))
1 is the cube width and 1.5 is the space. But this is not working good either.
In the screenshot the player is in the top left corner facing up(forward)
He can't move forward but in the inspector it says "Can go forward" And should be "Can't go forward"
It only happens when there are spaces between the cubes.
This line is wrong:
if (playerPosition.x + 1 < gridgenerator.gridWidth * 1.5f)
Your gridWidth variable stores the number of cubes, not their collective spacing. You have 10 cubes representing move spaces, determining the out-of-bounds this value should remain constant (it's still only 10 cubes, even if they're spaced with a half-block worth of space between them).
You need to convert from the player's scene location (transform.position.x) to a board space location (likely dividing by the same multiplier used to space the cubes out).
Alternatively, the "this makes my soul cry" solution of doing this:
if (playerPosition.x + 1.5f < gridgenerator.gridWidth * 1.5f)
Because the next cube is 1.5 scene units away, not 1. And this makes my soul cry because it makes your code full of hard-coded 1.5f multipliers and offsets rather than keeping such things to a single, fixed, constant value stored Elsewhere and used sparingly.
Related:
possibleDirections[0] = "Can go left";
Why are you using stringly typed things? There are values called booleans for a reason...
I'm trying to do a fade between two colors on a weather system in C#. I'm using the following code to fade the color of the keys of a gradient used by the clouds:
void ChangeWeather(string to)
{
Gradient g = skyController.WispyColorGradientColor[0];
GradientColorKey[] gck = new GradientColorKey[5];
GradientAlphaKey[] gak = new GradientAlphaKey[2];
gak[0].alpha = 1f;
gak[1].alpha = 1f;
gak[0].time = 0f;
gak[1].time = 100f;
Color color = new Color();
skyController.WispyColorGradientColor[0] = g;
//Set the initial value
gck[0] = g.colorKeys[0];
gck[1] = g.colorKeys[1];
gck[2] = g.colorKeys[2];
gck[3] = g.colorKeys[3];
gck[4] = g.colorKeys[4];
//refer te variables
g.colorKeys[0] = gck[0];
g.colorKeys[1] = gck[1];
g.colorKeys[2] = gck[2];
g.colorKeys[3] = gck[3];
g.colorKeys[4] = gck[4];
//set the times
gck[0].time = .209f;
gck[1].time = .238f;
gck[2].time = .50f;
gck[3].time = .756f;
gck[4].time = .791f;
if (to == "clear")
{
ColorUtility.TryParseHtmlString(cleanCloudsColors[0], out color);
gck[0].color = Color.Lerp(g.colorKeys[0].color, color, changeSpeed * Time.deltaTime);
gck[4].color = Color.Lerp(g.colorKeys[4].color, color, changeSpeed * Time.deltaTime);
ColorUtility.TryParseHtmlString(cleanCloudsColors[1], out color);
gck[1].color = Color.Lerp(g.colorKeys[1].color, color, changeSpeed * Time.deltaTime);
gck[3].color = Color.Lerp(g.colorKeys[3].color, color, changeSpeed * Time.deltaTime);
ColorUtility.TryParseHtmlString(cleanCloudsColors[2], out color);
gck[2].color = Color.Lerp(g.colorKeys[2].color, color, changeSpeed * Time.deltaTime);
Debug.Log("Changing");
}
}
The "skyController.WispyColorGradientColor[0]" refers to a Gradient in a array list and "ColorUtility.TryParseHtmlString" just convert a hex color (like #fff) to RGB. It log "Changing" but, well, the clouds were changing color without fade, so I made these changes and it does not change more. I NEED THE FADE, but nothing seems to work. :(
EDIT: I used a code like it to try to fade between colors in 5 seconds:
float fadeTime = 5f;
void Update(){
//...
if (param)
StartCoroutine(fadeColor(0, Color.grey, Color.white));
//...
}
IEnumerator fadeColor (int index, Color from, Color to){
float counter = 0;
while (counter < fadeTime){
counter += Time.deltaTime;
gradient.colorKeys[index].color = Color.Lerp(from, to, counter / fadeTime);
}
yield return null;
}
It change the color, but change instantly and I want to change over time.
Not able to understand your code and but all I know is that you want to fade between two Colors. This should be done with Coroutine. The function below should fade between two colors in any GameObject. You can easily modify it to suit whatever you are doing.
The function call below will change the GameObject's color to red in 5 seconds.
StartCoroutine(fadeColor(obj, Color.red, 5));
Fade Function:
IEnumerator fadeColor(GameObject objectToFade, Color newColor, float fadeTime = 3)
{
int mode = 0;
Color currentColor = Color.clear;
SpriteRenderer tempSPRenderer = objectToFade.GetComponent<SpriteRenderer>();
Image tempImage = objectToFade.GetComponent<Image>();
RawImage tempRawImage = objectToFade.GetComponent<RawImage>();
Renderer tempRenderer = objectToFade.GetComponent<Renderer>();
//Check if this is a Sprite
if (tempSPRenderer != null)
{
currentColor = tempSPRenderer.color;
mode = 0;
}
//Check if Image
else if (tempImage != null)
{
currentColor = tempImage.color;
mode = 1;
}
//Check if RawImage
else if (tempRawImage != null)
{
currentColor = tempRawImage.color;
mode = 2;
}
//Check if 3D Object
else if (tempRenderer != null)
{
currentColor = tempRenderer.material.color;
mode = 3;
}
else
{
yield break;
}
float counter = 0;
while (counter < fadeTime)
{
counter += Time.deltaTime;
switch (mode)
{
case 0:
tempSPRenderer.color = Color.Lerp(currentColor, newColor, counter / fadeTime);
break;
case 1:
tempImage.color = Color.Lerp(currentColor, newColor, counter / fadeTime);
break;
case 2:
tempRawImage.color = Color.Lerp(currentColor, newColor, counter / fadeTime);
break;
case 3:
tempRenderer.material.color = Color.Lerp(currentColor, newColor, counter / fadeTime);
break;
}
yield return null;
}
}
I've been working on building a procedural generator for Unity, that takes in noise and uses it to build a height map.
So far, everything seems to work as long as I limit the size of the mesh to around 250x250. If I attempt to make a larger mesh, the script won't calculate it.
The puzzling thing is that I get no memory errors or anything of that nature. I've implemented a Regenerate button that allows me to generate a new mesh in Unity and as long as I remain in the range of 250x250 or less, it works fine. If I pick a larger value, the mesh simply remains unchanged.
How I calculate the Mesh:
using UnityEngine;
using System.Collections;
using UnityEditor;
using System.IO;
[ExecuteInEditMode]
[RequireComponent(typeof(MeshFilter))]
[RequireComponent(typeof(Noise))]
public class CustomTerrain : MonoBehaviour {
//Note: sizeX*sizeZ determines mesh size.
public int sizeX = 4; //These values are public so they can be
public int sizeZ = 4; //modified in the Unity Editor.
public float noiseSize = 1.0f;
public float cellSize = 1.0f;
private string mPath = "Assets/Generated/";
Noise noise;
void Start() {
noise = GetComponent<Noise>();
this.LoadMesh();
if (!GetComponent<MeshFilter>().sharedMesh) {
this.Regenerate();
}
}
public void LoadMesh() {
Mesh mesh = Instantiate(AssetDatabase.LoadMainAssetAtPath(mPath + gameObject.name + ".asset") as Mesh);
if (mesh) {
GetComponent<MeshFilter>().mesh = mesh;
}
recalculateMeshCollider(mesh);
}
Vector3[] GenVertices() {
float x, z;
int w = (sizeX+1);
int l = (sizeZ+1);
Vector3[] vertices = new Vector3[w*l];
for (int gx = 0; gx < w; gx++) {
for (int gz = 0; gz < l; gz++) {
x = gx*cellSize;
z = gz*cellSize;
float height = (noiseSize * noise.Get(x,z));
vertices[gx*l+gz] = new Vector3(x, height, z);
}
}
return vertices;
}
int[] GenTriangles() {
int vertciesPerTriangle = 3;
int trianglesPerCell = 2;
int numberCells = sizeX * sizeZ;
int[] triangles = new int[vertciesPerTriangle * trianglesPerCell * numberCells];
int tIndeX = 0;
for (int cX = 0; cX < sizeX; cX++) {
for (int cZ = 0; cZ < sizeZ; cZ++) {
int n = cX*(sizeZ+1)+cZ;
triangles[tIndeX] = n;
triangles[tIndeX+1] = n+1;
triangles[tIndeX+2] = n+sizeZ+2;
triangles[tIndeX+3] = n;
triangles[tIndeX+4] = n+sizeZ+2;
triangles[tIndeX+5] = n+sizeZ+1;
tIndeX +=6;
}
}
return triangles;
}
Vector2[] GenUVs() {
int w = (sizeX + 1);
int l = (sizeZ + 1);
Vector2[] uvs = new Vector2[w * l];
for (int uX = 0; uX < w; uX++) {
for (int uZ = 0; uZ < l; uZ++) {
uvs[uX*l+uZ] = new Vector2((float)uX/sizeX, (float)uZ/sizeZ);
}
}
return uvs;
}
}
My Regenerate function:
public void Regenerate() {
noise.Init();
Mesh mesh = GetComponent<MeshFilter>().sharedMesh;
if(!mesh) {
mesh = new Mesh();
GetComponent<MeshFilter>().sharedMesh = mesh;
}
mesh.vertices = GenVertices();
mesh.triangles = GenTriangles();
mesh.uv = GenUVs();
mesh.RecalculateNormals();
recalculateMeshCollider(mesh);
}
public void recalculateMeshCollider(Mesh mesh) {
if (GetComponent<MeshCollider>()) {
DestroyImmediate(GetComponent<MeshCollider>());
}
transform.gameObject.AddComponent<MeshCollider>();
transform.GetComponent<MeshCollider>().sharedMesh = mesh;
}
By "250x250" do you mean there's 62.400 triangles?
Unity has a vertex limit of 65535 count - just use more than one mesh, no trouble.
I am following a tutorial in a book called Learn the Kinect API by Rob Miles.
Basically, it's an augmented reality game where spiders fall from the top of the screen and you hit them with a Mallet. After following the tutorial and looking at the codes, I understand how the spiders fall and how their position are randomized etc.
I have problem understanding the mallet though, I wish to replace the mallet with an image of a basket instead.
This is how the code for the mallet looks like
Brush malletHandleBrush = new SolidColorBrush(Colors.Black);
Brush malletHeadBrush = new SolidColorBrush(Colors.Red);
float malletHandleLength = 100;
float malletHeadLength = 50;
System.Windows.Vector malletPosition;
float malletHitRadius = 40;
bool malletValid = false;
void updateMallet(Joint j1, Joint j2)
{
// If Joint 1 (Right Wrist) or Joint 2 (Right Hand) is not tracked, we stop here
if (j1.TrackingState != JointTrackingState.Tracked || j2.TrackingState != JointTrackingState.Tracked)
return;
// Get the start and end positions of the mallet vector
ColorImagePoint j1P = myKinect.CoordinateMapper.MapSkeletonPointToColorPoint(j1.Position, ColorImageFormat.RgbResolution640x480Fps30);
ColorImagePoint j2P = myKinect.CoordinateMapper.MapSkeletonPointToColorPoint(j2.Position, ColorImageFormat.RgbResolution640x480Fps30);
int dX = j2P.X - j1P.X;
int dY = j2P.Y - j1P.Y;
System.Windows.Vector malletDirection = new System.Windows.Vector(dX, dY);
if (malletDirection.Length < 1) return;
// Convert into a vector of length 1 unit
malletDirection.Normalize();
// now set the length of the mallet
System.Windows.Vector handleVector = malletDirection * malletHandleLength;
Line handleLine = new Line();
handleLine.Stroke = malletHandleBrush;
handleLine.StrokeThickness = 10;
handleLine.X1 = j1P.X;
handleLine.Y1 = j1P.Y;
handleLine.X2 = j1P.X + handleVector.X;
handleLine.Y2 = j1P.Y + handleVector.Y;
//malletCanvas.Children.Add(handleLine);
Line headLine = new Line();
headLine.Stroke = malletHeadBrush;
headLine.StrokeThickness = 50;
System.Windows.Vector headVector = malletDirection * malletHeadLength;
headLine.X1 = handleLine.X2;
headLine.Y1 = handleLine.Y2;
headLine.X2 = handleLine.X2 + headVector.X;
headLine.Y2 = handleLine.Y2 + headVector.Y;
//malletCanvas.Children.Add(headLine);
malletPosition = new System.Windows.Vector(j1P.X, j1P.Y);
malletPosition = malletPosition + (malletDirection * (malletHandleLength + (malletHeadLength / 2)));
malletValid = true;
}
This is how the code for detecting if the mallet hits the objects looks like
// Declare Hit Vector for each Dollar Note
System.Windows.Vector _spiderHitVector = new System.Windows.Vector(malletPosition.X - _spiderCenterX, malletPosition.Y - _spiderCenterY);
Does anyone have any resources or give me some hints on how to work on this?