- Home /
Detect Shield Mesh Sides Hit
Hey everyone trying to make a 3d mesh shield that can take damage based on side hit. So detect top, bottom, fore, aft, left, right shield hits and those sides take float damage. Right now its working as a single shield and takes damage. Any ideas?
Current weapon script…
using UnityEngine;
using System.Collections;
[RequireComponent(typeof(LineRenderer))]
public class BeamArray : MonoBehaviour
{
LineRenderer line;
public Material lineMaterial;
bool phaser = false;
public AudioClip sound;
void Start()
{
line = GetComponent<LineRenderer>();
line.SetVertexCount(2);
line.renderer.material = lineMaterial;
line.SetWidth(0.1f, 0.25f);
line.enabled = false;
}
void Update()
{
var script = GameObject.Find("aaMain Camera").GetComponent<SelectTarget>();
if(Input.GetKeyDown("space") && phaser == false && script.gui == "yes")
{
phaser = true;
StartCoroutine (pulsetime());
}
}
IEnumerator pulsetime()
{
var script = GameObject.Find("aaMain Camera").GetComponent<SelectTarget>();
line.enabled = true;
AudioSource.PlayClipAtPoint(sound, Camera.main.transform.position);
RaycastHit hit;
if (Physics.Linecast(transform.position, script.selectedTarget.transform.position, out hit))
{
// call ApplyDamage(10) in the hit object:
hit.transform.SendMessage("ApplyDamage", 700, SendMessageOptions.DontRequireReceiver);
}
//wait the cooldown time in a loop
float delay = 1.680f;
while (delay > 0)
{
//update beam endpoints
if(script.Shields == false)
{
line.SetPosition(0, transform.position);
line.SetPosition(1, script.selectedTarget.transform.position);
}
if(script.Shields == true)
{
line.SetPosition(0, transform.position);
line.SetPosition(1, hit.point);
script.selectedTarget.GetComponent<MeshRenderer>().enabled = true;
}
//decrement delay time
delay -= Time.deltaTime;
//let unity free until next frame
yield return null;
}
line.enabled = false;
phaser = false;
script.selectedTarget.GetComponent<MeshRenderer>().enabled = false;
}
}
How about separate colliders for each section of the shield? You'd have to have a distinct GameObject for each section but they could be children of the Ship or Shield GameObject.
A simpler solution would be to look at the hit position relative to the ships position, and deter$$anonymous$$e left, right, top etc from that. It wouldn't quite have the precision of separate colliders but it's much simpler and might be good enough for your purposes.
Answer by Tomer-Barkan · Nov 05, 2013 at 11:40 PM
No, it's not beyond the capabilities of Unity.
How about you calculate the vector that points from your ship to the target ship, and then using that vector and the enemy ship's "Forward" vector, you can calculate where the ship was hit:
Vector3 toTarget = script.selectedTarget.transform.position - transform.position;
Vector3 targetForward = script.selectedTarget.transform.forward; // change to transform.up if it's 2d and the ship faces upwards
float angle = Vector3.Angle(toTarget, targetForward);
if (angle < 45) {
// less than 45 degrees difference, means we hit him from behind:
DamageShield("Behind");
} else if (angle > 135) {
// more than 135 degrees means the vectors are almost facing each other, so we hit the forward shields:
DamageShield("Forward");
} else {
// degree is between 45 and 135 so we hit from one of the sides. Need to calculate which:
Vector3 targetRight = script.selectedTarget.transform.right;
// calculate angle between firing vector and target's right vector
float rightAngle = Vector3.Angle(toTarget, targetRight);
if (rightAngle < 45) {
// degree less than 45 percent, so we hit behind the right vector, which means we hit the left side of the shields
DamageShield("Left");
} else {
DamageShield("Right");
}
}
Of course there are other ways to go about it (several colliders for instance), but this is the simplest way and it should do just fine for most games.
If you want to be even more accurate, instead of using the shooter's position in toTarget, use the position where the weapon hit the shields.
Edit: A solution for working with 6 sides (3d), would be to calculate the angle between the vector pointing from the target center to the hit position, and the 6 directions of the target (forward, back, top, bottom, left, right). The one with the smallest angle is the one that was hit:
if(script.Shields == true)
{
print("shields true and getting side hit");
// vector from the target center to the hit position
Vector3 hitDirection = hit.point - script.selectedTarget.transform.position;
Transform targetTransform = script.selectedTarget.transform;
float angleForward = Vector3.Angle(hitDirection, targetTransform.forward);
float angleBack = Vector3.Angle(hitDirection, -(targetTransform.forward));
float angleRight = Vector3.Angle(hitDirection, targetTransform.right);
float angleLeft = Vector3.Angle(hitDirection, -(targetTransform.right));
float angleTop = Vector3.Angle(hitDirection, targetTransform.up);
float angleBot = Vector3.Angle(hitDirection, -(targetTransform.up));
string shieldHit = "";
float minAngle = 180;
if (angleForward < minAngle) {
shieldHit = "Forward";
minAngle = angleForward;
}
if (angleBack < minAngle) {
shieldHit = "Back";
minAngle = angleBack;
}
if (angleRight < minAngle) {
shieldHit = "Right";
minAngle = angleRight;
}
if (angleLeft < minAngle) {
shieldHit = "Left";
minAngle = angleLeft;
}
if (angleTop < minAngle) {
shieldHit = "Top";
minAngle = angleTop;
}
if (angleBot < minAngle) {
shieldHit = "Bottom";
minAngle = angleBot;
}
print("Shields hit: " + shieldHit);
}
Note: A cleaner solution would use an array and a for loop, but this is more readable so I use it like this for the sake of the answer.
toTarget should be the vector from the hitpoint to the target, not just the hitpoint:
Vector3 toTarget = script.selectedTarget.transform.position - hit.point
we're trying to calculate which part of the shield was hit (the hit point relative to the target), not the world position of the hit.
Then you have to make sure that you enable and disable the shields correctly. The problem might be somewhere in your game logic, because the calculation of where the shields are hit seems to be working correctly.
One thing I noted - you check for script.Shields
, but script
is the camera game object. Is that really where you store the status of your shields? In the camera?
Hmmm.. I'm assu$$anonymous$$g your ship is facing forward. (Z axis).
Try adding:
toTarget.z = 0;
right after calculating toTarget
. This will flatten it for the shield calculations.
It's not... I've never seen games with bottom/top shields. Aren't 4 shields enough (so that if it hits the bottom a bit behind, it will be the aft shields, etc)?
The only other trick I can think that will take into account bot/top is to compare the angle of the hit with each of the directions (front/back/left/right/top/bot), and wherever the angle is the smallest, that is the hit:
// vector from the target center to the hit position
Vector3 hitDirection = hit.point - script.selectedTarget.transform.position;
Transform targetTransform = script.selectedTarget.transform;
float angleForward = Vector3.Angle(hitDirection, targetTransform.forward);
float angleBack = Vector3.Angle(hitDirection, -(targetTransform.forward));
float angleRight = Vector3.Angle(hitDirection, targetTransform.right);
float angleLeft = Vector3.Angle(hitDirection, -(targetTransform.right));
float angleTop = Vector3.Angle(hitDirection, targetTransform.up);
float angleBot = Vector3.Angle(hitDirection, -(targetTransform.up));
Then compare all the angles, and the one with the smallest angle is the one you want.
Note - please make sure that the transform.position of the target is actually the center of the target, or that will not work.
Try my last code section with 6 shield parts, let me know if it works like you expect. If it does, I can change it to 4 sections, if you prefer.
Your answer
Follow this Question
Related Questions
I'm trying to add a hitbox to a player. Can I add it to the mesh? 3 Answers
shield if hit get visible? 0 Answers
barycentricCoordinate always return vector(1,0,0) 0 Answers
if shield got hit show 1 Answer
Raycast bug? 1 Answer