I am trying to do a multiplayer game and I have a problem with spawning prefabs. I want this prefabs to be spawn in 2 fix position but I don't understand why my script doesn't work because when I start the game the objects are spawn in one position. I created an empty game object( I named it Spawner and added the script) and added 2 game objects ( Position1 , Position2 ) as Childs. The prefab is spawn in the position of the Spawner and not position 1 and 2 .
Here is the script I used. Also do I have to add to it PhotonView and Photon Transform ? and something with PunRPC?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SpawnPosition : MonoBehaviour
{
public GameObject[] powersPrefab;
public Transform[] points;
public float beat= (60/130)*2;
private float timer;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
if (timer > beat)
{
GameObject powers = Instantiate(powersPrefab[Random.Range(0, 2)]);
powers.transform.localPosition = Vector2.zero;
timer -= beat;
}
timer += Time.deltaTime;
}
}
You always set
powers.transform.localPosition = Vector2.zero
The object is instantiated on root level without a parent this equals setting its absolute position .... you always set it to the Unity origin.
You probably wanted to spawn it at the position of on of the elements in points like e.g.:
var powers = Instantiate(
powersPrefab[Random.Range(0, powersPrefab.Length)],
points[Random.Range(0, points.Length)].position,
Quaternion.identity
);
see Instantiate for available overloads.
However as you also state this is for multiplayer so you shouldn't use Instantiate at all since this only spawns this object on this client but not on others. You should probably rather make sure that this spawner is only running on one of your clients and use PhotonNetwork.Instantiate instead.
Something like e.g.
public class SpawnPosition : MonoBehaviour
{
public GameObject[] powersPrefab;
public Transform[] points;
public float beat= (60/130)*2;
private float timer;
// Update is called once per frame
void Update()
{
// only run this if you are the master client
if(!PhotonNetwork.isMasterClient) return;
if (timer > beat)
{
// spawn the prefab object over network
// Note: This requires you to also reference the prefabs in Photon as spawnable object
Instantiate(
powersPrefab[Random.Range(0, 2)].name,
points[Random.Range(0, points.Length)].position,
Quaternion.identity,
0
);
timer -= beat;
}
timer += Time.deltaTime;
}
}
This should work
void Update() {
if (timer > beat) {
GameObject powers = Instantiate(powersPrefab[Random.Range(0, 2)]);
powers.transform.localPosition = points[Random.Range(0, points.Length)].position;
timer -= beat;
}
timer += Time.deltaTime;
}
}
You are not assigning right position, and since they are parentless power.transform.position = Vector2.zero means that power's global position would always 0,0,0. So you must assign it as I wrote above, and it's also randomized.
Related
Hello I'am trying to make a system that instantiate and object, and the moves it to a set of waypoints. When i use intantiate in the Start() function it travels like intended through the waypoints, but when i add the instantiate line to my update() function it only travels a little while and then stops, the same goes for the rest of the instantiated objects. It has something to do with timer i guess, but i have tried a few approaches, but they all lead to the same thing. Hope someone can help.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class waypointTest : MonoBehaviour
{
[SerializeField] private Transform[] waypoints;
public GameObject waypointInvader;
GameObject go;
private int nextUpdate = 1;
public float speed = 5f;
private int waypointIndex;
void Start()
{
}
void Update()
{
if (Time.time >= nextUpdate)
{
nextUpdate = Mathf.FloorToInt(Time.time) + 1;
go = Instantiate(waypointInvader, transform.position, transform.rotation) as GameObject;
}
if (go.transform.position != waypoints[waypointIndex].transform.position)
{
Vector3 newPos = Vector3.MoveTowards(go.transform.position, waypoints[waypointIndex].transform.position, speed * Time.deltaTime);
go.transform.position = newPos;
if (newPos == waypoints[waypointIndex].transform.position)
{
waypointIndex += 1;
}
if (waypointIndex == waypoints.Length)
{
waypointIndex = 0;
}
}
}
}
The problem is that you are loosing the reference to the object you want to move.
If instantiate is inside Start():
go is set to be the instantiated object
go is moved to every waypoint
go is moved to the very first waypoint
go is moving through the waypoints again
If instantiate is inside Update():
go is set to be the first instantiated object
go is moved to a few waypoints until Time.time >= nextUpdate returns true
go is set to be the second instantiated object and will loose its reference to the first go
The first go stops moving
The second go starts moving
Repeat
One way to solve this problem is to give the moving object go its own movement script. That way you just have to instantiate go and it will handle its movement by itself. If go does not know where the waypoints are you can give it to it after instantiating (For example waypointInvader is a prefab). E.g.:
if (Time.time >= nextUpdate)
{
nextUpdate = Mathf.FloorToInt(Time.time) + 1;
go = Instantiate(waypointInvader, transform.position, transform.rotation) as GameObject;
go.GetComponent<GoMovement>().ListOfWaypoints = waypoints;
}
I'm creating a game where objects are being created. These objects are moving left and the player has to press space bar before the object reaches the end of the screen. Every thing works fine with the exception of spawning a prefab on the moving objects.
The idea is to spawn a animation on the nearest target. But when instantiated, the prefab always instantiate at the prefab location (0,0,0). How do I make the instantiated prefab spawn at the correct place? (I've tested with print(nearestTarget.transform.position) and the print always gives me a different location depending on the "nearestTarget")
Trying to spawn the prefab in HandSlapAnimation() Method.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerInput : MonoBehaviour
{
// Reference to levelManager
[SerializeField] LevelManager levelManager;
// Array of all present entities
private GameObject[] targets;
// Nearest entity
private GameObject nearestTarget;
// Array of all x position of all present entities
private float[] locationOfTargets;
// Nearest x position (transform.position.x) in all entities
private float nearestLocation;
// Finds the index location of the float value
private int index;
// Hand prefab to be instantiate during Keypress
public GameObject handPrefab;
void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
targets = GameObject.FindGameObjectsWithTag("Entities");
if (targets.Length > 0)
{
FindLocationOfEntities();
AssignNearestTarget();
HandSlapAnimation();
DestroyNearestTarget();
}
}
}
void FindLocationOfEntities()
{
locationOfTargets = new float[targets.Length];
for (int i = 0; i < targets.Length; i++)
{
locationOfTargets[i] = targets[i].transform.position.x;
}
}
void AssignNearestTarget()
{
nearestLocation = Mathf.Min(locationOfTargets);
index = System.Array.IndexOf(locationOfTargets, nearestLocation);
nearestTarget = targets[index];
}
void DestroyNearestTarget()
{
if (nearestTarget.GetComponent<CubeMovement>().isCat == true)
{
levelManager.LoadLevel("Game Over");
}
else
{
Destroy(nearestTarget);
}
}
void HandSlapAnimation()
{
// Instantiate prefab Hand GameObject at the nearest target to execute the Hand Slap animation
Instantiate(handPrefab, transform.position, Quaternion.identity);
handPrefab.transform.SetParent(nearestTarget.transform);
print(nearestTarget.transform.position);
}
}
The problem is that in:
Instantiate(handPrefab, transform.position, Quaternion.identity);
The transform.positionis the position of the actual object, your PlayerInput instance.
Then, you do: handPrefab.transform.SetParent(nearestTarget.transform) but that doesn't move the position, only sets the parent.
Instead of using transform.position in the Instantiate method, use nearestTarget.transform.position.
Instantiate(handPrefab, nearestTarget.transform.position, Quaternion.identity);
I would like to calculate a new position based on the pitch of a mesh in order to make an object following the top of my object which is rotated:
And result in:
I cannot make the square object as represented above as a child (in the Unity object hierarchy) of the line object because the rotated object can see its scale changed at anytime.
Does a mathematics solution can be used in this case?
Hotspots
If you'd like to place something at a particular location on a generic object which can be scaled or transformed anywhere, then a "hotspot" can be particularly useful.
What's a hotspot?
Edit the target gameobject (the line in this case) and add an empty gameobject to it. Give it some appropriate name - "cross arms hotspot" for example, and then move it to the location where you'd like your other gameobject to target. Essentially, a hotspot is just an empty gameobject - a placement marker of sorts.
How do I use it?
All you need is a reference to the hotspot gameobject. You could do this by adding a little script to the pole gameobject which tracks it for you:
public class PowerPole : MonoBehaviour {
public GameObject CrossArmsHotspot; // Set this in the inspector
}
Then you can get that hotspot reference from any power pole instance like this:
var targetHotspot = aPowerPoleGameObject.GetComponent<PowerPole>().CrossArmsHotspot;
Then it's just a case of getting your target object to place itself where that hotspot is, using whichever technique you prefer. If you want it to just "stick" there, then:
void Start(){
targetHotspot = aPowerPoleGameObject.GetComponent<PowerPole>().CrossArmsHotspot;
}
void Update(){
transform.position = targetHotspot.transform.position;
}
would be a (simplfied) example.
A more advanced example using lerp to move towards the hotspot:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CrossArmsMover : MonoBehaviour
{
public GameObject PowerPole;
private GameObject targetHotspot;
public GameObject CrossArms;
public float TimeToTake = 5f;
private float timeSoFar;
private Vector3 startPosition;
private Quaternion startRotation;
// Start is called before the first frame update
void Start()
{
startPosition = CrossArms.transform.position;
startRotation = CrossArms.transform.rotation;
targetHotspot = PowerPole.GetComponent<PowerPole>().CrossArmsHotspot;
}
// Update is called once per frame
void Update()
{
timeSoFar+=Time.deltaTime;
var progress = timeSoFar/TimeToTake;
// Clamp it so it doesn't go above 1.
if(progress > 1f){
progress = 1f;
}
// Target position / rotation is..
var targetPosition = targetHotspot.transform.position;
var targetRotation = targetHotspot.transform.rotation;
// Lerp towards that target transform:
CrossArms.transform.position = Vector3.Lerp(startPosition, targetPosition, progress);
CrossArms.transform.rotation = Quaternion.Lerp(startRotation, targetRotation, progress);
}
}
You would need to put a script on the following gameobject in wich you would put :
GameObject pitcher = //reference to the gameobject with the pitch;
const int DISTANCE_ON_LINE = //distance between the 2 objects
void Update() {
transform.position = pitcher.transform.position + pitcher.transform.forward * DISTANCE_ON_LINE;
}
I'm trying to animate / transform a gameObject movingObject from it's spawn position to the destination. I believe the issue is somewhere in the implementation of the IncrementPosition function.
Rather than moving the one cube from A to B. The script spawns multiple cubes until it gets to B. Can you see where I'm going wrong?
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class onClickSpawnMove : MonoBehaviour
{
public float speed;
public GameObject randomSpawn;
private GameObject movingObject;
private Vector3 destination;
void Start()
{
Spawn();
}
void Update()
{
SetDestination(movingObject.transform.position);
if (destination != movingObject.transform.position) {
IncrementPosition();
}
}
void IncrementPosition()
{
float delta = speed * Time.deltaTime;
Vector3 currentPosition = movingObject.transform.position;
Vector3 nextPosition = Vector3.MoveTowards(currentPosition, destination, delta);
movingObject.transform.position = nextPosition;
}
void Spawn() {
Vector3 spawnPosition = new Vector3(10, 0, 0);
movingObject = Instantiate(randomSpawn, spawnPosition, Quaternion.identity);
}
public void SetDestination(Vector3 value)
{
destination = new Vector3(20, 0, 0);
}
}
There are several ways to call the Spawn / Start method casually:
gameObject.AddComponent<onClickSpawnMove>(); the Start method will be invoked again.
Instantiate a prefab that onClickSpawnMove script is attached already.
gameObject.SendMessage("Start"); maybe, but rarely seen.
You can add a log or break point to check when the Spawn / Start method is called.
Print the hash code will help you know the different onClickSpawnMove instances.
And you can click the message in the console to know which GameObject is.
void Start()
{
Spawn();
Debug.Log("Start " + this.GetHashCode(), this);
}
I have this code here ,i am trying to move an object from one position to another ,on mouse click ,but everytime i run it it justs instantiate the projectile object in a specific position while it had to instantiate it in a the ffor object position
using UnityEngine;
using System.Collections;
public class Shoot : MonoBehaviour
{
public GameObject projectile;
public GameObject foot;
public GameObject mouse;
void Start()
{
}
void Update()
{
if (Input.GetMouseButtonDown(0))
{
Vector2 Target = Input.mousePosition;
Vector2 pos1 = Camera.main.ScreenToWorldPoint(Target);
GameObject newObj = (GameObject)GameObject.Instantiate(projectile);
Vector2 pos2 = foot.transform.position;
transform.position=Vector2.Lerp(pos2,pos1,Time.deltaTime);
}
}
There are several issues here, I'll address them one at a time. First, the code for moving the projectile is wired up wrong:
transform.position=Vector2.Lerp(pos2,pos1,Time.deltaTime);
You are moving the object that "Shoot" is attached to, not the new game object (newObj, as you have named it.)
Second, it's important to understand the Update pattern and how to properly use it. Update is run every frame. Time.deltaTime is how much time has passed between the last frame render and this one. This number is usually very small. Lastly, Input.GetMouseButtonDown is true only on the first frame that the mouse is pressed.
The current code you have only attempts to (but fails, due to other code problems) move the projectile the one frame the mouse is clicked. What we want is the mouse click to spawn a projectile, and the projectile to move forward EVERY update.
This will be best accomplished with two classes. I will call them Gun and SeekerBullet. The Gun class will be responsible for creating a bullet every time the mouse button is pressed. The SeekerBullet class will be responsible for moving the bullet to it's target.
Gun
public SeekerBullet ProjectilePrefab;
void Update()
{
if (Input.GetMouseButton(0))
{
Vector2 target = Camera.main.ScreenToWorldPoint(Input.mousePosition);
FireBullet(target);
}
}
void FireBullet(Vector2 target)
{
GameObject projectile = (GameObject)GameObject.Instantiate(ProjectilePrefab, transform.position, Quaternion.Identity);
projectile.GetComponent<SeekerBullet>().Target = target;
}
SeekerBullet
public float MoveSpeed = 5;
public Vector2 Target { get; set; }
public void Update()
{
transform.position = Vector3.MoveTowards(transform.position, Target, MoveSpeed * Time.deltaTime);
if (transform.position == Target)
OnReachTarget();
}
void OnReachTarget()
{
// Do whatever you want here
Destroy(gameObject); // delete this seekerbullet
}
The main Idea I'm trying to stress is isolating your code to perform it's one function well. The gun shouldn't be responsible for moving the projectile, just creating it and telling it where to go.
Also, note that the projectile is starting wherever the Gun is. See this line
GameObject projectile = (GameObject)GameObject.Instantiate(ProjectilePrefab, transform.position, Quaternion.Identity);
The transform.position is the position of the gun object. If you want it to start at the foot, like you have in your code, you can re-implement that just like you have in your example.
Why don't you use Raycast. It's pretty simple. Here's an example (Moves the object (transform) in the direction and distance of translation.):
var obj:Transform;
var hit:RaycastHit;
var move: boolean = false;
var moveSpeed:float;
var moveTime:float;
private var startTime:float;
function Update ()
{
if (Input.GetButtonDown ("Fire1"))
{
var ray = Camera.main.ScreenPointToRay (Input.mousePosition);
if (Physics.Raycast (ray, hit, 10000)){
move = true;
startTime = Time.time;
}
}
if(move){
var curTime = Time.time;
var elapsedTime = curTime - startTime;
var amountToMove = elapsedTime / moveTime;
print(amountToMove);
obj.transform.position = Vector3.Lerp(obj.transform.position, hit.point, amountToMove);
if(obj.transform.position == hit.point){
move = false;
}
This code creates a plane, and a cube. Assign the above code to the plane, assign the cube to the obj var in the inspector. Click on the plane, and watch the fun.
This is pretty simple. You can use the Vector3.Lerp function to achieve this. Use raycasting to get the mouse click position or the touch position. Then use the initial and the final position in the lerp function. The initial position being the position that the gameobject is at now and the final position being the click / touch position.
You can find the article by The Game Contriver on the same here
Move to Touch / Click Position - The Game Contriver