unity changing weapons.prefab issues - unity3d

So i'm trying to change weapons for my 2d top down space shooter. by weapon I just mean my bullet prefab so it shoots a different bullet which I can then add damage to etc.
here is the code I have. when I press number 2 it shoots my prefab clone in the hierarchy but its greyed out and nothing shows up in the game view. Below is my playerShoot code.
public class playerShoot : MonoBehaviour {
public Vector3 bulletOffset = new Vector3 (0, 0.5f, 0);
float cooldownTimer = 0;
public float fireDelay = 0.25f;
public GameObject bulletPrefab;
int bulletLayer;
public int currentWeapon;
public Transform[] weapons;
void Start () {
}
void Update () {
if (Input.GetKeyDown(KeyCode.Alpha1)){
ChangeWeapon(0);
}
if (Input.GetKeyDown(KeyCode.Alpha2)){
ChangeWeapon(1);
}
cooldownTimer -= Time.deltaTime;
if (Input.GetButton("Fire1") && cooldownTimer <= 0){
cooldownTimer = fireDelay;
Vector3 offset = transform.rotation * bulletOffset;
GameObject bulletGO = (GameObject)Instantiate(bulletPrefab, transform.position + offset, transform.rotation);
bulletGO.layer =gameObject.layer;
}
}
public void ChangeWeapon(int num){
currentWeapon = num;
for (int i = 0; i < weapons.Length; i++){
if (i ==num)
weapons[i].gameObject.SetActive(true);
else
weapons[i].gameObject.SetActive(false);
}
}
}

Keeping the rest of the code same, just change the following line
GameObject bulletGO = (GameObject)Instantiate(bulletPrefab, transform.position + offset, transform.rotation);
to
GameObject bulletGO = (GameObject)Instantiate(weapons[currentWeapon].gameObject, transform.position + offset, transform.rotation);
What the change does is use the transforms for the weapons in your weapon array, rather than using the bulletPrefab.
The problem occured because you were Instantiating a single prefab, which was the same as the Transform you used for the first element in your weapons array. So, when you call ChangeWeapon(1), the prefab would get deactivated. This reulted in inactive GameObjects being instantiated.
What I would suggest you do is to have two separate prefabs and spawn those accordingly.

Related

Why are my programmatically instantiated Prefabs not firing mouse events?

In my Unity project I'm instantiating 20 Prefabs. These prefabs have box colliders and an attached script that includes:
private void OnMouseEnter()
{
print($"Mouse Enter detected by: {this.name}");
}
However these events never fire. If you google this issue you'll find multiple posts about this going back more than a decade. Unfortunately none of those threads seem to include a solution. If I drag the Prefab into the scene the mouse events will work, but if I create them programmatically they do not. Can someone explain to me how I can get mouse events working on programmatically created prefabs?
EDIT:
Since someone asked for my instantiation code here it is:
foreach (var movie in movies.Select((value, index) => (value, index)))
{
float angle = movie.index * Mathf.PI * 2 / movies.Count;
float x = Mathf.Cos(angle) * radius;
float z = Mathf.Sin(angle) * radius;
Vector3 pos = transform.position + new Vector3(x, height, z);
float angleDegrees = -angle * Mathf.Rad2Deg;
Quaternion rot = Quaternion.Euler(0, angleDegrees, 0);
var pre = Instantiate(moviePrefab, pos, rot, carousel.transform);
pre.transform.LookAt(Vector3.zero);
}
You didn't give me many details but I made what you want to do and this is how.
I made two classes:
NewBehaviourScript - for instatiating prefabs
public class NewBehaviourScript : MonoBehaviour
{
public GameObject Prefab;
private void Start()
{
for (int i = 0; i < 10; i++)
{
Instantiate(Prefab, new Vector3(transform.position.x + i, transform.position.y, 0), Quaternion.identity);
}
}
}
PrefabScript - script for prefab
public class PrefabScript : MonoBehaviour
{
private void OnMouseDown()
{
Debug.Log("Hit");
}
}
I created empty object "InstatiateObjectsHelper" in scene with the NewBehaviourScript
Then I created a prefab by creating it in the hierarchy, added to it PrefabScript, added to it BoxCollider, and then dragged & dropped it into the assets window.
Pressed play and tested it and it is working how you want it to.

how to spawn and move prefabs objects frequently?

I have a spawner game object the spawns 2 falling prefabs randomly.
The first version of the spawner only contained the spawning system and the falling effect was a component that the prefabs had, the problem was that I wanted that as the game progresses the SpawnRatio and falling speed will get higher with synchronization so I merged the spawning and the falling systems into the spawner game object and now for some reason the objects are spawning but no falling down.
public class Random_Spawn : MonoBehaviour {
public GameObject cube, circle;
public float spawnRate = 2f;
static float fallSpeed = 2f;
float nextSpawn = 0f;
int whatToSpawn;
void Update()
{
if (Time.time > nextSpawn)
{
whatToSpawn = Random.Range(1, 3);
switch (whatToSpawn)
{
case 1:
GameObject myCube = (GameObject)Instantiate(cube, transform.position, Quaternion.identity);
myCube.transform.Translate(Vector2.down * fallSpeed * Time.deltaTime, Space.World);
myCube.transform.parent = transform;
break;
case 2:
GameObject myCircle = (GameObject)Instantiate(circle, transform.position, Quaternion.identity);
myCircle.transform.Translate(Vector2.down * fallSpeed * Time.deltaTime, Space.World);
myCircle.transform.parent = transform;
break;
}
nextSpawn = Time.time + spawnRate;
if (spawnRate >= 0.05)
{
spawnRate -= 0.04f;
fallSpeed -= 0.04f;
}
}
}
}
The problem is that you are only calling Vector.Translate once for each spawned object. You need this to be called every frame for the movement to continue.
It would be best to attach a separate movement script to the cube and circle prefabs that calls Vector.Translate in their own Update() functions.
To handle the increasing fall speed you can have the new movement script reference a fallSpeed variable from your spawner script to adjust your Vector.Translate speed.
speed = spawner.GetComponent<Random_Spawn>().fallSpeed;

Why my code fires bullet at random positions?

I see that the bullets are being fired at random positions and not actually in forward direction of the camera. What's wrong here and how should I fix it?
So I am using pooling and each time the bullet is enabled this code is run:
private void OnEnable()
{
transform.position = Camera.main.transform.position;
transform.rotation =Quaternion.identity;
GetComponent<Rigidbody>().AddForce((Camera.main.transform.forward + new Vector3(0, 0, 0)) * 5000);
Invoke("Destroy", 1.5f);
}
I have also changed it to the below code but even the second one doesn't work.
private void OnEnable()
{
Rigidbody rb = GetComponent<Rigidbody>();
rb.position = Camera.main.transform.position;
rb.rotation = Quaternion.identity;
rb.AddForce((Camera.main.transform.forward + new Vector3(0, 0, 0)) * 5000);
Invoke("Destroy", 1.5f);
}
First of all make sure the code works with out pooling. Secondly disable the collider component on the bullet (they might be colliding with themselves).
I've quickly tried this on my machine and this is the result I get.
using UnityEngine;
public class BulletController : MonoBehaviour
{
[SerializeField]
GameObject bulletPrefab;
void Update()
{
GameObject bullet = Object.Instantiate(bulletPrefab);
Rigidbody body = bullet.GetComponent<Rigidbody>();
body.position = Camera.main.transform.position;
body.AddForce(Camera.main.transform.forward * 75f, ForceMode.Impulse);
}
}
Here is the code I use with direction, position and velocity variables.
void Inception::shootGeode(std::string typeGeode, const btVector3& direction) {
logStderr(VERBOSE, "MESSAGE: Shooting geode(s)...\n");
std::shared_ptr<Geode> geode;
glm::vec3 cameraPosition = m_camera->getPosition();
btVector3 position = glm2bullet(cameraPosition + 3.0f * glm::normalize(m_camera->getTarget() - cameraPosition));
if (typeGeode == "cube")
geode = m_objectFactory->createCube("cube", new btBoxShape(btVector3(1.0f, 1.0f, 1.0f)), position, "dice");
if (typeGeode == "sphere")
geode = m_objectFactory->createSphere("sphere", new btBoxShape(btVector3(1.0f, 1.0f, 1.0f)), position);
btVector3 velocity = direction;
velocity.normalize();
velocity *= 25.0f;
geode->getRigidBody()->setLinearVelocity(velocity);
}

Patrol using children waypoints

In my game, I have multiple objects that should patrol different waypoints.
public Transform[] targets;
public float speed = 1;
private int currentTarget = 0;
IEnumerator StartMoving ()
{
while (true)
{
float elapsedTime = 0;
Vector3 startPos = transform.position;
while (Vector3.Distance(transform.position, targets[currentTarget].position) > 0.05f )
{
transform.position = Vector3.Lerp(startPos, targets[currentTarget].position, elapsedTime/speed);
elapsedTime += Time.deltaTime;
yield return null;
}
yield return new WaitForSeconds(delay);
}
}
The code works fine, but for organizing reasons I would like each object to have its waypoints as children of that object, but the problem is because the waypoints are children of that object, they move with it, which results in an unwanted behavior.
Is there any workaround for this?
You'd have to add a level of hierarchy. One parent item as container for the character and the waypoints. Then the code moves the character only.
- Container with Scripts
- Character with mesh
- Waypoints
- WaypointA
- WaypointB
- ...
Well, if you really want to parent them.. you can move the waypoints in the opposite direction of the patrolling objects:
//Remember prev pos
Vector3 prevPosition = transform.position;
transform.position = Vector3.Lerp(startPos, targets[currentTarget].position, elapsedTime/speed);
//Move the waypoints in the opposite direction
foreach(Transform childWaypoint in ...)
{
childWaypoint.position -= transform.position - prevPosition;
}
But a better solution would be the assign an array of Vector3 for your patrolling objects..
public class Patrollers : Monobehaviour
{
Vector3[] _waypoints;
//..
}

Ball falls through platform collider

There are 2 GameObjects; a platform and a ball.
The ball is controlled via a custom controller, and the platform moves via an animation.
Components
platform
+ rigidbody
+ box collider
ball
+ rigidbody
+ sphere collider
When the ball comes in contact with the platform, the ball should stop its current velocity and attain the velocity of the platform it is in contact with. However currently, the ball just falls straight through the platform as if there is no colliders attached.
Code of Player:
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class PlayerController : MonoBehaviour {
public Text winText;
public float speed;
public Text countText;
public GameObject light;
public GameObject player;
private Rigidbody rb;
private int count;
private int a = 0;
private int b = 0;
private int c = 0;
void Start ()
{
rb = GetComponent<Rigidbody>();
count = 0;
SetCountText ();
winText.text = "";
}
void FixedUpdate()
{
if (player.transform.position.y < -15) {
transform.position = new Vector3(a, b, c);
}
float moveHorizontal = Input.GetAxis ("Horizontal");
float moveVertical = Input.GetAxis ("Vertical");
Vector3 movement = new Vector3 (moveHorizontal, 0.0f, moveVertical);
rb.AddForce (movement * speed );
}
void OnTriggerEnter (Collider other)
{
if (other.gameObject.CompareTag ("Pick Up"))
{
other.gameObject.SetActive (false);
count = count + 1;
SetCountText ();
}
if (other.gameObject.CompareTag ("Check point"))
{
other.gameObject.SetActive (false);
light.gameObject.SetActive (false);
a = 0;
b = -10;
c = 96;
}
}
void SetCountText ()
{
countText.text = "Score: " + count.ToString();
if (count >= 8)
{
winText.text = "You Win!";
}
}
}
You said you are using a custom controller. Please make sure that you are not using Transform() to change the ball's position manually and move your ball as this defies the physics laws in unity. Instead use Rigidbody.MovePosition().
More at Unity docs
Make sure you have all those game objects in same Z axis.
Throw a debug.log() message in your OnCollisionEnter2D() method to see if they are actually colliding.
Could you also check for the type of Colliders you are using.
More Details about Collision in unity :
https://docs.unity3d.com/Manual/CollidersOverview.html
Also if it a custom controller make sure that something is not changing the position of ball to go below the platform.
Fast moving objects need the dynamic ContinuousDynamic or Continuous mode to work reliable
Make sure both rigidbodies are kinetic and the colliders are not triggers. Thats what really worked for me.