我的目标是编写一个可以在不同游戏对象上使用的脚本,并且该脚本应该在该游戏对象上具有与之相关的特定变量,而不会影响该过程中的其他脚本。
例如,如果我使用此脚本并将其放在两个游戏对象上,则每个游戏对象在同一脚本中应具有自己的唯一变量值。
如果我的问题还不够清楚,我很乐意进一步阐述。
我对Unity编辑器有很好的了解,但是,我对C#还是很陌生,所以我认为在代码中的某个地方出现菜鸟错误并不觉得不合理。
设置的方式是,我有两个单独的脚本:
Fighting
控制诸如Team
,Health
,Attack Damage
,Cool Down
,Cooling down
和{{1} }
Snap
控制是否检测到由于敌人进入触发半径而激活的触发。
我目前遇到的问题在于我猜的TrigDetect
脚本。
还应注意,有问题的每个游戏对象附带的空白都包含这两个脚本,并标记为“部队”。
TrigDetect
TrigDetect
战斗
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TrigDetect : MonoBehaviour
{
//public GameObject[] Enemy;
bool once = false;
void OnTriggerEnter(Collider other)
{
if (other.CompareTag("Troop"))
{
//Debug.Log("Entered");
}
}
void OnTriggerExit(Collider other)
{
if (other.CompareTag("Troop"))
{
//Debug.Log("Exitted");
}
}
void OnTriggerStay(Collider other)
{
if (other.CompareTag("Troop"))
{
Fighting self = GetComponent<Fighting>();
GameObject g = GameObject.Find("Detection");
Fighting fScript = g.GetComponent<Fighting>();
//Enemy = GameObject.FindGameObjectsWithTag("Troop");
//Debug.Log("Staying");
//Debug.Log(Enemy);
//Debug.Log(self.Health);
//Debug.Log(fScript.Health);
if (once == false)
{
Debug.Log("I am the team:" + self.Team);
Debug.Log("I have detected the team:" + fScript.Team);
once = true;
}
if (self.Team != fScript.Team)
{
if (self.CoolingDown == false)
{
self.CoolingDown = true;
fScript.Health -= self.AttackDamage;
}
else
{
self.CoolDown -= Time.deltaTime;
if (self.CoolDown <= 0)
{
self.CoolingDown = false;
self.CoolDown = self.original;
}
}
}
}
}
}
当我将一个游戏对象移动到另一个对象的触发半径中时,预期结果是它们应该都开始基于using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Fighting : MonoBehaviour
{
public int Team = 1;
public int Health = 100;
public int AttackDamage = 10;
public float CoolDown = 2;
public float original = 2;
public bool CoolingDown = false;
public bool Snap = false;
// Update is called once per frame
void Update () {
if (Snap == true || Health <= 0)
{
//Destroy(gameObject, .5f);
Destroy(transform.parent.gameObject);
}
if (Input.GetKey(KeyCode.N)) Instantiate(transform.parent.gameObject);
}
}
值相互减去Health
。每当AttackDamage
值为false时,他们就应该这样做。执行攻击后,它会翻转到CoolingDown
并启动一个计时器,计时器完成后它会翻转回到true
。
但是,在将两个对象移动到彼此的半径中时,第一个对象的健康状况如预期的那样消失,然后继续执行任何操作,直到其健康状况达到false
,然后由于对象攻击而死亡。攻击对象已成功攻击了另一个对象,但仍不受其攻击对象的影响。
答案 0 :(得分:5)
基本上,g = Find(name)
仅返回该名称的任何内容的第一个实例,因此几乎可以保证您的OnTriggerStay(Collider other)
永远不会永远成为与您的触发/冲突条件相关的对象。 GameObject g = GameObject.Find("Detection");
Fighting fScript = g.GetComponent<Fighting>();
已经为您提供了位于触发区域中的“其他”对撞机,因此请使用它。 :)
替换此:
Fighting fScript = other.GetComponent<Fighting>();
与此:
#include <bitset>
...
std::bitset<128> bs;
bs[0] = 1; bs[127] = 1;
std::cout << bs.to_string() << std::endl;
// prints 128 digits with ones on both ends
答案 1 :(得分:2)
到您的问题标题:
每个不变的(非静态)值对于相应组件始终是唯一的,因此对于附加到的相应GameObject
也是唯一的。您可能想换个问题,因为这实际上不是您的问题。
问题在于,当您这样做
GameObject.Find("Detection");
它实际上两次都找到了相同对象:即层次结构中的第一个对象。因此,在这两个组件之一中,您将找到自己的空对象,并在
中跳过其余部分if(self.Team != FScript.Team)
..您可以尝试使用
other.Find("Detection");
只能在相应的上下文中搜索。.但是,您完全不应该使用Find
!
您不需要这种情况
由于您说两个脚本都附加到了同一对象,因此您可以简单地使用
GetComponent<Fighting>();
,您可以在Awake
中这样做,并重新使用引用:
private Fighting myFighting;
private void Awake()
{
myFighting = GetComponent<Fighting>();
}
除了碰撞之外,您也不必使用Find
,因为您已经有了与之碰撞的对象的引用:other.gameObject
。我不知道您的整个设置,但是您可以在层次结构中向下搜索该组件
// the flag true is sued to also find inactive gameObjects and components
// leave it without parameters if you don't want this
var otherFighting = other.GetComponentInChildren<Fighting>(true);
或在层级中向上滑动
var otherFighting = other.GetComponentInParent<Fighting>(true);
或者如果您已经知道自己与正确的GameObject完全碰撞,则只需使用
var otherFighting = other.GetComponent<Fighting>();
在我的示例中将使用后者。
Update
中的无处不在比健康更是一个巨大的性能问题。您应该有一个方法,例如TakeDamage
,仅在您的健康状况实际发生变化时进行检查:
战斗
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Fighting : MonoBehaviour
{
public int Team = 1;
public int Health = 100;
public int AttackDamage = 10;
public float CoolDown = 2;
public float original = 2;
// you don't need that flag see below
//public bool CoolingDown = false;
public bool Snap = false;
private void Update()
{
// you might also put this in a callback instead of update at some point later
if(Snap == true)
{
Destroy(transform.parent.gameObject);
}
// Note: this also makes not muh sense because if you destroyed
// the parent than you cannot instantiate it again!
// use a prefab instead
if (Input.GetKey(KeyCode.N)) Instantiate(transform.parent.gameObject);
}
public void TakeDamge(int DamageAmount)
{
Health -= DamageAmount;
if (Health > 0) return;
Destroy(transform.parent.gameObject);
}
}
另一个普遍的性能问题:即使Start
,Update
等为空,如果脚本中存在它们,Unity也会调用它们。因此,如果您不使用它们,则将它们完全删除以避免不必要的开销。
所以我会
TrigDetect
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TrigDetect : MonoBehaviour
{
bool once = false;
private Fighting myFighting;
private void Awake()
{
myFighting = GetComponent<Fighting>();
}
void OnTriggerStay(Collider other)
{
// if wrong tag do nothing
if (!other.CompareTag("Troop")) return;
Fighting fScript = other.GetComponent<Fighting>();
// here you should add a check
if(!fScript)
{
// By using the other.gameObject as context you can find with which object
// you collided exactly by clicking on the Log
Debug.LogError("Something went wrong: Could not get the Fighting component of other", other.gameObject);
}
if (!once)
{
Debug.Log("I am the team:" + self.Team);
Debug.Log("I have detected the team:" + fScript.Team);
once = true;
}
// if same team do nothing
if (self.Team == fScript.Team) return;
// you don't need the CoolingDown bool at all:
self.CoolDown -= Time.deltaTime;
// if still cooling down do nothing
if(self.CoolDown > 0) return;
fScript.TakeDamage(self.AttackDamage);
self.CoolDown = self.original;
}
}