CamRatioAdapter.cs

纵向2D游戏的屏幕宽度匹配 

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

// 本脚本适用于纵向2D游戏的屏幕宽度匹配
// 如果是横向卷轴游戏,不需要用这个脚本
public class CamRatioAdapter : MonoBehaviour
{
    // 测试结果:屏幕宽高比3:4 = 0.75对应摄像机size3.75
    // 屏幕宽高比9:16 = 0.5625对应摄像机大小5

    [Tooltip("屏幕宽/高")]
    [SerializeField]
    float ratio1 = 0.75f;

    [Tooltip("正交摄像机Size")]
    [SerializeField]
    float size1 = 3.75f;

    Camera cam;

    void Update()
    {
        // 获取屏幕比例,计算正交摄像机的size
        float curRatio = (float)Screen.width / Screen.height;

        // 摄像机默认适配高度。当宽高比与摄像机size成反比时,能得到适配宽度的结果
        float a = ratio1 * size1;
        float size = a / curRatio;
        
        cam = GetComponent<Camera>();
        cam.orthographicSize = size;
    }

}

2D游戏多图裁剪,设置层级

unity发射器_System

 

unity发射器_c#_02

 碰撞

unity发射器_unity发射器_03

 灵敏度

unity发射器_unity发射器_04

PlayerCha.cs

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

public class PlayerCha : MonoBehaviour
{
    public float speed = 3;
    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        
    }

    public void Move(Vector3 input)
    {
        transform.position += input * speed * Time.deltaTime;
    }
}

PlayerControl.cs

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

public class PlayerControl : MonoBehaviour
{
    PlayerCha player;
    // Start is called before the first frame update
    void Start()
    {
        player = GetComponent<PlayerCha>();
    }

    // Update is called once per frame
    void Update()
    {
        float h = Input.GetAxis("Horizontal");
        float v = Input.GetAxis("Vertical");

        Vector3 move = new Vector3(h, v, 0);

        //调用角色的移动函数
        player.Move(move);

    }
}

Texture Repeat 

unity发射器_System_05

  

unity发射器_System_06

借用图形学知识

unity发射器_c#_07

采用3D的Quad做2D的背景(Unity用图片做2D背景有Bug)

unity发射器_unity_08

sharedMaterial&Material

BGMove.cs

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

public class BGMove : MonoBehaviour
{
    Material mat;
    public float speed;
    // Start is called before the first frame update
    void Start()
    {
        mat = GetComponent<MeshRenderer>().sharedMaterial;
    }

    // Update is called once per frame
    void Update()
    {
        mat.mainTextureOffset += new Vector2(0, speed * Time.deltaTime);
    }
}

Bullet.cs

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

public class Bullet : MonoBehaviour
{
    public float speed = 6;
    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        transform.position += Vector3.up * speed * Time.deltaTime;
    }

    private void OnTriggerEnter2D(Collider2D collision)
    {
        Destroy(gameObject);
    }

}

层碰撞矩阵

unity发射器_Time_09

 EnemyBeHit.cs

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

public class EnemyBeHit : MonoBehaviour
{
    SpriteRenderer[] renders;

    public float redTime;   //保持红色的时间
    float changeColorTime;  //变回白色的时间
    void Start()
    {
        renders = GetComponentsInChildren<SpriteRenderer>();
    }

    private void Update()
    {
        if (Time.time >= changeColorTime)
        {
            SetColor(Color.white);
        }
    }

    void SetColor(Color c)
    {
        if(renders[0].color == c)
        {
            return;
        }
        foreach(var r in renders)
        {
            r.color = c;
        }
    }

    private void OnTriggerEnter2D(Collider2D collision)
    {
        SetColor(Color.red);
        changeColorTime = Time.time + redTime;
    }


}

创建爆炸动画

裁剪

Grid By Cell Count 4x4:

unity发射器_c#_10

创建Square,创建Animation取名为Boom,把裁剪好的图片全选拖入Animation窗口,把Boom拖入Square,随机选一张爆炸图修改Square初始图片

unity发射器_System_11

unity发射器_unity发射器_12

 

unity发射器_System_13

添加脚本AnimEvent.cs

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

public class AnimEvent : MonoBehaviour
{
    public void Destroy()
    {
        Destroy(gameObject);
    }
}

 

unity发射器_unity_14

EnemyBeHit.cs

unity发射器_c#_15

//播放爆炸特效

Instantiate(prefabBoom, transform.position, Quaternion.identity);

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

public class EnemyBeHit : MonoBehaviour
{
    SpriteRenderer[] renders;

    public float redTime = 0.1f;   //保持红色的时间
    float changeColorTime;  //变回白色的时间

    public float hp = 10;

    public Transform prefabBoom;  //爆炸动画
    void Start()
    {
        renders = GetComponentsInChildren<SpriteRenderer>();
    }

    private void Update()
    {
        if (Time.time >= changeColorTime)
        {
            SetColor(Color.white);
        }
    }

    void SetColor(Color c)
    {
        if(renders[0].color == c)
        {
            return;
        }
        foreach(var r in renders)
        {
            r.color = c;
        }
    }

    private void OnTriggerEnter2D(Collider2D collision)
    {
        SetColor(Color.red);
        changeColorTime = Time.time + redTime;

        hp -= 1;
        if (hp <= 0)
        {
            //死亡
            Destroy(gameObject);
            //播放爆炸特效
            Instantiate(prefabBoom, transform.position, Quaternion.identity);

        }
    }
}

添加小怪

照之前的方法切割,拼图

更改压缩质量、去除磨皮效果

unity发射器_Time_16

Before: 

 

unity发射器_unity_17

Now:

 

unity发射器_Time_18

 同样添加组件

unity发射器_unity_19

并修改层级

unity发射器_c#_20

 写个Enemy Move脚本,挂到小怪兽上

 EnemyMove.cs

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

public class EnemyMove : MonoBehaviour
{
    public float speed = 3;
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        transform.position += Vector3.down * speed * Time.deltaTime;
    }
}

为了防止子弹一直存在,积累太多,写个脚本挂在子弹上,4s后自动销毁

unity发射器_System_21

 DelayDestroy.cs

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

public class DelayDestroy : MonoBehaviour
{
    // Start is called before the first frame update
    public float time = 1;
    void Start()
    {
        StartCoroutine(Delay());
    }

    IEnumerator Delay()
    {
        yield return new WaitForSeconds(time);
        Destroy(gameObject);
    }

}

为了防止玩家出框,给玩家设置边界(左右2.3,上下4.3)并加上[Serializable]特性使边界可编辑

写个Border类放到Border.cs脚本里

Border.cs

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

public class Border : MonoBehaviour
{
    public float top = 4.3f;
    public float bottom = -4.3f;
    public float left = -2.3f;
    public float right = 2.3f;
}

 在PlayerCha.cs中调用Border 

    //移动的边界范围
    Border moveBorder;

//Clamp:限定范围
        pos.x = Mathf.Clamp(pos.x, moveBorder.left, moveBorder.right);
        pos.y = Mathf.Clamp(pos.y, moveBorder.bottom, moveBorder.top);

        transform.position = pos;

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

public class PlayerCha : MonoBehaviour
{
    public Transform prefabBullet;
    public float speed = 3;

    public float fireCD = 0.2f;
    float lastFireTime;

    //移动的边界范围
    Border moveBorder;

    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        
    }
    public void Move(Vector3 input)
    {
        Vector3 pos = transform.position + input * speed * Time.deltaTime;

        //Clamp:限定范围
        pos.x = Mathf.Clamp(pos.x, moveBorder.left, moveBorder.right);
        pos.y = Mathf.Clamp(pos.y, moveBorder.bottom, moveBorder.top);

        transform.position = pos;
        //transform.position += input * speed * Time.deltaTime;       
    }
    public void Fire()
    {
        if(Time.time < lastFireTime + fireCD)
        {
            return;
        }

        Vector3 pos = transform.position + new Vector3(0, 0.8f, 0);
        Transform bullet = Instantiate(prefabBullet, pos, Quaternion.identity);
        lastFireTime = Time.time;

    }

}

创建怪物营地

创建空物体Spawner

Spawner.cs

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

public class Spawner : MonoBehaviour
{
    //多个怪物的预制体
    public List<Transform> monsters;

    public float minTime = 0.5f;
    public float maxTime = 2;

    // Start is called before the first frame update
    void Start()
    {
        StartCoroutine(Create());
    }

    IEnumerator Create()
    {
        while (true)
        {
            //创建怪物

            //随机怪物下标
            int i = Random.Range(0, monsters.Count);
            //随机位置
            Vector3 pos = new Vector3(Random.Range(-2.1f,2.1f), transform.position.y, 0);
            Transform m = Instantiate(monsters[i], pos, Quaternion.identity);


            //等一段时间
            float t = Random.Range(minTime, maxTime);
            yield return new WaitForSeconds(t);

        }
    }

    // Update is called once per frame
    void Update()
    {
        
    }
}

把脚本挂在空物体上,把前面做好的 小怪兽拖到Monsters列表里

unity发射器_Time_22

 让大怪兽左右飞行

BossMove.cs

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

public class BossMove : MonoBehaviour
{
    //枚举状态,定义在类之内
    enum State
    {
        Down,
        LeftRight,
    }
    State state = State.Down;

    public float minY = 2.6f;
    public float minX = -2.3f;
    public float maxX = 2.3f;

    public float speed = 3f;

    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        switch (state)
        {
            case State.Down:
                {
                    transform.position += Vector3.down * 3 * Time.deltaTime;
                    if(transform.position.y < minY)
                    {
                        state = State.LeftRight;
                    }
                }
                break;
            case State.LeftRight:
                {
                    transform.position += Vector3.left * speed * Time.deltaTime;
                    if (transform.position.x < minX)
                    {
                        speed = -Mathf.Abs(speed);
                    }
                    if (transform.position.x > maxX)
                    {
                        speed = Mathf.Abs(speed);
                    }
                    //if (transform.position.x < minX || transform.position.x > maxX)
                    //{
                    //    speed *= -1;
                    //}
                }
                break;
        }
    }
}

全部脚本

PlayerControl.cs

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

public class PlayerControl : MonoBehaviour
{
    PlayerCha player;
    // Start is called before the first frame update
    void Start()
    {
        player = GetComponent<PlayerCha>();
    }

    // Update is called once per frame
    void Update()
    {
        float h = Input.GetAxis("Horizontal");
        float v = Input.GetAxis("Vertical");

        Vector3 move = new Vector3(h, v, 0);

        //调用角色移动函数
        player.Move(move);

        if (Input.GetButton("Fire1"))
        {
            player.Fire();
        }
        
    }
}

PlayerCha.cs

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

public class PlayerCha : MonoBehaviour
{
    public Transform prefabBullet;
    public float speed = 3;
    public float fireCD = 0.2f;
    float lastFireTime;

    //移动的边界范围
    public Border moveBorder;

    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        
    }
    public void Move(Vector3 input)
    {
        Vector3 pos = transform.position + input * speed * Time.deltaTime;

        //Clamp:限定范围
        pos.x = Mathf.Clamp(pos.x, moveBorder.left, moveBorder.right);
        pos.y = Mathf.Clamp(pos.y, moveBorder.bottom, moveBorder.top);

        transform.position = pos;
        //transform.position += input * speed * Time.deltaTime;       
    }
    public void Fire()
    {
        if(Time.time < lastFireTime + fireCD)
        {
            return;
        }

        Vector3 pos = transform.position + new Vector3(0, 0.8f, 0);
        Transform bullet = Instantiate(prefabBullet, pos, Quaternion.identity);
        lastFireTime = Time.time;

    }
    private void OnTriggerEnter2D(Collider2D collision)
    {
        Debug.Log("玩家碰到怪物");
        Destroy(gameObject);
    }
}

Bullet.cs

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

public class Bullet : MonoBehaviour
{
    public float speed = 6;
    public Transform prefabExpl;    //爆炸图的预制体
    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        transform.position += Vector3.up * speed * Time.deltaTime;
    }

    private void OnTriggerEnter2D(Collider2D collision)
    {
        Destroy(gameObject);
        //创建爆炸图
        if (prefabExpl)   //判断变量指向物体,且物体存在
        {
            Transform expl = Instantiate(prefabExpl, transform.position, Quaternion.identity);
        }
    }
}

EnemyBeHit.cs

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

public class EnemyBeHit : MonoBehaviour
{
    SpriteRenderer[] renders;

    public float redTime = 0.1f;   //保持红色的时间
    float changeColorTime;  //变回白色的时间

    public float hp = 10;

    public Transform prefabBoom;  //爆炸动画
    void Start()
    {
        renders = GetComponentsInChildren<SpriteRenderer>();
    }

    private void Update()
    {
        if (Time.time >= changeColorTime)
        {
            SetColor(Color.white);
        }
    }

    void SetColor(Color c)
    {
        if(renders[0].color == c)
        {
            return;
        }
        foreach(var r in renders)
        {
            r.color = c;
        }
    }

    private void OnTriggerEnter2D(Collider2D collision)
    {
        SetColor(Color.red);
        changeColorTime = Time.time + redTime;

        hp -= 1;
        if (hp <= 0)
        {
            //死亡
            Destroy(gameObject);
            //播放爆炸特效
            Instantiate(prefabBoom, transform.position, Quaternion.identity);

        }
    }
}

BoseMove.cs

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

public class BossMove : MonoBehaviour
{
    //枚举状态,定义在类之内
    enum State
    {
        Down,
        LeftRight,
    }
    State state = State.Down;

    public float minY = 2.6f;
    public float minX = -2.3f;
    public float maxX = 2.3f;

    public float speed = 3f;

    void Start()
    {
        
    }
    // Update is called once per frame
    void Update()
    {
        switch (state)
        {
            case State.Down:
                {
                    transform.position += Vector3.down * 3 * Time.deltaTime;
                    if(transform.position.y < minY)
                    {
                        state = State.LeftRight;
                    }
                }
                break;
            case State.LeftRight:
                {
                    transform.position += Vector3.left * speed * Time.deltaTime;
                    if (transform.position.x < minX)
                    {
                        speed = -Mathf.Abs(speed);
                    }
                    if (transform.position.x > maxX)
                    {
                        speed = Mathf.Abs(speed);
                    }
                    //if (transform.position.x < minX || transform.position.x > maxX)
                    //{
                    //    speed *= -1;
                    //}
                }
                break;
        }
    }
}

EnemyMove.cs

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

public class EnemyMove : MonoBehaviour
{
    public float speed = 3;
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        transform.position += Vector3.down * speed * Time.deltaTime;

        if(transform.position.y < -10 ||transform.position.y > 10)
        {
            Destroy(gameObject);
        }

    }
}

BGMove.cs

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

public class BGMove : MonoBehaviour
{
    Material mat;
    public float speed;
    // Start is called before the first frame update
    void Start()
    {
        mat = GetComponent<MeshRenderer>().sharedMaterial;
    }

    // Update is called once per frame
    void Update()
    {
        mat.mainTextureOffset += new Vector2(0, speed * Time.deltaTime);
    }
}

Spawner.cs

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

public class Spawner : MonoBehaviour
{
    //多个怪物的预制体
    public List<Transform> monsters;

    public float minTime = 0.5f;
    public float maxTime = 2;

    // Start is called before the first frame update
    void Start()
    {
        StartCoroutine(Create());
    }

    IEnumerator Create()
    {
        while (true)
        {
            //创建怪物

            //随机怪物下标
            int i = Random.Range(0, monsters.Count);
            //随机位置
            Vector3 pos = new Vector3(Random.Range(-2.1f,2.1f), transform.position.y, 0);
            Transform m = Instantiate(monsters[i], pos, Quaternion.identity);


            //等一段时间
            float t = Random.Range(minTime, maxTime);
            yield return new WaitForSeconds(t);

        }
    }

    // Update is called once per frame
    void Update()
    {
        
    }
}

Border.cs

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

[Serializable]
public class Border : MonoBehaviour
{
    public float top = 4.3f;
    public float bottom = -4.3f;
    public float left = -2.3f;
    public float right = 2.3f;
}

AnimEvent.cs

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

public class AnimEvent : MonoBehaviour
{
    public void Destroy()
    {
        Destroy(gameObject);
    }
}

DelayDestroy.cs

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

public class DelayDestroy : MonoBehaviour
{
    // Start is called before the first frame update
    public float time = 1;
    void Start()
    {
        StartCoroutine(Delay());
    }

    IEnumerator Delay()
    {
        yield return new WaitForSeconds(time);
        Destroy(gameObject);
    }

}

CamRatioAdapter.cs

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

// 本脚本适用于纵向2D游戏的屏幕宽度匹配
// 如果是横向卷轴游戏,不需要用这个脚本
public class CamRatioAdapter : MonoBehaviour
{
    // 测试结果:屏幕宽高比3:4 = 0.75对应摄像机size3.75
    // 屏幕宽高比9:16 = 0.5625对应摄像机大小5

    [Tooltip("屏幕宽/高")]
    [SerializeField]
    float ratio1 = 0.75f;

    [Tooltip("正交摄像机Size")]
    [SerializeField]
    float size1 = 3.75f;

    Camera cam;

    void Update()
    {
        // 获取屏幕比例,计算正交摄像机的size
        float curRatio = (float)Screen.width / Screen.height;

        // 摄像机默认适配高度。当宽高比与摄像机size成反比时,能得到适配宽度的结果
        float a = ratio1 * size1;
        float size = a / curRatio;
        
        cam = GetComponent<Camera>();
        cam.orthographicSize = size;
    }

}

附:开始界面(场景切换)

设置开始界面为0,游戏场景为1

unity发射器_Time_23

StartScene.cs

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

public class StartScene : MonoBehaviour
{
    public void OnBtnStart()
    {
        SceneManager.LoadScene(1);
    }
}

 创建空物体GameObject

unity发射器_System_24

把StartScene.cs拖进去

 

unity发射器_c#_25

 把空物体拖到Button的Onclick下,并修改事件为OnBtnStart

unity发射器_unity_26

Unity UI ---- Canvas 随画面缩放

unity发射器_c#_27

设置相对位置(锚点)

unity发射器_System_28

播放音效、闪烁等

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

public class StartScene : MonoBehaviour
{
    public AudioClip startSound;  //开始按钮音效
    AudioSource audioSource;

    void Start()
    {
        audioSource = GetComponent<AudioSource>();
    }
    public void OnstartButton()
    {
        //播放音效
        audioSource.clip = startSound;
        audioSource.Play();

        //开启协程
        StartCoroutine(CoGameStart());
    }
    IEnumerator CoGameStart()
    {
        GameObject btn = GameObject.Find("开始按钮");
        //开始按钮闪烁
        for(int i = 0; i < 6; i++)
        {
            //隐藏/显示
            btn.SetActive(!btn.activeInHierarchy);
            yield return new WaitForSeconds(0.3f);
        }
        //切换场景
        Debug.Log("切换场景");
        SceneManager.LoadScene(1);
    }
}