日期:2014-05-17  浏览次数:20767 次

unity3d学习笔记(十八)--利用C#的代理和事件结合NGUI的按钮实现施放技能

本系列文章由Aimar_Johnny编写,欢迎转载,转载请标明出处,谢谢。

http://blog.csdn.net/lzhq1982/article/details/12999381


对C#还不是很熟,在学习的过程中了解到C#有种代理和事件的机制很方便,之前用cocos2d的时候也用过代理,虽然此代理非彼代理,但他们的作用有相似之处,都是触发者只是告知事件,并不调用相关类和方法实现,而是由代理方法实现,可能有些难懂,下面我用之前的demo中英雄施放技能这里做个试验。

本篇涉及三个知识点,一个是最重要的代理,一个是NGUI的按钮,一个是施放技能特效。


1、NGUI制作技能按钮

关于NGUI我前面的文章说了好多,重复的部分我就不介绍了。我打算把技能按钮放在NGUI界面布局的右下角锚点处,先在右下角锚点处加个Panel,我起名SkillPanel,在该Panel下我建立一个按钮,选NGUI->Open the Widget Wizard,Atlas选你将图片打包的那个文件,没有的话先建立一个,不知道怎么建的看前面的文章。Template里选Button,然后会出现Background,是按钮图片,从Atlas中选一个,我的设置如下:


选择Add To后SkillPanel下新增一个按钮,我起名ZhongJiButton,布局如下:


调整位置,我的按钮截屏如下(右下角那个):



2、利用C#的代理和事件施放技能。

要施放技能,肯定要点击按钮,NGUI为按钮提供了OnClick接口。我们先创建一个脚本,我命名CastSkill,然后拖到ZhongJiButton上,CastSkill里只要实现OnClick接口就好了。一般我们会怎么实现点击施放呢,最传统的做法就是获得英雄的对象,然后利用该对象向她传递施放技能的消息,比如代码如下:

void OnClick() {
	GameObject hero = GameObject.Find("Blade_Girl_Prefab");
	if (hero)
		hero.SendMessage("CastSkill", 1);
}
像上面我通知hero的CastSkill接口,传递的参数1是SkillID,很简单,这就实现了,但你有没有想过,这又陷入了脚本之间耦合性的增加,看过我前面单例脚本和单例类这篇文章应该明白脚本之间大量的互相访问不是件好事。那我们就看看代理能不能帮我们解决办法。

想了解什么是代理和怎么用代理的可以看这篇文章,写的挺全的:C#中的代理与事件,重点看里面的一和三,我就偷个懒,只说明我这里是怎么实现的。现在我用代理重新改一下上面的脚本:

public class CastSkill : MonoBehaviour {
	public delegate void EventHandler(int nSkillId);
	public event EventHandler OnCastSkill;
	
	void OnClick() {
		if (OnCastSkill != null)
			OnCastSkill(1);
	}
}

可以看出上面先创建了一个代理EventHandler,传递一个参数nSkillId,然后创建该代理的一个事件OnCaskSkill,在OnClick里触发这个事件OnCastSkill(1),“1”是代理传递的那个参数nSkillId。你会发现这里根本没有Hero的事,那Hero怎么接收消息呢。下面我们看看Hero相关的代码。

CastSkill onCastSkill = skillBtn.GetComponent<CastSkill>();
onCastSkill.OnCastSkill += CastSkill;
void CastSkill(int nSkillId)
{
	if (curState == en_state.en_state_idel || curState == en_state.en_state_attack) {
		if (nSkillId == 1) {
			lastState = curState;
			curState = en_state.en_state_skill;
		}
	}
}

在Hero里,我先是获得按钮的那个脚本CaskSkill对象,重点是下面那句,我为OnCastSkill这个事件挂接了实现的方法CastSkill,然后你就可以在CastSkill里实现释放技能了。所谓代理,就是触发者根本就不用关心到底是谁接收了,而接受者只要调用该代理事件,并挂接个实现方法就OK了,这样只要触发者一触发,凡是挂接过该事件的方法都会响应,这就是代理。不知道您明白了吗。


3、施放技能
如上面代码,我给英雄置了当前状态为技能状态,她会在Update的状态机里处理,调用playEffect函数。

void playEffect()
{
	if (!animation.IsPlaying("ComboAttack"))
		gameObject.animation.CrossFade("ComboAttack");

	AnimationState state = animation["ComboAttack"];
	if (state.time >= state.length-0.5f && !isCastSkill) {			
		Vector3 pos = transform.position + transform.TransformDirection(Vector3.forward*3);
		Instantiate(effect, pos, transform.rotation);
		isCastSkill = true;
	}
		
	if (isCastSkill && state.time >= state.length-0.1f) {
		isCastSkill = false;
		curState = lastState;
	}
}



上面代码大致意思是先播放动作,当动作播放到一半的时候播放特效,我这里特效是个prefab,特效只播放一次,所以isCastSkill是用来控制播放次数的,因为特效要播放在角色身前,所以上面获取pos那句代码是根据角色的位置加上其朝向前方3个单位的距离获得的。最后上个图吧。


在这里谢谢各位的支持,使得本系列文章被csdn在博客首页和个人页侧边栏推荐为最新精华博文,本人不胜感激,受宠若惊,今后当更加努力,希望能多多的帮助他人,哈哈,也希望大家多提宝贵意见,小弟在这里拜谢了。