How to add a spawner on a side of moving camera in unity2D - unity3d

I'm creating a 2D racing game in Unity2D and unsure how to approach on coding my spawner for objects e.g. power-up, rewards and obstacles ahead on the right side of my moving camera. The camera follows my vehicle and moves from left to right. Currently objects spawn in the game, but only spawn on a point and continue to spawn in the same point when the camera has scrolled way past. Apologies, if the answer was simple.
Here are the scripts I used:
coin.cs is attached to my coin prefab
public class coin : MonoBehaviour
{
public Camera mainCamera;
Rigidbody2D rb;
// Start is called before the first frame update
void Start()
{
mainCamera = GameObject.FindObjectOfType<Camera>();
rb = this.gameObject.GetComponent<Rigidbody2D>();
transform.position = new Vector2(mainCamera.pixelWidth / 32, getRandomHeight());
}
float getRandomHeight(){
return Random.Range(-(mainCamera.pixelHeight / 2) / 100, (mainCamera.pixelHeight / 2) / 100);
}
private void OnTriggerEnter(Collider coll){
if (coll.gameObject.tag == "Player"){
Destroy(this.gameObject);
}
}
// Update is called once per frame
void Update()
{}
}
and coinSpawner.cs is attached to a gameObject in the scene
public class coinSpawner : MonoBehaviour
{
float LastSpawnTime = -500f;
float NextSpawnTime = 3;
public Object CoinPrefab; // declare coinPrefab
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
if (Time.time - LastSpawnTime > NextSpawnTime)
{
NextSpawnTime = Random.Range(3, 10);
LastSpawnTime = Time.time;
Instantiate(CoinPrefab);
}
}

Instantiate(CoinPrefab);
spawns this object without any information of position or parent object. This it will always be spawned at Scene root and 0,0,0.
Then this line
transform.position = new Vector2(mainCamera.pixelWidth / 32, getRandomHeight());
in coin always places it to the absolute position depending on your pixelWidth which doesn't change over time.
You are saying the Camera is moving so you should rather take it's transform.position into account.
You have basically two(three) ways to go here:
You can make the spawner GameObject a child of your Camera - so it is automatically moved along with it - and move it to the right to have the desired offset. Then simply spawn new objects at this GameObjects position. Then you can do it in coinSpawner:
Instantiate(CoinPrefab, transform.position, Quaternion.Identity);
Or get the Camera reference and use it's position + the desired offset either also only in coinSpawner like
// reference this already via the Inspector if possible
[SerializeField] Camera _camera;
// Otherwise get the reference on runtime
void Awake()
{
if(!_camera)_camera = Camera.main;
}
float getRandomHeight => Random.Range(-(_camera.pixelHeight / 2) / 100, (_camera.pixelHeight / 2) / 100;
and then do something like
Instantiate(CoinPrefab, new Vector2(_camera.transform.position.x + mainCamera.pixelWidth / 32, getRandomHeight()), Quaternion.Identity);
This would actually be more efficient since the entire coin script would be reduced to only the OnTriggerEnter part and not every coin would use FindObjectOfType and GetComponent when spawned.
Basically the same as above but sticking to your code structure simply do
transform.position = new Vector2(mainCamera.transform.position.x + mainCamera.pixelWidth / 32, getRandomHeight());
I wouldn't do it this way though due to efficiency as said.

Related

How Do I Destroy Finished Walking Particle (Clones) in UNITY?

VIDEO < in the video I have a walking particles that appear when ever my player moves left and right but I want them to be destroyed after the particles are finished fading away I tried using stop action in unity but that only destroyes the finish particles when the player stops moving and after that the particles will
stop showing up
these are my dublicated particles that will stay in my game forever and cause lag later on I need a way to stop showing them when they are done
IMAGE < the inspector of my particles
image < the name of my particles
is there a way I could some how in my code check if the particle is faded away or check if its finished and then destroy those because sometimes with the destroy it will destroy everything and the particles wont show up if I walk again
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class partscript2 : MonoBehaviour
{
public Joystick joystick2;
public GameObject hays2;
public Rigidbody2D rb;
float horizontalMove = 0f;
// public bool show = true;
public Animator animator3;
// public Transform player;
//public Transform particleposition;
// Start is called before the first frame update
void Start()
{
//transform.position = particleposition.position;
animator3 = GetComponent<Animator>();
//Destroy(gameObject, 1f);
}
//destroy(hays);
// Update is called once per frame
void Update()
{
if (joystick2.Horizontal <= -.2f)
{
Instantiate(hays2, transform.position, hays2.transform.rotation);
}
if (joystick2.Horizontal >= .2f)
{
Instantiate(hays2, transform.position, hays2.transform.rotation);
}
}
}
Firstly, instantiating a game object in update is not the best way to go considering that if your game runs at 60 frames per second you will end up creating 60 game objects each second which can and most likely will affect performance especially on a mobile device which you are working.
But into the point, you can call the Destroy method and pass the duration of the particle.
GameObject hay = Instantiate(hays2, transform.position, hays2.transform.rotation);
ParticleSystem p = hay.GetComponent<ParticleSystem>();
float duration = p.duration + p.startLifetime;
Destroy(hay , duration);
If your particle's duration is fixed you can always skip the part where we get the duration via script and simply pass it in the Destroy method.
GameObject hay = Instantiate(hays2, transform.position, hays2.transform.rotation);
Destroy(hay , 5f);

How to create a projectile Script in Unity

so recently my friends and I are trying to make a game for fun. Currently, I hit a wall and not sure how to do this. I am trying to create a simple base script where I have the character move and attack with right click. If it hits the ground, it will move there and and if in range of a target, it will send a projectile. So the game is creating the projectile but its not actually moving. Can anyone tell me what I should probably do. At first, I thought to just make it all one script but now I am thinking it be best to make another script for the projectile.
void Update()
{
if (Input.GetMouseButtonDown(1))
{
RaycastHit hit;
if(Physics.Raycast (Camera.main.ScreenPointToRay(Input.mousePosition), out hit) && hit.transform.tag == "Minion")
{
if(Vector3.Distance(this.transform.position, hit.point) <= atkRange)
{
GameObject proj = Instantiate(bullet) as GameObject;
proj.transform.position = Vector3.MoveTowards(this.transform.position, target, atkSpd);
}
}
else if (Physics.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition), out hit, speed))
{
agent.destination = hit.point;
}
}
}
So this is what I originally had. I am pretty sure I did something wrong here. Also I am not sure if I should have another script for the projectile itself or if it is not necessary. Thank you for any help or tips on what to do.
For starters, I'd advize using a Rigidbody component and letting physics handle movement but if you'd like to use Vector3.MoveTowards, it'll be a bit of work:
Vector3.MoveTowards is something that needs to be called every frame. I'm guessing bullet is your prefab so you'll want to make a new script for the movement and place it on that prefab:
public class MoveToTarget : MonoBehaviour
{
private float _speed;
private Vector3 _target;
public void StartMovingTowards(Vector3 target, float speed)
{
_target = target;
_speed = speed;
}
public void FixedUpdate()
{
// Speed will be 0 before StartMovingTowards is called so this will do nothing
transform.position = Vector3.MoveTowards(transform.postion, _target, _speed);
}
}
After you've attached this to your prefab, make sure you grab a reference and get it started when you instantiate a copy of your prefab:
GameObject proj = Instantiate(bullet) as GameObject;
var movement = proj.GetComponent<MoveToTarget>();
movement.StartMovingTowards(target, atkSpd);
If you instead go the physics route, add a Rigidbody component to your bullet prefab, and get a reference to that instead of making the MoveToTarget script:
GameObject proj = Instantiate(bullet) as GameObject;
var body = proj.GetComponent<Rigidbody>();
Then you can just apply a force and let physics take over:
body.AddForce(target - transform.position, ForceMode.Impulse);
Don't set the position like you currently are
proj.transform.position = Vector3.MoveTowards(this.transform.position, target, atkSpd);
Instead, add either a characterController or a rigidbody and use rb.addVelocity.

How to shoot particle like projectile?

I made a tank that shoot sphere balls on mouse click.
my C# script:
GameObject prefab;
// Use this for initialization
void Start () {
prefab = Resources.Load("projectile") as GameObject;
}
// Update is called once per frame
void Update() {
if (Input.GetMouseButtonDown(0))
{
GameObject projectile = Instantiate(prefab) as GameObject;
projectile.transform.position = transform.position + Camera.main.transform.forward * 2;
Rigidbody rb = projectile.GetComponent<Rigidbody>();
rb.velocity = Camera.main.transform.forward * 40;
}
}
in this script im shooting a mesh named projectile. But I want to shoot a particle ball and not a mesh. I already tried to change the particle to Orbparticle on script but no object was spawned. What im doing wrong?
No object was spawned because you probably don't have a resource called Orbparticle. Check if you have any errors when you run your script. If Resources.Load doesn't find the object you want by the path you gave it, it will give null, which probably why no object is being spawned.
If you want to shoot a particle instead of a mesh then what you need to do is set prefab to a GameObject you prepared ahead of time that has the ParticleSystem you want. I'd suggest against using Resources.Load for this.
1. Using Resources.Load.
Change your code to this so that it will alert you if it doesn't find the resource:
GameObject prefab;
// Use this for initialization
void Start () {
string name = "OrbParticle";
prefab = Resources.Load<GameObject>(name);
if (prefab == null) {
Debug.Error("Resource with name " + name + " could not be found!");
}
}
// Update is called once per frame
void Update() {
if (Input.GetMouseButtonDown(0))
{
GameObject projectile = Instantiate(prefab) as GameObject;
projectile.transform.position = transform.position + Camera.main.transform.forward * 2;
Rigidbody rb = projectile.GetComponent<Rigidbody>();
rb.velocity = Camera.main.transform.forward * 40;
}
}
Now in order for this to work you need a prefab called "OrbParticle" or whatever string you set the variable name to. Resources.Load looks for items in paths such as Assets/Resources. So you MUST have your "OrbParticle" prefab located in that Resources folder. Unless you have a specific reason for using Resources.Load, I strongly suggest you go with solution 2.
2. Ditching Resources.Load and using the Prefab directly.
Change your code to this:
public GameObject prefab;
// Update is called once per frame
void Update() {
if (Input.GetMouseButtonDown(0))
{
GameObject projectile = Instantiate(prefab) as GameObject;
projectile.transform.position = transform.position + Camera.main.transform.forward * 2;
Rigidbody rb = projectile.GetComponent<Rigidbody>();
rb.velocity = Camera.main.transform.forward * 40;
}
}
Then do this:
Create a new empty GameObject.
Attach a ParticleSystem to the GameObject.
Make a new prefab asset.
Drag and drop the newly created GameObject into a Prefab asset.
Drag and drop the the prefab into prefab field in your Monobehaviour (the object doing the shooting. It will have a prefab field in the Inspector. That's why we set prefab to be a public field).
If you continue having problems, look in Unity's Hierarchy to see if no object is being created at all. It might be the case that it is instantiating a GameObject but the GameObject is invisible for some reason or not instantiating in the location you expect.

How do I make my Unity3d camera rotate around his following object?

I'm making a game but I do not now how to let my camera rotate with the object he's following. (I did the follow part) Can somebody help me please. I'm using C#.
Please, can you describe what you actually want to do? What does "let my camera rotate with the object" mean?
If you want your camera to exactly follow the gameobject's rotation in a first person camera, you could achieve this by putting your camera as the gameobject's child.
You could also do this using the following code:
[SerializeField]
private Transform obj; //reference the gameobject's transform
void Update()
{
transform.rotation = obj.rotation;
}
You should use the transform.RotateAround to move the camera. This should be done inside the update method in your camera.
For example:
var target:transform;
function Update(){
//...
transform.RotateAround (target.position, Vector3.up, speed * Time.deltaTime);
}
For more information on the rotation method, see the docs.
If you want simple 3rd person camera, you can place camera as a child of your target object - the camera will "stick to it.
If you want to do this in code (for some reasons), something like this should work (attach script to GameObject with Camera component):
using UnityEngine;
public class CameraFollow : MonoBehaviour
{
public Transform target; // Object to fallow. Select in Inspector
public Vector3 offset = new Vector3(0, 0, -10); // Offset to target
private GameObject container; // Container for our camera
void Start()
{
container = new GameObject("Camera Container"); // Create container (empty GameObject) for camera to avoid unnecessary calculations. It will follow the target object
transform.parent = container.transform; // Make this object child of container
}
//Update your camera follow script in LateUpade(), to be sure that 'target' movement is done
void LateUpdate()
{
//Check if target is selected
if (target == null)
return;
container.transform.position = target.position; // Set container position same as target
container.transform.rotation = target.rotation; // Set container rotation same as target
transform.localPosition = offset; // Move camera by offset inside the container
transform.LookAt(target); // Optionaly, force camera look at target object on any offset
}
}

Unity ball with constant speed

I'm making 2D mobile game and I have a ball, but my ball doesn't have a constant moving speed. What I need to do?
When I build game on my android device, ball have a various speed. In that case, my game is not playable.
I hope that someone can help me. Thanks.
This is on my start function:
void Start () {
GetComponent<Rigidbody2D> ()
.AddForce (new Vector2 (1f, 0.5f)* Time.deltaTime * force);
}
Is it a good practice if I used in code " Application.LoadLevel ("__Scena_0"); " to load existing scene when I lose " life" ? Problem happens when I lost " life " and try playing game in second chance.
My update function is about OnTriggerEnter2D when my ball hit trigger objects.
EDIT 23.12.2015. : problem solve with adding physics material (fiction 0) and adding to script:
using UnityEngine.SceneManagement;
...
SceneManager.LoadScene ("MainScene");
The problem is the calculation of the force vector:
new Vector2 (1f, 0.5f) * Time.deltaTime * force
You are using Time.deltaTime as a factor, which means that the applied force is not constant, but depending on the deltaTime, which is the duration of the last frame. This explains why it changes randomly.
I don't think Time.deltaTime is what you want here, try just removing the factor and adjusting the "force" factor accordingly. You should now have a constant force applied, independent from the platform you play on.
Create a new Physics Material, set friction zero and add it to your object. If your object has no friction, its speed cannot be decreased. Then, use AddForce() on Rigidbody2D to speed up.
Assuming that your ball and colliding walls have bouncy materials with no friction. Try
public float _ballSpeed = 2.5f;
Rigidbody2D _rb;
void Start()
{
_rb = GetComponent<Rigidbody2D>();
_rb.velocity = Vector2.one * _ballSpeed;
}
void Update()
{
}
From this you can control ball speed through _ballSpeed
//========== OR ==========//
If you want to retain speed even after ball destruction.
Retain _ballSpeed in any global static variable.
Suppose you have a class named Globals, declare a variable like,
public class Globals
{
public static float BALL_SPEED = 2.5f;
}
Now in Ball Script
Rigidbody2D _rb;
void Start()
{
_rb = GetComponent<Rigidbody2D>();
_rb.velocity = Vector2.one * Globals.BALL_SPEED;
}
void Update()
{
}