概述
经过不到一周的学习,制作完成了太空大战,游戏虽然简陋,但是在制作的过程中学习到了hin多的知识
游戏截图:
游戏源码:
1.player
//player.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//可以自定义脚本在菜单栏中的位置
[AddComponentMenu("脚本/MyGame/Player")]
public class Player : MonoBehaviour {
//定义飞船的生命值
public float HP = 100;
//定义飞船移动的速度
public float movespeed = 6f;
//获取子弹的预构体
public Transform rocket;
//子弹的发射计时器
public float rocketTimer;
//加载声音,从面板拖入到当前脚本组件上来添加
public AudioClip m_shootClip;
//声音源组件,用于播放声音
protected AudioSource m_audio;
//爆炸特效
//注意爆炸特效是一个预构体,需要用Transform的类接受
public Transform m_explosionFX;
//定义目标位置
// protected Vector3 m_targetPOS;
//鼠标射线碰撞层
// public LayerMask m_inputMask;
void Start () {
//在初始化的时候获取音效组件
m_audio = this.GetComponent<AudioSource>();
//m_targetPOS = this.transform.position;
}
void Update () {
//MoveTo();
//每次进行刷新的时候的移动侦测
//在每次都先重置位置
float movex = 0;
float movez = 0;
//上下左右移动
if (Input.GetKey(KeyCode.W))
{
//上
movez -= movespeed * Time.deltaTime;
}
if (Input.GetKey(KeyCode.S))
{
//下
movez += movespeed * Time.deltaTime;
}
if (Input.GetKey(KeyCode.A))
{
//左
movex += movespeed * Time.deltaTime;
}
if (Input.GetKey(KeyCode.D))
{
//右
movex -= movespeed * Time.deltaTime;
}
//移动
transform.Translate(new Vector3(movex, 0f, movez));
//发射子弹
//if (Input.GetMouseButton(0))
//{
// Instantiate(rocket, transform.position, transform.rotation);
//}
//连续发射的太快,于是要修改发射频率
rocketTimer -= Time.deltaTime;
if (rocketTimer<=0)
{
rocketTimer = 0.1f;
if (Input.GetMouseButton(0))
{
//实例化rocket的prefab
Instantiate(rocket, transform.position, transform.rotation);
//在实例化之后还可以加上声音
m_audio.PlayOneShot(m_shootClip);
}
}
}
//碰撞器
//一定要注意 碰撞器一定要和刚体组件一起使用
void OnTriggerEnter(Collider other)
{
//定义主角在发生碰撞时的事件
if (other.tag.CompareTo("PlayerRocket")!=0)
{
if (other.tag.CompareTo("Enemy")==0)
{
HP -= 5;
}
else if(other.tag.CompareTo("SuperEnemy")==0)
{
HP -= 15;
}
else if (other.tag.CompareTo("EnemyRocket")==0)
{
HP -= other.GetComponent<Enemy_rocket>().damage;
}
//在UI中显示更改后的生命
GameManager.Instance.HP_display(HP);
if (HP <= 0)
{
//在销毁之前添加爆炸特效,使用实例化来添加特效
//Quaternion.identity就是不作旋转
Instantiate(m_explosionFX, transform.position,Quaternion.identity);
Destroy(this.gameObject);
}
}
}
//获取鼠标射线
//void MoveTo()
//{
// if (Input.GetMouseButton(0))
// {
// Vector3 ms = Input.mousePosition;
// Ray ray1 = Camera.main.ScreenPointToRay(ms);
// RaycastHit hitinfo;
// bool iscast = Physics.Raycast(ray1, out hitinfo, 1000, m_inputMask);
// if (iscast)
// {
// //如果射中目标,记录射线碰撞点
// m_targetPOS = hitinfo.point;
// }
// //使用Vector3向量提供的MoveTowards函数,获取朝目标移动的位置
// Vector3 pos = Vector3.MoveTowards(transform.position, m_targetPOS, 5*movespeed * Time.deltaTime);
// //更新位置
// this.transform.position = pos;
// }
//}
}
2.rocket
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[AddComponentMenu("脚本/MyGame/Rocket")]
public class rocket : MonoBehaviour {
//定义子弹的属性
public float movespeed = 10f;
public float livetime = 1;
public float damage = 10f;
void Start () {
Destroy(gameObject, livetime);
}
void Update () {
transform.Translate(new Vector3(0,0, -movespeed * Time.deltaTime));
}
//一定要注意 碰撞器一定要和刚体组件一起使用
private void OnTriggerEnter(Collider other)
{
if (other.tag.CompareTo("Enemy")==0 || other.tag.CompareTo("SuperEnemy")==0)
{
Destroy(this.gameObject);
}
}
}
3.Enemy_rocket
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[AddComponentMenu("脚本/MyGame/Enemy_rocket")]
public class Enemy_rocket : rocket {
private void OnTriggerEnter(Collider other)
{
if (other.tag.CompareTo("Player") != 0)
{
//print("不是玩家");
return;
}
// print("是玩家");
Destroy(this.gameObject);
}
}
4.Enemy
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[AddComponentMenu("脚本/MyGame/Enemy")]
public class Enemy : MonoBehaviour {
//初级敌人的一些参数
public float movespeed;
public float HP;
private int enemypoint=2;
public Transform m_explosionFX;
void Start () {
renderer1 = this.GetComponent<Renderer>();
}
//刷新中进行的操作
void Update () {
UpdateMove();
//每一帧都侦测是否移动到了屏幕外部
if (isActiv && !this.renderer1.isVisible)
{
Destroy(this.gameObject);
}
//让敌人旋转
//transform.Rotate(new Vector3(0,transform.position.y,0), SpinAngle);
}
//为了将来的扩展功能,将UpdateMove写成一个虚函数,继承使用的时候更改更加方便
protected virtual void UpdateMove()
{
//随事件变化的左右随机移动
float rx = Mathf.Sin(Time.time) * Time.deltaTime;
//前进和左右随机移动共同呈现了敌人的移动
transform.Translate(new Vector3(movespeed * Time.deltaTime, 0,rx ));
}
//一定要注意 碰撞器一定要和刚体组件一起使用
private void OnTriggerEnter(Collider other)
{
//如果敌人撞到子弹
if (other.tag.CompareTo("PlayerRocket")==0)
{
rocket rocket = other.GetComponent<rocket>();
if (HP!=0)
{
HP -= rocket.damage;
if (HP<=0)
{
Destroy(this.gameObject);
Instantiate(m_explosionFX, transform.position, Quaternion.identity);
//如果死亡,就传给GameManager相应增加分数的函数score_up应该增加的函数
GameManager.Instance.score_up(enemypoint);
}
}
}
//如果敌人撞到主角
else if (other.tag.CompareTo("Player")==0)
{
HP = 0;
Destroy(this.gameObject);
Instantiate(m_explosionFX, transform.position, Quaternion.identity);
}
}
//侦测是否进入屏幕,并且进行操作
//首先要定义两个组件
//1.在初始化Update中获得模型渲染组件renderer
internal Renderer renderer1;
//2.决定是否激活的组件
internal bool isActiv = false;
private void OnBecameVisible()
{
isActiv = true;
}
}
5.SuperEnemy
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[AddComponentMenu("脚本/MyGame/SuperEnemy")]
public class SuperEnemy : Enemy
{
//模型旋转角度
public float SpinAngle;
private int enemypoint_super = 7;
//获取音效资源
public AudioClip m_audioClip;
//获取音效组件
protected AudioSource m_audio;
//获取敌人子弹的预构体
public Transform Enemy_rocket;
protected float ShootTime = 2f;
//出生的时候查找主角
protected Transform player;
private void Awake()
{
GameObject gameObject = GameObject.Find("Player");
if (gameObject != null)
{
//获取主角的位置
player = gameObject.transform;
}
//注意在初始化的时候记得获取音效组件
m_audio = GetComponent<AudioSource>();
}
//重新定义移动
protected override void UpdateMove()
{
ShootTime -= Time.deltaTime;
//射击时间间隔为2s
if (ShootTime <= 0)
{
ShootTime = 2;
if (player != null)
{
//使用向量计算子弹在飞出时的朝向---向量减法
Vector3 relativePOS = transform.position - player.position;
//实例化敌人子弹并且设定朝向为玩家方向
Instantiate(Enemy_rocket, this.transform.position, Quaternion.LookRotation(relativePOS));
//实例化后可以输出射击音效
m_audio.PlayOneShot(m_audioClip);
}
}
//自身不断向前移动
transform.Translate(new Vector3(0, 0,-movespeed * Time.deltaTime));
}
//重写高级敌人撞到子弹的判断函数
private void OnTriggerEnter(Collider other)
{
//如果敌人撞到子弹
if (other.tag.CompareTo("PlayerRocket") == 0)
{
rocket rocket = other.GetComponent<rocket>();
if (HP != 0)
{
HP -= rocket.damage;
if (HP <= 0)
{
Destroy(this.gameObject);
Instantiate(m_explosionFX, transform.position, Quaternion.identity);
//如果死亡,就传给GameManager相应增加分数的函数score_up应该增加的函数
GameManager.Instance.score_up(enemypoint_super);
}
}
}
//如果敌人撞到主角
else if (other.tag.CompareTo("Player") == 0)
{
HP = 0;
Destroy(this.gameObject);
Instantiate(m_explosionFX, transform.position, Quaternion.identity);
}
}
}
6.EnemySpawn (敌人生成器)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[AddComponentMenu("脚本/MyGame/EnemySpawn")]
public class EnemySpawn : MonoBehaviour {
//需要调用协程
//IEnumerator是协程函数的标识符,它的功能有些类似线程
//注意将敌人生成器制作成两个,一个是普通敌人,另一个是高级敌人,但是两者的脚本一样
//获取敌人的预构体
public Transform m_enemy;
void Start () {
//初始化的时候调用协程
StartCoroutine(SpawnEnemy());
}
IEnumerator SpawnEnemy ()
{
//协程一定要有yield return 返回
yield return new WaitForSeconds(Random.Range(5f, 30f));
//在生成器的位置实例化一个个敌人
//使用协程可以在不堵塞主线程的情况下,让函数进行等待,每隔几秒创建一个敌人,然后循环这个过程
//调用协程函数一定要使用 StartCoroutine(协程函数()) 函数
Instantiate(m_enemy, transform.position, transform.rotation);
//循环进行协程操作,不断产生敌人
StartCoroutine(SpawnEnemy());
}
//用来显示敌人生成器图标的函数,这样方便摆放和设置
private void OnDrawGizmos()
{
Gizmos.DrawIcon(transform.position,"item.png",true);
}
}
7.GameManager
using System.Collections;
using System.Collections.Generic;
//需要调用Unity中的UI类库
using UnityEngine.UI;
//切换场景需要调用Unity中的SceneManagement类库
using UnityEngine.SceneManagement;
using UnityEngine;
[AddComponentMenu("脚本/MyGame/GameManager")]
public class GameManager : MonoBehaviour {
//静态实例,保存这个组件到instance中,这样所有的脚本都可以通过GameManager这个类来访问他
//在Start函数中指向自身,这样可以方便在其他类的对象中引用 GameManager 实例
//这种做法通常只用于只有一个游戏对象的时候
public static GameManager Instance;
//显示分数的UI界面
public Transform m_canvas_main;
//显示游戏失败的游戏界面
public Transform m_canvas_gameover;
//得分UI文字
public Text m_text_score;
//最高分UI文字
public Text m_text_best;
//生命UI文字
public Text m_text_HP;
//游戏得分
protected int m_score=0;
//最高分
public static int m_bestscore=0;
//游戏主角
protected Player m_player;
//背景音乐
public AudioClip m_background_music;
//背景音乐声音源
public AudioSource m_background_source;
void Start () {
//获取实例
Instance = this;
//使用代码来添加音效组件
m_background_source = this.gameObject.AddComponent<AudioSource>();
m_background_source.clip = m_background_music;
m_background_source.loop = true;
m_background_source.Play();
//获取主角
//这里获取的Player组件是 Player脚本组件
m_player = GameObject.FindGameObjectWithTag("Player").GetComponent<Player>();
//获取UI
m_text_score = m_canvas_main.Find("Text_Score").GetComponent<Text>();
m_text_best = m_canvas_main.Find("Text_Best").GetComponent<Text>();
m_text_HP = m_canvas_main.Find("Text_HP").GetComponent<Text>();
//初始化UI显示
m_text_score.text = string.Format("分数 {0}",m_score);
m_text_best.text = string.Format("最佳 {0}", m_bestscore);
m_text_HP.text = string.Format("HP {0}", m_player.HP);
//var是隐式定义
//获取重新开始按钮
var restart_button = m_canvas_gameover.transform.Find("Button").GetComponent<Button>();
//按钮事件回调,重新开始关卡
//监听事件,定义delegate委托类型来传递方法
restart_button.onClick.AddListener(delegate(){
//中间是传递的方法
SceneManager.LoadScene(SceneManager.GetActiveScene().name);
});
//在游戏开始的时候默认游戏结束界面是隐藏的,即m_canvas_gameover的游戏对象组件默认是不显示的
m_canvas_gameover.gameObject.SetActive(false);
}
//设置游戏分数增加的函数
public void score_up(int point) {
m_score += point;
//每次都更新高分记录
if (m_score > m_bestscore)
{
m_bestscore = m_score;
}
//刷新输出分数和最高分
//通过不断更改Text中的文本就可以实现
m_text_score.text = string.Format("分数 {0}", m_score);
m_text_best.text = string.Format("最佳 {0}", m_bestscore);
}
//设置更改生命显示的函数
public void HP_display(float life)
{
//不断更新生命值
m_text_HP.text = string.Format("HP {0}", m_player.HP);
if (m_player.HP <= 0)
{
//通过设置游戏结束场景为显示就可以切换到游戏结束界面
m_canvas_gameover.gameObject.SetActive(true);
}
}
}
8.IndexScene (欢迎界面)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
[AddComponentMenu("脚本/MyGame/IndexScece")]
public class IndexScene : MonoBehaviour {
void Start () {
}
void Update () {
}
private void OnGUI()
{
//文字大小
GUI.skin.label.fontSize = 50;
//UI中心对齐
GUI.skin.label.alignment = TextAnchor.LowerCenter;
//显示标题
GUI.Label(new Rect(0, 30, Screen.width, 100), "太空大战");
//开始游戏按钮
if (GUI.Button(new Rect(Screen.width * 0.5f - 100, Screen.height * 0.7f, 200, 30), "开始游戏"))
{
SceneManager.LoadScene("level1");
}
}
}
9.ProcessModel (制作过程中的Prefab自动生成器--以超级敌人为例)
//自动创建Prefabs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//添加UnityEditor类库,可以使用Unity的编辑器相关API
using UnityEditor;
//继承自AssetPostprocessor , 专门用来处理资源导入。
public class ProcessModel : AssetPostprocessor
{
//只需要一个加载模型的函数,定义这个载入的模型是input
void OnPostprocessModel(GameObject input)
{
//只处理高级敌人的模型
if (!input.name.Contains("SuperEnemy"))
{
return;
}
//设置导入模型的tag
input.tag = "SuperEnemy";
//查找导入模型的碰撞模型
foreach (Transform obj in input.GetComponentInChildren<Transform>())
{
if (obj.name.CompareTo("碰撞模型") != 0)
{
//要是没有碰撞模型,指定Renderer脚本
//obj.gameObject.AddComponent<EnemyRenderer>();
}
else
{
//如果有就取消碰撞模型的显示
MeshRenderer r = obj.GetComponent<MeshRenderer>();
r.enabled = false;
//添加Mesh碰撞体
obj.gameObject.AddComponent<MeshCollider>();
//设置碰撞体的tag
obj.tag = "SuperEnemy";
}
}
//设置刚体
Rigidbody rigidbody = input.AddComponent<Rigidbody>();
rigidbody.useGravity = false;
rigidbody.isKinematic = true;
//取得导入模型的相关信息
ModelImporter importer = assetImporter as ModelImporter;
//从工程中将该模型读出来
GameObject tar = (GameObject)AssetDatabase.LoadAssetAtPath(importer.assetPath, typeof(GameObject));
//将获取到的模型创建为prefab,保存在相应路径下
GameObject prefab = (GameObject)PrefabUtility.CreatePrefab("Assets/prefabs/Superenemy.prefab", tar);
//给Prefab添加音效组件
prefab.AddComponent<AudioSource>();
//在相应路径获取子弹的prefab对象
GameObject enemyrocket = (GameObject)AssetDatabase.LoadAssetAtPath("Assets/prefabs/Enemy_rocket.prefab",
typeof(GameObject));
//获取爆炸效果的prefab
var fx = (GameObject)AssetDatabase.LoadAssetAtPath("Assets/FX/explosion.prefab", typeof(GameObject));
//获取射击音效
AudioClip audiocilp = (AudioClip)AssetDatabase.LoadAssetAtPath("Assets/FX/shoot.WAV", typeof(AudioClip));
//给高级敌人prefab添加相应的SuperEnemy脚本
SuperEnemy enemy = prefab.AddComponent<SuperEnemy>();
//设置脚本的默认参数
enemy.movespeed = 0.2f;
enemy.HP = 140;
enemy.SpinAngle = 0;
enemy.Enemy_rocket = enemyrocket.transform;
enemy.m_explosionFX = fx.transform;
enemy.m_audioClip = audiocilp;
}
}
在制作的过程中,除了看书上的注意事项之外,还遇到了一些错误,现在整理解决方法如下:
1. 尽量不要使用和类型名称几乎重名的变量名
https://answers.unity.com/questions/778335/warning-cs0108-playerphysicscollider-hides-inherit.html
2. Object reference not set to an instance of an object
https://blog.csdn.net/slwbcsdn/article/details/80791336
3. Invalid AABB inAABB
https://blog.csdn.net/Htlas/article/details/79077009
https://blog.csdn.net/Zafir6453/article/details/78571702
4. Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition)会报错 空引用
http://blog.51cto.com/chenyuanyu/1380837
游戏的主要部分包括C#代码已经上传到了GitHub:
https://github.com/dzzhyk/SpaceWar
最后
以上就是爱听歌苗条为你收集整理的Unity太空大战制作初试的全部内容,希望文章能够帮你解决Unity太空大战制作初试所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复