I'm creating a game with Unity and I'm learning C#. I needed some help with a bullet firing mechanism for my game so I found the below script on Unity Answers. It works great, but fires the bullet backwards (which would land anyone in the game in a bad situation). Could anyone help? Thank you!
using UnityEngine;
using System.Collections;
public class ShootDemo : MonoBehaviour
{
public Rigidbody projectile;
public float speed = 20;
// Update is called once per frame
void Update()
{
if (Input.GetButtonDown("Fire1"))
{
Rigidbody instantiatedProjectile = Instantiate(projectile, transform.position,
transform.rotation) as Rigidbody;
instantiatedProjectile.velocity = transform.TransformDirection(new Vector3(0, 0, speed));
}
}
}
What you have would work if you had the forward (blue axis) of the gameobject of ShootDemo pointing in the direction you'd want to shoot.
The fact that does that shoots it in the opposite direction means the forward is pointing is actually pointing in the opposite direction.
Taking that into account by negating speed will reverse the velocity to create the desired effect:
instantiatedProjectile.velocity = transform.forward * -speed;
Or in the format you've already used
instantiatedProjectile.velocity = transform.TransformDirection(new Vector3(0, 0, -speed));
Related
I'm pretty new to Unity. I tried to create a script that the camera would follow the actor (with a little difference). Is there a way to improve the code? It works just fine. But I wonder if I did it the best way. I want to do it about as I wrote, so if you have any tips. Thank you
Maybe change Update to FixedUpdate ?
public GameObject player;
// Start is called before the first frame update
void Start()
{
player = GameObject.Find("Cube"); // The player
}
// Update is called once per frame
void Update()
{
transform.position = new Vector3(player.transform.position.x, player.transform.position.y + 5, player.transform.position.z - 10);
}
Making the camera following the player is quite straight forward.
Add this script to your main camera.
Drag the reference of the player object to the script and then you are done.
You can change the values in the Vector 3 depending on how far you want the camera to be from the player.
using UnityEngine;
public class Follow_player : MonoBehaviour {
public Transform player;
// Update is called once per frame
void Update () {
transform.position = player.transform.position + new Vector3(0, 1, -5);
}
}
Follows player in the back constantly when the player rotates, no parenting needed, with smoothing.
Piece of Knowledges:
Apparently, Quaternion * Vector3 is going to rotate the point of the Vector3 around the origin of the Vector3 by the angle of the Quaternion
The Lerp method in Vector3 and Quaternion stand for linear interpolation, where the first parameter gets closer to the second parameter by the amount of third parameter each frame.
using UnityEngine;
public class CameraFollow : MonoBehaviour
{
public Transform target;
public float smoothSpeed = 0.125f;
public Vector3 locationOffset;
public Vector3 rotationOffset;
void FixedUpdate()
{
Vector3 desiredPosition = target.position + target.rotation * locationOffset;
Vector3 smoothedPosition = Vector3.Lerp(transform.position, desiredPosition, smoothSpeed);
transform.position = smoothedPosition;
Quaternion desiredrotation = target.rotation * Quaternion.Euler(rotationOffset);
Quaternion smoothedrotation = Quaternion.Lerp(transform.rotation, desiredrotation, smoothSpeed);
transform.rotation = smoothedrotation;
}
}
This will always follow the player from the same direction, and if the player rotates it will still stay the same. This may be good for top-down or side-scrolling view, but the camera setup seems to be more fitting for 3rd person, in which case you'd want to rotate the camera when the player turns.
The easiest way to do this is actually not with code alone, simply make the camera a child of the player object, that way its position relative to the player will always stay the same!
If you do want to do it through code, you can change the code to be like this:
void Update()
{
Vector3 back = -player.transform.forward;
back.y = 0.5f; // this determines how high. Increase for higher view angle.
transform.position = player.transform.position - back * distance;
transform.forward = player.transform.position - transform.position;
}
You get the direction of the back of the player (opposite of transform's forward). Then you increase the height a little so the angle will be a bit from above like in your example. Last you set the camera's position to be the player's position and add the back direction multiplied by the distance. That will place the camera behind the player.
You also need to rotate the camera so it points at the player, and that's the last line - setting the camera's forward direction to point at the player.
Here is just another option. I always find it easier to have the variables which are populated in the inspector so you can adjust it and fine tune it as needed.
public GameObject player;
[SerializeField]
private float xAxis, yAxis, zAxis;
private void Update()
{
transform.position = new Vector3(player.transform.position.x + xAxis, player.transform.position.y + yAxis, player.transform.position.z + zAxis);
}
I recently posted a problem with a jittering Camera Follow in my 2D Game made in Unity, which was solved here.
However after some time I noticed, that I am still getting jumps. I now know, that the problem lies in the lerp method of my camera follow. Time.deltaTime varies as described in my prior question and thus makes the player move different distances each frame. But because the camera reacts with a delay, you can see the jump on screen (on device even more than in Unity Editor).
A solution would be to detect those Time.DeltaTime jumps and in these cases make the camera imitate that jump somehow, am I correct? What would be a Workaround here?
These are my scripts:
public class Player: MonoBehaviour
{
float speed = 5f;
void Update()
{
transform.Translate(0,speed*Time.deltaTime,0);
}
}
public class CamFollow : MonoBehaviour
{
public Transform Player;
private Vector3 FollowVector;
float transition = 0.05f;
void LateUpdate()
{
FollowVector = Player.position - new Vector3(0, -4.0f, 10);
transform.position = Vector3.Lerp(transform.position, FollowVector, transition);
}
}
Try using Time.fixedDeltaTime. This is like deltatime but it's fixed and so it doesn't very as you said. It does reduce the jittering, but I would recommend using Cinemachine, as it's very performant and you would have a lot of control over it.
I have a rectangle player sprite with a Box Collider 2D and a Rigidbody2D attached. I also have a script for point-and-click movement attached to the player object (i.e. player moves to mouse click position). However as soon as the player character hits a collider, it starts to jitter rather than just fully stop. I don't know a lot about Unity physics other than what I've picked up in a few tutorials, so I'll include as much relevant information as I can.
The Rigidbody 2D component has all forces set to 0, except for mass being 0.0001. The body type is dynamic, and collision detection is set to continuous. My movement script looks like this, got it straight from a tutorial:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerControls : MonoBehaviour
{
public float speed = 1;
private Vector3 target;
void Start()
{
target = transform.position;
}
void Update()
{
if (Input.GetMouseButtonDown(0)) {
target = Camera.main.ScreenToWorldPoint(Input.mousePosition);
target.z = transform.position.z;
}
transform.position = Vector3.MoveTowards(transform.position, target, speed * Time.deltaTime);
}
}
Is there an easier way to implement smooth point-and-click movement?
I started making a simple game in Unity3d: a tank to shoot at a wall (see image).
A GameObject is attached to the turret of the tank, and to this GameObject is attached the following script :
using UnityEngine;
using System.Collections;
public class Shooter : MonoBehaviour {
public Rigidbody bullet;
public float power = 1500f;
void Update () {
if (Input.GetButtonDown ("Fire1")) {
Rigidbody bulletRB = Instantiate (bullet, transform.position, transform.rotation) as Rigidbody;
Vector3 fwd = transform.TransformDirection(Vector3.forward);
bulletRB.AddForce(fwd*power);
}
}
}
When I press on the Fire1 button the bullet does not shoot. I put (for test) a Debug.Log("BULLET SHOOT") after bulletRB.addForce(). The message is displayed, so the script reached this point. What is wrong with my code?
Based on this somewhat similar question on Unity Answers, you should probably be instantiating the GameObject of the bullet prefab/instance, rather than its Rigidbody directly. Then, access the Rigidbody component of that new bullet and add the force.
Your adjusted Update() method would then look like:
void Update () {
if (Input.GetButtonDown ("Fire1")) {
GameObject newBullet = Instantiate (bullet.gameObject, transform.position, transform.rotation) as GameObject;
RigidBody bulletRB = newBullet.GetComponent<Rigidbody>();
Vector3 fwd = transform.TransformDirection(Vector3.forward);
bulletRB.AddForce(fwd*power);
}
}
Another thing you may want to change is using transform.forward (aka. Forward vector of the turret) rather than Vector3.forward (global forward vector Vector3(0, 0, 1), which may not match the direction of the turret).
Hope this helps! Let me know if you have any questions.
Force can be applied only to an active rigidbody. If a GameObject is inactive, AddForce has no effect.
Wakes up the Rigidbody by default. If the force size is zero then the Rigidbody will not be woken up.
The above description is taken from Unity
Therefore, I would suggest to check if the GameObject is active first.
You can test it by doing the following:
if (newBullet.activeInHierarchy === true)
{
//active
}else{
//inactive
}
When reading this, keep in mind I'm new to both programming and Unity, so I might be missing some terms or tools Unity offer. Please elaborate your answers in an ELI5 manner. Thanks in advance!
I am currently working on some game-physics for a small personal project. Currently I've created a platform, a character and what should be, a following companion.
However, since I'm still not on a level, where I can create perfect code on own hand, I found an "enemy" script and tried to modify it a bit.
It Works to an extend, but it needs some tweaks which I hope I can help aquire with you guys.
This is how it looks now (the orange square is the companion)
It follows the player, and I can tweak the speed to fit as a companion, and not a player. However, as the Picture presents, the companion runs for the center of the player. What I want to create is a companion which follows the player, but still keeps a small gap from the player.
My first thoughts was to create some kind of permanent offset, but I fail to figure out how to do this without messing up the follow function.
I hope you can help me, it will be much appreciated!
Here's the code for reference.
Code attached to Player:
using UnityEngine;
using System.Collections;
public class PlayerCompanion : MonoBehaviour
{
//In the editor, add your wayPoint gameobject to the script.
public GameObject wayPoint;
//This is how often your waypoint's position will update to the player's position
private float timer = 0.5f;
void Update ()
{
if (timer > 0) {
timer -= Time.deltaTime;
}
if (timer <= 0) {
//The position of the waypoint will update to the player's position
UpdatePosition ();
timer = 0.5f;
}
}
void UpdatePosition ()
{
//The wayPoint's position will now be the player's current position.
wayPoint.transform.position = transform.position;
}
}
Code attached to companion:
using UnityEngine;
using System.Collections;
public class FollowerOffset : MonoBehaviour {
//You may consider adding a rigid body to the zombie for accurate physics simulation
private GameObject wayPoint;
private Vector3 wayPointPos;
//This will be the zombie's speed. Adjust as necessary.
private float speed = 10.0f;
void Start ()
{
//At the start of the game, the zombies will find the gameobject called wayPoint.
wayPoint = GameObject.Find("wayPoint");
}
void Update ()
{
wayPointPos = new Vector3(wayPoint.transform.position.x, transform.position.y, wayPoint.transform.position.z);
//Here, the zombie's will follow the waypoint.
transform.position = Vector3.MoveTowards(transform.position, wayPointPos, speed * Time.deltaTime);
}
}
bump, I guess ? :)
You can use smooth follow script. I have created a sample class for you. This class has features to follow any given gameobject with some delay and offset. You will have to tweak some values according to your need.
using UnityEngine;
using System.Collections;
public class PlayerCompanion : MonoBehaviour
{
[SerializeField]
private GameObject wayPoint;
[SerializeField]
public Vector3 offset;
public Vector3 targetPos;//Edit: I forgot to declare this on firt time
public float interpVelocity;
public float cameraLerpTime = .1f;
public float followStrength = 15f;
// Use this for initialization
void Start ()
{
//At the start of the game, the zombies will find the gameobject called wayPoint.
wayPoint = GameObject.Find("wayPoint");
offset = new Vector3 (5,0,0);//input amount of offset you need
}
void FixedUpdate () {
if (wayPoint) {
Vector3 posNoZ = transform.position;
Vector3 targetDirection = (wayPoint.transform.position - posNoZ);
interpVelocity = targetDirection.magnitude * followStrength;
targetPos = transform.position + (targetDirection.normalized * interpVelocity * Time.deltaTime);
transform.position = Vector3.Lerp (transform.position, targetPos + offset, cameraLerpTime);
}
}
}
Attach this class to your player companion, play with different values.
To preserve object orientation your companion schould not be anyways child of your main character.
Your wayPoint doesn't needs to be a GameObject but a Transform instead and your code will looks like better.
If your game is a 2D platform your and your companion needs to be backwards your player it probabli applys to just one axis (X?) so you can decrement your waiPoint in a more directly way by calculating it on your UpdatePosition function like this:
wayPoint.position = transform.position * (Vector3.left * distance);
where your "distance" could be a public float to easily setup.
so on your companion script Update just do:
transform.position = Vector3.MoveTowards(transform.position, wayPoint.position, speed * Time.deltaTime);
I can't test it right now so you could have problems with Vector3 multiply operations, just comment and I'll try to fix as possible ;)