How can i access start() function from another script since start function can be only defined once
This is the script containing start() -
using UnityEngine;
using System.Collections;
public class MoverBolt : MonoBehaviour {
public PlayerControl obj ;
public float speed ;
public Rigidbody rb;
void Start(){
rb = GetComponent<Rigidbody>();
rb.velocity = transform.forward * speed;
}
}
Script which need to access start()
using UnityEngine;
using System.Collections;
[System.Serializable]
public class Boundary{
public float xMax,xMin,zMax,zMin;
}
public class PlayerControl : MonoBehaviour
{
public Boundary boundary ;
public float velocity;
public float tilt;
MoverBolt obj = new MoverBolt();
/* I made an object but it seems you are not supposed to create an object of class which is inheritance of MonoBehaviour */
void FixedUpdate()
{
float moveHorizontal = Input.GetAxis ("Horizontal");
float moveVertical = Input.GetAxis ("Vertical");
Vector3 movement = new Vector3 (moveHorizontal, 0.0f, moveVertical);
obj.rb.velocity = movement*velocity;
Vector3 current_position = obj.rb.position;
obj.rb.position = new Vector3 ( Mathf.Clamp(current_position.x,boundary.xMin,boundary.xMax),
0.0f,
Mathf.Clamp(current_position.z, boundary.zMin, boundary.zMax)
);
obj.rb.rotation= Quaternion.Euler(0.0f,0.0f,obj.rb.velocity.x*-tilt );
}
}
Error You are trying to create a MonoBehaviour using the 'new' keyword. This is not allowed. MonoBehaviours can only be added using AddComponent().
Are there any alternatives ?
it's possible to call a Start() method from outside. just make it public.
public class MoverBolt : MonoBehaviour {
public void Start ()
{
Debug.Log("MoverBolt.Start() was called");
}
}
public class PlayerControl : MonoBehaviour {
[SerializeField]
private MoverBolt _moverBolt;
void Start ()
{
_moverBolt.Start();
}
}
The output in the console of this is
MoverBolt.Start() was called
MoverBolt.Start() was called
UPDATE 1
I would not recommend this, because the Start() method is called by your code and the game engine again.
When I need to make sure a MonoBehaviour is properly setup, before another class uses it. I replace the Awake/Start method with public void Initialize() method and call that from outside.
Very simple answer. You can't Access start () function from any other scripts.
Use "Instantiate". For example, you can create of prefab of the game object that you want to make a copy of and then use the prefab to generate the new objects.
public class ObjectFactory : MonoBehaviour()
{
public GameObject prefab; // Set this through the editor.
public void GenerateObject()
{
// This will create a copy of the "prefab" object and its Start method will get called:
Instantiate(prefab);
}
}
Related
I have a C# script attached to an empty object called GameManager. The script is GameManager.cs. Here are the first few lines:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GameManager : MonoBehaviour {
public GameObject tilePrefab;
public GameObject startTile;
public GameObject lastTile;
I have another script attached to a camera called CameraManager.cs. I'm attempting to reference lastTile from GameManager but it's always null. Here is the full code for CameraManager.cs:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CameraManager : MonoBehaviour
{
// Start is called before the first frame update
private Vector3 currPos;
private Vector3 newPos;
public float CamMoveSpeed = 5f;
GameManager gameManager;
private void Awake() {
gameManager = gameObject.AddComponent<GameManager>();
}
private void Start() {
}
private void Update() {
if (gameManager.lastTile != null) {
currPos = gameObject.transform.position;
Vector3 tilePos = gameManager.lastTile.transform.position;
newPos = new Vector3(currPos.x + tilePos.x, currPos.y + tilePos.y, currPos.z + tilePos.z);
this.transform.position = Vector3.Lerp(currPos, newPos, CamMoveSpeed * Time.deltaTime);
Debug.Log("Moving Camera...");
} else {
Debug.LogWarning("gameManager.lastTile is NULL");
}
}
}
This latest iteration is based on this SO question. The previous iteration was based on this SO question.
What is the proper way to reference a value from another script/class?
All I had to do was make the property public and then assign it in the inspector by dragging the GameManager object to the corresponding field. I was able to remove everything in the awake routine.
In the awake method of your camera class you assign gameManager with AddComponent, that will create a new instance of the GameManager script on the same object that your camera manager class is on, meaning that the reference that your camera manager class has to the GameManager class is not the one that’s on your GameManager gameObject.
What people do usually with GameManager classes is to use a Signlton structure
Basically you can have a static field of type GameManager in your GameManager class and assign it to its own instance on the Awake method of your GameManager class. Something like this
public class GameManager : MonoBehaviour {
public GameObject tilePrefab = new GameObject("Name");
public GameObject startTile = new GameObject("Name");
public GameObject lastTile = new GameObject("Name");
public static GameManager Instance;
private void Awake(){
Instance = this;
}
}
And then you can use your game manager in any other class with this line GameManager.Instance.lastTitle
public class GameManager : MonoBehaviour {
public GameObject tilePrefab;
public GameObject startTile;
public GameObject lastTile;
}
It doesnt look like your ever assigning these variables to anything, therefore they will always be null.
For them not to be null you need to assign them to something e.g.
public class GameManager : MonoBehaviour {
public GameObject tilePrefab = new GameObject("Name");
public GameObject startTile = new GameObject("Name");
public GameObject lastTile = new GameObject("Name");
}
Or you can set them dynamically by doing
private void Update() {
gameManager.lastTile = new GameObject("Name");
}
I am making a game when you gather but my MoveTowards method just teleports the object there or to the position I asked. I have made my own MoveTo method so here are my 3 scripts. One is an IUNit script which is an interface and holds the method MoveTo:
using System;
using UnityEngine;
public interface IUnit
{
void MoveTo(Vector2 position, float stopDistance, Action onArrivedAtPosition);
}
Here is my Unit script which is where the AI goes:
using UnityEngine;
public class Unit: MonoBehaviour, IUnit
{
public float speed;
public void MoveTo(Vector2 position, float stopDistance, System.Action arrivedAtPosition)
{
if (Vector2.Distance(transform.position, position) >= stopDistance)
{
transform.position = Vector2.MoveTowards(transform.position, position, speed * Time.deltaTime);
}
}
}
Then my GathererAI which activates my script:
using UnityEngine;
[RequireComponent(typeof(Unit))]
public class GathererAI : MonoBehaviour
{
public Transform treeNode;
public Transform storageNode;
public IUnit unit;
private void Start()
{
unit = gameObject.GetComponent<IUnit>();
unit.MoveTo(treeNode.position, 10f, null);
}
}
But the thing is it just teleports to the position without slowly moving. Please help?
Also, how do you start an action?
Instead of MoveTo, you can try using a Rigidbody (rb), and do:
public Rigidbody2D rb;
public float speed, acceleration;
public Transform goHere;
void FixedUpdate()
{
Vector3 direction = goHere.position - transform.position;
direction = direction.normalized;
Vector3 targetVelocity = new Vector3(direction.x * speed, direction.y * speed);
rb.velocity = Vector3.Lerp(rb.velocity, targetVelocity, acceleration);
}
Unless you don't want to use Rigidbodies, in which case, you should still have a target Vector (direction or location), and Lerp towards that position in a similar fashion ( Lerp = Linear interpolation).
Here are your three scripts which I changed a bit to make it work.
IUnit.cs:
using System;
using UnityEngine;
public interface IUnit
{
void MoveTo(Vector2 position, float stopDistance, Action onArrivedAtPosition);
}
Unit.cs:
using UnityEngine;
public class Unit: MonoBehaviour, IUnit
{
public float speed = 5;
public void MoveTo(Vector2 position, float stopDistance, System.Action arrivedAtPosition)
{
if (Vector2.Distance(transform.position, position) >= stopDistance)
{
transform.position = Vector2.MoveTowards(transform.position, position, speed * Time.deltaTime);
}
}
}
GatheredAI.cs:
using UnityEngine;
[RequireComponent(typeof(Unit))]
public class GathererAI : MonoBehaviour
{
public Transform treeNode;
public Transform storageNode;
public IUnit unit;
private void Start()
{
unit = gameObject.GetComponent<IUnit>();
// unit.MoveTo(treeNode.position, 10f, null);
}
void Update()
{
unit.MoveTo(treeNode.position, 10f, null);
}
}
Usually Vector2.MoveTowards is called in a repeating function, and yours was being called only once. And your speed may have been a bit too much for the distance that your body was supposed to travel, so it just teleported in that single call.
Also it won't be ideal to invoke an Action in this case because you are not finishing the complete movement in single call. To do that you will need to convert this MoveTo function to a coroutine maybe to loop over Vector2.MoveTowards and when the coroutine comes to an end then you simply call the action parameter as a function. It will simply call a callback function when your movement is done.
public void MoveTo(Vector2 position, float stopDistance, System.Action arrivedAtPosition)
{
// your move logic here....
arrivedAtPosition();
//if you need to pass some argument say a bool, then change function parameter as "Action<bool> arrivedAtPosition" and call "arrivedAtPosition(true);"
}
I'm trying to use a UI Slider to change the movement speed for my player character using the GetComponent feature. I have everything working except apply the number(float) that I create from the movement of the slider to the variable that controls how fast the player can move.
I've used Debug.Log(); to determine that the variable I'm trying to grab from one script does not equal the other. It almost seems that they're being stored as two separate variables.
The varspeed variable keeps track of the number when I move the slider.
In script BallScript:
GameObject.Find("Canvas").GetComponent<PointBuyScript>().varspeed = speedvar1;
Debug.Log(speedvar1);
In script PointBuyScript:
public void Start()
{
mySpeed.onValueChanged.AddListener(delegate { ValueChangeCheck(); });
}
public void LateUpdate()
{
varspeed = mySpeed.value;
Debug.Log(varspeed);
}
When I move the slider the number in the console from PointBuyScript scales with the Slider. However, the one from BallScript forever remains the same.
BallScript Code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class BallScript : MonoBehaviour
{
// Start is called before the first frame update
public float speed;
private Rigidbody rb;
public float speedvar1;
public float SpeedMain;
void Start()
{
rb = GetComponent<Rigidbody>();
speedvar1 = GameObject.Find("Canvas").GetComponent<PointBuyScript>().mySpeed.value;
}
void FixedUpdate()
{
float moveHorizontal = Input.GetAxis("Horizontal");
float moveVertical = Input.GetAxis("Vertical");
Vector3 movement = new Vector3(moveHorizontal, 0.00f, moveVertical);
speed = speedvar1; // this is where I try and update the speed variable to the slider number
rb.AddForce(movement * speed);
}
void LateUpdate()
{
Debug.Log(speedvar1);
Debug.Log(speed);
// Debug.Log(SpeedMain);
}
}
PointBuyScript Code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class PointBuyScript : MonoBehaviour
{
public Slider mySpeed;
public float varspeed;
public float mainSpeed;
public void Start()
{
// GameObject speed1 = GameObject.Find("Ball");
// BallScript hellome = speed1.GetComponent<BallScript>();
// varspeed = GameObject.Find("Ball").GetComponent<BallScript>().speed;
//Adds a listener to the main slider and invokes a method when the value changes.
mySpeed.onValueChanged.AddListener(delegate { ValueChangeCheck(); });
}
public void Update()
{
// Debug.Log(mySpeed.value);
//mainSpeed = mySpeed.value;
}
public void LateUpdate()
{
varspeed = mySpeed.value;
Debug.Log(varspeed);
}
// Invoked when the value of the slider changes.
public void ValueChangeCheck()
{
}
}
This code:
GameObject.Find("Canvas").GetComponent<PointBuyScript>().varspeed = speedvar1;
Says "take the value in speedvar1 and assign it to PointBuyScript#varspeed." That is, the value of PointBuyScript#varspeed is changed (and speedvar1 remains unchanged).
You probably want:
speedvar1 = GameObject.Find("Canvas").GetComponent<PointBuyScript>().varspeed;
I am trying to code my first game 'Tappy Bird' using Unity2D. When I try to run the app, I am receiving the following error message in Unity:
Assets/scripts/TapController.cs(6,6): error CS0592: The attribute
UnityEngine.RequireComponent is not valid on this declaration type.
It is valid on class declarations only
Code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class NewBehaviourScript : MonoBehaviour
{
[RequireComponent(typeof(Rigidbody2D))]
public float tapForce = 10;
public float tiltSmooth = 5;
public Vector3 startPos;
Rigidbody2D rigidbody;
Quaternion downRotation;
Quaternion forwardRotation;
void Start()
{
rigidbody = GetComponent<Rigidbody2D();
downRotation = Quaternion.Euler(0, 0, -90);
forwardRotation = Quaternion.Euler(0, 0, 35);
}
void update()
{
if (input.GetMouseButtonDown(0))
{
transform.rotation = forwardRotation;
rigidbody.AddForce(vector2.up * tapForce, ForceMode2D.Force);
}
transform.rotation = Quaternion.Lerp(
transform.rotation, downRotation, tiltSmooth * Time.deltaTime);
}
void onTriggerEnter2D(Collider2D col){
if(col.gameObject.tag == "ScoreZone") {
//register a Score event
//play sound
}
if(col.gmeObject.tag == "DeadZone") {
//register a dead event
//play a sound
}
}
}
If I understand your code right you should add attribute before class declaration:
[RequireComponent(typeof(Rigidbody2D))]
public class NewBehaviourScript : MonoBehaviour
{
...
}
The RequireComponent attribute that adds required components as dependencies needs to be set outside of your class.
https://docs.unity3d.com/ScriptReference/RequireComponent.html
https://docs.unity3d.com/ScriptReference/RequireComponent.html
Firstly, it should be in front of the class name;
Secondly, if you have attach the script to gameobject, you need to reattach again.
[RequireComponent(typeof(Rigidbody2D))]
public class NewBehaviourScript : MonoBehaviour
{
//...
}
I made a script which swaps two game objects on click.But the script won't work because the objects are actualy clones of the original prefab.
This is the script(java) :
#pragma strict
var object1 : GameObject;
var object2 : GameObject;
function OnMouseDown ()
{
Instantiate(object2,object1.transform.position,object1.transform.rotation);
Destroy(object1);
}
I use this script to create other game objects (clones)[c#] :
using UnityEngine;
using System.Collections;
public class Spawner : MonoBehaviour {
public GameObject[] obj;
public float spawnMin = 1f;
public float spawnMax = 2f;
// Use this for initialization
void Start () {
Spawn ();
}
void Spawn()
{
Instantiate(obj[Random.Range(0, obj.GetLength(0))],transform.position, Quaternion.identity);
Invoke ("Spawn", Random.Range (spawnMin, spawnMax));
}
}
The objects get renamed to NAME (Clone).
What I wanna do is make the script affect clones too.So they will swap when I click on them.