物理向的小遊戲,首先我們需要知道這個組件:SpringJoint,也就是2D彈簧組件,很有意思的組件,做UI的時候可以用來實現那種繩子吊着木牌懸掛的感覺。
這是這個小遊戲實現的核心之一。
哦,對了,還有這個組件:LineRender組件,也就是劃線的組件,其實主要就是用到了它的setPosition方法。
知道了這些後,看下實現效果:
細心可以發現,這裏麪包含了,“豬的死亡”,“鳥的發射”,“換鳥操作”,還有遊戲輸贏邏輯判斷。
小鳥身上的腳本:主要是控制我們彈弓的劃線,和小鳥自身的遊戲飛出
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/*
作者:王祥瑞
*/
namespace JumpAgent
{
public class Birds : MonoBehaviour
{
private bool isClick = false;
public bool isFlyed = false;
public float maxDistance = 3.0f;
private SpringJoint2D sp;
private Rigidbody2D rb;
//劃線
public LineRenderer right;
public LineRenderer left;
public Transform leftPos;
public Transform rightPos;
public SpringJoint2D Sp
{
get
{
return sp;
}
set
{
sp = value;
}
}
public Rigidbody2D Rb
{
get
{
return rb;
}
set
{
rb = value;
}
}
private void Awake()
{
sp = this.GetComponent<SpringJoint2D>();
rb = this.GetComponent<Rigidbody2D>();
sp.enabled = false;//禁用bird身上的這個組件,要不然一開始所有的小鳥都會飛到彈弓上去
}
private void OnMouseDown()
{
isClick = true;
//鼠標擡起的時候禁用劃線組件
right.enabled = true;
left.enabled = true;
rb.isKinematic = true;
}
private void OnMouseUp()
{
isClick = false;
rb.isKinematic = false;
isFlyed = true;
Invoke("fly", 0.1f);
//鼠標擡起的時候禁用劃線組件
right.enabled = false;
left.enabled = false;
}
void Update()
{
if (isClick)
{
transform.position = Camera.main.ScreenToWorldPoint(Input.mousePosition);
transform.position += new Vector3(0, 0, -Camera.main.transform.position.z);
if (Vector3.Distance(transform.position, rightPos.position) > maxDistance)
{
Vector3 offset = (transform.position - rightPos.position).normalized;
offset *= maxDistance;
transform.position = offset + rightPos.position;
}
LineRender();
}
}
/// <summary>
/// 控制小鳥飛翔
/// </summary>
private void fly()
{
sp.enabled = false;
}
/// <summary>
/// 劃線的實現
/// </summary>
private void LineRender()
{
right.SetPosition(0, rightPos.position);
right.SetPosition(1, transform.position);
left.SetPosition(0, leftPos.position);
left.SetPosition(1, transform.position);
}
/// <summary>
/// 這裏我沒有采用直接銷燬遊戲物體,取而代之的是將其隱藏起來.
/// </summary>
public void Dohidethis()
{
Invoke("hidethis", 5f);
}
public void hidethis()
{
this.gameObject.SetActive(false);
}
}//類
}//命名空間
然後是豬(障礙物)的腳本:
這個豬的腳本主要是控制豬的受傷(根據碰撞時的速度來判斷傷害,傷害處理機制,我封裝了一個腳本),其實這個豬的腳本可以泛用的,比如就是說可以用到我們的障礙物身上,小鳥撞擊障礙物,會進行同樣的傷害判定,還可以通過修改不同障礙物的生命值來控制實現不同障礙物的不同特性,不過在這裏我並沒有進行泛用,雖說可以泛用,但是隻是95%代碼一樣,豬比障礙物多了個死亡沒死亡的bool判斷值,這在下面的GameManager腳本里解釋。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/*
作者:王祥瑞
*/
namespace JumpAgent
{
public class Pig : MonoBehaviour
{
private float maxSpeed = 10;//碰撞最大速度
private float minSpeed = 3;//碰撞最小速度
[SerializeField]
private float hp = 100;
public GameObject Bloom;
public GameObject[] ScorePrefab;//頭頂分數
private SpriteRenderer spriteRenderer;
public Sprite[] sp;//存放不同級別的受損圖片,不過一般這遊戲就是一張受損
public bool isPigDead = false;//豬是不是死了
private void Awake()
{
spriteRenderer = this.GetComponent<SpriteRenderer>();
}
//豬(障礙物)與鳥的碰撞檢測,
private void OnCollisionEnter2D(Collision2D collision)
{
if (collision.relativeVelocity.magnitude > maxSpeed && collision.gameObject.tag == "Player")
{
float damage = (collision.relativeVelocity.magnitude * 10f);
PigDeathJudge(damage);
collision.gameObject.GetComponent<Birds>().Dohidethis();
}
if (collision.relativeVelocity.magnitude > minSpeed && collision.relativeVelocity.magnitude < maxSpeed)
{
if (!isPigDead)
{
float damage = (collision.relativeVelocity.magnitude * 10f);
PigDeathJudge(damage);
collision.gameObject.GetComponent<Birds>().Dohidethis();
}
}
}
//豬的傷害判定腳本
private void PigDeathJudge(float damage)
{
hp -= damage;
if (hp <= 0)
{
isPigDead = true;
GameObject temp = Instantiate(ScorePrefab[0], new Vector3(transform.position.x, (this.transform.position.y + 1f), this.transform.position.z), Quaternion.identity);
temp.SetActive(true);
this.spriteRenderer.color = Color.clear;
Bloom.SetActive(true);
Invoke("PigDestory", 0.467f);
}
if (hp <= 50 && hp > 0)
{
spriteRenderer.sprite = sp[0];
}
}
private void PigDestory()
{
this.gameObject.SetActive(false);
}
}//類
}//命名空間
然後是我們的遊戲核心邏輯代碼了:
裏面有:換鳥操作,和兩個分別管理豬,鳥的集合,也就是說我們判斷輸贏,就只需要維護我們的這兩個集合就好啦。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
/*
作者:王祥瑞
*/
namespace JumpAgent
{
public class GameManager : MonoBehaviour
{
public List<Birds> birds;
public List<Pig> pigs;
public GameObject win;
public GameObject lose;
public static GameManager _instance;
private void Awake()
{
_instance = this;
birds = new List<Birds>();
pigs = new List<Pig>();
}
private void Start()
{
AllFindPigAndBird();//初始化好所有的豬和鳥
BirdsAlternate();//換上第一隻鳥
StartCoroutine("GameWinOrLoseJudgment");//開始遊戲邏輯
}
/// <summary>
/// 遊戲輸贏判斷
/// </summary>
/// <returns></returns>
private IEnumerator GameWinOrLoseJudgment()
{
int pigAliveCount = 0;
int birdFlyedCount = 0;
while (true)
{
yield return new WaitForSeconds(3);
//遍豬的數組,如果豬的狀態都爲Dead,則遊戲勝利
foreach (Pig item in pigs)
{
if (!item.isPigDead)
{
pigAliveCount++;
}
}
// Debug.Log("現在豬的數量爲:" + pigAliveCount);
if (pigAliveCount == 0)
{
Debug.Log("遊戲勝利");
//TODO:遊戲勝利的邏輯
win.SetActive(true);
Time.timeScale = 0;
}
else//反之則開始判斷小鳥的飛出數量
{
pigAliveCount = 0;
}
//在這裏可以考慮一下延時
yield return new WaitForSeconds(1);
//遍歷小鳥數組,如果小鳥飛出的數量等於小鳥原來集合的Count的話
foreach (Birds item in birds)
{
if (item.isFlyed)
{
birdFlyedCount++;
}
}
Debug.Log("小鳥數量爲" + (birds.Count - birdFlyedCount) + "/" + birds.Count);
if ((birds.Count - birdFlyedCount) == 0)//如果剩餘的小鳥數量(所有鳥的數量減去已經飛出的小鳥的數量==0)
{
Debug.Log("遊戲失敗");
//TODO:遊戲失敗的邏輯
lose.SetActive(true);
}
else//反之則爲遊戲進行中
{
birdFlyedCount = 0;
BirdsAlternate();//調用換鳥
}
}
}
/// <summary>
/// 換鳥操作
/// </summary>
public void BirdsAlternate()
{
//本質上就是遍歷鳥的集合,逐次的打開小鳥身上相對應的組件
for (int i = 0; i < birds.Count; i++)
{
if (!birds[i].isFlyed)
{
birds[i].transform.position = new Vector3(-6.5f, -1.8f, 0);
birds[i].enabled = true;
birds[i].Sp.enabled = true;
break;
}
}
}
/// <summary>
/// 初始化豬和鳥的集合
/// </summary>
public void AllFindPigAndBird()
{
GameObject[] GObird = GameObject.FindGameObjectsWithTag("Player");
GameObject[] GOpig = GameObject.FindGameObjectsWithTag("Enemy");
for (int i = 0; i < GObird.Length; i++)
{
birds.Add(GObird[i].GetComponent<Birds>());
}
for (int i = 0; i < GOpig.Length; i++)
{
pigs.Add(GOpig[i].GetComponent<Pig>());
}
//把小鳥的birds組件都先禁用
for (int i = 0; i < birds.Count; i++)
{
birds[i].enabled = false;
}
}
}//類
}//命名空間
然後是多關卡的實現,這裏說下實現思路:
首先我們不能就是說,有多少關就做多少個場景,然後在選關界面做一堆Button,然後點哪個就跳哪個場景,那樣是不可取的,除去會讓遊戲變得很大之外,而且如果那樣的話,上面寫的這堆自動判斷輸贏,自動查找鳥和豬以及自動換鳥的這些操作就沒有任何意義了。
那麼該如何實現呢?我們要做的僅僅是做出不同的障礙物組合,然後把他們放到prefabs文件夾,然後根據每個關卡(爲每個關卡設置枚舉)的枚舉數,來在地圖相應的位置(位置要先定義好)來加載你需要的鳥和障礙物即可,只要你把你需要的障礙物和鳥加到遊戲場景中,遊戲就會自動運行。