开发软件: unity3d 、 vs2017
游戏简介: 在3D模式下开发的2D游戏,使用UGUI进行场景搭建,适合有一定unity基础的同学学习制作
●首先放上完成的图
●然后再放上主要功能的代码
控制枪的行为
using UnityEngine;
public class GunFollow : MonoBehaviour
{
public RectTransform UGUICanvas;
public Camera mainCamera;
void Update()
{
Vector3 mousePos;
RectTransformUtility.ScreenPointToWorldPointInRectangle(UGUICanvas, new Vector2
(Input.mousePosition.x, Input.mousePosition.y), mainCamera, out mousePos);
float z;
if (mousePos.x > transform.position.x)
{
z = -Vector3.Angle(Vector3.up, mousePos - transform.position);
}
else
{
z = Vector3.Angle(Vector3.up, mousePos - transform.position);
}
transform.localRotation = Quaternion.Euler(0, 0, z);
}
}
生成鱼及控制鱼的行为
using UnityEngine;
using System.Collections;
public class FishMaker : MonoBehaviour
{
public Transform fishHolder;
public Transform[] genPositions;
public GameObject[] fishPrefabs;
public float fishGenWaitTime = 0.5f;
public float waveGenWaitTime = 0.3f;
void Start()
{
InvokeRepeating("MakeFishes", 0, waveGenWaitTime);
}
void MakeFishes()
{
int genPosIndex = Random.Range(0, genPositions.Length);
int fishPreIndex = Random.Range(0, fishPrefabs.Length);
int maxNum = fishPrefabs[fishPreIndex].GetComponent().maxNum;
int maxSpeed = fishPrefabs[fishPreIndex].GetComponent().maxSpeed;
int num = Random.Range((maxNum / 2) + 1, maxNum);
int speed = Random.Range(maxSpeed / 2, maxSpeed);
int moveType = Random.Range(0, 2); //0:直走;1:转弯
int angOffset; //仅直走生效,直走的倾斜角
int angSpeed; //仅转弯生效,转弯的角速度
if (moveType == 0)
{
angOffset = Random.Range(-22, 22);
StartCoroutine(GenStraightFish(genPosIndex, fishPreIndex, num, speed, angOffset));
}
else
{
if (Random.Range(0, 2) == 0) //是否取负的角速度
{
angSpeed = Random.Range(-15, -9);
}
else
{
angSpeed = Random.Range(9, 15);
}
StartCoroutine(GenTrunFish(genPosIndex, fishPreIndex, num, speed, angSpeed));
}
}
IEnumerator GenStraightFish(int genPosIndex,int fishPreIndex,int num,int speed,int angOffset)
{
for (int i = 0; i < num; i++)
{
GameObject fish = Instantiate(fishPrefabs[fishPreIndex]);
fish.transform.SetParent(fishHolder, false);
fish.transform.localPosition = genPositions[genPosIndex].localPosition;
fish.transform.localRotation = genPositions[genPosIndex].localRotation;
fish.transform.Rotate(0, 0, angOffset);
fish.GetComponent().sortingOrder += i;
fish.AddComponent().speed = speed;
yield return new WaitForSeconds(fishGenWaitTime);
}
}
IEnumerator GenTrunFish(int genPosIndex, int fishPreIndex, int num, int speed, int angSpeed)
{
for (int i = 0; i < num; i++)
{
GameObject fish = Instantiate(fishPrefabs[fishPreIndex]);
fish.transform.SetParent(fishHolder, false);
fish.transform.localPosition = genPositions[genPosIndex].localPosition;
fish.transform.localRotation = genPositions[genPosIndex].localRotation;
fish.GetComponent().sortingOrder += i;
fish.AddComponent().speed = speed;
fish.AddComponent().speed = angSpeed;
yield return new WaitForSeconds(fishGenWaitTime);
}
}
}
鱼被打的结果
using UnityEngine;
public class FishAttr : MonoBehaviour
{
public int hp;
public int exp;
public int gold;
public int maxNum;
public int maxSpeed;
public GameObject diePrefab;
public GameObject goldPrefab;
private void OnTriggerEnter2D(Collider2D collision)
{
if (collision.tag == "Border")
{
Destroy(gameObject);
}
}
void TakeDamage(int value)
{
hp -= value;
if (hp <= 0)
{
GameController.Instance.gold += gold;
GameController.Instance.exp += exp;
GameObject die = Instantiate(diePrefab);
die.transform.SetParent(gameObject.transform.parent, false);
die.transform.position = transform.position;
die.transform.rotation = transform.rotation;
GameObject goldGo = Instantiate(goldPrefab);
goldGo.transform.SetParent(gameObject.transform.parent, false);
goldGo.transform.position = transform.position;
goldGo.transform.rotation = transform.rotation;
if (gameObject.GetComponent() != null)
{
AudioManager.Instance.PlayEffectSound(AudioManager.Instance.rewardClip);
gameObject.GetComponent().PlayEffect();
}
Destroy(gameObject);
}
}
}
子弹发射事件
using UnityEngine;
public class BulletAttr : MonoBehaviour
{
public int speed;
public int damage;
public GameObject webPrefab;
private void OnTriggerEnter2D(Collider2D collision)
{
if (collision.tag == "Border")
{
Destroy(gameObject);
}
if (collision.tag == "Fish")
{
GameObject web = Instantiate(webPrefab);
web.transform.SetParent(gameObject.transform.parent, false);
web.transform.position = gameObject.transform.position;
web.GetComponent().damage = damage;
Destroy(gameObject);
}
}
}
游戏主控制
using System.Collections;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
public class GameController : MonoBehaviour
{
private static GameController _instance;
public static GameController Instance
{
get
{
return _instance;
}
}
public Text oneShootCostText;
public Text goldText;
public Text lvText;
public Text lvNameText;
public Text smallCountdownText;
public Text bigCountdownText;
public Button bigCountdownButton;
public Button backButton;
public Button settingButton;
public Slider expSlider;
public int lv = 0;
public int exp = 0;
public int gold = 500;
public const int bigCountdown = 240;
public const int smallCountdown = 60;
public float bigTimer = bigCountdown;
public float smallTimer = smallCountdown;
public Color goldColor;
public int bgIndex = 0;
public Image bgImage;
public GameObject lvUpTips;
public GameObject seaWaveEffect;
public GameObject fireEffect;
public GameObject changeEffect;
public GameObject lvEffect;
public GameObject goldEffect;
public Transform bulletHolder;
public Sprite[] bgSprites;
public GameObject[] gunGos;
public GameObject[] bullet1Gos;
public GameObject[] bullet2Gos;
public GameObject[] bullet3Gos;
public GameObject[] bullet4Gos;
public GameObject[] bullet5Gos;
//使用的是第几档的炮弹
private int costIndex = 0;
//每一炮所需的金币数和造成的伤害值
private int[] oneShootCosts = { 5, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000 };
private string[] lvName = { "新手", "入门", "钢铁", "青铜", "白银", "黄金", "白金", "钻石", "大师", "宗师" };
void Awake()
{
_instance = this;
}
void Start()
{
gold = PlayerPrefs.GetInt("gold", gold);
lv = PlayerPrefs.GetInt("lv", lv);
exp = PlayerPrefs.GetInt("exp", exp);
smallTimer = PlayerPrefs.GetFloat("scd", smallCountdown);
bigTimer = PlayerPrefs.GetFloat("bcd", bigCountdown);
UpdateUI();
}
void Update()
{
ChangeBulletCost();
Fire();
UpdateUI();
ChangeBg();
}
void ChangeBg()
{
if (bgIndex != lv / 20)
{
bgIndex = lv / 20;
AudioManager.Instance.PlayEffectSound(AudioManager.Instance.seaWaveClip);
Instantiate(seaWaveEffect);
if (bgIndex >= 3)
{
bgImage.sprite = bgSprites[3];
}
else
{
bgImage.sprite = bgSprites[bgIndex];
}
}
}
void UpdateUI()
{
bigTimer -= Time.deltaTime;
smallTimer -= Time.deltaTime;
if (smallTimer <= 0)
{
smallTimer = smallCountdown;
gold += 50;
}
if (bigTimer <= 0 && bigCountdownButton.gameObject.activeSelf == false)
{
bigCountdownText.gameObject.SetActive(false);
bigCountdownButton.gameObject.SetActive(true);
}
//经验等级换算公式:升级所需经验=1000+200*当前等级
while (exp >= 1000 + 200 * lv)
{
exp = exp - (1000 + 200 * lv);
lv++;
lvUpTips.SetActive(true);
lvUpTips.transform.Find("Text").GetComponent().text = lv.ToString();
StartCoroutine(lvUpTips.GetComponent().HideSelf(0.6f));
AudioManager.Instance.PlayEffectSound(AudioManager.Instance.lvUpClip);
Instantiate(lvEffect);
}
goldText.text = "$" + gold;
lvText.text = lv.ToString();
if ((lv / 10) <= 9)
{
lvNameText.text = lvName[lv / 10];
}
else
{
lvNameText.text = lvName[9];
}
smallCountdownText.text = " " + (int)smallTimer / 10 + " " + (int)smallTimer % 10;
bigCountdownText.text = (int)bigTimer + "s";
expSlider.value = ((float)exp) / (1000 + 200 * lv);
}
void Fire()
{
GameObject[] useBullets = bullet5Gos;
int bulletIndex;
if (Input.GetMouseButtonDown(0) && EventSystem.current.IsPointerOverGameObject() == false)
{
if (gold - oneShootCosts[costIndex] >= 0)
{
switch (costIndex / 4)
{
case 0: useBullets = bullet1Gos; break;
case 1: useBullets = bullet2Gos; break;
case 2: useBullets = bullet3Gos; break;
case 3: useBullets = bullet4Gos; break;
case 4: useBullets = bullet5Gos; break;
}
bulletIndex = (lv % 10 >= 9) ? 9 : lv % 10;
gold -= oneShootCosts[costIndex];
AudioManager.Instance.PlayEffectSound(AudioManager.Instance.fireClip);
Instantiate(fireEffect);
GameObject bullet = Instantiate(useBullets[bulletIndex]);
bullet.transform.SetParent(bulletHolder, false);
bullet.transform.position = gunGos[costIndex / 4].transform.Find("FirePos").transform.position;
bullet.transform.rotation = gunGos[costIndex / 4].transform.Find("FirePos").transform.rotation;
bullet.GetComponent().damage = oneShootCosts[costIndex];
bullet.AddComponent().dir = Vector3.up;
bullet.GetComponent().speed = bullet.GetComponent().speed;
}
else
{
StartCoroutine(GoldNotEnough());
}
}
}
void ChangeBulletCost()
{
if (Input.GetAxis("Mouse ScrollWheel") < 0)
{
OnButtonMDown();
}
if (Input.GetAxis("Mouse ScrollWheel") > 0)
{
OnButtonPDown();
}
}
public void OnButtonPDown()
{
gunGos[costIndex / 4].SetActive(false);
costIndex++;
AudioManager.Instance.PlayEffectSound(AudioManager.Instance.changeClip);
Instantiate(changeEffect);
costIndex = (costIndex > oneShootCosts.Length - 1) ? 0 : costIndex;
gunGos[costIndex / 4].SetActive(true);
oneShootCostText.text = "$" + oneShootCosts[costIndex];
}
public void OnButtonMDown()
{
gunGos[costIndex / 4].SetActive(false);
costIndex--;
AudioManager.Instance.PlayEffectSound(AudioManager.Instance.changeClip);
Instantiate(changeEffect);
costIndex = (costIndex < 0) ? oneShootCosts.Length - 1 : costIndex;
gunGos[costIndex / 4].SetActive(true);
oneShootCostText.text = "$" + oneShootCosts[costIndex];
}
public void OnBigCountdownButtonDown()
{
gold += 500;
AudioManager.Instance.PlayEffectSound(AudioManager.Instance.rewardClip);
Instantiate(goldEffect);
bigCountdownButton.gameObject.SetActive(false);
bigCountdownText.gameObject.SetActive(true);
bigTimer = bigCountdown;
}
IEnumerator GoldNotEnough()
{
goldText.color = goldColor;
goldText.color = Color.red;
yield return new WaitForSeconds(0.5f);
goldText.color = goldColor;
}
}
音效控制
using UnityEngine;
public class AudioManager : MonoBehaviour
{
private static AudioManager _instance;
public static AudioManager Instance
{
get
{
return _instance;
}
}
private bool isMute = false;
public bool IsMute
{
get
{
return isMute;
}
}
public AudioSource bgmAudioSource;
public AudioClip seaWaveClip;
public AudioClip goldClip;
public AudioClip rewardClip;
public AudioClip fireClip;
public AudioClip changeClip;
public AudioClip lvUpClip;
void Awake()
{
_instance = this;
isMute = (PlayerPrefs.GetInt("mute", 0) == 0) ? false : true;
DoMute();
}
public void SwitchMuteState(bool isOn)
{
isMute = !isOn;
DoMute();
}
void DoMute()
{
if (isMute)
{
bgmAudioSource.Pause();
}
else
{
bgmAudioSource.Play();
}
}
public void PlayEffectSound(AudioClip clip)
{
if (!isMute)
{
AudioSource.PlayClipAtPoint(clip, new Vector3(0, 0, -5));
}
}
}
还有一些简单的代码就不一一贴出来了,然后说明一下游戏素材是在siki学院下载的,制作教程那里也有,然后再附上游戏完整项目链接:https://pan.baidu.com/s/1yoyPGTIjH9IgHwr32jlJvQ 提取码:c336
PC版exe程序:https://pan.baidu.com/s/1zDhr_0BIym7J7c2a46nl7Q 提取码:wumu
**最后再总结一下:**学习U3D也快三个月了,这是自己第一个真正完整的游戏作品,从一开始的怎样搭建游戏场景到代码编写挂载等到游戏成功按预期运行,每解决一个bug都能感受到自己的进步,同时学习的越多却越发觉得学的还不够多,是啊,本来做程序就是个不断学习的事,所以,如果想在程序上走的更远,一定不要停下你学习的脚步,共勉。