Angelyatou/Endless_Unity_Projects: Unity Projects of Endlessdaydram ()/Angelyatou/Endless_Unity_Projects
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(){// 获取屏幕比例,计算正交摄像机的sizefloat curRatio = (float)Screen.width / Screen.height;// 摄像机默认适配高度。当宽高比与摄像机size成反比时,能得到适配宽度的结果float a = ratio1 * size1;float size = a / curRatio;cam = GetComponent<Camera>();cam.orthographicSize = size;}}
2D游戏多图裁剪,设置层级
碰撞
灵敏度
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 updatevoid Start(){}// Update is called once per framevoid 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 updatevoid Start(){player = GetComponent<PlayerCha>();}// Update is called once per framevoid Update(){float h = Input.GetAxis("Horizontal");float v = Input.GetAxis("Vertical");Vector3 move = new Vector3(h, v, 0);//调用角色的移动函数player.Move(move);}}
Texture Repeat
借用图形学知识
采用3D的Quad做2D的背景(Unity用图片做2D背景有Bug)
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 updatevoid Start(){mat = GetComponent<MeshRenderer>().sharedMaterial;}// Update is called once per framevoid 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 updatevoid Start(){}// Update is called once per framevoid Update(){transform.position += Vector3.up * speed * Time.deltaTime;}private void OnTriggerEnter2D(Collider2D collision){Destroy(gameObject);}}
层碰撞矩阵
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:
创建Square,创建Animation取名为Boom,把裁剪好的图片全选拖入Animation窗口,把Boom拖入Square,随机选一张爆炸图修改Square初始图片
添加脚本AnimEvent.cs
using System.Collections;using System.Collections.Generic;using UnityEngine;public class AnimEvent : MonoBehaviour{public void Destroy(){Destroy(gameObject);}}
EnemyBeHit.cs
//播放爆炸特效
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);}}}
添加小怪
照之前的方法切割,拼图
更改压缩质量、去除磨皮效果
Before:
Now:
同样添加组件
并修改层级
写个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 framevoid Update(){transform.position += Vector3.down * speed * Time.deltaTime;}}
为了防止子弹一直存在,积累太多,写个脚本挂在子弹上,4s后自动销毁
DelayDestroy.cs
using System.Collections;using System.Collections.Generic;using UnityEngine;public class DelayDestroy : MonoBehaviour{// Start is called before the first frame updatepublic 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 framevoid 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 updatevoid 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 framevoid Update(){}}
把脚本挂在空物体上,把前面做好的小怪兽拖到Monsters列表里
让大怪兽左右飞行
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 framevoid 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 updatevoid Start(){player = GetComponent<PlayerCha>();}// Update is called once per framevoid 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 framevoid 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 updatevoid Start(){}// Update is called once per framevoid 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 framevoid 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 framevoid 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 updatevoid Start(){mat = GetComponent<MeshRenderer>().sharedMaterial;}// Update is called once per framevoid 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 updatevoid 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 framevoid 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 updatepublic 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(){// 获取屏幕比例,计算正交摄像机的sizefloat curRatio = (float)Screen.width / Screen.height;// 摄像机默认适配高度。当宽高比与摄像机size成反比时,能得到适配宽度的结果float a = ratio1 * size1;float size = a / curRatio;cam = GetComponent<Camera>();cam.orthographicSize = size;}}
附:开始界面(场景切换)
设置开始界面为0,游戏场景为1
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
把StartScene.cs拖进去
把空物体拖到Button的Onclick下,并修改事件为OnBtnStart
Unity UI ---- Canvas随画面缩放
设置相对位置(锚点)
播放音效、闪烁等
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);}}