美文网首页
24U3D开发之2D拾荒者

24U3D开发之2D拾荒者

作者: _谭小坤 | 来源:发表于2017-03-03 12:48 被阅读150次

    2D游戏拾荒者开发##

    效果展示

    一、预支物的制作##

    1.获取资源: https://pan.baidu.com/s/1qYAozV2
    2.图片的截取.

    截取图片 截取效果

    3.Player和Enemy的动画制作.

    1.把主角的6张图片同时拖入到Hierarchy面板中,制动创建Animator,有Controller,和对应的动画.
    2.在把攻击的图片拖上去,自动创建攻击动画.同理把收到伤害的图片拖上去,得到受到伤害的动画.
    
    
    制作过程 完成效果
    Enemy敌人的制作
    和Player的制作一样,但是我们在制作Enemy2的时候,可以不用从新创建一个Controller了.可以创建一个
    Animator Override Controller,通过Enemy1创建Enemy2的动画,改变图片从新创建一个新的预支物就可以.
    
    
    
    OverriderController

    3.Floor,OutWall的Prefab的制作.

    Floor,OutWall的制作

    二、创建地图##

    游戏范围展示
    这里涉及到层的概念:我们要设计好层次关系,不然系统识别不了那个在前面.
    我们吧外墙(OutWall),地板(Floor)设置为最底层(Background).
    食物(friut,soda)设置为Item,敌人和Player设置为Role层.
    
    层次的设定 Map管理脚本在Inspector中展示
    脚本代码管理:
    public class MapManager : MonoBehaviour {
    
    
        public GameObject[] OutWalls;
        public GameObject[] Floors;
        public GameObject[] walls;
        public GameObject[] foods;
        public GameObject[] enemys;
        public GameObject exitPrefab;
    
        public  int line = 10;
        public  int row = 10;
        Transform mapHolder;
    
        private List<Vector2> positionList = new List<Vector2>();//用来保存在敌人,障碍物生成区域的位置信息
        private GameManger gameManager;
    
    
    
    
        int minCountWall = 2;//最少内墙个数
        int maxCountWall = 8;//最多内墙个数,随机生成
    
    
    
    
        void Awake () {
            gameManager = this.GetComponent<GameManger>();
            //InitMap();
    
        }
        
        
        void Update () {
            
        }
    
        public void InitMap()
        {
            mapHolder = new GameObject("Map").transform;//穿件一个空物体用来管理生成的地图
            //创建外围墙和地板
            for (int i = 0; i < line; i++)
            {
                for (int j = 0; j < row; j++)
                {
                    if (i == 0 || i == line - 1 || j == 0 || j == row - 1)
                    {
                        int index = Random.Range(0, OutWalls.Length);
                        GameObject go=Instantiate(OutWalls[index], new Vector3(i, j, 0), Quaternion.identity)as GameObject;
                        go.transform.SetParent(mapHolder);
                    }
                    else
                    {
                        int index = Random.Range(0, Floors.Length);
                        GameObject go=Instantiate(Floors[index],new Vector3(i,j,0),Quaternion.identity)as GameObject;
                        go.transform.SetParent(mapHolder);
    
                    }
                }
            }
    
            positionList.Clear();//承储敌人,障碍物区域的信息到list里面。
            for (int i = 2; i < line-2; i++)
            {
                for (int j = 2; j < row-2; j++)
                {
                    positionList.Add(new Vector2(i,j));
                }
            }
    
            //创建障碍物
            int wallCount = Random.Range(minCountWall, maxCountWall + 1);
            InstantiateItem(wallCount,walls);
    
            //创建食物2-level*2
            int foodCount = Random.Range(2, GameManger.level*2+1);//创建的敌人个数与关卡有关系
            InstantiateItem(foodCount,foods);
    
            //创建敌人level/2
            int enemyCount = GameManger.level/ 2;
            InstantiateItem(enemyCount,enemys);
    
            //创建出口
            GameObject go1= Instantiate(exitPrefab, new Vector2(line - 2, row - 2), Quaternion.identity) as GameObject;
            go1.transform.SetParent(mapHolder);
        }
    
        private Vector2 RandomPosition()
        {
            int positionIndex = Random.Range(0, positionList.Count);
            Vector2 pos = positionList[positionIndex];//随机拿到一个位置List里面的地点信息
            positionList.RemoveAt(positionIndex);//在把这个地点信息移除,避免在同一个地点出现多个物体。
            return pos;
        }
    
        private GameObject RandomPrefab(GameObject[]prefabs)
        {
            int index = Random.Range(0, prefabs.Length);
            return prefabs[index];
        }
    
        private void InstantiateItem(int count,GameObject[] prefabs)
        {
            for (int i = 0; i < count; i++)
            {
                Vector2 pos = RandomPosition();
                GameObject enemyPrefab = RandomPrefab(prefabs);
                GameObject go = Instantiate(enemyPrefab, pos, Quaternion.identity);
                go.transform.SetParent(mapHolder);
            }
        }
    
    
    
    }
    
    

    三、Player和Enemy的动画完善##

    Player动画Transition过渡参数详解 Player动画Transition过渡参数详解2 Enemy动画完善

    四、主角(Player)的移动逻辑##

    主角身上的脚本控制
    脚本展示:
    public class Player : MonoBehaviour {
    
    
        public float smoothing = 1;
        public float restTime = 1;
    
        //声音文件
        public AudioClip chop1Audio;
        public AudioClip chop2Audio;
        public AudioClip step1Audio;
        public AudioClip step2Audio;
    
        public AudioClip soda1Audio;
        public AudioClip soda2Audio;
        public AudioClip fruit1Audio;
        public AudioClip fruit2Audio;
    
        private float restTimer = 0;
        public Animator animator;
       
        [HideInInspector]public Vector2 targetPos = new Vector2(1, 1);//主角开始的位置
        private Rigidbody2D rigibody;
        private BoxCollider2D collider;
    
    
        
        void Start () {
            rigibody = GetComponent<Rigidbody2D>();
            collider = GetComponent<BoxCollider2D>();
            animator=GetComponent<Animator>();
        }
        
        
        void Update () {
            rigibody.MovePosition(Vector2.Lerp(transform.position, targetPos, smoothing * Time.deltaTime));
    
           // if (GameManger.Instance.food <= 0) return;
    
            restTimer += Time.deltaTime;
            if (restTimer < restTime) return;
            float h = Input.GetAxisRaw("Horizontal");//只会返回-1,0,1
            float v = Input.GetAxisRaw("Vertical");
            //print(h);
            //print(v);
            if (h>0)
            {
                v = 0;
            }
                  
            if (h != 0 || v != 0)
            {
                GameManger.Instance.ReduceFood(1);
                //检测
                collider.enabled = false;//设置为不可用,不然会检测到自己
                RaycastHit2D hit=Physics2D.Linecast(targetPos,targetPos+new Vector2(h,v));
                collider.enabled = true;
                if (hit.transform == null)
                {
                    targetPos += new Vector2(h, v);
                    AudioManager._instance.RandomPlay(step1Audio,step2Audio);
                   
                }
                else
                {
                    switch (hit.collider.tag)
                    {
                        case "OutWall":
                            break;
                        case "Wall":
                            animator.SetTrigger("Attack");
                            AudioManager._instance.RandomPlay(chop1Audio, chop2Audio);
                            hit.collider.SendMessage("TakeDamage");                     
                            break;
                        case "Food":
                            GameManger.Instance.AddFood(10);
                            targetPos += new Vector2(h, v);
                            AudioManager._instance.RandomPlay(step1Audio, step2Audio);
                            Destroy(hit.transform.gameObject);
                            AudioManager._instance.RandomPlay(fruit1Audio,fruit2Audio);
                            break;
                        case "Soda":
                            GameManger.Instance.AddFood(20);
                            targetPos += new Vector2(h, v);
                            AudioManager._instance.RandomPlay(step1Audio, step2Audio);
                            Destroy(hit.transform.gameObject);
                            AudioManager._instance.RandomPlay(soda1Audio, soda2Audio);
                            break;
                        case "Enemy":
                            break;
                    }
    
                }
                GameManger.Instance.OnPlayerMove();//没帧检测有没有到达终点
                restTimer = 0;
    
            }
            if (GameManger.Instance.food==0||GameManger.Instance.isEnd==true)
            {
                this.enabled = false;
            }
        }
    
        public void TakeDamage(int lossFood)
        {
            GameManger.Instance.ReduceFood(lossFood);
            animator.SetTrigger("Damager");
        }
    }
    
    

    五、控制敌人的移动##

    敌人Enemy展示
    代码展示:
    public class Enemy : MonoBehaviour {
    
        private Vector2 targetPosition;
        private Transform player;
        private Rigidbody2D rigidbody;
    
        public float smoothing = 3;
        private BoxCollider2D collider;
        private Animator animator;
        public int lossFood = 10;
    
        public AudioClip attackAudio;
    
        void Start()
        {
            player = GameObject.FindGameObjectWithTag("Player").transform;
            targetPosition = transform.position;
            rigidbody = GetComponent<Rigidbody2D>();
            collider = GetComponent<BoxCollider2D>();
            animator = GetComponent<Animator>();
            GameManger.Instance.enemyList.Add(this);//保存敌人到集合里面
    
        }
    
        void Update()
        {
            rigidbody.MovePosition(Vector2.Lerp(transform.position,targetPosition,smoothing*Time.deltaTime));
        }
    
    
        
        public void Move()
        {
            Vector2 offset = player.position - transform.position;
            if (offset.magnitude < 1.1f)
            {
                //攻击
                animator.SetTrigger("Attack");
                AudioManager._instance.RandomPlay(attackAudio);
                player.SendMessage("TakeDamage",lossFood);
    
            }
            else
            {
                float x = 0;
                float y = 0;
                if (Mathf.Abs(offset.y) > Mathf.Abs(offset.x))//按照y轴移动
                {
                    if (offset.y < 0)//向反向
                    {
                        y = -1;
                    }
                    else//正向
                    {
                        y = 1;
                    }
                }
                else//按照x轴移动
                {
                    if (offset.x > 0)
                    {
                        x = 1;
                    }
                    else
                    {
                        x = -1;
                    }
                }
                //设置目标位置之前,先做检测;
                collider.enabled = false;
                RaycastHit2D hit = Physics2D.Linecast(targetPosition, targetPosition+ new Vector2(x, y));
                collider.enabled = true;
                if (hit.transform == null)
                {
                    targetPosition += new Vector2(x, y);
                }
                else
                {
                    if (hit.collider.tag=="Food"||hit.collider.tag=="Soda")
                    {
                        targetPosition += new Vector2(x, y);
                    }
                }
                
            }
        }
    
    
    
    
    }
    
    
    

    六、游戏管理脚本(对整个游戏进行管理)##

    public class GameManger : MonoBehaviour {
    
        public static int level = 1;//当前关卡
        public int food = 100;
    
        public AudioClip dieClip;
    
    
        private static GameManger _instance;
    
        public static GameManger Instance
        {
            get
            {
                return _instance;
            }
        }
    
        [HideInInspector]public bool isEnd = false;
        public List<Enemy> enemyList = new List<Enemy>();
        private bool sleepStep = true;//控制敌人移动的限定;
        private Text foodText;
        private Text failText;
        private Image dayImage;
        private Text dayText;
        private Player player;
        private MapManager mapManager;
    
        void Awake()
        {
           
            _instance = this;
            //DontDestroyOnLoad(gameObject);
            InitGame();
    
        }
    
    
        void InitGame()
        {
            //初始化地图
            mapManager = GetComponent<MapManager>();
            mapManager.InitMap();
            food = PlayerPrefs.GetInt("Food", 10);
            //初始化UI
            foodText = GameObject.Find("FoodText").GetComponent<Text>();
            UpdateFoodText(0);
            failText = GameObject.Find("FailText").GetComponent<Text>();
            failText.enabled = false;
            player = GameObject.FindGameObjectWithTag("Player").GetComponent<Player>();
            mapManager = GetComponent<MapManager>();
            dayImage = GameObject.Find("DayImage").GetComponent<Image>();
            dayText = GameObject.Find("DayText").GetComponent<Text>();
            dayText.text = "Day" + " " + level;
            Invoke("HideBlack", 1);
    
            //初始化参数
            isEnd = false;
            enemyList.Clear();
        }
    
        void UpdateFoodText(int foodChange)
        {
            if (foodChange == 0)
            {
                foodText.text = "Food:" + food;
            }
            else
            {
                string str = "";
                if (foodChange<0)
                {
                    str = foodChange.ToString();
                }
                else
                {
                    str = "+" + foodChange;
                }
                foodText.text = str+" " + "Food:" + food;
            }
            
        }
    
    
    
        public void ReduceFood(int count)
        {
            food -= count;
            UpdateFoodText(-count);
            if(food<=0)
            {
                failText.enabled = true;
                AudioManager._instance.StopBgMusic();
                AudioManager._instance.RandomPlay(dieClip);
            }
        }
    
        public void AddFood(int count)
        {
            food += count;
            UpdateFoodText(count);
        }
    
    
        public void OnPlayerMove()//通知敌人行走,逻辑,主角走2步,敌人走一步
        {
            if (sleepStep == true)
            {
                sleepStep = false;
            }
            else
            {
                foreach (var enemy in enemyList)
                {
                    enemy.Move();
                }
                sleepStep = true;
            }
            //检测有没有到达终点
            if (player.targetPos.x==mapManager.line-2&&player.targetPos.y==mapManager.row-2)
            {
                PlayerPrefs.SetInt("Food", food);
                isEnd = true;
                //加载下一个关卡
                SceneManager.LoadScene(0);
                //Application.LoadLevel(Application.loadedLevel);//从新加载本关卡
            }
        }
    
        void OnLevelWasLoaded()
        {
            //PlayerPrefs.GetFloat("level", 1);
            level++;
            //PlayerPrefs.SetFloat("level", level);
           // InitGame();
        }
    
        void HideBlack()
        {
            dayImage.gameObject.SetActive(false);    
        }
    }
    
    

    七、Player对敌人,食物,和墙里面障碍物的处理##

    对内墙的攻击处理:
    public class Wall : MonoBehaviour {
    
        public int hp = 2;
        public Sprite damageSprite;//受到攻击的图片
    
    
        public void TakeDamage()
        {
            hp -= 1;
            GetComponent<SpriteRenderer>().sprite = damageSprite;
            if(hp==0)
            {
                Destroy(this.gameObject);
            }
        }
    }
    
    

    八、食物的UI处理##

    UI处理 UI处理2

    九、声音文件的添加##

    声音文件很重要,在适当的时候,合适的位置添加声音文件.
    
    脚本管理:
    public class AudioManager : MonoBehaviour {
    
        public float minPitch = 0.9f;
        public float maxPitch = 1.1f;
    
        public static AudioManager _instance;
    
        public AudioSource efxSouce;
        public AudioSource bgSource;
    
        void Awake()
        {
            _instance = this;
        }
       
    
    
        public void RandomPlay(params AudioClip[]clips)//播放声音文件
        {
            float pitch = Random.Range(minPitch,maxPitch);
            int index = Random.Range(0,clips.Length);
            AudioClip clip = clips[index];
            efxSouce.clip = clip;
            efxSouce.pitch = pitch;//播放速度
            efxSouce.Play();
    
    
        }
    
        public void StopBgMusic()//游戏结束时,结束背景音乐的播放
        {
            bgSource.Stop();
        }
    
    
    
    }
    
    

    相关文章

      网友评论

          本文标题:24U3D开发之2D拾荒者

          本文链接:https://www.haomeiwen.com/subject/zfvhgttx.html