Within my 2d game i wsih to have a number of OnGui elements there for the user to select, however, the cursor that im using is another ongui element(using kinect to navigate) is this possible by any chance, at the moment im using planes but i will be zooming in and out of the camera so ill essentially need them attatched to the screen. Any ideas, suggestions or workarounds.
THis is currently my cursor.
using UnityEngine;
using System;
using System.Collections;
public class PillarAgent : MonoBehaviour {
public SkeletonWrapper sw;
public Vector3 distance;
public float progress =0f;
public Texture2D cursor;
public Texture2D load;
public Camera mainCam;
public float startTime;
private int roundedRestSecounds;
// Use this for initialization
float differencex = 0;
float differencey = 0;
void Start () {
distance =new Vector3(0f,0f,0f);
}
float translate(float value, float leftMin, float leftMax,
float rightMin,float rightMax)
{
float leftSpan = leftMax - leftMin;
float rightSpan= rightMax - rightMin;
float valueScaled = (value-leftMin)/(leftSpan);
return rightMin+(valueScaled * rightSpan);
}
// Update is called once per frame
void Update () {
if (sw.pollSkeleton())
{
distance.x=sw.bonePos[0,0].x - sw.bonePos[0,7].x;//5 is left shoulder
distance.y=sw.bonePos[0,0].y -sw.bonePos[0,7].y;
differencex=translate(distance.x,.6f,0,0,Screen.width);
differencey=translate(distance.y,-.5f,0,0,Screen.height);
//Debug.Log();
float width = sw.bonePos[0,5].x+ sw.bonePos[0,9].x;
float height =sw.bonePos[0,4].y- sw.bonePos[0,0].y;
float heightdiv= (height/2)+sw.bonePos[0,0].y;
}
}
void OnGUI() {
//left top width height
Rect r = new Rect(differencex,differencey,80,50);
GUI.Label(r,cursor);
GUI.BeginGroup(new Rect(differencex,differencey+50,50*Mathf.Clamp01(progress),15));
//Debug.Log(progress);
GUI.DrawTexture(new Rect(0,0,50,50),load);
GUI.EndGroup();
transform.position =mainCam.ScreenToWorldPoint(new Vector3(differencex,Screen.height-differencey,50));
//mainCam.fieldOfView()
}
void OnCollisionStay(Collision Other)
{
startTime+=Time.deltaTime;
if(Other.gameObject.GetComponent(typeof(TextControl)))
{
roundedRestSecounds=Mathf.CeilToInt(Time.time);
progress = Time.time *0.2f;
CurrentState=true;
}
else if(Other.gameObject.tag==("Scalpal")){
progress = startTime *0.5f;
//scallpall activated
//
}
}
void OnCollisionExit(Collision Other){
startTime =0f;
progress =0f;
}
public Boolean CurrentState{get;set;}
}
The next class is essentially the class in which i pick up my tools, currently this code doesnt work(not sure why), but what i wish to do is select some tools which show up on the screen so that i can use them,for e.g pick up paint brush start painting bricks or what not. at the moment i have my tools on a plane, i wish to always have them on the screen at all times when the camera moves.
using UnityEngine;
using System.Collections;
public class SelectTool : MonoBehaviour {
public Tools tools;
public float startTime;
public bool ScalpalSelected;
public GameObject selectedTool;
void Start()
{
tools = this.GetComponent<Tools>(); //in order to use this tools muyst be attached to the game object
//this is essentially saying with regards to this game object get the component named tools
}
void update()
{
}
void OnCollisionStay(Collision Other)
{
startTime +=Time.deltaTime;
if(startTime >5f){
if(Other.collider.tag==("Scalpal"))
{
selectedTool = Other.collider.gameObject;
Debug.Log(selectedTool+" What in gods good name is:" +tools.utilities[0]);
}
else {
selectedTool=null;
}
if(selectedTool){
for(int i=0;i<tools.utilities.Length;i++)
{
}
}
ScalpalSelected=true;
renderer.material.color = Color.yellow;
}
}
void OncollisionStay(Collision other){
startTime = 0f;
}
}
From the comment section to the question I will assume that you want to know how to do this:
"... you want your plane objects to move together with the camera ..." - Steven Mills
"thank you #StevenMills Do you have any example of how this can be done?" j bel
While the answer provided in the comments is to just manually add the planes as children of the camera (a very straightforward, manual approach), I will give another way to do this through scripting (in light of maybe this will help someone else out disregarding the likeliness of someone using this solution).
The idea of this is to create a script (thus following being attached to the MainCamera) that will search through all of the GameObject in the Object Hierarchy with the method GameObject.FindGameObjectsWithTag. Once we have all our GameObject with the associated Tag, we can then loop through the array and parent the attached script's GameObject to each.
public class ParentGameObjects : MonoBehaviour {
//The tag to search for on all game objects in the hierarchy
public String objectTag;
//The game objects that we will parent the main camera to
private GameObject[] children;
//It's not necessary to store references to the children but if you want to modify them at some point you will be able to
void Start() {
//Find all game objects with the tag we want
children = GameObject.FindGameObjectsWithTag(objectTag);
//Loop through all of the game objects found and parent this object's transform
for(int i = 0; i < children.Length; i++) {
children[i].transform.parent = transform;
}
}
}
Now, there are a few things you have to do for this script to work:
Attach this script to any GameObject that you want to parent other objects to.
In the Inspector of the GameObject that the script is attached to, enter in the name of the Tag you want to use.
For all GameObject(s) in the Hierarchy that should be added as children, assign the same Tag.
Of course there are other things you can do like, for example, instead of only searching for one Tag be able to search for multiple but that requires a bit (not exactly much) more work. Nonetheless, I hope this will at least be useful information to someone on how parenting works via scripting.
Related
i was working on a simple car controller script and a humvee model i downloaded. the script works as its supposed to but the car wheels are out of place and are spinning crazy. i tried searching everywhere but didn't found any solution.
here's the code:
using UnityEngine;
public class GroundVehicleController : MonoBehaviour {
public void GetInput()
{
m_horizontalInput = Input.GetAxis("Horizontal");
m_verticalInput = Input.GetAxis("Vertical");
}
private void Steer()
{
m_steeringAngle = maxSteerAngle * m_horizontalInput;
frontDriverW.steerAngle = m_steeringAngle;
frontPassengerW.steerAngle = m_steeringAngle;
}
private void Accelerate()
{
frontDriverW.motorTorque = m_verticalInput * motorForce;
frontPassengerW.motorTorque = m_verticalInput * motorForce;
}
private void UpdateWheelPoses()
{
UpdateWheelPose(frontDriverW, frontDriverT);
UpdateWheelPose(frontPassengerW, frontPassengerT);
UpdateWheelPose(rearDriverW, rearDriverT);
UpdateWheelPose(rearPassengerW, rearPassengerT);
}
private void UpdateWheelPose(WheelCollider _collider, Transform _transform)
{
Vector3 _pos = _transform.position;
Quaternion _quat = _transform.rotation;
_collider.GetWorldPose(out _pos, out _quat);
_transform.position = _pos;
_transform.rotation = _quat;
}
private void FixedUpdate()
{
GetInput();
Steer();
Accelerate();
UpdateWheelPoses();
}
private float m_horizontalInput;
private float m_verticalInput;
private float m_steeringAngle;
public WheelCollider frontDriverW, frontPassengerW;
public WheelCollider rearDriverW, rearPassengerW;
public Transform frontDriverT, frontPassengerT;
public Transform rearDriverT, rearPassengerT;
public float maxSteerAngle = 30;
public float motorForce = 50;
}
The error on Unity console is telling you the problem:
UnassignedReferenceException: The variable frontDriverW of
groundVehicleController has not been assigned. You problably need to
assign the frontDriverW variable of the GroundVehicleController script
in the inspector.
Well, when your script runs, it tries to access the field frontDriverW, but since it was never assigned a value, it throws the mentioned exception.
You need to go in the inspector for the object that contains the GroundVehicleController script and add a value for the frontDriverW field. While you're there, make sure all the other fields have values too, because if they don't, those will also cause the same error.
From the pictures you've show us, it is not possible to know in which object you added the GroundVehicleController script, but just check all of the Humvee objects until you find it in the inspector. My guess is that it will probably be in the object Wheels, or the object Humvee.
a) Check the prefab you've created to see if these offsets are there even on the prefab.
b) You're updating the wheel pose with global positions and rotations. this is probably what is causing the offsets. try setting the pose local, or just make the wheel meshes follow whatever the wheel colliders are doing, make sure they're all under the same co-ordinate space. Why not just child each individual wheel to it's corresponding wheel collider? theyre just meshes after all.
c) You haven't assigned your wheel meshes at all in your script.
c) play around with different mass values on the RigidBody (keep it heavy), and also consider attaching a physic material to your wheel colliders to reduce slip and spinning (If the car controller already doesnt have a slip setting)
I am trying to create a script for my enemy turret, but it is not going well. I have a couple animations of the turret being activated and deactivated. What I need is that based on the distance from the player, it plays either animation. So once it moves inside the detection radius it plays the activation animation and once it is outside it plays the deactivation animation. Most of the other ways I try require me to create an Animation Controller, which I have little experience in using. I want a simple way to play one animation once it is inside and play a different one when it is outside. I think there was a way to store the animation clip in the script, and then play it. I have attached my current script, so you know what I mean.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyTurret : MonoBehaviour
{
public GameObject Player;
public float DistanceToPlayer;
public float DetectionRadius = 75;
// Start is called before the first frame update
void Start()
{
Player = GameObject.FindGameObjectWithTag("PlayerTank");
}
// Update is called once per frame
void Update()
{
DistanceToPlayer = Vector3.Distance(transform.position, Player.transform.position);
if (DistanceToPlayer<=DetectionRadius)
{
Debug.Log("Within Radius");
}
if (DistanceToPlayer >= DetectionRadius)
{
Debug.Log("Outside Radius");
}
}
}
Calculating and checking the distance of the player for every update() is not ideal. It will work, but it will do more work than it needs to when the player isn't even near it. Its not efficient.
What you may want to do if your player is a Rigidbody, is add a SphereCollider to the turret, set isTrigger=true, set the radius to be your detection radius, and handle the OnTriggerEnter() and OnTriggerExit() events to play or stop animations.
You can also add two public Animiation objects to the script, drag and drop your animations in the editor, then you can use animation.Play() and .Stop() etc. to control the animations.
Something similar to this. Not tested fully, but you can get the idea.
public float detectionRadius = 75;
public Animation activateAnimation;
public Animation deactivateAnimation;
void Start()
{
SphereCollider detectionSphere = gameObject.AddComponent<SphereCollider>();
detectionSphere.isTrigger = true;
detectionSphere.radius = detectionRadius;
detectionSphere.center = Vector3.zero;
}
private void OnTriggerEnter(Collider other)
{
if (other.gameObject.tag == "PlayerTank")
{
activateAnimation.Play();
}
}
private void OnTriggerExit(Collider other)
{
if (other.gameObject.tag == "PlayerTank")
{
deactivateAnimation.Play();
}
}
Your animations must not loop otherwise you will have to add more logic to check if animation.isPlaying and do your own animation.Stop() etc.
I have a spawner object. Every time a gameobject is spawned, I want that object to move randomly (wandering). The problem in my script is that the gameobject movement is very random (jittery). How can I solve this?
void Start ()
{
InvokeRepeating("SpawnNPC", Spawntime, Spawntime);
}
// Update is called once per frame
void Update () {
population = GameObject.FindGameObjectsWithTag("NPCobject");
for (int i = 0; i < population.Length; i++)
{
getNewPosition();
if (population[i].transform.position != pos)
{
population[i].transform.position = Vector3.MoveTowards(population[i].transform.position, pos, .1f);
}
}
}
void getNewPosition()
{
float x = Random.Range(-22, 22);
float z= Random.Range(-22, 22);
pos = new Vector3(x, 0, z);
}
I made the New randomize vector in different method, because I plan to change it with pathfinder function and make it in different thread/task.
You are choosing a new direction every single frame. That will always be very jittery. You wan't to only change direction after, at least, a small interval. Here is a link to one way to do that from Unity's website. https://docs.unity3d.com/ScriptReference/MonoBehaviour.InvokeRepeating.html
What about using Navigation? As you said wandering, I thought it would give you a nice result and also make your code simple.
The following screenshot is a sample with Navigation. The moving game objects are also changing their direction nicely, although it cannot be seen in the sample because the game object is capsule...
Ground game object in the sample program has NavMesh. See here to build NavMesh.
Agent game object has NavMeshAgent Component. See here to set it up.
Th Behaviour class below is for Agent game object.
using UnityEngine;
using UnityEngine.AI;
public class NavAgentBehaviour : MonoBehaviour {
public Transform[] Destinations { get; set; }
// Use this for initialization
void Start ()
{
InvokeRepeating("changeDestination", 0f, 3f);
}
void changeDestination()
{
var agent = GetComponent<NavMeshAgent>();
agent.destination = Destinations[Random.Range(0, Destinations.Length)].position;
}
}
The next Behaviour class is just for spawning the Agent and setting up the destinations. On Unity, set it to whatever game object in the scene, and allocate game objects to the fields.
using UnityEngine;
public class GameBehaviour : MonoBehaviour {
public GameObject Agent;
public Transform SpawnPoint;
public Transform Destination1;
public Transform Destination2;
public Transform Destination3;
// Use this for initialization
void Start()
{
Agent.SetActive(false);
InvokeRepeating("Spawn", 0f, 2f);
}
void Spawn() {
var newAgent = Instantiate(Agent);
newAgent.GetComponent<NavAgentBehaviour>().Destinations = new[] { Destination1, Destination2, Destination3 };
newAgent.transform.position = SpawnPoint.position;
newAgent.SetActive(true);
}
}
Increase the number of destination, to make the moves look more random. By the way, the destinations do not need to be specified by game objects, which is only for making it easy to see the sample program's behaviour.
The source of the jitteriness comes from the fact that you are updating the position to move every frame so your objects never have a consistent location to move to. I would instead suggest attaching a new script to each of your objects that individually handles their movement. In that script you could do something like the following, which has a delay to keep the target position for more than 1 frame.
float delaytimer;
Vector3 pos;
void Start () {
getNewPosition(); // get initial targetpos
}
void Update () {
delaytimer += Time.deltaTime;
if (delaytimer > 1) // time to wait
{
getNewPosition(); //get new position every 1 second
delaytimer = 0f; // reset timer
}
transform.position = Vector3.MoveTowards(transform.position, pos, .1f);
}
void getNewPosition()
{
float x = Random.Range(-22, 22);
float z= Random.Range(-22, 22);
pos = new Vector3(x, 0, z);
}
You are changing the direction they are moving in every frame, thats what is causing the jitter.
You could wait a few moments before you change the direction, perhaps something like this.
// Outside update
float betweenChanges = 2;
float lastChange = 0;
// Inside update
if(Time.realtimeSinceStartup > lastChange)
{
// Change directions
// ...
lastChange = Time.realTimeSinceStart + betweenChanges;
}
You could also solve this by using InvokeRepeating or a Coroutine.
If you dont want all the NPC's to change direction at the same time and still plan on controlling every NPC from the same class like in your example, you should perhaps add a timer for each NPC instance instead and use that to decide when to change its direction.
A better idea would be to let each NPC have its own Movement-script.
I'm trying to create a falling word game like z-type. Once the game starts a few words are displayed on the screen. When the user types a letter and if that matches with the first letter of any of the words displayed, an activeWord tag is added to the word. I have also created a laser script that checks if the tag is active and when that happens, it shoots the laser.
What's happening right now is that the laser is shot only once i.e when the first letter matches but doesn't shoot a laser when the remaining words are typed.
This is the laser script:
using UnityEngine;
using UnityEngine.UI;
public class Laser : MonoBehaviour {
public float speed = 10.0f;
private Vector3 laserTarget;
private void Update () {
GameObject activeWord = GameObject.FindGameObjectWithTag("activeWord");
if (activeWord && activeWord.GetComponent<Text>().text.Length > 0) {
laserTarget = activeWord.transform.position; // find position of word
transform.Translate(laserTarget * speed * Time.deltaTime); // shoot the laser
}
}
}
I'm also adding the code that I use in the display/UI field.
public void RemoveLetter() {
/* remove the first letter if its correct and so
on for the remaining letters. change the color of the word to red and add
the "activeddWord" tag.*/
text.text = text.text.Remove(0, 1);
text.color = Color.red;
text.gameObject.tag = "activeWord";
}
public void RemoveWord() { // destroy the word once all the letters match
Destroy(gameObject);
}
Can someone please have a look at the code and tell me where I'm making a mistake.
I think you have to reset the position of your laser if it reaches the target:
public float speed = 10.0f;
private Vector3 laserTarget;
private Vector3 laserOrigin;
private void Start () {
// save laser's origin position
laserOrigin = transform.position;
}
private void Update () {
GameObject activeWord = GameObject.FindGameObjectWithTag("activeWord");
if (activeWord && activeWord.GetComponent<Text>().text.Length > 0)
{
laserTarget = activeWord.transform.position; // find position of word
transform.Translate(laserTarget * speed * Time.deltaTime); // shoot the laser
float distance = Vector3.Distance(laserTarget , transform.position);
if(distance < 0.05f){ // I don't know your scaling, perhaps change the limit here!
transform.position = laserOrigin;
}
}
}
Here is one way you can do this using Instantiate() and prefabs. The benefit of this method is that it is scalable. You can create multiple lasers with minimal tweaking. Please note that to use multiple lasers you will have to remove WaitForThisLaserDestroyed;.
To get this to work you will have to start by changing your laser gameObject into a prefab and adding this script onto it:
https://docs.unity3d.com/Manual/Prefabs.html
public class Laser : MonoBehaviour
{
public float speed = 10.0f;
public Vector3 laserTarget;
public float destroyLaserAfterTime = 3f;
private void Update ()
{
transform.Translate(laserTarget * speed * Time.deltaTime);
}
}
And then on some arbitrary other object. For example an empty game object in the same scene:
public class LaserInitializer : MonoBehaviour
{
public GameObject laserPrefab;
public GameObject laserOrigin;
private GameObject WaitForThisLaserDestroyed;
private void Update ()
{
GameObject activeWord = GameObject.FindGameObjectWithTag("activeWord");
if (WaitForThisLaserDestroyed == null && activeWord && activeWord.GetComponent<Text>().text.Length > 0)
{
CreateLaser(activeWord);
}
}
private void CreateLaser(GameObject activeWord)
{
GameObject activeLaser = Instantiate(laserPrefab, laserOrigin.Transform.Position, Quaternion.identity) as GameObject;
Laser laserScript = activeLaser.GetComponent<Laser>();
laserScript.laserTarget = activeWord.transform.position;
WaitForLaserDestroyed = activeLaser;
Destroy(activeLaser, destroyLaserAfterTime);
}
}
To explain the code:
The Laser prefab has its own script for moving towards the word, and as soon as it exists and has the target passed to it, it will move towards the active word.
Somewhere else in the scene you have a game object that exists to hold the second script. Lets call it the "controller game object". It checks to see if the words are "active", as per the earlier design. When a word is active this script creates exactly one laser, and tells it to target the active word.
You have another gameobject (this can be the same one as the controller game object), that marks the origin of the laser. You can do this in other ways, but I thought that using a game object to mark the start point would be an easy way for beginners.
I'm working on Unity 5, and I need to create a list of transforms in order to modify them in the inspector (position and rotation) to emulate a different camera. This emulation is for a demo, like a camera moving on its own during the demo.
I currently have a list of transforms, but I don't know how to make them modifiable in the inspector and change their position at runtime?
Edit: 18/11/15
Here is the solution that if find with a help of a friend of mine more aware of what really does unity, hope it will help you and thanks again for all your reply it helped me a lot :D :
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class MoveCamera : MonoBehaviourSingleton<MoveCamera>
{
public List<Transform> cameraPositions = new List<Transform>();
private Transform m_Target;
private float m_Speed;
private bool m_Translate;
private bool m_Rotate;
public void SwitchToNext(int index, float speed)
{
m_Target = cameraPositions[index];
m_Translate = true;
m_Rotate = true;
}
public void Update()
{
if (m_Target != null && (m_Translate || m_Rotate))
{
float ratio = Time.deltaTime * m_Speed;
transform.position = Vector3.Lerp(transform.position, m_Target.position, ratio);
transform.rotation = Quaternion.Slerp(transform.rotation, m_Target.rotation, ratio);
if (Vector3.Distance(transform.position, m_Target.position) < 0.001f)
{
transform.position = m_Target.position;
m_Translate = false;
}
if (Quaternion.Angle(transform.rotation, m_Target.rotation) < 0.001f)
{
transform.rotation = m_Target.rotation;
m_Rotate = false;
}
}
}
}
Ok lets see if this helps you.(i will write my code assuming you want this)
You have x gameObjects in your scene.
You will need a GameObject List. Lets say you get them by doing
public List<GameObject> myObjectList = new List<GameObject>();
public List<Transform> myTransformList = new List<Transform>();
myObjectList = GameObject.FindGameObjectsWithTag("YourCustomTagHere");
foreach(Gameobject g in myObjectList)
{
myTransformList.Add(g.transform);
}
I dont know if this code works, i cant test it right now, but i think the logic is there. Go ahead and try a few things, give some feedback whether you made it or not.
I would suggest just a simple public list in your MoveCamera script and then dragging the targets into that list. Doing it this way you have full control over the order of the objects and thus you can do animated transitions from camera position n to n + 1.
public List<Transform> cameraPositions = new List<Transform> ();
Maybe a simple sequence does not fit your requirements and you need a more sophisticated way to decide which position is allowed to switch to which other position. In this case I'd suggest a helper script e.g. CameraTransition.cs. Here you can place your check logic and definition parameters.
Attach this to every allowed target position object and replace the list in MoveCamera by List<CameraTransition>.