++U3D小案例简述
++++这里是立钻哥哥汇总的几个U3D小案例,通过案例学习U3D的基本编程和技巧。
++++小案例会不断更新补充,通过学习掌握U3D的编程和思想。
++小案例目录:
++++小案例001、贪吃蛇Demo
++++小案例002、飞机大战Demo
++++小案例003、MVC框架(提升等级案例)
++++小案例004、简单背包案例
++++小案例005、塔防Demo
++++小案例006、秘密行动Demo
++++小案例007、A_Star
++++小案例008、血条LiftBar跟随
++++小案例009、见缝插针StickPin
++++小案例010、UnityNetDemo
++++小案例011、SocketFileRecv
++++小案例012、切水果CutFruitDemo
++++小案例013、吃鸡_友军方位UV
++++小案例014、数据库背包SqliteEZ_Bag
++++小案例015、Json数据存储
++++小案例016、关卡系统LevelSystem
++++超级Demo:斗地主
++小案例001:贪吃蛇demo
++++Cube_Snake_Body.prefab
++++Cube_Snake_Food.prefab
++++Scene02Snake.unity
++++SnakeMoveScript.cs
(C:\000-ylzServ_U3D_Pro\小案例001\Assets\DemoSnake\SnakeMoveScript.cs)
++SnakeMoveScript.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Linq;
using UnityEngine.SceneManagement; //引入场景控制器
public class SnakeMoveScript : MonoBehaviour{
/*
蛇头移动:
#1、蛇头移动(默认方向朝上,wsad控制移动)
#2、生成食物(随机生成)
#3、吃到食物后生成蛇身
#4、游戏结束
*/
//1、蛇头移动(默认方向朝上,wsad控制移动)
Vector2 dirV2Move = Vector2.up; //默认向上移动
public float speedMoveRate= 5f; //速度
public GameObject snakeBody; //身体
public GameObject snakeFood; //食物
//创建集合存放身体(蛇身)
List<Transform> bodyList = new List<Transform>();
bool isCreate = false; //控制是否创建身体
//Use this for initialization
void Start(){
for(int i =0; i <5; i++){
Invoke(“CreatFood”,1.0f); //延迟1秒,调用Creat
}
//在游戏开始1.5秒调用Move方法,然后每隔0.2秒再重复调用
InvokeRepeating(“SnakeMove”,1.5f, 0.2f); //每几秒重复调用这个函数
}
//Update is called once per frame
void Update(){
dirV2Move = GetMoveDir(); //获取控制方向
}
//触发检测
void OnTriggerEnter(Collider other){
if(other.gameObject.CompareTag(“SnakeFood”)){
//如果碰撞到的是食物
Destroy(other.gameObject); //销毁食物
isCreate = true;
Invoke(“CreatFood”,0.3f); //0.3秒之后创建食物
}else if(other.gameObject.CompareTag(“SnakeBody”)){
//碰到自己
Debug.Log(“yanlzPrint:碰到自己身体了,游戏结束!”);
//todo优化碰到自己身体处理事件
}else{
Debug.Log(“yanlzPrint:碰到墙了,游戏重新开始!”);
SceneManager.LoadScene(“Scene02Snake”); //重新加载场景(新一局)
}
}
//自定义函数
//获取方向控制
//1、蛇头移动(默认方向朝上,wsad控制移动)
Vector2 GetMoveDir(){
if(Input.GetKeyDown(KeyCode.W)){
dirV2Move = Vector2.up;
}else if(Input.GetKeyDown(KeyCode.S)){
dirV2Move = Vector2.down;
}else if(Input.GetKeyDown(KeyCode.A)){
dirV2Move = Vector2.left;
}else if(Input.GetKeyDown(KeyCode.D)){
dirV2Move = Vector2.right;
}
return dirV2Move;
}
//生成食物
void CreatFood(){
Vector3 foodPosV3 = new Vector3(Random.Range(-14,14),Random.Range(-14,14),0);
Instantiate(snakeFood,foodPosV3,Quaternion.identity);
}
//移动方法
void SnakeMove(){
Vector3 curPos= transform.position; //移动之前,首先记录蛇头位置
//创建蛇身
if(isCreate == true){
//创建身体
Vector3 createBodyPosV3 = curPos; //在蛇头位置创建
GameObject createBodyObj;
createBodyObj = Instantiate(snakeBody,createBodyPosV3,Quaternion.identity);
Color colorRandom = new Color(Random.value,Random.value,Random.value);
createBodyObj.GetComponent<MeshRenderer>().material.color = colorRandom;
bodyList.Insert(0,createBodyObj.transform); //将身体插入到集合当中
isCreate = false; //将创建标志置为false
}else if(bodyList.Count>0){
//身体个数大于0
//蛇身最后位置 //当前蛇头位置
bodyList.Last().position = curPos; //更新蛇身位置
//list里面元素进行交换位置,最后一个元素添加到最前面
bodyList.Insert(0, bodyList.Last());
bodyList.RemoveAt(bodyList.Count -1); //移除最后一个元素(因为其已经被加入到第一个位置)
}
transform.Translate(dirV2Move); //改变当前蛇头位置
}
}
++小案例002、耳轮跳demo
++++HudText.cs
++++BallFallScript.cs
++++CreateGap.cs
++++CreateRing.cs
++++CreateTrap.cs
++++GameMgr.cs
++++RingInfo.cs
++++RotatePillar.cs
++++SectorInfor.cs
(D:\zz_DemoPro()-\小案例002、耳轮跳-HelixJump-\Assets\HudText.cs)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class HudText:MonoBehaviour{
private void Start(){
GameObject.Destroy(gameObject,1f);
}
//下落
private void Update(){
transform.position -= Vector3.up*Time.deltaTime* 0.5f;
GetComponent<CanvasGroup>().alpha -= Time.deltaTime;
}
//设置值
public void SetText(string s){
transform.GetComponentInChildren<Text>().text=s;
}
}
(D:\zz_DemoPro()-\小案例002、耳轮跳-HelixJump-\Assets\Project\Scripts\BallFallScript.cs)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
public class BallFallScript:MonoBehaviour{
float g = -9.8f;
float v = 0;
float timer = 0;
//1m的间距最大速度达到4.4m/s,这里考虑小球和平板的高度,取3.5f,也就是说最大速度为3.5f
float maxV = 3.5f;
public int power =0; //小球势能
public int powerToggle =3; //达到层数,可以获得击碎能力
private void Update(){
Fall();
}
private void Fall(){
v = v + g *Time.delatTime;
v = Mathf.Clamp(v, -maxV, maxV);
transform.position += transform.up*Time.deltaTime*v;
}
private void LateUpdate(){
float y = Camera.main.WorldToScreenPoint(transform.position).y;
if(y /Screen.height<0.7f){
Camera.main.transform.SetParent(transform);
}else{
Camera.main.transform.SetParent(null);
}
}
//碰撞结算
private void OnCollisionEnter(Collision collision){
v =maxV;
Camera.main.transform.SetParent(null);
SectorInfo si =collision.collider.GetComponent<SectorInfo>();
if(power>=powerToggle){
si.transform.parent.GetComponent<RingInfo>().Explosion();
}else if(si.IsTrap&&si.transform.parent.GetComponent<RingInfo>().isBreaken == false){
GameObject.FindObjectOfType<GameMgr>().GameOver();
}
power = 0;
}
}
(D:\zz_DemoPro()-\小案例002、耳轮跳-HelixJump-\Assets\Project\Scripts\CreateGap.cs)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CreateGap:MonoBehaviour{
public int minGapGroup=1;
public int maxGapGroup=3;
public int minGap=2;
public int maxGap=4;
MeshCollider[] sectors;
private void Start(){
sectors = GetComponentsInChildren<MeshCollider>()
int group = Random.Range(minGapGroup, maxGapGroup+1);
for(int i =0; i<group; i++){
int pos = Random.Range(0,secotrs.Length);
int gaps = Random.Range(minGap,maxGap+1);
for(int j=0;j <gaps; j++){
sectors[(pos+j) %sectors.Length].gameObject.SetActive(false);
}
}
}
}
(D:\zz_DemoPro()-\小案例002、耳轮跳-HelixJump-\Assets\Project\Scripts\CreateRing.cs)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
public class CreateRing:MonoBehaviour{
public GameObject ringPre;
private void Start(){
for(int i = 0; i <100;i++){
GameObject ring = GameObject.Instantiate(ringPre,new Vector3(0, -50+i *1f),Quaternion.identity);
ring.GetComponent<RingInfo>().index = i;
ring.transform.SetParent(transform);
}
}
}
(D:\zz_DemoPro()-\小案例002、耳轮跳-HelixJump-\Assets\Project\Scripts\CreateTrap.cs)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CreateTrap:MonoBehaviour{
public int minTrapGroup = 1;
public int maxTrapGroup =3;
public int minTrap = 2;
public int maxTrap = 4;
MeshCollider[] sectors;
private void Start(){
sectors = GetComponentsInChildren<MeshCollider>();
int group = Random.Range(minTrapGroup,maxTrapGroup+1);
for(int i = 0; i<group;i++){
int pos = Random.Range(0, sectors.Length);
int gaps = Random.Range(minTrap,maxTrap+1);
for(int j=0; j<gaps; j++){
int index = (pos+ j) %sectors.Length;
if(sectors[index].gameObject.activeSelf&&transform.GetComponent<RingInfo>().index<95){
sectors[index].GetComponent<MeshRenderer>.material.color = Color.red;
sectors[index].GetComponent<SectorInfo>.IsTrap=true;
}
}
}
}
}
(D:\zz_DemoPro()-\小案例002、耳轮跳-HelixJump-\Assets\Project\Scripts\GameMgr.cs)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
public class GameMgr:MonoBehaviour{
//设置分数
public Text scoreText;
public Text levelText;
public Button restartBtn;
public int score=0;
public bool gameOver=false;
priavate void Awake(){
Time.timeScale=0;
Screen.SetResolution(750,1334,false);
}
private void Start(){
restartBtn.onClick.AddListener(GameStart);
restartBtn.gameObject.SetActive(false);
}
public void GameStart(){
SceneManger.LoadScene(“Demo002_HelixJump_Lovezuanzuan”);
}
public void GameOver(){
gameOver = true;
Time.timeScale = 0;
restartBtn.gameObject.SetActive(true);
}
private void Update(){
if(Input.GetMouseButtonDown(0) && gameOver ==false){
Time.timeScale = 1;
}
}
public void AddScore(int s, RingInfoinfo){
score += s;
HudText hud = ((GameObject)GameObject.Instantiate(Resources.Load(“HudText”))).transform.GetComponent<HudText>();
hud.SetText(“+” + s);
scoreText.text = score.ToString();
levelText.text = info.index.ToString();
}
}
(D:\zz_DemoPro()-\小案例002、耳轮跳-HelixJump-\Assets\Project\Scripts\RingInfo.cs)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//立钻哥哥:环信息
public class RingInfo:MonoBehaviour{
public int index; //层数
public bool isBreaken=false; //是否击毁
GameObject ball;
private void Start(){
ball = GameObject.Find(“Ball”);
}
private void Update(){
if(ball == null){
return;
}
if(ball.transform.position.y < transform.position.y - 0.1f && !isBreaken){
isBreaken = true;
//提高小球势能
GameObject.Find(“Ball”).GetComponent<BallFallScript>().power += 1;
int power=GameObject.Find(“Ball”).GetComponent<BallFallScript>().power;
//计算分数,与通过的势能相等
GameObject.FindObjectOfType<GameMgr>().AddScore(power*4,this);
Explosion();
}
}
public void Explosion(){
//打散散开
for(int i=0; i <transform.childCount; i++){
if(transform.GetChild(i).gameObject.activeSelf == false){
continue;
}
Rigidbody rig;
if((rig = transform.GetChild(i).gameObject.GetComponent<Rigidbody>()) == null){
rig = transform.GetChild(i).gameObject.AddComponent<Rigidbody>();
}
rig.AddForce((transform.GetChild(i).forward+Vector3.up*Random.Range(0.3f,1)) * Random.Range(40,80));
transform.GetChild(i).GetComponent<MeshCollider>().enabled = false;
}
StartCoroutine(ChangeAlpha()); //渐隐
GameObject.Destroy(gameObject,3); //3s后销毁
}
IEnumerator ChangeAlpha(){
float alpha = 1;
while(true){
alpha -= Time.deltaTime;
for(int i =0; i < transform.childCount; i++){
if(transform.GetChild(i).gameObject.activeSelf == false){
continue;
}
Material mat =transform.GetChild(i).GetComponent<MeshRenderer>.material;
transform.GetChild(i).GetComponent<MeshRenderer>.material.color= new Color(mat.color.r,mat.color.g,mat.color.b,alpha)
}
yield return null;
}
}
}
(D:\zz_DemoPro()-\小案例002、耳轮跳-HelixJump-\Assets\Project\Scripts\RotatePillar.cs)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
public class RotatePillar:MonoBehaviour{
private void Update(){
if(Input.GetMouseButton(0)){
float y =Input.GetAxis(“Mouse X”);
transform.Rotate(Vector3.up, -Time.deltaTime*180*y);
}
}
}
(D:\zz_DemoPro()-\小案例002、耳轮跳-HelixJump-\Assets\Project\Scripts\SectorInfo.cs)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
public class SectorInfo:MonoBehaviour{
public bool IsTrap{ get; set; }
}
++小案例003、MVC框架(提升等级案例)
++++PlayerMsgController.cs
++++PlayerMsgView.cs
++++PlayerScript.cs
(C:\000-ylzServ_DemoPro\小案例003\Assets\PlayerMsgController.cs)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//Controller层:
public class PlayerMsgController : MonoBehaviour{
public static PlayerMsgController controller;
private int levelUpValue=20;
void Awake(){
controller = this;
}
void Start(){
PlayerScript.GetMod().PlayerLevel = 1;
PlayerScript.GetMod().PlayerExperience = 0;
PlayerScript.GetMod().PlayerFullExperience = 100;
PlayerScript.GetMod().GoldNum = 0;
}
//提升经验按钮点击事件
public void OnExperienceUpButtonClick(){
PlayerScript.GetMod().PlayerExperience += levelUpValue;
if(PlayerScript.GetMod().PlayerExperience >= PlayerScript.GetMod().PlayerFullExperience){
PlayerScript.GetMod().PlayerLevel +=1;
PlayerScript.GetMod().PlayerFullExperience += 200*PlayerScript.GetMod().PlayerLevel;
levelUpValue += 20;
if(PlayerScript.GeMod().PlayerLevel % 3 == 0){
PlayerScript.GetMod().GoldNum += 100*PlayerScript.GetMod().PlayerLevel;
}
}
}
}
(C:\000-ylzServ_DemoPro\小案例003\Assets\PlayerMsgView.cs)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
//立钻哥哥:UI视图层
public class PlayerMsgView :MonoBehaviour{
//UI
public Text playerLevel;
public Text playerExperience;
public Text goldNum;
public Button experienceUpButton;
void Start(){
//委托事件绑定
PlayerScript.GetMod().OnLevelChange += SetLevel;
PlayerScript.GetMod().OnExperienceChange += SetExperience;
PlayerScript.GetMod().OnFullExperienceChange += SetFullExperience;
PlayerScript.GetMod().OnGlodNumChange += SetGoldNum;
//View绑定按钮控制功能
//添加观察者:
experienceUpButton.onClick.AddListener(
PlayerMsgController.controller.OnExperienceUpButtonClick);
}
//修改UILevel值
public void SetLevel(int level){
playerLevel.text = level.ToString();
}
//修改UI经验值
public void SetExperience(int experience){
//将字符串以”/”拆开
string[] str = playerExperience.text.Split(newchar[]{‘/’ });
}
public void SetFullExperience(int fullExperience){
string[] str = playerExperience.text.Split(newchar []{ ‘/’ });
playerExperience.text = str[0] +“/” + fullExperience;
}
public void SetGoldNum(int goldn){
goldNum.text = goldn.ToString();
}
}
(C:\000-ylzServ_DemoPro\小案例003\Assets\PlayerScript.cs)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//模型委托(当用户信息发生变化时执行)
public delegate void OnValueChange(int val);
public class PlayerScript{
private int playerLevel; //玩家等级
private int playerExperience; //玩家经验
private int playerFullExperience; //玩家升级经验
private int goldNum; //金币数量
//声明委托对象
public OnValueChange OnLevelChange; //当等级发生变化时,触发的事件
public OnValueChange OnExperienceChange; //当经验发生变化时,触发的事件
public OnValueChange OnFullExperienceChange; //当升级经验发生变化时
public OnValueChange OnGoldNumChange; //当金币数量发生变化时
private static PlayerScript mod; //单例
public static PlayerScript GetMod(){
if(mod == null){
mod = new PlayerScript();
}
return mod;
}
private PlayerScript(){
}
//玩家等级属性
public int PlayerLevel{
get{
return playerLevel;
}
set{
playerLevel = value;
if(OnLevelChange!= null){
//如果委托对象不为空
OnLevelChange(playerLevel); //执行委托
}
}
}
//玩家经验属性
public int PlayerExperience{
get{
return playerExperience;
}
set{
playerExperience = value;
if(OnExperienceChange !=null){
OnExperienceChange(playerExperience);
}
}
}
//玩家升级经验属性
public int PlayerFullExperience{
get{
return playerFullExperience;
}
set{
playerFullExperience = value;
if(OnFullExperienceChange!= null){
OnFullExperienceChange(playerFullExperience);
}
}
}
//金币数量属性
public int GoldNum{
get{
return goldNum;
}
set{
goldNum = value;
if(OnGoldNumChange != null){
OnGoldNumChange(goldNum);
}
}
}
}
++小案例004、简单背包案例
++++Controller/
--PlayerBagController.cs
++++Model/
--PlayerModelScript.cs
--ToolModel.cs
++++View/
--BagView.cs
--GridView.cs
--HPView.cs
--PlayerBagView.cs
--PlayerInfoView.cs
++Controller/
++++PlayerBagController.cs
(C:\000-ylzServ_DemoPro\小案例004\Bag\Assets\Scripts\Controller\PlayerBagController.cs)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using System;
using System.Reflection;
using UnityEditor;
//实现赋值数据,展示数据,物品拖拽,交换等主要功能
// 赋值M -- V交互
public class PlayerBagController :MonoBehaviour,IMoveHandle{
//引入背包视图,相当于将其下的所有子物体脚本都引入
public BagView bagView; //背包视图
void Start(){
MakeData(); //赋值数据
ShowData(); //展示数据
}
//测试数据:
PlayerModelScriptplayer;
public Sprite s1;
public Sprite s2;
public Sprite s3;
public Sprite s4;
//public Sprite s5;
//public Sprite s6;
void MakeData(){
player = new PlayerModelScript(“立钻哥哥”,1000,200);
ToolModel t1 = new ToolModel(“道具1”,ToolType.HP,2000,s1);
ToolModel t2 = new ToolModel(“道具2”,ToolType.HP,500,s2);
ToolModel t3 = new ToolModel(“道具3”,ToolType.ATK,300,s3);
ToolModel t4= new ToolModel(“道具4”,ToolType.ATK,100,s4);
//放入指定下标
player.bagArray[0] = t1;
player.bagArray[5] = t2;
player.bagArray[16] = t3;
player.bagArray[7] =t4;
}
void ShowData(){
//背包
//生成背包格子
creatGrid(
player.bagArray,
bagView.playerBagView.gridGroupView.transform,
“BagGrid”);
//装备
creatGrid(){
player.gearArray,
bagView.playerInfoView.gridGroupView.transform,
“GearGrid”
};
//显示生命值
bagView.playerInfoView.hpView.HPValue.text=player.HP.ToString();
}
//1、根据数组元素个数生成
//2、父物体
//3、格子tag值
void creatGrid(ToolModel[] arr, Transform t, string gridTag){
for(int i=0; i <arr.Length; i++){
//生成格子
GameObject obj = Instantiate<GameObject>(
Resources.Load<GameObject>(“Perfabs/GridView”),
Vector3.zero,
Quaternion.identity
);
//参数赋值:
obj.tag = gridTag; //tag值:格子tag赋值给生成的格子
GridView gv = obj.GetComponent<GridView>(); //获取脚本组件
gv.index =i; //设置格子index
//走过之一段代码之后controller就为格子的代理,那么其就要执行接口里边的方法
gv.moveHandle = this; //设置代理
//给图片赋值
if(arr[i] != null){
gv.contentImage.gameObject.SetActive(true); //激活image
gv.contentImage.sprite = arr[i].toolSprite;
}
//添加到父物体
obj.transform.SetParent(t);
}
}
/*
移动有四种情况:
--1、背包--->背包
--2、背包--->装备
--3、装备--->装备
--4、装备--->背包
--5、有--->无
--6、丹药类型点击消失增加属性
*/
//实现接口方法
Transform targetTransform; //目标位置
public void BeginMove(GridView grid, PointerEventData pointData){
if(grid.tag == “BagGrid”){
//判空:如果背包数组没有东西那么不需要移动
if(player.bagArray[grid.index] == null){
return;
}
}
if(gird.tag == “GearGrid”){
//判空:装备格子判断
if(player.gearArray[gird.index] == null){
return;
}
}
#warning有数据
//有数据:开始拖拽前记录信息不交换时候让其回到原来位置
targetTransform = grid.contentImage.transform;
gird.contentImage.raycastTarget = false; //关闭射线检测(检测后方物体)
targetTransform.SetParent(targetTransform.root); //脱离父物体
}
public void Move(GridView grid, PointerEventData pointData){
if(targetTransform == null){
//如果目标为空,那么返回原来位置
return;
}
targetTransform.position = Input.mousePosition;
}
//PointerEventData:系统方法
public void EndMove(GridView grid, PointerEventData pointData){
if(targetTransform==null){
return;
}
//pointData.pointerEnter:目标物体
GameObject pointerEnter = pointData.pointerEnter; //鼠标松手后最后触碰的物体
//从背包区开始拖拽
if(grid.tag == “BagGrid”){
//到背包区
if(pointerEnter.tag == “BagGrid”){
GridView gv = pointerEnter.GetComponent<GridView>();
//判断格子中是否有物品
//gv:目标格子
if(player.bagArray[gv.index] == null){
ChangeUINullGrid(grid, gv); //grid:当前格子
}else{
ChangeUIFullGrid(grid, gv); //变UI
}
//变数据
ToolModel tm = player.bagArray[gv.index];
player.bagArray[gv.index] = player.bagArray[gird.index];
player.bagArray[grid.index] = tm;
}
//到装备区
if(pointerEnter.tag == “GearGrid”){
//判断拖拽的是否是装备
if(player.bagArray[gird.index].type == ToolType.ATK){
GridView gv = pointerEnter.GetComponent<GridView>();//获取脚本组件
//判断是否有数据
if(player.gearArray[gv.index] == null){
ChangeUINullGrid(gird,gv); //无
}else{
ChangeUIFullGrid(grid,gv); //有
}
//数据交换
ToolModel tm = player.bagArray[gird.index];
player.bagArray[gird.index] = player.gearArray[gv.index];
player.gearArray[gv.index] = tm;
}
}
}
//从装备区拖拽
if(grid.tag == “GearGrid”){
//到装备区
if(pointerEnter.tag == “GearGrid”){
GridView gv = pointerEnter.GetComponent<GridView>();
if(player.gearArray[gv.index] == null){
ChangeUINullGrid(grid,gv); //空
}else{
ChangeUIFullGrid(grid,gv); //不空
}
//交换数据
ToolModel tm = player.gearArray[gv.index];
player.gearArray[gv.index] = player.gearArray[grid.index];
player.gearArray[grid.index] = tm;
}
//到背包
if(pointerEnter.tag == “BagGrid”){
GridView gv = pointerEnter.GetComponent<GridView>();
bool isChange =true; //判断是否交换
if(player.bagArray[gv.index] == null){
ChangeUINullGrid(gird,gv); //空
}else{
//判断物体的类型
//如果不是装备则UI不交换
if(player.bagArray[gv.index].type == ToolType.ATK){
ChangeUIFullGrid(grid,gv); //不空
}else{
isChange =false;
}
}
if(isChange){
//数据
ToolModel tm = player.bagArray[gv.index];
player.bagArray[gv.index] = player.gearArray[grid.index];
player.gearArray[grid.index] = tm;
}
}
}
targetTransform.SetParent(grid.transform); //返回原来的格子
targetTransform.localPosition = Vector3.zero; //在父物体的位置localPosition归0
targetTransform = null; //清0
}
public void ClickTool(GridView grid, PointerEventData pointData){
if(player.bagArray[grid.index] != null){
if(player.bagArray[grid.index].type == ToolType.HP){
//数据更新
player.HP+= player.bagArray[grid.index].value;
player.bagArray[grid.index] = null;
//UI更新
bagView.playerInfoView.hpView.HPValue.text = player.HP.ToString();
grid.contentImage.sprite = null;
grid.contentImage.gameObject.SetActive(false);
}
}
}
#region 改变UI
//放到没有物品的格子中(destination: 目标格子)
void ChangeUINullGrid(GridView origin, GridView destination){
destination.contentImage.gameObject.SetActive(true); //目的格子图片激活
//将源格子的图片赋值给目的格子
destination.contentImage.sprite = origin.contentImage.sprite;
origin.contentImage.sprite = null; //将源格子图片清空
origin.contentImage.gameObject.SetActive(false); //将源格子图片取消激活
}
//放到有物品的格子中
void ChangeUIFullGrid(GridView origin, GridView destination){
Sprite s = destination.contentImage.sprite;
destination.contentImage.sprite = origin.contentImage.sprite;
origin.contentImage.sprite = s;
}
#endregion
}
++Model/
++++PlayerModelScript.cs
++++ToolModel.cs
(C:\000-ylzServ_DemoPro\小案例004\Bag\Assets\Scripts\Model\PlayerModelScript.cs)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerModelScript{
public string playerName{get;set; } //姓名
public int HP{get;set; } //血量
public int ATK{get;set; } //攻击力
public ToolModel[] gearArray; //装备区
public ToolModel[] bagArray; //背包
public PlayerModelScript(string name,int hp,int atk){
playerName = name;
HP = hp;
ATK = atk;
gearArray = new ToolModel[8]; //装备
bagArray = new ToolModel[20]; //背包
}
}
(C:\000-ylzServ_DemoPro\小案例004\Bag\Assets\Scripts\Model\ToolModel.cs)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public enmu ToolType{
HP,
ATK
}
//立钻哥哥:道具Model类
public class ToolModel{
public string toolName{set;get; } //道具名字
public ToolType type{set;get; } //道具类别
public int value{set;get; } //数值
public Sprite toolSprite{set;get; } //道具图片
//构造方法
public ToolModel(string name, ToolTypett, int v, Sprite sp){
toolName = name;
type = tt;
value = v;
toolSprite = sp;
}
}
++View/
++++BagView.cs
++++GridView.cs
++++HPView.cs
++++PlayerBagView.cs
++++PlayerInfoView.cs
(C:\000-ylzServ_DemoPro\小案例004\Bag\Assets\Scripts\View\BagView.cs)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//挂载在BagView上,目的收集子视图View
public class BagView :MonoBehaviour{
public PlayerInfoView playerInfoView; //人物界面
public PlayerBagView playerBagView; //背包界面
}
(C:\000-ylzServ_DemoPro\小案例004\Bag\Assets\Scripts\View\GridView.cs)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
//using System.Net.NetworkInformation;
//移动的接口
public interface IMoveHandle{
void BeginMove(GridView grid, PointerEventData pointData); //鼠标进入
void Move(GridView grid, PointerEventData pointData); //移动
void EndMove(GridView grid, PointerEventData pointData); //结束移动
void ClickTool(GridView grid, PointerEventData pointData); //点击的道具
}
public class GridView : MonoBehaviour,IBeginDragHandler,IDragHandler,IEndDragHandler,IPointerClickHandler{
public Image contentImage;
public int index{set;get; } //格子创建时的下标,标记它的目的是为了在交换物品或者移动时候和数组元素对应
public IMoveHandle moveHandle; //将接口定义为视图的字段或者属性
//实现继承过来接口里边的内容
public void OnBeginDrag(PointerEventData eventData){
moveHandle.BeginMove(this,eventData);
}
public void OnDrag(PointerEventData eventData){
moveHandle.Move(this,eventData);
}
public void OnEndDrag(PointerEventData eventData){
moveHandle.EndMove(this,eventData);
}
public void OnPointerClick(PointerEventData eventData){
moveHandle.ClickTool(this,eventData);
}
}
(C:\000-ylzServ_DemoPro\小案例004\Bag\Assets\Scripts\View\HPView.cs)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
//获得它下边的两个文本
public class HPView : MonoBehaviour{
public Text HpText;
public Text HPValue;
}
(C:\000-ylzServ_DemoPro\小案例004\Bag\Assets\Scripts\View\PlayerBagView.cs)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerBagView: MonoBehaviour{
public RectTransform gridGroupView;
}
(C:\000-ylzServ_DemoPro\小案例004\Bag\Assets\Scripts\View\PlayerInfoView.cs)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//任务属性界面脚本(目的:收集其子物体关于View的脚本)
public class PlayerInfoView : MonoBehaviour{
public RectTransform gridGroupView; //格子视图
public HPView hpView;
}
++小案例005、塔防Demo
++++BulletScript.cs
++++CameraMoveScript.cs
++++EndScript.cs
++++GameDataScript.cs
++++InitMonsterScript.cs
++++InitTowerScript.cs
++++MonsterScript.cs
++++TowerFireScript.cs
(D:\000-ylzServ_DemoPro\小案例005\Assets\DemoBak\Homework\BulletScript.cs)
using UnityEngine;
using System.Collections;
//该脚本功能是控制子弹的发射和碰撞检测(加到粒子特效上,模拟子弹)
public class BulletScript :MonoBehaviour{
public Transform target; //子弹要攻击的目标
public float bulletSpeed=3; //子弹的飞行速度
public float damager=100; //子弹的伤害值
void Update(){
if(target){
Vector3 dir =target.position-transform.position; //得到子弹要飞行的向量
Transform.position += dir*Time.deltaTime*bulletSpeed; //子弹移动
}else{
Destroy(gameObject); //如果目标是空,把子弹销毁
}
}
void OnTriggerEnter(Collider other){
if(other.tag == “monster”){
Other.GetComponent<MonsterScript>().health -= damage; //怪物掉血
Destroy(this.gameObject); //把子弹销毁掉
}
}
}
(D:\000-ylzServ_DemoPro\小案例005\Assets\DemoBak\Homework\CameraMoveScript.cs)
using UnityEngine;
using System.Collections;
public class CameraMoveScript : MonoBehaviour{
public float moveSpeed =3;
void Update(){
float hor = Input.GetAxis(“Horizontal”);
float ver = Input.GetAxis(“Vertical”);
transform.position += new Vector3(hor,0,ver) *Time.deltaTime*moveSpeed;
}
}
(D:\000-ylzServ_DemoPro\小案例005\Assets\DemoBak\Homework\EndScript.cs)
using UnityEngine;
using System.Collections;
//加在End物体上,功能是当怪物触发后,把怪物销毁
public class EndScript : MonoBehaviour{
void OnTriggerEnter(Collider other){
if(other.tag == “monster”){
Debug.Log(“tttt”);
Destroy(other.gameObject);
}
}
}
(D:\000-ylzServ_DemoPro\小案例005\Assets\DemoBak\Homework\GameDataScript.cs)
using UnityEngine;
using System.Collections;
using System;
//功能是控制所生成怪物的数量,速度和时间间隔,主要的思路是用一个结构体数组,数组的长度即为波数,每一波对应数组里面的一个元素,读取结构体里面的数据。
public class GameDataScript : MonoBehaviour{
public static GameDataScript Instance;
public struct Data{
public float waitTime; //等待多长时间产生一波敌人
public int monsterCount; //每一波敌人的数量
public float moveSpeed; //每一波敌人的移动速度
}
//刚开始时的默认数据
float waitTimeDefault =3;
int monsterCountDefault= 3;
float moveSpeedDefault =2;
public Data[] monsterData; //每一波所对应的数据
void Awake(){
Instance = this;
}
void Start(){
monsterData = new Data[10];
for(int i =0; i < monsterData.Length; i++){
//第一次循环时把默认数据赋值给第一个元素
monsterData[i].waitTime =waitTimeDefault;
monsterData[i].monsterCount = monsterCountDefault;
monsterData[i].moveSpeed =moveSpeedDefault;
//每循环一次数据增加
waitTimeDefault += 0.5f;
monsterCountDefault += 1;
moveSpeedDefault += 0.3f;
}
}
}
(D:\000-ylzServ_DemoPro\小案例005\Assets\DemoBak\Homework\InitMonsterScript.cs)
using UnityEngine;
using System.Collections;
//怪物生成(加到Start空物体上)
public class InitMonsterScript : MonoBehaviour{
puiblic GameObject monster; //怪物预设体
float timer; //计时器
int index = 0; //生成怪物的波数
bool isInit = false //当前是否正在生成怪物
int monsterCount = 0; //一波中怪物的数量
bool isGaming=true; //是否在游戏中
void Update(){
if(isGaming){
timer += Time.deltaTime;
//读取Data数组中index中相对应的元素,再找到里面对应的相关数据
//1、先得到时间间隔
float timeInterval = GameDataScript.Instance.monsterData[index].waitTime;
//2、如果计时器达到等待生成怪物的时间,并且没有初始化怪物,则把计时器归0,开始初始化怪物
if(!isInit && timer > timeInterval){
timer = 0;
isInit =true;
}else if(isInit){
//如果能初始化怪物
if(timer > 1){
//每隔一秒生成一个怪物
timer =0;
GameObject currentMonster = Instantiate(monster,transform.position,Quaternion.identity) as GameObject; //生成怪物
currentMonster.GetComponent<UnityEngine.AI.NavMeshAgent>().speed = GameDataScript.Instance.monsterData[index].moveSpeed; //把数据组中的速度赋值给导航中的速度
monsterCount++; //怪物数量增加
if(monsterCount == GameDataScript.Instance.monsterData[index].monsterCount){
//如果怪物生成的数量与给定的数量相同
monsterCount = 0; //数据归零
index++; //进入下一波
isInit = false; //不能再进行初始化了
if(index >GameDataScript.Instance.monsterData.Length-1){
//说明波次已经够了,此时游戏结束
isGaming =false;
}
}
}
}
}
}
}
(D:\000-ylzServ_DemoPro\小案例005\Assets\DemoBak\Homework\InitTowerScript.cs)
using UnityEngine;
using System.Collections;
//加到空GameController上,主要的功能是点击鼠标左键,创建炮塔
public class InitTowerScript :MonoBehaviour{
public GameObject tower;
RaycastHit hit;
void Update(){
//如果按下鼠标左键
if(Input.GetMouseButtonDown(0)){
//从摄像机到鼠标点击位置发出一条射线
if(Physics.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition), out hit)){
Debug.Log(hit.collider.name);
//检测点击到的是否是木箱,如果名字中包含Tower,并且没有子物体
if(hit.collider.name.IndexOf(“Tower”) != -1 && hit.collider.transform.childCount ==0){
Vector3 pos =hit.collider.transform.position+Vector3.up* 2.65f;
GameObject gun = Instantiate(tower,pos,Quaternion.identity) as GameObject; //生成大炮
gun.transform.SetParent(hit.collider.transform); //给生成的炮塔设置父物体
}
}
}
}
}
(D:\000-ylzServ_DemoPro\小案例005\Assets\DemoBak\Homework\MonsterScript.cs)
using UnityEngine;
using System.Collections;
//功能是控制怪物的运动(脚本加到Monster上)
public class MonsterScript :MonoBehaviour{
public float health = 100; //生命值
UnityEngine.AI.NavMeshAgent nav; //导航组件
Transform end; //终点
Animation ani; //动画组件
void Awake(){
nav = GetComponent<UnityEngine.AI.NavMeshAgent>();
ani = GetComponent<Animation>();
end = GameObject.FindWithTag(“end”).transform;
}
void Start(){
nav.destination = end.position;
}
void Update(){
//如果血量小于等于0
if(health <0){
GetComponent<CapsuleCollider>().enabled = false; //关闭碰撞器
ani.CrossFade(“Dead”);
Destroy(gameObject,1); //1秒钟后销毁自己
}
}
}
(D:\000-ylzServ_DemoPro\小案例005\Assets\DemoBak\Homework\TowerFireScript.cs)
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class TowerFireScript :MonoBehaviour{
public GameObject bullet; //生成炮弹
public float fireRadius= 7f; //攻击半径
public float rotateSpeed=3f; //炮头转向速度
public float distance=0.5f; //炮头与炮身之间的距离
public float bullectMoveSpeed=5f; //子弹飞行的速度
public Transform fireTarget; //攻击的目标
public float fireTimeInterval=0.5f; //发射子弹的间隔时间
private float timer=0; //计时器
private Queue<Transform> monsterQueue; //怪物的队列
void Awake(){
monsterQueue = new Queue<Transform>();
}
void Start(){
}
void Update(){
//如果攻击目标为空
if(fireTarget == null){
if(monsterQueue.Count>0){
fireTaget = monsterQueue.Dequeue();
}
}else{
Fire();
}
}
//当怪物进入触发器中,把该怪物添加到要攻击的队列中
void OnTriggerEnter(Collider other){
Debug.Log(“enter”);
//如果是怪物
if(other.tag == “monster”){
monsterQueue.Enqueue(other.transform);
}
}
//离开触发
void OnTriggerExit(Collider other){
Debug.Log(“exit”);
if(other.tag == “monster”){
//如果是当前正在攻击的目标
if(other.transform == fireTarget){
fireTarget= null; //把攻击目标设置为空
}else{
//如果队列不为空
if(monsterQueue.Count>0){
monsterQueue.Dequeue();
}
}
}
}
void Fire(){
Vector3 dir =fireTarget.position-transform.position;
Quaternion rotation = Quaternion.LookRotation(dir);
transform.rotation =Quaternion.Lerp(transform.rotation,rotation,Time.deltaTime*rotateSpeed);
Debug.DrawRay(transform.position, dir,Color.red);
Debug.DrawRay(transform.position, transform.forward * 10,Color.green);
if(Vector3.Angle(dir,transform.forward) <5){
InitBullet();
}
}
void InitBullet(){
timer += Time.deltaTime;
if(timer >fireTimeInterval){
timer = 0;
Vector3 point = transform.GetChild(0).position+transform.GetChild(0).forward*distance;
GameObject currentBullet =Instantiate(bullet,point,Quaternion.identity)asGameObject;
currentBullet.GetComponent<BulletScript>().target = this.fireTarget;
currentBullet.GetComponent<BulletScript>().bulletSpeed = this.bulletMoveSpeed;
}
}
}
++小案例006、 秘密行动Demo
++++AlarmLight.cs
++++CameraMovement.cs
++++CCTVPlayerDetection.cs
++++DoorAnimation.cs
++++EnemyAI.cs
++++EnemyAnimation.cs
++++EnemyShooting.cs
++++EnemySight.cs
++++HashIDs.cs
++++KeyPickup.cs
++++LaserController.cs
++++LaserSwitchDeactivation.cs
++++LastPlayerSighting.cs
++++LiftDoorsTracking.cs
++++PlayerHealth.cs
++++PlayerInventory.cs
++++PlayerMovement.cs
++++SyncDoor.cs
++++Tags.cs
++秘密行动思维导图
---0、添加Tag脚本
---1、添加场景模型
---2、创建一个空游戏物体
---3、添加英雄char_ethan
---4、添加平行光
---5、给主摄像机添加脚本,用来控制摄像机的移动
---6、在GameController上添加子物体SecondSound
---7、给警报喇叭添加标签
---8、给GameController添加脚本LastPlayerSighting
---9、添加激光灯
---10、创建空物体Doors,用来管理自动门
---11、创建空物体SwitchUnits来控制激光门的开和关
---12、添加钥匙卡
---13、添加CCTV摄像机
---14、添加电梯外面的开关门
---15、添加电梯
---16、放置巡逻点
---17、小机器人
---18、添加手枪
---======================---===============---
++++0、添加Tag脚本,该脚本可以直接取到tag值,不加到任何游戏物体上。
++++1、添加场景模型
--1.1、添加 env_stealth_static
--1.2、添加卡车 prop_battleBus
--1.3、添加网格碰撞器 env_stealth_collision
++++2、创建一个空游戏物体
--2.1、命名GameController
--2.2、添加声音组件播放背景音乐
---playonawake = true,
---loop = true,
---volume = 1
--2.3、添加脚本HashID,用来给动画控制设置参数。
--2.4、添加tag值GameController
++++3、添加英雄 char_ethan
--3.1、添加胶囊碰撞器
--3.2、添加刚体,冻结所有的旋转以及y轴方向的位置
--3.3、添加声音组件,声音片段为脚步声
--3.4、添加动画控制器PlayerAnimator
--3.5、添加脚本PlayerHealth,用来控制英雄的少血以及死亡
--3.6、添加脚本PlayerMove,用来控制英雄的移动
--3.7、添加tag值Player
++++4、添加平行光
--4.1、做了警报灯,颜色为红色,intensity=0
--4.2、添加脚本AlarmLight脚本组件,用来控制警报灯由明变暗再由暗变明
--4.3、添加tag值AlarmLight
++++5、给主摄像机添加脚本,用来控制摄像机的移动
--5.1、Editor/ProjectSetting/Physic/Hit Triggers取消勾选(否则射线会检测触发器,取消后只会检测碰撞器)
--5.2、添加脚本CameraMove
++++6、在GameController上添加子物体SecondSound
--6.1、给子物体添加AudioSource组件
--6.2、添加声音片段music_panic
--6.3、设置声音的初始值为0
--6.4、PlayOnAwake和Loop勾选
++++7、给警报喇叭添加标签
--7.1、给prop_megaphon添加siren标签
--7.2、给六个喇叭添加AudioSource组件
--7.3、添加声音片段alarm_trigger
--7.4、设置声音的初始值为0
--7.5、PlayOnAwake和Loop勾选
++++8、给GameController添加脚本LastPlayerSighting
++++9、添加激光灯
--9.1、创建空物体Lasers用来管理激光门
--9.2、把fx_laserFence_lasers插到场景中并放到合适的位置(大小和旋转)
--9.3、添加AudioSource组件,加上laser_hum声音片段,把Loop和PlayOnAwake勾选,音量设置为1
--9.4、添加点灯源组件,颜色为红色,Range=5,Intensity=1.5,Bounce=1
--9.5、添加一个Box触发器,用来进行触发检测
--9.6、添加脚本LaserController
++++10、创建空物体Doors,用来管理自动门
--10.1、把door_generic_slide拖到合适的位置
--10.2、添加球形触发器,半径为1.5,高为1。
在门的子物体上添加盒形碰撞器,防止没有钥匙的时候,玩家可以直接穿透门
--10.3、添加AudioSource组件,和door_open声音片段,最小距离1,最大距离为5
--10.4、添加DoorAnimator动画控制器组件,给自动门添加动画,添加播放声音的事件
--10.5、添加脚本DoorAnimation
++++11、创建空物体SwitchUnits来控制激光门的开和关
--11.1、拖动prop_switchUnit_screen到场景中
--11.2、在父物体上添加Box碰撞器,在子物体上添加Box触发器,在子物体上添加声音组件
--11.3、添加脚本 LaserSwitchDeactivation
++++12、添加钥匙卡
--12.1、拖动prop_keycard到场景中合适的位置
--12.2、添加球形触发器
--12.3、添加点光源,颜色为蓝色
--12.4、添加动画控制器组件
++++13、添加CCTV摄像机
--13.1、Y轴旋转180度
--13.2、子物体_body x轴旋转30度
--13.3、给子物体_joint添加帧动画
--13.4、在_body子物体下添加空物体trigger,沿X轴旋转30度,并添加MeshCollider组件,添加prop_cctvCam_collision,并使其变为触发器
--13.5、添加Light组件,选择spot的灯光,Range=40, Angle=62,intensity=4, bounce=1, cookie选择fx_cameraView_alp
--13.6、给trigger子物体添加脚本CCTV
++++14、添加电梯外面的开关门
--14.1、拖动door_exit_outer到合适的位置,沿y轴旋转-90
--14.2、添加球形碰撞器
--14.3、添加声源组件,添加open_door声音片段
--14.4、添加动画控制器RedDoorAnimator
--14.5、添加DoorAnimation脚本组件
++++15、添加电梯
--15.1、拖动prop_lift_exit到电梯井里面,并沿Y轴旋转-90
--15.2、添加声源组件,并添加endgame声音片段
--15.3、给子物体_carriage添加声源组件,添加lift_rise声音片段
--15.4、给_carriage添加四个box碰撞器:
---第一个设置为trigger,
---第二个center.z=2(其余不变), size.z=0.15(其余不变)
---第三个center.z=2(其余不变),size.z=0.15(其余不变)
---第四个center.x=1.87,其余为0,size.x=0.2
--15.5、给carriage添加脚本LiftDoor
--15.6、给子物体door_inner添加脚本SyncDoor
++++16、放置巡逻点
++++17、小机器人
--17.1、添加小机器人的动画控制器EnemyAnimatorController
--17.2、在hashids里面添加新的动画参数值
--17.3、添加动画遮罩EnemyShootingMask
--17.4、设置射击层的过渡条件
--17.5、设置导航路面
--17.6、给小机器人添加animator组件,刚体组件,胶囊体碰撞器,球形触发器导航组件
--17.7、添加EnemySight组件
++++18、添加手枪
--18.1、在机器人char_robotGuard_RightHandThumb1下添加子物体prop_sciFiGun_low
--18.2、在枪的子物体下添加子物体Effect,添加灯光组件以及linerander组件,二者都设置为不可用。
--18.3、给射击的动画片段添加动画曲线
--18.4、添加脚本EnemyAnimation
--18.5、在场景中添加小机器人巡逻的小旗帜
--18.6、添加脚本EnemyAI
--18.7、添加脚本EnemyShooting
(D:\zz_DemoPro()-\小案例006、秘密行动Demo\Demo006_StealthActionDemo\Assets\Scripts\AlarmLight.cs)
using UnityEngine;
using System.Collections;
public class AlarmLight:MonoBehaviour{
public bool alarmOn=false; //是否开启警报
public float turnSpeed=3f; //警报灯切换速度
private float highIntensity=2f; //高光强
private float lowIntensity=0f; //低光强
private float targetIntensity=0f; //目标光强
private Light alarmLight; //警报灯光
void Awake(){
alarmLight = GetComponent<Light>(); //获取警报灯
targetIntensity = highIntensity; //设置目标光强初始值为高光强
}
void Update(){
//如果警报开启
if(alarmOn){
//警报灯切换到目标光强
alarmLight.intensity = Mathf.Lerp(alarmLight.intensity,targetIntensity,Time.deltaTime*turnSpeed);
//如果当前光强强度到达了目标光强,需要切换目标
if(Math.Abs(targetIntensity-alarmLight.intensity) <0.05f){
//如果当前目标是高光强
if(targetIntensity == highIntensity){
targetIntensity = lowIntensity; //切换目标为低光强
}else{
targetIntensity =highIntensity; //否则切换目标为高光强
}
}
}else{
//警报灯渐变到低光强
alarmLight.intensity = Mathf.Lerp(alarmLight.intensity,lowIntensity,Time.deltaTime*turnSpeed);
//如果已经到达了低光强
if(alarmLight.intensity < 0.05f){
//直接切换光强为0,减少CPU的计算
alarmLight.intensity =lowIntensity;
}
}
}
}
(D:\zz_DemoPro()-\小案例006、秘密行动Demo\Demo006_StealthActionDemo\Assets\Scripts\CameraMovement.cs)
using UnityEngine;
using System.Collections;
public class CameraMovement:MonoBehaviour{
public float moveSpeed= 3f; //摄像机移动速度
public float turnSpeed=10f; //摄像机旋转速度
private Transform player; //玩家
private Vector3 direction; //摄像机与玩家之间的方向向量
private RaycastHit hit; //射线碰撞检测器
private float distance; //摄像机与玩家的最小距离
private Vector3[] currentPoints; //当前所有的点
void Awake(){
player = GameObject.FindWithTag(Tags.Player).transform;
currentPoints = new Vector3[5];
}
void Start(){
//计算玩家头顶方向与摄像机的距离
distance = Vector3.Distance(transform.position,player.position) -0.5f;
//游戏开始时玩家与摄像机之间的方向向量
direction = player.position-transform.position;
}
void Lateupdate(){
Vector3 startPoint =player.position-direction; //第一个点
Vector3 endPoint =player.position+Vector3.up*distance; //最后一个点
currentPoint[1] = Vector3.Lerp(startPoint,endPoint,0.25f); //第二个点
currentPoint[2] = Vector3.Lerp(startPoint,endPoint,0.5f); //第三个点
currentPoint[3] = Vector3.Lerp(startPoint,endPoint,0.75f); //第四个点
//放到数组中
currentPoints[0] = startPoint;
currentPoints[4] = endPoint;
//创建一个点,用来存储选择好可以看到玩家的点
Vector3 viewPosition =currentPoints[0];
//遍历五点
for(int i = 0; i <5; i++){
if(CheckView(currentPoints[i])){
viewPosition = currentPoints[i]; //更新合适的点
break;
}
}
//摄像机移动到指定点
transform.position = Vector3.Lerp(transform.position,viewPosition,Time.deltaTime*moveSpeed);
SmoothRotate(); //执行平滑旋转
}
//检测是否可以看到玩家
//return true:看到了,false:没看到
//param pos:射线发射点
bool checkView(Vector3 pos){
Vector3 dir = player.position -pos; //计算方向向量
//发射射线
if(Physics.Raycast(pos,dir, out hit)){
//如果看到了
if(hit.collider.tag == Tags.Player){
return true;
}
}
return false;
}
//平滑旋转
void SmoothRotate(){
//计算方向向量
Vector3 dir = player.position + Vector3.up* 0.2f-transform.position;
Quaternion qua =Quaternion.LookRotation(dir); //转换为四元数
//平滑移动
transform.rotation =Quaternion.Lerp(transform.rotation,qua,Time.deltaTime*turnSpeed);
//优化Y轴和Z轴旋转
transform.eulerAngles = new Vector3(transform.eulerAngles.x,0, 0);
}
}
(D:\zz_DemoPro()-\小案例006、秘密行动Demo\Demo006_StealthActionDemo\Assets\Scripts\CCTVPlayerDetection.cs)
using UnityEngine;
using System.Collections;
public class CCTVPlayerDetection:MonoBehaviour{
private LastPlayerSighting lastPlayerSighting; //传输警报位置
void Awake(){
lastPlayerSighting = GameObject.FindWithTag(Tags.GameController).GetComponent<LastPlayerSighting>();
}
void OnTriggerEnter(Collider other){
//如果是玩家,同步警报位置
if(other.tag == Tags.Player){
lastPlayerSighting.alarmPositon =other.transform.position;
}
}
}
(D:\zz_DemoPro()-\小案例006、秘密行动Demo\Demo006_StealthActionDemo\Assets\Scripts\DoorAnimation.cs)
using UnityEngine;
using System.Collections;
public class DoorAnimation:MonoBehaviour{
public bool needKey = false; //当前门是否需要钥匙
public AudioClip refuseAud; //拒绝开门的声音片段
private bool playerIn=false; //玩家进入到了大门触发器范围内
private int count=0; //人数
private Animator ani;
private AudioSource aud;
private PlayerInventory playerInventory; //玩家是否拥有钥匙的脚本
void Awake(){
ani = GetComponent<Animator>();
aud = GetComponent<AudioSource>();
playerInventory = GameObject.FindWithTag(Tags.Player).GetComponent<PlayerInventory>();
}
void OnTriggerEnter(Collider other){
//如果进来的是玩家或机器人
if(other.tag ==Tags.Player|| (other.tag ==Tags.Enemy&&other.GetType() ==typeof(CapsuleCollider))){
count++; //人数递增
//如果是玩家
if(other.tag == Tags.Player){
playerIn =true; //设置玩家进入的标志位
//如果玩家没有钥匙
if(!playerInventory.hasKey&&needkey){
//播放拒绝声音
AudioSource.PlayClipAtPoint(refuseAud,transform.position);
}
}
}
}
void OnTriggerExit(Collider other){
//如果进来的是玩家或机器人
if(other.tag == Tags.Player|| (other.tag ==Tags.Enemy&&other.GetType() == typeof(CapsuleCollider))){
count--; //人数递减
//如果是玩家
if(other.tag ==Tags.Player){
playerIn =false; //设置玩家进入的标志位
}
}
}
void Update(){
//不需要钥匙的时候
if(!needKey){
if(count > 0){
ani.SetBool(HashIDs.DoorOpen,true); //门打开
}else{
ani.SetBool(HashIDs.DoorOpen, false); //门关闭
}
}else{
//玩家带着钥匙进去
if(playerIn&&playerInventory.hasKey){
ani.SetBool(HashIDs.DoorOpen, true);
}else{
ani.SetBool(HashIDs.DoorOpen, false);
}
}
}
//动画帧事件,播放开关门声音
public void PlayVoice(){
if(Time.time > 0.1f){
aud.Play(); //播放声音
}
}
}
(D:\zz_DemoPro()-\小案例006、秘密行动Demo\Demo006_StealthActionDemo\Assets\Scripts\EnemyAI.cs)
using UnityEngine;
using System.Collections;
public class EnemyAI:MonoBehaviour{
public Transform[] wayPoints; //巡逻点
public float chasingSpeed=6f; //追捕速度
public float patrallingSpeed= 2.5f; //巡逻速度
public float chasingWaitTime=3f; //巡视时间
private float chasingTimer; //追捕等待计时器
private float patrallingTimer; //巡逻等待计时器
private EnemySight enemySight;
private LastPlayerSighting lastPlayerSighting;
private UnityEngine.AI.NavmeshAgent nav;
private int index; //巡逻目标索引号
private PlayerHealth playerHealth;
void Awake(){
enemySight = GetComponent<EnemySight>();
lastPlayerSighting = GameObject.FindWithTag(Tags.GameController).GetComponent<LastPlayerSighting>();
nav = GetComponent<UnityEngine.AI.NavMeshAgent>();
playerHealth = GameObject.FindWithTag(Tags.Player).GetComponent<PlayerHealth>();
index = 0;
}
void Update(){
if(enemySight.playerInSight&&playerHealth.health>0){
Shooting(); //射击
}else if(enemySight.personalAlarmPosition!=lastPlayerSighting.normalPosition&&playerHealth.health>0){
Chasing(); //追捕
}else{
Patrolling(); //巡逻
}
}
//射击
void Shooting(){
nav.Stop(); //导航停止
}
//追捕
void Chasing(){
nav.Resume(); //恢复导航
nav.speed = chasingSpeed; //加快速度
nav.SetDestination(enemySight.personalAlarmpositon); //设置导航目标
//到达了警报位置
if(nav.remainingDistance -nav.stoppingDistance<0.5f){
chasingTimer += Time.deltaTime; //追捕等待计时器计时
//达到等待时间
if(chasingTimer > chasingWaitTime){
chasingTimer =0; //重置计时器
//警报解除
lastPlayerSighting.alarmPosition =lastPlayerSighting.normalPosition;
}
}else{
chasingTimer = 0; //重置计时器
}
}
//巡逻
void Patrolling(){
nav.speed = patrallingSpeed; //巡逻速度
nav.SetDestination(wayPoints[index].position); //设置巡逻目标
//达到巡逻点
if(nav.remainingDistance- nav.stoppingDistance< 0.5f){
patrallingTimer += Time.deltaTime; //计时器计时
//计时器完成本次计时
if(patrallingTimer >chasingWaitTime){
//更新下一个巡逻点索引号
//index = ++index % wayPoints.Length;
index++;
index =index%wayPoints.Length;
patrallingTimer = 0; //计时器清零
}
}else{
patrallingTimer = 0; //计时器清零
}
}
}
(D:\zz_DemoPro()-\小案例006、秘密行动Demo\Demo006_StealthActionDemo\Assets\Scripts\EnemyAnimation.cs)
using UnityEngine;
using System.Collections;
public class EnemyAnimation:MonoBehaviour{
public float deadZone=4; //死角度数
public float dampSpeedTime= 0.1f; //设置动画参数的延迟时间
public float dampAngularSpeedTime=0.1f;
private UnityEngine.AI.NavMeshAgent nav;
private EnemySight enemySight;
private Transform player;
private Animator ani;
void Awake(){
nav = GetComponent<UnityEngine.AI.NavMeshAgent>();
enemySight = GetComponent<EnemySight>();
player = GameObject.FindWithTag(Tags.Player).transform;
ani = GetComponent<Animator>();
deadZone *= Mathf.Deg2Rad; //死角度数转为弧度
}
void OnAnimatorMove(){
nav.velocity = ani.deltaPosition/Time.deltaTime;
transform.rotation =ani.rootRotation;
}
void Update(){
float speed = 0;
float angularSpeed =0;
//如果看到了玩家
if(enemySight.playerInSight){
speed = 0; //停下来
angularSpeed = FindAngle(); //角速度,按导航转向
//如果角度过小,进入死角
if(Mathf.Abs(angularSpeed) < deadZone){
angularSpeed =0; //停止用动画转身
transform.LookAt(player); //机器人直接看向玩家
}
}else{
//直线速度 =机器人前方的投影向量的模
speed = Vector3.Project(nav.desiredVelocity,transform.forward).magnitude;
angularSpeed = FindAngle(); //角速度,按导航转向
}
//设置动画参数
ani.SetFloat(HashIDs.Speed,speed,dampSpeedTime,Time.deltaTime);
ani.SetFloat(HashIDs.AngularSpeed,angularSpeed,dampAngularSpeedTime,Time.deltaTime);
}
float FindAngle(){
Vector3 dir = nav.desiredVelocity; //期望速度
//机器人前方与期望速度形成的夹角
float angle = Vector3.Angle(dir,transform.forward);
//计算两向量的法向量
Vector3 normal = Vector3.Cross(transform.forward,dir);
//如果期望速度在机器人左方,角度为负
if(normal.y <0){
angle *= -1;
}
//将角度转换为弧度
angle *= Mathf.Deg2Rad;
//如果期望速度为0
if(dir ==Vector3.zero){
angle = 0;
}
return angle;
}
}
(D:\zz_DemoPro()-\小案例006、秘密行动Demo\Demo006_StealthActionDemo\Assets\Scripts\EnemyShooting.cs)
using UnityEngine;
using System.Collections;
public class EnemyShooting:MonoBehaviour{
public float damage= 10; //一枪伤害
private Animator ani;
private Light shootLight;
private LineRenderer shootLine;
private bool shooting = false;
private Transform player;
private PlayerHealth playerHealth;
void Awake(){
ani = GetComponent<Animator>();
shootLight = GetComponentInChildren<Light>();
shootLine = GetComponentInChildren<LineRenderer>();
player = GameObject.FindWithTag(Tags.Player).transform;
playerHealth = player.GetComponent<PlayerHealth>();
}
void Update(){
//射击开始
if(ani.GetFloat(HashIDs.shot) > 0.5f && !shooting){
Shooting();
}elseif(ani.GetFloat(HashIDs.Shot) < 0.5f){
shooting = false;
shootLight.enabled =false;
shootLine.enabled =false;
}
}
//射击
void Shooting(){
shootLight.enabled = true; //打开闪光
//绘制激光线
shootLine.SetPosition(0, shootLine.transform.parent.position);
shootLine.SetPosition(1, player.position+Vector3.up*1.5f);
shootLine.enabled =true;
shooting = true; //正在射击
playerHealth.TakeDamage(damage); //计算伤害
}
void OnAnimatorIK(int layer){
float weight = ani.GetFloat(HashIDs.AimWeight); //获取曲线中的权重
ani.SetIKPositionWeight(AvatarIKGoal.RightHand,weight); //设置IK权重
//设置IK位置
ani.SetIKPosition(AvatarIKGoal.RightHand,player.position+Vector3.up*1.5f);
}
}
(D:\zz_DemoPro()-\小案例006、秘密行动Demo\Demo006_StealthActionDemo\Assets\Scripts\EnemySight.cs)
using UnityEngine;
using System.Collections;
public class EnemySight:MonoBehaviour{
public bool playerInSight= false; //能够看到玩家
public float fieldOfView= 110f; //机器人视野夹角
private float distanceOfView; //机器人视野距离
private SphereCollider sph; //机器人触发器
public Vector3 personalAlarmPosition; //私人警报位置
private Vector3 previousAlarmPosition; //上一帧的公共警报位置
private LastPlayerSighting lastPlayerSighting; //公共警报脚本
private RaycastHit hit; //射线碰撞检测器
private UnityEngine.AI.NavMeshAgent nav; //导航组件
private PlayerHealth playerHealth; //玩家血量脚本
private Animator ani; //动画组件
void Awake(){
lastPlayerSighting = GameObject.FindWithTag(Tags.GameController).GetComponent<LastPlayerSighting>();
//获取触发器
sph = GetComponent<SphereCollider>();
nav = GetComponent<UnityEngine.AI.NavMeshAgent>();
playerHealth = GameObject.FindWithTag(Tags.Player).GetComponent<PlayerHealth>();
ani = GetComponent<Animator>();
}
void Start(){
//私人警报初值为非警报位置
personalAlarmPosition = lastPlayerSighting.normalPosition;
//上一帧的公共警报位置初值也为非警报位置
previousAlarmPosition = lastPlayerSighting.normalPosition;
//获取视野距离
distanceOfView = sph.radius;
}
void Update(){
//公共警报一旦发生变化 --->通知到PersonalAlarmPosition
//PersonalAlarmPosition --/-->不能通知给公共警报
//如果上一帧的公共警报位置,与本帧的公共警报位置不一致
if(previousAlarmPosition != lastPlayerSighting.alarmPosition){
//将最新的公共警报位置通知到私人警报位置
personalAlarmPosition = lastPlayerSighting.alarmPosition;
}
//获取本帧的公共警报位置
previousAlarmPosition =lastPlayerSighting.alarmPosition;
//如果玩家血量正常
if(playerHealth.health > 0){
ani.SetBool(HashIDs.PlayerInSight,playerInSight);
}else{
ani.SetBool(HashIDs.PlayerInSight, false);
}
}
void OnTriggerStay(Collider other){
//如果是玩家
if(other.tag ==Tags.Player){
playerInSight = false; //重置
//玩家与机器人的距离
float distance = Vector3.Distance(other.transform.position, transform.position);
//计算机器人自身前方与方向向量之间的夹角
float angular = Vector3.Angle(dir, transform.forward);
//满足视野范围内核距离范围内
if(distance <distanceOfView &&angular<fieldOfView/2){
if(Physics.Raycast(transform.position+Vector3.up*1.7f, dir,outhit)){
if(hit.collider.tag == Tags.Player){
playerInSight = true; //可以看到玩家
//报警
lastPlayerSighting.alarmPosition = other.transform.position;
}
}
}
//听觉:如果机器人与玩家的导航路径在听觉路径范围内
if(EnemyListening(other.transform.position)){
//如果玩家发出了声音
if(other.GetComponent<AudioSource>().isPlaying){
//赋值私人警报位置
personalAlarmPosition =other.transform.position;
}
}
}
}
//机器人与玩家的导航距离在视觉范围内
bool EnemyListening(Vector3 playerPos){
UnityEngine.AI.NavMeshPath path = new UnityEngine.AI.NavMeshPath();
//如果导航可以到达玩家位置
if(nav.CalculatePath(playerPos, path)){
//用数组获取所有的路径点
Vector3[] points =new Vector3[path.corners.Length+2];
points[0] = transform.position; //起点
points[points.Length-1] = playerPos; //终点
//赋值中间的拐点
for(inti =1; i < points.Length-1; i++){
points[i] = path.corners[i -1];
}
float navDistance= 0; //导航距离
//遍历计算距离
for(int i =0; i < points.Length-1; i++){
navDistance +=Vector3.Distance(points[i],points[i +1]);
}
//导航距离在听觉距离范围内
if(navDistance < distanceOfView){
return true;
}
}
return false;
}
}
(D:\zz_DemoPro()-\小案例006、秘密行动Demo\Demo006_StealthActionDemo\Assets\Scripts\HashIDs.cs)
using UnityEngine;
using System.Collections;
public class HashIDs :MonoBehaviour{
public static int DoorOpen;
public static int Speed;
public static int Sneak;
public static int AngularSpeed;
public static int Dead;
public static int PlayerInSight;
public static int Shot;
public static int AimWeight;
public static int LocomotionState;
void Awake(){
DoorOpen = Animator.StringToHash(“DoorOpen”);
Speed = Animator.StringToHash(“Speed”);
Sneak = Animator.StringToHash(“Sneak”);
AngularSpeed = Animator.StringToHash(“AngularSpeed”);
Dead = Animator.StringToHash(“Dead”);
PlayerInSight = Animator.StringToHash(“PlayerInSight”);
Shot = Animator.StringToHash(“Shot”);
AimWeight = Animator.StringToHash(“AimWeight”);
LocomotionState = Animator.StringToHash(“Locomotion”);
}
}
(D:\zz_DemoPro()-\小案例006、秘密行动Demo\Demo006_StealthActionDemo\Assets\Scripts\KeyPickup.cs)
using UnityEngine;
using System.Collections;
public class KeyPickup:MonoBehaviour{
public AudioClip pickAud; //拾取到钥匙的声音
private PlayerInventory playerInventory;
void Awake(){
playerInventory = GameObject.FindWithTag(Tags.Player).GetComponent<PlayerInventory>();
}
void OnTriggerEnter(Collider other){
if(other.tag == Tags.Player){
playerInventory.hasKey = true; //更换标志位,玩家获取到了钥匙
AudioSource.PlayClipAtPoint(pickAud, transform.position); //播放声音
Destroy(gameObject); //销毁自己
}
}
}
(D:\zz_DemoPro()-\小案例006、秘密行动Demo\Demo006_StealthActionDemo\Assets\Scripts\LaserController.cs)
using UnityEngine;
using System.Collections;
public class LaserController:MonoBehaviour{
public bool isBlinking=false; //激光是否是闪动的
public float blinkDeltaTime=3f; //闪动间隔时间
private float timer=0; //计时器
private LastPlayerSighting lastPlayerSighting; //玩家警报脚本
void Awake(){
//找到玩家警报脚本
lastPlayerSighting = GameObject.FindWithTag(Tags.GameController).GetComponent<LastPlayerSighting>();
}
void Update(){
timer += Time.deltaTime; //计时器计时
//到达计时器时间
if(timer>= blinkDeltaTime && isBlinking){
timer = 0; //计时器归零
//控制激光组件的显影
GetComponent<MeshRenderer>().enabled = !GetComponent<MeshRenderer>().enabled;
GetComponent<Light>().enabled = !GetComponent<Light>().enabled;
GetComponent<AudioSource>().enabled = !GetComponent<AudioSource>().enabled;
GetComponent<BoxCollider>().enabled = !GetComponent<BoxCollider>().enabled;
}
}
//玩家触碰到激光
void OnTriggerEnter(Collider other){
//如果是玩家
if(other.tag ==Tags.Player){
//将玩家位置同步到警报位置
lastPlayerSighting.alarmPosition = other.transform.position;
}
}
}
(D:\zz_DemoPro()-\小案例006、秘密行动Demo\Demo006_StealthActionDemo\Assets\Scripts\LaserSwitchDeactivation.cs)
using UnityEngine;
using System.Collections;
public class LaserSwitchDeactivation:MonoBehaviour{
public GameObject controlledLaser; //所控制的激光
public Material unlockMat; //解锁的屏幕材质
//当玩家进入到电脑控制范围
void OnTriggerStay(Collider other){
//当玩家按下Z键
if(Input.GetKeyDown(KeyCode.Z) && other.tag ==Tags.Player && controlledLaser.activeSelf){
controlledLaser.SetActive(false); //关闭激光
GetComponent<MeshRenderer>().material = unlockMat; //切换屏幕材质
GetComponent<AudioSource>().Play();
}
}
}
(D:\zz_DemoPro()-\小案例006、秘密行动Demo\Demo006_StealthActionDemo\Assets\Scripts\LastPlayerSighting.cs)
using UnityEngine;
using System.Collections;
public class LastPlayerSighting : MonoBehaviour{
public Vector3 alarmPosition = new Vector3(1000,1000,1000); //警报位置
public Vector3 normalPosition = new Vector3(1000,1000,1000); //非警报位置
public float turnSpeed=3f; //声音切换速度
private AlarmLight alarmLight; //警报灯脚本
private AudioSource mainAudio; //主背景音乐
private AudioSource panicAudio; //警报背景音乐
private AudioSource[] alarmAudios; //警报喇叭声音
void Awake(){
//找到警报灯脚本
alarmLight = GameObject.FindWithTag(Tags.AlarmLight).GetComponent<AlarmLight>();
mainAudio = GetComponent<AudioSource>(); //找到主背景音乐
//找到警报背景音乐
panicAudio = transform.GetChild(0).GetComponent<AudioSource>();
//先找到所有喇叭对象
GameObject[] sirens =GameObject.FindGameObjectsWithTag(Tags.Siren);
alarmAudios = new AudioSource[sirens.Length]; //初始化AudioSource数组
//获取所有喇叭对象中的AudioSource组件
for(inti =0; i< sirens.Length; i++){
alarmAudios[i] =sirens[i].GetComponent<AudioSource>();
}
}
void Update(){
//解除警报
if(alarmPosition == normalPosition){
alarmLight.alarmOn =false; //关闭警报灯
//渐渐关闭警报背景音乐
panicAudio.volume =Mathf.Lerp(panicAudio.volume,0,Time.deltaTime*turnSpeed);
//逐个渐渐关闭警报喇叭声音
for(inti=0; i <alarmAudios.Length; i++){
alarmAudios[i].volume = Mathf.Lerp(alarmAudios[i].volume,0,Time.deltaTime*turnSpeed);
}
//渐渐开启主背景音乐
mainAudio.volume = Mathf.Lerp(mainAudio.volume,1,Time.deltaTime*turnSpeed);
}else{ //开启警报
alarmLight.alarmOn =true; //开启警报灯
//渐渐关闭主背景音乐
mainAudio.volume = Mathf.Lerp(mainAudio.volume,0,Time.deltaTime*turnSpeed);
//渐渐开启警报背景音乐
panicAudio.volume = Mathf.Lerp(panicAudio.volume,1,Time.deltaTime*turnSpeed);
//渐渐开启警报喇叭声音
for(int i = 0; i < alarmAudios.Length; i++){
alarmAudios[i].voluem = Mathf.Lerp(alarmAudios[i].volume,1,Time.deltaTime*turnSpeed);
}
}
}
}
(D:\zz_DemoPro()-\小案例006、秘密行动Demo\Demo006_StealthActionDemo\Assets\Scripts\LiftDoorsTracking.cs)
using UnityEngine;
using System.Collections;
using UnityEngine.SceneManagement;
public class LiftDoorTracking:MonoBehaviour{
private float timer;
public float waitTime=1f;
public float moveTime=2f;
public float moveSpeed=3f;
private Transform player;
private AudioSource liftRaise;
private AudioSource endGame;
void Awake(){
player = GameObject.FindWithTag(Tags.Player).transform;
liftRaise = GetComponent<AudioSource>();
endGame = transform.parent.GetComponent<AudioSource>();
}
void OnTriggerStay(Collider other){
if(other.tag == Tags.Player){
timer += Time.deltaTime;
//到达上升时间
if(timer > waitTime){
//播放电梯声音
if(!liftRaise.isPlaying){
liftRaise.Play();
}
//播放结束游戏声音
if(!endGame.isPlaying){
endGame.Play();
}
//电梯上升
transform.root.position += Vector3.up*Time.deltaTime*moveSpeed;
//人物上升
player.position +=Vector3.up*Time.deltaTime*moveSpeed;
if(timer > waitTime+moveTime){
//TODO:重启游戏
SceneManager.LoadScene(“Yanlz_Demo006_Stealth”);
}
}
}
}
}
(D:\zz_DemoPro()-\小案例006、秘密行动Demo\Demo006_StealthActionDemo\Assets\Scripts\PlayerHealth.cs)
using UnityEngine;
using System.Collections;
using UnityEngine.SceneManagement;
public class PlayerHealth:MonoBehaviour{
public float health =100; //玩家血量
public AudioClip endGameAud; //游戏结束声音
private Animator ani;
private bool isdead = false; //玩家是否死亡
private bool endGame = false; //游戏结束
void Awake(){
ani = GetComponent<Animator>();
}
public void TakeDamage(float damage){
health -= damage;
}
void Update(){
//如果血量小于等于0,死亡
if(health <=0&& !isdead){
ani.SetTrigger(HashIDs.Dead);
isdead = true;
}else if(isdead&& !endGame){
StartCoroutine(EndGame()); //开启结束游戏协程
endGame = true;
}
}
IEnumerator EndGame(){
AudioSource.PlayClipAtPoint(endGameAud,transform.position); //播放结束音效
yield return new WaitForSeconds(4.4f); //等待4.4秒
SceneManager.LoadScene(“Yanlz_Demo003_Stealth”);
}
}
(D:\zz_DemoPro()-\小案例006、秘密行动Demo\Demo006_StealthActionDemo\Assets\Scripts\PlayerInventory.cs)
using UnityEngine;
using System.Collections;
public class PlayerInventory:MonoBehaviour{
public boolhasKey=false; //玩家是否拥有钥匙
}
(D:\zz_DemoPro()-\小案例006、秘密行动Demo\Demo006_StealthActionDemo\Assets\Scripts\PlayerMovement.cs)
using UnityEngine;
using System.Collections;
//立钻哥哥:玩家控制脚本
public class PlayerMovement:MonoBehaviour{
public float turnSpeed=10; //转身速度
private float hor,ver; //操纵键变量
private bool sneak=false;
private Animator ani; //动画组件
private AudioSource aud; //声音组件
private PlayerHealth playerHealth;
void Awake(){
ani = GetComponent<Animator>();
aud = GetComponent<AudioSource>();
playerHealth = GetComponent<PlayerHealth>();
}
void Update(){
if(playerHealth.health>0){
//获取用户的按键情况
hor = Input.GetAxis(“Horizontal”);
ver = Input.GetAxis(“Vertical”);
}else{
hor = 0;
ver = 0;
}
if(Input.GetKey(KeyCode.LeftShift)){
sneak = true;
}else{
sneak = false;
}
//设置潜行参数
ani.SetBool(HashIDs.Sneak, sneak);
//如果用户按下了方向键
if(hor!=0 || ver!= 0){
//动画参数Speed渐变到5.5(奔跑动画)
ani.SetFloat(HashIDs.Speed,5.5f,0.1f, Time.deltaTime);
TurnDir(hor, ver); //玩家转向
}else{
ani.SetFloat(HashIDs.Speed,0); //立刻停下来
}
FootSteps(); //执行脚本声控制
}
//玩家转向
void TurnDir(float hor, float ver){
Vector3 dir = new Vector3(hor,0,ver); //拿到方向向量
//将方向向量转换成四元数(参考Y轴)
Quaternion qua = Quaternion.LookRotation(dir);
//玩家转向到该方向
transform.rotation =Quaternion.Lerp(transform.rotation,qua,Time.deltaTime*turnSpeed);
}
void FootSteps(){
//如果当前玩家正在播放Locomotion正常行走的动画
if(ani.GetCurrentAnimatorStateInfo(0).shortNameHash == HashIDs.LocomotionState){
//如果脚步声没有播放
if(!aud.isPlaying){
aud.Play(); //播放
}
}else{
aud.Stop(); //停止播放脚步声
}
}
}
(D:\zz_DemoPro()-\小案例006、秘密行动Demo\Demo006_StealthActionDemo\Assets\Scripts\SyncDoor.cs)
using UnityEngine;
using System.Collections;
public class SyncDoor:MonoBehaviour{
public Transform outterleft;
public Transform outterright;
private Transform innerleft;
private Transform innerright;
void Awake(){
innerleft = transform.GetChild(0);
innerright = transform.GetChild(1);
}
void Update(){
//左右里门同步左右外门
innerleft.localPosition = new Vector3(innerleft.localPosition.x,innerleft.localPosition.y,outterleft.localPosition.z);
innerright.localPosition = new Vector3(innerright.localPosition.x,innerright.localPosition.y,outterright.localPosition.z);
}
}
(D:\zz_DemoPro()-\小案例006、秘密行动Demo\Demo006_StealthActionDemo\Assets\Scripts\Tags.cs)
using UnityEngine;
using System.Collections;
//立钻哥哥:标签管理
public class Tags{
public const stringAlarmLight=“AlarmLight”;
public const stringSiren= “Siren”;
public const stringPlayer=“Player”;
public const string GameController=“GameController”;
public const string Enemy=“Enemy”;
}
++小案例007、A_Star
++++FindPath.cs
++++GridMap.cs
++++Node.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
public class FindPath : MonoBehaviour{
private GridMap _grid; //整张地图
public Transform startPoint, endPoint;
private void Start(){
_grid = GameObject.FindObjectOfType<GridMap>();
}
private void Update(){
FindingPath(startPoint.position, endPoint.position);
}
//立钻哥哥:核心算法:生成路径
private void FindingPath(Vector3 startPos,Vector3 EndPos){
//获取起点和终点的格子
Node startNode = _grid.GetNodeFromPosition(StartPos);
Node endNode = _grid.GetNodeFromPosition(EndPos);
//创建开启列表和关闭列表
List<Node> openSet =new List<Node>();
HashSet<Node>closeSet =new HashSet<Node>();
openSet.Add(startNode);
while(openSet.Count>0){
Node currentNode =openSet[0]; //从开启列表中随便取出一个节点
//取最小的节点
for(int i=0; i < openSet.Count; i++){
if(openSet[i].fCost < currentNode.fCost){
currentNode = openSet[i];
}
}
//从开启列表移除,加入关闭列表
openSet.Remove(currentNode);
closeSet.Add(currentNode);
//找到终点
if(currentNode == endNode){
GeneratePath(startNode, endNode); //生成一条路径
return;
}
foreach(var node in _grid.GetNeibourhood(currentode)){
if(!node._canWalk||closeSet.Contains(node)){
continue;
}
//计算与相邻格子的距离
int newCost = currentNode.gCost + GetDistance(currentNode,node);
if(newCost <node.gCost || !openSet.Contains(node)){
node.gCost =newCost;
node.hCost = GetDistance(node,endNode);
node.parent = currentNode;
if(!openSet.Contains(node)){
openSet.Add(node);
}
}
}
}
}
//计算两点间的距离
int GetDistance(Node a, Nodeb){
int cntX= Mathf.Abs(a._gridX-b._gridX);
int cntY =Mathf.Abs(a._gridY-b._gridY);
if(cntX>cntY){
return 14*cntY+10* (cntX-cntY);
}else{
return 14*cntX+10* (cntY-cntX);
}
}
//生成最终路径
private void GeneratePath(Node startNode,Node endNode){
List<Node> path =new List<Node>();
Node temp = endNode;
while(temp !=startNode){
path.Add(temp);
temp = temp.parent;
}
path.Reverse();
_grid.path=path;
}
}
(D:\yanlz_DemoPro()-\小案例007、AStar\Assets\GridMap.cs)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
public class GridMap:MonoBehaviour{
private Node[,] grid; //存放所有格子的容器
[Tooltip(“地图的尺寸”)]
public Vector2 gridSize;
[Tooltip(“每个格子的半径”)]
public float nodeRadius;
//直径
private float nodeDiamenter{
get{ return nodeRadius*2; }
}
[Tooltip(“障碍物所在的层”)]
public LayerMask ObstacleLayer;
private int gridCntX,gridCntY; //地图上横纵格子数量
public List<Node>path = new List<Node>(); //最终路径
private void Start(){
gridCntX = Mathf.RoundToInt(gridSize.x /nodeDiameter);
gridCntY = Mathf.RoundToInt(gridSize.y /nodeDiameter);
grid = newNode[gridCntX,gridCntY];
CreateGrid();
}
//立钻哥哥:创建节点
private void CreateGrid(){
Vector3 startPoint = transform.position-gridSize.x /2 *Vector3.right-Vector3.forward*gridSize.y /2;
for(int i=0; i < gridCntX; i++){
for(intj =0; j < gridCntY; j++){
//每个格子的世界坐标
Vector3 worldPoint = startPoint+ Vector3.right* (i *nodeDiameter+nodeRadius) +Vector3.forward* (j *nodeDiameter+nodeRadius);
//格子上是否有障碍物
bool canWalk = !Physics.CheckSphere(wordPoint,nodeRadius,ObstacleLayer);
grid[i,j] = new Node(canWalk,worldPoint,i,j);
}
}
}
//立钻哥哥:Unity回调
private void OnDrawGizmos(){
if(Application.isPlaying==false){
return;
}
if(gird ==null){
return;
}
foreach(var node in grid){
Gizmos.color = node._canWalk?Color.gray:Color.red; //指定颜色
//绘制图形
Gizmos.DrawCube(node._wordPos, (nodeDiameter -nodeDiameter*0.1f) *Vector3.one);
}
if(path !=null){
foreach(var node in path){
Gizmos.color = Color.green;
Gizmos.DrawCube(node._wordPos, (nodeDiameter -nodeDiameter*0.1f) *Vector3.one);
}
}
}
//根据世界位置,得到Node
public Node GetNodeFromPosition(Vector3 position){
float percentX = (position.x +gridSize.x /2) / gridSize.x;
float percentY = (position.z +gridSize.y /2) / gridSize.y;
percentX = Mathf.Clamp01(percentX);
percentY = Mathf.Clamp01(percentY);
int x = Mathf.RoundToInt((gridCntX-1) *percentX);
int y = Mathf.RoundToInt((gridCntY-1) *percentY);
return grid[x,y];
}
//获取一个格子周围的8个格子
public List<Node> GetNeibourhood(Node node){
List<Node> neibourhood= new List<Node>();
for(inti = -1; i <=1; i++){
for(int j = -1; j <= 1; j++){
if(i ==0&& j==0){
continue;
}
int tempX= node._gridX+i;
int tempY= node._gridY+j;
if(tempX < gridCntX && tempX > 0 && tempY> 0 &&tempY<gridCntY){
neibourhood.Add(grid[tempX,tempY]);
}
}
}
return neibourhood;
}
}
(D:\yanlz_DemoPro()-\小案例007、AStar\Assets\Node.cs)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
//立钻哥哥:格子数据结构
//Node: 一个小格子
//GridMap: 整张地图
//FindPath: 根据A*算法,生成的路径
public class Node{
public int gCost;
public int hCost;
public int fCost{
get{ return gCost+hCost; }
}
public Node parent; //指向父格子的指针
public int _gridX,_gridY; //格子序号
public bool _canWalk; //格子上方是否有障碍物
public Vector3 _worldPos; //格子所在的世界坐标
public Node(bool Canwalk, Vector3 position, int x, int y){
_canWalk = Canwalk;
_worldPos = position;
_gridX = x;
_gridY = y;
}
}
++小案例008、血条LiftBar跟随
++++FaceToCamera.cs
++++HeadHP.cs
++++HPTest.cs
++++PlayerMove.cs
(D:\yanlz_DemoPro()-\小案例008、血条LiftBar跟随\Assets\FaceToCamera.cs)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class FaceToCamera :MonoBehaviour{
private Camera camera;
void Start(){
camera = Camera.main;
}
//立钻哥哥:Update is called once per frame
void Update(){
Vector3 pos= camera.transform.position-transform.position;
pos.x = pos.z = 0;
transform.LookAt(camera.transform.position-pos);
transform.Rotate(0,180,0);
}
}
(D:\yanlz_DemoPro()-\小案例008、血条LiftBar跟随\Assets\HeadHP.cs)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class HeadHP:MonoBehaviour{
private Image image;
private int hp=150;
private int maxhp;
void Start(){
image = GetComponent<Image>();
maxhp = hp;
}
void Update(){
if(Input.GetKeyDown(KeyCode.Space)){
hp -= 10;
image.fillAmout = (float)hp/maxhp;
}
}
}
(D:\yanlz_DemoPro()-\小案例008、血条LiftBar跟随\Assets\HPTest.cs)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class HPTest:MonoBehaviour{
private RectTransform rectTrans;
public Transform target;
public Vector2 offsetPos;
void Start(){
rectTrans = GetComponent<RectTransform>();
}
void Update(){
Vector3 postar =target.transform.position;
Vector2 pos=RectTransformUtility.WorldToScreenPoint(Camera.main,postar);
rectTrans.position =pos+offsetPos;
}
}
(D:\yanlz_DemoPro()-\小案例008、血条LiftBar跟随\Assets\PlayerMove.cs)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
public class PlayerMove:MonoBehaviour{
private NavMeshAgent nav;
void Start(){
nav = GetComponent<NavMeshAgent>();
}
void Update(){
if(Input.GetMouseButtonDown(0)){
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
Raycasthit hit;
if(Physics.Raycast(ray, out hit)){
nav.SetDestination(hit.point);
}
}
}
}
#小案例009、见缝插针StickPin
++++GameManager.cs
++++Pin.cs
++++PinHead.cs
++++RotateSelf.cs
(D:\yanlz_DemoPro()-\小案例009、见缝插针StickPin\Assets\Scripts\GameManager.cs)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
public class GameManager:MonoBehaviour{
private Transform startPoint;
private Transform spawnPoint;
private Pin currentPin;
private bool isGameOver=false;
private int score =0;
private Camera mainCamera;
public Text scoreText;
public GameObject pinPrefab;
public float speed =3;
void Start(){
startPoint = GameObject.Find(“StartPoint”).transform;
spawnpoint = GameObject.Find(“SpawnPoint”).transform;
mainCamera = Camera.main;
SpawnPin();
}
private void Update(){
if(isGameOver){
return;
}
if(Input.GetMouseButtonDown(0)){
score++;
scoreText.text = score.ToString();
currentPin.StartFly();
SpawnPin();
}
}
void SpawnPin(){
currentPin = GameObject.Instantiate(pinPrefab,spawnPoint.position,pinPrefab.transform.rotation).GetComponent<Pin>();
}
public void GameOver(){
if(isGameOver){
return;
}
GameObject.Find(“Circle”).GetComponent<RotateSelf>().enabled = false;
StartCoroutine(GameOverAnimation());
isGameOver = true;
}
IEnumerator GameOverAnimation(){
while(true){
mainCamera.backgroundColor = Color.Lerp(mainCamera.backgroundColor,Color.red, speed* Time.deltaTime);
mainCamera.orthographicSize=Mathf.Lerp(mainCamera.orthographicSize, 4, speed*Time.deltaTime);
if(Mathf.Abs(mainCamera.orthographicSize-4) <0.01f){
break;
}
yield return 0;
}
yield return new WaitForSeconds(0.2f);
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
}
}
(D:\yanlz_DemoPro()-\小案例009、见缝插针StickPin\Assets\Scripts\Pin.cs)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Pin:MonoBehaviour{
public float speed= 5;
private bool isFly =false;
private bool isReach =false;
private Transform startPoint;
private Vector3 targetCirclePos;
private Transform circle;
void Start(){
startPoint = GameObject.Find(“StartPoint”).transform;
//circle = GameObject.Find(“Circle”).transform;
circle = GameObject.FindGameObjectWithTag(“Circle”).transform;
targetCirclePos = circle.position;
targetCirclePos.y -= 1.55f;
}
void Update(){
if(isFly ==false){
if(isReach==false){
transform.position = Vector3.MoveTowards(transform.position, startPoint.position, speed*Time.deltaTime);
if(Vector3.Distance(transform.position, startPoint.position) <0.05f){
transform.position = targetCirclePos;
transform.parent =circle;
isFly =false;
}
}
}
}
public void StartFly(){
isFly = true;
isReach = true;
}
}
(D:\yanlz_DemoPro()-\小案例009、见缝插针StickPin\Assets\Scripts\PinHead.cs)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PinHead:MonoBehaviour{
private void OnTriggerEnter2D(Collider2D collision){
if(collision.tag ==“PinHead”){
GameObject.Find(“GameManger”).GetComponent<GameManager>().GameOver();
}
}
}
(D:\yanlz_DemoPro()-\小案例009、见缝插针StickPin\Assets\Scripts\RotateSelf.cs)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class RotateSelf:MonoBehaviour{
public float speed=90;
void Update(){
transform.Rotate(new Vector3(0,0, -speed* Time.deltaTime));
}
}
#小案例010、UnityNetDemo
++++Player.cs
(D:\yanlz_DemoPro()-\小案例010、UnityNetDemo\Assets\Player.cs)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
public class Player :NetworkBehaviour{
public float rotSpeed=150f;
public float movSpeed= 3.0f;
private float hor,ver;
publicGameObject bulletPrefab;
publicTransform bulletSpawn;
voidUpdate(){
if(!isLocalPlayer){
return;
}
PlayerMove();
if(Input.GetKeyDown(KeyCode.Space)){
CmdFire();
}
}
[Command]
void CmdFire(){
GameObject bullect =Instantiate<GameObject>(bulletPrefab,bulletSpawn.position,bullectSpawn.rotation);
bullect.GetComponent<Rigidbody>().velocity = bullet.transform.forward*6;
NetworkServer.Spawn(bullect);
Destroy(bullet,2f);
}
void PlayerMove(){
hor = Input.GetAxis(“Horizontal”) * Time.deltaTime*rotSpeed;
ver = Input.GetAxis(“Vertical”) * Time.deltaTime*movSpeed;
transform.Rotate(0, hor, 0);
transform.Translate(0,0, ver);
}
public override void OnStartLocalPlayer(){
GetComponent<MeshRenderer>().material.color= Color.green;
}
}
#小案例011、SocketFileRecv
++++Server\Program.cs
++++Client\Program.cs
(D:\yanlz_DemoPro()-\小案例011、socketFileRecv\Server\ConsoleApp1\Program.cs)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Server{
class Program{
static void Main(string[] args){
Myserver server = newMyserver();
server.Start();
}
}
class Myserver{
Socket serverSocket = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
IPEndPoint point = new IPEndPoint(IPAddress.Any,12345);
public void Start(){
serverSocket.Bind(point);
serverSocket.Listen(10);
Console.WriteLine(“立钻哥哥Print:服务器启动成功”);
Thread acceptThread = new Thread(Accept);
acceptThread.IsBackground =true;
acceptThread.Start();
Console.ReadKey();
}
void Accept(){
Socket client = serverSocket.Accept();
IPEndPoint point = client.RemoteEndPointas IPEndPoint;
Console.WriteLine(point.Address +“[” + point.Port +“]连接成功”);
Thread receiveThread = new Thread(Receive);
receiveThread.IsBackground= true;
receiveThread.Start(client);
Accept();
}
public void Receive(objectobj){
Socket client = objas Socket;
IPEndPoint point= client.RemoteEndPointas IPEndPoint;
byte[]msg =newbyte[1024];
int length= client.Receive(msg);
Console.WriteLine(point.Address +“[” + point.Port +“]” + Encoding.UTF8.GetString(msg, 0, length));
Receive(client);
}
}
}
(D:\yanlz_DemoPro()-\小案例011、socketFileRecv\Client\ConsoleApp2\Program.cs)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
namespace Client{
class Program{
static void Main(string[] args){
MyClient client = newMyClient();
client.Connect(“127.0.0.1”,12345);
Console.WriteLine(“立钻哥哥Print:请输入内容”);
string msg = Console.ReadLine();
while(msg!= “q”){
client.Send(msg);
msg =Console.ReadLine();
}
}
class MyClient{
Socket clientSocket = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
public void Connect(stringip,int port){
clientSocket.Connect(ip,port);
Console.WriteLine(“立钻哥哥Print:连接成功”);
}
public void Send(string msg){
clientSocket.Send(Encoding.UTF8.GetBytes(msg));
}
}
}
}
#小案例012、切水果CutFruitDemo
++++MouseControl.cs
++++DestroyOnTime.cs
++++ObjectControl.cs
++++Spawner.cs
++++UIOver.cs
++++UIScore.cs
++++UIStart.cs
(D:\yanlz_DemoPro()-\小案例012、切水果CutFruitDemo\Assets\MouseControl.cs)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
public class MouseControl:MonoBehaviour{
LineRenderer lineRenderer;
Vector3[] positions=new Vector3[10];
bool firstMouse;
bool MouseDown;
Vector3 head;
Vector3 last;
int posCount;
private voidStart(){
lineRenderer = GetComponent<LineRenderer>();
}
private void Update(){
if(Input.GetMouseButtonDown(0)){
firstMouse = true;
MouseDown = true;
}
if(Input.GetMouseButtonUp(0)){
MouseDown = false;
}
OnDrawLine();
firstMouse=false;
}
private void OnDrawLine(){
if(firstMouse){
posCount = 0;
head = Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePositon.x,Input.mousePosition.y,12.9f));
last = head;
}
if(MouseDown){
head = Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x,Input.mousePosition.y,12.9f));
if(Vector3.Distance(head,last) > 0.01f){
SavePosition(head);
posCount++;
OnRayCast(head);
}
last=head;
}else{
positions = new Vector3[10];
}
ChangePositions(positions);
}
void SavePosition(Vector3 pos){
if(posCount <= 9){
for(inti =posCount; i <=9; i++){
positions[i] =pos;
}
}else{
for(int i =0; i<9; i++){
positions[i] =positions[i +1];
positions[9] =pos;
}
}
}
void ChangePositions(Vector3[ ] positions){
linerRenderer.SetPositions(positions);
}
void OnRayCast(){
Vector3 screenPosition = Camera.main.WorldToScreenPoint(pos);
Ray ray = Camera.main.ScreenPointToRay(screenPosition);
RaycastHit[]hits =Physics.RaycastAll(ray);
for(int i =0; i <hits.Length; i++){
hits[i].collider.gameObject.SendMessage(“OnCut”,SendMessageOptions.DontRquireReceiver);
}
}
}
(D:\yanlz_DemoPro()-\小案例012、切水果CutFruitDemo\Assets\Scripts\DestroyOnTime.cs)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//立钻哥哥:按照时间销毁
public class DestroyOnTime:MonoBehaviour{
public float desTime=2f;
void Start(){
Invoke(“Dead”, desTime);
}
void Dead(){
Destroy(gameObject);
}
}
(D:\yanlz_DemoPro()-\小案例012、切水果CutFruitDemo\Assets\Scripts\ObjectControl.cs)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//立钻哥哥:物体控制脚本
public class ObjectControl:MonoBehaviour{
public GameObject halfFruit; //一半的水果
public GameObject Splash;
public GameObject SplashFlat;
public GameObject Firework;
private bool dead=false;
public AudioClip ac;
//被切割的时候调用
public void OnCut(){
//防止重复调用
if(dead){
return;
}
if(gameObject.name.Contains(“Bomb”)){
//生成特效
Instantiate(Firework,transform.position,Quaternion.identity)
UIScore.Instance.Remove(20); //如果是炸弹,就需要扣分
}else{
//先生成被切割的水果
for(inti = 0; i <2; i++){
GameObject go= Instantiate<GameObject>(halfFruit,transform.position,Random.rotation);
go.GetComponent<Rigidbody>().AddForce(Random.onUnitSphere*5f,ForceMode.Impulse);
}
//生成特效
Instantiate(Splash,transform.position,Quaternion.identity);
Instantiate(SplashFlat,transform.position,Quaternion.identity);
UIScore.Instance.Add(10); //如果是水果,就加分
}
AudioSource.PlayClipAtPoint(ac,transform.position);
Destroy(gameObject); //销毁自身
dead = true;
}
}
(D:\yanlz_DemoPro()-\小案例012、切水果CutFruitDemo\Assets\Scripts\Spawner.cs)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//立钻哥哥:用来产生水果、炸弹等(也让它能控制销毁)
public class Spawner:MonoBehaviour{
[Header(“水果的预设”)]
public GameObject[] Fruits;
[Header(“炸弹的预设”)]
public GameObject Bomb;
public AudioSource audioSource; //播放声音的组件
float spawnTime = 3f; //产生时间
bool isPlaying = true; //是否在玩游戏
void Update(){
if(!isPlaying){
return;
}
spawnTime-= Time.deltaTime;
if(0 >spawnTime){
//到时间了就开始产生水果
int fruitCount= Random.Range(1,5);
for(inti=0; i <fruitCount; i++){
onSpawn(true);
}
//随机产生炸弹
int bombNum = Random.Range(0,100);
if(bombNum>10){
onSpawn(false);
}
spawnTime=3f;
}
}
private int tmpZ=0; //临时存储当前水果的z坐标
//产生水果和炸弹
//param isFruit:是否是水果
private void onSpawn(bool isFruit){
this.audioSource.Play(); //播放音乐
//x范围:-8.4~8.4
//y范围:transform.pos.y
//得知坐标范围
float x =Random.Range(-8.4f, 8.4f);
float y = transform.position.y;
float z =tmpZ;
//tmpZ -= 2;
tmpZ = tmpZ-2; //使水果不在一个平面上
if(tmpZ<= -10){
tmpZ = 0;
}
//实例化水果
int fruitIndex =Random.Range(0, Fruits.Length);
GameObject go;
if(isFruit){
go = Instantiate<GameObject>(Fruits[fruitIndex],new Vector3(x,y,z),Random.rotation);
}else{
go = Instantiate<GameObject>(Bomb,new Vector3(x,y,z),Random.rotation)
}
//水果的速度
Vector3 velocity =new Vector3(-x *Random.Range(0.2f,0.8f), -Physics.gravity.y *Random.Range(1.2f,1.5f),0);
//Rigidbody rigidbody = transform.GetComponent
Rigidbody rigidbody = go.GetComponent<Rigidbody>();
rigidbody.velocity= velocity;
}
//有物体碰撞的时候调用
private void OnCollisionEnter(Collision other){
Destroy(other.gameObject);
}
}
(D:\yanlz_DemoPro()-\小案例012、切水果CutFruitDemo\Assets\Scripts\UIOver.cs)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Events;
public class UIOver :MonoBehaviour{
public UnityEvent events;
public void OnClick(){
UnityEngine.SceneManagement.SceneManager.LoadScene(0);
}
}
(D:\yanlz_DemoPro()-\小案例012、切水果CutFruitDemo\Assets\Scripts\UIScore.cs)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class UIScore:MonoBehaviour{
public static UIScore Instance=null; //立钻哥哥:单例对象
void Awake(){
Instance = this;
}
[SerializeField]
private Text txtScore;
private int score = 0; //当前多少分
//加分
public void Add(int score){
this.score += score;
textScore.text = this.score.ToString();
}
//扣分
public void Remove(int score){
this.score -= score;
//如果分数小于0,那么游戏结束
if(this.score <= 0){
UnityEngine.SceneManagement.SceneManager.LoadScene(“over”);
return;
}
textScore.text =this.score.ToString();
}
}
(D:\yanlz_DemoPro()-\小案例012、切水果CutFruitDemo\Assets\Scripts\UIStart.cs)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
public class UIStart:MonoBehaviour{
private Button btnPlay; //开始按钮
private Button btnSound; //声音按钮
private AudioSource audioSourceBG; //背景音乐播放器
private Image imgSound; //声音的图片
public Sprite[] soundSprites; //声音的图片
void Start(){
getCompnents();
btnPlay.onClick.AddListener(onPlayClick);
bthSound.onClick.AddListener(onSoundClick);
}
void OnDestroy(){
btnPlay.onClick.RemoveListener(onPlayClick);
btnPlay.onClick.RemoveListener(onSoundClick);
}
//寻找组件
private void getComponents(){
btnPlay = transform.Find(“btnPlay”).GetComponent<Button>();
btnSound = transform.Find(“btnSound”).GetComponent<Button>();
audioSourceBG = transform.Find(“btnSound”).GetComponent<AudioSource>();
imgSound = transform.Find(“btnSound”).GetComponent<Image>();
}
//当开始按钮按下的点击事件
void onPlayClick(){
SceneManager.LoadScene(“play”,LoadSceneMode.Single);
}
//当声音按钮点击时候调用
void onSoundClick(){
if(audioSourceBG.isPlaying){
//正在播放
audioSourceBG.Pause();
imgSound.sprite=soundSprites[1];
}else{
//停止播放
audioSourceBG.Play();
imgSound.sprite=soundSprites[0];
}
}
}
#小案例013、吃鸡_友军方位UV
++++CoordScript.cs
++++FriendMoveScript.cs
++++CameraScript.cs
(D:\yanlz_DemoPro()-\小案例013、吃鸡_友军方位UV\FriendCoordTest\Assets\CoordScript.cs)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using UnityEngine.UI;
public class CoordScript:MonoBehaviour{
RawImage rawImage;
public Transform friendTrans; //友军
public Transform friendImg; //友军Image
float width;
private void Start(){
rawImage = GetComponent<RawImage>();
width = transform.GetComponent<RectTransform>().rect.width;
}
private void Update(){
Rect tmpRect = new Rect(GetY(Camera.main.transform.eulerAngles.y),0.38f,1,1);
rawImage.uvRect =tmpRect;
//相机的投影前方
Vector3 cameraForward =new Vector3(Camera.main.transform.forward.x,0,Camera.main.transform.forward.z);
//计算与友军的夹角
Vector3 dir = friendTrans.position-Camera.main.transform.position;
dir = new Vector3(dir.x, 0, dir.z);
float angle= Vector3.Angle(cameraForward,dir);
//计算友军左右
Vector3 normal =Vector3.Cross(cameraForward,dir);
angle = normal.y<0 ?360-angle : angle; //计算最终夹角
float percent =GetYY(angle); //根据角度(0-1)的percent
float x =percent* width - width/2; //变换
friendImg.transform.localPosition =new Vector3(x, -30,0);
}
private float GetY(float x){
return (1 /360.0f) * (x %360) + 0.5f;
}
private float GetYY(float x){
return ((1 /180.0f) *x /2 +0.5f) %1;
}
}
(D:\yanlz_DemoPro()-\小案例013、吃鸡_友军方位UV\FriendCoordTest\Assets\FriendMoveScript.cs)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
public class FriendMoveScript:MonoBehaviour{
private void Update(){
transform.RotateAround(Vector3.zero,Vector3.up, Time.deltaTime*90f);
}
}
(D:\yanlz_DemoPro()-\小案例013、吃鸡_友军方位UV\FriendCoordTest\Assets\Scripts\Application\CameraScript.cs)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
public class CameraScript:MonoBehaviour{
public Transform y_Axis;
public Transform x_Axis;
public Transform z_Axis;
public Transform zoom_Axis;
public Transform player;
float hor,ver,scrollWheel;
public float roSpeed=180;
public float scSpeed=5f;
float upLimitAngle=60f;
float downLimitAngle=0;
public bool followFlag=true;
float x = 0;
floatsc= 8,minDis= 1,maxDis=12;
void LateUpdate(){
hor = Input.GetAxis(“Mouse X”);
ver = Input.GetAxis(“Mouse Y”);
scrollWheel = Input.GetAxis(“Mouse ScrollWheel”);
//水平旋转
if(hor != 0){
y_Axis.Rotate(Vector3.up*roSpeed* hor *Time.deltaTime);
}
//垂直旋转
if(ver!= 0){
x -= ver*Time.deltaTime*roSpeed;
x = Mathf.Clamp(x, -downLimitAngle,upLimitAngle);
Quaternion q =Quaternion.identity;
q = Quaternion.Euler(new Vector3(x,x_Axis.eulerAngles.y,x_Axis.eulerAngles.z));
x_Axis.rotation=q;
}
//缩放
if(scrollWheel != 0){
sc -= scrollWheel*Time.deltaTime*scSpeed;
zoom_Axis.transform.localPosition = new Vector3(0,0,Mathf.Clamp(-sc, -maxDis, -minDis));
}
//跟随玩家
if(followFlag){
y_Axis.position = player.position + Vector3.up*1.7f;
}
//控制玩家旋转
//player.forward = new Vector3(transform.forward.x, 0, transform.forward.z);
}
}
#小案例014、数据库背包SqliteEZ_Bag
++++DataBaseController.cs
++++HeroMessage.cs
++++SqliteDataScripts.cs
++++StoreWeapon.cs
++++WeaponBox.cs
(D:\yanlz_DemoPro()-\小案例014、SqliteEZ_Bag\Assets\DataBaseController.cs)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Mono.Data.Sqlite;
//立钻哥哥:封装数据库
public class DataBaseController:MonoBehaviour{
public static DataBaseController instance; //单例脚本对象
private string sqlitePath; //数据库地址
private SqliteConnection con; //连接
private SqliteCommand command;
private SqliteDataReader reader;
void Awake(){
instance = this;
}
//连接数据库
//param databaseName:数据库名称
public void ConnectToSqlite(string databaseName){
string connectDatabaseName = databaseName; //获取数据库名称
//判断数据库名称中是否包含.sqlite
if(!connectDatabaseName.Contains(“.sqlite”)){
connectDatabaseName +=“.sqlite”; //如果不包含就添加
}
//拼接数据库连接路径
sqlitePath =“Data Source=” +Application.streamingAssetsPath+“/” +connectDatabaseName;
con = new SqliteConnection(sqlitePath); //实例化数据库连接对象
command = con.CreateCommand(); //创建数据库指令对象
try{
con.Open(); //打开数据库
print(“立钻哥哥Print:数据库打开成功”);
}catch(SqliteException ex){
//抛出异常
Debug.Log(“立钻哥哥Print:----异常:” + ex);
}
}
//关闭数据库
public void CloseSqliteConnection(){
try{
//如果连接对象不为空
if(con != null){
con.Close(); //关闭数据库
}
}catch(SqliteExceptionex){
Debug.Log(“----” + exsss);
}
}
//查询属性信息
//param isHero:查询的是否是人物的属性
//param name:人物名称或者装备名称
public float[]SelectHeroMsg(bool isHero,string name){
try{
float[] result=newfloat[4]; //result:用于存储结果
string selectQuery; //查询
//如果查询的是人物的属性
if(isHero){
selectQuery =“select AD,AP,AR,MP from hero where HeroName =‘”+name+”’”;
}else{
selectQuery =“select AD,AP,AR,MP from Equip where EquipName =‘”+name+”’”
}
command.CommandText =selectQuery;
//执行sql语句
reader= command.ExecuteReader();
//读取第一行数据
while(reader.Read()){
//遍历获取的结果
//根据字段的个数进行遍历
for(int i =0; i <reader.FieldCount; i++){
result[i] =System.Convert.ToSingle(reader.GetValue(i));
}
}
reader.Close(); //关闭连接
return result; //返回结果
}catch(SqliteException ex){
Debug.Log(“立钻哥哥Print:出错了~~~” + ex);
return null;
}
}
//添加或者移除装备
public float[] AddOrRemoveProperty(boolisAdd, float[] heroProperty, float[] equipProperty){
try{
if(heroProperty.Length==4 &&equipProperty.Length==4){
float[] result =new float[4]; //创建结果数组,保存结果
//如果是添加装备
if(isAdd){
//遍历添加赋值
for(int i =0; i <result.Length; i++){
result[i] =heroProperty[i] +equipProperty[i];
}
}else{
//遍历移除赋值
for(inti =0; i<result.Length; i++){
result[i] =heroProperty[i] -equipProperty[i];
}
}
return result; //将结果返回
}else{
Debug.Log(“立钻哥哥Print:出错了,属性个数不匹配”);
return null;
}
}catch(SqliteException ex){
Debug.Log(“----异常:” + ex);
return null;
}
}
//更新数据库中英雄的属性信息
//param newHeroProperty:新的人物属性信息
//param heroName:人物名称
public void UpdateHeroProperty(float[] newHeroProperty, string heroName){
try{
//更新人物属性信息sql语句
string updateQuery =“update hero set ad=” + newHeroProperty[0]
+“,ap=” +newHeroProperty[1]
+“,ar=” +newHeroProperty[2]
+“,mp” +newHeroProperty[3]
+“ where heroname=’”+heroName+”’”
command.CommandText = updateQuery; //赋值给指令对象
command.ExecuteNonQuery(); //执行sql语句:增删改操作
}catch(SqliteException ex){
Debug.Log(“----出错了:” + ex);
}
}
//直接通过SQL语句去查询一个结果
//returns:查询到的单个数据
//param query:SQL语句
public object SelectSingle(string query){
try{
command.CommandText =query; //赋值SQL语句
object obj =command.ExecuteScalar(); //执行查询语句
return obj; //返回结果
}catch(SqliteExceptionex){
Debug.Log(“立钻哥哥Print: ----异常:” + ex);
return null;
}
}
//查询更多数据
//returns:数据结果
//param query: SQL语句
public List<ArrayList> SelectMore(string query){
try{
List<ArrayList> result =new List<ArrayList>(); //创建结果数组
command.CommandText= query; //赋值SQL语句
reader = command.ExecuteReader(); //执行
while(reader.Read()){
ArrayList temp =new ArrayList(); //实例化临时集合
for(int i =0; i <reader.FieldCount; i++){
temp.Add(reader.GetValue(i)); //将结果添加到集合中
}
result.Add(temp); //将临时集合添加到泛型集合(result)中
}
return result; //返回最终结果
}catch(SqliteException ex){
Debug.Log(“立钻哥哥Print:异常:” + ex);
return null;
}
}
}
(D:\yanlz_DemoPro()-\小案例014、SqliteEZ_Bag\Assets\HeroMessage.cs)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
//立钻哥哥:展示人物基础属性
public class HeroMessage:MonoBehaviour{
private Text uiText;
void Awake(){
uiText = transfrom.GetChild(0).GetComponent<Text>();
}
//更新人物UI的信息
//parma msg:人物信息数组
public void UpdateUIMessage(float[] msg){
//UIText赋值
uiText.text = “攻击力” +msg[0] +“\n” +
“法强:” +msg[1] +“\n” +
“护甲:” +msg[2] +“\n” +
“魔抗” +msg[3];
}
void Start(){
DataBaseController.instance.ConnectToSqlite(“LOL”); //连接数据库
//查询数据
float[] heroMsg= DataBaseController.instance.SelectHeroMsg(true, “EZ”);
UpdateUIMessage(heroMsg); //展示
DataBaseController.instance.CloseSqliteConnection(); //关闭数据库
}
}
(D:\yanlz_DemoPro()-\小案例014、SqliteEZ_Bag\Assets\SqliteDataScript.cs)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Data;
using Mono.Data.Sqlite;
public class SqliteDataScript:MonoBehaviour{
private string path; //指定路径
void Start(){
path = Application.dataPath +“/weapon.sqlite”; //1、数据存储的路径
//2、创建数据库连接(Data Source:数据源)
SqliteConnection connection =new SqliteConnection(“Data Source=” +path);
connection.Open(); //3、打开数据库
//4、创建指令对象(真正执行sql语句)
SqliteCommand command =connection.CreateCommand();
//5、将sql语句设置给指令对象
//string InsertStr =“insert into hero values(‘立钻哥哥’,10,8,100)”; //插入
//string InsertStr =“insert into hero values(‘亦菲妹妹’,10,8,100)”;
//string InsertStr =“insert into hero(‘heroname’,’ap’,’ad’,’level’)values(‘大哥哥’,10,8,100)”;
//string DeleStr =“delete from hero where level <5”; //删除
//string UpdateStr =“update hero set AP=1000 where rowid=2”; //修改
string SleStr =“select * from hero”; //查询
command.CommandText =SleStr;
//6、让指令对象去执行sql语句
//ExecuteNonQuery:只作为增,删,改操作,不做查询
command.ExecuteNonQuery();
//查询方法1:ExecuteScalar
//command.ExecuteScalar(); //返回所有结果中的第一个查询到的值
//查询方法2:ExecuteReader
//SqliteDataReader:查询到的所有值都会存储到SqliteDataReader中
SqliteDataReader reader= command.ExecuteReader();
//Read: 处理结果集(只要执行一次就会读取结果中的一行数据)
while(reader.Read()){
string name1 =reader.GetString(0); //取出字段值
int ap1= reader.GetInt16(1);
int ad1 =reader.GetInt16(2);
int level1 =reader.GetInt16(3);
print(string.Format(“name:{0},ap{1},ad{2},level:{3}”,name1,ap1,ad1,level1));
}
connection.Close(); //7、关闭数据库
}
}
(D:\yanlz_DemoPro()-\小案例014、SqliteEZ_Bag\Assets\StoreWeapon.cs)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class StoreWeapon:MonoBehaviour{
private WeaponBox box;
private HeroMessage msg;
void Start(){
box = GameObject.FindWithTag(“WeaponB”).GetComponent<WeaponBox>();
msg = GameObject.FindWithTag(“HeroMsg”).GetComponent<HeroMessage>();
}
//立钻哥哥:添加装备的按钮
//param equip:装备对象
public void OnAddEquipButtonClick(GameObject equip){
int index= box.CanAddEquip(); //查看装备栏中能否添加装备
//index != -1证明可以添加装备
if(index!= -1){
//拿到装备图片
Sprite equipImage = equip.GetComponent<Image>().sprite;
//将装备图片放置到装备栏中
box.transform.GetChild(index).GetComponent<Image>().sprite = equipImage;
string equipName = equip.name; //获取装备名称
//通过数据库查询到指定装备数据
DataBaseController.instance.ConnectToSqlite(“LOL”); //打开数据库
//查询并获得装备属性
float[] equipProperty = DataBaseController.instance.SelectHeroMsg(false,equipName);
//拿到人物属性
float[] heroProperty =DataBaseController.instance.SelectHeroMsg(true,“EZ”);
//生成新的人物属性
float[] newHeroProperty = DataBaseController.instance.AddOrRemoveProperty(true,heroProperty,equipProperty);
//将新的人物属性同步到数据库中
DataBaseController.instance.UpdateHeroProperty(newHeroProperty,“EZ”);
msg.UpdateUIMessage(newHeroProperty); //同步UI
DataBaseController.instance.closeSqliteConnection(); //关闭数据库
//将当前装备栏中的装备名称,存储到PlayerPrefs中
PlayerPrefs.SetString(“Weapon” +index,equip.name);
}
}
}
(D:\yanlz_DemoPro()-\小案例014、SqliteEZ_Bag\Assets\WeaponBox.cs)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class WeaponBox:MonoBehaviour{
public Sprite defaultPicture; //装备栏的默认图片
private HeroMessage msg;
public Sprite[] equipPicture; //所有装备图片的数组
void Awake(){
msg = GameObject.FindWithTag(“HeroMsg”).GetComponent<HeroMessage>();
}
void Start(){
//获得两个Weapon
string weapon0 = PlayerPrefs.GetString(“Weapon0”);
stirng weapon1= PlayerPrefs.GetString(“Weapon1”);
if(weapon!=“Empty”){
//遍历图片库
foreach(Sprite item in equipPicture){
//如果图片库中的图片名称和PlayerPrefs的名称一样
if(item.name== weapon0){
//将图片库中的这张图片显示到装备栏中
transform.GetChild(0).GetComponent<Image>().sprete=item;
}
}
}
if(weapon1!= “Empty”){
//遍历图片库
foreach(Sprite item in equipPicture){
if(item.name == weapon1){
transform.GetChild(1).GetComponent<Image>().sprite=item;
}
}
}
}
//能否添加装备
public int CanAddEquip(){
//获取两个装备栏中的图片名称
string box01= transform.GetChild(0).GetComponent<Image>().sprite.name;
string box02 = transform.GetChild(1).GetComponent<Image>().sprite.name;
string defaultName =“InputFieldBackground”; //装备栏默认图片的名称
//如果装备栏中没有装备
if(box01 == defaultName){
return 0;
}else if(box02 == defaultName){
return 1;
}else{
return -1;
}
}
//移除装备按钮
//param equip:装备
public void OnRemoveEquipButtonClick(GameObject equip){
string defaultName= “InputFieldBackground”; //装备栏默认图片名
if(equip.GetComponent<Image>().sprite.name!=defaultName){
//获取当前装备栏的装备名称
string equipName =equip.GetComponent<Image>().sprite.name;
//将装备栏图片设置为默认图片
equip.GetComponent<Image>().sprite = defaultPicture;
DataBaseController.instance.ConnectToSqlite(“LOL”); //打开数据库
//查询数据库获取当前装备栏装备的属性
float[] equipProperty =DataBaseController.instance.SelectHeroMsg(false,equipName);