Unity3D-微信-飞机大战-项目经过

2015年12月14日14:49:59 BeatPlane ProjectLog

1.新建项目
2.导入资源

3.把背景图片拖到scene窗口中

4.并设置位置归零

5.修改设置为手机端


6.在Game窗口中把分辨率改为 480x800

7.在MainCamera中把Size修改为4,这样背景就可以在摄像机中全屏显示了

8.复制一个背景,拖到上面,使它们两个背景无缝连接

9.为背景添加脚本,使其能做成一直在运动的动画

代码如下:

保存,运行测试,发现背景可以无缝移动。

10.从素材文件夹里拖一个飞机(玩家)到Project 面板,但是不会动,下面添加代码使主角有动画

代码如下:已添加好注释

注,记得把素材里的主角动画图片拖到代码中,使数组初始化

保存,测试,玩家的飞机已经有动画了

11.新建一个空物体,作为玩家飞机的子物体,位置移动到飞机头的位置,用来在此生成子弹,并在此物体上挂一个shoot 脚本

11.1脚本代码如下:

12.把子弹作为Perfabs(预置体)并挂上Bullet脚本

这里可以给2种子弹指定不同的速度

13.Bullet 脚本代码如下:

14.同样的给左边和右边的“发射器”挂上Shoot(生成子弹)的脚本,并指定要生成的子弹为子弹2号,这里也可以给他们不同的 rate(生成速率)

保存,运行测试一下

OK,没有问题。

15.把素材里的敌机拖到场景中。并挂上脚本,设置成预置体

16.代码如下:

注:三种类型不同的飞机,可以设置不同的生命,不同的速度

17.新建一个空物体,改名为Spawn,用来源源不断生成敌机。把位置移到上面的屏幕之外

17.1 并挂上脚本

17.2 代码如下:

18.同样的方法,把奖励物品也拖到场景中,并挂上 Enemy 的脚本,修改一下速度,并设为预置体

18.1 并在Spawn 脚本中加上 随机生成 奖励物品的代码,如下:

还有别忘了在场景中指定要生成的物品种类

19.通过鼠标按下拖动控制飞机的移动,有点绕。

**主要逻辑就是:一直不停的获取鼠标的位置,此时获取的位置是相对于屏幕的坐标,屏幕的左下角为0,0. 如果玩家按下鼠标,则 记录按下时的坐标转换成世界坐标, 此时拖动鼠标(鼠标还是按下的状态,并还在不停的获取鼠标的位置存在Input.mousePosition中)会产生一个偏移(鼠标现在的位置减去鼠标按下那刻所在的位置),然后在用飞机的位置加上这个偏移就是飞机移动的动画!
if判断为假就是鼠标按下那刻鼠标所在的位置,按下以后进入if判断为真后就开始执行上面所描述的内容。**

19.1 边界检查,不让飞机飞出屏幕

2015年12月17日00:17:42 有点累,今天先到这。

20.为两种类型的子弹加上(Rigidbody2D)2d刚体组件和BoxCollider2D(碰撞检测2D)组件,
并设置Gravity Scale 为0,勾上collider 中的Is Trigger 选项。

20.1 打开子弹代码,添加如下:

21.为三种飞机也添加上BoxCollider2D(碰撞检测2D)组件

如图飞机边上的绿框为碰撞检测范围。保存,测试,发现子弹击中敌机就会消失了。

22.给每种敌机加上 Enemy 标签

22.1给子弹添加代码,如果碰到的是敌机则调用敌机的Behit(自建的) 方法

22.2 选中一个敌机,这里我选的是enemy0(小飞机),打开Animation 窗口

22.3点Create为它创建被击中爆炸的动画

22.4 随便起个名字,我起的叫 enemy0_Destory 点击保存

22.5 依次打开,添加精灵动画

22.6 从素材文件夹把小飞机爆炸的动画图片都拖过来,按时间顺序排好,它们之间的距离决定了爆炸动画的时长(快慢),PS:经过我反复测试,觉得在10帧完成动画看起来刚好。
注:可以点击上面的播放按钮预览一下速度的快慢。

22.7 完成以后关闭Animation 窗口,打开Enemy 脚本添加代码
22.7.1 先声明一个飞机的枚举类型

22.7.2 声明一个变量,默认设为smallEnemy

22.7.3 回到编辑器给每种类型的飞机指定相应的类型

22.7.4 继续编辑脚本,声明一些变量

22.7.5 如果被击中,先看飞机现在的状态是生是死,如果是活着的,则生命值减1,再继续判断,当生命值减为0时,飞机的状态就为死了。这时候要播放完爆炸动画后销毁该飞机,所以用到了个延时函数,延时0.2s后销毁。

22.8 对了,忘了解释一下上面anim.SetBool(“Dead”,true);这句了
22.8.1 打开Animator 窗口

22.8.2 新建一个状态,设为默认状态,速度设为20

22.8.3 再建一个状态,命个名

22.8.4 点Parameters(参数)面板,旁边的加号,添加一个bool 值的参数Dead

22.8.5 右键那个默认的状态(蛋黄色)的那个创建连接

22.8.6 连上刚才新建的那个状态

22.8.7 点中间的箭头,在右边把条件设为 true

22.8.8 回到编辑器 把 循环播放取消勾选


22.8.9 至此,解释一下上面anim.SetBool(“Dead”,true); 当飞机为死亡状态时,动画状态机根据Dead的值决定要不要播放死亡动画。

23.1下面设置中型飞机的动画,因为中型飞机被击中时多了个被击中的动画。所以,先新建一个被击中的动画片段

23.2 再建一个被摧毁的动画


23.3 再为(Enemy1)中型飞机新建一个动画状态控制机,它有2个条件参数,都是Bool类型的,一个是死亡,一个是被击中

23.4 为他们的过度条件设定好

23.5 这里值得注意的是把默认的动画播放速度设置的快点,设为30

23.6 把 enemy1_hit 的动画设置 has exit time意思是0.3s后播放一次自动退出被击中的动画

24.同理,给大飞机也添加上动画,和动画状态控制器


25.修改Enemy 脚本,由于改动较大,就不一一讲解了,直接贴出代码

    using UnityEngine;
using System.Collections;
public enum EnemyType  //飞机的枚举类型
{
smallEnemy,  //小型飞机
middleEnemy, //中型飞机
bigEnemy,//大型飞机 
}
public class Enemy : MonoBehaviour {
public int life;//敌机的生命
public float speed;   //敌机的速度
public EnemyType planeType = EnemyType.smallEnemy;  //默认是小飞机
Animator anim;  //存放动画组件
//public float destoryTimer = 1;
private bool alive = true;  //是否还活着
private bool isHit = false;   //是否被击中,初始状态没有
// Use this for initialization
void Start () {
anim = GetComponent(); //获取动画组件

    }

    // Update is called once per frame
    void Update () {
transform.Translate(Vector3.down * speed * Time.deltaTime);
//敌机以Speed的速度向下运动
if (transform.position.y <= -5.4)   //如果超出了屏幕最低边
{ //这里的5.4是以最大飞机消失在屏幕里算的
Destroy(this.gameObject);   //则销毁此物体(敌机)
}
checkLife();  //每帧检查生命
    }
void Behit()   //被击中时从子弹发过来的消息调用的方法
{

//print(this.gameObject + "I'm Hit!");
this.life--;  //生命值减1
this.isHit = true;  //被击中 状态 设为 真

}
IEnumerator Delay(int state)   //延时方法
{
if (state == 1)
{
anim.SetBool("Dead", true);
//anim.SetInteger("Dead", 0);
//anim.SetFloat("Dead", -1f);
yield return new WaitForSeconds(0.25f);
//延时0.2秒
Destroy(this.gameObject);
//这时候爆炸动画差不多做完了,然后销毁该物体(小飞机)
}else if(state == 2)  //飞机被击中受损的动画
{
//anim.SetInteger("Hited", 1);  
anim.SetBool("Hited", isHit);
yield return new WaitForSeconds(0.2f);
this.isHit = false;  //播放完把是否被击中的状态设置为假
}
else if (state == 3)   //如果是打飞机,给它更多的时间播放爆炸动画
{
//anim.SetInteger("Hited", 1);  
anim.SetBool("Dead", true);
yield return new WaitForSeconds(0.42f);
Destroy(this.gameObject);
}

}


void checkLife()   //检查生命
{
if (planeType == EnemyType.smallEnemy) //如果是小飞机
{
if (life <= 0)  //如果生命小于0
{
 StartCoroutine(Delay(1));  //调用延时1的方法
}
}
if(planeType == EnemyType.middleEnemy)  //中型飞机
{
if (life <= 0)
{
StartCoroutine(Delay(1));
}
else  //如果生命不为0,则播放受伤动画
{
   // this.isHit = true;
StartCoroutine(Delay(2));  
//this.isHit = false;
}
}
if (planeType == EnemyType.bigEnemy)  //大飞机
{
if (life <= 0) //生命为0,播放时间更长的爆炸动画
{
StartCoroutine(Delay(3));
}
else  //播放受伤动画
{
StartCoroutine(Delay(2));   
}
}

}
}

26.保存,测试,可以实现小飞机一击爆炸,中、大飞机击中有个被击中后受损的动画,生命为0的时候有爆炸动画




2015年12月21日00:09:28 今天就先到这。

27.为2种补给品添加标签 Award

28.为主角添加Collider2D碰撞检测和RigidBody(刚体)组件

29.先打开Shoot 脚本修改,删掉Start方法,添加StopFire方法,具体代码如下:

29.1 打开主角脚本,声明一些变量

29.2 然后在Start方法中做一些初始化

29.3 在Update中每帧检查

29.4 下面是自定义的两种枪切换的方法

30.下面完成吃到炸弹的功能
30.1 先从素材里拖一个炸弹图标到场景中,并调整位置在左下角

30.2 然后新建一个Text组件

30.3 修改一下属性,同样的是左下角

30.4 为bomb添加一个脚本,代码如下:

30.5 打开Enemy和bombManager 脚本,分别 修改Update脚本,添加如下代码:

30.6 回到30.6保存,测试。没有问题。
2015年12月21日21:45:05 今天先到这。

31.下面完成分数功能,先新建一个TEXT,调整位置,显示在左上角

32.给摄像机新建一个脚本GameManager,打开脚本,添加如下代码:

33.回到编辑器记得指定对象

34.打开Enemy脚本,修改延时方法中部分代码,每次敌机死亡,调用一次增加分数的方法,这里用一个标志isDead检测,防止它死亡时每帧都会调用,这样加出来的分数就不准确了。

35.保存,运行,没问题

2015年12月23日23:15:54 明天继续。

36.接下来完成游戏暂停功能,从素材里把游戏暂停图标拖放到屏幕右上角合适的位置,记得设置好层,不然可能无法显示

36.1 并新建个脚本,添加一个碰撞检测组件

36.2 并为上面的Sp指定2张图片,分别是暂停图标和运行中图标

36.3 编辑 GameStateButton 脚本,代码如下,无法全部截图,只好复制了
using UnityEngine;
using System.Collections;

public class GameStateButton : MonoBehaviour {

public Sprite[] sp;  //精灵数组,存放 游戏继续和游戏暂停两个图标
public SpriteRenderer spRender; //存放组件
public static GameStateButton _instance;  //单例
// Use this for initialization
void Awake()
{
    _instance = this;  //实例化一个本对象供其他脚本调用访问内部方法
}
void OnMouseUpAsButton()  //当鼠标或点击了此对象
{
    //print("Click!");
    if (GameMananger._instance.gs == GameState.Running) //如果游戏正在运行
    {
        setToPause();  //把图标变为暂停
        GameMananger._instance.switchGameState();  //切换游戏状态
    }
    else
    {
        setToContinue();  //否则把图标变为运行
        GameMananger._instance.switchGameState();  //切换游戏状态
    }                       
}
void Start()
{
    spRender = GetComponent();  //获取图标渲染组件

}
public void setToPause()   //设置图标为暂停状态(两个竖杠)
{
    spRender.sprite = sp[1];
}
public void setToContinue()//设置图标为运行状态(一个三角形)
{
    spRender.sprite = sp[0];
}

}

也不做过多解释了,都注释好了

36.4 运行,已经可以通过点击右上角的图标进行暂停游戏了,但是虽然画面暂停了,但主角还是可以移动,这是个BUG,得解决一下

36.5 解决方法,打开控制玩家移动的代码heroMovement 修改Update中控制玩家移动条件的判断

这样 如果 游戏是正在运行状态才可以移动主角,反之游戏暂停状态则不能移动主角。

36.6 这只是一种通过点击屏幕上的图标暂停的,下面增加一种通过按键ESC暂停游戏,打开GameManager 脚本,在Update中添加代码,先声明一个枚举类型标志游戏状态

算了还是复制吧
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public enum GameState//游戏运行状态
{
Running, //正在运行
Pause, //暂停
}
public class GameMananger : MonoBehaviour {

public Text scoreText;  //获取 显示分数的组件
public static GameMananger _instance; //实例化一个对象
public int score;  //分数
public GameState gs = GameState.Running;
// Use this for initialization
void Start() {
_instance = this;  //实例化一个对象
}

// Update is called once per frame
   void Update()
{
//每帧检查是否按下ESC键,如果按下并且游戏是正在运行的状态
if (Input.GetKeyDown(KeyCode.Escape)&&gs==GameState.Running)
{
switchGameState();  //改变游戏状态
GameStateButton._instance.setToPause();  //右上角的暂停图标修改为暂停  
}
else if(Input.GetKeyDown(KeyCode.Escape) && gs == GameState.Pause)
{
switchGameState();//改变游戏状态
GameStateButton._instance.setToContinue();//右上角的暂停图标修改为运行
}
}
public void addScore(int sc)  //增加分数方法
{
   this.score = score + sc;
   scoreText.text = "Score:" + score;
//显示分数
}
public void switchGameState() //切换游戏状态
{
if (gs == GameState.Running)  //如果是正在运行的状态
{
pauseGame();  //调用暂停游戏的方法
}
else if(gs == GameState.Pause)  //如果游戏当前状态是暂停的
{
continueGame(); //调用继续游戏方法
}

}
public void pauseGame()  //暂停游戏
{
Time.timeScale = 0; //时间缩放为0
gs = GameState.Pause; 
}
public void continueGame()  //游戏继续
{
Time.timeScale = 1;   //时间缩放为1
gs = GameState.Running;
}


void OnGUI()   //显示继续游戏,退出游戏按钮
{
if (gs == GameState.Pause)  //游戏在暂停状态才会显示
{
if (GUI.Button(new Rect(Screen.width * 0.5f - 50, Screen.height * 0.4f, 100, 30), "Continue Game"))
{
continueGame();  //如果点击了 继续游戏按钮,则继续游戏
GameStateButton._instance.setToContinue();  // 调用右上角的按钮,把图标设为正在运行的图标
}
if (GUI.Button(new Rect(Screen.width * 0.5f - 50, Screen.height * 0.6f, 100, 30), "Quit Game"))
{
Application.Quit(); //如果点击的是退出游戏按钮,则关闭游戏
//GameStateButton._instance.setToPause();
}
}
}

}

36.7 这样就可以通过两种方式控制游戏状态了,点击也行,按键也行

37 此时,玩家还不会死亡,下面完成玩家死亡逻辑,按前面的方法为玩家的飞机做一个死亡动画和动画状态机设置好,不啰嗦了,直接截图表示


37.1 动画设置好以后,打开heroMovement 脚本 在OntriggerEneter方法中添加碰撞到敌机的代码


这样玩家撞到敌机后会爆炸,然后消失
38.下面完成游戏结束界面

38.1 把素材里的游戏结束图片拖到场景中,居中

38.2 新建2个Text 放到合适的位置,调整好大小

38.3为游戏结束那张图片新建一个脚本GameOver 编辑

38.4回到场景,记得指定好组件

39.再从素材里把“重新开始”、“退出游戏”两个图片拖到场景中,放好位置,并作为gameover图片的子集,并挂上BoxCollider 碰撞检测组件,用来相应点击

39.1 给“重新开始”新建一个脚本并编辑

39.2 给“退出游戏”也新建一个脚本

40.保存。下面是完整的测试

2015年12月25日00:23:29 Merry Christmas!

下面是源文件下载链接:
链接: http://pan.baidu.com/s/1o7p30Au 密码: na3y

你可能感兴趣的:(Unity3D)