2015-06-26 16:10:41 lfh719852029 阅读数 2619

       之前的项目中有用虚拟摇杆来操纵角色移动,但是之前使用的是EasyTouch,属于NGUI下的一个插件,但是本身项目是基于UGUI的,觉得这样掺杂在一起有些不伦不类,就自己用UGUI做了一个简易的虚拟摇杆(可以实现给角色移动脚本发出摇杆的偏移参数类似于EasyTouch),若要实现更加复杂的功能,可以参照EasyTouch自行编写。

       不多说下面开始实现步骤:(写这篇文章的时候离制作有些久了,有些地方可能有遗忘或者错误请见谅)

一、UGUI上接受拖拽事件。

       我们项目基于Android平台,所以要考虑一些点击,拖动什么的能不能得到相应,然后在网上搜到了这篇帖子:

(雨松MOMO:UGUI研究院之控件以及按钮的监听事件系统(五))原文:http://www.xuanyusong.com/archives/3325


这是监听事件的脚本:EventTriggerListener.cs


using UnityEngine;
using System.Collections;
using UnityEngine.EventSystems;

public class EventTriggerListener : UnityEngine.EventSystems.EventTrigger
{
	public delegate void VoidDelegate (GameObject go);
	public VoidDelegate onClick;
	public VoidDelegate onDown;
	public VoidDelegate onEnter;
	public VoidDelegate onExit;
	public VoidDelegate onUp;
	public VoidDelegate onSelect;
	public VoidDelegate onUpdateSelect;
	
	static public EventTriggerListener Get (GameObject go)
	{
		EventTriggerListener listener = go.GetComponent<EventTriggerListener>();
		if (listener == null) listener = go.AddComponent<EventTriggerListener>();
			return listener;
	}

	public override void OnPointerClick(PointerEventData eventData)
	{
		if(onClick != null) 	onClick(gameObject);
	}

	public override void OnPointerDown (PointerEventData eventData)
	{
		if(onDown != null) onDown(gameObject);
	}

	public override void OnPointerEnter (PointerEventData eventData)
	{
		if(onEnter != null) onEnter(gameObject);
	}

	public override void OnPointerExit (PointerEventData eventData)
	{
		if(onExit != null) onExit(gameObject);
	}

	public override void OnPointerUp (PointerEventData eventData)
	{
		if(onUp != null) onUp(gameObject);
	}

	public override void OnSelect (BaseEventData eventData)
	{
		if(onSelect != null) onSelect(gameObject);
	}

	public override void OnUpdateSelected (BaseEventData eventData)
	{
		if(onUpdateSelect != null) onUpdateSelect(gameObject);
	}
}


二、虚拟摇杆的实现

using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using UnityEngine.Events;

public class JoyStick : MonoBehaviour 
{
	public float fJoyTouchRadius;
	public float fJoyAreaRadius;
	
	private Image joyTouchImage;
	private Image jouAreaImage;

	private bool bIsActived;//是否触发
	public bool BIsActived
	{
		get{ return bIsActived; }
	}
	
	private bool bIsLocked = false;//是否上锁
	public bool BIsLocked
	{
		get{ return bIsLocked; }
		set
		{ 
			bIsLocked = value; 
			if(bIsLocked)
			{
				if(joyTouchImage)
				{
					joyTouchImage.transform.position = initPos;
					//将偏移量归零
					JoyStickAxis = Vector2.zero;
					//角色移动函数
					if(joyStickMoveEnd != null)
						joyStickMoveEnd();
				}
			}
		}
	}
	private float fDragRadius;//可拖动的半径
	private Vector3 initPos;//初始位置
	private float fScreenRate;//屏幕比率
	private Vector2 JoyStickAxis;//用来传值给角色控制器
	
	//角色移动代理函数
	public delegate void JoyStickMove(Vector2 joyStickOffset);
	public static event JoyStickMove joyStickMove;
	
	//角色停止移动代理函数
	public delegate void JoyStickMoveEnd();
	public static event JoyStickMoveEnd joyStickMoveEnd;
	
	void Start () 
	{
		//我这边自己做的自适应,后面的GlobalManager.iScreenWitdh是你默认的屏幕宽度,其实可以用UGUI里面的
		//Horizontal Layout Group来控制自适应
		fScreenRate = (float)Screen.width / GlobalManager.iScreenWitdh;
		joyTouchImage = transform.FindChild("JoyTouch").GetComponent<Image>();
		jouAreaImage = transform.FindChild("JoyArea").GetComponent<Image>();
		
		//设置joystick的大小
		joyTouchImage.rectTransform.localScale = new Vector2 (fJoyTouchRadius, fJoyTouchRadius);
		jouAreaImage.rectTransform.localScale = new Vector2 (fJoyAreaRadius, fJoyAreaRadius);
		
		//可拖拽的半径
		fDragRadius = jouAreaImage.rectTransform.rect.width * fJoyAreaRadius * fScreenRate * 0.5f;
		
		initPos = new Vector3 (1, 1, 0) * fDragRadius * 1.2f;//1.2距离侧边的距离放大1.2倍,这边可以自己后面更改
		
		joyTouchImage.transform.position = initPos;
		jouAreaImage.transform.position = initPos;
		
		//给joytouch注册事件
		EventTriggerListener.Get (joyTouchImage.gameObject).onDown = OnJoyTouchDown;
		EventTriggerListener.Get (joyTouchImage.gameObject).onUp = OnJoyTouchUp;
		
		//给joyarea注册事件
		EventTriggerListener.Get (jouAreaImage.gameObject).onDown = OnJoyTouchDown;
		EventTriggerListener.Get (jouAreaImage.gameObject).onUp = OnJoyTouchUp;
	}
	
	void Update()
	{
		#if UNITY_ANDROID
//		if (Input.touchCount > 1)
//			return;
		//这边会有一个bug就是当你在拖拽摇杆的时候,点击屏幕别的地方,摇杆会向点击处偏移
		//我没有找到很好的解决方法,暂时是用多点触控屏蔽的方法
		#endif
		
		if(bIsActived && !bIsLocked)
		{
			//joy世界坐标坐标
			Vector3 wJoyTouchPos = joyTouchImage.transform.position;
			
			//鼠标屏幕坐标
			Vector3 mScreenPosition = new Vector3 (Input.mousePosition.x, Input.mousePosition.y, wJoyTouchPos.z);
			
			//获得鼠标和对象之间的偏移量,拖拽时相机应该保持不动
			Vector3 offset = wJoyTouchPos - mScreenPosition;		
			
			//对象新坐标 
			joyTouchImage.transform.position -= offset;
			
			//判断与初始位置的距离,之所以不用世界坐标是因为本身半径要转化为世界坐标的半径,麻烦
			float fDis = Vector3.Distance(joyTouchImage.transform.position, initPos);
			
			//当相对位置大于可拖动的半径的时候,按比例缩减
			if(fDis > fDragRadius)
			{
				joyTouchImage.transform.position = initPos + 
					(joyTouchImage.transform.position - initPos) * fDragRadius / fDis;
			}
			
			//虚拟摇杆偏移量
			JoyStickAxis.x = (joyTouchImage.transform.position.x - initPos.x) / fDragRadius;
			JoyStickAxis.y = (joyTouchImage.transform.position.y - initPos.y) / fDragRadius;

			//角色移动函数
			if(joyStickMove != null)
				joyStickMove(JoyStickAxis);
		}
	}
	
	//当触碰虚拟摇杆的进入
	private void OnJoyTouchDown(GameObject go)
	{
		if(go == joyTouchImage.gameObject || go == jouAreaImage.gameObject)
		{
			bIsActived = true;
		}
	}
	
	//当触碰虚拟摇杆的退出
	private void OnJoyTouchUp(GameObject go)
	{
		if(go == joyTouchImage.gameObject || go == jouAreaImage.gameObject)
		{
			bIsActived = false;

			//回到原位
			joyTouchImage.transform.position = initPos;
			//将偏移量归零
			JoyStickAxis = Vector2.zero;

			//角色停止移动函数
			if(joyStickMoveEnd != null)
				joyStickMoveEnd();
		}
	}
}
该脚本的核心处就是Update里面,我写的效率不是很高,可以自行改写。


三、具体操作方式

1.在canvas下创建一个空的JoyStick,该joyStick放在canvas的最下面,否则会被其他控件覆盖掉(UGUI就是这点很烦不能更改控件的Depth)。

2.在joystick下创建2个sprite,给两张转为2dSperite的图片(joyTouch在joyArea的下面)输入缩放大小,本来我这边还有参数设置初始位置,但是后面做自适应找到一个比较适中的值就去掉了,需要的可以自行编写。

3.在角色控制移动脚本处

加入:

void OnEnable()  
{  
	JoyStick.joyStickMove += JoystickMove;
	JoyStick.joyStickMoveEnd += JoystickMoveEnd;
} 

void OnDisable()  
{  
	JoyStick.joyStickMove -= JoystickMove;
	JoyStick.joyStickMoveEnd -= JoystickMoveEnd;
} 
还有就是:

public void JoystickMoveEnd()
{
	//摇杆停止移动响应函数
}
public void JoystickMove(Vector2 joyPos)
{
	//摇杆开始移动响应函数,这边的joyPos就是摇杆偏移量
}

差不多就做好了一个UGUI的简易虚拟摇杆,没有什么扩展功能,没有进行什么优化,如果有什么更好的改进方法请私信我,谢谢!



2013-07-27 20:41:16 qqMCY 阅读数 4503

Unity不愧是收费开发软件,有写好的Joystick(虚拟手柄),使用起来很简单,我们一起来学习一下哈!!

本文源代码Win版的 :http://vdisk.weibo.com/s/BDn59yfnBVRuD

我们先添加手柄图标啊!先导入一个包。在Project视图中按右键啊。


内容如下:



我们再来创建装有虚拟手柄的容器。


创建完后改名称Joy 再修改一些属性如下图:



之后再将Joystick与虚拟手柄的容器相关联。



创建一个人物:导入人物的包。






我们接下来一个一个JS的脚本:

#pragma strict

var hero :GameObject;
var joyStickPlayer:Joystick;



function Start () 
{
	hero = GameObject.Find("Hero");

}
function Update ()
{
if(joyStickPlayer.tapCount >0 )
{
	var joyPosition_x = joyStickPlayer.position.x;
	var joyPosition_y = joyStickPlayer.position.y;
	
	if(joyPosition_y != 0 || joyPosition_x != 0)
	{
		hero.transform.Translate(Vector3.forward* Time.deltaTime * 5);
		hero.transform.LookAt(Vector3(hero.transform.position.x + joyPosition_x,hero.transform.position.y,hero.transform.position.z + joyPosition_y));
		hero.animation.Play("run");
	}
	else
	{
		hero.animation.Play("idle");
	}
}	
	
}


我们还要修改一下,摄像头的源文件,修改方法见http://blog.csdn.net/qqmcy/article/details/9391283




最后,做如下图的操作,要在真机上测试哦,Android或iOS都可以的。




2016-05-28 00:41:29 woaini454186694 阅读数 11713

【虚拟现实】Unity3D+VR的实现


针对CardBoard一类的眼镜用Unity3D开发VR内容。

1、创建VRCamera:
使用Dive插件,从DiveUnityDemo提取摄像机和有关的脚本并export出来。

2、对象选择:
视选模式:从眼睛发射一条射线,选择看到的对象。
手柄模式:蓝牙手柄上的按键来选择对象。

3、视选模式的实现:
视选:使用Raycast检测,RaycastHit返回碰撞到的物体信息。
private RaycastHit rayHitInfo;
public Transform goPoint;//为射线发出点,是两个摄像机中间的一个点。
if (Physics.Raycast(goPoint.position, goPoint.forward, out rayHitInfo))
{
    Debug.Log("RaySelect: " + rayHitInfo.collider.gameObject.name);
}
焦点:新建一个Plane,和Point放在同一个局部坐标系下,然后调整transform,使其放到视野中间,去选Mesh collider。
给焦点开发动画效果:Texture循环播放。
给视选设置一个停留时间:不是说看到某个物体就触发,而是盯着某个物体一定时间才触发。

4、手柄模式的实现:
检测手柄是否存在:
if ((Input.GetJoystickNames().Length > 0) && (!Input.GetJoystickNames()[0].Equals("")))
{
    //手柄存在
}
void Start () 
{
    InvokeRepeating("detect", 0, 5);//每隔5s调用一次detect函数,做检测手柄动作。
}
检测手柄按键:
if (Input.GetKeyDown(KeyCode.Joystick1Button0))
{
    //手柄键1
}
else if (Input.GetKeyDown(KeyCode.Joystick1Button1))
{
    //手柄键2
}
//以此类推
设置并检测手柄摇杆:
设置摇杆通过在input里面增加axis的手柄,4个方向,要新增设置四个。
检测摇杆:
if (Input.GetAxis("AxisName"))
{
    //摇杆的一个方向
}

2017-04-07 06:05:51 zslsir 阅读数 163

从今天开始,一定要认真学习unity3d。

早几天,我上课的学生让我帮他们配置下unity3d对游戏手柄的输入支持,直到昨天,我才抽出时间帮他们设置了一下。

其实我接触unity3d比较早,好像2011年就开始了,当时导师让我学习这个。当时老师只是让我试试用这个软件做做虚拟现实方面的东西。

由于当时工作比较忙,没投入多少精力去学,再加上当时的学习资料较少,也就没有过多深入地学习了。

真正开始学习是从2013年开始的,当时到北京去培训了一周unity3d。

2014年给学校游戏班的学生上unity3d的课,直到今年,已经给三届的学生上了这个课了。

2014年我主持了一个三维展馆的子项目,包括湘绣馆和刺绣馆,也是用unity3d做的。

2015年给湖南大学艺术学院的学生上了这个课(当时是蛮牛教育临时让我去上的),自己才进一步对这产生了兴趣。

2013-11-20 20:12:45 huangfe1 阅读数 882



那抱歉,上次那个Unity+kinect还没有更新,最近在深一步研究,不久将更新(绝对不负众望)!现在进入正题,十分钟带你打造unity3D第一人称射击游戏!

看完本篇博客,你将学会第一人称控制,粒子的添加,碰撞的检测,鼠标的监听,画2d图像,预制物体克隆,添加力,添加声音等等!(本篇博客假设你已经对unity稍微有点了解)

一,打开unity,创建一个场景,添加一个plane,(gameobject->createother->plane)。

二,添加虚拟第一人称任务(现在没搞模型,模型后面可以自己添加);Assert->importpackages->Charactercontroll,之后你将Project面板里面看到这个资源包,打开里面的charactercontroll文件,将里面的first Person controll拖动到合适的位置。

三,然后我们将添加一个虚拟的枪口,作为子弹的发生点!这个你可以创建一个椭圆,放在摄像机的最中间


 然后要将椭圆设置为摄像机的子物体,这样他将随着摄像机运动(不能设置为任务模型的子物体,因为任务模型的不能上下移动,也就不是这样后不能上下射击)。也就是在hierahcry面板中点击你创建椭圆,拖到摄像机上,这样他就成了摄像机的子物体。可以点击运行测试下,你会发现这东西只是虚拟枪口,所以我们设置它看不见,点击椭圆,在修改面板上,有个MeshRender,你单击下,椭圆就看不见了,但是它存在,然后再点击CapsuleColisder,取消他的碰撞(以免影响子弹的射击);
三,子弹的射击

我们首先创建一个圆,(用这个圆来模拟子弹,如果你自己有子弹模型,就用子弹模型),然后在project中创建一个prefab,用于之后的克隆子弹,现在我们来子弹一点火焰效果,Assert->importpackage->particles导入粒子,点击里面的fire,将里面的Flame拖到游戏中,位置和你创建的球(子弹)一样,然后将你设置的,然后同样的方法,将火焰设置为,子弹的子物体,这样,火焰将和子弹一起运动,自己在属性面板里 修改火焰的大小,然后将子弹拖到你创建的prefab中,修改prefab的名字为balls!添加一个刚体属性,Rigidbody(Addcomment->ragidbody)然后删除游戏中的子弹(嗯,删除)!现在子弹的预制物体已经创建好了,现在我们来射击!

四 ,点击鼠标,发生子弹

现在 就是敲代码码的时候了

var aim:Transform;
//克隆子弹
private var ball:Transform;
//绘制准星的材质
var material:Material;
function Start () {

}

function Update () {
//将鼠标的图标隐藏
Screen.showCursor=false;
//var zj=Vector3(Screen.width/2,Screen.height/2,0);
//var ray:Ray=Camera.main.ScreenPointToRay(Input.mousePosition);
//定义一个方向,为发射点y轴方向
var dir=aim.transform.TransformDirection(Vector3.up);
//var dir=ray.direction;
//按下鼠标左键
if(Input.GetMouseButtonDown(0)){
//实列化一个球,发射点的位置,
ball=Instantiate(balls,aim.position,Quaternion.identity);
//在某一个方向加一个力
ball.rigidbody.AddForce(dir.normalized*1000);
print("----------->>>");
//三秒后删除小球
Destroy(ball.gameObject,3);
}
}

 这里用到了,Screen.showCursor=false;将鼠标隐藏,要将他放在updatae中,放在start中不行var dir=aim.transform.TransformDirection(Vector3.up);这是定义一个方向,子弹将以这个方向射击

其他的没什么解释的了,注释很详细了,方法里面传入的参数,查一下API文档就行

五 ,现在们开始绘制准星

 

//绘制准星的材质

var material:Material;

先定义 一个材质,用来绘制图像

 

//绘制准星
function OnPostRender(){
DrawRecent(Screen.width/2,Screen.height/2,10,10);
}
//绘制四边形的方法
function DrawRecent(x:float,y:float,width:float,height:float){
//材质通道设置为默认的0
 material.SetPass(0);
 //绘制2D图形
  GL.LoadOrtho();
 //绘制长方体
 GL.Begin(GL.QUADS);
 //传入四个点的相对屏幕的坐标,先后分别是左上角,左下角,右下角,右上角
  GL.Vertex(new Vector3(x/Screen.width,y/Screen.height,0));
  GL.Vertex(new Vector3(x/Screen.width,(y+height)/Screen.height,0));
  GL.Vertex(new Vector3((x+width)/Screen.width,(y+height)/Screen.height,0));
  GL.Vertex(new Vector3((x+width)/Screen.width,y/Screen.height,0));
  //结束绘画
  GL.End();
}

 这个没什么好解释的,注释有,按照各个规则就是

 

然后就是,如果你射击到了敌人,敌人就着火

四,射击敌人

首先我们,创建几个cube,这个用来模拟敌人,如果你有好的模型,就用模型。给cube创建ridibody

然后给它一个标签,在属性面板上面有个Tag,点击,选择player,给个player标签,你也可以点击addTag自己添加一个Tag,现在我们创建一个prefab预制火火焰,创建一个空物体,将先前导入的fires拖到空物体中

将空物体放入prefab中,改名为fires

现在 我们添加碰撞事件

新建一个脚本,

 

#pragma strict
//预制火焰
var fires:Transform;
//克隆火焰
private var fire:Transform;
function Start () {

}

function Update () {

}//碰撞监听
function OnCollisionEnter(other:Collision){
//如果碰到的事cube(先前我们将cube的tag设置成了player)
if(other.transform.tag=="Player"){
//克隆一个火焰
fire=Instantiate(fires,other.transform.position,Quaternion.identity);
//设置火焰的父对象为箱子,这样火焰将和物体一起运动,
fire.transform.parent=other.transform;}
}

 五,你想加入声音嘛?如果你想,接着看两种方式添加音乐,首先添加背景音乐,点击摄像机,AddCommpent->aduio->aduiosource

 

首先 下载你需要的背景音乐,将音乐拖进Asset文件夹中,然后将音乐拖进刚才添加的aduiosource的中

然后 教你添加动作音效,在第一和代码中加入var music:AudioClip;

然后再发生子弹的那个方法中,AudioSource.PlayClipAtPoint(music,transform.position);播放,

六:挂载脚本

你首先将以第一个脚本,挂到摄像机上面,然后将第一个frefab(balls)拖到变量中

第二个脚本放在balls上,将fires和音乐拖到变量中!!

OK!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 现在开火!!!!!!!!!

 

 

 

源码下载

没有更多推荐了,返回首页