The question is answered, right answer was accepted
Automatic cannon aiming
Hello,
I am making cannon in 2D, which is aiming at the target automatically by calculating angle of shoot... I used range of projectile equation, it worked, but it was more like a howitzer, so I upgrade it to cannon style aiming by Quaternion.inverse. Problem appeared, when there was a difference between Y positions of cannon barrel and the target. Problem is because, when it is in normal form (without Quaternion changes) it needed only a little additional angle to shoot at upper or lower object. Now, when cannon aiming from 0 - 45 degrees (before changes it was 90-45) angle adjust only a little, like before my upgrades, so it need more additional angle. I actually tried lot of ways in hope to fix it, but no one seems to work. Guys, can you help me, please? :)
Before:
After:
void Update()
{
x = (Target.transform.position.x - BarrelEnd.transform.position.x) * XMultiply;
v = AmmoSpeed - Plusser;
v2 = v * v;
g = Mathf.Abs(Physics.gravity.y);
y = (Target.transform.position.y - BarrelEnd.transform.position.y);
Angle = Mathf.Atan((v2 + Mathf.Sqrt(v2*v2 - g*(g*x*x + 2*y*v2))) / (g*x));
transform.rotation = Quaternion.Inverse(Quaternion.Euler(0,0, Mathf.Rad2Deg*Angle - 90));
}
Answer by nebikhero · Apr 12, 2016 at 08:08 PM
@Vokyczech I created this piece of code 3 years ago, but i think it`s still working.
var Target: Transform; var grenadePrefab: Transform; var fireRate = 10; var attackRange = 20.0; var Damping = 6.0; private var Distance : float; private var nextFireTime = 0.0; function Start () { Target = PlayerTransform.playerTransform; } function Update(){ Distance = Vector3.Distance(Target.position, transform.position); if (Distance < attackRange) { Fire (); } } function BallisticVel(Target: Transform, angle: float): Vector3 { var dir = Target.position - transform.position; // get target direction var h = dir.y; // get height difference dir.y = 0; // retain only the horizontal direction var dist = dir.magnitude ; // get horizontal distance var a = angle * Mathf.Deg2Rad; // convert angle to radians dir.y = dist * Mathf.Tan(a); // set dir to the elevation angle dist += h / Mathf.Tan(a); // correct for small height differences // calculate the velocity magnitude var vel = Mathf.Sqrt(dist * Physics.gravity.magnitude / Mathf.Sin(2 * a)); return vel * dir.normalized; } function ElevationAngle(Target: Transform): float { // find the cannon->target vector: var dir = Target.position - transform.position; // create a horizontal version of it: var dirH = Vector3(dir.x, 0, dir.y); // measure the unsigned angle between them: var ang = Vector3.Angle(dir, dirH); // add the signal (negative is below the cannon): return ang; } function Fire () { if (Time.time > fireRate + nextFireTime){ nextFireTime = Time.time; FireOneShot(); } } function FireOneShot () { var ang = ElevationAngle(Target); var shootAng = ang +15; //shootAng = Mathf.Clamp(shootAng, 0, 360); transform.eulerAngles.z = -shootAng - 15; var grenade: Transform = Instantiate(grenadePrefab, transform.position, transform.rotation); var shoot = BallisticVel(Target, shootAng); shoot = Vector3(Random.Range((shoot.x - 20),(shoot.x + 5)), shoot.y, shoot.z); grenade.GetComponent.<Rigidbody>().velocity = shoot; //BallisticVel(Target, shootAng); // pass the angle and the target transform }
I tried, but cannon didn´t move, even the variables are null... So, it isn´t working, but I don´t know, maybe it is caused by my JS skills... :D (btw thx for help)
using UnityEngine; using System.Collections;
public class CannonUpgrade : $$anonymous$$onoBehaviour {
public Transform Target;
public Transform grenadePrefab;
public float fireRate;
public float attackRange = 20.0f;
public float Damping;
private float Distance;
private float nextFireTime = 0.0f;
public Vector3 shoot;
private Vector3 dirH;
// Update is called once per frame
void Update () {
Distance = Vector3.Distance(Target.position, transform.position);
if (Distance < attackRange)
{
Fire ();
}
}
public Vector3 BallisticVel(Transform Target, float angle)
{
Vector3 dir = Target.position - transform.position;
float h = dir.y;
dir.y = 0;
float dist = dir.magnitude;
float a = angle * $$anonymous$$athf.Deg2Rad;
dir.y = dist * $$anonymous$$athf.Tan (a);
dist += h / $$anonymous$$athf.Tan (a);
float vel = $$anonymous$$athf.Sqrt (dist * Physics.gravity.magnitude / $$anonymous$$athf.Sin (2 * a));
return vel * dir.normalized;
}
public float ElevationAngle(Transform Target)
{
Vector3 dir = Target.position - transform.position;
dirH.Set(dir.x, 0f, dir.y);
float ang = Vector3.Angle (dir, dirH);
return ang;
}
public void Fire()
{
if (Time.time > fireRate + nextFireTime)
{
nextFireTime = Time.time;
FireOneShot();
}
}
public void FireOneShot()
{
float ang = ElevationAngle (Target);
float shootAng = ang + 15;
shootAng = $$anonymous$$athf.Clamp (shootAng, 0, 360);
transform.position = new Vector3(transform.position.x,transform.position.y,-shootAng - 15);
GameObject Grenade = Instantiate (grenadePrefab, transform.position, transform.rotation) as GameObject;
Vector3 shoot1 = BallisticVel(Target, shootAng);
shoot.Set(Random.Range((shoot1.x - 20),(shoot1.x + 5)), shoot1.y, shoot1.z);
Grenade.GetComponent<Rigidbody2D> ().velocity = shoot;
BallisticVel (Target, shootAng);
}
}
I tried JS version and its working in Unity 5.3.4. I'm not quite sure what`s wrong with C# version. $$anonymous$$y C# skill isn`t good enough. $$anonymous$$aybe you didn`t enter Target, grenadePrefab, fireRate manually in Editor?
I remember I had a similar problem, i manually added greater angle. float shootAng = ang + 15; // you can add any angle After ElevationAngle function calculates $$anonymous$$imum (like on your second picture) angle required to hit target
function ElevationAngle(Target: Transform): float {
// find the cannon->target vector:
var dir = Target.position - transform.position;
// create a horizontal version of it:
var dirH = Vector3(dir.x, 0, dir.y);
// measure the unsigned angle between them:
var ang = Vector3.Angle(dir, dirH);
// add the signal (negative is below the cannon):
return ang;
}
And after that. BallisticVel function calculates required velocity for the grenade with my desire angle (shootAng).
function BallisticVel(Target: Transform, angle: float): Vector3 {
var dir = Target.position - transform.position; // get target direction
var h = dir.y; // get height difference
dir.y = 0; // retain only the horizontal direction
var dist = dir.magnitude ; // get horizontal distance
var a = angle * $$anonymous$$athf.Deg2Rad; // convert angle to radians
dir.y = dist * $$anonymous$$athf.Tan(a); // set dir to the elevation angle
dist += h / $$anonymous$$athf.Tan(a); // correct for small height differences
// calculate the velocity magnitude
var vel = $$anonymous$$athf.Sqrt(dist * Physics.gravity.magnitude / $$anonymous$$athf.Sin(2 * a));
return vel * dir.normalized;
}
$$anonymous$$aybe this small explanation with help you with your code.
var Target: Transform;
var grenadePrefab: Transform;
var fireRate = 10;
var attackRange = 20.0;
var Damping = 6.0;
private var Distance : float;
private var nextFireTime = 0.0;
function Start ()
{
Target = PlayerTransform.playerTransform;
}
function Update()
{
Distance = Vector3.Distance(Target.position, transform.position);
if (Distance < attackRange)
{
Fire ();
}
}
function BallisticVel(Target: Transform, angle: float): Vector3 {
var dir = Target.position - transform.position; // get target direction
var h = dir.y; // get height difference
dir.y = 0; // retain only the horizontal direction
var dist = dir.magnitude ; // get horizontal distance
var a = angle * $$anonymous$$athf.Deg2Rad; // convert angle to radians
dir.y = dist * $$anonymous$$athf.Tan(a); // set dir to the elevation angle
dist += h / $$anonymous$$athf.Tan(a); // correct for small height differences
// calculate the velocity magnitude
var vel = $$anonymous$$athf.Sqrt(dist * Physics.gravity.magnitude / $$anonymous$$athf.Sin(2 * a));
return vel * dir.normalized;
}
function ElevationAngle(Target: Transform): float {
// find the cannon->target vector:
var dir = Target.position - transform.position;
// create a horizontal version of it:
var dirH = Vector3(dir.x, 0, dir.y);
// measure the unsigned angle between them:
var ang = Vector3.Angle(dir, dirH);
// add the signal (negative is below the cannon):
return ang;
}
function Fire ()
{
if (Time.time > fireRate + nextFireTime)
{
nextFireTime = Time.time;
FireOneShot();
}
}
function FireOneShot ()
{
var ang = ElevationAngle(Target);
var shootAng = ang +15; //
shootAng = $$anonymous$$athf.Clamp(shootAng, 0, 360);
transform.eulerAngles.z = -shootAng - 15;
var grenade: Transform = Instantiate(grenadePrefab, transform.position, transform.rotation);
var shoot = BallisticVel(Target, shootAng);
shoot = Vector3(Random.Range((shoot.x - 20),(shoot.x + 5)), shoot.y, shoot.z); grenade.GetComponent.<Rigidbody2D>().velocity = shoot; //
BallisticVel(Target, shootAng); // pass the angle and the target transform
}
+++
And still nothing :/
I copy-paste your JS code and its working. Try to remove
function Start ()
{
Target = PlayerTransform.playerTransform;
}
Answer by Voky · Apr 17, 2016 at 06:53 PM
@nebikhero Thx, it´s finally working!!!
One last question: Have you any tip how to easily invert x position of aiming? Because the cannon shoot at the wrong side :D
@Vokyczech Tune this line of code, because now it`s rotating cannon for shooting from right to left. $$anonymous$$ake it positive with desire angle. transform.eulerAngles.z = -shootAng - 15;
Fine, it´s finally done! Thx for your patience and for piece of your own script...
Follow this Question
Related Questions
Linking projectiles to enemy 0 Answers
Why are my instantiated projectiles not firing? 0 Answers
Fireball not moving after time change 0 Answers
Shoot towards target 0 Answers
Unreferenced label? 0 Answers