unity3d 2d游戏(太空大战)开发笔记

最近刚开始看unity3d游戏开发,感觉2d游戏似乎简单些,所以先从2d游戏入手试试看吧。

2d游戏大约要分为背景,角色(需要控制的己方角色car,敌机enemy,奖励物品prop),ui(分数显示,暂停继续等),音乐(背景音乐,攻击音乐,死亡音乐等)

unity3d 2d游戏(太空大战)开发笔记大约长这样,emmm,原视频是主角是小飞机,背景是天空,也给有素材,但起初学习的时候想稍微更改下,就自己制作了小汽车主角和马路的背景,之后。。。觉得有点麻烦还是用了源素材,所以忽略这种突兀的感觉吧!

1.首先背景移动,需要两张背景交替向下移动,实现背景连续移动的效果。挂在背景图片上。

 

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

public class move : MonoBehaviour {        //背景移动

    public float speed = 2f;        //速度
    
    // Update is called once per frame
    void Update ()
    {
        this.transform.Translate (Vector3.down * speed * Time.deltaTime);        //每帧向下移动
        Vector3 postion = this.transform.position;
        if (postion.y <= -20.48f) {        //如果移动超过。。则向上移动,实现循环
            this .transform .position = new Vector3 (postion .x,postion .y + 20.48f*2,postion .z);
        }
    }
}

2.主角car(好吧假装是个飞机)实现发射子弹与主角的移动

创建两个空物体作为主角的子对象,放在子弹发射的起始位置,这样子弹就会相对主角的位置移动,只用实现子弹生成与移动就好了。为子弹添加2d碰撞检测器,当子弹碰到敌机时调用敌机的死亡脚本

子弹生成

public class gun : MonoBehaviour {

    public float rate = 0.1f;       //子弹生成时间间隔
    public float speed = 2f;        //子弹生成速度
    public GameObject bullet;
    // Use this for initialization


    public void fire ()
    {
        GameObject .Instantiate (bullet,transform .position ,Quaternion .identity );
    }
    public void openfire(){
        InvokeRepeating ("fire",1,rate);    //1秒后开始生成子弹,之后每隔rate个时间生成一个
    }
    public void stopfire ()
    {
        CancelInvoke ("fire");
    }

}

子弹移动

public class bullet : MonoBehaviour {    //子弹移动

    public float speed = 5f;


    void Update ()
    {
        transform.Translate (Vector3.up * speed * Time.deltaTime);
        if (transform.position.y >= 8.5f) {          //如果子弹移动出屏幕范围,销毁
            Destroy (this .gameObject );
        }
    }

    void OnTriggerEnter2D (Collider2D other)
    {
        if (other.tag == "enemy") {        //击中敌机,调用敌机的BeHit方法并将自身删除
            if (!other.GetComponent <enemy > ().isDeath) {
                other.gameObject.SendMessage ("BeHit");
                GameObject.Destroy (this.gameObject);
            }
        }
    }
}

将子弹生成脚本挂在空物体上,在Bullet后找到相应的子弹物体

unity3d 2d游戏(太空大战)开发笔记

将子弹移动脚本挂在子弹物体上

对于主角car,通过切换两张图片实现主角的动画(我记得sprite有个直接把2d序列帧图片放在一张图片上会自动裁切并且按序列帧播放的,但是没有尝试,之后再说吧),通过检测鼠标按下时的位置来对car进行移动(需要将屏幕坐标转换为世界坐标),判断car在世界坐标中的位置来控制car不移出背景。

public class car : MonoBehaviour
{

    public bool animation = true;
    //动画控制开关

    public int frameCountPersconds = 10;
    //每秒播放10帧

    public Camera TempC;

    public float timer = 0;
    //计时器

    public Sprite[] sprites;

    public float superGunTime = 10f;

    public gun gunRight;

    public gun gunLeft;

    private float resetSuperGunTime;

    private bool isMouseDown = false;

    private  Vector3 lastMoustPosition = Vector3.zero;

    //    private Transform hero;

    private int gunCount = 1;


    void Start ()
    {
//        spreteRender = this .GetComponent <SpriteRenderer >();
//        hero = GameObject .FindGameObjectWithTag ("hero").transform ;        //利用标签找物体
//        TempC  = this.GetComponent <Camera >();
        resetSuperGunTime = superGunTime;
        superGunTime = 0;
        gunLeft .openfire ();
    }

    void Update ()
    {
        if (animation) {        //切换两张图片实现动画
            timer += Time.deltaTime;        //计时
            int frameIndex = (int)(timer / (1f / frameCountPersconds));     //图片切换几次
            int frame = frameIndex % 2;     //将图片切换次数循环
            this.GetComponent <SpriteRenderer > ().sprite = sprites [frame];        //将图片于次数对应
        }
        if (Input.GetMouseButtonDown (0)) {        //检测鼠标是否按下
            isMouseDown = true;
        }
        if (Input.GetMouseButtonUp (0)) {
            isMouseDown = false;
//            lastMoustPosition = Vector3 .zero ;
        }
        if (isMouseDown && scoreShow .instance .gameState == GameState.Runing ) {    //鼠标按下且游戏是运行状态(非暂停)
            if (lastMoustPosition != Vector3.zero) {
        
                //    Camera .main .ScreenToWorldPoint (Input .mousePosition )    将屏幕坐标转化为世界坐标
//                Debug .Log ("Camera.main.ScreenToWorldPoint(Input .mousePosition"+TempC .ScreenToWorldPoint(new Vector3 ( //Input .mousePosition.x,Input .mousePosition .y,10.0f )));
                Vector3 offset = TempC.ScreenToWorldPoint (new Vector3 (Input.mousePosition.x, Input.mousePosition.y, 10f)) - lastMoustPosition;        //坐标不能为0
                transform.position = transform.position + offset;        //移动
                checkPosition ();
            }
            lastMoustPosition = TempC.ScreenToWorldPoint (new Vector3 (Input.mousePosition.x, Input.mousePosition.y, 10f));
        }
        superGunTime -= Time.deltaTime;
        if (superGunTime > 0) {     //切换超级子弹
            if (gunCount == 1) {
                transformToSuperGun ();
            }
        } else {
            if (gunCount == 2) {
                transformToNormalGun ();
            }
        }        
    }

    private void transformToSuperGun ()
    {
        gunCount = 2;
        gunRight.openfire ();
        gunLeft.stopfire ();

    }

    private void transformToNormalGun ()
    {
        gunCount = 1;
        gunRight.stopfire ();
        gunLeft.openfire ();

    }

    private void checkPosition ()           //检测car移动的位置防止移动出背景
    {
        //check -2.1<x<2.1
        //check -3.23<y<2.84
        Vector3 pos = transform.position;
        float x = pos.x;
        float y = pos.y;
        if (x < -2.1f) {
            x = -2.1f;
        }
        if (x > 2.1f) {
            x = 2.1f;
        }
        if (y < -3.23f) {
            y = -3.23f;
        }
        if (y > 2.84f) {
            y = 2.84f;
        }
        transform.position = new Vector3 (x, y, 0);
        
    }

    public void OnTriggerEnter2D (Collider2D collider)      //如果碰撞到标签是prop的物体,切换超级子弹(初始化superGunTime,并逐渐减少)
    {    
        if (collider.tag == "prop") {
            prop prop = collider.GetComponent <prop > ();
            if (prop.type == 0) {
                superGunTime = resetSuperGunTime;
                Destroy (collider .gameObject );
            }
        }
    }
}

  3.敌机与奖励物品生成和移动

创建空物体,放在屏幕外稍微靠上的部位用于敌机和奖励物品的生成。利用随机数控制敌机生成的位置

public class spawn : MonoBehaviour {        //敌机和奖励的生成

    public GameObject enemy0;
    public GameObject enemy1;
    public GameObject enemy2;

    public GameObject prop0;
    public GameObject prop1;

    public float rate0 = 1f;
    public float rate1 = 5f;
    public float rate2 = 8f;

    public float rateProp0 = 3f;
    public float rateprop1 = 5f;

    // Use this for initialization
    void Start () {
        InvokeRepeating ("createnemy0",1,rate0);
        InvokeRepeating ("createnemy1",3,rate1);
        InvokeRepeating ("createnemy2",5,rate2);

        InvokeRepeating ("creatprop0",5,rateProp0);
        InvokeRepeating ("creatprop1",8,rateprop1);
    }
    
    // Update is called once per frame
    void Update ()
    {
    }
    
    public void createnemy0(){
        float x0 = Random .Range (-2.3f,2.3f);
        GameObject .Instantiate (enemy0  ,new Vector3 (x0,this .transform .position .y,0),Quaternion .identity );
        }
    public void createnemy1(){
        float x1 = Random .Range (-2.2f,2.2f);
        GameObject .Instantiate (enemy1  ,new Vector3 (x1,this .transform .position .y,0),Quaternion .identity );
        }
    public void createnemy2(){
        float x2 = Random .Range (-1.8f,1.8f);
        GameObject .Instantiate (enemy2  ,new Vector3 (x2,this .transform .position .y,0),Quaternion .identity );
        }

    public void creatprop0(){
        float x0 = Random .Range (-2.2f,2.2f);
        GameObject .Instantiate (prop0  ,new Vector3 (x0,this .transform .position .y,0),Quaternion .identity );
        }
    public void creatprop1(){
        float x1 = Random .Range (-2.1f,2.1f);
        GameObject .Instantiate (prop1  ,new Vector3 (x1,this .transform .position .y,0),Quaternion .identity );
        }
}

奖励物品比较简单,只用移动,检测到于主角car碰撞后将自身删除就可以了

public class prop : MonoBehaviour {        //奖励物品移动

    public float speed = 1.5f ;
    public GameObject award;
    public int type = 1;
    public float posY;

    // Use this for initialization
    void Start () {
        
    }
    
    // Update is called once per frame
    void Update () {
        this .transform .Translate (Vector3 .down *speed *Time .deltaTime );
        if (this .transform .position .y <= posY ){
            Destroy (this.gameObject );
        }
    }
}

敌机的状态较为复杂,三种敌机分别设置不同的移动速度,有不同的hp值和分数,当子弹碰撞到敌机时切换敌机状态为BeHit状态,hp递减且播放受伤动画(不知道为什么这里的受伤动画一直没弄好)当hp为0时切换为toDie,调用isDeath方法并且增加分数。isDeath为true时播放死亡动画,动画播放完后删除此物体

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

public enum EnumyType{
        smallEnemy,
        middleEnemy,
        bigEnemy
}

public class enemy : MonoBehaviour {        

    public int hp = 1;
    public float speed = 2f;

    public int score = 100;

    public float posY;

    public EnumyType type =  EnumyType.smallEnemy ;

    public bool isDeath = false ;

    public Sprite [] explosionSprites;
    private float timer = 0;
    public int frameCountPersconds = 20;

    private  SpriteRenderer render;

    public float hitTimer = 0.2f;
    private float resetHitTime;
    public Sprite [] hitSprites;
    // Use this for initialization
    void Start () {
        render = this.GetComponent <SpriteRenderer>();

        resetHitTime  = hitTimer ;
        hitTimer = 0f;
    }
    
    // Update is called once per frame
    void Update ()
    {        //敌机移动
        this.transform.Translate (Vector3.down * speed * Time.deltaTime);
        if (transform.position.y <= posY) {
            Destroy (this.gameObject);
        }
        if (isDeath == true) {        //播放死亡动画

            timer += Time.deltaTime;
            int frameIndex = (int)(timer / (1f / frameCountPersconds));
            if (frameIndex >= explosionSprites.Length) {
                Destroy (this.gameObject);
            } else {
                render.sprite = explosionSprites [frameIndex];
            }        
        } 
//        else {        //播放受伤动画
//            if(type == EnumyType .middleEnemy || type == EnumyType .bigEnemy ){
//                if (hitTimer >0 ){
////                    Debug .Log ("hitTime" +hitTimer );
//                    hitTimer -=Time .deltaTime ;
////                    Debug .Log ("resetHitTime"+resetHitTime);
//                    int frameIndex = (int)((resetHitTime - hitTimer )/(1f/frameCountPersconds ));
//                    int frame = frameIndex %2;
////                    Debug .Log ("frame" + frame );
//                    render.sprite = hitSprites [frame];
//                }
//            }
//        }

    }

    public void BeHit ()        //被击中
    {
        hp -= 1;
        if (hp <= 0) {
            toDie ();
        }
//         else {
//            hitTimer = resetHitTime ;
//        }
    }
    private void toDie ()
    {    
        if (!isDeath) {
            isDeath = true;
            scoreShow .instance.score += score;
        }
    }
}

4.分数的记录显示与游戏的暂停

public enum GameState {
    Runing,
    Pause
}

public class scoreShow : MonoBehaviour {

    public static scoreShow instance ;

    public int score = 0;      //分数

    private GameObject findscrShow;
    private Text txt_score;

    public GameState gameState = GameState.Runing;


    // Use this for initialization
    void Start () {
        instance = this;
        //  txt_score = this.GetComponent<Text>();      //法1:获取到Text(手动挂在scroeShow下)
        findscrShow = GameObject.Find("scoreShow");      //法2  获取scroeShow后获取Text
        txt_score = findscrShow.GetComponent<Text>();
    }
    
    // Update is called once per frame
    void Update () {
        txt_score.text = "score:" + score;
    }

    public void transformGameState() {
        if (gameState == GameState.Runing ) {
            pauseGame();
        }
        else if (gameState==GameState.Pause ) {
            resumeGame();
        }
    }
    public void pauseGame() {
        Time.timeScale = 0;
        gameState = GameState.Pause;
    }
    public void resumeGame() {
        Time.timeScale = 1;
        gameState = GameState.Runing;
    }
}

暂停

public class gamePause : MonoBehaviour {

    private void OnMouseUpAsButton()
    {
        scoreShow .instance.transformGameState();
    }
}

 

unity3d 2d游戏(太空大战)开发笔记

unity3d 2d游戏(太空大战)开发笔记