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