在一个脚本中单例的时候用另一个脚本调用,不要再awake方法里面调用脚本,那样会空指针,放到start方法里面调用比较好
对于地图中有物体让人物过不去可以添加cube,只留下box collider,一个房子用添加多个cube弄成围墙一样把房子围起来
如果我在update函数中每个2秒调用一次R函数如果采用下面的代码:
private float time=0;
void Update(){
while (time<2)
{
time += Time.deltaTime;
}
time = 0;
R();
}
那么会一直执行R函数,所以应该这样才能达到所要的效果
time += Time.deltaTime;
if (time>2)
{
time = 0;
R();
}
让小怪四处乱转的代码:
transform.Rotate(Vector3.up*Random.Range(0,360));当怪物切换到行走动画时添加这个,由于左转右转都是向y轴,也即上下轴转所以是vector3
怪物收到攻击身体变为红色只需更改GetComponent<Renderer>().material.color
相机镜头的向前移动代码:
那么这里总结一下 vector3.forward和transform.forward的区别。
vector3.forward的值永远等于(0,0,1)。
transform.forward的值则等于当前物体的自身坐标系z轴在世界坐标上指向,因此不一定等于(0,0,1),但是其magnitude长度是1。
transform.position 本身就是世界坐标。
1、transform.position+= vector3.forward
等于是在世界坐标的z轴前进。
2、transform.position+=transform.forward
等于是物体自身坐标系的z轴前进
实现小狼打中的miss效果:
它使用到了NGUI的HUDText插件,导入,可以看到他提供的例子是这样的(就是头上的文字效果):
只需要导入的插件中保留prefab文件夹中的HUDTEXT即可
给他添加UI Follow Target脚本在该脚本中要指定Target,Game Camera和UI camera(是UI Root中的相机),可以看到HUD Text是负责文字显示的,UI Follow Target负责跟随的
给小狼头顶创建一个Gameobject命名为HUDText,我们要创建一个miss效果首先要创建到UIRoot中然后将它跟随到HUDText上,在UIRoot上创建一个invisible weight命名为HudTextParent,在小狼的脚本中这样写
private HUDText hudText;//这个是hudTextGo里面的一个组件
public GameObject hudTextPrefab;//这个是NGUI中prefab中的资源文件
private GameObject hudTextGo;//这个是在游戏中创建的实例
private GameObject hudTextFellow;//这个是在小狼中创建的位置的GameObject
private UIFollowTarget fellowTarget;
在start方法中这样写:
hudTextFellow = transform.Find("HUDText").gameObject;
// hudTextGo = Instantiate(hudTextPrefab,Vector3.zero,Quaternion.identity);
// hudTextGo.transform.parent = HudTextParent._instance.gameObject.transform;
//对于NGUI的创建对象不要用instantiate创建用下面的方法创建
hudTextGo = NGUITools.AddChild(HudTextParent._instance.gameObject, hudTextPrefab);
hudText = hudTextGo.GetComponent<HUDText>();
fellowTarget = hudTextGo.GetComponent<UIFollowTarget>();
fellowTarget.target = hudTextFellow.transform;
fellowTarget.gameCamera = Camera.main;
fellowTarget.uiCamera = UICamera.currentCamera;
在该显示miss效果的时候调用 hudText.Add("Miss",Color.gray,1);让它显示一秒,字体灰色即可
最后记得小狼死亡的时候也要把它销毁:
private void OnDestroy()
{
Destroy(hudTextGo);
}
按ctrl 和加号自动跳转到上一个光标处
对于小狼的攻击动画的代码参考下面代码:
private void Update()
{
if (state==BabyWolfState.attack)//攻击状态
{
AutoAttack();
}
}
//自动攻击函数
void AutoAttack()
{
if (target != null) //找到攻击目标且在最小攻击距离之内就开始攻击,
//在最小攻击距离和最大距离之间,就走过去攻击
{
float distance = Vector3.Distance(target.position, this.transform.position);
if (distance>=maxAttackDistance)
{
target = null;
state = BabyWolfState.idle;
}else if (distance<=minAttackDistance) //自动攻击
{
attackTimer += Time.deltaTime; //一进入自动攻击就开始计时,到了攻击一次的时间就重置
anim.CrossFade(aniName_nowAttack);
if (aniName_nowAttack==aniName_normalAttack)
{
if (attackTimer>time_normalAttack)//当时间超过一次普通攻击时间的动画长度就停下来
{
//TODO产生普通攻击伤害
aniName_nowAttack = anim_idle;
}
}
else if (aniName_nowAttack==aniName_crazyAttack)
{
if (attackTimer > time_crazyAttack)
{
// TODO产生疯狂攻击伤害
aniName_nowAttack = anim_idle;
}
}
if (attackTimer>attackRate)
{
attackTimer = 0;//重置时间
RandomAttack(); //发动下一次攻击
}
}
else //走过去攻击
{
transform.LookAt(target);
cc.SimpleMove(transform.forward);
anim.CrossFade(anim_walk);
}
}
else //攻击目标为空就站立状态
{
state = BabyWolfState.idle;
}
}
void RandomAttack()
{
float a = Random.Range(0f,1f);
if (a>crazyAttack_rate)
{
aniName_nowAttack = aniName_normalAttack;
}
else
{
aniName_nowAttack = aniName_crazyAttack;
}
}
对于人物的状态划分,可以枚举好几种状态,第一个
public enum PlayerState { //非攻击状态,普攻状态和技能攻击状态
ControlWalk,
NormalAttack,
SkillAttack
}
第二个
public enum AttackState //攻击状态的分类,包括攻击的移动状态,攻击的站立状态和攻击状态
{
Moving,
Idle
Attack
}
在ControlWalk的非攻击状态下包括人物的站立,行走动画,在攻击状态下也包含人物的行走,站立动画
先说普通技能攻击怪物的步骤:
在PlayerAttack脚本中update中if检测鼠标左键进行射线检测,tag是怪物将state置为PlayerState.NormalAttack否则没有点到怪物就state置为PlayerState.ControlWalk,在update中当state为NormalAttack检测角色和怪物距离是否超过法师攻击最小距离,在距离之内面向怪物,播放当前动画(默认为普攻动画),开始计时,当时间超过普通动画时间就将当前标志位设为站立,当时间超过一次攻击速度就state设为NormalAttack进行下一次普攻,如果超过攻击距离,就attackState = AttackState.Moving;让人物走过去
参考代码:
public enum PlayerState { //非攻击状态,普攻状态和技能攻击状态
ControlWalk,
NormalAttack,
SkillAttack
}
public enum AttackState //攻击状态的分类,包括攻击的移动状态,攻击的站立状态和攻击状态
{
Moving,
Idle,
Attack
}
public class PlayerAttack : MonoBehaviour {
public PlayerState state = PlayerState.ControlWalk;
public string animName_NormalAttack;
public string animName_Idle;
public string animName_now;
public float time_NormalAttack;
public float min_distance = 5;
public float timer = 0;
private Transform target_normalAttack;
private PlayerDir dir;
public AttackState attackState = AttackState.Idle;
private Animation anim;
public float rate_NormalAttack;
public GameObject flash;
private bool isShowflash = false;
private void Start()
{
dir = GetComponent<PlayerDir>();
anim = GetComponent<Animation>();
}
void Update () {
if (Input.GetMouseButtonDown(0)) //鼠标左键让人物行走时进行射线检测
{
RaycastHit hitInfo;
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
bool isCollider = Physics.Raycast(ray, out hitInfo);
//不是hitInfo.tag而是hitInfo.collider.tag
if (isCollider&&hitInfo.collider.tag==Tags.enemy)
{
//点击到了敌人就获取到敌人的位置
target_normalAttack = hitInfo.collider.transform;
state = PlayerState.NormalAttack;
timer = 0;
isShowflash = false;
}
else //没有点击到敌人切换为行走状态且目标为空
{
state = PlayerState.ControlWalk;
target_normalAttack = null;
}
}
if (state==PlayerState.NormalAttack)
{
if (target_normalAttack==null) {
//如果怪物已经打死了消失了,就切换为行走模式
state = PlayerState.ControlWalk;
}
else {
float distance = Vector3.Distance(transform.position,target_normalAttack.position);
if (distance<min_distance)//攻击
{
//面向怪物
Vector3 v = new Vector3(target_normalAttack.position.x, transform.position.y, target_normalAttack.position.z);
transform.LookAt(v);
attackState = AttackState.Attack;
timer += Time.deltaTime;
anim.CrossFade(animName_now);
if (timer>time_NormalAttack) //一次普攻的释放时间结束就处于站立状态
{
animName_now = animName_Idle;
//显示特效
if (isShowflash==false) {
isShowflash = true;
//让小狼受到伤害
target_normalAttack.GetComponent<BabyWolf>().TakeDamage(10);
GameObject.Instantiate(flash, target_normalAttack.position,Quaternion.identity);
}
}
if (timer>(1f/rate_NormalAttack))
{
timer = 0;//切记一定要归零
isShowflash = false;
animName_now = animName_NormalAttack;
}
}
else
{
//走过去
attackState = AttackState.Moving;
dir.SimpleMove(target_normalAttack.position);
}
}
}
}
}
这里有个问题在小狼死的时候要通知小狼产生器当前小狼的数量减一,但是小狼是在prefab中没法拿到小狼孵化器的脚本,这样做,在小狼脚本public 定义一个孵化器脚本名为bp,在小狼孵化器脚本产生了一个小狼的Gameobject为go,那么go.GetComponent<BabyWolf>().bp = this;就可以让小狼获取到了孵化器