How to create a projectile Script in Unity - unity3d

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.

Related

Better movement script needed?

I got an issue that I've been trying to figure out for some time now and still haven't managed. I created a script for movement which besides using the WASD keys also uses two more buttons to go up and down. The thing is - because of the way I added those buttons for some reason no other function regarding position of the player doesn't work well. For example if I put a collider with a simple on trigger transform.position function for the player to hit - the player is placed on that position but then instantly returned back like there was nothing.
Here is my code. I had tons of iterations how this movement can be done. I did it through physics and controller in several ways but nothing helped. Can you guys tell me if it's the code or some hidden Unity synergy that I don't know about?
(this version works around addForce. Regardless, whatever way I make the up and down functions I cannot move the player with script after that.)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Mov : MonoBehaviour
{
private CharacterController controller;
private Rigidbody Rb;
private Vector3 playerVelocity;
private float playerSpeed =12;
void Start()
{
controller = gameObject.AddComponent<CharacterController>();
Rb = gameObject.GetComponent<Rigidbody>();
}
// Update is called once per frame
void FixedUpdate()
{
Vector3 move = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
Vector3 add =new Vector3 (0, playerSpeed, 0);
controller.Move(move * Time.deltaTime * playerSpeed);
if (Input.GetKey(KeyCode.Mouse1))
{
Rb.AddForce(0, 1200, 0, ForceMode.Acceleration);
}
if (Input.GetKey(KeyCode.Mouse0))
{
Rb.AddForce(0, -1200, 0, ForceMode.Acceleration);
}
}
}
I'm not sure what you mean by "no other function regarding position of the player doesn't work well" but from have you turning "Collision Detection" in your Rigidbody's settings to "Continuous" and "Interpolate" to "Interpolate"? If you don't do so, Unity's collision's may be a bit funky especially if you are going at high speeds.

Camera follow player around planet

I have a planet and a player moving on it using gravity. I would like to have a camera to follow the player around it. Using the Parent Constraint component works perfectly, but I want to delay the rotation follow, so I have to use a script. I just cannot figure out how to make it follow it around the globe. I either have a camera that completely freaks out, or a camera that sort of follows the player but doesn't move over the planet and always stays in front of it. And often the position following works, but as soon as I add something that changes rotation it only does that. I've tried many different scripts but nothing works. I'm grateful for any help.
EDIT
I'm sorry for not adding an example. At the moment I've tried this script attached to the camera:
public class CameraFollow : MonoBehaviour
{
public GameObject player;
private Vector3 offset;
void Start()
{
offset = transform.position - player.transform.position;
}
void LateUpdate()
{
transform.rotation = Quaternion.Slerp(transform.rotation, player.transform.rotation, 50f * Time.deltaTime);
transform.position = player.transform.position + offset;
}
The camera does mimic the rotation of the player, but the position isn't being follow correctly anymore. It seems mostly stuck in place, moving only very slightly.
In order to have a camera following a GameObject, you need to go to the camera you want following the GameObject, select Add component, write FollowPlayer, press New script, and then press select and add. Edit the script so it contains the following:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class FollowPlayer : MonoBehaviour
{
public Transform player;
public Vector3 offset;
// Update is called once per frame
void Update()
{
transform.position = player.position + offset;
}
}
Then, you will need to drag and drop the GameObject you want the camera to follow, in the "Player" box.
Define the offset of the camera from the GameObject, and your'e good to go.

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.

GameObject Follow cursor yet also follows enemies?

I'm making a simple character that follows the player's cursor. What I also want is for when the game object "enemy" appears the character then goes to that location to alert the player. Once the enemy is gone the character continues to follow the cursor like normal. Is there a reason why my script won't work. How else can I paraphrase it?
public class FollowCursor : MonoBehaviour
{
void Update ()
{
//transform.position = Camera.main.ScreenToWorldPoint( new Vector3(Input.mousePosition.x,Input.mousePosition.y,8.75f));
if (gameObject.FindWithTag == "Enemy")
{
GameObject.FindWithTag("Enemy").transform.position
}
if (gameObject.FindWithTag != "Enemy")
{
transform.position = Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x,Input.mousePosition.y,8.75f));
}
}
}
You are not using FindWithTag correctly, as it is a method that takes a string as parameter you need to use it like this:
GameObject.FindwithTag("Something") as stated in the Unity scripting API
Now to apply this to your code you would need to do the following to set your players position based on wether or not an enemy is found (assuming this script is on your actual player object):
if(GameObject.FindWithTag("Enemy"))
{
//If an enemy is found with the tag "Enemy", set the position of the object this script is attatched to to be the same as that of the found GameObject.
transform.position = GameObject.FindWithTag("Enemy").transform.position;
}
else
{
//when no enemy with the tag "Enemy" is found, set this GameObject its position to the the same as that of the cursor
transform.position = Camera.main.ScreenToWorldPoint( new Vector3(Input.mousePosition.x,Input.mousePosition.y,8.75f));
}
However this code will just snap your player instantly to the position of the found Enemy. If this is not the desired behaviour you could use a function like Vector3.MoveTowards instead to make the player move to it gradually.
This code also has room for optimisation as searching for a GameObject every update frame is not the ideal solution. But for now it should work.
I'm going to code coding all the function for you, I'm not pretty sure about the beavihour of your code, I understand a gameobject will be attached to the mouse position, so not really following....
Vector3 targetPosition;
public float step = 0.01f;
void Update()
{
//if there is any enemy "near"/close
//targetPosition = enemy.position;
//else
//targetPosition = MouseInput;
transform.position = Vector3.MoveTowards(transform.position, targetPosition , step);
}
For the f you can use a SphereCast and from the enemies returned get the closest one.

Firing on both side Unity 2D

I am trying to make a 2D platformer but my player is not firing on both side I don't know what is wrong with my script.
using UnityEngine;
using System.Collections;
public class Bullet : MonoBehaviour
{
public float bulletSpeed;
public GameObject bullet;
public Transform bulletX;
GameObject clone;
void Update ()
{
if (Input.GetKeyUp ("space"))
{
clone = Instantiate(bullet,new Vector3(bulletX.position.x,bulletX.position.y+0.1f,0f),Quaternion.identity) as GameObject;
if (GameObject.Find ("Player").GetComponent<Player> ().left == true)
bulletSpeed = -30f;
else
bulletSpeed = 30f;
}
bullet.rigidbody2D.velocity = new Vector2(bulletSpeed * 0.5f, 0f);
Destroy (clone, 1f);
}
}
I tried to increase velocity inside the if condition but bullet was moving faster than I needed.
I think your question was very hard to understand what you want to accomplish, but I can see some errors in your code that will render the "clone" you are creating, useless.
The update loop is continuously executing, and you have placed the destroy outside your "Press space" code block. Unity tries to destroy it every frame. Place it inside the space.
I feel it should look more like this:
if (Input.GetKeyUp ("space"))
{
clone = Instantiate(bullet,new Vector3(bulletX.position.x,bulletX.position.y+0.1f,0f),Quaternion.identity) as GameObject;
if (GameObject.Find ("Player").GetComponent<Player> ().left == true)
bulletSpeed = -30f;
else
bulletSpeed = 30f;
bullet.rigidbody2D.velocity = new Vector2(bulletSpeed * 0.5f, 0f);
Destroy (clone, 1f);
}
This might not answer your question, but could you specify more what behaviour you are after? And what object is this script running on? (It is called Bullet with a field referance to another bullet ?)
Debug.Log your bulletSpeed * 0.5f
If I am correct. Even if your Player is Looking at the other way. It is returning
an ABS number meaning (bulletSpeed = -30f & 0.f is != -44954 something but == 44954).
Alternatively you can use AddForce instead of Velocity. It is easier to control.
QUESTION. Why not use Instantiate Vector2?