Unity2d Shoot Ball From Cannon at Z Rotation - c#

I have the cannon attached to a hinge2d.
I move it by the Z rotation.
float offset = Mathf.Abs(gameObject.transform.eulerAngles.z);
if (Input.GetKey("w"))
{
gun.transform.rotation = Quaternion.RotateTowards(
gun.transform.rotation,
Quaternion.Euler(0.0f, 0.0f, minClamp + offset),
rotationSpeed * Time.deltaTime);
}
else if (Input.GetKey("s"))
{
gun.transform.rotation = Quaternion.RotateTowards(
gun.transform.rotation,
Quaternion.Euler(0.0f, 0.0f, maxClamp + offset),
rotationSpeed * Time.deltaTime);
}
This code has an offset for Z-rotation of any object the the cannon is mounted on.
When the cannon is fully up, I have it constrained to Z = 30.
When the cannon is fully down, I have it constrained to Z = -60.
What I'm trying to do is shoot the cannon ball out and up based on where the cannon is pointing.
I have tried a few different things, all of which didn't work.
private void ShootBullet()
{
GameObject bullet = Instantiate(bulletPrefab, gunTip.transform.position, Quaternion.identity);
var rb = bullet.GetComponent<Rigidbody2D>();
//setting rotation of bullet to have same rotation of cannon stem
bullet.transform.rotation = Quaternion.Euler(
gun.transform.eulerAngles.x,
gun.transform.eulerAngles.y,
gun.transform.eulerAngles.z + Mathf.Abs(gameObject.transform.eulerAngles.z));
//this is my issue right now, I dont know how to apply the correct force to the Y direction based on the Z(angle) of my cannon.
rb.AddForce(new Vector3( bulletSpeed, ?, 0), ForceMode2D.Impulse);
}

I have found some code snippet which may help you.
void Launch() {
GameObject clone = Instantiate (projectile, shootLocation, Quaternion.identity) as GameObject;
Rigidbody2D clonerb = clone.GetComponent<Rigidbody2D> ();
clonerb.AddRelativeForce (
transform.TransformDirection(new Vector2(
(Mathf.Cos (transform.rotation.z * Mathf.Deg2Rad) * speed),
(Mathf.Sin (transform.rotation.z * Mathf.Deg2Rad) * speed) )
),
ForceMode2D.Impulse
);
}
Source: 1
Further more an Setup that I created just now and worked is following:
public class Shoot : MonoBehaviour {
public GameObject Bullet;
public Transform ShootPoint;
public float bulletSpeed = 10.0f;
void Start() {
}
// Update is called once per frame
void Update() {
if(Input.GetKeyDown(KeyCode.Space)) {
if(!Bullet)
return;
GameObject clone = Instantiate(Bullet, ShootPoint.position, ShootPoint.rotation);
Rigidbody2D rb2d = clone.GetComponent<Rigidbody2D>();
rb2d.AddRelativeForce(Vector2.right * bulletSpeed, ForceMode2D.Impulse);
}
}
}

You could rather simply use AddRelativeForce
Adds a force to the rigidbody2D relative to its coordinate system.
which takes the orientation of the object into account:
// You should also simply set the rotation vis the Rigidbody2D component
rb.rotation = gunTip.transform.eulerAngles.z;
rb.AddRelstiveForce(Vector2.right * bulletSpeed, ForceMode2D.Impulse);

This ended up being what I needed. Thanks #At Least Vision
private void ShootBullet()
{
GameObject bullet = Instantiate(bulletPrefab, gunTip.transform.position, Quaternion.identity);
var rb = bullet.GetComponent<Rigidbody2D>();
bullet.transform.rotation = Quaternion.Euler(gun.transform.eulerAngles.x, gun.transform.eulerAngles.y, gun.transform.eulerAngles.z);
rb.AddRelativeForce(
bullet.transform.TransformDirection(new Vector2(
(Mathf.Cos(bullet.transform.rotation.z * Mathf.Deg2Rad) * bulletSpeed),
(Mathf.Sin(bullet.transform.rotation.z * Mathf.Deg2Rad) * bulletSpeed))
),
ForceMode2D.Impulse
);
}

Related

Unity - How can I fix this code so it works without transform.position = newPosition?

so my character has to walk around a tower, simple
but me being stupid can only work it out by using transform.position in update so jumping and collisions ofc, dont work
here is the tower concept ( see image )
Tower
here is how it works rn (see video: https://streamable.com/7tmq1l)
You will see in the clip how bad it breaks if i comment the transform.position = newposition to allow for jumping
Here is my code I used:
public class Movement : MonoBehaviour
{
[SerializeField] private float radius = 7;
[SerializeField] private float angleSpeed = 28;
[SerializeField] private float jumpForce = 5;
private float angle;
Rigidbody rb;
private void Start()
{
rb = GetComponent<Rigidbody>();
}
void Update()
{
transform.rotation = Quaternion.Euler(0, angle, 0);
float horizontalInput = Input.GetAxis("Horizontal");
angle -= horizontalInput * angleSpeed * Time.deltaTime;
Vector3 newPosition = Quaternion.Euler(0, angle, 0) * new Vector3(0, 0, radius);
transform.position = newPosition;
//jump
if(Input.GetKeyDown(KeyCode.Space)|| Input.GetKeyDown(KeyCode.W))
{
Debug.Log("Jumping!");
rb.AddForce(Vector3.up * jumpForce, ForceMode.Impulse);
}
}
Ofc the jumping doesnt work because of this
adjust the XZ position using the rigidBody and let the rb adjust the Y axis.
Vector3 newPosition = Quaternion.Euler(0, angle, 0) * radius;
newPosition.Y = rb.position.Y; // leave Y unchanged to allow for jumps
rb.position = newPosition;

How to add relative movement to multiple virtual cameras?

I am using a Cinemachine state driver to transition between my 8 directional cameras orbiting my player. Right now my player script is set to a basic isometric character controller:
Player.cs
public float speed = 5f;
Vector3 forward;
Vector3 right;
// Start is called before the first frame update
void Start()
{
forward = Camera.main.transform.forward;
forward.y = 0;
forward = Vector3.Normalize(forward);
right = Quaternion.Euler(new Vector3(0, 90, 0)) * forward;
}
// Update is called once per frame
void Update()
{
if (Input.anyKey)
{
Move();
}
}
void Move ()
{
Vector3 direction = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
Vector3 rightMovement = right * speed * Time.deltaTime * Input.GetAxis("Horizontal");
Vector3 upMovement = forward * speed * Time.deltaTime * Input.GetAxis("Vertical");
Vector3 heading = Vector3.Normalize(rightMovement + upMovement);
transform.forward += heading;
transform.position += rightMovement;
transform.position += upMovement;
}
I want the players move direction to reflect the direction of the camera. For example, using W (from WASD) will always move the player up. Could I edit the script to pick up the direction of each of my virtual cameras and add that to my player controller or is there a better way?
To solve this problem you have to change the movement of the keys according to the angle of the camera. This is done as follows with transform.TransformDirection. When the movement is synchronized with the direction of the camera, it causes the W key to press the character towards the ground, because the angle in front of the camera is inside the ground. To solve the problem, we set y to zero and then normalize the axis.
public float speed = 10f;
void Update()
{
var moveInput = new Vector3(Input.GetAxis("Horizontal"), 0f , Input.GetAxis("Vertical"));
moveInput = Camera.main.transform.TransformDirection(moveInput);
moveInput.y = 0;
moveInput = moveInput.normalized;
transform.position += moveInput * Time.deltaTime * speed;
}

Rotate rigidbody with moverotation in the direction of the camera

I want to use moverotation to rotate the object in the direction of the Main Camera, like a common third person shooter, but I don't know how to set the quaternion values or otherwise
`using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class movimento : MonoBehaviour
{
[SerializeField] float walk = 1;
[SerializeField] float run = 2;
Vector3 movement = Vector3.zero;
private Rigidbody rig;
// Start is called before the first frame update
void Start()
{
rig = GetComponent<Rigidbody>();
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.LeftShift)) walk = (walk + run);
if (Input.GetKeyUp(KeyCode.LeftShift)) walk = (walk - run);
float Horizontal = Input.GetAxis("Horizontal");.
float Vertical = Input.GetAxis("Vertical");
movement = Camera.main.transform.forward * Vertical + Camera.main.transform.right * Horizontal;
float origMagnitude = movement.magnitude;
movement.y = 0f;
movement = movement.normalized * origMagnitude;
}
private void FixedUpdate ()
{
rig.MovePosition(rig.position + movement * walk * Time.fixedDeltaTime);
Quaternion rotation = Quaternion.Euler(???);
rig.MoveRotation(rig.rotation * rotation);
}
}`
i use a coroutine to do smooth rotation. I use Quaternion.LookRotation for the job.
so you indicate the position of object to look at and the duration of animation. Here you want to rotate face to the main camera
StartCoroutine(SmoothRotation(Camera.main.transform, 3f));
:
:
IEnumerator SmoothRotation(Transform target, float duration)
{
float currentDelta = 0;
var startrotation = transform.rotation;//use your rigisbody if you want here i use the gameobject
var LookPos = target.position - transform.position;
var finalrot = Quaternion.LookRotation(LookPos);
while (currentDelta <= 1f)
{
currentDelta += Time.deltaTime / duration;
transform.rotation = Quaternion.Lerp(startrotation, finalrot, currentDelta);//
yield return null;
}
transform.rotation = finalrot;
}
if you want to see (in scene when running) where your camera points just add this line of code in update():
Debug.DrawRay(Camera.main.transform.position, Camera.main.transform.TransformDirection(Vector3.forward) * 10f, Color.black);
if you want to point in same direction tha nthe Camera just change the line of finalrot in SmoothRotation Method:
var finalrot = Camera.main.transform.rotation;
you dont need to calculate the LookPos
for your problem of crazy rotation, i suggest you to reset rotation x and z
direction = hit.transform.position - transform.position;
Quaternion rotation = Quaternion.LookRotation(direction);
rotation.x = 0f;
rotation.z = 0f;
a tips to detect object what you want with the raycast inside spere : Physics.OverlapSphere: you could select what you want to cast when using the optional parameter layermask
private void DetectEnemy(Vector3 center, float radius)
{
var hitColliders = Physics.OverlapSphere(center, radius );
for (var i = 0; i < hitColliders.Length; i++)
{
print(hitColliders[i].name + "," + hitColliders[i].transform.position);
// collect information on the hits here
}
}
I created a raycast from the camera, and I would like to rotate the rigidbody to where the raycast is pointing but if i launch unity, it rotated wildly. What is the error?
Vector3 direction;
Vector3 rayDir = new Vector3(Screen.width/2,Screen.height/2);
void Update()
Ray ray = Camera.main.ScreenPointToRay(rayDir);
Debug.DrawRay(ray.origin, ray.direction * 10, Color.yellow);
RaycastHit hit = new RaycastHit ();
direction = hit.point - transform.position;
private void FixedUpdate ()
Quaternion rotation = Quaternion.LookRotation(direction);
rig.MoveRotation(rig.rotation * rotation);
Add a character controller component, this is what is for. See:
https://docs.unity3d.com/Manual/class-CharacterController.html

When I hit play, my Sprite character rotates. Why?

I am making a top down game on Unity, so I am using the x and z axis as my plane. I have my character rotated x 90, y 0, z 0 so that it is flat on the plane. As soon as I hit play the character is rotated vertical?! I think it has something to do with my script to face the mouse position.
What it should look like:
When I hit play:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
public static float moveSpeed = 10f;
private Rigidbody rb;
private Vector3 moveInput;
private Vector3 moveVelocity;
// Update is called once per frame
void Start()
{
rb = GetComponent<Rigidbody>();
mainCamera = FindObjectOfType<Camera>();
}
void Update()
{
// Setting up movement along x and z axis. (Top Down Shooter)
moveInput = new Vector3(Input.GetAxis("Horizontal"), 0f, Input.GetAxis("Vertical"));
moveVelocity = moveInput * moveSpeed;
//Make character look at mouse.
var dir = Input.mousePosition - Camera.main.WorldToScreenPoint(transform.position);
var angle = Mathf.Atan2(dir.y, dir.x) * Mathf.Rad2Deg;
transform.rotation = Quaternion.AngleAxis(angle, Vector3.up);
}
void FixedUpdate()
{
// Allows character to move.
rb.velocity = moveVelocity;
}
}
Figured it out: I am answering my own question to help others.
Vector3 difference = Input.mousePosition - Camera.main.WorldToScreenPoint(transform.position);
float rotZ = Mathf.Atan2(difference.y, difference.x) * Mathf.Rad2Deg;
transform.rotation = Quaternion.Euler(90f, 0f, rotZ -90);
This does EXACTLY what I wanted!

How to Instantiate player bullet on leftside in unity

In my unity 2D game I've instantiate bullet with player direction but bullet bullet instantiate on right side of player i try to bullet instantiate on player left side.this is my player bullet
public Rigidbody2D playerWeapon;
void Start(){
InvokeRepeating ("PlayerWeapon",1.0f,1.0f);
}
void PlayerWeapon()
{
Rigidbody2D bPrefab = Instantiate (playerWeapon, new Vector3 (transform.position.x, transform.position.y, transform.position.z), Quaternion.identity) as Rigidbody2D;
}
Using transform.forward should do it. You can also use an offset to modify the distance the bullet should be spawned from the player's distance. Try the code below:
public Rigidbody2D playerWeapon;
void Start()
{
InvokeRepeating("PlayerWeapon", 1.0f, 1.0f);
}
void PlayerWeapon()
{
float offset = 5;
Vector3 plyrPos = transform.position;
Quaternion plyrRot = transform.rotation;
Vector3 plyrDir = transform.forward;
Vector3 spawnPos = plyrPos + plyrDir * offset;
Rigidbody2D bPrefab = Instantiate(playerWeapon, spawnPos, plyrRot) as Rigidbody2D;
}
EDIT:
You could also do this instead:
void PlayerWeapon()
{
float shootSpeed = 10f;
float offset = 5;
Rigidbody2D bPrefab = Instantiate(playerWeapon, transform.position + (offset * transform.forward), transform.rotation) as Rigidbody2D;
bPrefab.velocity = transform.forward * shootSpeed;
}
If it is still going in the wrong direction, flip the shootSpeed value to -10, try again and also flip offset to -5. This will likely fix your problem.

Categories