C#/Unity/Hybrid ECS - Trying to convert GameObject into ECS Entity - c#

I am Using Unity 2019.2.14f.
Here is my code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Unity.Entities;
using Unity.Transforms;
using Unity.Collections;
public class GameSystem : MonoBehaviour
{
public GameObject player;
public int spawnNumber;
public bool useECS;
private EntityManager manager;
// Start is called before the first frame update
void Start()
{
manager = World.Active.EntityManager;
if (useECS)
{
SpawnECS(player);
}
else
{
for (int i = 0; i <= spawnNumber; i++)
{
Spawn(player);
}
}
}
// Update is called once per frame
void Update()
{
}
private void Spawn(GameObject unit)
{
float x = Random.Range(5, 249);
float y = 0f;
float z = Random.Range(5, 249);
float rx = 0f;
float ry = Random.Range(1, 180);
float rz = 0f;
Instantiate(unit, new Vector3(x, y, z), Quaternion.Euler(rx,ry,rz));
}
private void SpawnECS(GameObject unit)
{
float x = Random.Range(5, 249);
float y = 0f;
float z = Random.Range(5, 249);
float rx = 0f;
float ry = Random.Range(1, 180);
float rz = 0f;
NativeArray<Entity> players = new NativeArray<Entity>(spawnNumber, Allocator.Temp);
manager.Instantiate(unit, players);
players.Dispose();
}
}
This is the prefab which I am instantiating:
When I select on my GameSystem component useECS to be true I can see it is creating enteties into my entity debugger. Take a look:
So as you can see Entities are created. However when I inspect one Entity here is what I see:
As you can see Components are not converted. Where is my mistake?
How can I create visible entity out of GameObhject Prefab or use the so-called Hybrid ECS method?

NativeArray<Entity> players = new NativeArray<Entity>( 3 , Allocator.Temp );
Is equivalent to writing :
var players = new GameObject[]{ new GameObject() , new GameObject() , new GameObject() };
It's a list of prefab entities, that are completely empty. This is why spawning that list will give N amount of default entities.
What to should do instead is to convert that player GameObject to an entity prefab and instantiate that entity prefab N times (or populate that NativeArray with set of entity prefabs)
Entity entityPrefab = GameObjectConversionUtility.ConvertGameObjectHierarchy( gameObjectPrefab );

Related

How can I move the transform randomly in ping pong?

First I generate new objects in this example 1000 objects over the terrain in height 10 in random positions :
using System;
using UnityEngine;
using Random = UnityEngine.Random;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
public class CloneObjects : MonoBehaviour
{
public Terrain terrain;
public GameObject prefab;
public GameObject parent;
[Range(10, 1000)]
public int numberOfObjects;
public float yOffset = 10f;
private float terrainWidth;
private float terrainLength;
private float xTerrainPos;
private float zTerrainPos;
void Start()
{
//Get terrain size
terrainWidth = terrain.terrainData.size.x;
terrainLength = terrain.terrainData.size.z;
//Get terrain position
xTerrainPos = terrain.transform.position.x;
zTerrainPos = terrain.transform.position.z;
generateObjectOnTerrain();
}
void generateObjectOnTerrain()
{
for (int i = 0; i < numberOfObjects; i++)
{
//Generate random x,z,y position on the terrain
float randX = UnityEngine.Random.Range(xTerrainPos, xTerrainPos + terrainWidth);
float randZ = UnityEngine.Random.Range(zTerrainPos, zTerrainPos + terrainLength);
float yVal = Terrain.activeTerrain.SampleHeight(new Vector3(randX, 0, randZ));
//Apply Offset if needed
yVal = yVal + yOffset;
//Generate the Prefab on the generated position
GameObject objInstance = Instantiate(prefab, new Vector3(randX, yVal, randZ), Quaternion.identity);
objInstance.name = "Waypoint";
objInstance.tag = "Waypoint";
objInstance.transform.parent = parent.transform;
}
}
}
The result is :
And then on each object there is a script attached :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MoveObject : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
transform.position = new Vector3(Mathf.PingPong(Time.time * 3, Random.Range(2f, 9f)), transform.position.y, transform.position.z);
}
}
The problem is that the objects are not moving in ping pong from the original spawned positions like in the screenshot on the top the first screenshot but they are all moving first to the edge of the terrain and making the ping pong there :
PingPong is a lot like Lerp. You need to supply a time value to it, not a delta time. As such, you'll want to store the initial object height, and work out how high you want to pingpong on top of that.
This example code will do just that:
public float Speed;
private float intitialY;
private float pingPongHeight;
private void Start ( )
{
intitialY = transform.localPosition.y;
pingPongHeight = UnityEngine.Random.Range ( 2f, 9f );
}
private void Update ( )
{
var height = Mathf.PingPong ( Time.time * Speed, pingPongHeight );
var position = transform.localPosition;
position.y = intitialY + height;
transform.localPosition = position;
}
I've assumed you used a random value to determine how high each object will travel over the course of the pingpong.

How can I rotate the camera around group of objects and not only a single one?

The camera is child of one soldier only and also the target is this soldier.
And the script attached to the camera.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CameraMove : MonoBehaviour
{
public Transform target;
public float speed = 0.1f;
// Use this for initialization
void Start ()
{
}
// Update is called once per frame
void Update ()
{
transform.RotateAround(target.transform.position, new Vector3(0, 1, 0), 100 * Time.deltaTime * speed);
}
}
But now I want to do two things. To make the camera to rotate around the whole soldiers and not only the specific one. And also to make the camera stop slowly when it's facing the soldiers. Now the camera is behind when starting the game.
Using a bool flag if true to make the camera rotate around the soldiers until it's facing them then stop rotation and keep moving with the soldiers.
If unchecked false make the camera rotating around the solders none stop.
UPDATE what I tried so far:
This code will make it rotating around all the soldiers and it's working fine:
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
public class CameraMove : MonoBehaviour
{
public float speed = 0.1f;
private List<GameObject> Soldiers = new List<GameObject>();
// Use this for initialization
void Start()
{
Soldiers.AddRange(GameObject.FindGameObjectsWithTag("Soldier"));
}
// Update is called once per frame
void Update()
{
RotateAround();
}
private void RotateAround()
{
transform.RotateAround(GetAverageLocationOfSoliders(), new Vector3(0, 1, 0), 100 * Time.deltaTime * speed);
}
private Vector3 GetAverageLocationOfSoliders()
{
var total = new Vector3();
foreach (var soldier in Soldiers)
total += soldier.transform.position;
return total / Soldiers.Count(); // Assuming Soldiers is List<Soldier>
}
}
Then I tried to add a slowDown bool flag variable, But I messed it all and it's not working at all.
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
public class CameraMove : MonoBehaviour
{
public float speed = 0.1f;
public bool slowDown = false;
private List<Vector3> SoldiersPositions = new List<Vector3>();
private List<Vector3> SoldiersFacingDirection = new List<Vector3>();
// Use this for initialization
void Start()
{
}
// Update is called once per frame
void FixedUpdate()
{
RotateAround();
}
private void RotateAround()
{
var getSoldiers = GameObject.FindGameObjectsWithTag("Soldier");
foreach (GameObject soldier in getSoldiers)
{
SoldiersPositions.Add(soldier.transform.position);
SoldiersFacingDirection.Add(soldier.transform.forward);
}
var Center = GetAverageLocationOfSoliders();
var FacingDirections = GetAverageFacingDirectionOfSoldiers();
if (slowDown == true)
{
var D = transform.position - Center;
var CamAngle = Vector3.Angle(D, FacingDirections);
speed = speed - CamAngle;
}
transform.RotateAround(Center, new Vector3(0, 1, 0), 100 * Time.deltaTime * speed);
SoldiersPositions = new List<Vector3>();
SoldiersFacingDirection = new List<Vector3>();
}
private Vector3 GetAverageLocationOfSoliders()
{
var total = new Vector3();
foreach (var soldier in SoldiersPositions)
total += soldier;
return total / SoldiersPositions.Count(); // Assuming Soldiers is List<Soldier>
}
private Vector3 GetAverageFacingDirectionOfSoldiers()
{
var total = new Vector3();
foreach (var soldierfacingdir in SoldiersFacingDirection)
total += soldierfacingdir;
return total / SoldiersFacingDirection.Count();
}
}
I'm not sure if the first code example only for the rotation is fine the way I wrote it. It's working but not sure if this is a good way to do the code ?
It seems to me that in the first code only the rotation the camera is a bit shaking or stuttering I mean the camera is not moving smooth when rotating around. It's almost hard to see in the game view in the editor but you can see it a bit in the scene view I think.
The reason I'm calling RotateAround(); in the Update is that the soldiers are in a move they are walking forward non stop.
How should I do the slowDown part ?
UPDATE 2:
This is the full coed now:
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
public class CameraMove : MonoBehaviour
{
[Header("Spin")]
public bool spin = false;
public Vector3 Direction;
[Range(0, 300)]
public float speed = 10f;
public bool randomSpeed = false;
public bool randomDirection = false;
[Range(0f, 100f)]
public float timeDirChange;
public Vector3 defaultDirection;
[Space(5)]
[Header("Move in circles")]
public bool moveInCircles = true;
public GameObject rotateAroundTarget;
public Vector3 axis;//by which axis it will rotate. x,y or z.
public float rotationSpeed; //or the speed of rotation.
public float upperLimit, lowerLimit, delay;// upperLimit & lowerLimit: heighest & lowest height;
public bool randomHeight = false;
public bool stopRotatingWhenFacing = false;
private float height, prevHeight, time;//height:height it is trying to reach(randomly generated); prevHeight:stores last value of height;delay in radomness;
[Space(5)]
[Header("Follow objects")]
public GameObject[] objectsToFollow;
public bool randomFollow;
private float nextRotationTime = 0f;
private int counter = 0;
private List<GameObject> Soldiers = new List<GameObject>();
// Use this for initialization
void Start()
{
Soldiers.AddRange(GameObject.FindGameObjectsWithTag("Soldier"));
}
private void Update()
{
if (randomSpeed)
{
speed = UnityEngine.Random.Range(0, 300);
}
if (spin)
{
if (randomDirection == false)
{
nextRotationTime = 0;
timeDirChange = 0;
Direction = defaultDirection;
}
else
{
if (Time.time > nextRotationTime)
{
nextRotationTime += timeDirChange;
RandomDirection();
}
}
transform.Rotate(Direction, speed * Time.deltaTime);
}
else
{
timeDirChange = 0;
randomDirection = false;
randomSpeed = false;
}
if (moveInCircles)
{
MoveInCircles();
}
}
private void RandomDirection()
{
Direction = new Vector3(UnityEngine.Random.Range(-1, 1), UnityEngine.Random.Range(-1, 1), UnityEngine.Random.Range(-1, 1));
while (Direction == new Vector3(0, 0, 0))
{
counter++;
Direction = new Vector3(UnityEngine.Random.Range(-1, 1), UnityEngine.Random.Range(-1, 1), UnityEngine.Random.Range(-1, 1));
if (counter == 2)
{
Direction = new Vector3(1, 0, 0);
break;
}
}
counter = 0;
}
private void MoveInCircles()
{
var F = GetAverageDirectionsOfSoliders();
var D = transform.position - GetAverageLocationOfSoliders();
var angle = Vector3.Angle(D, F);
if (angle < 5f)
{
rotationSpeed -= 0.1f;
}
transform.RotateAround(GetAverageLocationOfSoliders(), axis, rotationSpeed);
time += Time.deltaTime;
//Sets value of 'height' randomly within 'upperLimit' & 'lowerLimit' after delay
if (time > delay)
{
prevHeight = height;
if (randomHeight)
{
height = UnityEngine.Random.Range(lowerLimit, upperLimit);
}
time = 0;
}
if (randomHeight == false)
{
height = transform.position.y;
}
if (randomHeight)
{
//Mathf.Lerp changes height from 'prevHeight' to 'height' gradually (smooth transition)
transform.position = new Vector3(transform.position.x, Mathf.Lerp(prevHeight, height, time), transform.position.z);
}
else
{
transform.position = new Vector3(transform.position.x, height, transform.position.z);
}
}
private Vector3 GetAverageLocationOfSoliders()
{
var total = new Vector3();
foreach (var soldier in Soldiers)
{
total += soldier.transform.position;
}
return total / Soldiers.Count(); // Assuming Soldiers is List<Soldier>
}
private Vector3 GetAverageDirectionsOfSoliders()
{
var totalf = new Vector3();
foreach (var soldier in Soldiers)
{
totalf += soldier.transform.forward;
}
return totalf / Soldiers.Count();
}
}
The RotateAround part is working fine:
transform.RotateAround(GetAverageLocationOfSoliders(), axis, rotationSpeed);
But the slow down part is not working. It's not slowing down at all when the camera is facing the soldiers.
This is how I calculate the average transform.forward vector of all the soldiers:
private Vector3 GetAverageDirectionsOfSoliders()
{
var totalf = new Vector3();
foreach (var soldier in Soldiers)
{
totalf += soldier.transform.forward;
}
return totalf / Soldiers.Count();
}
Then inside the MoveInCircles method I did:
var F = GetAverageDirectionsOfSoliders();
var D = transform.position - GetAverageLocationOfSoliders();
var angle = Vector3.Angle(D, F);
if (angle < 5f)
{
rotationSpeed -= 0.1f;
}
But it's never getting to the line:
rotationSpeed -= 0.1f;
To rotate around all the soldiers:
Get the center of the all the soldiers (sum the world position of all soldiers and divide by N number of soldiers)
Get the maximum distance of the soldiers from the center
Rotate the camera about the center, and ensure that it is further than the max distance from the center
To slow the camera down when facing the soldiers' front:
Average out the transform.forward vector of all the soldiers. We call this vector F. This is fair since all your soldiers will typically be facing in the same general direction for this request to even make sense.
Calculate the direction D, which is the direction from the soldiers' center to the camera. This is easy: D = camera.transform.position - soldiersCenter
Finally, find the acute angle between D and F, using Vector3.Angle(). If this angle is lower than a certain threshold, decrease the moveSpeed of the camera.
The actual code is easy to write, but I'll let you practice. Let me know if you need any help
From the sounds of it, it seems you have it already able to orbit around a single soldier, so do to more than one, simply take the average of their locations.
Pseudo code:
transform.RotateAround(GetAverageLocationOfSoliders(), ...);
...
private static Vector3 GetAverageLocationOfSoliders
{
var total = new Vector3();
foreach(var soldier in Soldiers)
total += soldier.transform.position;
return total / Soliders.Count(); // Assuming Soldiers is List<Soldier>
}
Now, Vector3 might not have stuff like Vector3 += Vector3 or Vector3 / int, but if that's the case just create your own methods were you do that manually (adding vectorA.x + vectorB.x, and vectorA.x / num, etc.
As far as making the camera stop when it's in front, that's a bit trickier. You might want to do some checks first to make sure they all have the same rotation, and then check, each Update, if the look at rotation of the camera will point to one of the soldiers.
But, if you want it to slow down, then, instead of checking if the lookAtRotation can point to a soldier, check if it can point to some offset of the camera's rotation, like so:
Pseudo Code:
lookRotation(transform.Rotation + offset) // Use something like this to find Soldiers[0]
Then, if that finds one, you can use a Lerp on your speed to lerp back down to a speed of 0.
You will also have to maintain a List<Soldier> or Soldier[] somehow.

Why when drawing line in the scene view between two positions the lines deleted?

What i'm trying to do is to draw lines between two positions and a route of a cube movement without deleting the lines.
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
public class SpawnObjects : MonoBehaviour
{
public int numberOfObjects;
public GameObject objectToPlace;
public Vector3 newObjectsSize = new Vector3(5, 5, 5);
public float speed;
private int wallsLengthX;
private int wallsLengthZ;
private int wallsPosX;
private int wallsPosZ;
private int currentObjects;
private List<GameObject> objects = new List<GameObject>();
void Start()
{
var wi = GetComponent<WallsTest>();
wallsLengthX = (int)wi.lengthX;
wallsLengthZ = (int)wi.lengthZ;
wallsPosX = (int)wi.wallsStartPosition.x;
wallsPosZ = (int)wi.wallsStartPosition.z;
}
// Update is called once per frame
void Update()
{
Spawn();
var randpos = GenerateRandomPositions(objects[0]);
objects[0].transform.position = Vector3.Lerp(objects[0].transform.position,
randpos, (Mathf.Sin(speed * Time.deltaTime)));
Debug.DrawLine(objects[0].transform.position, randpos, Color.red);
}
private void Spawn()
{
if (currentObjects != numberOfObjects)
{
if (objects.Count != 1) // Why did i make a check if not = 1 ?
{
GameObject newObject = (GameObject)Instantiate(objectToPlace);
newObject.transform.localScale = new Vector3(newObjectsSize.x, newObjectsSize.y, newObjectsSize.z);
newObject.transform.localPosition = GenerateRandomPositions(newObject);
newObject.name = "Spawned Object";
newObject.tag = "Spawned Object";
objects.Add(newObject);
currentObjects += 1;
}
}
}
private Vector3 GenerateRandomPositions(GameObject newObject)
{
float paddingX = Mathf.Clamp(newObject.transform.localScale.x, 0, wallsLengthX) / 2f;
float paddingZ = Mathf.Clamp(newObject.transform.localScale.z, 0, wallsLengthZ) / 2f;
float originX = wallsPosX + paddingX - wallsLengthX / 2f;
float originZ = wallsPosZ + paddingZ - wallsLengthZ / 2f;
float posx = UnityEngine.Random.Range(originX, originX + wallsLengthX - paddingX);
float posz = UnityEngine.Random.Range(originZ, originZ + wallsLengthZ - paddingZ);
float posy = Terrain.activeTerrain.SampleHeight(new Vector3(posx, 0, posz));
return new Vector3(posx, posy, posz);
}
}
When i'm using the Debug.DrawLine:
Debug.DrawLine(objects[0].transform.position, randpos, Color.red);
It's drawing the lines but then delete them. How can i make that it will keep the lines ?
And how can i draw a line in green and also to keep it so it will not delete that show the cube movement route ? The cube is the objects[0]
Well, as you've said yourself, lines are drawn, not created.
They aren't objects, and will not have such behavior as "persisting until deleted". They are "deleted" every single frame.
You can specify a time for the editor to keep (re)drawing them for, using the 4th parameter; but that's the editor taking care of redrawing them every frame; they will still be "deleted" at the end of the frame.
Here is the full method signature: public static void DrawLine(Vector3 start, Vector3 end, Color color = Color.white,float duration = 0.0f, bool depthTest = true);
A duration of 0 means the line is rendered only for the current frame. A value of 0.5f would mean the line will be (re)rendered for all frames within the next half second.

Unity 5 renderer.material.setTexture("_PARALLAXMAP"); Won't change the heightmap

So I have been working on a piece of code that generates a perlin noise texture and applies it to a plane in order to create waves. But I can't get it to set the heightmap texture of the material. I have included material.EnableKeyword("_PARALLAXMAP"); but it does nothing. I have tried this with the normal map as well, without results. Here's the full code.
using UnityEngine;
using System.Collections;
public class NoiseGenerator : MonoBehaviour {
private Texture2D noiseTex;
private float x = 0.0F;
private float y = 0.0F;
public int scale = 10;
private Color[] pixels;
public float speed;
public float move = 0.0F;
void Start () {
Renderer render = GetComponent<Renderer>();
noiseTex = new Texture2D(scale,scale);
render.material = new Material(Shader.Find("Standard"));
render.material.EnableKeyword("_PARALLAXMAP");
render.material.SetTexture("_PARALLAXMAP", noiseTex);
pixels = new Color[noiseTex.width * noiseTex.height];
}
void Update () {
float y = 0.0F;
while (y < noiseTex.height)
{
float x = 0.0F;
while (x < noiseTex.width)
{
float xCoord = move + x / noiseTex.width * scale;
float yCoord = move + y / noiseTex.height * scale;
float sample = Mathf.PerlinNoise(xCoord, yCoord);
pixels[Mathf.RoundToInt(y) * noiseTex.width + Mathf.RoundToInt(x)] = new Color(sample, sample, sample);
x++;
}
y++;
}
noiseTex.SetPixels(pixels);
noiseTex.Apply();
move = move + speed;
}
}
You need to include a Material that use this Parallax variant to notify Unity about you need this.
This can be used in the scene or include in the resource folder.
If not Unity omit this on build how unused.
Just use
ur_material.SetFloat("_Parallax",[value])

Attempting to get a Hex grid

Im trying to get the hex prefab shapes that have already been created to line up with one another in a grid formation. I got the grid but I can't seem to get the hexes to fit into each other. Fixed the y%2 but the way it is setup now it crashes.
using UnityEngine;
using System.Collections;
public class boardObject : MonoBehaviour {
// Instantiates a prefab in a grid
public GameObject prefab;
public float gridX = 5f;
public float gridY = 5f;
public float spacing = 2f;
void Start() {
for (float y = 0.0f; y < gridY; y++) {
for (float x = 0.0f; x < gridX; x++) {
// THIS IS WHAT WAS MISSING FOR THIS TO ACTUALLY WORK MAKING A NEW VECTOR 3
// POSITION AFTER THE LOOP WAS SET UP. EACH NEW hex NEEDED HAVE A NEW POSITION. ->
Vector3 pos = new Vector3(x, 0.0f, y) * spacing;
//
//
//%2 thingy
if (y%2.0f==0.0f)
gridY += 0.5f;
else
gridY -= 0.0f;
Instantiate(prefab, pos, Quaternion.identity);
}
}
}
}
First pic is the one I have, second is the one I am trying to make.
This is the square board hex
This is what I am trying to do
using UnityEngine;
using System.Collections;
public class boardObject : MonoBehaviour {
// Instantiates a prefab in a grid
public GameObject prefab;
public float gridX = 5f;
public float gridY = 5f;
public float spacing = 2f;
public float xsize = 1.0f;
public float ysize = 1.0f;
void Start() {
for (float y = 0; y < gridY; y++) {
for (float x = 1; x < gridX; x++) { //<<<<<This is where the change was made to get it to work. x = 1 instead of 0.
Vector3 pos = new Vector3 (x * xsize, 0.0f, y * ysize) ;
Instantiate (prefab, pos, Quaternion.identity);
if (y % 2 == 0)
y += 1;
else
y -= 1;
}
}
}
void Update() {
}
}

Categories

Resources