I have a simple project where I spawn multiple asteroids and they tend to gravitate over a planet. I wanted to add a simple trail to enhance the visual effects. It's very simple when I add the asteroid manually and then add component "trail renderer" and select desired material. But I can't work it out on how to add it to a script. This is my code for now:
using System.Collections;
using UnityEngine;
[RequireComponent(typeof(Rigidbody))]
[RequireComponent(typeof(FauxGravityBody))]
public class Spawner : MonoBehaviour {
public GameObject meteorPrefab;
public float distance = 20f;
public float time = 10f;
private GameObject meteor;
public TrailRenderer trail;
void Start ()
{
StartCoroutine(SpawnMeteor());
}
IEnumerator SpawnMeteor()
{
Vector3 pos = Random.onUnitSphere * distance;
meteor = Instantiate(meteorPrefab, pos, Quaternion.identity);
meteor.AddComponent<FauxGravityBody>();
meteor.AddComponent<DestroyMeteor>();
meteor.AddComponent<SphereCollider>();
meteor.AddComponent<TrailRenderer>();
yield return new WaitForSeconds(time);
StartCoroutine(SpawnMeteor());
}
}
Which indeed adds the trail to the spawned objects, but it's using the default pink trail. My desired trail material is located in folder "Assets/Effects/Trail.mat". How can I specify in the script that I want to use that specific material?
Kind regards.
Note if you need these components -- TrailRenderer, SphereCollider etc. -- on all meteors, you can simply add them to the Prefab itself manually (by dragging them over it). Then they will already be there, right materials and all, once you Instantiate the main prefab.
You can then still adjust specific settings (or disable components) by using getting them via GetComponent<TrailRenderer>() etc. Good luck!
The best way to do it is....
create Prefab and attach you needed component to your Prefab
and Instatiate it when and where you need it
and using GetComponent<>() method you can get attached component
GameObject bullets = Instantiate(yourPrefab, yourtransform.position, Quaternion.identity) as GameObject;
bullets.GetComponent<Rigidbody>().AddForce(transform.forward * 100, ForceMode.Impulse);
Related
I'm rather new to Unity and trying to get started with a simple scene consisting only of an FPS Controller and a few obstacles.
As the controller I'm using the one from the Unity Standard Assets and everything worked fine.
Upon adding a Character Mesh however I noticed that I had to setup camera clamping. The controller script accesses the serialized "MouseLook" script in which I have to edit a few variables to fit my needs.
Since it's serialized however I can't simply change the variables, save the code and get the changes.
Since I'm not planning on changing the fact that the script is serialized I just want to update my changed variables.
I hope this was understandable. Thanks in advance!
Hello and welcome #Corneey,
For starters, I have no idea how to recompile that script or change any values (except for some input fields it might have?), but there's a workaround:
public class LookAtMouse : MonoBehaviour
{
//The object to rotate with/look at the mouse
public Transform target;
//Update is called once per frame
public void Update()
{
//Get mouse position in 3D space
Plane target = new Plane(Vector3.up, 0);
Ray r = Camera.mainCamera.ScreenPointToRay(Input.mousePosition);
//On the hit, rotate the target to the "impact point"
if(target.Raycast(r, out float distance)
Vector3 hitPoint = r.GetPoint(distance);
}
}
I'm currently developing a game in unity using c# scripts and I have a small problem. I'm trying to give one of my game objects a constant speed/velocity without it being affected by other gravity, drag or any other type of physics characteristic except velocity. I looked through the Unity manual to find any classes that would be able to help me with this and I seemed to have found one class that would do the job:
https://docs.unity3d.com/ScriptReference/Rigidbody-velocity.html
I edited it in order to make it fit my game since this is a game object that doesn't have its velocity affected by the player but every time I run the game in the test screen nothing happens(The object stays static). I was wondering if anyone knows of a class in Unity or C# that deals with this problem or generally knows how I can make this happen. Both by having it affect all the game objects appearing on the screen at the same time or only a select few? And secondly, I was also wondering how I could convert the rigidbody velocity vector2 into from a world point into a screen point?
Thanks alot.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BallSpeed : MonoBehaviour
{
public Rigidbody rb;
void Start()
{
rb = GetComponent<Rigidbody>();
}
void Update()
{
rb.velocity = new Vector2(0, 100);
}
}
Expected result: The game object moves upwards with a speed of 100.
Actual result: Nothing happens.
If you are trying to make your object move at a constant speed, there is no need for a rigidbody reference.
public float upSpeedPerSecond = 100f;
void Update() {
transform.translate(new Vector3(0, upSpeedPerSecond*time.deltaTime, 0));
}
Be sure to check that your Rigidbody2D is set to dynamic in the inspector, as Kinematic and Static rigidbodies do not have physics. If you don't want it to be dynamic, just use rb.Translate() instead. However, NEVER translate a static rigidbody, as it messes with the optimizations the engine does to them, use kinematic rigidbodies for transforming instead.
I have a very strange problem.
I created an AI using the navmesh tools and a custom script which keeps assigning a new destination to the navmesh agent once the old destination is reached.
I had to replace the model for this AI (was a capsule before), so I did that, copied almost all components, adjusted a few parameters like agent height etc., and ran it.
The capsule AI does its job properly, but the AI with the correct model clearly doesn't.
After debugging, I discovered that the List of destinations for the modelled AI consists if Vector3.zero's, while the capsule AI has the correct vector3s in its destination list.
Here's my AI destination script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
public class AIMovement : MonoBehaviour
{
private NavMeshAgent _navMeshAgent; //reference to the navmesh agent
private MapController _mapControllerScript; //reference to the map controller script to access waypoints
private List<Vector3> _wayPoints = new List<Vector3>();
private Vector3 _destination;
// Use this for initialization
void Start()
{
_mapControllerScript = GameObject.Find("Map_01").GetComponent<MapController>();
SetWayPointLocations();
_navMeshAgent = this.GetComponent<NavMeshAgent>();
Debug.Log(_mapControllerScript.ToString());
Debug.Log(_mapControllerScript.HealthPickUpPositions.ToString());
Debug.Log(_navMeshAgent);
Debug.Log(_wayPoints);
foreach (Vector3 waypoint in _wayPoints)
{
Debug.Log(waypoint);
}
}
// Update is called once per frame
void Update()
{
MoveAroundMap();
}
void MoveAroundMap()
{
if (_navMeshAgent.transform.position.x == _destination.x &&
_navMeshAgent.transform.position.z == _destination.z
|| _destination == new Vector3(0, 0, 0)
)
{
Debug.Log("Acquiring new position");
_destination = _wayPoints[Random.Range(0, _wayPoints.Count-1)];
}
_navMeshAgent.SetDestination(_destination);
}
void SetWayPointLocations()
{
foreach (Vector3 waypoint in _mapControllerScript.HealthPickUpPositions)
{
_wayPoints.Add(waypoint);
}
foreach (Vector3 waypoint in _mapControllerScript.AmmoPickUpPositions)
{
_wayPoints.Add(waypoint);
}
}
}
Here's the console: you can clearly see the coordinates of the capsule AI being correct, while the coordinates of the broken AI being (0, 0, 0).
Here's the hierarchy window: Capsule is the working AI, Character_Piccolo the non-working.
Here's the inspector of the Capsule, the working AI.
Here's the inspector of the model, the broken AI.
Sorry for making this long, but I wanted to make sure you guys had all the needed information.
Thanks in advance!
The problem - and also the solution - are not in your AIMovement script, or in any edit you did while changing from the capsule to you new model, not even in any of the scripts and components you provided in the question. The problem is a subtlety in you MapController class that was already there all the time (even before your changes), and the fact that you did not experience this error before is a matter of casuality.
As you said in the comments, you're setting up HealthPickUpPositions and AmmoPickUpPositions properties of you MapController class in its Start() method. And you're reading the values of those properties on the Start() method of your component class. The thing is: the Start message runs once a gameObject is set on a loaded scene, but the order in that objects get started does not depend on your game logic (it depends on the scene hierarchy, prefabs, object instance number and other stuff, whatever...) and should be considered random.
In your specific case, the Start() of your AIMovement is being called before the Start() of MapController, i.e. before the proper values of the properties being set - hence, all you read are zero-vectors (default values).
Because of that, unity has a similar message named Awake() on gameObjects. You also don't know the order in which the objects will be awoken, but you can assure that any Start() message will be sent only after all the Awake() messages were already been sent. More on this here, here, here and here.
The solution: Put all internal initialization logic of your classes in the Awake method; and all the connections to other gameobjects (that assume they are initialized) on the Start method.
I am trying to make a game where you drag different types of spheres and put them together to form a figure (without any gravity). For dragging the objects I use this script:
using UnityEngine;
using System.Collections;
public class Test : MonoBehaviour {
void OnMouseDrag()
{
float distance_to_screen = Camera.main.WorldToScreenPoint(gameObject.transform.position).z;
transform.position = Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, distance_to_screen ));
}
}
When I drag two spheres to eachother they go trough eachother. I added a rigibody to the objects, tried a LOT of different things with it, but nothing seemed to work. They always seem to bounce off eachother OR they just don't collide at all. Any sollution to this? Imagine this like a person running in to a wall. The person doesn't bounce off the wall, he just stops moving.
The reason why you're getting some strange behaviour (objects clipping through/ignoring each other) is that you're setting transform.position directly, rather than manipulating the Rigidbody component of the object. Use Rigidbody.MovePosition() to also take into account physics when positioning an object.
Now, seeing objects bounce off each other is not an abnormal physics behaviour - this is because when objects clip into each other (as they will often do with your code), they exert a repulsing force on each other (a bit like Newton's third law). If you want to freeze them as soon as they collide, try setting Rigidbody.isKinematic = true in the OnCollisionEnter() event.
Bringing this all together, your class might look like:
public class Test : MonoBehaviour {
Rigidbody rb;
void Start()
{
// Store reference to attached Rigidbody
rb = GetComponent<Rigidbody>();
}
void OnMouseDrag()
{
float distance_to_screen = Camera.main.WorldToScreenPoint(gameObject.transform.position).z;
// Move by Rigidbody rather than transform directly
rb.MovePosition(Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, distance_to_screen )));
}
void OnCollisionEnter(Collision col)
{
// Freeze on collision
rb.isKinematic = true;
}
}
Hope this helps! Let me know if you have any questions.
When directly giving the position variable coordinates in a non-incremental way, the object is "phasing" into existence at the next location fooling the collision system.
You have to code it by having some sort of other system move the object in incremental ways:
Instead of moving the object directly like this:
position =
position = lerp(oldPosition,new position,Time.deltaTime)
I'd like some help with the following issue. I'm making a simple game where you have a character running and he has to jump over obstacles coming at him.
And I'm currently stuck when it comes to creating GameObjects and randomly generating them within the game scene at run time.
I've written a class to help accomplish this:
using UnityEngine;
using System.Collections;
public class randomObstacles : MonoBehaviour {
public GameObject myCube;
public Vector3 spawnLocation = new Vector3(0,2,0);
// Use this for initialization
void Start () {
GameObject SpawnLocation = (GameObject)Instantiate(myCube, spawnLocation, Quaternion.identity);
}
// Update is called once per frame
void Update () {
}
}
The above code is what I wrote to simply create Objects, one after the other. But when I run the game, it comes up empty -_- !
Can anyone please tell me where am going wrong, and from the look of it my code doesn't seem to do what I am hoping to achieve :(
I've attached the above script into an empty GameObject as I saw in a tutorial from the Unity Community forum, but that did not help either.
(I've looked around and it seems like no one has come across such an issue - I could bee wrong)
It would seem that your myCube variable is the root of your problems, having tested it in a scene of my own. By subsituting
(GameObject)Instantiate(myCube, ...
with
(GameObject)Instantiate(GameObject.CreatePrimitive(PrimitiveType.Cube), ...
I was able to produce a cube at (0,2,0) with no qualms. Perhaps your myCube GameObject is missing a Mesh Renderer, in which case it would appear in the Hierarchy during runtime even though it would not appear visible in Game View. Perhaps you are not assigning it in the Inspector before you run the game, in which case the myCube variable would refer to null and thus not be created. Additionally, though you may be assigning the GameObject you instantiate to SpawnLocation, it is an unused local variable (something MonoDevelop or your code editor should notify you of). Make sure you either provide a reference to a myCube GameObject in the Inspector before runtime or through script referencing to a loaded prefab/GameObject during runtime. It would also be helpful to provide a fallback (say, to PrimitiveType.Cube perhaps?), which will make your code more robust and able to handle errors in referencing should they arise.
Regardless, in order to achieve the functionality you have described, first make sure yo have properly prepared whatever you would desire myCube to be. Also, for future posterity, you may want to initialize your spawnLocation in the Start routine, and assign the variable coordinates by substituting Random.value * yourValueCeiling in for each random coordinate you would like myCube to spawn on. You could even go as far to make a helper method externalized and thus independent from the start routine, such that you will not have to have a hundred instances of a single script to create a hundred instances of what you need; rather, you can call the method through a single script, and save yourself trouble in this way. If you would so appreciate it, here is my implementation of your objective, hope this helps!
using UnityEngine;
using System.Collections;
public class randomObstacles : MonoBehaviour {
public Vector3 spawnLocation;
public GameObject myCube;
// Use this for initialization
void Start () {
if (myCube != true) {
Debug.Log("myCube not set");
myCube = GameObject.CreatePrimitive(PrimitiveType.Cube);
}
if (myCube.renderer.enabled == false) {
Debug.Log("myCube not rendered");
myCube = GameObject.CreatePrimitive(PrimitiveType.Cube);
}
CreateCube();
}
// Update is called once per frame
void Update () {
}
void CreateCube() {
spawnLocation = new Vector3(0, Random.value * 10, 0);
Instantiate(myCube, spawnLocation, Quaternion.identity);
}
}
It may be worth pointing out that you're creating your object in the Start method, which means your code will only run once: from the name of your class, I'd assume you want to create more than one object using this code.
If you move the code into Update you'll create one object per frame, which is most likely too many. My guess would be that you want something like a coroutine that will run on a random interval, and then spawn cubes repeatedly over time, something like this:
void Start () {
StartCoroutine("SpawnObjects");
}
IEnumerator SpawnObjects()
{
while (keepAddingObjects) // a boolean - could just be "true" or could be controlled elsewhere
{
GameObject SpawnLocation = (GameObject)Instantiate(myCube, spawnLocation, Quaternion.identity);
float delay = Random.Range(1f, 5f); // adjust this to set frequency of obstacles
yield return new WaitForSeconds(delay);
}
}
Taken from my own code in a game that auto generate mazes:
public class Cell
{
private GameObject instance;
public void CreateVisual()
{
// Load a GameObject that exist inside the "Resources" folder.
GameObject prefab = (GameObject)Resources.Load("Models/Walls/3W1");
// Create an instance of the prefab
instance = (GameObject)GameObject.Instantiate(prefab);
instance.transform.position = myPosition;
}
}
I think the part you are missing is the Resources.Load() method.