Area Effect Damage

I have a script on a cannonball so that when it hits a target directly, it kills them instantly, if it hits near them, they might die instantly, or they might get severely damage. If they’re farther away, less damaged, etc. So I tried doing that with this script:

#pragma strict

var explosion : GameObject;
var blast : AudioClip;
var waterHit : GameObject;
var waterBlast : AudioClip;
var target : Transform;
var closeAreaEffect : float = 1.5;
var mediumAreaEffect : float  = 3;
var farAreaEffect : float = 5;
private var speed : float = 100;
private var destroyTime : float = 5;
private var detachChildren : boolean = false;
private var closeDamage : float = 100;
private var mediumDamage : float = 50;
private var farDamage : float = 25;

function Update ()
{
	transform.Translate(Vector3.forward * Time.deltaTime * speed);
}

function Awake ()
{	
Invoke ("DestroyNow", destroyTime);
}

function DestroyNow ()
{	
	if (detachChildren) {
		transform.DetachChildren ();
	}	
	DestroyImmediate(gameObject);
}

function OnCollisionEnter (collision : Collision) {

		if(collision.gameObject.CompareTag("British")){
	Instantiate(explosion, transform.position, transform.rotation);
	audio.PlayOneShot(blast);
	}	
		if(collision.gameObject.CompareTag("Terrain")){
	Instantiate(explosion, transform.position, transform.rotation);
audio.PlayOneShot(blast);	
	}
		if(collision.gameObject.CompareTag("Water")){
	Instantiate(waterHit, transform.position, transform.rotation);
audio.PlayOneShot(waterBlast);	
	}		
	Destroy(gameObject);

var distance = Vector3.Distance(target.transform.position, transform.position);

		if(collision.gameObject.CompareTag("British")){        
	collision.collider.gameObject.SendMessage("ApplyDamage", closeDamage, SendMessageOptions.DontRequireReceiver);
	}
		if(collision.gameObject.CompareTag("British") && distance <= closeAreaEffect){        
	collision.collider.gameObject.SendMessage("ApplyDamage", closeDamage, SendMessageOptions.DontRequireReceiver);
	}
		if(collision.gameObject.CompareTag("British") && distance <= mediumAreaEffect){        
	collision.collider.gameObject.SendMessage("ApplyDamage", mediumDamage, SendMessageOptions.DontRequireReceiver);
	}
		if(collision.gameObject.CompareTag("British") && distance <= farAreaEffect){        
	collision.collider.gameObject.SendMessage("ApplyDamage", farDamage, SendMessageOptions.DontRequireReceiver);
	}
}	

@script RequireComponent(Rigidbody);

The problem with this script is that the only way for it to calculate the distance is according to it’s target. Well the target is a transform, but the cannonball itself is a GameObject, so I can’t assign the transform. How should I change this?

The idea should be modified a little: in a explosion, objects that are near but were not directly hit should also be damaged. It’s usually done with Physics.OverlapSphere centered at the explosion position, and with a farAreaEffect radius: this function returns an array of all colliders that intersect the spherical volume, and you can check the individual distances to apply the damage. You could modify the last part of the OnCollisionEnter function this way:

function OnCollisionEnter (collision : Collision) {

    if (collision.gameobject.CompareTag("British")){
        Instantiate(explosion, transform.position, transform.rotation);
        audio.PlayOneShot(blast);
    }  
    if (collision.gameobject.CompareTag("Terrain")){
        Instantiate(explosion, transform.position, transform.rotation);
        audio.PlayOneShot(blast);   
    }
    if (collision.gameobject.CompareTag("Water")){
        Instantiate(waterHit, transform.position, transform.rotation);
        audio.PlayOneShot(waterBlast);  
    }   
    Destroy(gameObject);

    // This is the modified part:
    // find the colliders inside a sphere of radius farAreaEffect
    var colls = Physics.OverlapSphere(transform.position, farAreaEffect);
    for (var col: Collider in colls){
        if (col.CompareTag("British")){ // if it's a bloody British...
            // calculate the distance from the impact...
            var distance = Vector3.Distance(col.transform.position, transform.position);
            var damage = farDamage; // assume farDamage initially...
            if (distance <= closeAreaEffect){
                damage = closeDamage; // but if inside close area, change to max damage
            }
            else 
            if (distance <= mediumAreaEffect){
                damage = mediumDamage; // else if inside medium area, change to medium damage
            }
            // apply the selected damage
            col.SendMessage("ApplyDamage", damage, SendMessageOptions.DontRequireReceiver);
        }
    }
}   

http://unity3d.com/support/documentation/ScriptReference/Collision-contacts.html
With this you can get the position of where your cannonball hit. but from that position i would probably use a physics overlap sphere to populate an array of who should take any damage. Then you could do a foreach loop to apply it to only whoever you want. Or perhaps 3 overlap spheres with different radius’ that way enemies near the hit would be detected in all 3 (3x damage), middle would be detected by only mid and near, and those at the outer radius would only be detected by 1.