笔记30 Unity跑酷类型游戏
街区
添加雾
玩家跑步代码。为了进行街区的制作,先让玩家跑起来
public int Hp = 1;
// 速度
public float Speed = 4;
void Start()
{
}
void Update()
{
if(Hp <= 0)
{
//什么也不做了
return;
}
//跑步(向前方*速度*转换成每秒)
transform.Translate(transform.forward*Speed*Time.deltaTime);
}
代码:街区GroundControl
//地形预设体的数组
public GameObject[] GroundPres;
//玩家位置
private Transform playerTrans;
void Start()
{
//在这里得到。=得到玩家.位置
playerTrans = GameObject.FindWithTag("Player").transform;
}
// Update is called once per frame
void Update()
{
//如果玩家离开了当前地面,当前地面位置前进80米
//因为地面Z轴长度是40米,只要大于20米,即算离开。
//为了画面衔接更好,所以别20米大点。
if(playerTrans.position.z - transform.position.z > 25)
{
//往前方前进80米
transform.position += Vector3.forward * 80;
//销毁当前地形,创建新地形
Destroy(transform.GetChild(0).gameObject);
//随机创建新的地形。创建(什么东西(随机一个),位置(和当前点的位置一样),旋转(不旋转))
//创建出来之后,要当做当前点的子物体,所以在后面直接添加“.transform(拿到).SetParent设置父物体(transform当前点)”
Instantiate(GroundPres[Random.Range(0, GroundPres.Length)], transform.position, Quaternion.identity).transform.SetParent(transform);
}
}
出现的一个小Bug
声音控制器+代码AudioManager
//单例
public static AudioManager Instance;
//播放器有两个
public AudioSource MusicPlayer;
public AudioSource SoundPlayer;
//单例写在Awake这里
void Awake()
{
Instance = this;
}
//方法有两个。一个是播放音乐
public void PlayMusic(string name)
{
//如果音乐播放器没在播放
if(MusicPlayer.isPlaying == false)
{
//就读取一个声音片段,声音判断是通过R加载上来的
AudioClip clip = Resources.Load<AudioClip>(name);
MusicPlayer.clip = clip;
MusicPlayer.Play();
}
}
//另一个是停止的方法
public void StopMusic()
{
MusicPlayer.Stop();
}
//播放音效
public void PlaySound(string name)
{
//加载声音片段
AudioClip clip = Resources.Load<AudioClip>(name);
SoundPlayer.PlayOneShot(clip);
}
玩家
玩家左右变换跑道
未使用动画插件,切换较生硬(不好)
//靠左边跑
if(Input.GetKeyDown(KeyCode.A) && isGround == true)
{
//如果它在中间、右侧跑道(即X轴大于等于0),才可以靠左边跑
if (transform.position.x >= 0)
{
//transform.position.x -= 2;是会爆红的。因为,Vector3是可读可写,xyz是只读。所以,这里需要使用座标转换。
//拿到当前座标
Vector3 v = transform.position;
//减
v.x -= 2;
//再赋值回来
transform.position = v;
}
}
//靠右边跑
if (Input.GetKeyDown(KeyCode.D) && isGround == true)
{
//如果它在中间、左侧跑道(即X轴小于等于0),才可以靠右边跑
if (transform.position.x <= 0)
{
//拿到当前座标
Vector3 v = transform.position;
//加
v.x += 2;
//再赋值回来
transform.position = v;
}
}
使用动画插件,切换自然+代码
/*
是否在动画当中(因为,下面利用插件左右移动时,给的动画时间是0.5秒,
如果在未到0.5秒(即未到指定位置,未播完动画),便按了其他按键,会导致位置不准确
所以添加判断:是否在动画中
*/
private bool isAni = false;
//靠左边跑
if(Input.GetKeyDown(KeyCode.A) && isGround == true)
{
//如果它在中间、右侧跑道(即X轴大于等于0),才可以靠左边跑
if (transform.position.x >= 0 && isAni == false)
{
//播放音效
AudioManager.Instance.PlaySound("变换跑道");
//设定动画状态
isAni = true;
//目标位置。target的x = 当前位置的x减2
float targetx = transform.position.x - 2;
//创建动画。一个动画,就是一个Tween。增加了很多方法,此处用X轴移动(DOMoveX)
//DOMoveX(目标位置,动画时间)
Tween tween = transform.DOMoveX(targetx, 0.5f);
/*
此处,应该讲动画的状态设置为false。
法一:在下面写一个结束方法,在这里“Invoke("AniEnd", 0.5f);”。
意思是,0.5秒以后,调用动画结束方法。
法二:在下面写一个结束方法,onComplete完成委托。TweenCallback委托(AniEnd方法)
两种方法,法二的优点是不需要知道动画播放时间,
所以如果动画的播放时间是随机的,该方法便是极好用的了。
*/
tween.onComplete = new TweenCallback(AniEnd);
}
}
//靠右边跑
if (Input.GetKeyDown(KeyCode.D) && isGround == true)
{
//如果它在中间、左侧跑道(即X轴小于等于0),才可以靠右边跑
if (transform.position.x <= 0 && isAni == false)
{
//播放音效
AudioManager.Instance.PlaySound("变换跑道");
//设定动画状态
isAni = true;
//目标位置。target的x = 当前位置的x加2
float targetx = transform.position.x + 2;
//创建动画。一个动画,就是一个Tween。增加了很多方法,此处用X轴移动(DOMoveX)
//DOMoveX(目标位置,动画时间)
Tween tween = transform.DOMoveX(targetx, 0.5f);
//完成委托
tween.onComplete = new TweenCallback(AniEnd);
}
}
地面检测出现的小问题
障碍物
金币
创建金币,注意它所属的位置
金币特效
第一组粒子
第二组粒子
代码:金币CoinCollider
// 拿到金币特效
public GameObject CoinEffect;
void Start()
{
}
//金币是一直旋转的
private void Update()
{
//注意金币是形变后得到的,所以要查看此时向上的是什么轴,此处是Y轴。
//每秒旋转80度
transform.Rotate(Vector3.forward, 80 * Time.deltaTime);
}
//如果玩家进来了
private void OnTriggerEnter(Collider other)
{
if(other.tag == "Player")
{
//实例化特效。实例化(实例化什么,位置,旋转)
Instantiate(CoinEffect, transform.position, Quaternion.identity);
//播放碰到金币的音效
AudioManager.Instance.PlaySound("金币");
//销毁自己
Destroy(gameObject);
}
}
自动销毁金币特效+代码AudioDestroy
// 金币特效是的粒子发射时间最长是0.5秒,所以,默认给它0.5秒
public float DestroyTime = 0.5f;
void Start()
{
Destroy(gameObject, DestroyTime);
}
void Update()
{
}
代码:玩家PlayerControl
public int Hp = 1;
// 速度
public float Speed = 4;
/*是否在动画当中(因为,下面利用插件左右移动时,给的动画时间是0.5秒,
如果在未到0.5秒(即未到指定位置,未播完动画),便按了其他按键,会导致位置不准确
所以添加判断:是否在动画中*/
private bool isAni = false;
//是否接触地面(因为,此游戏限定在空中不可以切换跑道)
private bool isGround = false;
void Start()
{
}
// Update is called once per frame
void Update()
{
if(Hp <= 0)
{
//什么也不做了
return;
}
//跑步(向前方*速度*转换成每秒)
transform.Translate(transform.forward*Speed*Time.deltaTime);
//判断有没有踩到地面有两种方法,此处使用射线检测
//创建射线。此处应注意,这个模型的transform.position是紧贴地面的,所以要将射线的起始点上移一点点。
//方向:Vector3.down向下
Ray ray = new Ray(transform.position + Vector3.up * 0.05f, Vector3.down);
RaycastHit hit;
//射线检测。(检测谁ray, 检测结果out hit, 射线长度0.1f)
bool res = Physics.Raycast(ray, out hit, 0.1f);
//画出射线(无用,删除即可)。把上面小括号里射线的相关数据复制一下,添加长度,颜色
//Debug.DrawRay(transform.position + Vector3.up * 0.05f, Vector3.down * 0.1f, Color.red);
if(res = true && hit.collider.tag == "Ground")
{
isGround = true;
}
else
{
isGround = false;
}
//靠左边跑
if(Input.GetKeyDown(KeyCode.A) && isGround == true)
{
//如果它在中间、右侧跑道(即X轴大于等于0),才可以靠左边跑
if (transform.position.x >= 0 && isAni == false)
{
//播放音效
AudioManager.Instance.PlaySound("变换跑道");
//设定动画状态
isAni = true;
//目标位置。target的x = 当前位置的x减2
float targetx = transform.position.x - 2;
//创建动画。一个动画,就是一个Tween。增加了很多方法,此处用X轴移动(DOMoveX)
//DOMoveX(目标位置,动画时间)
Tween tween = transform.DOMoveX(targetx, 0.5f);
/*
此处,应该讲动画的状态设置为false。
法一:在下面写一个结束方法,在这里“Invoke("AniEnd", 0.5f);”。
意思是,0.5秒以后,调用动画结束方法。
法二:在下面写一个结束方法,onComplete完成委托。TweenCallback委托(AniEnd方法)
两种方法,法二的优点是不需要知道动画播放时间,
所以如果动画的播放时间是随机的,该方法便是极好用的了。
*/
tween.onComplete = new TweenCallback(AniEnd);
}
}
//靠右边跑
if (Input.GetKeyDown(KeyCode.D) && isGround == true)
{
//如果它在中间、左侧跑道(即X轴小于等于0),才可以靠右边跑
if (transform.position.x <= 0 && isAni == false)
{
//播放音效
AudioManager.Instance.PlaySound("变换跑道");
//设定动画状态
isAni = true;
//目标位置。target的x = 当前位置的x加2
float targetx = transform.position.x + 2;
//创建动画。一个动画,就是一个Tween。增加了很多方法,此处用X轴移动(DOMoveX)
//DOMoveX(目标位置,动画时间)
Tween tween = transform.DOMoveX(targetx, 0.5f);
//完成委托
tween.onComplete = new TweenCallback(AniEnd);
}
}
//跳跃
if(Input.GetKeyDown(KeyCode.Space) && isGround == true)
{
//给刚体一个向上的力
GetComponent<Rigidbody>().AddForce(200f * Vector3.up);
//播放跳跃音效
AudioManager.Instance.PlaySound("跳");
}
}
//动画结束
void AniEnd()
{
//保障x永远是-2、0、2个值中的一个,使代码更严谨。
//思路:判断结果是1.8,就直接改成2
isAni = false;
}
//
private void OnCollisionEnter(Collision collision)
{
if(collision.collider.tag == "Obs")
{
Hp--;
if(Hp <= 0)
{
//停止背景音乐(自己填的第一条代码)
AudioManager.Instance.StopMusic();
//播放死亡音效。(我出现的问题:死亡音效发生二重唱!)
AudioManager.Instance.PlaySound("死亡2");
//播放死亡动画
GetComponent<Animation>().Play("die");
}
}
}