Move object towards respective instantiated object - c#

On pressing the 'A' key i'm trying to spawn an asteroid within a set area away from the camera and also spawn a missile to take down this exact asteroid which spawns from under the camera. Ideally you should be able to press this key super fast and each time have a new asteroid and missile prefab spawn, which then are destroyed upon collision.
Issue: currently each missile goes towards the first object with the 'asteroid' tag assigned, rather than each missile firing at its respective asteroid. Also, when pressing super fast, some asteroids are missed completely and while the missiles are destroyed, these missed asteroids are not.
Here is my code, any help would be much appreciated!
Assigned to Missile prefab:
using System.Collections.Generic;
using UnityEngine;
public class launch : MonoBehaviour
{
// Use this for initialization
void Start()
{
}
// Update is called once per frame
public float speed;
void Update()
{
transform.position = Vector3.MoveTowards(transform.position, GameObject.FindGameObjectWithTag("Asteroid").transform.position, speed * Time.deltaTime);
}
void OnCollisionEnter(Collision collision)
{
if (collision.gameObject.tag == "Asteroid")
{
Destroy(collision.gameObject);
Destroy(this.gameObject);
}
}
}
Assigned to blank game object where asteroids spawn
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SpawnAsteroid : MonoBehaviour
{
public GameObject Asteroidprefab;
public GameObject Missileprefab;
public Vector3 center;
public Vector3 ship;
public Vector3 size;
// Use this for initialization
void Start()
{
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.A))
{
SpawnSpaceRock();
}
}
public void SpawnSpaceRock()
{
Vector3 pos = center + new Vector3(Random.Range(-size.x / 2, size.x / 2), Random.Range(-size.y / 2, size.y / 2), Random.Range(-size.z / 2, size.z / 2));
Instantiate(Asteroidprefab, pos, Quaternion.identity);
Instantiate(Missileprefab, ship, Quaternion.identity);
}
private void OnDrawGizmosSelected()
{
Gizmos.color = new Color(1, 0, 0, 0.5f);
Gizmos.DrawCube(center, size);
}
}

It is very bad to use any Find method in Update since it is quite expensive!
it also returns only the first found GameObject.
What you want instead is store a target reference in launch when you initialize it and use that one
launch
public class launch : MonoBehaviour
{
public GameObject Target;
public float speed;
void Update()
{
transform.position = Vector3.MoveTowards(transform.position, Target.transform.position, speed * Time.deltaTime);
}
void OnCollisionEnter(Collision collision)
{
// Only collide with your specific target
if (collision.gameObject != Target) return;
Destroy(Target);
Destroy(this.gameObject);
}
}
SpawnAsteroide
// Hint of you use the correct component type here
// you don't even have to use GetComponent later
public launch MissilePrefab;
public GameObject Asteroideprefab;
//...
public void SpawnSpaceRock()
{
Vector3 pos = center + new Vector3(Random.Range(-size.x / 2, size.x / 2), Random.Range(-size.y / 2, size.y / 2), Random.Range(-size.z / 2, size.z / 2));
// store reference of Instantiated GameObject
var asteroide = Instantiate(Asteroidprefab, pos, Quaternion.identity);
// Store reference of Instantiated launch componemt
var missile = Instantiate(Missileprefab, ship, Quaternion.identity);
// Now set the taregt
missile.Target = asteroid;
}
Alternatively - single Update
sometimes the performance is better if you don't have a lot of objects running individual Update methods but having only one central Update method controlling them all. In this case you could e.g. use a dictionary
in SpawnAsteroide
public float speed;
private Dictionary<launch, GameObject> MissileToAsteroid = new Dictionary<launch, GameObject>();
public void SpawnSpaceRock()
{
Vector3 pos = center + new Vector3(Random.Range(-size.x / 2, size.x / 2), Random.Range(-size.y / 2, size.y / 2), Random.Range(-size.z / 2, size.z / 2));
// store reference of Instantiated GameObject
var asteroide = Instantiate(Asteroidprefab, pos, Quaternion.identity);
// Store reference of Instantiated launch componemt
var missile = Instantiate(Missileprefab, ship, Quaternion.identity);
// Since launch is still responsible for different both objects
// you still need to pass the reference
missile.Target = asteroid;
// Add to dictionary
MissileToAsteroid [missile] = asteroid;
}
And than run it all in your central Update method
void Update()
{
if (Input.GetKeyDown(KeyCode.A))
{
SpawnSpaceRock();
}
// TODO: Maybe later remove null elements for better performance
// Run each move towards
foreach(var kvp in MissileToAsteroid)
{
var missile = kvp.key;
var asteroid = kvp.value;
if(missile)
{
missile.transform.MoveTowards(missile.transform.possition, asteroid.transform.position, speed * Time.deltaTime);
}
}
}
and than let launch only handle the destroying of both objects (so remove the Update there)

In missle objects save target stone and use lists of missles and stones. Foreach missle in missle array move in Update

Related

I am making a space shooter but my bullets keep on going up instead of out and not deleting from the Unity Hierarchy

I am trying to practice making a space shooter in order to build on concepts for my main project, and I am having issues because I have gotten where the bullets fire and follow with the ship but they fire up and never delete from the hierarchy in Unity.
Here is the code for the Controller:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour
{
private Transform myTransform;
public int playerSpeed = 5;
// Start is called before the first frame update
// Reusable Prefab
public GameObject BulletPrefab;
void Start()
{
myTransform = transform;
// Spawning Point
// Position x = -3, y = -3, z = -1
myTransform.position = new Vector3(-3, -3, -1);
}
// Update is called once per frame
void Update()
{
// Movement (left / right) and speed
myTransform.Translate(Vector3.right * playerSpeed * Input.GetAxis("Horizontal") * Time.deltaTime);
// Make the player wrap. If the player is at x = -10
// then it should appear at x = 10 etc.
// If it is positioned at 10, then it wraps to -10
if (myTransform.position.x > 10)
{
myTransform.position = new Vector3(-10, myTransform.position.y, myTransform.position.z);
}
else if (myTransform.position.x < -10)
{
myTransform.position = new Vector3(10, myTransform.position.y, myTransform.position.z);
}
// Space to fire!
// If the player presses space, the ship shoots.
if (Input.GetKeyDown(KeyCode.Space))
{
// Set position of the prefab
Vector3 position = new Vector3(myTransform.position.x, myTransform.position.y - 2, myTransform.position.z);
// Fire!
Instantiate(BulletPrefab, position, Quaternion.identity);
}
}
}
and here is the one for the Bullet prefab:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Bullet : MonoBehaviour
{
public int mySpeed = 50;
private Transform myTransform;
// Start is called before the first frame update
void Start()
{
myTransform = transform;
}
// Update is called once per frame
void Update()
{
// Shooting animation
myTransform.Translate(Vector3.up * mySpeed * Time.deltaTime);
if (myTransform.position.z > 20)
{
DestroyObject(gameObject);
}
}
}
Not sure what I am doing. The bullet has gravity unchecked & is kinematic checked.
Player is positioned at -3, -1, -3.
Why your object isn't being deleted is probably because you are checking its position along the z-axis when you are only moving it along the y-axis. The destroy never runs since your bullet's z position is static and always under 20:
// Shooting animation
myTransform.Translate(Vector3.up * mySpeed * Time.deltaTime);
if (myTransform.position.z > 20)
{
DestroyObject(gameObject);
}
Either you can change the if statement to check along the y-axis or move the bullet along the z-axis, which one you want I cant really say since I don't really understand which direction you want the bullet to travel in.
Also, I don't know if it would cause any problems but DestroyObject has been replaced by Destroy().

Move 3d models in Unity 3d

In unity 3d, I've create an Empty GameObject that Instanciates a simple 3d model when i click with the mouse ( 3d model imported from blender).
I've written a simple script that moves the EmptyGameObject using
transform.Translate(speed * Time.deltaTime, 0, 0);
But when i run the project, only the Empty Game Object moving but I need that the 3d model moving to x asix. How can i resolve this problem? Thanks for the help.
Moving script (putting on EmptyGameObject):
public float speed = 0f;
// Start is called before the first frame update
void Start()
{
speed = 0f;
}
// Update is called once per frame
void Update()
{
transform.Translate(speed * Time.deltaTime, 0, 0);
if (Input.GetMouseButtonDown(0)) {
speed += speed + 0.5f;
}
}
Script for instantiated objects:
public GameObject model;
public GameObject model1;
public int counter = 0;
void Start(){
model= Instantiate(model, transform.position, Quaternion.identity); //spawn model
}
void Update(){
if (Input.GetMouseButtonDown(0)) {
ChangeModel();
}
}
void ChangeModel(){
counter++;
switch (counter) {
case 1:
Destroy(model);
Destroy(model1);
model = (GameObject) Instantiate(model, transform.position, Quaternion.identity);
break;
case 2:
Destroy(model);
model1= (GameObject) Instantiate(model1, transform.position, Quaternion.identity);
counter =0;
break;
}
}
In general all you need to do is spawn the new objects always as children of this EmptyGameObject. Instantiate therefore has an overload taking an additional parent Transform reference to spawn the prefab as child to.
As I understand the second script is also attached to the EmptyGameObject so your target parent is simply transform (the Transform component of the GameObject this script is attached to):
//spawn model as child of given Transform
model = Instantiate(prefab, transform.position, Quaternion.identity, transform);
Also note that a cast to (GameObject) is redundant since Instantiate anyway returns the type of the given prefab.
However
I do not really understand your usage of model, model1 and Instantiate and Destroy here ...
What do you destroy the model for if you want to directly respawn it anyway?
In general I think you would be way better also performance wise spawning them both once and only activate and deactivate according models:
public GameObject prefab;
public GameObject prefab1;
void Start()
{
model = Instantiate(prefab, transform.position, Quaternion.identity, transform);
model1 = Instantiate(prefab1, transform.position, Quaternion.identity, transform);
model1.SetActive(false);
}
void ChangeModel()
{
counter = (counter + 1) % 2;
model.SetActive(counter == 0);
model1.SetActive(counter == 1);
}
That's it. If you simply already place the two prefabs into the EmptyGameObject right from the beginning you don't need the Instantiate at all ...
And btw in case you only have two states anyway instead of a counter you could also use a simple bool here:
bool isModel1;
private void ChangeModel()
{
isModel1 = !isModel1;
model.SetActive(!isModel1);
model1.SetActive(isModel1);
}
And finally note that from your movement script:
speed += speed + 0.5f;
this results in
speed = speed + speed + 0.5f;
but I guess what you rather want is
speed += 0.5f;
which results in
speed = speed + 0.5f;

Unity Moving Platform script stops working?

I have a script that should move a platform between 2 positions.
The platform moves to pos1 but then just stops....
Here is my code :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Platform : MonoBehaviour
{
public Transform pos1, pos2;
public float speed;
public Transform startPos;
Vector3 nextPos;
// Start is called before the first frame update
void Start()
{
nextPos = pos1.position;
}
// Update is called once per frame
void Update()
{
if (transform.position == pos1.position)
{
nextPos = pos2.position;
}
if (transform.position == pos2.position)
{
nextPos = pos1.position;
}
transform.position = Vector3.MoveTowards(transform.position, nextPos, speed * Time.deltaTime);
}
private void OnDrawGizmos()
{
Gizmos.DrawLine(pos1.position, pos2.position);
}
}
You're setting it sequentially, so it's always going to be the second option.
In one case if nextpos is in position 1, it'll be set to position 2, but is then immediately changed again as
if nextpos is in position 2, it'll be set back to 1.
easy change should be just to change the second if statement to an else if
paraphrasing the code, but hopefully it makes sense

Let script modify transform position even if the gameobject is disabled

I am trying to use Main Camera position to make an appear and disappear. For example, if the camera.main.transform.position = (0,2,0); make the object appear otherwise make it disappear.
The object in this case a basic Cube. I started using setActive function but as it turns out once you have setActive as false, Update function on the specific object does not run. I have added the script I was using:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class backandforth : MonoBehaviour
{
public float speed = 2.5f;
GameObject targetObject;
// Use this for initialization
void Start()
{
targetObject = GameObject.Find("Cube");
targetObject.SetActive(false);
}
// Update is called once per frame
void Update()
{
//move the cube from (0,0,0)
if (Camera.main.transform.position== new Vector3(0, 2, 0)) {
transform.position = new Vector3(Mathf.PingPong(Time.time * speed, 5), transform.position.y, transform.position.z);
transform.Rotate(0, 0, 5);
}
else
{
targetObject.SetActive(true);
transform.position = new Vector3(Mathf.PingPong(Time.time * speed, 5), transform.position.y, transform.position.z);
transform.Rotate(0, 0, 100);
//gameObject.SetActive(false);
}
}
}
Here is the hierarchy view of the setup to make the GameObject definition clear.
Any suggestion on how do I go about doing this? Thanks!
If I understand correctly the update method should be like this:
void Update()
{
if (Camera.main.transform.position== new Vector3(0, 2, 0)) {
//if the camera.main.transform.position = (0,2,0); make the object appear
targetObject.SetActive(true);
}
else
{
//otherwise make it disappear
targetObject.SetActive(false);
}
}

How to add parallax to objects instantiated in play mode and recreated with camera position in Unity 3d

So my endless 2d game has 2 layers of mountains in the background which I want to add parallax on, the Near layer needs to be slower than actor/camera, & the Far to be slowest. The problem is, I can't directly add script of movement to them as they are instantiated in play mode randomly according to the random theme colors, so they are being created one after other from the script below, but I want to add a movement on them on x axis slower than camera speed, while also letting it recreate continuously at the end of last one.
Here's the script creating new mountains :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PathManager : MonoBehaviour {
public static PathManager Instance;
public GameObject CoinFragments;
public GameObject SlideArrow;
public float parallaxSpeed = 5f; //
private GameObject lastPathObject;
private float PathXPosition;
private GameObject lastMountainFar;
private float MountainFarXPosition;
private GameObject lastMountainNear;
private float MountainNearXPosition;
private float StarXPostion;
private float lastCameraX; //
// Use this for initialization
void Start () {
Instance = this;
}
// Update is called once per frame
void Update()
{
}
private void LateUpdate()
{
// Check for new Near Mountain
if (lastMountainNear != null && GamePlayCameraManager.Instance.MainCamera.transform.position.x > lastMountainNear.transform.position.x)
{
this.GenerateNearMountain();
}
// Check for new Far Mountain
if (lastMountainFar != null && GamePlayCameraManager.Instance.MainCamera.transform.position.x > lastMountainFar.transform.position.x)
{
this.GenerateFarMountain();
}
}
// Start Creating Mountains
public void StartMountainCreation(){
MountainNearXPosition = GamePlayCameraManager.Instance.MainCamera.transform.position.x;
MountainFarXPosition = GamePlayCameraManager.Instance.MainCamera.transform.position.x;
this.GenerateNearMountain();
this.GenerateFarMountain();
}
private void GenerateNearMountain(){
Vector3 MountainPosition = new Vector3(MountainNearXPosition - 4f, -3.6f, 10f);
lastMountainNear = Instantiate(ThemeManager.Instance.SelectedMountainNear, MountainPosition, Quaternion.identity);
MountainNearXPosition = MountainNearXPosition + lastMountainNear.GetComponent<Renderer>().bounds.size.x - 0.01f;
//float deltaX = GamePlayCameraManager.Instance.MainCamera.transform.position.x - lastCameraX;
//lastCameraX = GamePlayCameraManager.Instance.MainCamera.transform.position.x;
//lastMountainNear.transform.position += Vector3.right * (deltaX * parallaxSpeed);
}
private void GenerateFarMountain(){
Vector3 MountainPosition = new Vector3(MountainFarXPosition - 4f, -3.6f, 22f);
lastMountainFar = Instantiate(ThemeManager.Instance.SelectedMountainFar, MountainPosition, Quaternion.identity);
MountainFarXPosition = MountainFarXPosition + lastMountainFar.GetComponent<Renderer>().bounds.size.x - 0.01f;
}
Here's my camera movement script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GamePlayCameraManager : MonoBehaviour {
public static GamePlayCameraManager Instance; // Singleton Instance
public Camera MainCamera; // Main Camera
private Vector3 offset;
// Use this for initialization
void Start () {
Instance = this;
MainCamera.transform.position = new Vector3(0, 0, -10);
}
// Update is called once per frame
void Update () {
}
void LateUpdate()
{
if (GameStateManager.GameState == GameState.Set || GameStateManager.GameState == GameState.Playing)
MainCamera.transform.position = new Vector3(this.offset.x + ActorManager.Instance.Actor.transform.position.x + 0.8f, 0, -10);
}
// Fixed Update Method
void FixedUpdate(){
}
public void FindCameraOffset(){
this.offset = ActorManager.Instance.Actor.transform.position - MainCamera.transform.position + new Vector3(1.5f, 0f, 0f);
}
}
First, you should look into pooling your mountain objects so you don't waste cpu and memory endlessly creating them.
Once you have them pooled in your PathManager, you'll need to first know how far the camera moved in the last frame, and then tell the mountains to move according to that. You are going to have to have a reference to your PathManager in your camera Manager.
In your Camera Manager's LateUpdate:
if (GameStateManager.GameState == GameState.Set || GameStateManager.GameState == GameState.Playing) {
Vector3 newPosition = new Vector3(this.offset.x + ActorManager.Instance.Actor.transform.position.x + 0.8f, 0, -10);
float cameraMoveAmount = newPosition.x - MainCamera.transform.position.x;
MainCamera.transform.position = newPosition;
pathManager.MoveMountains(cameraMoveAmount)
}
Then, in your PathManager, use that moveAmount to change the positions of all of the mountains, as well as where the next one will be created. After this point is where you should check for any need to show new mountains, not in the PathManager's LateUpdate. This is because you need to move the mountains before you check to add new ones, and there is no guarantee which happens first if you have them in different LateUpdate calls.
Something like this:
// How fast the mountain layers are going to move in the direction of the camera.
// 0.0f - will not move with the camera, mountains will slide out of frame at normal speed.
// 1.0f - will move with the camera, no movement will be visible in frame.
public float nearMountainMoveSpeed = 0.5;
public float farMountainMoveSpeed = 0.9f;
. . .
public void MoveMountains(float cameraMoveAmount) {
float nearMountainParallaxMove = nearMountainMoveSpeed * cameraMoveAmount;
float farMountainParallaxMove = farMountainMoveSpeed * cameraMoveAmount;
// Move the near mountains & their next placement
MountainNearXPosition += nearMountainParallaxMove;
foreach (GameObject nearMountain in pooledNearMountains) {
nearMountain.transform.position = nearMountain.transform.position + new Vector3(nearMountainParallaxMove,0f,0f);
}
// Check for new Near Mountain
if (lastMountainNear != null && GamePlayCameraManager.Instance.MainCamera.transform.position.x > lastMountainNear.transform.position.x) {
this.GenerateNearMountain();
}
// Move the far mountains & their next placement
MountainFarXPosition += farMountainParallaxMove;
foreach (GameObject farMountain in pooledFarMountains) {
farMountain.transform.position = farMountain.transform.position + new Vector3(farMountainParallaxMove,0f,0f);
}
// Check for new Far Mountain
if (lastMountainFar != null && GamePlayCameraManager.Instance.MainCamera.transform.position.x > lastMountainFar.transform.position.x) {
this.GenerateFarMountain();
}
}
And as an aside, If you end up changing your code and having a single gameobject with all of the farMountains as children and one with all of the nearMountains as children, then you can just move the transform of those parent gameobjects instead of looping through each individual mountain. The amount you would need to move it is the same, of course.

Categories