Unity recompile serialized script - c#

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);
}
}

Related

Unity Physics.Raycast with LayerMask does not detect object on layer. Used bitshifting, tried inverting layer, still nothing works

novice to intermediate Unity developer here. I've been hitting a pretty significant roadblock the past ~2 days concerning the raycast detection of objects with specific layers. I've been researching this issue quite a lot, and all the solutions I've found don't seem to reflect the strange issue I'm facing.
Basically, the problem follows this sequence of events:
My player character has a vision cone shaped trigger mesh called 'InSightBox' which detects all objects with the tag 'Mob' and adds them to a List of colliders called 'MobsInRange'.
public List<Collider> mobsInRange;
public List<Collider> GetColliders()
{
return mobsInRange;
}
// Start is called before the first frame update
void Start()
{
mobsInRange = new List<Collider>();
}
// Update is called once per frame
void Update()
{
}
//add enemy with tag 'mob' to list
private void OnTriggerEnter(Collider other)
{
if(!mobsInRange.Contains(other) && other.tag == "Mob")
{
mobsInRange.Add(other);
}
}
//remove enemy with tag 'mob' to list
private void OnTriggerExit(Collider other)
{
if (mobsInRange.Contains(other) && other.tag == "Mob")
{
mobsInRange.Remove(other);
}
}
This list is then fed up to the root/parent player game object containing everything relating to the player.
public Transform closestMob;
public List<Collider> mobs;
public Transform GetClosestEnemy()
{
Transform tMin = null;
float minDist = Mathf.Infinity;
Vector3 currentPos = transform.position;
foreach(Collider trans in mobs)
{
//find enemy with closest distance and set tMin to it. Method returns tMin
float dist = Vector3.Distance(trans.transform.position, currentPos);
if(dist < minDist)
{
tMin = trans.transform;
minDist = dist;
}
}
//Debug.Log(tMin);
return tMin;
}
The player then uses a 'Look at' method to find the closest of all 'mobs' to the player. The player will set their forward transform to look at the closest mob.
Problem Step ---> 4) When the player raises their gun and attempts to shoot the closest enemy, a ray is cast with a layermask that looks only for objects on the layer 'Enemy', the 8th layer. When the ray detects the enemy, the enemy script should fire its 'TakeDamage' method which decreases the 'curHealth' variable by 8. Only problem is, the cast doesn't seem to detect the enemy object on the 'Enemy' layer.
LayerMask layerMask = 1 << 8;
void Fire()
{
//play the audio of the gunshot
StartCoroutine("SetPlaying");
RaycastHit hit;
//cast a ray from the player forward and check if the hit object is on layer 'Enemy'
if (Physics.Raycast(transform.position, transform.forward, out hit, Mathf.Infinity, layerMask))
{
//if hit object is an enemy, set its 'gotShot' bool to true
print("hit enemy");
closestMob.GetComponent<EnemyBase>().gotShot = true;
}
//play gunshot sound and stop player from turning
source.clip = fireSound;
source.PlayOneShot(fireSound, gunshotVolumeScale);
turnSpeed = 0;
}
I'll also note that all the solutions I've seen to this issue are not working for me. I declared an int variable called 'layerMask' and initialized it in Awake() by bit shifting layer 8 into it (i.e. int layerMask = 1 << 8), but it still isn't detecting it. The enemy contains all that I belive it should need for this to work, including a rigidbody, a capsule collider, the associated scripts, as well as being on the 'Enemy' layer.
This is where it gets weird (at least to my knowledge), when I invert the mask in the cast (~layerMask), it does exactly what I'd expect, and begins firing the code within the raycasts if statement when the player 'shoots' anything that doesn't have the 'Enemy' layer.
Any help would be suuuper appreciated as I'm getting to the point of slamming my face into the desk :/
Side Note: I'm getting to the point where I may just attach a 'fire range' cube trigger to my player and enabled it when the Fire() event is triggered, then have that check for game objects with the tag 'mob' as that kind of detection works most consistent to me.
First, be sure that you didn't confuse layers with tags. They are different.
Second, get rid of any implicit actions and references, i.e. don't use bitshifting, layer indices, or any non-straightforward reference. Instead, create something like this:
[SerializedField] private LayerMask _layerMask;
Use inspector to assign needed layer(s).
This way you will explicitly see, which layer you are using. This is useful not only for you, but for you in future, when you forget layers' indices. Also, for anyone who aren't familiar with the project.
Third is for debug. Be sure that your raycasting works as intended at other aspects:
Try remove layerMask and see if the ray goes where you want it to
Use custom gizmos to check if you cast the ray in a right direction
Try using RaycastAll. Maybe some objects catch (block) your ray earlier than you think
Looks like the issue was that I had my 'Enemy' prefab which contained the necessary components (RigidBody, Collider, scripts, NavmeshAgent) nested inside an empty game object. I thought at first to make something a prefab you needed to have it inside an Empty. I see now that is rather redundant and not necessary (at least in my case).
Physics.RaycastAll solved this issue as it no longer got 'halted' by the parent empty's collider and also hit the child.
I actually got it working just using a regular Physics.Raycast by rebuilding the Enemy prefab as just a single Capsule object (which I'll replace with character meshes later on).
Side Note
Before I got this new method working, I also used a different one that achieves the same goal in a pretty lightweight manner.
I added a long and thin box trigger to the front of my player so that it has enough distance to collide with any enemies within the shooting range.
I then enable the trigger any time the player enters their 'Aiming' state. If the trigger collides with any mesh that has the tag "Mob', it sets a bool on the player that indicates if the enemy is in range.
Then if the enemy is in range && the player enters the 'Firing Gun' state, a method in the Enemy Base script is fired that decrements the enemy health by a publicly decided variable called damagetaken.
Both the Raycast method and the box trigger method work equally well for me, but the box trigger one just took less time to figure out and gave me less headache haha.
Hope this helps anyone else in a bind!!!!!

Trail Renderer in Unity c# script

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);

Giving a game object velocity/speed and converting vectors points

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.

Script working properly on one gameobject, but not on another

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.

Unity3d maintaining a minimum distance between multiple GameObjects c#

I have multiple enemies that move toward the player. I am trying to stop them from merging into each other, i.e maintain some type of minimum distance between each other. What I'm trying is this (from unity3d forums):
enemy1.transform.position = (enemy1.transform.position -
enemy2.transform.position).normalized * distance + enemy2.transform.position;
However, when I have >= 3 enemies they still seem to bunch up even when I apply this to every enemy combination.
I need a better method as this one does not work and does not scale.
What you do around your enemy prefab is place a quad box which in effect is a trigger element, then on you script for the enemy you set that if another enemy (using tag types, I imagine) comes within touching of the quad box then to run appropriate code to stop the enemy getting closer in and to prevent the enemy actually overlapping with this trigger box.
Your code you example in your question looks like it is referencing the enemy units specifically rather than as instance entitites which is very probably a bad way of coding, as you're finding, it's very inflexible dealing with not-specifically-named reference entities.
using UnityEngine;
using System.Collections;
public class ExampleClass : MonoBehaviour
{
private Transform otherEntity;
public float distance = 50.0f;
private Transform thisEntity;
void OnTriggerEnter(Collider other)
{
otherEntity = other.GetComponent<Transform>();
thisEntity = GetComponent<Transform>();
thisEntity.position = (thisEntity.position - otherEntity.position).normalized * distance + otherEntity.position;
}
}
I have not tested the above code but using the code you reference the values for the transform are loaded from the Game Component for the referenced entities, as this has changed ALOT in Unity since release of version 5.1 and your source for your code was an answer given in 2012!!
thisEntity is the object that the script is attached to, typically one of the enemy. The otherEntity is the object that comes within the quad trigger (please remember the quad needs to be referenced as a trigger element.
The values of the Entity variables need to be set once the trigger is entered, so that it always effects the correct other element.
(I may be totally wrong with my methodology but I hope this helps.)

Categories

Resources