2019-03-01 16:50:57 beiluo77 阅读数 914
  • Unity 值得看的500+ 技术内容列表

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

Unity学习笔记:Unity 3D 飞机大战

1、打开unity软件后,首先新建Quad作为背景,导入飞机模型,并为其添加刚体
然后创建C#脚本,挂载到飞机上。
2、给飞机创建子弹,让子弹成为预制体,同样创建C#脚本
3、创建陨石和敌机作为敌方,飞机发射子弹使其销毁,如果飞机与敌方相撞,则飞机爆炸消失。

放上完成后的图:
在这里插入图片描述
给飞机设置的组件:
alt
子弹的组件:
在这里插入图片描述
陨石的组件:
在这里插入图片描述
敌机和其子弹的组件与飞机类似,就不放图了~

接下来是代码:
1、飞机脚本

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


/** 玩家飞机飞行的脚本 */
public class PlayerMovement : MonoBehaviour
{
    /** 飞机可以飞行的区域 */
    public float xMax;
    public float xMin;
    public float zMax;
    public float zMin;

    /** 飞机自身的刚体 以及 飞机发射子弹的位置 */
    Rigidbody _plane_rig;           
    Transform _plane_fire_point;

    /** 子弹的预制体 */
    GameObject _bullet;

    private void Awake()
    {
        //获取刚体
        _plane_rig = this.GetComponent<Rigidbody>();
        //获取开火位置
        _plane_fire_point = transform.GetChild(1);
        //获取子弹的预制体
        //通过资源加载的方式获取预制体
        _bullet = Resources.Load("Prefabs/Bullet") as GameObject;
    }

    private void FixedUpdate()
    {
        float h = Input.GetAxis("Horizontal");
        float v = Input.GetAxis("Vertical");
        //飞机移动
        Move(h, v);
        //飞机开火
        Shoot();
    }

    /** 飞机的飞行速度 以及飞机的倾斜度 */
    public float plane_speed = 3f;
    public float plane_Tilt = 2f;
    void Move(float h,float v)
    {
        //1.获取飞机移动的方向
        Vector3 plane_fly_dir = new Vector3(h, 0, v);
        //2.设定飞机的飞行速度
        _plane_rig.velocity = plane_fly_dir * plane_speed;
        //3.移动
        _plane_rig.position = new Vector3
            (
                //Mathf.Clamp(x,y,z)的作用是将x限定在y和z之间
                Mathf.Clamp(_plane_rig.position.x,xMin,xMax),
                5f,
                Mathf.Clamp(_plane_rig.position.z,zMin,zMax)
            );
        //4.设置飞机倾斜度
        _plane_rig.rotation = Quaternion.Euler(0f, 0f, _plane_rig.velocity.x * -plane_Tilt);
    }


    float _shoot_rate = 0.5f;
    float _timer = 0f;
    void Shoot()
    {
        //计时
        _timer += Time.deltaTime;
        //按下鼠标左键
        if (Input.GetMouseButton(0) && _timer >= _shoot_rate)
        {
            //在_plane_fire_point.position的位置生成_bullet实例,保持_plane_fire_point.rotation的旋转
            Instantiate(_bullet, _plane_fire_point.position, _plane_fire_point.rotation);
            //重置定时器
            _timer = 0f;
        }
    }
}

2、子弹的脚本

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

public class BulletMovement : MonoBehaviour
{
    /** 子弹的飞行速度 */
    public float bullet_speed = 20f;

    private void FixedUpdate()
    {
        this.GetComponent<Rigidbody>().velocity = bullet_speed * transform.forward;
    }
}

3、陨石的脚本

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

public class AsteroidMove : MonoBehaviour
{
    //陨石的移动速度集合
    float[] _asteroid_speeds = { 8, 10, 13, 16 };

    private void Awake()
    {
        //左闭右开 [0,4)
        int index = Random.Range(0, _asteroid_speeds.Length);

        this.GetComponent<Rigidbody>().velocity = Vector3.back * _asteroid_speeds[index];
    }

}

陨石旋转

 //陨石旋转的速率集合
    float[] rotRations = { 4f, 6f, 8f };

    private void Awake()
    {
        int index = Random.Range(0, rotRations.Length);

        //Random.insideUnitSphere 随机返回球体(半径为1的球体)内部的任意一点
        this.GetComponent<Rigidbody>().angularVelocity = Random.insideUnitSphere * rotRations[index];
    }

陨石爆炸

/** 爆炸效果预制体 */
    public GameObject asteroidExp;
    public GameObject playerExp;

    private void OnTriggerEnter(Collider other)
    {
        //碰到陨石或者是敌方飞机 不处理直接返回
        if (other.gameObject.tag == "Asteroid" || other.gameObject.tag == "Enemy" || other.gameObject.tag == "EBullet")
            return;

        //碰到了子弹
        if(other.gameObject.tag == "Bullet")
        {
            //生成爆炸体
            GameObject exp = Instantiate(asteroidExp, transform.position, transform.rotation);
            //销毁
            Destroy(exp, 0.3f);
        }

        //碰到了玩家
        if(other.gameObject.tag == "Player")
        {
            //生成爆炸体
            GameObject exp = Instantiate(playerExp, transform.position, transform.rotation);
            //销毁
            Destroy(exp, 0.3f);
        }

        //销毁碰到的物体
        Destroy(other.gameObject);
        //销毁自身
        Destroy(transform.gameObject);

    }

以及陨石的管理

 /** 三个陨石预制体 */
    GameObject _Asteroid_01;
    GameObject _Asteroid_02;
    GameObject _Asteroid_03;

    /** 存放所有的陨石 */
    List<GameObject> _Asteroids;

    private void Awake()
    {
        //初始化陨石集合
        _Asteroids = new List<GameObject>();

        //通过资源加载的方式先获取到三个陨石
        _Asteroid_01 = Resources.Load("Prefabs/Asteroid_01") as GameObject;
        _Asteroid_02 = Resources.Load("Prefabs/Asteroid_02") as GameObject;
        _Asteroid_03 = Resources.Load("Prefabs/Asteroid_03") as GameObject;

        //将三个陨石加入到集合中
        _Asteroids.Add(_Asteroid_01);
        _Asteroids.Add(_Asteroid_02);
        _Asteroids.Add(_Asteroid_03);
    }

    private void Start()
    {
        //重复调用某一个方法
        InvokeRepeating("CreateAsteroid", 0f, 3f);
    }

    void CreateAsteroid()
    {
        //1.随机从集合中取出陨石
        GameObject asteroid = _Asteroids[Random.Range(0, _Asteroids.Count)];
        //2.创建随机位置
        Vector3 asteroidPos = 
            new Vector3(Random.Range(transform.position.x, -transform.position.x), 5f, 17.52f);
        //3.创建陨石
        Instantiate(asteroid, asteroidPos, Quaternion.identity);
    }

    private void OnApplicationQuit()
    {
        //当程序结束的时候取消invoke的重复调用
        CancelInvoke("CreateAsteroid");
    }

4、最后是敌机和其子弹

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

public class EnemyShip : MonoBehaviour {

    //敌机的移动速度集合
    float _enemy_speeds = 3f;
    Transform _eplane_fire;

    /** 敌机子弹的预制体 */
    GameObject _ebullet;

    private void Awake()
    {
        //左闭右开 [0,4)
        this.GetComponent<Rigidbody>().velocity = Vector3.back * _enemy_speeds;
        transform.eulerAngles = new Vector3(transform.eulerAngles.x, 180, transform.eulerAngles.z);

        //获取开火位置
        _eplane_fire = transform.GetChild(1);
        //获取子弹的预制体
        //通过资源加载的方式获取预制体
        _ebullet = Resources.Load("Prefabs/EBullet") as GameObject;

    }

    private void FixedUpdate()
    {
        //敌机开火
        Shoot();
    }

    float _shoot_rate = 2f;
    float _timer = 0f;
    void Shoot()
    {
        //计时
        _timer += Time.deltaTime;
        if (_timer >= _shoot_rate)
        {
            //在_plane_fire_point.position的位置生成_bullet实例,保持_plane_fire_point.rotation的旋转
            Instantiate(_ebullet, _eplane_fire.position, Quaternion.identity);
            //重置定时器
            _timer = 0f;
        }
    }
}

(敌机的爆炸及其子弹的爆炸和陨石爆炸代码类似,下面就不放了)


5、最后的最后(终于要完成了~)给敌机设置管理

/** 敌机 */
    GameObject _enemys;

    private void Awake()
    {
        //通过资源加载的方式先获取到敌机
        _enemys = Resources.Load("Prefabs/EnemyShip") as GameObject;
    }

    private void Start()
    {
        //重复调用某一个方法
        InvokeRepeating("CreateEnemy", 0f, 3f);
    }

    void CreateEnemy()
    {
        
        //1.创建随机位置
        Vector3 enemyPos =
            new Vector3(Random.Range(transform.position.x, -transform.position.x), 5f, 17.52f);
        //2.创建陨石
        Instantiate(_enemys, enemyPos, Quaternion.identity);
    }

    private void OnApplicationQuit()
    {
        //当程序结束的时候取消invoke的重复调用
        CancelInvoke("CreateEnemy");
    }

撒花!!!一个飞机大战小游戏就完成了,用 unity 做这款小游戏有些大材小用,却也的确比用 h5 简单很多!

2019-03-06 17:19:34 qq_42216823 阅读数 87
  • Unity 值得看的500+ 技术内容列表

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

Unity3D实现飞机大战(一)

实现背景轮播

  1. 首先找两个背景图片,让两张图片竖直摆放且没有间隔
  2. 两个图片的下降的播放速度应当同步
   public float moveSpeed = 3f;//指的是在unity里的移动速度
    // Update is called once per frame
    void Update()
    {
        this.transform.Translate(Vector3.down * moveSpeed *Time.deltaTime);
        Vector3 vector3 = this.transform.position;
        //表示背景已经出了游戏相机的边框
        if (vector3.y <= -8.52f)
        {
            //将其移到上面的游戏背景区,如果是-vector3.y会导致两张图片之间有空隙无法达到轮播的效果
            this.transform.position = new Vector3(vector3.x, vector3.y+8.52f*2, vector3.z);
        }

出现的问题:
当图片的位置变成-8.52以下时,更改位置使用到的是
this.transform.position = new Vector3(vector3.x, -vector3.y, vector3.z);
导致当背景图进行播放的时候会产生间隙。因为vector3的值小于-8.52时使用绝对值时图片的高会比加法大,导致有间隙。

实现角色的动画

  1. 假设该动画是由多张图片构成的,那么可更改SpriteRender组件的Sprite属性以实现动画的效果。
  2. 在初始化中得到组件,在update中修改Sprite属性
  //判断动画是否继续,因为如果暂停了游戏,就可以不进行动画
    public bool animation = true;
    //每秒播放几帧
    public int frameCountPreSeconds = 10;
    //计时器
    public float timer = 0;                                                                       
    //播放帧的数组
    public Sprite[] sprites;
    private SpriteRenderer SpriteRenderer;
    // Start is called before the first frame update
    void Start()
    {
        SpriteRenderer = this.GetComponent<SpriteRenderer>();
    }

    // Update is called once per frame
    void Update()
    {
        if (animation) {
            timer += Time.deltaTime;
            //1f/frameCountPreSeconds 每一帧的时间间隔                   
            int frameIndex =(int) (timer /(1f/ frameCountPreSeconds));
            //当前应当播放的是哪一帧
            int frame = frameIndex % 2;
            //首先先获取组件SpriteRenderer,再获取组件里的sprite
            SpriteRenderer.sprite=sprites[frame];
        }
    }
2015-01-10 09:09:18 u014735301 阅读数 1731
  • Unity 值得看的500+ 技术内容列表

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

对象池补充

先说下上一篇对象池的一个问题。用脚本,在一个SpawnPool,添加多个prefab,

运行游戏时,只有第一个prefab预加载了规定个数,当用到其他prefab时,

其他prefab才出现在pool中,而且数量会无限增加! 但是第一个prefab却不会,

还是会限制在 limitAmount规定的个数。如果将一个对象对应一个SpawnPool,运行时正常! 

这个问题很是诡异,目前还没有找到原因。


解决方法就是 不用脚本初始化,而是用插件事先编辑好对象池,运行! 没有任何问题

using UnityEngine;
using System.Collections;
using PathologicalGames;

public class SpawnTest : MonoBehaviour {

    public GameObject prefab, prefab1;
    //对象池
    SpawnPool spawnPool;
    
	// Use this for initialization
	void Start () {
        spawnPool = PoolManager.Pools["Spawn"];

        //每隔0.5秒,调用一次CreatPerfab方法
        InvokeRepeating("CreatPerfab", 1f, 0.2f);
	}
	
	// Update is called once per frame
	void Update () {

	}
    void CreatPerfab() {
        //从对象池中取出物体,并且设置它的位置
        spawnPool.Spawn(prefab.transform, new Vector3(transform.position.x, transform.position.y, 0), Quaternion.identity);
        spawnPool.Spawn(prefab1.transform, new Vector3(transform.position.x+3f, transform.position.y, 0), Quaternion.identity);
    }
}

帧动画的播放

飞机帧动画的循环播放

//每秒帧数
public int frameCountPersconds = 10;
//时间
public float timer  = 0;
//渲染组件
private SpriteRenderer spriteRender;
//代码实现
timer+=Time.deltaTime;
int frameIndex = (int)(timer/(1f/frameCountPersconds));
int frame = frameIndex%2;
spriteRender.sprite = sprites[frame];

敌机被消灭时播放的一次性帧动画

		if(isDeath){
				timer+=Time.deltaTime;// 0
				int frameIndex = (int)(timer/(1f/explosionAnimationFrame));
				if(frameIndex>=explosionSprites.Length){
                    this.gameObject.SetActive(false);
				}else{
					render.sprite= explosionSprites[frameIndex];
				}

游戏暂停

Time.timeScale = 0;//暂停

了解更多,可以学习雨松的这篇文章:Unity3D研究院之Time.timeScale、游戏暂停(七十四)

碰撞检测

子弹攻击敌机,敌机与飞机碰撞后,飞机销毁,游戏结束都需要碰撞检测。

物体发生碰撞的必要条件

两个物体都必须带有碰撞器(Collider),其中一个物体还必须带有Rigidbody刚体。

在unity3d中,能检测碰撞发生的方式有两种,一种是利用碰撞器,另一种则是利用触发器。

碰撞器: 一群组件,它包含了很多种类,比如:Box Collider(盒碰撞体),Mesh Collider(网格碰撞体)等,这些碰撞器应用的场合不同,但都必须加到GameObjecet身上。

触发器 ,只需要在检视面板中的碰撞器组件中勾选IsTrigger属性选择框。

触发信息检测:


1.MonoBehaviour.OnTriggerEnter(Collider collider)当进入触发器

2.MonoBehaviour.OnTriggerExit(Collider collider)当退出触发器

3.MonoBehaviour.OnTriggerStay(Collider collider)当逗留触发器

碰撞信息检测:

1.MonoBehaviour.OnCollisionEnter(Collision collision) 当进入碰撞器

2.MonoBehaviour.OnCollisionExit(Collision collision) 当退出碰撞器

3.MonoBehaviour.OnCollisionStay(Collision collision)  当逗留碰撞器

unity3d中的碰撞器和触发器的区别:

当Is Trigger=false时,碰撞器根据物理引擎引发碰撞,产生碰撞的效果,可以调用OnCollisionEnter/Stay/Exit函数;

当Is Trigger=true时,碰撞器被物理引擎所忽略,没有碰撞效果,可以调用OnTriggerEnter/Stay/Exit函数。

如果既要检测到物体的接触又不想让碰撞检测影响物体移动或要检测一个物件是否经过空间中的某个区域这时就可以用到触发器

所以在飞机大战中,我们要给飞机和子弹添加上碰撞器和刚体组件,

同时为了避免有碰撞效果,我们在飞机和子弹的碰撞器组件上,勾选使用触发器 Is Trigger=true



给敌机和奖励物品添加上碰撞器组件


这样我们就可以在脚本内通过方法来处理逻辑了

    //当子弹碰撞到敌机
	void OnTriggerEnter2D(Collider2D other) {
		if(other.tag=="Enemy"){
			if(!other.GetComponent<Enemy>().isDeath){
				other.gameObject.SendMessage("BeHit");
                this.gameObject.SetActive(false);
			}
		}
	}

游戏界面

开始界面 游戏进行 游戏结束

使用UGUI制作游戏界面

我的结构是 制作三个界面的面板,通过一个单例的UIManager脚本来控制UI的逻辑

using UnityEngine;
using UnityEngine.UI;
using System.Collections;

public class UImanager : MonoBehaviour {

    public static UImanager _instance;
    //三个面板
    public GameObject panel_start, panel_run, panel_over;
    //飞机,怪物刷新
    public GameObject hero, spawn;
    // UI:当前分数,最高分数,炸弹个数
    public Text run_curScore, over_curScore, over_highScore, boom;
    //分数 炸弹个数
    public int score,boomCount;
    //游戏是否暂停
    private bool isRun;
    void Awake(){
        _instance = this;
    }
	void Start () {
        isRun = true;
	}
	
	// Update is called once per frame
	void Update () {
	    if(panel_run.activeSelf){ 
          //  Debug.Log("running!~~~~~~~~");
            run_curScore.text = score.ToString();
            boom.text = "X"+boomCount.ToString();
        }
        if (panel_over.activeSelf)
        {
            over_curScore.text = score.ToString();
            over_highScore.text = GameManager._instance.HistoryHighScore().ToString();
        }
            
	}

    //开始游戏
    public void StartGame() {
        panel_start.SetActive(false);
        panel_run.SetActive(true);
        hero.SetActive(true);
        spawn.SetActive(true);
    }
    //游戏结束
    public void OverGame()
    {
        panel_run.SetActive(false);
        panel_over.SetActive(true);
        //hero.SetActive(false);
        //spawn.SetActive(false);
        //spawn.GetComponent<Spawn>().enabled = false;
        //PauseGame();
    }
    //重开一局
    public void ReStartGame()
    {
        panel_over.SetActive(false);
        panel_run.SetActive(true);
        hero.SetActive(true);
        spawn.SetActive(true);
    }
    //退出游戏
    public void ExitGame()
    {
        Application.Quit();
    }
    //暂停/继续游戏
    public void PauseGame()
    {
        if (isRun)
        {
            Time.timeScale = 0;//暂停
            isRun = false;
        }
        else {
            Time.timeScale = 1;
            isRun = true;
        }

    }
}
对于游戏UI的自适应,还有没怎么研究,目前解决的方法就是UGUI自己的自适应,Reference Resolution组件 挂在Canvas上 ,一些ui使用锚点进行定位。

游戏分数的存储

    //返回 历史最高分
    public int HistoryHighScore() {
        int historyScore = PlayerPrefs.GetInt("historyHighScore", 0);
        int nowScore = UImanager._instance.score;
        if (nowScore > historyScore)
        {
            PlayerPrefs.SetFloat("historyHighScore", nowScore);
            historyScore = nowScore;
        }
        return historyScore;
    }

总结

在游戏最后,可以增加一个分享功能,这里我想安卓的ShareSDK,在下一篇文章中,我会对此学习,与大家交流~~

2015-10-02 16:01:57 qq_18293659 阅读数 2875
  • Unity 值得看的500+ 技术内容列表

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



1.摄像机的设置需要注意:选择摄像机的投影方式为Orthographic(正交投影)。
2.控制飞船的移动,其实就是控制一个3D的Vector3(x,y,z)的变换,首先需要得到
在x轴方向和z轴方向上面的移动变量,接着再给坐标赋值,实现坐标自身相应的移
动,变换。
接着还要给刚体相应的速度方向。具体使用:
GetComponent<Rigidbody>().velocity=movement;
3.为了提高游戏可玩性,加入方向上面的速度
GetComponent<Rigidbody>().velocity=movement*speed;
4.控制发射的时间间隔:
Time.time>nextFire
5.实例化做好的子弹并且发射出去:
Instantiate(shot,shotSpawn.position,shotSpawn.rotation);
6.管理子弹的生命周期:
为游戏区域添加触发器,并当电光子弹飞出区域时触发事件,在事件响应函数中
调用Destroy方法。
7.添加小行星随机旋转功能:
在脚本中添加一个表示小行星旋转系数的变量tumble,再重载Start函数,为刚体
组件的角速度赋上随机值。
例如:
GetComponent<Rigidbody>().angularVelocity=Random.insideUnitSphere*tumble;

PS:注意需要设置角阻力为0,否则该小行星速度会越来越慢。

8.添加小行星随机产生的逻辑:
注意需要让小行星在一定的范围之内产生。(x轴方向)
例如: 
spawnPosition.x=Random.Range(-spawnValues.x,spawnValues.x);
spawnPosition.z=spawnValues.z;
spawnRotation=Quaternion.identity;
Instantiate(hazard,spawnPosition,spawnRotation);

9.使用Unity中的协程来让小行星的生成有时间间隔。

10.添加音频:
在发生碰撞的时候,调用音频来产生爆炸的声音

11.UI
添加计分UI的时候需要注意UI的位置。

12.重新加载场景
Application.LoadLevel(Application.loadedLevel);
是Unity中重新加载场景的常用方法。



2016-08-05 19:55:31 q382767 阅读数 2251
  • Unity 值得看的500+ 技术内容列表

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

Unity3D游戏开发之飞机大战项目讲解

内容出自上图的参考教程,请结合上图的参考教程食用本攻略
本Unity3D版本为5.2.3

由于参考上面的教程现在的Unity是5.2.3版本,因此在这里发表一下关于Unity制作的2D打飞机的食用攻略


内容出自上图的参考教程,请结合上图的参考教程食用本攻略
本Unity3D版本为5.2.3





创建UIText,GameObject--UI--Text




子弹添加2D碰撞器,Collider2D,已经2D刚体,Rigidbody2D
Is Trigger和Is Kinematic都要选上



敌人的设置如图所示



之前遇到添加了碰撞器Collider各种触发不了OnCollisionEnter函数,OnCollisionStay函数,OnCollisionExit函数。


重新看了一下碰撞器Collider和Trriger触发器


参考这篇文章




如果要使得物体能够进行触发,需要添加碰撞器Collider,才能使得OnCollisionEnter函数,OnCollisionStay函数,OnCollisionExit函数能够返回值。


当勾选碰撞器Collider的选项Is Trriger选项的时候,碰撞器Collider会变成触发器,之前的触发器OnCollisionEnter函数,OnCollisionStay函数,OnCollisionExit函数都无效。
OnTriggerEnter(),OnTriggerStay(),OnTriggerExit()函数才有效。


然而最重要的是这些都是建立在3D的环境下。
如果只是用2D的需要在这些后面加上2D才可以。
如果只是用2D的需要在这些后面加上2D才可以。
如果只是用2D的需要在这些后面加上2D才可以。


类似下面的例子,最好在后面都加上2D!!!
void OnTriggerEnter2D(Collider2D mCollider2D)
{
print ("Bullet meet Enemy");
if(mCollider2D.gameObject.tag=="Enemy")
{
mCollider2D.gameObject.GetComponent<Enemy>().Hit(Damage);
Player.GetComponent<Player>().Add(1);
Destroy(this.gameObject);
}//
}//

unity之飞机大战

阅读数 522

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