这是我的第一个Unity3D的游戏,下载地址:REME
另外还有一个低配网页WebGL版本:点我跳转
没有错,它十分地简陋,没有开始结束画面~
你只需要控制雷姆移动并且挥动手中的流星锤击倒怪物即可,可能你有幸一次性全部击杀完毕,那么恭喜你完成了游戏,此时地图上只有孤单的雷姆和手中的流星锤,不过似乎这个概率不算高,因为一旦碰到怪物,画面上可能只剩下孤单滚动的锤锤和一脸懵比的怪物…没有重新开始功能,没有重新开始功能,没有重新开始功能,重要的事情说三遍!当然我并不满足于现状,学习路途漫漫,以后会回来填坑的,记住这个时刻【2018年3月11日14:38:06】
下面来说说这个游戏的结构吧:
这个流星锤可没少折腾我,一定要把球的碰撞检测初始位置放到地面的上方!如果开始位置就嵌入了地面,那么他的运动轨迹将出乎你的意料。。。惨痛的教训
游戏背景音乐就不多说了。
上代码:
RemeControl.cs:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class RemeControl : MonoBehaviour {
//一些参数
public float speed=9f;
public float rotspeed=10f;
private float movez = 0;
private float movex = -0.00001f;
private bool dead = false;
//起初自作聪明以为自己实现一个输入缓存能够减少卡顿,结果事实证明这是画蛇添足
// private float []rot=new float[2];
// private int buff;
// Use this for initialization
void Start () {
//画蛇添足
//rot [0] = 0;
//rot [1] = 0;
}
// Update is called once per frame
void Update () {
//死亡以后则无法控制并进入死亡动作
if (!dead) {
//这部分是输入控制 x z平面
//这里使用增量的方式,每次update后将组合的按键的最后效果作为本次移动最终效果
//注意:Input.GetKey (KeyCode.D) | Input.GetKey (KeyCode.RightArrow)不能写成Input.GetKey (KeyCode.D|KeyCode.RightArrow)
if (Input.GetKey (KeyCode.D) | Input.GetKey (KeyCode.RightArrow)) {
movez -= speed * Time.deltaTime;
//画蛇添足
//rot[buff] = rotspeed * Time.deltaTime ;//-rot[1^buff];
//transform.Find ("reme").Rotate (Vector3.up *rot[buff]);
//transform.Rotate (Vector3.up * Time.deltaTime * rotspeed);
}
if (Input.GetKey (KeyCode.A) | Input.GetKey (KeyCode.LeftArrow)) {
movez += speed * Time.deltaTime;
//画蛇添足
//rot [buff] = -rotspeed * Time.deltaTime;//-rot[1^buff];
//transform.Find ("reme").Rotate (Vector3.down *rot[buff]);
//transform.Rotate (Vector3.up * Time.deltaTime * -rotspeed);
}
if (Input.GetKey (KeyCode.W) | Input.GetKey (KeyCode.UpArrow)) {
movex += speed * Time.deltaTime;
//画蛇添足
//rot[buff] = rotspeed * Time.deltaTime -rot[1^buff];
}
if (Input.GetKey (KeyCode.S) | Input.GetKey (KeyCode.DownArrow)) {
movex -= speed * Time.deltaTime;
//画蛇添足
//rot[buff] = rotspeed * Time.deltaTime -rot[1^buff];
}
//移动时候的转向的四维变量
Quaternion quaDir = Quaternion.LookRotation (new Vector3 (movex, 0, movez), Vector3.up);
// Quaternion.Lerp是插值平滑过渡函数
//进行转向
transform.Find ("reme").rotation = Quaternion.Lerp (transform.Find ("reme").rotation, quaDir, Time.deltaTime * rotspeed);
//对x,z坐标进行移动
transform.Translate (new Vector3 (movex, 0, movez));
//画蛇添足
//Vector3.up * Time.deltaTime * rotspeed*rot[buff]
//transform.Rotate (Vector3.up *rot[buff]);
//transform.Find ("reme").Rotate (Vector3.up *rot[buff]);
//Debug.Log ("rot[buff]:" + rot[buff]);
//Debug.Log ("rot[buff^1]:" + rot[buff^1]);
//Debug.Log ("movex:" + movex);
//Debug.Log ("movez:" + movez);
//初始化x,z的移动增量
//这里有一个问题,之所以将movex初始化为-0.00001f有两点:
//1.迫于人物没有收到任何按键的情况下不知人物会鬼畜(不知道如何解决),这两个参数决定了每帧的转向方向
//2.在尽量不影响下一帧的情况下尽量缩小movex的绝对值
movez = 0;
movex = -0.00001f;
//画蛇添足
//rot[1^buff] = 0;
//buff ^= 1;
} else {
//死亡动作直接倒地,2是速率
transform.Rotate(2,0,0);
}
}
public void Hurt(){
//原本想改进死亡的动作,后来还是算了,直接倒地,并且功能放在update中实现
//Vector3 dir = Vector3.RotateTowards (transform.forward, new Vector3(0,1,0), 100, 0.0f);
//transform.rotation = Quaternion.LookRotation (dir);
//Debug.Log ("!!!!");
//Debug.Log("Dead!");
//标志死亡
dead=true;
//销毁对象0.3s以后
Destroy (gameObject,(float)0.3);
//调用游戏结束函数,虽然这个函数是空的...
GameManager.gm.Over();
}
}
boss.cs:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class boss : MonoBehaviour {
//一些参数
//这里用到了Transform变量来实时跟踪人物的移动
public Transform player;
private bool dead=false;
public float speed=10;
public float rootSpeed=10;
public float deadSpeed=10;
//private bool over = false;
// Use this for initialization
void Start () {
//人物的坐标根据公共静态类GameManager-gm获取,来应对新增怪物也能跟踪玩家
player = GameManager.gm.player;
}
// Update is called once per frame
void Update () {
//判断是否死亡和玩家是否死亡
if (!dead&&player != null) {
//向量指向被减数(玩家)dir是方向向量
Vector3 dir = player.position - transform.position;
//步长
float step = rootSpeed * Time.deltaTime;
//螺旋前进向量【这部分已经忘了】
//这个函数类似于MoveTowards除了将向量被视为一个方向,而不是一个位置上。当前向量将被旋转朝向目标方向由maxRadiansDelta的角度,
//虽然会恰好落在目标,而不是超过。如果当前的大小和目标的是不同的,那么结果的幅度将被线性地旋转过程中进行插值。
//如果一个负值用于maxRadiansDelta ,向量会转离目标/直到它指向完全相反的方向,然后停止。
Vector3 newDir = Vector3.RotateTowards (transform.forward, dir, step, 0.0f);
//旋转
transform.rotation = Quaternion.LookRotation (newDir);
//移动
transform.Translate (transform.forward * Time.deltaTime * speed);
} else {
if (player != null) {
//进行死亡动作
transform.Rotate(deadSpeed/2,0,0);
} else {
//玩家死亡则不动
}
}
}
//雷姆碰撞检测
void OnTriggerEnter(Collider coll){
//ebug.Log ("YY");
//死后就不能造成伤害了,但死亡有延迟0.2s因此!dead
if (coll.tag .Equals( "Player")&&!dead) {
//Debug.Log ("XX");
coll.GetComponent<RemeControl> ().Hurt ();
}
}
public void Hurt(){
//Vector3 dir = Vector3.RotateTowards (transform.forward, new Vector3(0,1,0), 100, 0.0f);
//transform.rotation = Quaternion.LookRotation (dir);
//Debug.Log ("!!!!");
dead=true;
Destroy (gameObject,(float)0.2);
}
}
GameManager.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GameManager : MonoBehaviour {
//全局静态类
public static GameManager gm;
public Transform player;
public GameObject enemy1;
public GameObject enemy2;
//间隔时间
public float rateTime=1500;
float myTime=1999;
// Use this for initialization
void Awake () {
//awake后赋值
gm = this;
}
// Update is called once per frame
void Update () {
myTime += Time.deltaTime;
//Debug.Log (myTime);
if (myTime > rateTime) {
//随机生成二维坐标
Vector2 r = Random.insideUnitCircle * 60;
//判断“兵种”是否灭绝
if (enemy1 != null) {
Instantiate (enemy1, player.position + new Vector3 (r.x, 0, r.y), Quaternion.identity);
}
//判断“兵种”是否灭绝
if (enemy2 != null) {
Instantiate (enemy2, player.position + new Vector3 (r.x, 0, r.y), Quaternion.identity);
}
myTime = 0;
}
}
public void Over()
{
//结束游戏
}
}
ball.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ball : MonoBehaviour {
// Use this for initialization
//碰撞函数,类似回调
void OnTriggerEnter(Collider coll){
//判断碰撞物的Tag并进行操作
if (coll.tag .Equals( "Enemy")) {
//使用此次碰撞得到其<boss>的组件并调用Hurt()销毁怪物
coll.GetComponent<boss> ().Hurt ();
}
}
}
参考:
从零开始三小时速撸一款雷姆小游戏Unity3D全过程(果然还是跟着教程走省心~)
Unity3D工程文件:Reme源码