概念1:预制体PreFab
将一个GameObject制作成一个组件模板,用于批量套用。
向场景添加一个预制体时,会创建一个它的实例,可在不同场景或同一场景创建多个预制体的实例,当修改预制体的属性时,这些修改也应用在所有实例上。
概念2:碰撞器Box collider
两个碰撞的物体身上都要有碰撞器组件,其中至少有一个为刚体Rigidbody(最好是运动的一方)
原理:刚体长时间不运动会休眠以提升程序性能,如果选择不运动的为刚体,可能互动无效。
其中2D、3D谨防混用,混用则无效
概念3:组件层级Layer
Camera-Sorting Layer-Order In layer
概念4:音频源Audio Source
属性说明Audio Clip设置被播放的音频文件Mute静音播放Play On Awake唤醒时播放脚本结构:
public class XXX:Monobehaviour{ //继承Unity的Monobehaviour部分方法 void Start(){ //游戏运行第一帧执行 } void Update(){ //游戏每运行一帧执行一次 } } 菜单页通过键盘【W】、【S】键控制指针选择单/双人游戏,点击空格键确认选项并开始游戏。玩家有三点生命值,在每次生成后的三秒内带有保护盾,敌方攻击无效。游戏开始后生成三架敌方坦克,此后每隔四秒随机生成敌方坦克,当玩家坦克被击杀三次或最下方巢穴被敌方炸毁后游戏失败,失败后玩家不可控制坦克移动,三秒后跳转回菜单页。游戏页右侧图标和数字显示被玩家击杀的坦克数和玩家剩余生命值。【ESC】退出游戏。
玩家脚本:
public class Player : MonoBehaviour { public float moveSpeed=3; private Vector3 bulletEulerAngles; private float timeVal;//设置攻击CD private float defendTimeVal=3; private bool isDefended=true; private SpriteRenderer sr; public Sprite[] tankSprite;//依次为上右下左 public GameObject bulletPrefab; public GameObject explosionPrefab; public GameObject defendEffectPrefab;//受保护引用 public AudioSource moveAudio;//音效组件引用,控制音效播放 public AudioClip[] tankAudio;//音效素材,拿到资源,控制渲染器引用 public void Awake()//属性等在awake中赋值,一开始就拿到 { sr = GetComponent<SpriteRenderer>(); } // Start is called before the first frame update void Start() { } // Update is called once per frame void Update() { //是否处于无敌状态 if(isDefended) { defendEffectPrefab.SetActive(true); defendTimeVal -= Time.deltaTime; if(defendTimeVal<=0) { isDefended = false; defendEffectPrefab.SetActive(false); } } } private void FixedUpdate()//固定物理帧,规定占用时间固定 { if(PlayerManager.Instance.isDefeated) { return; } Move(); if(timeVal>=0.4f) { Attack(); } else { timeVal += Time.fixedDeltaTime; } } private void Attack() { if(Input.GetKeyDown(KeyCode.Space)) { //2D游戏旋转方向与3D相反 Instantiate(bulletPrefab,transform.position,Quaternion.Euler(transform.eulerAngles+bulletEulerAngles));//最后一个参数:欧拉角转变成四元数 timeVal = 0; } } //坦克移动 private void Move() { float h = Input.GetAxisRaw("Horizontal");//h和v值为1或-1 transform.Translate(Vector3.right * h * moveSpeed * Time.fixedDeltaTime,Space.World); //改变转向:1.更换不同图片 2.直接改变图片转向 if(h<0) { sr.sprite = tankSprite[3]; bulletEulerAngles =new Vector3(0,0,90); } else if(h>0) { sr.sprite = tankSprite[1]; bulletEulerAngles =new Vector3(0,0,-90); } if(Mathf.Abs(h)>0.05f) { moveAudio.clip = tankAudio[1]; if(!moveAudio.isPlaying) { moveAudio.Play(); } } if(h!=0)//设置优先级,横向优先 { return; } float v = Input.GetAxisRaw("Vertical"); transform.Translate(Vector3.up * v * moveSpeed * Time.fixedDeltaTime,Space.World); if(v<0) { sr.sprite = tankSprite[2]; bulletEulerAngles =new Vector3(0,0,180); } else if(v>0) { sr.sprite = tankSprite[0]; bulletEulerAngles =new Vector3(0,0,0); } if(Mathf.Abs(v)>0.05f) { moveAudio.clip = tankAudio[1]; if(!moveAudio.isPlaying) { moveAudio.Play(); } }else{ moveAudio.clip = tankAudio[0]; if(!moveAudio.isPlaying) { moveAudio.Play(); } } } public void Die() { if(isDefended) { return; } PlayerManager.Instance.isDead = true; //爆炸特效 Instantiate(explosionPrefab,transform.position, transform.rotation); //坦克死亡 Destroy(gameObject); } }炸弹脚本
public class Bullet : MonoBehaviour { public float moveSpeed=10; public bool isPlayerBullet;//不设置默认为false public AudioClip hitAudio; // Start is called before the first frame update void Start() { } // Update is called once per frame void Update() { //Translate的第一个参数是沿着世界坐标移动时最后一个参数可写可不写,默认世界坐标 //沿着自身坐标移动时,最后一个参数一定要写 transform.Translate(transform.up * moveSpeed * Time.deltaTime, Space.World); } private void OnTriggerEnter2D(Collider2D collision) { switch(collision.tag) { case "Tank": if(!isPlayerBullet) { collision.SendMessage("Die"); Destroy(gameObject); } break; case "Heart": collision.SendMessage("Die"); Destroy(gameObject); break; case "Enemy": if(isPlayerBullet) { collision.SendMessage("Die"); Destroy(gameObject);//销毁自身 } break; case "Wall": if(isPlayerBullet) { PlayAudio(); } Destroy(collision.gameObject); Destroy(gameObject);//销毁墙和炮弹本身 break; case "Barrier": if(isPlayerBullet) { PlayAudio(); } Destroy(gameObject); break; default: break; } } public void PlayAudio() { AudioSource.PlayClipAtPoint(hitAudio,transform.position); } }首页面选择单人/双人游戏
攻击敌人
显示攻击敌人的数量和剩余生命值
游戏失败
保存并命名场景-find-Build Settings-Build-选择打包到的目录。
踩坑:
UnityError.BuildPlayerWindow+BuildMaethodException:2 errors
解决方法:
选择打包目录时创建一个空文件夹存放。
字体显示模糊