天天看点

unity飞机大战(2)一些细节问题对象池补充帧动画的播放游戏暂停碰撞检测游戏界面游戏分数的存储总结

对象池补充

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

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

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

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

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

unity飞机大战(2)一些细节问题对象池补充帧动画的播放游戏暂停碰撞检测游戏界面游戏分数的存储总结

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

unity飞机大战(2)一些细节问题对象池补充帧动画的播放游戏暂停碰撞检测游戏界面游戏分数的存储总结
unity飞机大战(2)一些细节问题对象池补充帧动画的播放游戏暂停碰撞检测游戏界面游戏分数的存储总结
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

unity飞机大战(2)一些细节问题对象池补充帧动画的播放游戏暂停碰撞检测游戏界面游戏分数的存储总结
unity飞机大战(2)一些细节问题对象池补充帧动画的播放游戏暂停碰撞检测游戏界面游戏分数的存储总结

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

unity飞机大战(2)一些细节问题对象池补充帧动画的播放游戏暂停碰撞检测游戏界面游戏分数的存储总结

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

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

游戏界面

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

unity飞机大战(2)一些细节问题对象池补充帧动画的播放游戏暂停碰撞检测游戏界面游戏分数的存储总结
unity飞机大战(2)一些细节问题对象池补充帧动画的播放游戏暂停碰撞检测游戏界面游戏分数的存储总结
unity飞机大战(2)一些细节问题对象池补充帧动画的播放游戏暂停碰撞检测游戏界面游戏分数的存储总结

使用UGUI制作游戏界面

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

unity飞机大战(2)一些细节问题对象池补充帧动画的播放游戏暂停碰撞检测游戏界面游戏分数的存储总结
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,在下一篇文章中,我会对此学习,与大家交流~~

继续阅读