zoukankan      html  css  js  c++  java
  • 关于Unity的入门游戏飞机大战的开发(上)

    每个组件都是一个类的实例,要获得某个组件,要先创建一个同类型的组件类实例,然后把实例传引用过去,就可以对想要的组件实例进行操作。

    做游戏一般创建一个逻辑节点,里面只管逻辑,再创建一个动画节点,里面有好多动画节点。一般我们把逻辑节点作为动画节点的父节点。

    开发步骤:

    1: 搭建unity项目工程;
    2: 资源整理好;
    3: 配置好我们的canvas;
    4: 做一个开始界面;
    5: 做一个总的游戏的控制脚本game_scene;
    6: 点击开始按钮,让这个开始界面消失;
    7: 让这个飞行射击类游戏背景滚动起来;
    8: 创建一个飞机,能让它被自由的移动和拖动;
    9: 创建一个子弹,能够在物理引擎的控制下发射出去;
    10: 产生一个预制体,让这个飞机不断的射击;
    11: 修改开始,让玩家获得开始消息;

    步骤一和步骤二>>>>>>搭建unity项目工程>>>>>>资源整理好

    1.创建一个2D的Unity项目

    2.创建好scenes,resources,scripts文件夹

    3.在resources文件夹下再创建一个tex文件夹

    4.把要用到的图片资源放进tex文件夹中

    5.保存场景到scenes文件夹

    步骤三>>>>>>配置好我们的canvas

    1.创建一个Canvas节点

    2.把Canvas节点的Canvas组件中的Render Mode设置为Screen Space-Camera,并把Main Camera节点拖进Render Camera属性

    3.把Canvas节点的Canvas Scaler组件的UI Scale Mode设置为Scale With Screen Size,并把Refernces Resultion设置为和Game视图分辨率一样的640X960

    4.创建两个空节点game_root和menu_root作为Canvas节点的子节点,game_root是用来放游戏的节点,menu_root是用来放菜单的节点。由于还没有讲场景跳转,所以这里需要这两个节点。

    步骤四>>>>>>做一个开始界面

    1.给menu_root创建一个叫menu_bg的Image子节点,把背景拖进去,set native size。

    2.给menu_root创建一个叫start_button的button子节点,,把按钮贴纸拖进去,set native size,把它自带的Text子节点删除。

    步骤五>>>>>>做一个总的游戏的控制脚本game_scene

    1.创建一个叫game_scene的脚本挂载在Canvas下面作为游戏总控制的脚本。

    步骤六>>>>>>点击开始按钮,让这个开始界面消失

    1.打开game_scene脚本,编写一个游戏开始函数,on_game_start_click(){}

    using UnityEngine;
    using System.Collections;
    
    public class game_scene : MonoBehaviour {
       //设置一个开始游戏的标志
        bool is_started = false;
    
        // Use this for initialization
        void Start () {
      
        }
    //删除菜单节点函数   private void delete_menu() { MonoBehaviour.Destroy(GameObject.Find("Canvas/menu_root")); } //游戏开始按钮点击,菜单按钮点击后的响应函数,记得要设置为public权限才能关联按钮 public void on_game_start_click() {      //防止重复点击  if (this.is_started) { return; } this.is_started = true;      //执行一个定时器(自带的),让删除节点的函数过一会再执行,过渡效果 this.Invoke("delete_menu", 0.2f); }    // Update is called once per frame void Update () { } }

    2.写好按钮事件函数后,可以直接在Inspector视图里面关联相应的按钮,就是在按钮的属性视图的最下面。

    步骤七>>>>>>让这个飞行射击类游戏背景滚动起来

    1.先把menu_root节点隐藏起来,像ps里面的把眼睛关掉

    2. 给game_root创建一个叫sky的Raw Image子节点(有UVRect属性,只有它才能动态修改纹理坐标),,用来做游戏地图滚动背景。再把sky的贴图属性改成Texture(只有这种模式才能repeat纹理),我这个版本没有Texture属性,只有一个Default属性,两者效果一样的。再把Wrap Mode改成repeat,最后Apply。

    3.把背景地图拖进sky节点的贴图属性,set native size。设置大小(512X1024)和缩放比例(X:1.25 Y:1.25),只要覆盖Canvas节点就行,没必要太大,影响性能。

    4.创建一个叫sky的脚本挂载在sky下面,用来实现地图滚动效果。

    5.打开sky脚本,主要是拿到Raw Image组件,并且拿到UVRect属性,进行动态修改地图纹理坐标移动,又因为Repeat的特效,会让地图一直重复。

    using UnityEngine;
    using System.Collections;
    using UnityEngine.UI;
    
    public class sky : MonoBehaviour {
      //背景图片移动的速度设置
        public float speed = 0.1f;
    
      //创建一个RawImage用来操作组件实例
        private RawImage img;
    
        // Use this for initialization
        void Start () {
            this.img = this.GetComponent<RawImage>();
        }
        
        // Update is called once per frame
        void Update () {
            float sy = this.speed * Time.deltaTime;
            Rect uvrect = this.img.uvRect;//不是传引用
            uvrect.y += sy;
            this.img.uvRect = uvrect;
        }
    }

    步骤八>>>>>>创建一个飞机,能让它被自由的移动和拖动

    1.给game_root创建一个叫plane的空子节点,在plane节点下面创建一个叫anim的Image类型的动画子节点。

    2.把飞机贴图拖进anim节点,set native size,节点大小设置大一点,让飞机大一点。

    3.创建一个叫plane的脚本挂载在plane节点下面,用来实现飞机被鼠标自由的移动和拖动的效果。

    4..打开plane脚本,先实现飞机被鼠标自由的移动和拖动;的效果

    using UnityEngine;
    using System.Collections;
    
    public class plane : MonoBehaviour {
      //飞机随着鼠标运动需要定义飞机坐标和鼠标坐标
        Vector3 start_plane_pos; // 按钮按下的时候飞机的起始坐标
        Vector3 start_mouse_pos; // 鼠标的起始坐标;
    
        // Use this for initialization
        void Start () {
            
        }
    
        //这里有一个问题就是鼠标不按在飞机上,飞机也会跟着移动,这是还没有处理碰撞的原因,后面会改
        //屏幕坐标转世界坐标我的理解是把摄像机拍的二维平面坐标,也就是我们鼠标点击的那个坐标,转化为三维世界的坐标,三维世界的坐标才能做一些动作。
        // 响应我们的鼠标事件,GetMouseButton(0)
        
        // Update is called once per frame
        void Update () {
            if (Input.GetMouseButtonDown(0)) { // 鼠标按下的情况
                // 世界坐标来记录
                // 记录一下当前鼠标的位置,获得鼠标的初始点击位置
                this.start_mouse_pos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
                // 记录一下当前我们飞机的位置,获得飞机的初始位置
                this.start_plane_pos = this.transform.position;
            }
            else if (Input.GetMouseButton(0)) {  // 鼠标在滑动的情况
                Vector3 w_pos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
                Vector3 offset = w_pos - this.start_mouse_pos;//获得偏移量
                this.transform.position = this.start_plane_pos + offset;//设置飞机偏移后的位置
            }
        }
    }

    5.修改

    上次说过,这里有一个问题就是鼠标不按在飞机上,也可以移动飞机,这是因为没有在鼠标控制飞机前判断鼠标是否点在飞机上,所以这里的代码修改如下

    打开plane脚本

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.UI;
    
    public class plane : MonoBehaviour {
        //飞机随着鼠标运动需要定义飞机坐标和鼠标坐标
        Vector3 start_plane_pos;
        Vector3 start_mouse_pos;
    
        //-----修改-----
        private bool is_touch = false;//是否点到飞机
    
        // Use this for initialization
        void Start () {
    
        }
    
        // Update is called once per frame
        void Update () {
        //鼠标按下的情况
        if(Input.GetMouseButtonDown(0))
        {
           //-----修改-----
          this.is_touch = false;//每次鼠标点下去,不管有没有点到飞机,初始化为没点到
            Ray myRay = Camera.main.ScreenPointToRay(Input.mousePosition);//从摄像机发出一条射线
            RaycastHit2D hit = Physics2D.Raycast(new Vector2(myRay.origin.x, myRay.origin.y), Vector2.zero);//射线从鼠标点击屏幕的那个点出发,射到以当前点击位置为原点的坐标系中的垂直于(0,0)的位置,
                                                                 //如果从3D的视角看就是摄像机的射线垂直射到Canvas上
            if (hit.collider)//如果碰到有Collider2D组件的物体,就做一些事情
            {
                if (hit.transform.gameObject.name == "plane")//如果碰到的是飞机
                {
                     //Debug.Log(hit.transform.name);//打印出碰撞到的节点的名字
                     this.is_touch = true;//点到飞机
                }
            }  
    
            if (is_touch)//如果点到飞机
            {
                //获得鼠标的初始点击位置
                this.start_mouse_pos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
                //获得飞机的初始位置
                this.start_plane_pos = this.transform.position;
            }
         }
    
         //鼠标滑动的情况
         else if (Input.GetMouseButton(0) && this.is_touch)
         {
             Vector3 w_pos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
             //获得偏移量
             Vector3 offset = w_pos - this.start_mouse_pos;
             //设置飞机偏移后的位置
             this.transform.position = this.start_plane_pos + offset;
         }
       }
    }

    步骤九>>>>>>创建一个子弹,能够在物理引擎的控制下发射出去

    1.给game_root创建一个叫bullet_root的空子节点,在bullet_root节点下面创建一个叫plane_bullet的Image类型的子节点,Hierarchy视图中把bullet_root节点移动到plane节点的上面,这样子弹不会跑到飞机上面去。

    2.把plane_bullet节点的大小设置为10,height:14,颜色为红色。

    3.准备要给子弹添加刚体组件和碰撞形状组件,所以要先进行物理引擎设置edit --> ProjectSetting -->Physices 2D;设置重力为0

    4.给子弹添加Rigidbody 2D刚体组件,打钩Freeze Rotation,不然子弹在碰撞过程中旋转。又因为子弹的碰撞是连续的(比较特殊),所以Collision Detection设置为Continuous

    5.给子弹添加碰撞形状检测器组件,设置碰撞检测器的大小,再在物理引擎设置器中设置碰撞检测器的边界框的颜色,再打钩always show coll总是显示边界框。

    6.创建一个叫plane_bullet的脚本挂载在plane_bullet节点下面,用来实现子弹飞行和飞出半个屏幕后消失的效果。

    using UnityEngine;
    using System.Collections;
    
    public class plane_bullet : MonoBehaviour {
       //设置子弹的速度
        public float speed = 8; // 子弹的飞行速度
      
    //什么时候删除我们的子弹,因为设计分辨率是640X960,但是如果改变了分辨率, //就不会还是半个屏幕的时候子弹消失,所以要转换设计分辨率的屏幕的高成具体的分辨率高, //有一个scale比例,转换完再乘0.5f就可以取一半屏幕高    private float dead_line_y;

       Rigidbody2D body;
    // Use this for initialization void Start () { this.body = this.GetComponent<Rigidbody2D>(); Vector2 v = new Vector2(0, this.speed);      //刚体的运动会带动与它相连接的整个节点的运动 this.body.velocity = v; float scale = 640.0f / (float)Screen.width; this.dead_line_y = Screen.height * scale * 0.5f; //Debug.Log("this.dead_line_y: " + this.dead_line_y); } // Update is called once per frame void Update () { // 找准已给时机来删除我们的子弹;这里原点是屏幕中心,所以只要超过一半屏幕的高度就删除子弹。 if (this.transform.localPosition.y >= this.dead_line_y) { MonoBehaviour.Destroy(this.gameObject); } } }

    步骤十>>>>>>产生一个预制体,让这个飞机不断的射击

    1.为了飞机不断地射击,不断地产生子弹,需要把子弹变成预制体,就是把刚才设计的子弹变成一个模板,后面可以不断地用这个模板生成子弹。

    2.在Resources文件夹下面创建一个prefabs文件夹,里面存放子弹预制体,也就是直接把plane_bullet节点拖动到prefabs文件夹下面,原节点名字变蓝。

    3.打开飞机节点下的plane脚本,里面添加让飞机不断通过子弹预制体产生子弹的实现代码

    要添加三个public的Inspector视图属性,一个放预制体,一个放目标父节点,也就是生成的一大堆子弹等下放在哪里,一个是子弹发射的频率,这里分别拖进plane_bullet和bullet_root和自定义频率数值。

    4.打开plane脚本

    using UnityEngine;
    using System.Collections;
    
    public class plane : MonoBehaviour
    {
        //飞机随着鼠标运动需要定义飞机坐标和鼠标坐标
        Vector3 start_plane_pos; // 按钮按下的时候飞机的开始的坐标
        Vector3 start_mouse_pos; // 鼠标开始的坐标;
    
        //子弹预制体
        public GameObject bullet_prefab;//预制体子弹节点
        public Transform bullet_root;//预制体子弹节点的父节点
        public float shoot_rate = 0.2f; // 子弹发射的频率;我感觉是一个时间间隔,设定的子弹发射时间间隔
        private float shoot_time = 0.0f; // 距离上一次发射过去的时间
        private bool is_shooting = false;//是否处于发射子弹的状态
    
        //-----优化-----
        private bool is_touch = false;//是否点到飞机
    
        // Use this for initialization
        void Start()
        {
    
        }
    
        void shoot_bullet()
        {
            //使用预制体生成一颗子弹
            GameObject bullet = GameObject.Instantiate(this.bullet_prefab);
            // 注意这个参数要使用false,和Canvas的实现机制有关,false意思是不用世界坐标
            bullet.transform.SetParent(this.bullet_root, false);
    
            //使用localPosition是因为子弹和plane都有相同的父节点,两者之间是相对坐标 
            Vector3 offset = new Vector3(0, 64, 0);
            //之所以用localPosition是因为子弹和飞机都是同一个父节点的子节点
            bullet.transform.localPosition = this.transform.localPosition + offset;
        }
    
        // 响应我们的鼠标事件,GetMouseButton(0)
        void Update()
        {
            //鼠标按下的情况
            if (Input.GetMouseButtonDown(0))
            {
                //-----修改-----
                this.is_touch = false;//每次鼠标点下去,不管有没有点到飞机,初始化为没点到
                Ray myRay = Camera.main.ScreenPointToRay(Input.mousePosition);//从摄像机发出一条射线
                RaycastHit2D hit = Physics2D.Raycast(new Vector2(myRay.origin.x, myRay.origin.y), Vector2.zero);//射线从鼠标点击屏幕的那个点出发,射到以当前点击位置为原点的坐标系中的垂直于(0,0)的位置,
                                                                   //如果从3D的视角看就是摄像机的射线垂直射到Canvas上
                if (hit.collider)//如果碰到有Collider2D组件的物体,就做一些事情
                {
                    if (hit.transform.gameObject.name == "plane")//如果碰到的是飞机
                    {
                        //Debug.Log(hit.transform.name);//打印出碰撞到的节点的名字
                        this.is_touch = true;//点到飞机
                    }
                }
    
                if (is_touch)//如果点到飞机
                {
                    //获得鼠标的初始点击位置
                    this.start_mouse_pos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
                    //获得飞机的初始位置
                    this.start_plane_pos = this.transform.position;
                }
            }
    
            //鼠标滑动的情况
            else if (Input.GetMouseButton(0) && this.is_touch)
            {
                Vector3 w_pos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
                //获得偏移量
                Vector3 offset = w_pos - this.start_mouse_pos;
                //设置飞机偏移后的位置
                this.transform.position = this.start_plane_pos + offset;
            }
    
            // 子弹发射逻辑控制,update里面嵌套自定义的update,自定义刷新函数
            this.shoot_update(Time.deltaTime);
        }
    
    
    
        void shoot_update(float dt)
        {
            if (!this.is_shooting)
            {
                return;
            }
    
            this.shoot_time += dt;
            if (this.shoot_time < this.shoot_rate)
            {
                return;
            }
    
            this.shoot_time = 0;
            this.shoot_bullet();
        }
    }

    5.然后可以把愿来Hierarchy视图里面蓝色名字的子弹节点plane_bullet删除

    步骤十一>>>>>>修改开始,让玩家获得开始消息

    1.给总的游戏控制脚本game_scene添加游戏开始的代码,就是点击按钮后触发游戏开始,飞机开始发射子弹。

    2.打开game_scene脚本

    using UnityEngine;
    using System.Collections;
    
    public class game_scene : MonoBehaviour {
      
       //设置一个开始游戏的标志
       bool is_started = false;    
    
        //定义plane脚本,为了等一下执行里面的start_game方法,这个方法可以让子弹开始发射
        private plane player_ctrl;
    
        // Use this for initialization
        void Start () {
         //获得plane脚本
            this.player_ctrl = this.transform.Find("game_root/plane").GetComponent<plane>();
        }
    
       //执行plane脚本里面的start_game函数开始发射子弹
        private void game_realy_started() {
            this.player_ctrl.start_game();//开始发射子弹
        }
     
       //删除菜单节点函数
        private void delete_menu() {
            MonoBehaviour.Destroy(GameObject.Find("Canvas/menu_root"));
        }
    
        //菜单按钮点击后的响应函数,记得要设置为public权限才能关联按钮
        public void on_game_start_click() {
            if (this.is_started) { // 防止重复点击
                return;
            }
            this.is_started = true;
            //执行一个定时器(自带的),让删除节点的函数过一会再执行,场景过渡效果
            this.Invoke("delete_menu", 0.2f);
            this.Invoke("game_realy_started", 1.0f);
        }
    
        // Update is called once per frame
        void Update () {
        
        }
    }

    3.打开plane脚本,里面添加游戏开始的触发函数

    using UnityEngine;
    using System.Collections;
    
    public class plane : MonoBehaviour
    {
    
        //飞机随着鼠标运动需要定义飞机坐标和鼠标坐标
        Vector3 start_plane_pos; // 按钮按下的时候飞机的开始的坐标
        Vector3 start_mouse_pos; // 鼠标开始的坐标;
    
        //子弹预制体
        public GameObject bullet_prefab;//预制体子弹节点
        public Transform bullet_root;//预制体子弹节点的父节点
        public float shoot_rate = 0.2f; // 子弹发射的频率;我感觉是一个时间间隔,设定的子弹发射时间间隔
        private float shoot_time = 0.0f; // 距离上一次发射过去的时间
        private bool is_shooting = false;//是否处于发射子弹的状态
    
        //-----优化-----
        private bool is_touch = false;//是否点到飞机
    
        // Use this for initialization
        void Start()
        {
    
        }
    
        public void start_game()
        {
            this.is_shooting = true;
    
        }
    
        void shoot_bullet()
        {
            //使用预制体生成一颗子弹
            GameObject bullet = GameObject.Instantiate(this.bullet_prefab);
            // 注意这个参数要使用false
            bullet.transform.SetParent(this.bullet_root, false);
    
            //使用localPosition是因为子弹和plane都有相同的父节点,两者之间是相对坐标
            Vector3 offset = new Vector3(0, 64, 0);
            bullet.transform.localPosition = this.transform.localPosition + offset;
        }
    
        // 响应我们的鼠标事件,GetMouseButton(0)
        void Update()
        {
            //鼠标按下的情况
            if (Input.GetMouseButtonDown(0))
            {
                //-----修改-----
                this.is_touch = false;//每次鼠标点下去,不管有没有点到飞机,初始化为没点到
                Ray myRay = Camera.main.ScreenPointToRay(Input.mousePosition);//从摄像机发出一条射线
                RaycastHit2D hit = Physics2D.Raycast(new Vector2(myRay.origin.x, myRay.origin.y), Vector2.zero);//射线从鼠标点击屏幕的那个点出发,射到以当前点击位置为原点的坐标系中的垂直于(0,0)的位置,
                                                                        //如果从3D的视角看就是摄像机的射线垂直射到Canvas上
                if (hit.collider)//如果碰到有Collider2D组件的物体,就做一些事情
                {
                    if (hit.transform.gameObject.name == "plane")//如果碰到的是飞机
                    {
                        //Debug.Log(hit.transform.name);//打印出碰撞到的节点的名字
                        this.is_touch = true;//点到飞机
                    }
                }
    
                if (is_touch)//如果点到飞机
                {
                    //获得鼠标的初始点击位置
                    this.start_mouse_pos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
                    //获得飞机的初始位置
                    this.start_plane_pos = this.transform.position;
                }
            }
    
            //鼠标滑动的情况
            else if (Input.GetMouseButton(0) && this.is_touch)
            {
                Vector3 w_pos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
                //获得偏移量
                Vector3 offset = w_pos - this.start_mouse_pos;
                //设置飞机偏移后的位置
                this.transform.position = this.start_plane_pos + offset;
            }
    
            // 子弹发射逻辑控制,update里面嵌套自定义的update,自定义刷新函数
            this.shoot_update(Time.deltaTime);
        }
    
        void shoot_update(float dt)
        {
            if (!this.is_shooting)
            {
                return;
            }
    
            this.shoot_time += dt;
            if (this.shoot_time < this.shoot_rate)
            {
                return;
            }
    
            this.shoot_time = 0;
            this.shoot_bullet();
        }
    }
  • 相关阅读:
    Leetcode 121. Best Time to Buy and Sell Stock
    Leetcode 120. Triangle
    Leetcode 26. Remove Duplicates from Sorted Array
    Leetcode 767. Reorganize String
    Leetcode 6. ZigZag Conversion
    KMP HDU 1686 Oulipo
    多重背包 HDU 2844 Coins
    Line belt 三分嵌套
    三分板子 zoj 3203
    二分板子 poj 3122 pie
  • 原文地址:https://www.cnblogs.com/HangZhe/p/7090543.html
Copyright © 2011-2022 走看看