如题,在学习unity的过程中,发现可恶的只能在线看视频,网速严重受限的我感觉很是烦恼,快进一下,诶,不动了,过了一会儿。。。黑屏,就能看到刷新的字样
千辛万苦找到可以下载的视频,打开一看,字幕是英文的。。。英文的。。。英文的(为什么说三遍你懂得)
虽然我英文不是很菜。。。基础的都能看懂,但是专业术语看着还是很伤心。。。用翻译又翻译的连亲妈都认不出来
英文版下载链接http://pan.baidu.com/s/1c0DHDs8
所以我就写篇文档,方便随时查看 (又没WiFi了,我现在在用手机流量写这篇博客。。。)
写的有点粗糙加无脑。。。凑活着看吧
Unity space shooter
一
1,save scene
2,拖动飞机模型到场景中并reset,
3,为飞机添加rigidbody组件
4,为飞机添加胶囊触发器 capsule collider,后来又改成mesh collider
5,调整方向direction为z轴
6,添加prefab里的喷射粒子特效
二,
1,调整摄像机 reset
2,x角度为90度,使摄像机朝下,调整y值
3,调整投射为直角orthographic
4,移动飞机位置,采用飞机位于中心点不动,移动camera视角的方法
5,clear flags 设为 solid color
6,create directional light
7, reset
8,rotation x = 20 , y = -115 照射使右边亮
9,光照强度 intensity 调为 0.75 更接近太阳光
10,复制一个光,并命名为fill light ,使其角度照射左边,设intensity为0.15,比右边稍暗
设置color,淡蓝色。。。其实光照这部分复杂而且效果。。。就当学习了
11,Ctrl + shift +n 创建空的gameobject,将两个光移动到里面,方便整理
1,禁用player ,create ,3d object, quad 命名为 BackGround,看不到quad,换到scene场景,调整x角度为90
2,取消 mesh coliider,用不到
3,拖动texture中的背景图到quad(BackGround)中,这是纹理,我们没创建材质(纹理是材质的一部分),unity自动帮我们创建,放在mesh renderer中,创建的纹理默认使用diffue shader(但是我这儿是standard)。。。后面作者换成了specular,即standard。Diffuse属于漫反射,后者属于镜面反射。最后换成unlit texture,不受光照,这时候变亮了
4,图片拉伸,为防止拉伸后失真,要保证图片宽高比不变,竖屏游戏中,宽拉满,高乘比例。X : 15, y : 30。。。。。(先分层,设置不同layer,调整背景层y为负值,使其与飞机分开层)
三
1,为player创建脚本Done_PlayerController
建立FixedUpdate函数,在每个固定物理时间步被调用,放置物理行为代码的地方
2,在函数中编写
public float speed; 速度
float moveHorizontal = Input.GetAxis ("Horizontal"); 水平轴
float moveVertical = Input.GetAxis ("Vertical"); 垂直轴
Vector3 movement = new Vector3 (moveHorizontal, 0.0f, moveVertical);
GetComponent<Rigidbody>().velocity = movement * speed;
使飞船可以移动
3,继续编写代码设定飞船可移动范围
[System.Serializable] 序列化(储存并转移信息的一种方法)该类,unity才能显示出来
public class Done_Boundary 另外定义一个共有类,里面的属性可以被其他对象共用
{
public float xMin, xMax, zMin, zMax;
}
在我们的类Done_PlayerController中实例化Done_Boundary
public Done_Boundary boundary;
GetComponent<Rigidbody>().position = new Vector3 定义x,z范围
(
Mathf.Clamp (GetComponent<Rigidbody>().position.x, boundary.xMin, boundary.xMax),
0.0f,
Mathf.Clamp (GetComponent<Rigidbody>().position.z, boundary.zMin, boundary.zMax)
);
保存在unity中调试xMin, xMax, zMin, zMax的值 -6,6,-4,8
4, public float tilt;
GetComponent<Rigidbody>().rotation = Quaternion.Euler (0.0f, 0.0f, GetComponent<Rigidbody>().velocity.x * -tilt);
根据速度返回一个z轴上旋转角度,使飞机左右移动时会倾斜
四,创建子弹
1,创建一个gameobject命名为bolt(别忘了reset),创建一个quad,命名为VFX(reset,x旋转90),将其拖到bolt中,后面创建的材质放这里
2,在materias中create一个材质命名为 fx_bolt_orange(实际上资源包里已经创建好了)
3,将texture中的fx_lazer_orange_dff纹理与刚才创建的材质建立联系,有两种方法:
1)直接拖到纹理到材质中
2)点击材质旁的select选择纹理
4,这时候到game视图,子弹周围还有黑框,shader选择 Mobile/Paticles/Additive(已经设置好了)
5,在VFX中remove mesh collider添加capsule collider
,为bolt添加刚体组件取消重力
6,调整方向为z-axis,半径0.03,高0.5,勾选 is trigger
7,为其添加脚本使其发射
public class Done_Mover : MonoBehaviour
{
public float speed;
void Start ()
{
GetComponent<Rigidbody>().velocity = transform.forward * speed;
}
}
8,回到unity,设置子弹速度为20
9.因为要有很多子弹,所以把子弹设为预制件prefab,直接将bolt拖动到下面prefab即可
10.在层级中删除bolt,点击运行,将预制件中的bolt一个个拖动到层级中,会看到子弹发射出去
五,1,创建gameobject命名为 Shot Spawn,将其拖到player里面,reset
2,将子弹prefab拖到Shot Spawn里,设z为1.25,查看效果后将子弹删除
3,在one_PlayerController里家这样一段代码
public GameObject shot;
public Transform shotSpawn;
public float fireRate;
private float nextFire;
void Update ()
{
if (Input.GetButton("Fire1") && Time.time > nextFire)
{
nextFire = Time.time + fireRate;
//GameObject clone =
Instantiate(shot, shotSpawn.position, shotSpawn.rotation);
//as GameObject
}
}
Fire1是input预设的一个按钮,即我们点击或按钮时而且当前游戏时间 > 下一次发射时间,那么执行: 下次发射时间增加,发射。(as GameObject 是告诉unity我们实例化了一个GameObject对象,新对象需要个参照对象才方便操作。但这里我们只让飞机发射,子弹并没有其他动作,所以用不到)
4,回到unity当中,为刚才创建的属性赋值
将prefab中的bolt拖到Shot中;
将Shot Spawn拖到Shot Spawn中;
将Fire Rate设为0.25.(1秒发射4次)。
运行。。。
5,create cube ,命名为Boundary,reset,,勾选 is trigger
6,设置其到中心,跟摄像机坐标一样 x,0,z,5;调整scale使其铺满屏幕:x,15,z,20
取消mesh render,到scene中看下效果
7,添加脚本Done_DestroyByBoundary
代码:
void OnTriggerExit (Collider other)
{
Destroy(other.gameObject);
}
当其他碰撞器停止与该触发器接触时调用这个函数(即离开时调用),即实现子弹,障碍等碰到边界时自动消除
8,remove mesh render和mesh filter,运行,会发现层级当中生成的bolt(clone )会自动消失
六
1,添加陨石,create gameobject ,命名为Astroide,reset
2,将model中的第一个拖到Astroide中,reset
3,为Astroide添加刚体组件,取消重力,添加capsule collider,勾选 is trigger
可以按住shift 调整 capsule collider的大小(但我的胶囊有问题。。。只有一个球,而且shift后没有出现触点)
4,为Asteroid添加脚本Done_RandomRotator 实现陨石随机角度翻滚
代码
public float tumble; 翻滚值
void Start ()
{
GetComponent<Rigidbody>().angularVelocity = Random.insideUnitSphere * tumble;
}
angularVelocity,旋转速率;insideUnitSphere 是vector3类型,会对x,y,z随机
回到unity,设置tumble值为5,设angular drag(角度阻力)为0
5,为Astroide添加脚本 Done_DestroyByContact
代码
void OnTriggerEnter (Collider other)
{
Destroy (other.gameObject);
Destroy (gameObject);
}
OnTriggerEnter 与OnTriggerExit不同,是第一次触碰时调用
Destroy (other.gameObject);销毁碰到的其他物体
Destroy (gameObject);销毁调用该脚本的对象即陨石
6,运行,发现陨石木有了 QAQ
7,我们来debug,在函数OnTriggerEnter中加OnTriggerEnter,再运行,发现是Boundary。。
8,为Boundary添加tag(Boundary),使其免疫与陨石的碰撞。在代码中注释debug并添加代码if (other.tag == "Boundary" || other.tag == "Enemy")
{
return;
}
Enemy先不管,后面用到,这里前面判定到Boundary的时候,中断这个函数的执行,就不再执行后面销毁的代码了。
9,添加代码
public GameObject explosion;
if (explosion != null)
{
Instantiate(explosion, transform.position, transform.rotation);
}
回到unity中,将预制件VFX中的explosion_asteroid拖到Asteroid对象的Explosion
和以前添加子弹一样,我们这里添加爆炸效果,使陨石被碰撞的时候释放爆炸效果
10,添加代码
public GameObject playerExplosion;
if (other.tag == "Player")
{
Instantiate(playerExplosion, other.transform.position, other.transform.rotation);
}
回到unity当中,设置player的tag为player,将explosion_player拖到Asteroid的Player Explosion当中,实现飞机与陨石碰撞时的爆炸效果
11,为Asteroid添加Done_Mover脚本,回到unity设置speed为-5,使其能朝向飞机移动
12,将Asteroid拖入到prefab中,删除层级视图中的Asteroid
七
1,create gameobject,命名为Game Controller,reset,添加脚本Done_GameController
添加代码实现随机产生一个陨石
public GameObject hazard; 陨石参照对象
public Vector3 spawnValues; Vector3类型对象
void Start ()
{
SpawnWaves ();
}
void SpawnWaves()
{
Vector3 spawnPosition = new Vector3 (Random.Range (-spawnValues.x, spawnValues.x), spawnValues.y, spawnValues.z);
Quaternion spawnRotation = Quaternion.identity;
Instantiate (hazard, spawnPosition, spawnRotation);
}
Start中调用spawnwaves ,
spawnPosition 为陨石产生的坐标,由spawnValues赋值,随机产生只考虑x坐标,用Random.Range确定随机范围
spawnRotation 为陨石产生的角度,这里用Quaternion.identity设为不变,若有角度,就不能保证陨石直直的冲向飞机
2,想让当前代码暂停执行而不暂停当前游戏需要协同程序 cooperate
StartCoroutine (SpawnWaves ()); //协同函数被调用
IEnumerator SpawnWaves () //协同函数要加IEnumerator
{
yield return new WaitForSeconds (startWait); //开始准备时间
//调用函数暂停要加yield return new
while (true)
{
for (int i = 0; i < hazardCount; i++)
{
GameObject hazard = hazards [Random.Range (0, hazards.Length)];
Vector3 spawnPosition = new Vector3 (Random.Range (-spawnValues.x, spawnValues.x), spawnValues.y, spawnValues.z);
Quaternion spawnRotation = Quaternion.identity;
Instantiate (hazard, spawnPosition, spawnRotation);
yield return new WaitForSeconds (spawnWait); //每个陨石间隔
}
yield return new WaitForSeconds (waveWait); //每波陨石来临间隔
}
}
利用for循环一波生成多个陨石,且不会出现多个陨石同时出现导致陨石自相残杀的情况
3,这里有个问题,层级中爆炸对象不会自动消失,要为两个爆炸添加脚本Done_DestroyByTime
代码
public float lifetime;
void Start ()
{
Destroy (gameObject, lifetime);
}
在开始的一帧推延lifetime的时间执行销毁,lifetime设为2
八,
1,unity有三个音频组件音频剪辑,音频源,音频监听器
2,将audio中的对应音效拖入prefab中Explosions的对应预制件中,勾选play on awake
这样为爆炸效果与音效建立了关联
3,添加飞机武器音效,将weapon_player拖入player中,取消play on awake,打开PlayerController脚本
4,添加GetComponent<AudioSource>().Play ();
AudioSource 作用:建立音频源于组件的关联
Play是音频源的一个函数,用于播放音频剪辑
5,运行后发现没声音,仔细一看audio里面的音频剪辑也没声音。。。如果你们出声音了麻烦请告诉我
九,
1,创建 3D object,3D text。(Gui text什么的实在搞不出来,拿3D试出来了。。。)
Reset,x旋转90度,调整字样为 Score Text,调整坐标位置移动到屏幕左上角
2,打开脚本文件
添加代码public TextMesh scoreText;
private int score; (不希望被其他调用)
Start函数内添加
score = 0;
UpdateScore ();
添加函数
void UpdateScore ()
{
scoreText.text = "Score: " + score;
}
添加共有函数
public void AddScore (int newScoreValue)
{
score += newScoreValue;
UpdateScore ();
}
回到unity中将Score Text 属性设置为Score Text对象
3,点击Game Controller,设置tag为Game Controller。
public int scoreValue;
private Done_GameController gameController;
void Start ()
{
GameObject gameControllerObject = GameObject.FindGameObjectWithTag ("GameController");
if (gameControllerObject != null)
{
gameController = gameControllerObject.GetComponent <Done_GameController>();
}
if (gameController == null)
{
Debug.Log ("Cannot find 'GameController' script");
}
}
在爆炸的开始为每一个爆炸clone实例找到对应的gameObject的引用,
gameController.AddScore(scoreValue);
在爆炸的最后执行添加分数
最后回到unity中点击prefab中的Asteroid,设置Score Value为10,运行。。。
完结
1,创建gameobject,命名为Display,reset,将创建的3d text拖进去。
2,创建Restart Text,GameOver Text,reset,调整字样,调整位置,拖动到Display里
3,打开脚本Done_GameController
添加代码
定义
public TextMesh restartText;
public TextMesh gameOverText;
private bool gameOver;
private bool restart;
在start函数中初始化
gameOver = false;
restart = false;
restartText.text = ""; //使游戏开始时不显示这俩组件
gameOverText.text = "";
在update函数中添加restart的实现逻辑
if (restart)
{
if (Input.GetKeyDown (KeyCode.R))
{
Application.LoadLevel (Application.loadedLevel);
}
}
建立共有函数GameOver用于设置游戏结束信息和tag
public void GameOver ()
{
gameOverText.text = "Game Over!";
gameOver = true;
}
在IEnumerator SpawnWaves ()加入代码跳出while循环使游戏结束并显示重新开始的提示信息
if (gameOver)
{
restartText.text = "Press 'R' for Restart";
restart = true;
break;
}
在update中添加代码实现按下R是游戏重新开始
if (restart)
{
if (Input.GetKeyDown (KeyCode.R))
{
Application.LoadLevel (Application.loadedLevel); //重新加载当前场景
}
}
4,回到unity,将Restart Text和GameOver Text拖入Done_Game_Controller脚本的相关属性栏里
5,打开脚本Done_DestroyByContact
在判断触碰的函数OnTriggerEnter添加
if (other.tag == "Player")
{
Instantiate(playerExplosion, other.transform.position, other.transform.rotation);
gameController.GameOver();
}
如果陨石碰到的是飞机,播放动画,调用公有函数GameOver(),实现显示gameover的字样
待这一波陨石都消失后,会显示Press 'R' for Restart,然后按下R,会开始新一轮游戏
6,发布到web
Ctrl+Shift+B,选择web player,点击Add Current,将当前场景添加进去,build。选择一个你想把资源添加到的文件夹
9,发布后发现一个bug,按一下ctrl键,会一直放发射的音效,回去看了一下,发现不知道什么时候手贱把player的音频源里的loop点了