1000字范文,内容丰富有趣,学习的好帮手!
1000字范文 > 【开发日志】.10.06 Unity自制小游戏《飞龙射击》全过程详解

【开发日志】.10.06 Unity自制小游戏《飞龙射击》全过程详解

时间:2019-12-05 01:35:10

相关推荐

【开发日志】.10.06 Unity自制小游戏《飞龙射击》全过程详解

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);}}

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。