Road Crossing Game Template 学习
using UnityEngine; using System; namespace RoadCrossing.Types { /// <summary> /// 小路 /// </summary> [Serializable] public class Lane { /// <summary> /// 小路相关的游戏物体 /// </summary> public Transform laneObject; /// <summary> /// 生成这条路的几率 /// </summary> public int laneChance = 1; /// <summary> /// 小路的宽度 /// </summary> public float laneWidth = 1; /// <summary> /// 生成物品的几率 /// </summary> public float itemChance = 1; } }
using UnityEngine; using System; namespace RoadCrossing.Types { /// <summary> /// 掉落物品 /// </summary> [Serializable] public class ObjectDrop { /// <summary> /// 掉落物品 /// </summary> public Transform droppedObject; /// <summary> /// 掉落几率 /// </summary> public int dropChance = 1; } }
using UnityEngine; using System; namespace RoadCrossing.Types { /// <summary> /// 商店道具 /// </summary> [Serializable] public class ShopItem { /// <summary> /// 这个道具关联的按钮 /// </summary> public Transform itemButton; /// <summary> /// 解锁状态,0 未解锁 1 已解锁 /// </summary> public int lockState = 0; /// <summary> /// 解锁这个道具的花费 /// </summary> public int costToUnlock = 100; /// <summary> /// 这个道具在存档中的键名 /// </summary> public string playerPrefsName = "FroggyUnlock"; } }
using System; namespace RoadCrossing.Types { /// <summary> /// 接触后调用的函数信息 /// </summary> [Serializable] public class TouchFunction { /// <summary> /// 调用的函数名称 /// </summary> public string functionName = "CancelMove"; /// <summary> /// 在哪个目标上调用函数 /// </summary> public string targetTag = "Player"; /// <summary> /// 传递给函数的参数 /// </summary> public float functionParameter = 0; } }
using UnityEngine; using RoadCrossing.Types; namespace RoadCrossing { /// <summary> /// 能与玩家交互的块,可以是岩石,墙,敌人,金币 /// </summary> public class RCGBlock : MonoBehaviour { /// <summary> /// 能够接触这个块的物体的标签 /// </summary> public string touchTargetTag = "Player"; /// <summary> /// 这个块被目标接触后调用的函数列表 /// </summary> public TouchFunction[] touchFunctions; /// <summary> /// 经过多少次接触后删除这个物体 /// </summary> public int removeAfterTouches = 0; /// <summary> /// 这个物体是否可以被移除 /// </summary> internal bool isRemovable = false; /// <summary> /// 当这个物体被接触后的动画剪辑 /// </summary> public AnimationClip hitAnimation; /// <summary> /// 当这个物体被接触后的声音剪辑 /// </summary> public AudioClip soundHit; /// <summary> /// AudioSource所属物体的标签 /// </summary> public string soundSourceTag = "GameController"; /// <summary> /// 物体死亡后创建的死亡的特效 /// </summary> public Transform deathEffect; void Start() { if( removeAfterTouches > 0 ) isRemovable = true; } void OnTriggerEnter(Collider other) { if( other.tag == touchTargetTag ) { //调用目标物体上的函数 foreach( var touchFunction in touchFunctions ) { if( touchFunction.targetTag != string.Empty && touchFunction.functionName != string.Empty ) { GameObject.FindGameObjectWithTag(touchFunction.targetTag).SendMessage(touchFunction.functionName, touchFunction.functionParameter); } } //满足条件,播放动画 if( GetComponent<Animation>() && hitAnimation ) { GetComponent<Animation>().Stop(); GetComponent<Animation>().Play(hitAnimation.name); } //满足条件,删除物体,创建死亡特效 if( isRemovable == true ) { removeAfterTouches--; if( removeAfterTouches <= 0 ) { if( deathEffect ) Instantiate(deathEffect, transform.position, Quaternion.identity); Destroy(gameObject); } } //满足条件,播放声音 if( soundSourceTag != string.Empty && soundHit ) GameObject.FindGameObjectWithTag(soundSourceTag).GetComponent<AudioSource>().PlayOneShot(soundHit); } } } }
using UnityEngine; namespace RoadCrossing { /// <summary> /// 控制上下左右点击的按钮(collider) /// </summary> public class RCGButtonFunction : MonoBehaviour { /// <summary> /// 要执行函数的物体 /// </summary> public Transform functionTarget; /// <summary> /// 要执行的函数名称 /// </summary> public string functionName; /// <summary> /// 传递给函数的参数 /// </summary> public string functionParameter; /// <summary> /// 点击声音 /// </summary> public AudioClip soundClick; /// <summary> /// AudioSource 所属的物体 /// </summary> public Transform soundSource; void OnMouseDrag() { ExecuteFunction(); } /// <summary> /// 执行函数 /// </summary> void ExecuteFunction() { if( soundSource ) if( soundSource.GetComponent<AudioSource>() ) soundSource.GetComponent<AudioSource>().PlayOneShot(soundClick); if( functionName != string.Empty ) { if( functionTarget ) { functionTarget.SendMessage(functionName, functionParameter); } } } } }
using System.Collections; using UnityEngine; using UnityEngine.UI; using RoadCrossing.Types; namespace RoadCrossing { /// <summary> /// 游戏控制 /// </summary> public class RCGGameController : MonoBehaviour { /// <summary> /// 玩家物体列表 /// </summary> public Transform[] playerObjects; /// <summary> /// 当前玩家物体索引 /// </summary> public int currentPlayer; /// <summary> /// 跟随玩家的相机 /// </summary> public Transform cameraObject; /// <summary> /// 控制玩家移动的按钮(collider),如果是滑动控制,这些物体会被禁用 /// </summary> public Transform moveButtonsObject; /// <summary> /// 是否使用滑动控制 /// </summary> public bool swipeControls = false; /// <summary> /// 滑动起点 /// </summary> internal Vector3 swipeStart; /// <summary> /// 滑动终点 /// </summary> internal Vector3 swipeEnd; public float swipeDistance = 10; /// <summary> /// 滑动命令取消前的等待时间 /// </summary> public float swipeTimeout = 1; /// <summary> /// /// </summary> internal float swipeTimeoutCount; /// <summary> /// 所有的小路预设列表 /// </summary> public Lane[] lanes; internal Lane[] lanesList; public ObjectDrop[] objectDrops; internal Transform[] objectDropList; public int objectDropOffset = 4; /// <summary> /// 游戏开始前与预创建的小路数量 /// </summary> public int precreateLanes = 20; /// <summary> /// 下一条小路的位置 /// </summary> internal float nextLanePosition = 1; /// <summary> /// 得分 /// </summary> public int score = 0; /// <summary> /// 显示得分的文本 /// </summary> public Transform scoreText; /// <summary> /// 最高分数 /// </summary> internal int highScore = 0; /// <summary> /// 游戏中总共获得的分数 /// </summary> public string coinsPlayerPrefs = "Coins"; /// <summary> /// 游戏速度 /// </summary> public float gameSpeed = 1; /// <summary> /// 玩家升级需要的点数 /// </summary> public int levelUpEveryCoins = 5; /// <summary> /// 增加的分数 /// </summary> internal int increaseCount = 0; /// <summary> /// 在玩家身后追逐玩家的物体 /// </summary> public Transform deathLineObject; /// <summary> /// 追杀物体的移动速度 /// </summary> public float deathLineSpeed = 1; /// <summary> /// 追杀物体每次增加的速度的值 /// </summary> public float deathLineSpeedIncrease = 1; /// <summary> /// 追杀物体的最大移动速度 /// </summary> public float deathLineSpeedMax = 1.5f; /// <summary> /// 游戏面板 /// </summary> public Transform gameCanvas; /// <summary> /// 暂停面板 /// </summary> public Transform pauseCanvas; /// <summary> /// 游戏结束面板 /// </summary> public Transform gameOverCanvas; /// <summary> /// 游戏是否结束 /// </summary> internal bool isGameOver = false; /// <summary> /// 主目录场景 /// </summary> public string mainMenuLevelName = "MainMenu"; /// <summary> /// 升级声音 /// </summary> public AudioClip soundLevelUp; /// <summary> /// 游戏结束声音 /// </summary> public AudioClip soundGameOver; /// <summary> /// 使用AudioSource的物体的标签 /// </summary> public string soundSourceTag = "GameController"; /// <summary> /// 确认按钮 /// </summary> public string confirmButton = "Submit"; //暂停按钮 public string pauseButton = "Cancel"; /// <summary> /// 游戏是否暂停 /// </summary> internal bool isPaused = false; /// <summary> /// /// </summary> internal int index = 0; void Start() { ChangeScore(0); //隐藏游戏结束面板 if( gameOverCanvas ) gameOverCanvas.gameObject.SetActive(false); //获取存档中的最高分数 highScore = PlayerPrefs.GetInt(Application.loadedLevelName + "_HighScore", 0); int totalLanes = 0; int totalLanesIndex = 0; for(index = 0; index < lanes.Length; index++) { totalLanes += lanes[index].laneChance; } lanesList = new Lane[totalLanes]; for(index = 0; index < lanes.Length; index++) { int laneChanceCount = 0; while( laneChanceCount < lanes[index].laneChance ) { lanesList[totalLanesIndex] = lanes[index]; laneChanceCount++; totalLanesIndex++; } } int totalDrops = 0; int totalDropsIndex = 0; for(index = 0; index < objectDrops.Length; index++) { totalDrops += objectDrops[index].dropChance; } objectDropList = new Transform[totalDrops]; for(index = 0; index < objectDrops.Length; index++) { int dropChanceCount = 0; while( dropChanceCount < objectDrops[index].dropChance ) { objectDropList[totalDropsIndex] = objectDrops[index].droppedObject; dropChanceCount++; totalDropsIndex++; } } //从存档中获取当前玩家 currentPlayer = PlayerPrefs.GetInt("CurrentPlayer", currentPlayer); SetPlayer(currentPlayer); if( cameraObject == null ) cameraObject = GameObject.FindGameObjectWithTag("MainCamera").transform; CreateLane(precreateLanes); Pause(); } void Update() { if( isGameOver == true ) { if( Input.GetButtonDown(confirmButton) ) { Restart(); } if( Input.GetButtonDown(pauseButton) ) { MainMenu(); } } else { if( Input.GetButtonDown(pauseButton) ) { if( isPaused == true ) Unpause(); else Pause(); } if ( swipeControls == true ) { if ( swipeTimeoutCount > 0 ) swipeTimeoutCount -= Time.deltaTime; foreach ( Touch touch in Input.touches ) { if ( touch.phase == TouchPhase.Began ) { swipeStart = touch.position; swipeEnd = touch.position; swipeTimeoutCount = swipeTimeout; } if ( touch.phase == TouchPhase.Moved ) { swipeEnd = touch.position; } if( touch.phase == TouchPhase.Ended && swipeTimeoutCount > 0 ) { if( (swipeStart.x - swipeEnd.x) > swipeDistance && (swipeStart.y - swipeEnd.y) < -swipeDistance ) { MovePlayer("left"); } else if((swipeStart.x - swipeEnd.x) < -swipeDistance && (swipeStart.y - swipeEnd.y) > swipeDistance ) { MovePlayer("right"); } else if((swipeStart.y - swipeEnd.y) < -swipeDistance && (swipeStart.x - swipeEnd.x) < -swipeDistance ) { MovePlayer("forward"); } else if((swipeStart.y - swipeEnd.y) > swipeDistance && (swipeStart.x - swipeEnd.x) > swipeDistance ) { MovePlayer("backward"); } } } } } if( nextLanePosition - cameraObject.position.x < precreateLanes ) CreateLane(1); if( cameraObject ) { if( playerObjects[currentPlayer] ) cameraObject.position = new Vector3(Mathf.Lerp(cameraObject.position.x, playerObjects[currentPlayer].position.x, Time.deltaTime * 3), 0, Mathf.Lerp(cameraObject.position.z, playerObjects[currentPlayer].position.z, Time.deltaTime * 3)); if( deathLineObject ) { Vector3 newVector3 = deathLineObject.position; if( cameraObject.position.x > deathLineObject.position.x ) newVector3.x = cameraObject.position.x; if( isGameOver == false ) newVector3.x += deathLineSpeed * Time.deltaTime; deathLineObject.position = newVector3; } } } /// <summary> /// 创建小路 /// </summary> /// <param name="laneCount"小路数量></param> void CreateLane(int laneCount) { while( laneCount > 0 ) { laneCount--; int randomLane = Mathf.FloorToInt(Random.Range(0, lanesList.Length)); Transform newLane = Instantiate(lanesList[randomLane].laneObject, new Vector3(nextLanePosition, 0, 0), Quaternion.identity) as Transform; if( Random.value < lanesList[randomLane].itemChance ) { Transform newObject = Instantiate(objectDropList[Mathf.FloorToInt(Random.Range(0, objectDropList.Length))]) as Transform; Vector3 newVector = new Vector3(); newVector = newLane.position; newVector.z += Mathf.Round(Random.Range(-objectDropOffset, objectDropOffset)); newObject.position = newVector; } nextLanePosition += lanesList[randomLane].laneWidth; } } /// <summary> /// 改变分数 /// </summary> /// <param name="changeValue">改变的分数</param> void ChangeScore(int changeValue) { score += changeValue; //更新文本的分数显示 if( scoreText ) scoreText.GetComponent<Text>().text = score.ToString(); increaseCount += changeValue; //达到升级的条件,升级 if( increaseCount >= levelUpEveryCoins ) { increaseCount -= levelUpEveryCoins; LevelUp(); } } /// <summary> /// 升级,并增加游戏难度 /// </summary> void LevelUp() { //如果追杀物没有到达最大速度,增加它的速度 if( deathLineSpeed + deathLineSpeedIncrease < deathLineSpeedMax ) deathLineSpeed += deathLineSpeedIncrease; //播放升级声音 if( soundSourceTag != string.Empty && soundLevelUp ) GameObject.FindGameObjectWithTag(soundSourceTag).GetComponent<AudioSource>().PlayOneShot(soundLevelUp); } /// <summary> /// 暂停游戏 /// </summary> void Pause() { isPaused = true; Time.timeScale = 0; //显示暂停Canvas if( pauseCanvas ) pauseCanvas.gameObject.SetActive(true); //隐藏游戏Canvas if( gameCanvas ) gameCanvas.gameObject.SetActive(false); } /// <summary> /// 取消暂停 /// </summary> void Unpause() { isPaused = false; Time.timeScale = gameSpeed; //隐藏暂停Canvas if( pauseCanvas ) pauseCanvas.gameObject.SetActive(false); //显示游戏Canvas if( gameCanvas ) gameCanvas.gameObject.SetActive(true); } /// <summary> /// 游戏结束协程 /// </summary> /// <param name="delay">等待时间</param> IEnumerator GameOver(float delay) { yield return new WaitForSeconds(delay); isGameOver = true; //删除暂停面板 if( pauseCanvas ) Destroy(pauseCanvas.gameObject); //删除游戏面板 if( gameCanvas ) Destroy(gameCanvas.gameObject); //从存档中获取所有金币数量 int totalCoins = PlayerPrefs.GetInt( coinsPlayerPrefs, 0); //添加本局游戏获得的得分 totalCoins += score; //将新的总得分写入存档中 PlayerPrefs.SetInt( coinsPlayerPrefs, totalCoins); if( gameOverCanvas ) { //激活游戏结束面板 gameOverCanvas.gameObject.SetActive(true); //显示本次游戏得分 gameOverCanvas.Find("TextScore").GetComponent<Text>().text = "SCORE " + score.ToString(); //设置最高得分 if( score > highScore ) { highScore = score; PlayerPrefs.SetInt(Application.loadedLevelName + "_HighScore", score); } //将最高得分显示在文本上 gameOverCanvas.Find("TextHighScore").GetComponent<Text>().text = "HIGH SCORE " + highScore.ToString(); } } /// <summary> /// 重新开始 /// </summary> void Restart() { Application.LoadLevel(Application.loadedLevelName); } /// <summary> /// 回到主目录 /// </summary> void MainMenu() { Application.LoadLevel(mainMenuLevelName); } /// <summary> /// 根据玩家编号,激活选择的玩家 /// </summary> /// <param name="playerNumber"></param> void SetPlayer( int playerNumber ) { for(index = 0; index < playerObjects.Length; index++) { if ( index != playerNumber ) playerObjects[index].gameObject.SetActive(false); else playerObjects[index].gameObject.SetActive(true); } } /// <summary> /// 移动玩家 /// </summary> /// <param name="moveDirection">移动方向</param> void MovePlayer( string moveDirection ) { if ( playerObjects[currentPlayer] ) playerObjects[currentPlayer].SendMessage("Move", moveDirection); } } }
using UnityEngine; namespace RoadCrossing { /// <summary> /// 小路 /// </summary> public class RCGLane : MonoBehaviour { /// <summary> /// transform缓存 /// </summary> internal Transform thisTransform; /// <summary> /// 起始位置 /// </summary> public Vector3 laneStart = new Vector3(0, 0, -7); /// <summary> /// 结束位置 /// </summary> public Vector3 laneEnd = new Vector3(0, 0, 7); /// <summary> /// 小路上候选的移动物体数组 /// </summary> public Transform[] movingObjects; /// <summary> /// 小路上的移动物体数组 /// </summary> internal Transform[] movingObjectsList; /// <summary> /// 小路上允许存在的移动物体的数量范围 /// </summary> public Vector2 movingObjectsNumber = new Vector2(1, 3); /// <summary> /// 移动物体之间的间隔 /// </summary> public float minimumObjectGap = 1; /// <summary> /// 所有物体的移动速度范围 /// </summary> public Vector2 moveSpeed = new Vector2(0.5f, 1); /// <summary> /// 物体的移动方向 /// </summary> internal int moveDirection = 1; /// <summary> /// 是否随机方向 /// </summary> public bool randomDirection = true; void Start() { thisTransform = transform; //满足条件改变移动方向 if( randomDirection == true && Random.value > 0.5f ) moveDirection = -1; //随机选择移动速度 moveSpeed.x = Random.Range(moveSpeed.x, moveSpeed.y); //计算路的长度 float laneLength = Vector3.Distance(laneStart, laneEnd); //设置这条路上移动物体的数量 int currentMovingObjectsNumber = Mathf.FloorToInt(Random.Range(movingObjectsNumber.x, movingObjectsNumber.y)); //创建移动物体列表 movingObjectsList = new Transform[currentMovingObjectsNumber]; for(int index = 0; index < currentMovingObjectsNumber; index++) { //创建一个随机的移动物体 Transform newMovingObject = Instantiate(movingObjects[Mathf.FloorToInt(Random.Range(0, movingObjects.Length))]) as Transform; //在小路起点放置这个物体 newMovingObject.position = thisTransform.position + laneStart; //让这个物体朝向路的终点 newMovingObject.LookAt(thisTransform.position + laneEnd); newMovingObject.Translate(Vector3.forward * index * laneLength / currentMovingObjectsNumber, Space.Self); newMovingObject.Translate(Vector3.forward * Random.Range(minimumObjectGap, laneLength / movingObjectsNumber.x - minimumObjectGap), Space.Self); //将这个物体添加到移动物体列表 movingObjectsList[index] = newMovingObject; } foreach( Transform movingObject in movingObjectsList ) { //根据方向设置移动物体的朝向,起点或终点 if( moveDirection == 1 ) movingObject.LookAt(thisTransform.position + laneEnd); else movingObject.LookAt(thisTransform.position + laneStart); //如果又动画组件,播放动画 if( movingObject.GetComponent<Animation>() ) { //根据物体的移动速度设置动画的播放速度 movingObject.GetComponent<Animation>()[movingObject.GetComponent<Animation>().clip.name].speed = moveSpeed.x; } } } void Update() { foreach( Transform movingObject in movingObjectsList ) { if( movingObject ) { //如果移动方向等于1 if( moveDirection == 1 ) { //从起点向小路终点移动 movingObject.position = Vector3.MoveTowards(movingObject.position, thisTransform.position + laneEnd, moveSpeed.x * Time.deltaTime); //如果到达终点,将游戏物体放到起点 if( movingObject.position == thisTransform.position + laneEnd ) { movingObject.position = thisTransform.position + laneStart; movingObject.LookAt(thisTransform.position + laneEnd); } } //如果移动方向不等于1 else { //从终点向小路起点移动 movingObject.position = Vector3.MoveTowards(movingObject.position, thisTransform.position + laneStart, moveSpeed.x * Time.deltaTime); //如果到达起点,将游戏物体放到终点 if( movingObject.position == thisTransform.position + laneStart ) { movingObject.position = thisTransform.position + laneEnd; movingObject.LookAt(thisTransform.position + laneStart); } } } } } /// <summary> /// Gizmos下画起始点和结束点 /// </summary> void OnDrawGizmos() { Gizmos.color = Color.green; Gizmos.DrawSphere(transform.position + laneStart, 0.2f); Gizmos.color = Color.red; Gizmos.DrawSphere(transform.position + laneEnd, 0.2f); } } }
using UnityEngine; namespace RoadCrossing { /// <summary> /// 加载场景和URL /// </summary> public class RCGLoadLevel : MonoBehaviour { /// <summary> /// 加载URL /// </summary> /// <param name="urlName"></param> public void LoadURL(string urlName) { Application.OpenURL(urlName); } /// <summary> /// 加载指定场景 /// </summary> /// <param name="levelName"></param> public void LoadLevel(string levelName) { Application.LoadLevel(levelName); } /// <summary> /// 重新加载当前场景 /// </summary> public void RestartLevel() { Application.LoadLevel(Application.loadedLevelName); } } }
using UnityEngine; using RoadCrossing.Types; namespace RoadCrossing { /// <summary> /// 玩家 /// </summary> public class RCGPlayer : MonoBehaviour { /// <summary> /// 缓存transform /// </summary> internal Transform thisTransform; /// <summary> /// 游戏控制器 /// </summary> internal GameObject gameController; /// <summary> /// 移动速度 /// </summary> public float speed = 0.1f; /// <summary> /// 是否正在移动 /// </summary> internal bool isMoving = false; /// <summary> /// 上一个位置 /// </summary> internal Vector3 previousPosition; /// <summary> /// 目标位置 /// </summary> internal Vector3 targetPosition; /// <summary> /// 限制玩家移动的物体 /// </summary> public Transform moveLimits; /// <summary> /// 移动动画 /// </summary> public AnimationClip animationMove; /// <summary> /// 获得金币的动画 /// </summary> public AnimationClip animationCoin; /// <summary> /// 死亡效果的动画列表 /// </summary> public Transform[] deathEffect; /// <summary> /// 从不能移动到能移动的持续时间 /// </summary> public float moveDelay = 0; /// <summary> /// 移动声音 /// </summary> public AudioClip[] soundMove; /// <summary> /// 获得金币的声音 /// </summary> public AudioClip[] soundCoin; /// <summary> /// AudioSource所属的游戏物体标签 /// </summary> public string soundSourceTag = "GameController"; void Start() { thisTransform = transform; targetPosition = thisTransform.position; gameController = GameObject.FindGameObjectWithTag("GameController"); } void Update() { //让限制玩家移动的物体 跟随玩家移动 if( moveLimits ) { Vector3 newPosition = new Vector3(); newPosition.x = thisTransform.position.x; moveLimits.position = newPosition; } //计算移动延迟 if( moveDelay > 0 ) moveDelay -= Time.deltaTime; //不处于移动状态 移动延迟<=0 时间缩放>0 if( isMoving == false && moveDelay <= 0 && Time.timeScale > 0 ) { //垂直抽没有输入值时,才可以左右移动 if( Input.GetAxisRaw("Vertical") == 0 ) { //向右移动 if( Input.GetAxisRaw("Horizontal") > 0 ) { Move("right"); } //向左移动 if( Input.GetAxisRaw("Horizontal") < 0 ) { // Move one step to the left Move("left"); } } //水平轴没有输入值,才可以前后移动 if( Input.GetAxisRaw("Horizontal") == 0 ) { //向前移动 if( Input.GetAxisRaw("Vertical") > 0 ) { Move("forward"); } //向后移动 if( Input.GetAxisRaw("Vertical") < 0 ) { Move("backward"); } } } //其余的情况 移动玩家到目标位置 else { //保持向前移动直到 到达目标位置 if( thisTransform.position != targetPosition ) { //将玩家移动到目标位置 thisTransform.position = Vector3.MoveTowards(transform.position, targetPosition, Time.deltaTime * speed); } else { //表示玩家不在移动状态中 isMoving = false; } } } /// <summary> /// 移动 /// </summary> /// <param name="moveDirection">移动方向</param> void Move(string moveDirection) { if( isMoving == false && moveDelay <= 0 ) { isMoving = true; switch( moveDirection.ToLower() ) { //向前移动 case "forward": //让玩家朝前 Vector3 newEulerAngle = new Vector3(); newEulerAngle.y = 0; thisTransform.eulerAngles = newEulerAngle; //计算目标位置 targetPosition = thisTransform.position + new Vector3(1, 0, 0); //让玩家在固定的网格里移动 targetPosition.x = Mathf.Round(targetPosition.x); targetPosition.z = Mathf.Round(targetPosition.z); //记录上一个位置,用来在遇到障碍物的时候,让玩家回到上一个位置 previousPosition = thisTransform.position; break; case "backward": //让玩家朝后 newEulerAngle = new Vector3(); newEulerAngle.y = 180; thisTransform.eulerAngles = newEulerAngle; //记录上一个位置,用来在遇到障碍物的时候,让玩家回到上一个位置 previousPosition = thisTransform.position; //让玩家在固定的网格里移动 targetPosition.x = Mathf.Round(targetPosition.x); targetPosition.z = Mathf.Round(targetPosition.z); //计算目标位置 targetPosition = thisTransform.position + new Vector3(-1, 0, 0); break; case "right": //让玩家朝向右 newEulerAngle = new Vector3(); newEulerAngle.y = 90; thisTransform.eulerAngles = newEulerAngle; //记录上一个位置,用来在遇到障碍物的时候,让玩家回到上一个位置 previousPosition = thisTransform.position; //让玩家在固定的网格里移动 targetPosition.x = Mathf.Round(targetPosition.x); targetPosition.z = Mathf.Round(targetPosition.z); //计算目标位置 targetPosition = thisTransform.position + new Vector3(0, 0, -1); break; case "left": //让玩家朝向左 newEulerAngle = new Vector3(); newEulerAngle.y = -90; thisTransform.eulerAngles = newEulerAngle; //记录上一个位置,用来在遇到障碍物的时候,让玩家回到上一个位置 previousPosition = thisTransform.position; //让玩家在固定的网格里移动 targetPosition.x = Mathf.Round(targetPosition.x); targetPosition.z = Mathf.Round(targetPosition.z); //计算目标位置 targetPosition = thisTransform.position + new Vector3(0, 0, 1); break; default: //让玩家朝前 newEulerAngle = new Vector3(); newEulerAngle.y = 0; thisTransform.eulerAngles = newEulerAngle; //计算目标位置 targetPosition = thisTransform.position + new Vector3(1, 0, 0); //归一化目标位置 targetPosition.Normalize(); //记录上一个位置,用来在遇到障碍物的时候,让玩家回到上一个位置 previousPosition = thisTransform.position; break; } //满足条件 播放移动动画 if( GetComponent<Animation>() && animationMove ) { GetComponent<Animation>().Stop(); GetComponent<Animation>().Play(animationMove.name); //基于移动速度设置动画速度 GetComponent<Animation>()[animationMove.name].speed = speed; //满足条件播放移动声音 if( soundSourceTag != string.Empty && soundMove.Length > 0 ) GameObject.FindGameObjectWithTag(soundSourceTag).GetComponent<AudioSource>().PlayOneShot(soundMove[Mathf.FloorToInt(Random.value * soundMove.Length)]); } } } /// <summary> /// 取消玩家的移动,将玩家弹回到前一个位置 /// </summary> void CancelMove(float moveDelayTime) { //满足条件播放动画 if( GetComponent<Animation>() && animationMove ) { //基于移动速度,倒放动画 GetComponent<Animation>()[animationMove.name].speed = -speed; } //将目标位置设置为前一个位置 targetPosition = previousPosition; //设置移动延迟 moveDelay = moveDelayTime; } /// <summary> /// 获得金币 /// </summary> void AddCoin(int addValue) { //调用游戏控制里的改变分数方法 gameController.SendMessage("ChangeScore", addValue); //播放获得金币动画 if( GetComponent<Animation>() && animationCoin && animationMove ) { GetComponent<Animation>()[animationCoin.name].layer = 1; GetComponent<Animation>().Play(animationCoin.name); GetComponent<Animation>()[animationCoin.name].weight = 0.5f; } //播放获得金币声音 if( soundSourceTag != string.Empty && soundCoin.Length > 0 ) GameObject.FindGameObjectWithTag(soundSourceTag).GetComponent<AudioSource>().PlayOneShot(soundCoin[Mathf.FloorToInt(Random.value * soundCoin.Length)]); } /// <summary> /// 死亡 /// </summary> /// <param name="deathType">死亡效果类型</param> void Die(int deathType) { //调用游戏控制器的游戏结束方法 gameController.SendMessage("GameOver", 0.5f); //创建死亡特效 if( deathEffect.Length > 0 ) { Instantiate(deathEffect[deathType], thisTransform.position, thisTransform.rotation); } //销毁游戏物体 Destroy(gameObject); } } }
using UnityEngine; namespace RoadCrossing { /// <summary> /// 播放声音 /// </summary> public class RCGPlaySound : MonoBehaviour { /// <summary> /// 声音数组 /// </summary> public AudioClip[] audioList; /// <summary> /// AudioSource所在物体的标签 /// </summary> public string audioSourceTag = "GameController"; /// <summary> /// 游戏开始时是否播放 /// </summary> public bool playOnStart = true; void Start() { if( playOnStart == true ) PlaySound(); } /// <summary> /// 播放声音 /// </summary> void PlaySound() { if( audioSourceTag != string.Empty && audioList.Length > 0 ) GameObject.FindGameObjectWithTag(audioSourceTag).GetComponent<AudioSource>().PlayOneShot(audioList[Mathf.FloorToInt(Random.value * audioList.Length)]); } /// <summary> /// 根据索引播放声音 /// </summary> void PlaySound(int soundIndex) { if( audioSourceTag != string.Empty && audioList.Length > 0 ) GameObject.FindGameObjectWithTag(audioSourceTag).GetComponent<AudioSource>().PlayOneShot(audioList[soundIndex]); } } }
using UnityEngine; namespace RoadCrossing { /// <summary> /// 随机化物体的颜色 /// </summary> public class RCGRandomizeColor : MonoBehaviour { /// <summary> /// 颜色数组 /// </summary> public Color[] colorList; void Start() { //随机选择一个颜色 int randomColor = Mathf.FloorToInt(Random.Range(0, colorList.Length)); //将颜色应用到物体和子物体上 Component[] comps = GetComponentsInChildren<Renderer>(); foreach( Renderer part in comps ) part.GetComponent<Renderer>().material.color = colorList[randomColor]; } } }
using UnityEngine; namespace RoadCrossing { /// <summary> /// 随机化物体的旋转,缩放和颜色 /// </summary> public class RCGRandomizeTransform : MonoBehaviour { /// <summary> /// x轴的旋转范围 /// </summary> public Vector2 rotationRangeX = new Vector2(0, 360); /// <summary> /// y轴的旋转范围 /// </summary> public Vector2 rotationRangeY = new Vector2(0, 360); /// <summary> /// z轴的旋转范围 /// </summary> public Vector2 rotationRangeZ = new Vector2(0, 360); /// <summary> /// x轴缩放范围 /// </summary> public Vector2 scaleRangeX = new Vector2(1, 1.3f); /// <summary> /// y轴缩放范围 /// </summary> public Vector2 scaleRangeY = new Vector2(1, 1.3f); /// <summary> /// z轴缩放范围 /// </summary> public Vector2 scaleRangeZ = new Vector2(1, 1.3f); /// <summary> /// 是否统一比例缩放 /// </summary> public bool uniformScale = true; /// <summary> /// 颜色列表 /// </summary> public Color[] colorList; void Start() { //随机旋转 transform.localEulerAngles = new Vector3(Random.Range(rotationRangeX.x, rotationRangeX.y), Random.Range(rotationRangeY.x, rotationRangeY.y), Random.Range(rotationRangeZ.x, rotationRangeZ.y)); //如果是统一缩放,让y,z轴基于x轴的比例缩放 if( uniformScale == true ) scaleRangeY = scaleRangeZ = scaleRangeX; //随机缩放 transform.localScale = new Vector3(Random.Range(scaleRangeX.x, scaleRangeX.y), Random.Range(scaleRangeY.x, scaleRangeY.y), Random.Range(scaleRangeZ.x, scaleRangeZ.y)); //随机颜色 int randomColor = Mathf.FloorToInt(Random.Range(0, colorList.Length)); Component[] comps = GetComponentsInChildren<Renderer>(); foreach( Renderer part in comps ) part.GetComponent<Renderer>().material.color = colorList[randomColor]; } } }
using UnityEngine; namespace RoadCrossing { /// <summary> /// 经过一段时间后删除物体,用来在特效播放完成后删除特效 /// </summary> public class RCGRemoveAfter : MonoBehaviour { //删除物体的等待时间 public float removeAfter = 1; void Update() { removeAfter -= Time.deltaTime; if( removeAfter <= 0 ) Destroy(gameObject); } } }
using UnityEngine; using System.Collections; using UnityEngine.UI; using RoadCrossing.Types; namespace RoadCrossing { /// <summary> /// 商店 /// </summary> public class RCGShop : MonoBehaviour { /// <summary> /// 剩余的金币数量 /// </summary> public int coinsLeft = 0; /// <summary> /// 显示金币的文本 /// </summary> public Transform coinsText; /// <summary> /// 玩家的金币值 /// </summary> public string coinsPlayerPrefs = "Coins"; /// <summary> /// 商店道具列表 /// </summary> public ShopItem[] shopItems; /// <summary> /// 当前道具 /// </summary> public int currentItem = 0; /// <summary> /// 存档里的当前玩家键 /// </summary> public string playerPrefsName = "CurrentPlayer"; /// <summary> /// 道具的未被选择时的颜色 /// </summary> public Color unselectedColor = new Color(0.6f,0.6f,0.6f,1); /// <summary> /// 道具的选中颜色 /// </summary> public Color selectedColor = new Color(1,1,1,1); /// <summary> /// 暂未使用 /// </summary> public Color errorColor = new Color(1,0,0,1); void Start() { //获取剩余金币 coinsLeft = PlayerPrefs.GetInt(coinsPlayerPrefs, coinsLeft); //更新金币文本 coinsText.GetComponent<Text>().text = coinsLeft.ToString(); //获取当前道具 currentItem = PlayerPrefs.GetInt(playerPrefsName, currentItem); //更新所有道具 UpdateItems(); } /// <summary> /// 更新道具 /// </summary> void UpdateItems() { for ( int index = 0 ; index < shopItems.Length ; index++ ) { //从存档中获取这个道具的解锁状态 shopItems[index].lockState = PlayerPrefs.GetInt(shopItems[index].playerPrefsName, shopItems[index].lockState); //设置道具的颜色为 未选择的颜色 shopItems[index].itemButton.GetComponent<Image>().color = unselectedColor; //如果这个道具已经解锁 if ( shopItems[index].lockState > 0 ) { //禁用显示价格的物体 shopItems[index].itemButton.Find("TextPrice").gameObject.SetActive(false); //高亮当前选择的物体的颜色 if ( index == currentItem ) shopItems[index].itemButton.GetComponent<Image>().color = selectedColor; } //如果没有解锁 else { //更新这个道具的价格 shopItems[index].itemButton.Find("TextPrice").GetComponent<Text>().text = shopItems[index].costToUnlock.ToString(); } } } /// <summary> /// 买道具 /// </summary> /// <param name="itemNumber"></param> void BuyItem( int itemNumber ) { //如果这个道具已解锁,选择这个道具 if ( shopItems[itemNumber].lockState > 0 ) { SelectItem(itemNumber); } //如果有足够的金币,消耗金币买这个道具 else if ( shopItems[itemNumber].costToUnlock <= coinsLeft ) { //解锁道具 shopItems[itemNumber].lockState = 1; //在存档中更新这个道具的状态 PlayerPrefs.SetInt(shopItems[itemNumber].playerPrefsName, shopItems[itemNumber].lockState); //扣除金币 coinsLeft -= shopItems[itemNumber].costToUnlock; //更新文本 coinsText.GetComponent<Text>().text = coinsLeft.ToString(); //将剩余金币写入Prefs PlayerPrefs.SetInt(coinsPlayerPrefs, coinsLeft); //选择道具 SelectItem(itemNumber); } UpdateItems(); } /// <summary> /// 选择道具 /// </summary> /// <param name="itemNumber"></param> void SelectItem( int itemNumber ) { currentItem = itemNumber; PlayerPrefs.SetInt( playerPrefsName, itemNumber); } } }
using UnityEngine; using System.Collections; using UnityEngine.UI; namespace RoadCrossing { /// <summary> /// 显示文本 /// </summary> public class RCGTextByPlatform : MonoBehaviour { /// <summary> /// 显示在PC/Mac/Webplayer中的文本 /// </summary> public string computerText = "CLICK TO START"; /// <summary> /// 显示在Android/iOS/WinPhone中的文本 /// </summary> public string mobileText = "TAP TO START"; /// <summary> /// 显示在Playstation/Xbox/Wii中的文本 /// </summary> public string consoleText = "PRESS 'A' TO START"; void Start() { #if UNITY_STANDALONE || UNITY_WEBPLAYER GetComponent<Text>().text = computerText; #endif #if IPHONE || ANDROID || UNITY_BLACKBERRY || UNITY_WP8 || UNITY_METRO GetComponent<Text>().text = mobileText; #endif #if UNITY_WII || UNITY_PS3 || UNITY_XBOX360 GetComponent<Text>().text = consoleText; #endif } } }
using UnityEngine; using System.Collections; using UnityEngine.UI; namespace RoadCrossing { /// <summary> /// 声音开关 /// </summary> public class RCGToggleSound:MonoBehaviour { /// <summary> /// 播放声音的物体 /// </summary> public Transform soundObject; /// <summary> /// 存档中的名称 /// </summary> public string playerPref = "SoundVolume"; /// <summary> /// 声音的当前音量 /// </summary> internal float currentState = 1; void Awake() { if( soundObject ) currentState = PlayerPrefs.GetFloat(playerPref, soundObject.GetComponent<AudioSource>().volume); else currentState = PlayerPrefs.GetFloat(playerPref, currentState); SetSound(); } /// <summary> /// 设置声音大小 /// </summary> void SetSound() { //设置声音存档 PlayerPrefs.SetFloat(playerPref, currentState); Color newColor = GetComponent<Image>().material.color; //根据声音存档值设置按钮透明度 if( currentState == 1 ) newColor.a = 1; else newColor.a = 0.5f; //应用透明度 GetComponent<Image>().color = newColor; //设置音量 if( soundObject ) soundObject.GetComponent<AudioSource>().volume = currentState; } /// <summary> /// 开关声音 /// </summary> void ToggleSound() { currentState = 1 - currentState; SetSound(); } /// <summary> /// 播放声音 /// </summary> void StartSound() { if( soundObject ) soundObject.GetComponent<AudioSource>().Play(); } } }
视频:https://pan.baidu.com/s/1qYPhpsK
项目:https://pan.baidu.com/s/1mi5C7s0