applying direction to npc XNA - c#

I have NPC's in my game that follow a script where they move randomly around the game. I would like them to face the direction they are moving in though.
for (int i = 0; i < GameConstants.NumDaleks; i++)
{
if (dalekList[i].isActive)
{
Vector3 line = dalekList[i].direction;
float rotationDal = (float)(Math.Atan2(dalekList[i].position.Y, dalekList[i].position.X) / (2 * Math.PI));
Matrix dalekTransform = Matrix.CreateScale(GameConstants.DalekScalar) * Matrix.CreateRotationY(rotationDal) * Matrix.CreateTranslation(dalekList[i].position);
DrawModel(mdlDalek, dalekTransform, mdDalekTransforms);
}
}
I'm sure it must be something to do with rotationDal, I have tried changing the calculation and the characters do seem to rotate differently, just not in their current direction

Xna has a built in function that you might find handy here.
Matrix.CreateWorld(positionVector, DirectionVector, UpVector);
here's the doc: http://msdn.microsoft.com/en-us/library/bb975261(v=xnagamestudio.40).aspx
In your case:
for (int i = 0; i < GameConstants.NumDaleks; i++)
{
if (dalekList[i].isActive)
{
Matrix dalekTransform = Matrix.CreateScale(GameConstants.DalekScalar) * Matrix.CreateWorld(dalekList[i].position, dalekList[i].direction, Vector3.Up);
DrawModel(mdlDalek, dalekTransform, mdDalekTransforms);
}
}

Related

How to arrange objects like in 'snake' in unity?

the idea is how to align objects like in photo below, what formula need to use for this?
Now I can only do it this way, through sin or cos
void Start()
{
for (int i = 0; i < 50; i++)
characters.Add(Instantiate(characterPrefab, charactersParent));
}
// Update is called once per frame
void Update()
{
for (int i = 0; i < characters.Count; i++)
{
float x = Mathf.Cos(i * verticalLines * Mathf.PI / characters.Count) * horizontalRadius;
characters[i].GetComponent<RectTransform>().anchoredPosition = new Vector3(x, -i * (1920f / characters.Count), 0);
}
}
In snake your rewards/bug eated are added on the opposite direction that the last body-part is facing.
The problem here is how you stablish your current snake movement, to get the opposite direction.
Let's guess that your movement is x += 1, then your opposite position will be your X position on your characters[characters.Count] and go on the opposite direction x -=1.

Unity, get the "actual" current Terrain?

Unity has a function Terrain.sampleHeight(point) which is great, it instantly gives you the height of the Terrain underfoot rather than having to cast.
However, any non-trivial project has more than one Terrain. (Indeed any physically large scene inevitably features terrain stitching, one way or another.)
Unity has a function Terrain.activeTerrain which - I'm not making this up - gives you: the "first one loaded"
Obviously that is completely useless.
Is fact, is there a fast way to get the Terrain "under you"? You can then use the fast function .sampleHeight ?
{Please note, of course, you could ... cast to find a Terrain under you! But you would then have your altitude so there's no need to worry about .sampleHeight !}
In short is there a matching function to use with sampleHeight which lets that function know which Terrain to use for a given xyz?
(Or indeed, is sampleHeight just a fairly useless demo function, usable only in demos with one Terrain?)
Is there in fact a fast way to get the Terrain "under you" - so as to
then use the fast function .sampleHeight ?
Yes, it can be done.
(Or indeed, is sampleHeight just a fairly useless demo function,
usable only in demos with one Terrain?)
No
There is Terrain.activeTerrain which returns the main terrain in the scene. There is also Terrain.activeTerrains (notice the "s" at the end) which returns active terrains in the scene.
Obtain the terrains with Terrain.activeTerrains which returns Terrain array then use Terrain.GetPosition function to obtain its position. Get the current terrain by finding the closest terrain from the player's position. You can do this by sorting the terrain position, using Vector3.Distance or Vector3.sqrMagnitude (faster).
Terrain GetClosestCurrentTerrain(Vector3 playerPos)
{
//Get all terrain
Terrain[] terrains = Terrain.activeTerrains;
//Make sure that terrains length is ok
if (terrains.Length == 0)
return null;
//If just one, return that one terrain
if (terrains.Length == 1)
return terrains[0];
//Get the closest one to the player
float lowDist = (terrains[0].GetPosition() - playerPos).sqrMagnitude;
var terrainIndex = 0;
for (int i = 1; i < terrains.Length; i++)
{
Terrain terrain = terrains[i];
Vector3 terrainPos = terrain.GetPosition();
//Find the distance and check if it is lower than the last one then store it
var dist = (terrainPos - playerPos).sqrMagnitude;
if (dist < lowDist)
{
lowDist = dist;
terrainIndex = i;
}
}
return terrains[terrainIndex];
}
USAGE:
Assuming that the player's position is transform.position:
//Get the current terrain
Terrain terrain = GetClosestCurrentTerrain(transform.position);
Vector3 point = new Vector3(0, 0, 0);
//Can now use SampleHeight
float yHeight = terrain.SampleHeight(point);
While it's possible to do it with Terrain.SampleHeight, this can be simplified with a simple raycast from the player's position down to the Terrain.
Vector3 SampleHeightWithRaycast(Vector3 playerPos)
{
float groundDistOffset = 2f;
RaycastHit hit;
//Raycast down to terrain
if (Physics.Raycast(playerPos, -Vector3.up, out hit))
{
//Get y position
playerPos.y = (hit.point + Vector3.up * groundDistOffset).y;
}
return playerPos;
}
Terrain.GetPosition() = Terrain.transform.position = position in world
working method:
Terrain[] _terrains = Terrain.activeTerrains;
int GetClosestCurrentTerrain(Vector3 playerPos)
{
//Get the closest one to the player
var center = new Vector3(_terrains[0].transform.position.x + _terrains[0].terrainData.size.x / 2, playerPos.y, _terrains[0].transform.position.z + _terrains[0].terrainData.size.z / 2);
float lowDist = (center - playerPos).sqrMagnitude;
var terrainIndex = 0;
for (int i = 0; i < _terrains.Length; i++)
{
center = new Vector3(_terrains[i].transform.position.x + _terrains[i].terrainData.size.x / 2, playerPos.y, _terrains[i].transform.position.z + _terrains[i].terrainData.size.z / 2);
//Find the distance and check if it is lower than the last one then store it
var dist = (center - playerPos).sqrMagnitude;
if (dist < lowDist)
{
lowDist = dist;
terrainIndex = i;
}
}
return terrainIndex;
}
It turns out the answer is simply NO, Unity does not provide such a function.
You can use this function to get the Closest Terrain to your current Position:
int GetClosestTerrain(Vector3 CheckPos)
{
int terrainIndex = 0;
float lowDist = float.MaxValue;
for (int i = 0; i < _terrains.Length; i++)
{
var center = new Vector3(_terrains[i].transform.position.x + _terrains[i].terrainData.size.x / 2, CheckPos.y, _terrains[i].transform.position.z + _terrains[i].terrainData.size.z / 2);
float dist = Vector3.Distance(center, CheckPos);
if (dist < lowDist)
{
lowDist = dist;
terrainIndex = i;
}
}
return terrainIndex;
}
and then you can use the function like this:
private Terrain[] _terrains;
void Start()
{
_terrains = Terrain.activeTerrains;
Vector3 start_pos = Vector3.zero;
start_pos.y = _terrains[GetClosestTerrain(start_pos)].SampleHeight(start_pos);
}
public static Terrain GetClosestTerrain(Vector3 position)
{
return Terrain.activeTerrains.OrderBy(x =>
{
var terrainPosition = x.transform.position;
var terrainSize = x.terrainData.size * 0.5f;
var terrainCenter = new Vector3(terrainPosition.x + terrainSize.x, position.y, terrainPosition.z + terrainSize.z);
return Vector3.Distance(terrainCenter, position);
}).First();
}
Raycast solution: (this was not asked, but for those looking for Solution using Raycast)
Raycast down from Player, ignore everything that has not Layer of "Terrain" (Layer can be easily set in inspector).
Code:
void Update() {
// Put this on Player! Raycast's down (raylength=10f), if we hit something, check if the Layers name is "Terrain", if yes, return its instanceID
RaycastHit hit;
if (Physics.Raycast (transform.localPosition, transform.TransformDirection (Vector3.down), out hit, 10f, 1 << LayerMask.NameToLayer("Terrain"))) {
Debug.Log(hit.transform.gameObject.GetInstanceID());
}
}
At this point already, you have a reference to the Terrain by "hit.transform.gameObject".
For my case, i wanted to reference this terrain by its instanceID:
// any other script
public static UnityEngine.Object FindObjectFromInstanceID(int goID) {
return (UnityEngine.Object)typeof(UnityEngine.Object)
.GetMethod("FindObjectFromInstanceID", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static)
.Invoke(null, new object[] { goID });
}
But as written above, if you want the Terrain itself (as Terrain object) and not the instanceID, then "hit.transform.gameObject" will give you the reference already.
Input and code snippets taken from these links:
https://answers.unity.com/questions/1164722/raycast-ignore-layers-except.html
https://answers.unity.com/questions/34929/how-to-find-object-using-instance-id-taken-from-ge.html

How to move camera thats attached to player

I'm trying to recreate a dolphin dive type of feel, as of right now my character is a cube with no animation so I feel like the best way to do this would be to manually move the camera as if the character had just dolphin dived but every time I try to move the camera the entire player itself moves.
Code:
if (Input.GetKeyDown(KeyCode.C) && isSprinting) {
for (float i = 0; i <= 10; i++) {
var forceForward = 8f;
if (isGrounded == true && moveVertical != 0) {
_rgb.AddForce(fpsCam.transform.forward * forceForward);
for (float j = 0; j <= 10; j++) {
_camera.AddForce(Vector3.up * 3f);
}
}
}
}
if you need any more information let me know!
If you want a shortcut, you can make the camera gameobject a child of the player game object. This way it will move with the player.

How can I display sprites in random places every launching of game in Unity[c#]?

I'm making bubble shooter replica in unity and I encountered a problem with initalizing the bubbles in random places, should I create an array of them in the background class?
For example i have class Sprite1 and Sprite2 and I want to display them in random places in the background how can I do it?
This is how it looks.
http://imgur.com/a/DGpZj
And below it's my attempt to display it by for loop, but dont know the method.
void Start () {
Random.Range(0f,4.5f);
for (int i = 0; i < 100; i++)
{
Sprite.Create(?)
}
}
Displaying your bubbles randomly in the background all depends on what your "randomly" word means: if it like randomly on a grid, completely randomly, can they overlay other bubbles, ...
So here's a first approach to your problem using a grid generation: to generate your bubbles, you can either use the Instantiate method or create new GameObjects.
Your game seems to be a 2D one so I highly recommend you looking for the Unity UI tutorials. Once you'll understand the basics of the UI system, create a Canvas and add an empty game object to it. Afterward you can assign it the below script:
using UnityEngine;
using UnityEngine.UI;
[RequireComponent(typeof(RectTransform))]
public class TestScript: MonoBehaviour
{
[SerializeField]
private float m_BubbleSize;
[SerializeField]
private int m_BubbleColumns;
[SerializeField]
private int m_BubbleRows;
[SerializeField]
private Sprite[] m_BubbleSprites;
private GameObject[][] m_Bubbles;
void Start()
{
GenerateBubbles();
}
private void GenerateBubbles()
{
// Position of the most top left bubble
Vector3 initialPosition = GetComponent<RectTransform>().position;
initialPosition.y += GetComponent<RectTransform>().rect.height * 0.5f;
initialPosition.y -= 0.5f * m_BubbleSize;
initialPosition.x -= (m_BubbleColumns - 1) * 0.5f * m_BubbleSize;
initialPosition.x -= 0.25f * m_BubbleSize;
// Rows height: comes from https://en.wikipedia.org/wiki/Close-packing_of_equal_spheres
float rowsHeight = Mathf.Sqrt(6.0f * m_BubbleSize * m_BubbleSize) / 3.0f;
// Bubbles references array
m_Bubbles = new GameObject[m_BubbleColumns][];
for(int i = 0; i < m_Bubbles.Length; i++)
{
m_Bubbles[i] = new GameObject[m_BubbleRows];
}
// Generation
for(int x = 0; x < m_Bubbles.Length; x++)
{
for(int y = 0; y < m_Bubbles[x].Length; y++)
{
GameObject bubble = new GameObject("Bubble_" + x.ToString() + y.ToString(), new System.Type[] { typeof(RectTransform), typeof(Image), typeof(CircleCollider2D) });
bubble.transform.SetParent(transform);
if(y % 2 == 0)
{
bubble.GetComponent<RectTransform>().position = initialPosition + new Vector3(x * m_BubbleSize, -y * rowsHeight, 0.0f);
}
else
{
bubble.GetComponent<RectTransform>().position = initialPosition + new Vector3(0.5f * m_BubbleSize + x * m_BubbleSize, -y * rowsHeight, 0.0f);
}
bubble.GetComponent<RectTransform>().sizeDelta = new Vector2(m_BubbleSize, m_BubbleSize);
bubble.GetComponent<Image>().sprite = m_BubbleSprites[Random.Range(0, m_BubbleSprites.Length)];
bubble.GetComponent<CircleCollider2D>().radius = m_BubbleSize * 0.5f;
}
}
}
}
To complete your game here are the few (maybe not exhaustive list) steps you will need to go through:
Populating a list of the potential "cell" where bubbles can be
Creating a pool of bubble to be fired (with random shuffling)
Writing the shooting + rebounds dynamic (Unity 2D Physic can help with that)
Detecting collision after bubble has been fired
Finding nearest possible "cell"
Searching if enough bubbles are connected (and if so destroying them)
Searching if some of the bubbles aren't connected anymore (and if so deleting them too)
OPTIONAL Implementing a scoring system (and saving the scores)
OPTIONAL Implementing apparition of new bubbles row on top every X bubbles fired
...
Hope this helps,

Rotating enemy characters

I have a list of characters created in XNA C# as follows
for (int i = 0; i < GameConstants.NumDaleks; i++)
{
if (dalekList[i].isActive)
{
Vector3 line = dalekList[i].direction;
float rotationDal = (float)(Math.Atan2(dalekList[i].position.Y, dalekList[i].position.X) / (2 * Math.PI));
Matrix dalekTransform = Matrix.CreateScale(GameConstants.DalekScalar) * Matrix.CreateRotationY(rotationDal) * Matrix.CreateTranslation(dalekList[i].position);
DrawModel(mdlDalek, dalekTransform, mdDalekTransforms);
}
}
I'm trying to get characters to rotate to move in the direction they are facing. I believe this method is where I need to do but cannot figure out how to work out the angle require to go

Categories

Resources