ActionGame游戏总结

导入人物动画模型,资源点击player属性在Rig中点击Humanoid,Configure,在右侧属性的人物骨骼点击每一个关节在scene视图中观察是否一致,如果不一致在hierarchy中拖动该关节到有测属性中,点击Done--->apply发现在player模型中创建了一个Avatar,选中除了player的其他动画,全部选择Humanoid,Avatar Definition选择Copy from other Avatar,最后的source把第一个的Avatar拖进去,接着导入武器动画,在Rig的animation Rig中全部选择none。使用NGUI开发界面,拖动武器到hierarchy中,把人物所有部分添加材质,直接拖动到身体部位上即可,把武器拖动到人物右手下面,坐标reset即可看到人物手里拿着剑

导入NGUI和UI所有素材,在assets-->ActionGameStarterKit-->atlas选中所有图片,右键NGUI--->open atlas Maker,打开NGUI--->open--->prefab Toolbar,添加UI Root,添加图片和按钮(添加box collider和UI Button属性和Play Sound),点击player ,Windows--->animation添加自动旋转动画

注意,些脚本的名字中间不能有空格。

添加一个GameObject名为MenuController,添加脚本

整个脚本代码如下:

public Color purple;
    public SkinnedMeshRenderer headMeshRender;
    public Mesh[] headMeshArray;
    private int headMeshIndex = 0;
    private Color[] colorArray;
    private int colorIndex = -1;
    void Start()
    {
        colorArray = new Color[] { Color.blue, Color.red, Color.green , Color.cyan , purple };
        //不因游戏加载下个场景而销毁当前的脚本
        DontDestroyOnLoad(this.gameObject);
    }

    public void OnHeadMeshNext()
    {
        headMeshIndex++;
        headMeshIndex %= headMeshArray.Length;
        headMeshRender.sharedMesh = headMeshArray[headMeshIndex];
    }
    public void OnHandmeshNext()
    {


    }
    public void OnChangeColorBlue()
    {
        colorIndex = 0;
        OnChangeColor(Color.blue);
    }
    public void OnChangeColorRed()
    {
        colorIndex = 1;
        OnChangeColor(Color.red);
    }
    public void OnChangeColorGreen()
    {
        colorIndex = 2;
        OnChangeColor(Color.green);
    }
    public void OnChangeColorBlueGreen()
    {
        colorIndex = 3;
        OnChangeColor(Color.cyan);
    }
    public void OnChangeColorPurple()
    {
        colorIndex = 4;
        OnChangeColor(purple);
    }
   void OnChangeColor(Color c)
    {
        headMeshRender.material.color = c;
    }

    //点击play,进行信息的存储
    public void OnPlay()
    {
        PlayerPrefs.SetInt("HeadMeshIndex", headMeshIndex);
        PlayerPrefs.SetInt("ColorIndex", colorIndex);
        //当前场景为0,下一个场景为1
        Application.LoadLevel(1);
    }

这里注意的是把这个脚本放到一个Gameobject里面,在onStart函数中调用dontDestroyOnLoad,这样加载到第二个场景的时候该脚本的数组不会丢失


效果如下



对于相机的跟随,使用下面的函数:



然后创建场景002,搭建环境,单击Main Camera点击Gameobject--->align with view,给相机添加跟随角色移动的脚本代码如下:

 private Transform player;

	void Start () {
        player = GameObject.FindGameObjectWithTag(Tags.player).transform;	
	}
	
	void Update () {
        Vector3 targetPos = player.position + new Vector3(2f,2.6f,0);
        transform.position = Vector3.Lerp(transform.position,targetPos,Time.deltaTime);
        Quaternion targetRotation = Quaternion.LookRotation(player.position - transform.position);
        transform.rotation = Quaternion.Slerp(transform.rotation,targetRotation,Time.deltaTime);
	}
}

这里注意的是

 transform.position = Vector3.Lerp(transform.position,targetPos,Time.deltaTime);

这行代码是让相机跟随猪脚移动,效果如下:


但是如果加了下面两段代码

    Quaternion targetRotation = Quaternion.LookRotation(player.position - transform.position);
    transform.rotation = Quaternion.Slerp(transform.rotation,targetRotation,Time.deltaTime);

这里player.positon - transform.position是方向向量,让transform.rotation也即相机的旋转从它当前的角度,插值转动到猪脚的位置

这样相机会跟随猪脚不仅移动镜头同时也会注视它并且跟随,效果如下



给player添加character Controller,把三把武器放到人物的手上,给player添加PlayerMove脚本

 private CharacterController cc;
    public float speed = 4;
     void Awake()
    {
        cc = this.GetComponent<CharacterController>();
    }
    void Update()
    {
        float h = Input.GetAxis("Horizontal");
        float v = Input.GetAxis("Vertical");
        if (Mathf.Abs(h)>0.1f|| Mathf.Abs(v) > 0.1f)
        {
            Vector3 targetDir = new Vector3(-v, 0, h);
            transform.LookAt(targetDir+transform.position);
            cc.SimpleMove(transform.forward * speed);
        }
    }

给animator添加动画的跳转条件


在代码中移动添加条件

 if (Mathf.Abs(h)>0.1f|| Mathf.Abs(v) > 0.1f)
        {
            animator.SetBool("walk", true);
            if (animator.GetCurrentAnimatorStateInfo(0).IsName("PlayerRun"))
            {
                Vector3 targetDir = new Vector3(-v, 0, h);
                transform.LookAt(targetDir + transform.position);
                cc.SimpleMove(transform.forward * speed);
            }         
        }
        else
        {
            animator.SetBool("walk", false);
给屏幕添加攻击的按钮,要把按钮和事件的处理方法绑定,通过委托的方式,先new一个委托,this代表这个脚本中,第二个参数表示调用哪个方法,然后给按钮的onClick方法add委托即可


给player添加PlayerAnimationAttack脚本,我们发现PlayerAttackA后面有个连线PlayerAttackB这是当重复点普通攻击会进行角色连击,实现2连击的效果,做法如下,找到PlayerAttackA动画


在右侧属性有个Event也就是在该动画一个区间内,插入两个函数,AttackBEvent1和AttackBEvent2,而且要在代码中写入这两个函数


注意这里PlayerAttackA到B的连线属性中Has Exit Time不能不勾选,否则永远在playStand到PlayAttackA直接循环

    

给player添加PlayerAnimationAttack脚本

   private Animator animator;
    //用一个bool来标识是否可以进行AttackB的动画播放
    private bool isCanAttackB;

	void Start () {
        animator = GetComponent<Animator>();
        EventDelegate NormalAttackEvent = new EventDelegate(this, "OnNormalAttackClick");
        GameObject.Find("NormalAttack").GetComponent<UIButton>().onClick.Add(NormalAttackEvent);

        EventDelegate RandomAttackEvent = new EventDelegate(this, "OnRandomAttackClick");
        GameObject.Find("RandomAttack").GetComponent<UIButton>().onClick.Add(RandomAttackEvent);

        EventDelegate RedAttackEvent = new EventDelegate(this, "OnRedAttackClick");
        GameObject.Find("RedAttack").GetComponent<UIButton>().onClick.Add(RedAttackEvent);
        //先让巨人攻击按钮隐藏
        GameObject.Find("RedAttack").SetActive(false);
    }
	
	
    public void OnNormalAttackClick()
    {
        if (animator.GetCurrentAnimatorStateInfo(0).IsName("PlayerAttackA")&& isCanAttackB)
        {
            animator.SetTrigger("attackB");
        }
        else
        {
            animator.SetTrigger("attackA");
        }
    }
    public void OnRandomAttackClick()
    {
        animator.SetTrigger("attackRange");
    }
    public void OnRedAttackClick()
    {

        animator.SetTrigger("attackA");
    }
   //进入二连击,就可以设置标识为true
    public void AttackBEvent1()
    {
        //当进入该函数说明可以播放AttackB动画
        isCanAttackB = true;
    }
    public void AttackBEvent2()
    {
        isCanAttackB = false;
    }

接下来把boss的FBX文件拖到asset中,把怪物和武器拖到场景中,创建boss的状态机名为BossController,设置好boss的所有动画的跳转条件,给boss添加脚本,注意的是如果动画中添加跳转条件是Trigger那么跳转回来的条件不需要加Trigger,什么都不加就对了

boss的攻击和移动的脚本代码如下:

    private Transform player;
    private Animator animator;
    public float attackTime=0;
    public float attackTimer=2;
    //boss的攻击距离
    public float attackDistance = 2.5f;
    public float speed = 2;
    private CharacterController cc;
    void Start () {
        cc = GetComponent<CharacterController>();
        animator = GetComponent<Animator>();
        player = GameObject.FindGameObjectWithTag(Tags.player).transform;
        attackTime = attackTimer;
	}
	
	void Update () {
        Vector3 TargetPos = player.position;
        TargetPos.y = player.position.y;
        //让怪物朝向主角
        transform.LookAt(TargetPos);
        float distance = Vector3.Distance(TargetPos, transform.position);
        if(distance<=attackDistance){
            //在攻击距离之内
            attackTime += Time.deltaTime;
            if (attackTime>attackTimer)
            {
                //在攻击范围内,每过2秒进行一次攻击
                int i=Random.Range(0,2);
                if (i==0)
                {
                    animator.SetTrigger("attack1");
                }
                else
                {
                    animator.SetTrigger("attack2");
                }
                attackTime = 0;
            } else
            {
                animator.SetBool("walk", false);
            }
        }
        else
        { //在攻击距离之外就要跑过去
            attackTime = attackTimer;
            if (animator.GetCurrentAnimatorStateInfo(0).IsName("BossRun01"))
            {
                cc.SimpleMove(transform.forward * speed);
            }
            animator.SetBool("walk",true);
        }
	}

接下来导入怪物的模型动画,添加动画状态机和移动攻击脚本,不赘述

接下来把怪物和boss拖动到prefab中并删除,然后要批量生产怪物,

在场景的四个边角放四个gameobject名为MonsterSpawn和两个BossSpawn,添加脚本用于产生怪物

       public GameObject prefab;

        //产生怪物
	public GameObject Spawn () {
              return  Instantiate(prefab,transform.position,transform.rotation)as GameObject;	
	}
把prefab中的怪物和boss拖动到脚本中的prefab中


给EnemySpawn添加脚本名为SpawnManager

在脚本中创建

public EnemySpawn[] enemySpawnArray;
public EnemySpawn[] bossSpawnArray;
而在脚本属性中拖动四个位置的monsterSpawn和BossSpawn到两个数组中


代码如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//调用list就要加这个
using System.Collections.Generic;

public class SpawnManagere : MonoBehaviour {

    public EnemySpawn[] enemySpawnArray;
    public EnemySpawn[] bossSpawnArray;
    public List<GameObject> enemyList = new List<GameObject>();
    void Start () {
        StartCoroutine(Spawn());
	}
	
    IEnumerator Spawn()
    {
        //第一波敌人的生成,在遍历上下左右四个位置,每个位置调用Spawn方法来产生一个怪物
        foreach (EnemySpawn s in enemySpawnArray)
        {
            enemyList.Add(s.Spawn());
        }
        while (enemyList.Count>0)
        //如果敌人没有杀完,那就等0.2秒再看有没有杀完
        {
            yield return new WaitForSeconds(0.2f);
        }
        //第二波敌人的产生
        foreach (EnemySpawn s in enemySpawnArray)
        {
            enemyList.Add(s.Spawn());
        }
        yield return new WaitForSeconds(0.5f);

        foreach (EnemySpawn s in enemySpawnArray)
        {
            enemyList.Add(s.Spawn());
        }
        while (enemyList.Count > 0)
        {
            yield return new WaitForSeconds(0.2f);
        }
        //第三波敌人的产生
        foreach (EnemySpawn s in enemySpawnArray)
        {
            enemyList.Add(s.Spawn());
        }
        yield return new WaitForSeconds(0.5f);

        foreach (EnemySpawn s in bossSpawnArray)
        {
            enemyList.Add(s.Spawn());
        }
      
    }
}


接下来我们要处理伤害,创建AttackAndDamage脚本

    public float hp = 100;
    public float normalAttack = 50;
    public float attackDistance = 1;
    private Animator animator;

    void Awake()
    {
        animator = GetComponent<Animator>();
    }

    public virtual void TakeDamage(float damage)
    {
        if (hp > 0)
        {
            hp -= damage;
        }
        if (hp>0)
        {
            animator.SetTrigger("damage");
            //如果boss受到伤害,创建boss的伤害特效
            if (this.tag==Tags.boss)
            {
                Instantiate(Resources.Load("HitBoss"),transform.position,transform.rotation);
            }
            //如果monster受到伤害,创建monster的伤害特效
            else if (this.tag == Tags.monster)
            {
                Instantiate(Resources.Load("HitMonster"), transform.position, transform.rotation);
            }
        }
        else
        {
            animator.SetBool("dead",true);
        }
    }
给打击特效添加1秒后销毁的脚本

 public float exitTime = 1;

	void Start () {
        Destroy(this.gameObject,exitTime);
	}
	

接下来在角色的PlayerAttackA,PlayerAttackB,PlayerAttackRange,PlayerAttackGun四个攻击动画的Events中的某个点添加四个函数 AttackA,AttackB,AttackRange,AttackGun

创建脚本PlayerAttackAndDamage拖动到Player中继承AttackAndDamage,

public class PlayerAttackAndDamage : AttackAndDamage
{
    public float attackB = 80;
    public float attackRange = 100;


    public void AttackA()
    {
        GameObject enemy= null;
        float distance = attackDistance;
        foreach (GameObject go in SpawnManagere._instance.enemyList)
        {
           //在角色释放普攻的时刻遍历所有怪物,找到距离角色最近的怪物
            float temp = Vector3.Distance(transform.position,go.transform.position);
            if (temp < distance)
            {
                enemy = go;
                distance = temp;
            }
        }//找到了距离角色最近的怪物而且距离在攻击范围内,就让角色朝向该怪物而且让怪物收到伤害
        if (enemy!=null)
        {
            Vector3 targetPos = enemy.transform.position;
            targetPos.y= transform.position.y;
            transform.LookAt(targetPos);
            enemy.GetComponent<AttackAndDamage>().TakeDamage(normalAttack);
        }
    }
attackB方法和A一样,

 public void AttackRange()
    {
        float distance = attackDistance;
        foreach (GameObject go in SpawnManagere._instance.enemyList)
        {
            //对于群攻技能,直接在范围内的怪物收到伤害即可
            float temp = Vector3.Distance(transform.position, go.transform.position);
            if (temp < distance)
            {
                go.GetComponent<AttackAndDamage>().TakeDamage(attackRange);
            }
        }
    }

这里有个小问题:

为什么这样就可以



这样就不行


下面添加子弹,在hierarchy中添加一个sphere,添加rigidbody,添加脚本,子弹的脚本如下:

public classpublic class Bullet : MonoBehaviour {

    public float speed = 10;
    //枪的攻击力为100
    public float attack = 100;

    void Start()
    {
        //3秒后销毁该子弹
        Destroy(this.gameObject,3);
    }

    void Update () {
        transform.Translate(Vector3.forward*speed*Time.deltaTime);  //transform.Translate是物体平移函数,
               //还有这里为什么用vector3.forward而不是transform.forward
    }

    void OnTriggerEnter(Collider other)
    {
        if (other.tag==Tags.monster||other.tag==Tags.boss)
        {
            other.GetComponent<AttackAndDamage>().TakeDamage(attack);
        }
    }
}
 

 
然后给枪添加脚本,用来发射子弹 
public class WeaponGun : MonoBehaviour {

    //拖动子弹的位置到这里
    public Transform bulletPos;
    //拖动子弹的prefab到这里
    public GameObject bulletPrefeb;
    public float attack = 100;

    public void shot()
    {
       GameObject go= Instantiate(bulletPrefeb,bulletPos.position,transform.root.rotation);
        go.GetComponent<Bullet>().attack = attack;
    }

}
然后添加monster的攻击伤害函数,在它的攻击动画event中添加MonsterAttack函数,在prefab中给monster添加MonsterAttackAndDamage脚本继承AttackAndDamage

public class MonsterAttackAndDamage : AttackAndDamage {

    private Transform player;

    void Awake()
    {
        base.Awake();//调用父类的awake拿到animator组件
        player = GameObject.FindGameObjectWithTag(Tags.player).transform;//拿到主角的位置
    }

    public void MonsterAttack()
    {
        if (Vector3.Distance(player.position,transform.position)<attackDistance)
        {
            player.GetComponent<AttackAndDamage>().TakeDamage(normalAttack);
        }

    }
}
接下来发现人物死了怪物还在攻击,我们让人死了怪物不再动弹了,在MonsterMove中

private PlayerAttackAndDamage playerAttackAndDamage;


    void Start () {
        player = GameObject.FindGameObjectWithTag(Tags.player).transform;
        //注意playerAttackAndDamage是小写,如果是大写那就是那个脚本名字了
        playerAttackAndDamage = player.GetComponent<PlayerAttackAndDamage>();
}

void Update () {
        if (playerAttackAndDamage.hp<=0) {
            animator.SetBool("walk",false);
            return;
        }

}
添加这些内容,注意的是如果写成 playerAttackAndDamage = GetComponent<PlayerAttackAndDamage>();会报空指针错误,第二,在update的if中如果return,那么就退出update函数了,就不再执行update下面的怪物攻击角色的代码


我们发现敌人打主角的时候主角不能发动技能了,原因是怪物打击人物的时候,人物和怪物都会调用Damage动画,我们只让怪物和boss调用动画即可,在AttackAndDamage中

 if (hp > 0)
        {
            if (this.tag == Tags.monster||this.tag==Tags.boss)
            {
                animator.SetTrigger("damage");
            }
}
添加一个if即可
最后也是最关键的,在animator中set  dead为true的时候要把该对象销毁,在AttackAndDamage中 

   else
        {
            animator.SetBool("dead", true);
            if (this.tag == Tags.monster || this.tag == Tags.boss)
            {
                SpawnManagere._instance.enemyList.Remove(this.gameObject);
                Destroy(this.gameObject, 1);
                this.GetComponent<CharacterController>().enabled = false;
            }
        }

在游戏测试中发现报错:


在PlayerAttackAndDamage脚本中

public void AttackRange()
    {
        float distance = attackDistance;
        foreach (GameObject go in SpawnManagere._instance.enemyList)
        {
            //对于群攻技能,直接在范围内的怪物收到伤害即可
            float temp = Vector3.Distance(transform.position, go.transform.position);
            if (temp < distance)
            {
                go.GetComponent<AttackAndDamage>().TakeDamage(attackRange);
            }
        }
    }
我们遍历怪物集合,在攻击范围内就收到伤害,如果该伤害让怪物死了,那么就在list中移除该怪物,然而在foreach中正在遍历,不能修改list,解决方法是创建一个临时list来保存enemyList中的元素,遍历元素、

public void AttackRange()
    {
        List<GameObject> list = new List<GameObject>();
        foreach (GameObject go in SpawnManagere._instance.enemyList)
        {
            list.Add(go);
        }
        float distance = attackDistance;
        foreach (GameObject go in list)
        {
            //对于群攻技能,直接在范围内的怪物收到伤害即可
            float temp = Vector3.Distance(transform.position, go.transform.position);
            if (temp < distance)
            {
                go.GetComponent<AttackAndDamage>().TakeDamage(attackRange);
            }
        }
    }
接下来添加boss的攻击动画,在boss的attack的动画中添加event函数名,给boss模型添加脚本名为BossAttackAndDamage,大同小异,参照MonsterAttac的即可

public class BossAttackAndDamage : AttackAndDamage {

    private Transform player;
    void Awake()
    {
        base.Awake();//调用父类的awake拿到animator组件
        player = GameObject.FindGameObjectWithTag(Tags.player).transform;//拿到主角的位置
    }

    public void BossAttack1()
    {
        if (Vector3.Distance(player.position, transform.position) < attackDistance)
        {
            player.GetComponent<AttackAndDamage>().TakeDamage(normalAttack);
        }

    }
    public void BossAttack2()
    {
        if (Vector3.Distance(player.position, transform.position) < attackDistance)
        {
            player.GetComponent<AttackAndDamage>().TakeDamage(normalAttack);
        }
    }
}

然后开发掉落物品,在hierarchy创建2个sphere,拖放到resource中,添加脚本

public enum AwardType
{
    //奖励枪支
    Gun,
    //奖励双刃剑
    DualSward
}
public class AwardItem : MonoBehaviour {

    public AwardType type;
    public bool isMove=false;
    public Transform player;
    public float speed = 8;
    private void Update()
    {
        if (isMove)
        {
            transform.position=Vector3.Lerp(transform.position,player.position,speed*Time.deltaTime);
          //当小球碰到角色的时候
            if (Vector3.Distance(transform.position, player.position) <0.5f)
            {
                  player.GetComponent<PlayerAward>().GetAward(type);
                Destroy(this.gameObject);
            }
        }
    }

    void Start()
    {
        GetComponent<Rigidbody>().velocity = new Vector3(Random.Range(-5,5),0,Random.Range(-5,5));
    }
    private void OnCollisionEnter(Collision collision)
    {
        if (collision.collider.tag==Tags.ground)
        {
            GetComponent<Rigidbody>().useGravity = false;
            GetComponent<Rigidbody>().isKinematic = true;
            //当球球落到地面上时候会进行碰撞检测
            GetComponent<SphereCollider>().isTrigger = true;
            GetComponent<SphereCollider>().radius = 2;
        }
    }

    private void OnTriggerEnter(Collider other)
    {
        //当球球碰到人物的时候球球会自动移动到角色身边
        if (other.tag==Tags.player)
        {
            isMove = true;
            player = other.transform;
        }
    }
}

这里注意的是,在小球落到地面的时候开启触发检测,让检测的范围比较大,这样,如果猪脚进入检测范围的时候,小球会自动跑到猪脚身边


 

 
给Player添加脚本PlayerAward,由于三把武器已经放到了角色手里只是其他两把武器隐藏了,所以切换武器setActive即可 

public class PlayerAward : MonoBehaviour {
    public GameObject singleSword;
    public GameObject dualSword;
    public GameObject gun;
    public float gunTime = 0;
    public float dualSwordTime = 0;
    public float exitTime = 5;
    private void Update()
    {
        //如果双刃剑和枪时间超过了5秒就切回原来的单剑
        if (dualSwordTime>0)
        {
            dualSwordTime -= Time.deltaTime;
           
        }
        if (dualSwordTime<0)
        {
            TurnToSingleSword();
        }
        if (gunTime > 0)
        {
            gunTime -= Time.deltaTime;
        }
        if (gunTime < 0)
        {
            TurnToSingleSword();
        }
    }
    //小球碰到人物时候触发该方法,传入type参数,如果是双刃剑,那么让角色切换成双刃剑武器
    public void GetAward(AwardType type)
    {
        if (type == AwardType.DualSward)
        {
            TurnToDualSword();
        }
        else if (type == AwardType.Gun)
        {
            TurnToGun();
        }
    }

    void TurnToDualSword()
    {
        singleSword.SetActive(false);
        dualSword.SetActive(true);
        gun.SetActive(false);
        gunTime = 0;
        dualSwordTime = exitTime;
  }
    void TurnToGun()
    {
        singleSword.SetActive(false);
        dualSword.SetActive(false);
        gun.SetActive(true);
        dualSwordTime = 0;
        gunTime =exitTime;
    }

    void TurnToSingleSword()
    {
        singleSword.SetActive(true);
        dualSword.SetActive(false);
        gun.SetActive(false);
        gunTime = 0;
        dualSwordTime = 0;
}
}
在场景中把球球删去,让怪物死亡调出来,在AttackAndDamage脚本中

          animator.SetBool("dead", true);
            if (this.tag == Tags.monster || this.tag == Tags.boss)
            {
                SpawnManagere._instance.enemyList.Remove(this.gameObject);
                Destroy(this.gameObject, 1);
                //生成奖励物品
                AwardProduce();
              this.GetComponent<CharacterController>().enabled = false;
            }
其中AwardProduce这样写

  //奖励物品的产生
    void AwardProduce()
    {
        int count = Random.Range(1, 3);
        for(int i = 0; i < count; i++)
        {
            int index = Random.Range(0, 2);
            if (index ==0)
            {
                GameObject.Instantiate(Resources.Load("item_DualSword"),transform.position+Vector3.up,Quaternion.identity);
            }else if (index == 1)
            {
                GameObject.Instantiate(Resources.Load("item_Gun"), transform.position + Vector3.up, Quaternion.identity);
            }
        }
    }

下面进行普通攻击和red攻击在UI中的显示



给Attack添加脚本,因为Attack里面有3个按钮,可以获取里面的按钮进行显示

public class UiAttack : MonoBehaviour {

    public static UiAttack _instance;
    public GameObject normalAttack;
    public GameObject rangeAttack;
    public GameObject redAttack;

    private void Awake()
    {
        _instance = this;
    }
    private void Start()
    {
        normalAttack = transform.Find("NormalAttack").gameObject;
        rangeAttack = transform.Find("RandomAttack").gameObject;
        redAttack = transform.Find("RedAttack").gameObject;
    }

    public void TurnToOneAttack()
    {
        normalAttack.SetActive(false); 
        rangeAttack.SetActive(false);
        redAttack.SetActive(true);
    }

    public void TurnToTwoAttack()
    {
        normalAttack.SetActive(true);
        rangeAttack.SetActive(true);
        redAttack.SetActive(false);
    }
}
注意的是如果没有

   private void Awake()
    {
        _instance = this;
    }
在其他脚本中调用该单例会报空指针

当切换到枪的状态运行该方法即可

   UiAttack._instance.TurnToOneAttack();
在PlayerAnimationAttack脚本的OnRedAttackClick方法里会设置  animator.SetTrigger("attackGun");

调用PlayerAttackAndDamage脚本的AttackGun方法

在脚本最上面public WeaponGun gun;

在AttackGun方法里面gun.shot();即可这样切换成枪点击red攻击会发射一颗子弹

然后添加游戏的右上角小地图



红色三角为角色的面向,角色左转右转让三角在地图的十字的中心点旋转,在三角的外面添加一个invisible widget,让这个invisible widget转动就行,给地图添加一个脚本

public class MiniMap : MonoBehaviour {


    public static MiniMap _instance;
    private Transform playerSanJiao;

    private void Awake()
    {
        _instance = this;
        playerSanJiao = transform.Find("Container");
    }


    public Transform GetSanJiao()
    {
        return playerSanJiao;
    }
}
给Player添加脚本
public class PlayerMap : MonoBehaviour {
    private Transform playerSanJiao;

    private void Start()
    {
        playerSanJiao = MiniMap._instance.GetSanJiao();
    }
    private void Update()
    {
        playerSanJiao.localEulerAngles = new Vector3(0, 0,-(transform.eulerAngles.y));
    }
}

这里注意的是,我们要把人物在三维的左右转动的角度放到平面地图的三角转动的角度,因为三角在地图上面x,y是变化的,z轴永远是0,所以我们只给三角的z轴角度赋值,在三维中,人物的左右是xz平面,所以我们要拿到y轴的角度,利用欧拉角transform.eulerAngles.y拿到绕y轴的角度赋给平面三角的z轴角度即可


然后添加地图上的Monster图标,放到prefab中,在map的脚本中再添加2个方法

 public GameObject GetBossMap()
    {
        //由于要在小地图的NGUI上创建Monster的图标,所以不能用instantiate来创建
        //addChild第一个参数是在该地图上添加,
        GameObject go= NGUITools.AddChild(this.gameObject,enemyMapPrefab);
        go.GetComponent<UISprite>().spriteName = "BossIcon";
        return go;
    }
    public GameObject GetMonsterMap()
    {
        GameObject go = NGUITools.AddChild(this.gameObject, enemyMapPrefab);
        go.GetComponent<UISprite>().spriteName = "EnemyIcon";
        return go;
    }
创建EnemyMap放到Monster和boss的prefab中

public class EnemyMap : MonoBehaviour {
    private Transform icon;
    private Transform player;
    private void Start()
    {
        if (this.tag==Tags.boss)
        {
           icon= MiniMap._instance.GetBossMap().transform;
        }else if (this.tag == Tags.monster)
        {
           icon = MiniMap._instance.GetMonsterMap().transform;
        }
        player = GameObject.FindGameObjectWithTag(Tags.player).transform;
    }

    private void Update()
    {
        Vector3 offset = transform.position - player.position;
        icon.localPosition = new Vector3((offset.x)*10, (offset.z) * 10, 0);
    }

    private void OnDestroy()
    {
        if (icon!=null)
        {
            //销毁的是icon.gameObject而不是icon,icon是transform不能销毁
            Destroy(icon.gameObject);
        }
    }
}
这样在场景中创建一个怪物,在小地图上就显示出了一个怪物图标,并且会移动到主角身边

接下来给游戏添加声音,把Main Camera的Audio Listener移除放到player上,给Main Camera添加背景音乐
音乐部分不赘述了

下面添加武器的拖痕,用到插件这个:


在hierarchy剑的下面创建一个GameObject名为Trail,添加mesh renderer并在materials中添加材质,添加WeaponTrail脚本,这个脚本和材质是插件自带的,给剑添加一个脚本,代码不赘述了,详见博客

http://blog.csdn.net/akof1314/article/details/37603559


最后要做场景1和场景2的切换,首先来加载场景1的信息,给player添加换装脚本





  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值