ai代码 unity3d

2018-11-11 09:46:55 hddghhfd 阅读数 2754
  • Unity 值得看的500+ 技术内容列表

    Unity3D是由Unity Technologies开发的一个让玩家轻松创建诸如三维视频游戏、建筑可视化、实时三维动画等类型互动内容的多平台的综合型游戏开发工具,是一个全面整合的专业游戏引擎。

分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow

也欢迎大家转载本篇文章。分享知识,造福人民,实现我们中华民族伟大复兴!

               

1. 访问其它物体

1) 使用Find()和FindWithTag()命令
Find和FindWithTag是非常耗费时间的命令,要避免在Update()中和每一帧都被调用的函数中使用。在Start()和Awake()中使用,使用公有变量把它保存下来,以供后面使用。如:
  公有变量= GameObject.Find("物体名"); 或
  公有变量= GameObject.FindWithTag("物体标签名");
2) 把一个物体拖到公有变量上
3) 引用脚本所在的物体的组件上的参数,如下所示:

   transform.position = Vector3(0,5,4);   renderer.material.color = Color.blue;   light.intensity = 8;

4) SendMessge()命令:一个调用其它物体上指令(即物体上的脚本中的函数)的方法

5) GetComponent()命令:引用一个组件

实例代码如下所示:

#pragma strictvar thelight:GameObject;var thetxt:GameObject;var theCube1:GameObject;function Start () { thelight = GameObject.Find("Spotlight"); thetxt = GameObject.FindWithTag("txt"); theCube1 = GameObject.Find("Cube1");}function Update () if(Input.GetKey(KeyCode.L)){  thelight.light.intensity += 0.01;  thetxt.GetComponent(GUIText).text = "当前亮度:"+thelight.light.intensity; }  if(Input.GetKey(KeyCode.K)){  thelight.light.intensity -= 0.01;  thetxt.GetComponent(GUIText).text = "当前亮度:"+thelight.light.intensity; } if(Input.GetKey(KeyCode.S)){  theCube1.SendMessage("OnMouseDown"); //调用theCube1所有脚本中的OnMouseDown函数 }}

2. 制作第一人称控制器

    第一人称控制器脚本代码如下所示:

#pragma strictvar speed:float=6.0;var jumpspeed:float=8.0;var gravity:float=20.0;private var movedirection:Vector3=Vector3.zero;private var grounded:boolean=false;function Start () {}function FixedUpdate () if(grounded){  movedirection=Vector3(Input.GetAxis("Horizontal"),0,Input.GetAxis("Vertical"));    //Transforms direction from local space to world space.  movedirection=transform.TransformDirection(movedirection);    movedirection *= speed;    if(Input.GetButton("Jump")){   movedirection.y = jumpspeed;  } }  movedirection.y -= gravity*Time.deltaTime; //Move command  var controller:CharacterController = GetComponent(CharacterController); var flags = controller.Move(movedirection*Time.deltaTime); //CollisionFlags.CollidedBelow  底部发生了碰撞 //CollisionFlags.CollidedSides 四周发生了碰撞 //CollisionFlags.CollidedAbove 顶端发生了碰撞 grounded = (flags & CollisionFlags.CollidedBelow)!=0;}//强制Unity为本脚本所依附的物体增加角色控制器组件@script RequireComponent(CharacterController)


3. 导入3DMax模型

    在3DMax(.fbx文件)把显示单位和系统单位设置为cm,再导入到Unity3D(单位为m)中时,则大小相同。

4. 交互功能(自动开关门)

4.1 ControllerColliderHit(碰撞检测)    

    玩家撞到门时,门才能开。

    其相关代码如下所示,需要对模型的动画进行分割,以下脚本绑在玩家身上:

#pragma strictprivate var doorisopen:boolean = false;private var doortimer:float = 0.0;private var currentdoor:GameObject;var door_open_time:float = 5.0;var door_open_sound:AudioClip;var door_shut_sound:AudioClip;function Update()if(doorisopen){  doortimer += Time.deltaTime;    if(doortimer > door_open_time) {   doortimer = 0.0;   door(false,door_shut_sound,"doorshut",currentdoor);  } }}//检测玩家是否与门相撞function OnControllerColliderHit(hitt:ControllerColliderHit){ //hitt为与玩家相撞的碰撞体 print("test1"); if(hitt.gameObject.tag == "playerDoor" && doorisopen == false){  print("test2");  door(true,door_open_sound,"dooropen",hitt.gameObject);  currentdoor = hitt.gameObject; }}function door(doorcheck:boolean,a_clip:AudioClip,ani_name:String,thisdoor:GameObject){ doorisopen=doorcheck; thisdoor.audio.PlayOneShot(a_clip); //声音取消3D效果,否则无法播放 thisdoor.transform.parent.animation.Play(ani_name);}

4.2 RaycastHit(光线投射)

      玩家必须面对门时,光线投射到门时,门才能开。

      其检测碰撞代码如下所示,以下脚本绑在玩家身上

function Update()var hit:RaycastHit; //hit为与投射光线相遇的碰撞体 if(Physics.Raycast(transform.position,transform.forward,hit,3)){    print("collider happen" + hit.collider.gameObject.tag);  if(hit.collider.gameObject.tag == "playerDoor"){   var currentdoor:GameObject = hit.collider.gameObject;   currentdoor.SendMessage("doorcheck");   print("call doorcheck");  } }}


       门身上的脚本如下所示:

#pragma strictprivate var doorisopen:boolean = false;private var doortimer:float = 0.0;//private var currentdoor:GameObject;var door_open_time:float = 5.0;var door_open_sound:AudioClip;var door_shut_sound:AudioClip;function Update()if(doorisopen){  doortimer += Time.deltaTime;    if(doortimer > door_open_time) {   doortimer = 0.0;   door(false,door_shut_sound,"doorshut");  } }}function doorcheck()if(!doorisopen){  door(true,door_open_sound,"dooropen"); }}function door(doorcheck:boolean,a_clip:AudioClip,ani_name:String){ doorisopen=doorcheck; audio.PlayOneShot(a_clip); //声音取消3D效果,否则无法播放 transform.parent.animation.Play(ani_name);}


4.3 OnTriggerEnter(触发器)

      只要一进入触发区域,门就可以打开。需要特别注意调整小房子的Box Collider的大小和位置。

      以下脚本绑在门所在的小房子上:

#pragma strictfunction OnTriggerEnter (col:Collider) { //col为闯入此区域的碰撞体 if(col.gameObject.tag == "Player"){  transform.FindChild("door").SendMessage("doorcheck"); }}


4.4 OnCollisionEnter

             检测两个普通碰撞体之间的碰撞,需要发力,才能发生碰撞。不能与第一人称控制器发生碰撞。


4.5 交互总结

      1) OnControllerColliderHit

          专门提供给角色控制器使用,以供角色控制器检测与其它物体发生了碰撞。

          它与触发模式的碰撞体不能发生碰撞,而且还会穿过其物体。

           以下脚本绑定在玩家(第一人称控制器)身上。

function OnControllerColliderHit (hit:ControllerColliderHit) if(hit.gameObject.name != "Plane") gameObject.Find("wenzi").guiText.text = hit.gameObject.name;}


      2) RaycastHit

          它不是一个事件,而是一个命令,可以需要的地方调用它来发射一条光线来进行检测。

           可以与触发模式的碰撞体发生碰撞,但也会穿过其物体。   

           以下脚本绑定在玩家(第一人称控制器)身上。            

#pragma strictvar hit:RaycastHit;function Update () if(Physics.Raycast(transform.position,transform.forward,hit,2)){  if(hit.collider.gameObject.name != "Plane"){   gameObject.Find("wenzi").guiText.text = hit.collider.gameObject.name;  } }}

      3) OnTriggerEnter

          以下脚本绑定在与第一人称控制器相撞的物体上。

#pragma strictfunction OnTriggerEnter (col:Collider) { gameObject.Find("wenzi").guiText.text = col.gameObject.name;}

        4) OnCollisionEnter

             检测两个普通碰撞体之间的碰撞,需要发力,才能发生碰撞。不能与第一人称控制器发生碰撞。

5. 播放声音

5.1 audio.Play()

    GameObject有Audio Source组件,且在Audio Source组件中设置了Audio Clip。

     

5.2 audio.PlayOneShot

var door_open_sound:AudioClip; //在检测面板中设置audio clip;当然必须有Audio Source组件,但不需要设置Audio Clipfunction myAudioPlay(){ audio.PlayOneShot(door_open_sound); //声音取消3D效果,否则无法播放}


5.3 AudioSource.PlayClipAtPoint

      此种播放方式最佳,节约资源。

var collectSound:AudioClip; //在检测面板中设置其值function pickupCell()//临时申请一个AudioSource,播放完了即时销毁 AudioSource.PlayClipAtPoint(collectSound,transform.position);}

6. 销毁物体

    Destroy(gameObject);  //即时销毁物体

    Destroy(gameObject,3.0); // 3秒之后销毁物体

7. 给刚体增加速度

     方法一:

#pragma strictvar throwsound:AudioClip;var coconut_bl:Rigidbody; //为预制物体function Update () if(Input.GetButtonDown("Fire1")){  audio.PlayOneShot(throwsound);  var newcoconut:Rigidbody = Instantiate(coconut_bl,transform.position, transform.rotation);  newcoconut.velocity=transform.forward*30.0; //设置刚体速度 }}

8. 忽视碰撞命令

   使用这两个碰撞器碰撞时不发生效果

   Physics.IgnoreCollision(transform.root.collider,newcoconut.collider,true); 


9. 协同程序及动画播放

    协同程序:类似子线程,在运行本代码的同时,运动脚本中的其它代码。

#pragma strict// this script will be attached to target objectprivate var beenhit:boolean = false;private var targetroot:Animation; var hitsound:AudioClip;var resetsound:AudioClip;var resettime:float=3.0;function Start () { targetroot = transform.parent.transform.parent.animation;}function OnCollisionEnter (theobject:Collision) if(beenhit == false && theobject.gameObject.name == "coconut"){  StartCoroutine("targethit"); //协同程序:类似子线程,在运行本代码的同时,运动脚本中的其它代码 }}function targethit(){ audio.PlayOneShot(hitsound); // 播放声音 targetroot.Play("down");  // 播放动画 beenhit = true;  yield new WaitForSeconds(resettime); // wait for 3s  audio.PlayOneShot(resetsound); targetroot.Play("up"); beenhit=false;}

10. 动态添加和删除脚本

      

#pragma strictvar obj:GameObject;var myskin:GUISkin;function Start () {}function Update () {}function OnGUI()//GUI.skin = myskin; if(GUILayout.Button("Add_Component",GUILayout.Height(40),GUILayout.Width(110))){  obj.AddComponent("xuanzhuan"); // xuanzhuan为一个脚本xuanzhuan。js } if(GUILayout.Button("Del_Component",GUILayout.Height(40),GUILayout.Width(110))){  var script:Object = obj.GetComponent("xuanzhuan");  Destroy(script); }  }

11. 粒子系统

      粒子系统是在三维空间中渲染出来的二维图像,主要用于表现烟、火、水滴和落叶等效果。

      粒子系统由:粒子发射器、粒子动画器和粒子渲染器组成。


12. for循环和数组

       使用Unity3D内建数组:

var cms:Render[];fucntion Update(){   for(var co:Render in cms){      co.material.color = Color.red;   }}

       使用Unity3D非内建数组Array:

var wenzi_bl:GUIText;var arr = new Array(9,12,65,58);  //静态数组var barr = new Array();  //动态数组fucntion Start(){   barr.Push("push1");   barr.Push("push2");   arr.Sort();   wenzi_bl.text = arr.join(",") + " ,arr长度:" + arr.length+ " >>" + barr + " barr长度:" + barr.length;}


13. 延时函数及载入新场景

function OnMouseDown () { audio.PlayOneShot(beep); yield new WaitForSeconds(0.35); Application.LoadLevel(levelToload);}


14. 创建窗口及此窗口中的内容

static var windowSwitch:boolean = false;private var windowRect = Rect(300,280,240,200);function Update()if(Input.GetKeyDown(KeyCode.Escape)){  windowSwitch = !windowSwitch; }}function OnGUI()if(windowSwitch){  windowRect = GUI.Window(0,windowRect,WindowContain,"测试窗口"); }}// show window contentsfunction WindowContain()if(GUI.Button(Rect(70,70,100,20),"关闭音乐")){  gameObject.Find("Terrain").GetComponent(AudioSource).enabled = false; }  if(GUI.Button(Rect(70,100,100,20),"播放音乐")){  gameObject.Find("Terrain").GetComponent(AudioSource).enabled = true; }  if(GUI.Button(Rect(70,130,100,20),"关闭窗口")){  windowSwitch = false; }  if(GUI.Button(Rect(70,160,100,20),"退出游戏")){  Application.Quit(); } GUI.DragWindow(new Rect(0,0,1000,1000));}

15. 菜单制作方法

      1) GUITexture

      2) GUI对象:GUI.Window和GUISkin。


















           

给我老师的人工智能教程打call!http://blog.csdn.net/jiangjunshow

这里写图片描述
2020-04-08 17:39:10 TodayIsSundayy 阅读数 227
  • Unity 值得看的500+ 技术内容列表

    Unity3D是由Unity Technologies开发的一个让玩家轻松创建诸如三维视频游戏、建筑可视化、实时三维动画等类型互动内容的多平台的综合型游戏开发工具,是一个全面整合的专业游戏引擎。

Unity 3d 实现AI随机行走

通过自己的思路实现的 AI 随机行走,转向,新手上路如有写的不好的地方欢迎讨论。

效果图
在这里插入图片描述

下面是代码

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Threading;

public class xc : MonoBehaviour
{
    //行走速度和旋转速度,这里说一下加public挂载后可以在unity的检查器上修改数值并调试,反之则无
    public float MoveSpeed = 1.0f;
    public float RotateSpeed = 30.0f;
    //控制走路方式
    public int key = 0;
    //当前是否行走
    public bool temp= true;
    //当前挂载脚本的人物行为
    Animator m_Animator;
    // Start is called before the first frame update
    void Start()
    {
        key = 1;
        //获取人物行为,如未使用模型和行为树作请注释掉这条代码
        m_Animator = GetComponent<Animator>();
        //协程,也就是挂后台
        StartCoroutine("Wait");
    }


    void Update()
    {
        if (temp == false)
        {
            //行走为否直接跳过,不执行后面的走路代码
            return;
        }
        //开始行走,这里可以修改为四种行走方式
        switch (key)
        {
            case 1:
                //向前走
                transform.Translate(0, 0, 1 * MoveSpeed * Time.deltaTime, Space.Self);
                //旋转1度
                transform.Rotate(0, 1 * RotateSpeed * Time.deltaTime, 0, Space.Self);
                break;
            case 2:
                transform.Translate(0, 0, 1 * MoveSpeed * Time.deltaTime, Space.Self);
                transform.Rotate(0, 1 * RotateSpeed * Time.deltaTime, 0, Space.Self);
                break;
            case 3:
                transform.Translate(0, 0, 1 * MoveSpeed * Time.deltaTime, Space.Self);
                transform.Rotate(0, 1 * RotateSpeed * Time.deltaTime, 0, Space.Self);
                break;
            case 4:
                transform.Translate(0, 0, 1 * MoveSpeed * Time.deltaTime, Space.Self);
                transform.Rotate(0, 1 * RotateSpeed * Time.deltaTime, 0, Space.Self);
                break;

        }

    }
    IEnumerator Wait()
    {
        while (true)
        {
            //两秒运行一次Timer函数
            yield return new WaitForSeconds(2);
            Timer();
        }
    }

    void Timer()
    {
        //生成随机数1-3
        int i = Random.Range(0, 4);
        //走路的概率为3/2
        if ( i> 1)
        {
            temp = true;
            //设人物模型行为状态为站立,如果是使用cube等没有行为树的话请注释这条代码
            m_Animator.SetBool("idle", true);
            //自身旋转,原地向后转
            transform.Rotate(0, 180, 0, Space.Self);
            return;
        }
        else
        {
            temp = false;
            //设人物模型行为状态为走路
            m_Animator.SetBool("idle", false);
        }
        //换一种走路方式,这里是按顺序,你也可以改成随机
        key++;
        //走路方式控制在1-4开区间内,别问我开区间是啥
        if (key == 5)
        {
            key = 1;
        }
    }
}


挂载到人物模型上就行了,如果使用cube或者没有行为树,按照注释注释掉对应的地方即可。

关于人物的Animator行为我会在下期讲。

2014-05-06 21:56:32 qinyuanpei 阅读数 20542
  • Unity 值得看的500+ 技术内容列表

    Unity3D是由Unity Technologies开发的一个让玩家轻松创建诸如三维视频游戏、建筑可视化、实时三维动画等类型互动内容的多平台的综合型游戏开发工具,是一个全面整合的专业游戏引擎。

        大家好,我是秦元培,欢迎大家继续关注我的博客,我的博客地址是blog.csdn.net/qinyuanpei

        首先感谢大家对我博客的关注,今天我想和大家分享的是一个飞机大战的项目。这是一个比较综合的项目,希望对大家学习Unity3D有所帮助,我会在文章最后给出项目代码。作为一个游戏而言,游戏策划十分重要,所以在开始今天的文章之前,我们先来了解下这个项目的策划。我们的玩家是一个飞机,玩家可以使用A、D、S、W四个键位来控制飞机位置,当按下空格键时,我方飞机可以向敌机发射炮弹,当敌机中弹后将减少生命值,当敌机生命值为0时,敌机将爆炸销毁。在游戏场景中只有一种从屏幕上方不断向下飞行的敌机,当我方飞机与敌机碰撞后,双方都将减少生命值。当我方生命值减少至0时,游戏将结束。好了,了解完游戏规则设定后,我们就可以开始今天的内容了。

       

    一、游戏场景

      游戏场景我们采用2D的界面,如图,我们创建一个蓝天白云的平面场景,该场景垂直于摄像机并采取正交投影方式。如果对在Unity3D中创建2D场景尚存在疑惑的朋友可以参考文章《[Unity3D]Unity3D游戏开发之《经典打砖块》游戏的实现》《Unity3D游戏开发之使用Unity3D开发2D游戏 (一)》两篇文章。


      我们这里在场景中添加GUIText对象来显示玩家得分等基本信息,脚本定义如下:

using UnityEngine;
using System.Collections;

public class GameManager : MonoBehaviour {
	
	//玩家得分
	private Transform Grade;
	//玩家生命
	private Transform HP;
	//游戏结束
	private Transform Text;
	//玩家
	private GameObject Player;
	
	void Start ()
	{
	  //初始化界面
	  Grade=transform.Find("Grade");
	  HP=transform.Find("HP");
	  Text=transform.Find("Text");
	  Text.guiText.enabled=false;
	  //获取玩家对象
	  Player=GameObject.Find("Player");
	}
	
	void Update () 
	{
	  if(Player!=null)
	  {
	    //更新UI
	    Grade.guiText.text="得分:"+Player.GetComponent<Player>().Grade.ToString();
	    HP.guiText.text="生命:"+Player.GetComponent<Player>().MaxHP.ToString();
	  }
	  if(HP.guiText.text=="生命:0")
	  {
		 Text.guiText.enabled=true;
		 //立即复活
	     if(Input.GetKey(KeyCode.Y))
		 {
			Application.LoadLevel("Main");	
		 }
		 //退出
		 if(Input.GetKey(KeyCode.N))
		 {
			Application.Quit();
		 }
	  }
	}
}


      二、玩家飞机

      玩家飞机的创建和背景的创建时相同的,这里我们不再多说。玩家飞机需要完成移动、发射、碰撞的事件处理。为此我们编写下面的脚本:

using UnityEngine;
using System.Collections;

public class Player : MonoBehaviour {

    //飞机的移动速度
    public float MoveSpeed;
    //飞机的最大生命值
    public int MaxHP=100;
    //定义子弹对象
    public GameObject Bullet;
    //定义子弹发射位置
    private Transform BulletPosL;
    private Transform BulletPosR;
    
	[HideInInspector]
	public int Grade=0;
	
	void Start () 
	{
	  BulletPosL=this.transform.Find("BulletPosL");
	  BulletPosR=this.transform.Find("BulletPosR");
	}
	
	void Update () 
	{
	  if(Input.GetKey(KeyCode.A))
	  {
	     transform.Translate(Vector3.left*Time.deltaTime*(-MoveSpeed));
	  }
	  if(Input.GetKey(KeyCode.D))
	  {
	     transform.Translate(Vector3.left*Time.deltaTime* MoveSpeed );
	  }
	  if(Input.GetKey(KeyCode.W))
	  {
	     transform.Translate(Vector3.forward*Time.deltaTime*(-MoveSpeed));
	  }
	  if(Input.GetKey(KeyCode.S))
	  {
	     transform.Translate(Vector3.forward*Time.deltaTime*MoveSpeed);
	  }
	  //按下空格键,发射子弹
	  if(Input.GetKey(KeyCode.Space))
	  {
	     Instantiate(Bullet,BulletPosL.transform.position,Quaternion.Euler(new Vector3(0,1,0)));
	     Instantiate(Bullet,BulletPosR.transform.position,Quaternion.identity);
	  }
	}
	
	#region 减血
	public void Hit(int Value)
	{
	   if(MaxHP>0)
	   {
	     MaxHP-=Value;
	   }else
	   {
		 Destroy(this.gameObject);
	   }
	}
	#endregion
	
	#region 增加分数 
	public void Add(int Value)
	{
		Grade+=Value;
	}
	#endregion

}

       在这段代码中,Bullet是我们的子弹对象,它从飞机的两个子弹发射位置BulletPosL、BulletPosR发射,向屏幕上方按照一定的速度缓缓移动,当子弹与敌人碰撞时,子弹对象将销毁,同时敌人生命值减少。Bullet对象对应于我们的一个Prefab。BulletPosL、BulletPosR对应于飞机上的两个位置。如图:


      我们的子弹Bullet是一个绑定了脚本的Capsule。它的代码定义如下:

using UnityEngine;
using System.Collections;

public class Bullet : MonoBehaviour {
	
	//定义子弹的移动速度
	public float MoveSpeed=10F;
	//定义子弹的销毁时间
	public float DestroyTime=2.0F;
	//定义子弹对敌人的伤害值
	public int Damage=2;
	//玩家飞机
	private GameObject Player;
	
	void Start()
	{
		Player=GameObject.Find("Player");
	}
	void Update () 
	{
	   //移动子弹
	   transform.Translate(Vector3.up * MoveSpeed * Time.deltaTime);
	}
	
	//碰撞事件捕捉
	void OnTriggerEnter(Collider mCollider)
	{
		if(mCollider.gameObject.tag=="Enemy")
		{
			//敌人减血
			mCollider.gameObject.GetComponent<Enemy>().Hit(Damage);
			//我方得分
			Player.GetComponent<Player>().Add(1);
			//销毁子弹
			Destroy(this.gameObject);
		}
	}

     //当离开摄像机范围时触发销毁事件
	void OnBecameInvisible()
	{
	  Destroy(this.gameObject);
	}
}

   

   三、敌人飞机

   在我们的游戏中共有三种敌机,我们先将它们制作成预设。然后通过敌机生成器不断地生成敌机。如图:


     和子弹相反,我们希望敌机从屏幕上方以一定速度向下移动,当碰到玩家飞机或者子弹时,将减少生命值。为此,我们这样定义敌机的脚本:

using UnityEngine;
using System.Collections;

public class Enemy : MonoBehaviour {

	//移动速度
	public float MoveSpeed=1.5F;
	//爆炸
	public GameObject Explosion;
	//最大生命值
	public int MaxHP=100;
	
	
	void Update () 
	{
	  //移动飞机
	  transform.Translate(Vector3.forward*Time.deltaTime*MoveSpeed);
	}
	
	public void Hit(int Value)
	{ 
	  //如血量不低于0,则敌人飞机掉血
	  if(MaxHP>0)
	  {	
	     MaxHP-=Value;
	  }else
	  {
		 //产生爆炸效果
         Instantiate(Explosion,transform.position,Quaternion.Euler(new Vector3(90,180,0)));
		 //销毁敌机
		 Destroy(this.gameObject);
	  }
    }
	
	void OnTriggerEnter(Collider mCollider)
	{
	  //如果与玩家飞机遭遇,则双方减血
	  if(mCollider.gameObject.tag=="Player")
	  {
		 //敌机掉血
		 this.Hit(2);
		 //玩家飞机掉血
		 Transform mPlayer=mCollider.gameObject.transform.Find("Player");
		 mPlayer.GetComponent<Player>().Hit(2);
	  }
	}
	
	
	void OnBecameInvisible()
	{
	  Destroy(this.gameObject);
	}
}
      接下来,我们通过敌机生成器来不断地生成敌机。敌人生成器是我们预制在游戏场景中的空游戏体,它位于游戏场景的顶部。我们将下面的脚本绑定到游戏生成器 上,使其可以不断地生成敌人:

using UnityEngine;
using System.Collections;

public class SpawnEnemy : MonoBehaviour {
	
	//定义敌人速度
	public float SpawnTime=1.0f;
	//定义敌人对象数组
	public GameObject[] Enemys;
	
	void Start () 
	{
	   StartCoroutine("Spawn");
	}
	
	//通过迭代器生成敌人
	IEnumerator Spawn()
	{
	   //等待
	   yield return new WaitForSeconds(SpawnTime);
	   //克隆对象
       Instantiate(Enemys[Random.Range(0,3)],new Vector3(transform.position.x * Random.Range(-1F,1F),
			transform.position.y,-4),Quaternion.Euler(new Vector3(90,180,0)));  
	   StartCoroutine("Spawn");
	}
	
}
      其中Enemys对应到我们的敌人预设,每隔一段时间,我们随机地产生一种敌人,该敌人将从屏幕上方缓缓向下移动。

      

    四、碰撞检测

    在这个游戏中,主要存在子弹与敌机的碰撞、玩家飞机与敌机的碰撞两种形式。它们分别被定义在Bullet.cs和Enemy.cs两个类文件中。

//碰撞事件捕捉
	void OnTriggerEnter(Collider mCollider)
	{
		if(mCollider.gameObject.tag=="Enemy")
		{
			//敌人减血
			mCollider.gameObject.GetComponent<Enemy>().Hit(Damage);
			//我方得分
			Player.GetComponent<Player>().Add(1);
			//销毁子弹
			Destroy(this.gameObject);
		}
	}
void OnTriggerEnter(Collider mCollider)
	{
	  //如果与玩家飞机遭遇,则双方减血
	  if(mCollider.gameObject.tag=="Player")
	  {
		 //敌机掉血
		 this.Hit(2);
		 //玩家飞机掉血
		 Transform mPlayer=mCollider.gameObject.transform.Find("Player");
		 mPlayer.GetComponent<Player>().Hit(2);
	  }
	}
     

     五、爆炸特效

     当敌机被摧毁时,将显示爆炸特效,我们这里采用一组2D贴图来实现爆炸特效,原理是改变贴图的mainTextureScale和mainTextureOffset两个属性值。我们来一起看代码:

using UnityEngine;
using System.Collections;

public class Explosion : MonoBehaviour {
	
	//动画序列索引
	private int index=0;
	//声音
	private AudioSource mAudio;
	
	void Start()
	{
	   mAudio=GetComponent<AudioSource>();
	}
	
	void FixedUpdate () 
	{
	   if(index<8)
	   {
		 this.renderer.sharedMaterial.mainTextureScale=new Vector2(1.0F/8,1);
		 this.renderer.sharedMaterial.mainTextureOffset=new Vector2(index * 1.0F/8,0);
		 index+=1;
	   }else
		{
		  mAudio.Play();
		  Destroy(this.gameObject);
		}
	}
}
     其中mAudio对应到一个AudioSource组件,我们在这里指定一个爆炸的音效。同样地,我们将爆炸制作成预设,该预设对应于Enemy.cs中的Explosion。

     好了,到这里今天的 内容就讲解完了,我们一起来看看最终的效果吧!


     希望今天的内容大家能够喜欢。学了这么长时间的Unity3D,感慨还是挺多的,很多东西你不努力去做,是永远做不好的,你不给自己压力,你不会知道自己有多优秀。本项目源代码可以从这里下载。


     每日箴言: 不管活到什么岁数,总有太多思索、烦恼与迷惘。一个人如果失去这些,安于现状,才是真正意义上的青春的完结。——  渡边淳一




      喜欢我的博客请记住我的名字:秦元培,我的博客地址是blog.csdn.net/qinyuanpei
      转载请注明出处,本文作者:秦元培,本文出处:http://blog.csdn.net/qinyuanpei/article/details/25158323


2017-08-30 17:07:20 sun1018974080 阅读数 5006
  • Unity 值得看的500+ 技术内容列表

    Unity3D是由Unity Technologies开发的一个让玩家轻松创建诸如三维视频游戏、建筑可视化、实时三维动画等类型互动内容的多平台的综合型游戏开发工具,是一个全面整合的专业游戏引擎。

        首先你应该搞清楚的一点AI脚本属于一个工具类脚本,工具类脚本的含义就是他应当是由策划人员来绑定游戏对象使用的。也就是说AI脚本程序员应当写的非常的灵活,策划人员可以通过修改脚本对外的变量数值接口就能控制其中的敌人AI。接着创建一个c#脚本AI.CS ,如下图所示,目前脚本对外留出枚举接口变量,策划人员在使用这条脚本时选择对应敌人类型即可。(注:这里仅仅是示例,细致的话还可以将很多敌人详细的信息写入,如:攻击速度、技能类型、移动速度、命中率、攻击百分比、等等,但是一定要让你的脚本写的比较灵活,策划人员在外面选择即可完成)因为目前是一个示例,所以我在这里只简单的区分的敌人类型。

 

Unity3D研究院之游戏开发中的人工智能AI(三十八) - 雨松MOMO程序研究院 - 1

 

下面时这段简单AI的脚本

AI.CS

 

 

如下图所示,我们在游戏世界中添加两个敌人,此时给敌人们都绑定上AI的脚本,编辑器中设置不同的敌人类型,敌人执行各自的生命周期,当你控制主角与接近敌人时,敌人开始追击你并且向你展开攻击。

 

Unity3D研究院之游戏开发中的人工智能AI(三十八) - 雨松MOMO程序研究院 - 2

 

         demo仅仅是一个示例,主要希望大家明白一个道理。在编写Unity游戏脚本时,一定要想想这条脚本和对象的生命周期,切记每一条脚本只管和自己有关的东西,和自己无关的东西一概不要管。不然你会发现你的脚本会越写越乱,下一篇文章我会写点我平时在Unity3D开发中时如何搭建架构的,希望大家多多讨论,互相学习。

下载地址:http://vdisk.weibo.com/s/hmJUs

2014-04-01 18:52:54 qinyuanpei 阅读数 24382
  • Unity 值得看的500+ 技术内容列表

    Unity3D是由Unity Technologies开发的一个让玩家轻松创建诸如三维视频游戏、建筑可视化、实时三维动画等类型互动内容的多平台的综合型游戏开发工具,是一个全面整合的专业游戏引擎。

        大家好,欢迎大家关注由我为大家带来的Unity3D游戏开发系列文章,我的博客地址为:http://blog.csdn.net/qinyuanpei。

       在上一篇文章中,我们基本上实现了一个小地图的功能,今天呢,我们来实现怪物AI,所谓怪物AI就是指我们为怪物编写一定的算法,使其可以具备一定程度的智能化,以增强游戏的可玩性。在一般的RPG游戏中,怪物通常在一个游戏设定的范围内巡逻,当玩家进入怪物的警戒范围时,怪物就会由巡逻状态转变为攻击状态,向玩家进行攻击,那么,我们今天就来实现一个简单的怪物AI吧,下面我们一起来看代码:

using UnityEngine;
using System.Collections;

public class AI : MonoBehaviour {

	//定义怪物的四种状态:站立、行走、奔跑、无所事事
	public const int STATE_STAND=0;
	public const int STATE_WALK=1;
	public const int STATE_RUN=2;
	
	//怪物当前状态
	private int NowState;
	//游戏角色
	public GameObject Hero;
	//怪物思考时间
	public const int AI_THINK_TIME=2;
	//触发怪物攻击的临界距离
	public const int AI_ATTACT_DISTANCE=10;
	
	//上一次思考的时间
	private float LastThinkTime;
	
	void Start () 
	{
		
	}
	
	void Update () 
	{
	   //当敌人与怪物间的距离小于攻击范围半径的时候
	   if(Vector3.Distance(transform.position,Hero.transform.position)<AI_ATTACT_DISTANCE)
	   {
	      //敌人开始奔跑
	      this.GetComponent<Animation>().Play("run");
	      //敌人进入奔跑状态
	      NowState=STATE_RUN;
	      //使敌人面向角色
	      transform.LookAt(Hero.transform);
	      //向玩家靠近
	      transform.Translate(Vector3.forward*Time.deltaTime * 5);
	   }else
	   {
	      //当当前时间与上一次思考时间的差值大于怪物的思考时间时怪物开始思考
	      if(Time.time-LastThinkTime>AI_THINK_TIME)
	      {
	         //开始思考
	         LastThinkTime=Time.time;
	         //获取0-3之间的随机数字
	         int Rnd=Random.Range(0,2);	     
	         //根据随机数值为怪物赋予不同的状态行为
	         switch(Rnd)
	         {
	            case 0:
	            //站立状态
	            this.GetComponent<Animation>().Play("idle");
	            NowState=STATE_STAND;
	            break;
	            
	            case 1:
	            //行走状态
	            //使怪物旋转以完成行走动作
	            Quaternion mRotation=Quaternion.Euler(0,Random.Range(1,5)*90,0);
	            transform.rotation=Quaternion.Slerp(transform.rotation,mRotation,Time.deltaTime*1000);
	            //播放动画
	            this.GetComponent<Animation>().Play("walk");
	            //改变位置
	            transform.Translate(Vector3.forward*Time.deltaTime * 3);
	            NowState=STATE_WALK;
	            break;
	           
	            case 2:
	            //奔跑状态
	            this.GetComponent<Animation>().Play("run");
	            transform.Translate(Vector3.forward*Time.deltaTime * 5);
	            NowState=STATE_RUN;
	            break;
	         } 
	      }
	   }
	}
}

          在上面的代码中,能够触发怪物状态发生变化的有两个条件,第一,是玩家进入了怪物的警范围,此时怪物将面向玩家奔跑靠近;第二,当前时间与怪物上一次思考的时间之差大于怪物的思考时间,此时,怪物将随机作出反应。

          好,下面我们回到游戏界面当中来。


        如图,博主事先从官方资源商店里下载了一个人物模型。在这个模型中,设计者已经为我们设计好了人物动画,我们将这个模型拖放到场景中,调整到合适的位置,并将人物默认动画设置为idle,下面我们将刚才写好的脚本拖放到此模型上,并设置Hero为我们的玩家对象,在这里我们使用了官方提供的第三人称角色控制器组件,最终实现的效果如下 :



       可以看到,在不同的时刻,怪物可以自己执行不同的状态动作,当玩家靠近怪物的时候,会被敌人追击,这就是今天的内容啦,谢谢大家!

  

        

Unity3D如何编写AI

阅读数 1203