2015-04-29 13:46:28 nijiayy 阅读数 3079

ok,下面就进入我们的讲解工作啦,我的这个的讲解应该是比较适合初学者的,所以会有一些啰嗦什么的就请大家见谅啦!

想必来看这个blog的,大家都已经知道了Unity3D的一些基本的操作了吧!这里我也就不一一赘述了,毕竟不是什么一个Unity的课程。ok,我这里用的是Unity3D5,然后下面来说一下关于这个小程序的小车的建立。

一开始的时候,我只是在网上找了一些相关的3d模型然后直接拉入Unity中(注意一定要是fbx格式的哦),我当时天真的不断地调节车速和轮子的转动当然就是在脚本里写一些平移和旋转的代码啦,虽然离近了看还是不真实,但是至少我们的车轮还是动了是吧~但是,当遇到拐弯的时候,我就遇到了瓶颈,如果一个正常的车,它的拐弯一定是车头引导的啊,但是我现在无论怎么变也只是看着车头和车尾一起平移过去的,于是我开始查找,找了很多资料(或许也是刚学,没有输入正确的关键词吧),终于让我发现了一个unity自带的一个函数库——WheelCollider,这个类真的是天生就是为赛车游戏开发而设立的啊!这里的运动完全是通关后轮的驱动还带动前轮(当然也可以四驱),而拐弯也就是前轮的带动,实在是完美的解决了我的问题,但是问题也就随之而来了,那就是怎么用这个?我找了好多的资料,都是说把这个库拖入轮子上就好,但是,我拖入后根本就是无法和预想的一样啊,后来我好不容易发现了一个教学视频真的是帮了我的大忙!我觉得文字还是不够直观,所以我觉得大家还是去看看这个视频,真的很有用,那位老师教的很好~这里给出一个链接,大家可以去看看(一共分为了五个你可以找一下车轮的设置在哪里)可以到这里学习:http://www.tudou.com/programs/view/CaBwp072c2Y/

ok 下面就说一下具体的实现吧,话说让车子拐弯而又不脱离公路哪里我还真的是研究了好半天,怎么也找不到方法,终于想起了下载Unity自带的例子,于是我就去找,还真的找到了一个有关汽车ai的例子,也是千辛万苦的读下来,但是其中很多算法还是不明白,但是我发现我已经找到了一个方法了,而且是不需要ai的。受到例子的启示,我本来是想直接还是用Unity的一个WayPoint Circuit的但是这个是建立环路的,而我的想法是建立一条单向道路,所以我就防着这样的思路,建立了一个我的汽车行进的路线,如下图所示:


看到啦那个way_1那些标志了吗?这就是我们的路标点,其实就是一个个的Cube然后把他们保留Collider但是把形状渲染取消,所以就成了一个个透明的小盒子,给他们加入触发器,当校车碰到这个标志点的时候就让小车指向下一个标志点,到达最后一个标志点的时候把这个校车Destory,由于我们的路标点很少只有五个,如果让校车驶向一个个的路标点的话那么必然就会导致小车行驶的十分生硬,所以受到了Unity自带例子的启发我给没一个小车前面加入了一个透明的引导球这样的话让引导球驶向标志点,小车追着引导球(当然小车和引导球之间保持一样的速度),引导球就起到了一个缓冲的作用,保证了小车的圆滑的拐弯。下面是一个小车整体的组成:


看到了左边的小球了吗?那个除了引导的作用还有探测前方是否有车的情况,如果它有碰撞的话那么就会出现一个汽车被它后面的另一个汽车离得好远撞飞了,所以不可能让它具有碰撞性,所以,我们就应该给他设置为触发器方式,但是再次运行的时候你就会发现,这个引导球不见了,小车也不按照既定的路线行驶了,我通过种种的实验发现需要把小球的重力取消就ok!


这个是小球的检视面板看那个IsTriger打了勾就代表这个小球无碰撞,是一种触发器模式,而那个Use Gravity没有打勾就是没有重力的影响。而那个ballmove就是我们要写的函数,小球有两个任务一个是引导,一个是检测车辆,下面给出代码:

#pragma strict
private var waypoint:Transform[]=new Transform[5];
private var move_speed:float;
private var nextpoint:int;
var car:GameObject;
private var carbody:Rigidbody;
private var path:GameObject;
private var current:int;//记录当前point位置
private var turn_brake:int;//转弯刹车
private var stop_brake:int;//停车刹车
private var way_name:String;
private var go:int;
private var last_colllider:String;
function Start () {
  turn_brake=20;//30
  stop_brake=10000;
  nextpoint=0;
  carbody=car.GetComponent("Rigidbody");
  way_name=createcar.path_name;//从生成车辆函数得到当前车的位置并且选择与之对应的道路
  Debug.Log(way_name);
  if(way_name==null){//第一辆车本就有的不用生成所以对应name是null
    way_name="left_right";
  }
  switch(way_name){//针对不同位置生成的车对应不同的行进方式
    case "left_right":
    path=GameObject.Find("way_left_turnright");
    break;

    case "left_left":
    path=GameObject.Find("way_left_turnleft");
    break;
    
    case "left_go":
    path=GameObject.Find("way_left_go");
    break;
    
    case "left_hurry":
    path=GameObject.Find("way_left_hurry");
    break;
    
    case "bot_right":
    path=GameObject.Find("way_bot_right");
    break;
    
    case "bot_left":
    path=GameObject.Find("way_bot_left");
    break;
    
    case "bot_go":
    path=GameObject.Find("way_bot_go");
    break;
    
    case "bot_hurry":
    path=GameObject.Find("way_bot_hurry");
    break;
    
    case "top_right":
    path=GameObject.Find("way_top_right");
    break;
    
    case "top_left":
    path=GameObject.Find("way_top_left");
    break;
    
    case "top_go":
    path=GameObject.Find("way_top_go");
    break;
    
    case "top_hurry":
    path=GameObject.Find("way_top_hurry");
    break;
    
    case "right_right":
    path=GameObject.Find("way_right_right");
    break;
    
    case "right_left":
    path=GameObject.Find("way_right_left");
    break;
    
    case "right_go":
    path=GameObject.Find("way_right_go");
    break;
    
    case "right_hurry":
    path=GameObject.Find("way_right_hurry");
    break;
    
  }
  //childCount获得子物体的数量
  for(var i:int =0;i<path.transform.childCount;i++){//遍历路径的父集遍历集合把对应的point点放入我们的位置点数组中
    //Debug.Log(path.transform.GetChild(i).name);
    waypoint[i]=path.transform.GetChild(i);
  } 
}

function Update () {
  move_speed=carbody.velocity.magnitude;
  //Debug.Log("ball:"+move_speed);
  //改变小球的移动方向
  transform.forward=waypoint[nextpoint].position-transform.position;
  transform.Translate(0,0,move_speed*Time.deltaTime);
}

function lastcollider(name:String){
   Debug.Log("last coiilder:"+name);
   last_colllider=name;
}

function OnTriggerEnter(go:Collider){
//碰撞到point后转向下一个point
if(go.transform.name=="way_1"||go.transform.name=="way_2"||go.transform.name=="way_3"||go.transform.name=="way_4"||go.transform.name=="way_5"||go.transform.name=="stop_line"||go.transform.name=="Terrain"){
   counterway(go);
 }else if(transform.name=="cop_target"&&go.transform.name=="cop_collider"){//警车自己不要把自己弄停
   
 }else if(go.transform.name=="cop_target"||go.transform.name=="target"){
 
 }
 else if(go.transform.name!=lastcollider){
  Debug.Log("car_stop:"+go.transform.name);
  gameObject.SendMessageUpwards("isgo",1);
 }
}
function OnTriggerExit (other : Collider ) {
 // Debug.Log("exit");
  gameObject.SendMessageUpwards("isgo",0);
}

function counterway(go:Collider){
 if(nextpoint<waypoint.Length&&go.transform.IsChildOf(path.transform)){//因为有很多引导块,所以这里片段一下各自的路线,不要
 // 误走过了其他的路径块而导致计数的增加
   nextpoint++;
  }
 //右转遇到第二个标志点就减速
  if(way_name=="left_right"||way_name=="right_right"||way_name=="top_right"||way_name=="bot_right"){
  if(nextpoint==2){
    //Debug.Log("slow");
    gameObject.SendMessageUpwards("isbrake",turn_brake);
   }else{
    gameObject.SendMessageUpwards("isbrake",0);
   }
  }
  if(nextpoint==waypoint.Length){
   //Debug.Log("destory");
   Destroy(car);
  }
}
这里都有相应额注释我相信大家应该都可以看懂,其实代码并不难,重要的是一个解决问题的方式,ok小球和路径的建立就说到这里~

对了,想必大家也都看到了我有很多需要确定字符串的地方例如:way_name=="left_right"其实这里的字符串是要和建立物体的命名取得一致的,如下图给一个例子:


ok,今天这一节就讲到这里啦~

2015-04-29 13:44:32 nijiayy 阅读数 3979

    最近学习了Unity3d这个游戏引擎,感觉真的是非常的强大,正好赶上操作系统课程要做一个模拟信号量的模拟程序,于是打算做一个模拟十字路口的程序,大致的实现要实现的成果是:存在四种不同的汽车,包括一辆警车(不受交通信号灯的控制)随机产生在不同的路口,并且有不同的行动路线如:直走,左转,右转等,当然还有交通信号灯来控制车辆的有序运行。可以展示不同的视角来观察路口的情况(利用Q,W,E,R分别控制不同的视角),ok,废话不多说,下面来讲述一下具体的实现方案!毕竟初学,肯定会存在一些不足之处,还望见谅~

   下面来看一下我们最终实现的界面吧~


这个是最初的W视图


这个是Q视图


这个是E视图


这个是R视图

ok,我这里资源页有这里的脚本的下载,如果有需要的可以下载交流哈~

接下来的几个blog我会细细的讲述一下具体的实现过程!

资源地址:http://download.csdn.net/detail/nijiayy/8645197



2015-04-29 14:41:42 nijiayy 阅读数 1851

好的,下面我们来说一下,小车的创建,怎么实现随机的创建小车,其实在创建小车这里我主要是用来Instantiate函数来克隆prefab物体,当然这个预制物体也是需要设置一番的,看了视频的话我们肯定都已经知道了wheelcollider的创建,其实一个预制物体还有一个引导球包括他的脚本和一个包裹小车的用于感知其他小球碰撞的“保护膜”,

这里有一个层次结构大家可以看一下:


当前选中的那个其实是小车的外壳,他的作用就是在周围包裹一层collider来保证我们的小车不会从我们的场景中掉下去,用于控制我们小车的脚本是在那个父物体Pickup_Truck中,这样在一个预制物体生成的时候就会有相应的函数来执行,下面来看一个放在小车上的另一个脚本也就是控制小车的脚本:

#pragma strict
    var collider_FL:WheelCollider;
	var collider_FR:WheelCollider;
	var collider_BL:WheelCollider;
	var collider_BR:WheelCollider;

	var wheel_FL:Transform;
	var wheel_FR:Transform;
	var wheel_BL:Transform;
	var wheel_BR:Transform;

	private var left_light:GameObject;
	private var right_light:GameObject;
	private var bot_light:GameObject;
	private var top_light:GameObject;

    var target:Transform;	
	private var body:Rigidbody;
	private var motor:float;
	var CenterOfMass:Vector3;
	private var maxangle:float=40f;
	private var brake:float;//右转刹车
	private var go:int ;//是否继续前行的标志
	private var car_front:int ;//if any car in front 
	// Use this for initialization
function Start () {
		go=1;
		brake=0;
		motor=20;
		body=GetComponent("Rigidbody");
		body.centerOfMass=CenterOfMass;//用于重心的控制
		//left_light=GameObject.Find("traffic_lights_left");
		right_light=GameObject.Find("traffic_lights_right");
		bot_light=GameObject.Find("traffic_lights_bot");
		top_light=GameObject.Find("traffic_lights_top");
}

function Update () {
	   //渲染车轮的运动
		wheel_FL.Rotate(collider_FL.rpm/60*360*Time.deltaTime,0,0);
		wheel_FR.Rotate(collider_FR.rpm/60*360*Time.deltaTime,0,0);
		wheel_BL.Rotate(collider_BL.rpm/60*360*Time.deltaTime,0,0);
		wheel_BR.Rotate(collider_BR.rpm/60*360*Time.deltaTime,0,0);
		//渲染前轮的旋转
		wheel_FL.localEulerAngles=wheel_FR.localEulerAngles=new Vector3(wheel_FL.localEulerAngles.x,collider_FL.steerAngle,wheel_FR.localEulerAngles.z);
}

function FixedUpdate(){//表示物理操作的更新
	   //用于更新当前前轮的状态
		var offsetTargetPos:Vector3= target.position;//小球的位置
		var localTarget:Vector3= transform.InverseTransformPoint(offsetTargetPos);
		var targetAngle:float = Mathf.Atan2(localTarget.x, localTarget.z)*Mathf.Rad2Deg;
		var steer:float = Mathf.Clamp(targetAngle*0.05f, -1, 1)*Mathf.Sign(GetComponent.<Rigidbody>().velocity.magnitude);
		collider_FL.steerAngle=collider_FR.steerAngle=steer*maxangle;
		if(go==1&&car_front==0){//go判断前方是否有车是否是红灯
		  
		  brake=0;
		  motor=20;
		}else{//stop
		  motor=0;//动力
		  brake=25000;//刹车
		  var newx:float=body.velocity.x-1>0?body.velocity.x-1:0;
		  body.velocity=new Vector3(newx,0,0);
		  isgoon();//用于红灯时不断地检测当前信号灯的状态
		}
		collider_BL.motorTorque=collider_BR.motorTorque=motor;
		collider_BL.brakeTorque=collider_BR.brakeTorque=brake;
		
	}
function isbrake(a:int){
		brake=a;
		if(a==0){
		motor=20;
		}else{
		motor=0;
		}
		//Debug.Log (transform.name+" brake is "+brake);
	}
function isgo(a:int){
      car_front=a;
      //Debug.Log(transform.name+" car_front:"+car_front);
	}	
function isgoon(){
        var way_name=getway();
		switch(way_name){
		case "left":
			go=lightcontrol.go;
			break;
		case "right":
		    go=lightcontrol.go;
			break;
		case "bottom":
		    go=tblightcontrol.go;
			break;
		case "top":
		    go=tblightcontrol.go;
			break;
		case "notinroad"://包括最右面用于右转的那个车道
		    go=1;
		    break;
		}
	}
function OnTriggerEnter(go:Collider ) {
        if(go.transform.name=="trigger"){
         gameObject.BroadcastMessage("lastcollider",go.transform.name);
         }
		if(go.transform.name=="stop_line"){//也就是在路口前
			isgoon();
		//    Debug.Log("stop");
		}
	}
	
	//用于判断当前在哪条道路上
function getway(){
		var x:float=transform.position.x;
		var z:float=transform.position.z;
		//这里的车道的计算是不包括最右车道的,因为最右车道不是右拐就是紧急车道没有红灯
		if(x>0&&x<89&&z>96&&z<105.5){//left
			return "left";
		}else if(x>107&&x<200&&z>90.5&&z<102.5){//right
			return "right";
		}else if(x>89&&x<101&&z>0&&z<90.5){//bottom
			return "bottom";
		}else if(x>94&&x<107&&z>105.5&&z<200){//top
			return "top";
		}else{
			return "notinroad";
		}
	}

这里的注释也是比较详细,这里要说一下的就是那个控制前车轮的变化角度的计算,这个是我借鉴unity的car_ai的例子写的,主要是计算了一个正切角什么的,具体的时我也没太弄懂...不过可以使用,我就直接拿下来了(看来学好数学还是必须的!)。那个判断当前位置的函数的具体的x,z(y 是垂直的轴)是要大家自己计算的,不同的物理世界肯定是不同,这里只是给出了一个用于判断当前位置的方法~



2015-04-29 15:04:46 nijiayy 阅读数 1500

ok,我们已经知道我们的预制物体都是怎么个结构了,下面我们就来说一下,具体的随机创造车辆的函数,我是把这个脚本放到了我的地形这个物体上,当然你也可以放到摄像机上,正如最开始展示的图片,我们这里一共有四条道路,暂且我们把它命名为left,right,bottom,top每一条路都有四个车道,在我们中国都是靠右行驶的嘛,所以其中最靠右的就用于右转和紧急车辆的行驶。所以我们开始生成车辆,不多说上代码:

#pragma strict
var counter:float=0;
var SUV:GameObject;
var Pickup_Truck:GameObject;
var IceCreamTruck:GameObject;
var CopCar:GameObject;
private var Car:GameObject;
static var path_name:String;
private var angle:float;
private var n:int;//随机数的储存
private var prefabPath:String;
function Start () {
 n=0;
}

function Update () {
  counter=counter+Time.deltaTime;
  if(counter>5){//每隔五秒生成一辆车
  Car=choosecar();//获得不同种类的车
  if(n==3){//3是紧急车辆
    choosehurryway();
  }else{
    choosenormalway();
  }
   counter=0;
  }
  //Debug.Log(counter);
}
//选择紧急车辆的way
function choosehurryway(){
   n=Random.Range(0,4);//产生随机数
   switch(n){
    case 0://left
     angle=Mathf.Sqrt(2);
     Instantiate (Car, Vector3(67.7,0.6,94.5), new Quaternion(0,angle/2,0,angle/2));//最后那个是一个四元数用于控制车的朝向
     path_name="left_hurry";
     break;
    case 1:
     Instantiate (Car, Vector3(103.2,0.6,55.96), new Quaternion(0,0,0,1));
     path_name="bot_hurry";
     break;
    case 2:
     Instantiate (Car, Vector3(92.3,0.6,130.8), new Quaternion(0,1,0,0));
     path_name="top_hurry";
     break;
    case 3:
     angle=Mathf.Sqrt(2);
     Instantiate (Car, Vector3(129,0.6,105.5), new Quaternion(0,-angle/2,0,angle/2));
     path_name="right_hurry";
     break;
    }
}
//选择普通车辆的way
function choosenormalway(){
  n=Random.Range(0,12);//产生随机数
  switch(n){
    case 0://left
     angle=Mathf.Sqrt(2);
     Instantiate (Car, Vector3(67.7,0.6,94.5), new Quaternion(0,angle/2,0,angle/2));
     path_name="left_right";
     break;
    case 1:
     angle=Mathf.Sqrt(2);
     Instantiate (Car, Vector3(67.7,0.6,98.41), new Quaternion(0,angle/2,0,angle/2));
     path_name="left_left";
     break;
    case 2:
     angle=Mathf.Sqrt(2);
     Instantiate (Car, Vector3(67.7,0.6,98.41), new Quaternion(0,angle/2,0,angle/2));
     path_name="left_go";
     break;
    case 3://bottom
     Instantiate (Car, Vector3(103.2,0.6,55.96), new Quaternion(0,0,0,1));
     path_name="bot_right";
     break;
    case 4:
     Instantiate (Car, Vector3(99.5,0.6,55.96), new Quaternion(0,0,0,1));
     path_name="bot_left";
     break;
    case 5:
     Instantiate (Car, Vector3(99.5,0.6,55.96), new Quaternion(0,0,0,1));
     path_name="bot_go";
     break;
    case 6://top
     Instantiate (Car, Vector3(92.3,0.6,130.8), new Quaternion(0,1,0,0));
     path_name="top_right";
     break;
    case 7:
     Instantiate (Car, Vector3(95.9,0.6,130.8), new Quaternion(0,1,0,0));
     path_name="top_left";
     break;
    case 8:
     Instantiate (Car, Vector3(95.9,0.6,130.8), new Quaternion(0,1,0,0));
     path_name="top_go";
     break;
    case 9://right
     angle=Mathf.Sqrt(2);
     Instantiate (Car, Vector3(129,0.6,105.5), new Quaternion(0,-angle/2,0,angle/2));
     path_name="right_right";
     break;
    case 10:
     angle=Mathf.Sqrt(2);
     Instantiate (Car, Vector3(129,0.6,101.9), new Quaternion(0,-angle/2,0,angle/2));
     path_name="right_left";
     break;
    case 11:
     angle=Mathf.Sqrt(2);
     Instantiate (Car, Vector3(129,0.6,101.9), new Quaternion(0,-angle/2,0,angle/2));
     path_name="right_go";
     break;
  }
}

function choosecar(){
  n=Random.Range(0,4);//产生随机数
  //Debug.Log("car:"+n);
  switch(n){
  case 0:
    return SUV;
  case 1:
    return Pickup_Truck;
  case 2:
    return IceCreamTruck;
  case 3:
    return CopCar;
  }
}
//另一种克隆的方式
/*function choosecar(){
  //n=Random.Range(0,4);//产生随机数
  var car_name;
  n=0;
  switch(n){
  case 0:
    car_name="SUV";
    break;
  case 1:
    car_name="Pickup_Truck";
    break;
  case 2:
    car_name="IceCreamTruck";
    break;
  case 3:
    car_name="CopCar";
    break;
  }
  prefabPath="Assets/Prefabs/"+"SUV"+".prefab";
  Debug.Log("car:"+prefabPath);
}*/

下面说一下代码里面说的那个四元数,那是一个用于控制小车的朝向参数,它有一个自己的算法:

给定一个欧拉旋转(X, Y, Z)(即分别绕x轴、y轴和z轴旋转X、Y、Z度),则对应的四元数为:
x = sin(Y/2)sin(Z/2)cos(X/2)+cos(Y/2)cos(Z/2)sin(X/2)
y = sin(Y/2)cos(Z/2)cos(X/2)+cos(Y/2)sin(Z/2)sin(X/2)
z = cos(Y/2)sin(Z/2)cos(X/2)-sin(Y/2)cos(Z/2)sin(X/2)
w = cos(Y/2)cos(Z/2)cos(X/2)-sin(Y/2)sin(Z/2)sin(X/2)
q = ((x, y, z), w)
这样就可以自己随意的设置自己的小车的朝向了,Random.Range(0,12)这个函数是随机的产生一个0到12的整数(不包括12),当然那我的克隆的方法就是设置了四个共有变量在检视面板里面把相应的预制物体拉进去,你也可以尝试采用我后面注释掉的方式直接在文件中找到对应的预制物体进行克隆,在uinty里面凡是public的变量都可以在检视面板中从工程文件中把相应的实例拖进去,如下图:

那个SUV等车的模型就是从prefab文件夹中直接拖进去的,这里还要说一点就是警车的设置,因为警车直走直线而且只有在最右的道路,所以当随机出警车的话就只在四个不同的紧急路线中选择道路进行放置,Instantiate的第二个参数就是生成物体的位置,所以这个位置也要针对不同的物理世界进行不同的变化~



2018-11-20 20:24:37 yuyingwin 阅读数 1593

前面我们已经讲解了按钮制作、按钮的位移、缩放、渐变的实现,现在我们来讲解另一块房地产VR核心业务模块。项目简介、动态交通。这两个模块是平面展示中的核心模块。

现在我们来讲解一下,项目简介、动态交通的制作。项目简介功能的制作,可以分为两种:一种是纯海报式、一种是GIF模式(包含特殊的特效)、一种是平面与三位场景结合的静态画面。

以 项目简介为例,项目简介主要介绍当前建筑、小区开发的相关信息,文字较多;以平面展示为好,也可以用平面+实体场景来制作。

纯平面展示,例如:下面的图片,就是纯平面的,这个就需要一个厉害的PS的高手来制作精美的海报。

 

平面+实体:本质还是海报 平面展示,制作步骤就是,在Unity3D选中特定的角度,截取图片给PS(平面设计师)技师,让其在这基础上进行绘制。最后,在操作的时候,将相机拉到截取图片的位置,将效果图显示出来就好了。

动态交通图:下面就是一张业态、交通布局图,动态交通有很多种形式,我单单拿出这张图来就说明了这是重点展示的,也是现场销售经常布展的。App可以做的酷炫一点,也可以实用一点。我倾向于实用,用最好的方式解决行业痛点,提高效率。

不多说了,下面的图是一张静态图,我们可以找AE后期工程师做一些动效,突出重点,让其活动起来。

如果动起来了,我们怎样展示呢?方案:一个是播放Gif序列图;另一个是播放mp4视频。

播放Gif序列图代码:https://blog.csdn.net/yuyingwin/article/details/73554915

播放MP4视频的方式,向大家推荐一款插件:AVPro Video

 

下载地址:http://www.manew.com/thread-135442-1-1.html

地铁模型

阅读数 891

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