3D Isometric game in Unity - Projectile follows player movements - unity3d

I'm trying to make a 3D Isometric game with a wizard shooting fireballs. I managed to make it shoot the fireball but they go in the direction which the wizard is facing: if I rotate the wizard the fireballs change direction. What can I do? Thanks for helping me.
This is the script I made (attached to the player):
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class WizardController : Characters
{
[SerializeField]
public Transform spawnMagic;
private GameObject magicShot;
public List<GameObject> magicBullets = new List<GameObject>();
private void Start()
{
maxHP = 150.0f;
magicShot = magicBullets[0];
}
void Update()
{
GetInputs();
Attack();
Defend();
cameraFollow();
}
private void FixedUpdate()
{
LookAt();
Move();
}
public override void Attack()
{
if (Input.GetButtonDown("Fire1"))
{
GameObject magicBullet;
isAttacking = true;
GetComponent<Animator>().SetBool("hit1", true);
if (spawnMagic != null)
{
magicBullet = Instantiate(magicShot, spawnMagic.transform.position, Quaternion.identity);
}
}
else
{
GetComponent<Animator>().SetBool("hit1", false);
}
}
}
The movement script for the bullet is a simple "transform.position" line:
transform.position += spawnMagic.forward * (speed * Time.deltaTime);
And this is what happen when the player shoot:
https://youtu.be/TYwWDr8W4Q4

To solve this problem, you must make the bullet movement independent of the any objects that are Child of wizard or depend on it transfrom.
If you are careful, the spawnMagic rotates as the wizard moves, and the bullet is referenced by spawnMagic.forward.
First you need to place bullet rotation same as spawn spawnMagic rotation during production.
magicBullet = Instantiate(magicShot, spawnMagic.transform.position, spawnMagic.transform.rotation)
Then replace spawnMagic.forward with local bullet forward at movement part, it will make bullet movement indepent of spawnMagic direction during move phase:
transform.position += transform.forward * (speed * Time.deltaTime)

Related

How do I check the rotation angle of my object in Unity?

I am currently am making a detail with blood where when the player shoots an enemy, a object spawns with a random sprite to represent blood. The problem is that the sprite simply only spawns in the same angle. I tried looking up how to get the angle of the bullet to give it to the newly spawned object. Does anyone here know how to get such a angle? so I could give it to another object? here are both scripts incase it helps
// Script for the gun
public Transform firepoint;
public GameObject bulletprefab;
public float bulletforce = 20f;
void Update()
{
if (Input.GetButtonDown("Fire1"))
{
Shoot();
}
}
void Shoot()
{
GameObject bullet= Instantiate(bulletprefab, firepoint.position, firepoint.rotation);
Rigidbody2D rby = bullet.GetComponent<Rigidbody2D>();
rby.AddForce(firepoint.up * bulletforce, ForceMode2D.Impulse);
SoundEffectScript.Playsound("gunshot");
}
// script for the blood object so far
private int rand;
public Sprite[] sprites;
void Start()
{
rand = Random.Range(0,sprites.Length);
GetComponent<SpriteRenderer>().sprite = sprites[rand];
}

Unity collider shaking after hitting another collider

I have a SMALL a problem. In Unity 3D 2020 Beta, I've put a player with a sphere collider on it and some cubes (walls) with box colliders. I've added a player controller script to the player object.
I've put the camera above the plane where the player and the walls are on, and I've made that the player should rotate to face the mouse position. I used rigidbody.AddForce for movement in a FixedUpdate function.
The player controller script is attached below:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour
{
[Header("Keys")]
public KeyCode forward;
public KeyCode backward;
public KeyCode left;
public KeyCode right;
public KeyCode fire;
[Header("Health")]
public int hitpoints = 3;
[Header("Movement")]
public float speed;
public float turningSpeed;
[Header("Shooting")]
public GameObject bulletPrefab;
public Transform bulletSpawner;
public float bulletSpeed;
public float reloadTime;
private float currentReload;
private Rigidbody rb;
private Quaternion targetRotation;
void Start()
{
rb = GetComponent<Rigidbody>();
currentReload = reloadTime;
}
void LateUpdate()
{
if (hitpoints == 0)
Die();
// Rotation
var ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if (Physics.Raycast(ray, out hit))
{
targetRotation = Quaternion.LookRotation(hit.point - transform.position);
Debug.DrawLine(transform.position, hit.point, Color.white);
}
transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, turningSpeed * Time.deltaTime);
transform.eulerAngles = new Vector3(0, transform.rotation.eulerAngles.y, 0);
currentReload += Time.deltaTime;
// Shooting
if (Input.GetKeyDown(fire) && currentReload >= reloadTime)
{
currentReload = 0f;
GameObject bulletGO = Instantiate(bulletPrefab, bulletSpawner.position, transform.rotation);
bulletGO.transform.position = bulletSpawner.position;
Bullet bulletScript = bulletGO.GetComponent<Bullet>();
bulletScript.speed = bulletSpeed;
Destroy(bulletGO, 5f);
}
}
void FixedUpdate()
{
// Movement
if (Input.GetKey(forward))
{
rb.AddForce(Vector3.forward * speed, ForceMode.Force);
}
if (Input.GetKey(backward))
{
rb.AddForce(-Vector3.forward * speed, ForceMode.Force);
}
if (Input.GetKey(left))
{
rb.AddForce(Vector3.left * speed, ForceMode.Force);
}
if (Input.GetKey(right))
{
rb.AddForce(Vector3.right * speed, ForceMode.Force);
}
//transform.position = new Vector3(transform.position.x, 10, transform.position.z);
// ON RIGIDBODY I HAVE CONSTRAINS:
// POSITION: Y (thats why I commented the line above)
// ROTATION: X, Z (topdown -> so I want only rotation on Y)
}
private void Die()
{
Destroy(gameObject);
}
}
But the problem is when the player hits very hard a wall, the sphere collider starts shaking and the player does not look at the mouse position exactly (it is somewhere 10 degrees away most of the times - it depends on how hard do I hit the walls).
I can record if it helps. If you want any information, feel free to ask! Any help will be appreciated! :)
The problem here seems to be you're directly altering the transform of your object despite having a Rigidbody component. Generally you should avoid altering a transform directly when you have a Rigidbody attached, especially a non-kinematic one, as by attaching one you are signalling that the object is to be controlled by the physics simulation.
Solutions I would explore:
If you don't need a rigidbody, don't use one
If you can avoid altering the transform directly, then do not do so. You can rotate objects by applying torque and the likes
Try setting your object to kinematic if you don't need collisions to affect the rigidbody's physics
Manually set the torque and velocity of your object to 0 each fixed update

Isometric Unity 3D Game. How to shot a projectile?

I'm making an isometric 3D game. I made two joystick, one to move the player and the other one to shoot a projectile when the joystick is released. I made 3 attemps to achieve this result,but there's every time a problem. first try was with this :
clone.velocity = transform.TransformDirection(newpos);
but this need a rigidbody and a projectile can't be a rigidbody because it start from inside of the player.
Second try was this:
clone.transform.Translate(dir * (launchForce));
but this doesn't have a "speed" so it just move instantly to the position, not by moving, but translating
and the same happens with the third attemp:
clone.transform.position=Vector3.MoveTowards(Player.transform.position,newpos,10f);
This is the best solution until now because it gives me the possibility to choose a max range between the start posititon and the newposition.
Here's the full code:
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using System.Collections;
public class shoot : MonoBehaviour, IDragHandler, IPointerUpHandler, IPointerDownHandler
{
private Image bgImg;
private Image joystickImg;
private Vector3 inputVector;
public GameObject proiettile;
private Vector3 dir = Vector3.zero;
private Vector3 newpos;
public float launchForce;
public Rigidbody Player;
private GameObject clone;
private void Start()
{
bgImg = GetComponent<Image>();
joystickImg = transform.GetChild(0).GetComponent<Image>();
}
public virtual void OnDrag(PointerEventData ped)
{
Vector2 pos;
if (RectTransformUtility.ScreenPointToLocalPointInRectangle(bgImg.rectTransform, ped.position, ped.pressEventCamera, out pos))
{
pos.x = (pos.x / bgImg.rectTransform.sizeDelta.x);
pos.y = (pos.y / bgImg.rectTransform.sizeDelta.y);
inputVector = new Vector3(pos.x * 2 +1, 0, pos.y * 2 - 1);
inputVector = (inputVector.magnitude > 1.0f) ? inputVector.normalized : inputVector;
// Move joystickImg
joystickImg.rectTransform.anchoredPosition =
new Vector3(inputVector.x * bgImg.rectTransform.sizeDelta.x / 3
, inputVector.z * (bgImg.rectTransform.sizeDelta.y / 3));
}
}
public virtual void OnPointerDown(PointerEventData ped)
{
OnDrag(ped);
}
public virtual void OnPointerUp(PointerEventData ped)
{
dir.x = Horizontal();
dir.z = Vertical();
newpos = dir * (launchForce);
clone = Instantiate(proiettile, Player.transform.position, Player.transform.rotation);
//third attempt
//clone.transform.position=Vector3.MoveTowards(Player.transform.position,newpos,10f);
//second attempt
//clone.transform.Translate(dir * (launchForce));
//first attempt
//clone.velocity = transform.TransformDirection(newpos);
// joystick come back to start position
inputVector = Vector3.zero;
joystickImg.rectTransform.anchoredPosition = Vector3.zero;
//temporary solution to replace the absence of a max range for projectile
clone.timeoutDestructor = 5;
}
public float Horizontal()
{
if (inputVector.x != 0)
return inputVector.x;
else
return Input.GetAxis("Horizontal");
}
public float Vertical()
{
if (inputVector.z != 0)
return inputVector.z;
else
return Input.GetAxis("Vertical");
}
}
If I were you I would use rigidbody attempt. Just make sure it does not collide with player by setting collision layers/disabling collider for first fraction of second/spawning projectile outside of player.
Why?
Two main reasons:
Rigidbody will handle interpolation for you out of the box (without it movement may be glitchy)
Rigidbody will handle "between frame" collisions with CCD for you out of the box (without it your projectile may go trough walls, or even targets if it's fast enough)
And these two features will save you a lot of time later
One of attempts:
When I spawn projectile I check with SphereCast (or whatever shape it has) if it's colliding with something. If it is I change isTrigger to true and then in "OnTriggerExit" I change isTrigger to false again. If it is not colliding with anything on spawn I just set isTrigger to false at start and that should do the trick.

Unity 2D- Rays not going in the right direction

I have a game object which is supposed to shoot a beam in several directions. I want to keep it as flexible as possible so I added several targets, which a script will draw a ray(from the game object to the target). I have used the position variable of the target's transforms but that just caused all the rays to go off to a strange direction but did slightly change when i moved around. Then i tried the local position of the targets but that caused all the rays to go in their original direction, not accounting for a change in rotation.
Here is the code for the laser's script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Laser : MonoBehaviour {
private LineRenderer Linerenderer;
public List<Transform> rays;
void Start()
{
Physics2D.queriesStartInColliders = false;
}
void Update () {
foreach (Transform tran in rays)
{
RaycastHit2D hit = Physics2D.Raycast(transform.position, tran.position,20);
Debug.DrawLine(transform.position, hit.point);
}
}
}
Screenshots:
-Using world positions:
-Using local positions:
The Physics2D.Raycast() method's second parameter you are specifying is wrong: it should not be a position in space, but a direction. The second parameter for the Debug.DrawRay() method is also a direction, not a point in space.
Try the following:
void Update () {
foreach (Transform tran in rays)
{
Vector2 direction = (tran.position - transform.position).normalized;
RaycastHit2D hit = Physics2D.Raycast(transform.position, direction, 20);
Vector2 rayDirection = hit.point - transform.position;
Debug.DrawRay(transform.position, rayDirection);
}
}
Thank you, after bit of messing around I was finally able to get it to work.
If anyone else needs help with something similar (Dynamic ray-casting).
Here is the final code(you might have to edit it slightly):
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Laser : MonoBehaviour {
private LineRenderer Linerenderer;
public List<Transform> rays;
void Start()
{
Physics2D.queriesStartInColliders = false;
}
void Update()
{
foreach (Transform tran in rays)
{
Debug.DrawRay(new Vector3(1, 1, 0), new Vector3(-1, -1, 0));
Vector2 direction = (tran.position - transform.position).normalized;
RaycastHit2D hit = Physics2D.Raycast(transform.position, direction);
Vector2 rayDirection = (hit.point - new Vector2( transform.position.x, transform.position.y));
Debug.DrawRay(transform.position, rayDirection);
}
}
}

Why does this script not work on imported models

I've created a movement script that checks to see if an object is grounded, and if so, moves the object based on user input. When I attach it to an object I create in Unity, it works. When I attach it to an object I created in Blender and then imported, nothing. No errors, the object just fails to respond. I can't figure out what is causing the imported object to not respond to input. Both objects have a rigidbody and a collider.
This is the code for movement:
using UnityEngine;
using System.Collections;
public class PlayerMovement : MonoBehaviour {
public float speed = 10f;
public float rotationSpeed = 100f;
private float distToGround;
private Collider collider;
void Start() {
collider = GetComponent<Collider>();
distToGround = collider.bounds.extents.y;
}
void Update() {
MovePlayer();
}
void MovePlayer() {
float translation = Input.GetAxis("Vertical");
float rotation = Input.GetAxis("Horizontal");
if (translation != null && rotation != null) {
if (IsGrounded()) {
transform.Translate(0, 0, translation * speed * Time.deltaTime);
transform.Rotate(0, rotation * rotationSpeed * Time.deltaTime, 0);
}
}
}
bool IsGrounded() {
return Physics.Raycast(transform.position, -Vector3.up, distToGround + 0.1f);
}
}
I've made a video demonstrating this: https://www.youtube.com/watch?v=qatBF5Ov3Zo&feature=youtu.be
This is a complication caused by Blender left handed axis vs Unity's right handed axis. When I exported a rotated object from Blender, the script works on the object as expected. The solution is to make sure that the object you are exporting is facing the Z axis instead of the native Y axis.