So essentially I've:
Instantiated a new prefab of an object
Set all the variables in the transform of the prefab
Copied the script for the initial capsule (which works) into the prefab spawning script
And yet my prefabs for some reason really do not want to follow the path around, how do I make them follow the path?
public class PathFollower : MonoBehaviour
{
public float movementSpeed;
//private float pathProgress = 0;
public GameObject objectToSpawn;
public Transform[] positionPoint;
[Range(0,1)]
public float value;
void Start()
{
Debug.Log(iTween.PathLength(positionPoint));
}
void Update()
{
movementSpeed = 10f;
if (value < 1)
{
value += Time.deltaTime / movementSpeed;
}
iTween.PutOnPath(objectToSpawn, positionPoint, value);
}
private void OnDrawGizmos()
{
iTween.DrawPath(positionPoint,Color.green);
}
}
public class deployCapsule : MonoBehaviour
{
public float movementSpeed;
public Transform[] positionPoint;
public GameObject CapsulePrefab;
[Range(0, 1)]
public float value;
//movementspeed = 10f;
// Start is called before the first frame update
void Start()
{
}
void Update()
{
GameObject a = Instantiate(CapsulePrefab) as GameObject;
a.transform.position = Camera.main.ScreenToWorldPoint(new Vector3(Screen.width - 20, Screen.height - 20, 10));
//if (Input.GetKeyDown(KeyCode.Space))
//{
a.GetComponent<PathFollower>().positionPoint = positionPoint;
//}
movementSpeed = 10f;
if (value < 1)
{
value += Time.deltaTime / movementSpeed;
}
iTween.PutOnPath(a, positionPoint, value);
}
}
Where the scripts are attached, also shows transform arrays:
Hard to say what is the exact problem, but from the image no 3 I see that value of variable value is 1 which may cause the problem.
It should be 0 so the object is at the beginning of the path.
You can use Start method to explicitly set the value of the value variable
Despite this, I wouldn't recommend you to instantiate game objects every frame (in Update method) because it's not efficient and probably will never have such use case.
Related
Every time I add an argument to my parameter in Character.cs which is basically trying to create an object of a class that uses an interface so that I can use the methods of said class to implement a function:
Lmovements left = ScriptableObject.CreateInstance<Lmovements>(position);
I get the error:
No overload for method 'CreateInstance' takes 1 argument
This is my code:
Lmovements.cs:
public class Lmovements : ScriptableObject, Commandclass.Execute
{
Vector3 cdirection;
float speed = 3f;
public Lmovements(Vector3 direction)
{
cdirection = direction;
}
public void Execute()
{
cdirection.x += speed * Time.deltaTime;
}
}
Character.cs:
public class Character : MonoBehaviour
{
float speed = 3f;
void Update()
{
Vector3 position = transform.position;
if (Input.GetKey(KeyCode.LeftArrow))
{
//position.x += speed * Time.deltaTime;
Lmovements left = ScriptableObject.CreateInstance<Lmovements>(position);
left.Execute();
}
if (Input.GetKey(KeyCode.RightArrow))
{
position.x -= speed * Time.deltaTime;
}
if (Input.GetKey(KeyCode.UpArrow))
{
position.z -= speed * Time.deltaTime;
}
if (Input.GetKey(KeyCode.DownArrow))
{
position.z += speed * Time.deltaTime;
}
transform.position = position;
}
}
The problem is that you are providing a position as an argument to the ScriptableObject.CreateInstance method which is not allowed.
First of all, ScriptableObjects are data containers in Unity and they can't be instantiated into the scene, which means you can't set them up position
Second, you must create your ScriptableObject in the Editor and reference them into the Monobehaviour script attached to some GameObject on the scene
The easiest way to create ScriptableObject is to add CreateAssetMenu as shown below
[CreateAssetMenu(menuName = "Lmovement", fileName = "Lmovement")]
public class Lmovements : ScriptableObject
And after that, you will get the option for creating as you can see in the image below
I am really new to unity and i'm trying to make a PlayerController with different states in different files.
this is the code so far:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour
{
private PlayerState currentState;
void Start()
{
currentState = new PlayerIdle(this);
Cursor.lockState = CursorLockMode.Locked;
}
void Update()
{
currentState.OnStateUpdate();
}
public void ChangeState(PlayerState newState)
{
currentState.OnStateExit();
currentState = newState;
newState.OnStateEnter();
}
}
how do i fix this?
edit: here is the PlayerIdle code which is supposed to give me the error.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerIdle : PlayerState
{
public CharacterController controller;
public Transform cam;
public GameObject player = GameObject.Find("Player");
public float speed = 12f;
public float gravity = -9.81f;
public float jumpHeight = 3;
public float rotationSpeed;
float x;
float z;
public Transform groundCheck = GameObject.Find("groundCheck").transform;
public float groundDistance = 0.4f;
public LayerMask groundMask;
[SerializeField] Vector3 velocity;
public bool isGrounded;
public float turnSmoothTime = 1f;
float turnSmoothVelocity;
public PlayerIdle(PlayerController playerController) : base(playerController)
{
this.playerController = playerController;
}
public override void OnStateEnter()
{
}
public override void OnStateExit()
{
}
public override void OnStateUpdate()
{
x = Input.GetAxisRaw("Horizontal");
z = Input.GetAxis("Vertical");
isGrounded = Physics.CheckSphere(groundCheck.position, groundDistance, groundMask);
velocity = player.transform.TransformDirection(Vector3.forward) * speed * z + new Vector3(0f, velocity.y, 0f); ;
if (Input.GetButtonDown("Jump") && isGrounded)
{
velocity.y = Mathf.Sqrt(jumpHeight * -2 * gravity);
}
if (isGrounded && velocity.y < 0)
{
velocity.y = -2f;
}
velocity.y += gravity * Time.deltaTime;
player.transform.Rotate(new Vector3(0f, x * rotationSpeed, 0f));
controller.Move(velocity * Time.deltaTime);
}
}
any help would be much appreciated :)
also, i found out this is called a statemachine if that helps.
The error says that something in that line is null.
The only thing that can be null is the CurrentState variable.
Probably when you assign it the value of new PlayerIdle (this) in the Start () method, that value is null.
If you can figure out why it's null, you can fix it, but if you're still having trouble you can include the PlayerIdle () code.
A suggestion may be to insert a print (currentState) at the end of Start () to understand if it is actually null.
In addition, also insert a print (new PlayerIdel (this)) in the Update () method to understand if even during the update it continues to be null.
it seems that the update method was being called before the start method (which i still don't understand), so the solution was just to add an if statement before currentState.OnStateUpdate(); saying "if (currentState != null)"
Hello everyone I made a rocket fire partical with Unity's partical system but Idk how can I make it activated when I press my thrust engine button (W and up Arrow is my buttons)
This is my code;
public class Rocket : MonoBehaviour
{
private Rigidbody2D rb;
public float amount;
public float MaxVelocity = 3;
public float RotationSpeed = 3;
// Start is called before the first frame update
void Start()
{
rb = GetComponent<Rigidbody2D>();
}
public void ThrustForward(float amount)
{
Vector2 force = transform.up * amount;
rb.AddForce(force);
}
// Update is called once per frame
void Update()
{
float Yaxis = Input.GetAxis("Vertical");
float Xaxis = Input.GetAxis("Horizontal");
ThrustForward(Yaxis);
Rotate(transform, Xaxis * RotationSpeed);
}
private void ClampVelocity()
{
float x = Mathf.Clamp(rb.velocity.x, -MaxVelocity, MaxVelocity);
float y = Mathf.Clamp(rb.velocity.y, -MaxVelocity, MaxVelocity);
rb.velocity = new Vector2(x, y);
}
private void Rotate(Transform t,float amount)
{
t.Rotate(0, 0, amount);
}
}
Please help me how can I start a particle system in unity with buttons
Thanks!!
If You Have A Particle System, You Can Make A Variable In Your Code Like, Following:
public ParticleSystem particle;
You Can Play The Particle System By Using The Variable With .Play() in end, for example, if you have created a variable like above as I suggested, you can play the particle system whenever you want.
The Way We Do It Is Pretty Simple.
particle.Play();
Direct Solution
Remove Everything From Your Script And Try Overwriting It With Following Code
public class Rocket : MonoBehaviour
{
private Rigidbody2D rb;
public ParticleSystem particle;
public float amount;
public float MaxVelocity = 3;
public float RotationSpeed = 3;
// Start is called before the first frame update
void Start()
{
rb = GetComponent<Rigidbody2D>();
}
public void ThrustForward(float amount)
{
Vector2 force = transform.up * amount;
rb.AddForce(force);
particle.Play();
}
// Update is called once per frame
void Update()
{
float Yaxis = Input.GetAxis("Vertical");
float Xaxis = Input.GetAxis("Horizontal");
ThrustForward(Yaxis);
Rotate(transform, Xaxis * RotationSpeed);
// You Can Do Exactly Same Thing For Arrow Key
// To Get Better Rusults Try Messing With The Particle System's Settings
}
private void ClampVelocity()
{
float x = Mathf.Clamp(rb.velocity.x, -MaxVelocity, MaxVelocity);
float y = Mathf.Clamp(rb.velocity.y, -MaxVelocity, MaxVelocity);
rb.velocity = new Vector2(x, y);
}
private void Rotate(Transform t,float amount)
{
t.Rotate(0, 0, amount);
}
}
I am trying to create level prograss bar, here is the script to fill the Slider along with ball when its moving towards finish line , here finish line is prefab clone which is randomly instantiated at different position. but as expected finishTransform using position(0, 0, 0) from prefab not from the clone. how can i retrieve the clone into the script when it is instantiated? here is the Progressbar Script :
[SerializeField] Transform ballTransform;
[SerializeField] Transform finishTransform;
[SerializeField] Slider slider;
float maxDistance;
void Start()
{
maxDistance = getDistance();
}
void Update()
{
if (ballTransform.position.z <= maxDistance && ballTransform.position.z <= finishTransform.position.z)
{
float distance = 1 - (getDistance() / maxDistance);
setProgress(distance);
}
}
float getDistance()
{
return Vector3.Distance(ballTransform.position, finishTransform.position);
}
void setProgress(float p)
{
slider.value = p;
}
Here is the Platform script where i instantiated the finish line
GameObject finalPlatformInstance = Instantiate(finalPlatform, transform);
finalPlatformInstance.transform.localPosition = new Vector3(0, 0, spawnPosZ);
This can be a solution.
public class PlatformSpawner : MonoBehaviour
{
public GameObject finalPlatform; // This get injected in the editor
public GameObject finalPlatformInstance;
void Awake()
{
finalPlatformInstance = Instantiate(finalPlatform, transform);
finalPlatformInstance.transform.localPosition = new Vector3(0, 0, z);
// TODO: add other logic...
}
}
public class ProgressBar : MonoBehaviour
{
private Platform platform;
void Start()
{
platform = FindObjectOfType<PlatformSpawner>();
}
void Update()
{
// TODO: access it via "platform.finalPlatformInstance"
}
}
I'm not sure why but my .addforce on my rigidbody isn't working.
I have tried following the official unity addforce tutorial.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ArrowController : MonoBehaviour
{
public Rigidbody2D rb;
public float speed = 5.0f;
public Vector2 pos;
void Start()
{
rb = GetComponent<Rigidbody2D>();
}
// Update is called once per frame
void Update()
{
faceMouse();
testForClick();
}
void faceMouse()
{
Vector3 mousePos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
Vector3 differance = GameObject.Find("gunArm").transform.position - mousePos;
float gunAngle = Mathf.Atan2(differance.y, differance.x) * Mathf.Rad2Deg;
GameObject.Find("gunArm").transform.rotation = Quaternion.Euler(0, 0, gunAngle);
}
void testForClick()
{
if (Input.GetMouseButtonDown(0))
{
print("click");
rb.AddForce(transform.forward);
}
}
}
I expect arrow to have force added to it in the forwards direction but it just prints out "click" (The message I added to ensure the mouse-click was working).
I'm not sure why but I created a test script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Test : MonoBehaviour
{
public Rigidbody2D rb;
public float speed = 20.0f;
// Start is called before the first frame update
void Start()
{
rb = GetComponent<Rigidbody2D>();
}
// Update is called once per frame
void Update()
{
if (Input.GetMouseButtonDown(0))
{
print("click");
rb.AddForce(transform.right * speed, ForceMode2D.Impulse);
}
rotate();
}
private void rotate()
{
}
}
I also edited my old script to this:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ArrowController : MonoBehaviour
{
public Rigidbody2D rb;
public float speed = 50.0f;
public Vector2 pos;
private void Start()
{
rb = GetComponent<Rigidbody2D>();
}
private void Update()
{
faceMouse();
testForClick();
}
void FixedUpdate()
{
if (doForce == true)
{
doForce = false;
rb.AddForce(transform.forward * speed, ForceMode2D.Impulse);
}
}
private bool doForce;
private GameObject gunArm;
private Camera cam;
private void faceMouse()
{
// try to reuse the reference
if (!cam) cam = Camera.main;
var mousePos = cam.ScreenToWorldPoint(Input.mousePosition);
// try to re-use the reference
if (!gunArm) gunArm = GameObject.Find("gunArm");
var difference = rb.transform.position - mousePos;
var gunAngle = Mathf.Atan2(difference.y, difference.x) * Mathf.Rad2Deg;
rb.transform.rotation = Quaternion.Euler(0, 0, gunAngle);
}
void testForClick()
{
if (Input.GetMouseButtonDown(0))
{
print("click");
// only set the flag
doForce = true;
}
}
void place()
{
}
}
and the test worked by itself with no rotation and on the main script only the rotation worked so i tried having both scripts active at the same time and it started working, thanks for all the help on this issue.
Despite the fact that isn't working is a quite weak description:
First of all you should do it in FixedUpdate but get the input in Update.
Second reduce the Find calls in Update .. very inefficient. It would be better to reference them via the Inspector if possible. Otherwise maybe in Start .. the way I show here is the last resort with lazy initialization assuming your script might be spawned later on runtime
Additionally (thanks to EricOverflow) you might want to rather pass ForceMode.Impulse to AddForce since you add the force only once and not continuesly.
public class ArrowController : MonoBehaviour
{
public Rigidbody2D rb;
public float speed = 5.0f;
public Vector2 pos;
// store and re-use references!
// would be better to already reference them via drag&drop
// in the Inspector
[SerializeField] private GameObject gunArm;
[SerializeField] private Camera cam;
private void Start()
{
rb = GetComponent<Rigidbody2D>();
}
private void Update()
{
testForClick();
}
private void FixedUpdate()
{
// also do this here
faceMouse();
if (doForce)
{
doForce = false;
rb.AddForce(transform.forward, ForceMode.Impulse);
}
}
private bool doForce;
private void faceMouse()
{
// try to reuse the reference
if(!cam) cam = Camera.main;
var mousePos = cam.ScreenToWorldPoint(Input.mousePosition);
// try to re-use the reference
if (!gunArm) gunArm = GameObject.Find("gunArm");
var difference = gunArm.transform.position - mousePos;
var gunAngle = Mathf.Atan2(difference.y, difference.x) * Mathf.Rad2Deg;
gunArm.rotation = Quaternion.Euler(0, 0, gunAngle);
}
private void testForClick()
{
if (Input.GetMouseButtonDown(0))
{
print("click");
// only set the flag
doForce = true;
}
}
}
The reason your code doesn't do anything is not because it doesn't work, but instead because transform.forward is a vector with magnitude 1. Adding a force of magnitude 1 will not do much to most objects, and friction will likely slow down the object again.
Try adding a force with a higher strength and ForceMode.Impulse instead:
float strength = 50f;
rb.AddForce(transform.forward * strength, ForceMode.Impulse);
Update:
It looks like you want the gun to face your mouse position and that's where your problem might be:
Let's try using Quaternion.LookRotation to get that working instead of doing to math manually.
Maybe:
GameObject gunArm;
void Awake()
{
gunArm = GameObject.Find("gunArm");
}
void faceMouse()
{
Vector3 difference = mousePos - gunArm.transform.position;
difference.z = 0;
gunArm.transform.rotation = Quaternion.LookRotation(difference);
}