Currently I'm making my first video game using unity written in C#, but now I'm facing a trouble and I don't know what to do anymore. First I already made my character move but, I want to put all the attributes in one script, like it's moveSpeed, attackSpeed, etc. but once I access it to another script, my character just stands and do nothing. Here's my code
public class ClickToMove : MonoBehaviour {
public CharacterController controller; // Use to move the player
private Vector3 position; // Store the position at which the player clicked;
public Attributes attribute;
// Animation variables
public AnimationClip idleClip;
public AnimationClip runClip;
// Use this for initialization
void Start () {
position = transform.position; // Set the position to player's current position
}
// Update is called once per frame
void Update () {
// Execute the code below once the player press left click
if(Input.GetMouseButton(0)) {
locatePosition();
}
moveToPosition();
}
// Locate at which the player clicked on the terrain
private void locatePosition() {
RaycastHit hit; // Get information from ray
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); // A line in 3D space
// Cast a ray that start from the camera with a distance of 1000
if(Physics.Raycast(ray, out hit, 1000)) {
// Store the position if the casted ray is not pointing to the player or enemy's position
if(hit.collider.tag != "Player" && hit.collider.tag != "Enemy") {
position = new Vector3(hit.point.x, hit.point.y, hit.point.z);
}
}
}
// Move to the located position
private void moveToPosition() {
// Check if the player position and the destination is greater than one
if(Vector3.Distance(transform.position, position) > 1) {
// Subtract the clicked position to the player position
Quaternion newRotation = Quaternion.LookRotation (position - transform.position);
// Disable the rotation from x and z angle
newRotation.x = 0f;
newRotation.z = 0f;
// Rotate the player to a new rotation then move forward
transform.rotation = Quaternion.Slerp(transform.rotation, newRotation, Time.deltaTime * attribute.moveSpeed);
controller.SimpleMove(transform.forward * attribute.moveSpeed);
animation.CrossFade(runClip.name);
} else {
animation.CrossFade(idleClip.name);
}
}
}
and here is the script I'm accessing
public class Attributes : MonoBehaviour {
public float moveSpeed;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
}
}
I don't know what to do anymore. Any help will be appreciated. Thank you.
There are a couple of things that you need to double check, the first being that you are actually assigning a value to attribute.moveSpeed in the inspector. Otherwise moveSpeed will always be 0 and therefore all of your multiplication operations will result in 0, resulting in no movement at all.
Second, make sure that something is actually being hit by your raycast. You can do this a couple ways, first by printing a message to the console saying that you hit something
// Cast a ray that start from the camera with a distance of 1000
if(Physics.Raycast(ray, out hit, 1000)) {
// Send a debug message to Unity's console
Debug.Log("I hit Something!");
// Store the position if the casted ray is not pointing to the player or enemy's position
if(hit.collider.tag != "Player" && hit.collider.tag != "Enemy") {
position = new Vector3(hit.point.x, hit.point.y, hit.point.z);
}
}
and second by checking that the position variable changed values in the inspector. (Make the position variable public and look at your character's inspector)
Note that you've assigned a value to your attribute variable in the inspector because you're not getting NullReferenceExceptions
Related
I've been trying to set an enemy on a patrol path while not chasing my player character. I want to use RayCast so that the enemy can spot the player and begin to chase the player. It functions as I intended. However, even when there's an obstacle or wall between us, or when I approach from behind, the enemy 'sees' my player and starts to chase me. It seems to ignore the Raycast, and instead focuses on the proximity to the enemy.
Enemy spotting player through wall
public class EnemyController : MonoBehaviour
{
private NavMeshAgent enemy;// assaign navmesh agent
private Transform playerTarget;// reference to player's position
private float attackRadius = 10.0f; // radius where enemy will spot player
public Transform[] destinationPoints;// array of points for enemy to patrol
private int currentDestination;// reference to current position
public bool canSeePlayer = false;
private Ray enemyEyes;
public RaycastHit hitData;
private void Awake()
{
enemy = GetComponent<NavMeshAgent>();
playerTarget = GameObject.Find("Player").GetComponent<Transform>();
enemyEyes = new Ray(transform.position, transform.forward);
}
private void Start()
{
Physics.Raycast(enemyEyes, attackRadius);
}
private void Update()
{
Lurk();
Debug.DrawRay(transform.position, transform.forward * attackRadius);
}
void Lurk()
{
Debug.Log("Lurking");
float distanceToPlayer = Vector3.Distance(transform.position, playerTarget.position);
//check if raycast hits playerLayer and enemy is close enough to attack
if (Physics.Raycast(enemyEyes, out hitData, attackRadius * 2, layerMask: ~6) && distanceToPlayer < attackRadius)
{
Debug.Log("You hit " + hitData.collider.gameObject.name);
ChasePlayer();
}
else
{
canSeePlayer = false;
Patrol();
}
}
void Patrol()
{
if (!canSeePlayer && enemy.remainingDistance < 0.5f)
{
enemy.destination = destinationPoints[currentDestination].position;
UpdateCurrentPoint();
}
}
void UpdateCurrentPoint()
{
if (currentDestination == destinationPoints.Length - 1)
{
currentDestination = 0;
}
else
{
currentDestination++;
}
}
void ChasePlayer()
{
StartCoroutine(ChaseTime());
canSeePlayer = true;
transform.LookAt(playerTarget.position);
Vector3 moveTo = Vector3.MoveTowards(transform.position, playerTarget.position, attackRadius);
enemy.SetDestination(moveTo);
}
IEnumerator ChaseTime()
{
Debug.Log("Chasing");
yield return new WaitForSeconds(10.0f);
if (!Physics.Raycast(enemyEyes, out hitData, attackRadius * 2, layerMask: ~6))
{
canSeePlayer = false;
Debug.Log("Lurking");
Lurk();
}
}
}
I've removed the tilde "~" for the layermask, but then the enemy doesn't ever see the player.
I've initialised and set a layer mask reference to the 'playerLayer' and used it in place of "layermask: ~6", to no avail.
I've used the int reference to the Player layer, to no avail.
I've used bitwise operator to reference the player layer, to no avail.
I've removed the distanceToPlayer conditional, but the enemy doesn't see the player.
I've adjusted the length of the Ray but if it's ever shorter than the attack radius, it doesn't work.
I don't understand why you need a layer mask. If you want the Raycast to hit something in front of the player then you must include all layers in the Raycast.
What you need to do is remove the layermask from Raycast and in the if statement check if the out hit collider is on Player and if the player is in attack radius. Here is a simple outline
If(raycast)
{
if(hit.collider.gameobject==player && player in proximity)
{
Then can see is true
}
}
You can give this article on Unity Raycast a read to understand more on layermask.
regarding player detection through a wall,I would try adding an extra if statement in the Lurk method.This condition would check if the raycast is touching the wall, if so, do not proceed with the method, if not, continue. Sorry for giving the code in this form but I don't have access to a computer and the phone doesn't want to cooperate
enter image description here
Hi so i have followed every instruction from youtube videos (https://m.youtube.com/watch?v=NMt6Ibxa_XQ) but in the game mode i still cant drag and drop my cube, the cube just stay still when i click and drag it. This problem really gave me a headache i’m pretty sure i have followed every detail from the video and repeat it over and over, thank’s for your time and help i really appreciate and need it, thank youi
in order for your cube to take the OnMouseDown() event you need to add a collider and rigidbody. click the cube, go to the properties on the right and click
add component - physics - cube collider
then do the same, for the rigid body
add component - physics - rigid body.
dont forget to set the rigidbody to kinematic, or set the gravity scale to 0 if you dont want it to fall out of the scene
use this script in order to drad and drop 3D Objects :
using UnityEngine;
using System.Collections;
public class DragAndDrop : MonoBehaviour
{
private bool _mouseState;
private GameObject target;
public Vector3 screenSpace;
public Vector3 offset;
// Use this for initialization
void Start ()
{
}
// Update is called once per frame
void Update ()
{
// Debug.Log(_mouseState);
if (Input.GetMouseButtonDown (0)) {
RaycastHit hitInfo;
target = GetClickedObject (out hitInfo);
if (target != null) {
_mouseState = true;
screenSpace = Camera.main.WorldToScreenPoint (target.transform.position);
offset = target.transform.position - Camera.main.ScreenToWorldPoint (new Vector3 (Input.mousePosition.x, Input.mousePosition.y, screenSpace.z));
}
}
if (Input.GetMouseButtonUp (0)) {
_mouseState = false;
}
if (_mouseState) {
//keep track of the mouse position
var curScreenSpace = new Vector3 (Input.mousePosition.x, Input.mousePosition.y, screenSpace.z);
//convert the screen mouse position to world point and adjust with offset
var curPosition = Camera.main.ScreenToWorldPoint (curScreenSpace) + offset;
//update the position of the object in the world
target.transform.position = curPosition;
}
}
GameObject GetClickedObject (out RaycastHit hit)
{
GameObject target = null;
Ray ray = Camera.main.ScreenPointToRay (Input.mousePosition);
if (Physics.Raycast (ray.origin, ray.direction * 10, out hit)) {
target = hit.collider.gameObject;
}
return target;
}
}
This is my click to move code, This is my first question, so I'm new to this. If you need any more information I will be happy to give it to you!
I have made a top-down dungeon game (Like Diablo), I completed creating all of the dungeon levels and started to animate and move my player, I got it working starting on the third and last level and it works perfect, I was happy as this is my first time making a game. I created a prefab of the character and moved it into the other levels and only got error when I clicked to move, I have tried to add them in separately but still didn't work sadly.
using UnityEngine;
using System.Collections;
public class ClickToMove : MonoBehaviour
{
public float speed;
public CharacterController controller;
private Vector3 position;
public AnimationClip idle;
public AnimationClip run;
public static Vector3 cursorPosition;
// Use this for initialization
void Start ()
{
position = transform.position;
}
// Update is called once per frame
void Update ()
{
if(Input.GetMouseButton(0))
{
//Locate where the player clicked on the terrain
locatePosition();
}
//Move the player to the position
moveToPosition();
}
void locatePosition()
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if(Physics.Raycast(ray, out hit, 1000))
{
if(hit.collider.tag!="Player"&&hit.collider.tag!="Enemy")
{
position = hit.point;
}
}
}
void locateCursor()
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if(Physics.Raycast(ray, out hit, 1000))
{
cursorPosition = hit.point;
}
}
void moveToPosition()
{
//Game Object is moving
if(Vector3.Distance(transform.position, position)>1)
{
Quaternion newRotation = Quaternion.LookRotation(position- transform.position, Vector3.forward);
newRotation.x = 0f;
newRotation.z = 0f;
transform.rotation = Quaternion.Slerp(transform.rotation, newRotation, Time.deltaTime * 10);
controller.SimpleMove(transform.forward * speed);
GetComponent<Animation>().CrossFade("run");
}
//Game Object is not moving
else
{
GetComponent<Animation>().CrossFade("idle");
}
}
}
As Catwood said, double clicking on the error in the console will take you to the relevant line of code that's causing the exception. I'd expect it to be one of the GetComponent calls though as you're trying to call the CrossFade function on something that might return null (in the case that the Animator component can't be found).
As a side note, you should avoid using GetComponent like this as it's inefficient. Instead, create a private / protected variable and store the reference when you first get the component.
I'm following a tutorial on Unity 5 to create a simple stealth game.
I followed the instructions to create the script that controls the movement of the player. When I tested the game I noticed that the player takes a few seconds after pressing the button before moving.
It's as if before moving should await the conclusion of the rotation that is performed by Quaternion.Lerp.
Also pressing the x button should scream to attract attention and take proper animation.. It runs the sound but the animation is not done.. Was performed only once in multiple tests I did.
public class PlayerMovement : MonoBehaviour
{
public AudioClip shoutingClip; // Audio clip of the player shouting.
public float turnSmoothing = 15f; // A smoothing value for turning the player.
public float speedDampTime = 0.1f; // The damping for the speed parameter
private Animator anim; // Reference to the animator component.
private HashIDs hash; // Reference to the HashIDs.
void Awake ()
{
// Setting up the references.
anim = GetComponent<Animator>();
hash = GameObject.FindGameObjectWithTag(Tags.gameController).GetComponent<HashIDs>();
// Set the weight of the shouting layer to 1.
anim.SetLayerWeight(1, 1f);
}
void FixedUpdate ()
{
// Cache the inputs.
float h = Input.GetAxis("Horizontal");
float v = Input.GetAxis("Vertical");
bool sneak = Input.GetButton("Sneak");
MovementManagement(h, v, sneak);
}
void Update ()
{
// Cache the attention attracting input.
bool shout = Input.GetButtonDown("Attract");
// Set the animator shouting parameter.
anim.SetBool(hash.shoutingBool, shout);
AudioManagement(shout);
}
void MovementManagement (float horizontal, float vertical, bool sneaking)
{
// Set the sneaking parameter to the sneak input.
anim.SetBool(hash.sneakingBool, sneaking);
// If there is some axis input...
if(horizontal != 0f || vertical != 0f)
{
// ... set the players rotation and set the speed parameter to 5.5f.
Rotating(horizontal, vertical);
anim.SetFloat(hash.speedFloat, 5.5f, speedDampTime, Time.deltaTime);
}
else
// Otherwise set the speed parameter to 0.
anim.SetFloat(hash.speedFloat, 0);
}
void Rotating (float horizontal, float vertical)
{
// Create a new vector of the horizontal and vertical inputs.
Vector3 targetDirection = new Vector3(horizontal, 0f, vertical);
// Create a rotation based on this new vector assuming that up is the global y axis.
Quaternion targetRotation = Quaternion.LookRotation(targetDirection, Vector3.up);
// Create a rotation that is an increment closer to the target rotation from the player's rotation.
Quaternion newRotation = Quaternion.Lerp(GetComponent<Rigidbody>().rotation, targetRotation, turnSmoothing * Time.deltaTime);
// Change the players rotation to this new rotation.
GetComponent<Rigidbody>().MoveRotation(newRotation);
}
void AudioManagement (bool shout)
{
// If the player is currently in the run state...
if(anim.GetCurrentAnimatorStateInfo(0).nameHash == hash.locomotionState)
{
// ... and if the footsteps are not playing...
if(!GetComponent<AudioSource>().isPlaying)
// ... play them.
GetComponent<AudioSource>().Play();
}
else
// Otherwise stop the footsteps.
GetComponent<AudioSource>().Stop();
// If the shout input has been pressed...
if(shout)
// ... play the shouting clip where we are.
AudioSource.PlayClipAtPoint(shoutingClip, transform.position);
}
}
I'm new in unity so I might need some more explanation. Thanks to everyone!
The first issue, delaying your player movement, may be caused by the line
anim.SetFloat(hash.speedFloat, 5.5f, speedDampTime, Time.deltaTime);
The potential issue is that you are calling Time.deltaTime, which is intended to be use inside an update() call. Your function is called inside of fixedUpdate() which means you should be using Time.fixedDeltaTime.
For your second issue, shouting, the code seems fine and the issue is likely in your animation tree. Check that the state you are in before shouting can transition to shout, and checks for the correct trigger.
I'm in the process of getting multiple enemies to work in my game for my college project. I have a player with a ShootGun script which raycasts the gun and detects whether or not the object hit is one of the enemy colliders (tagged with Enemy_Head, _Torso and _Limb). If it is, it will get the gameobject of the enemy hit and the enemyHealth script component on that gameobject and will then call public functions on that script. Currently, when the ShootGun script tries to get the component / script it says the following error:
NullReferenceException: Object reference not set to an instance of an object
ShootGun.gunFire () (at Assets/Scripts/Gun/ShootGun.cs:107)
UPDATED ERROR CODE:
NullReferenceException: Object reference not set to an instance of an object
ShootGun.gunFire () (at Assets/Scripts/Gun/ShootGun.cs:113)
Line 113 = enHit.enemyShotTorso();
The error appears for each line where enHit tries to call a function from the enemyHealth script.
The following is the raycast within my ShootGun script:
// Raycasting for bullet projection against obstacles within the world (WIP)
float gunRayDistance = 50f;
Ray ray = GetComponent<Camera>().ViewportPointToRay(new Vector3(0.5F, 0.5F, 0));
// Name what for the raycast collides with (used to reference the target point)
RaycastHit hit;
// The actual raycast
if(Physics.Raycast(ray, out hit, gunRayDistance, 1 << 9) || Physics.Raycast(ray, out hit, gunRayDistance, 1 << 8)) {
Debug.Log("Bullet Hit");
EnemyHealth enHit = hit.collider.gameObject.GetComponent<EnemyHealth>();
// Checking if the raycast (bullet) collided with objects tagged with "Enemy_Head".
if (hit.collider.gameObject.CompareTag("Enemy_Head")) {
Debug.Log ("Headshot!");
//hitPoint = hit.collider.gameObject;
enHit = hit.collider.gameObject.GetComponent<EnemyHealth>();
enHit.enemyShotHead();
}
// Checking if the raycast (bullet) collided with objects tagged with "Enemy_Torso".
if (hit.collider.gameObject.CompareTag("Enemy_Torso")) {
Debug.Log ("Body-shot!");
//hitPoint = hit.collider.gameObject;
enHit = hit.collider.gameObject.GetComponent<EnemyHealth>();
enHit.enemyShotTorso();
}
// Checking if the raycast (bullet) collided with objects tagged with "Enemy_Limb".
if (hit.collider.gameObject.CompareTag("Enemy_Limb")) {
Debug.Log ("Limb-shot!");
enHit = hit.collider.gameObject.GetComponent<EnemyHealth>();
enHit.enemyShotLimb();
}
// The point of contact with the model is given by the hit.point (to not cause z-fighting issues with layering)
Vector3 bulletHolePosition = hit.point + hit.normal * 0.01f;
// Rotation to match where it hits (between the quad vector forward axis and the hit normal)
Quaternion bulletHoleRotation = Quaternion.FromToRotation(-Vector3.forward, hit.normal);
GameObject hole = (GameObject)GameObject.Instantiate(bulletHolePrefab, bulletHolePosition, bulletHoleRotation);
// Destroy the instantiated gameobject of the bulletHole after a delay of 5 seconds.
Destroy (hole, 5.0f);
}
}
The following is my EnemyHealth script:
public class EnemyHealth : MonoBehaviour {
public float enemyHealth = 100.0f;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
enemyDeath ();
}
public void enemyShotHead() {
enemyHealth -= 60f;
Debug.Log (enemyHealth);
}
public void enemyShotTorso() {
enemyHealth -= 40f;
Debug.Log (enemyHealth);
}
public void enemyShotLimb() {
enemyHealth -= 20f;
Debug.Log (enemyHealth);
}
void enemyDeath() {
if (enemyHealth <= 0.0f) {
Debug.Log ("Enemy Killed");
gameObject.SetActive(false);
}
}
}
Any help with trying to figure out why it's not getting the reference / setting them would be greatly appreciated, thanks.
enHit is likely null. Repace all your
hit.transform.gameObject.GetComponent<EnemyHealth>();
with
hit.collider.gameObject.GetComponent<EnemyHealth>();
You have about 4 of them in your script. You want to get the EnemyHealth Script attached to the object the Ray hit through the collider.
EDIT:
You also need to change
hit.transform.CompareTag("Enemy_Head")
hit.transform.CompareTag("Enemy_Torso")
hit.transform.CompareTag("Enemy_Limb")
to
hit.collider.gameObject.CompareTag("Enemy_Head")
hit.collider.gameObject.CompareTag("Enemy_Torso")
hit.collider.gameObject.CompareTag("Enemy_Limb")
This may NOT solve the current error you are getting but it is one of the problems that is causing that error.