结构图:
两个场景,一个是开始界面。一个是游戏界面:
脚本说明:依次是:敌人脚本,主角游戏,主菜单,工具
Enemy
1 using UnityEngine; 2 using System.Collections; 3 4 public class Enemy : MonoBehaviour 5 { 6 7 /*=============================== 8 * 敌人脚本 9 *==============================*/ 10 11 //敌人状态 12 13 //敌人站立状态 14 public const int STATE_STAND = 0; 15 //敌人行走状态 16 public const int STATE_WALK = 1; 17 //敌人奔跑状态 18 public const int STATE_RUN = 2; 19 //敌人暂停状态 20 public const int STATE_PAUSE = 3; 21 22 //记录敌人当前状态 23 private int enemState; 24 //主角对象 25 private GameObject hero; 26 27 //备份上一次敌人的思考时间 28 private float backUptime; 29 //敌人思考下一次行为时间 30 private const int AI_ATTACK_TIME = 2; 31 //敌人的巡逻范围 32 public const int AI_ATTACK_DISTANCE = 10; 33 34 //是否绘制血条 当鼠标指向敌人则绘制。离开则不绘制 35 bool showBlood = false; 36 37 //血条资源贴图 38 public Texture2D tex_red; 39 public Texture2D tex_black; 40 41 //生命值贴图 42 public Texture2D tex_hp; 43 44 //生命值 45 private int HP = 100; 46 47 //敌人仇恨 48 private bool ishatred = false; 49 50 //图片数字资源 51 Object[] texmube; 52 53 54 // Use this for initialization 55 void Start() 56 { 57 //获取主角对象,这里前端赋值比较好 58 hero = GameObject.Find("Hero"); 59 60 //读取图片资源 61 texmube = Resources.LoadAll("number"); 62 63 //设置敌人默认状态为站立 64 enemState = STATE_STAND; 65 } 66 67 // Update is called once per frame 68 void Update() 69 { 70 //判断敌人与主角之间的距离 71 if (Vector3.Distance(transform.position, hero.transform.position) < AI_ATTACK_DISTANCE || ishatred) 72 { 73 //敌人进入奔跑状态 74 gameObject.animation.Play("run"); 75 enemState = STATE_RUN; 76 77 //设置敌人面朝主角方向 78 transform.LookAt(hero.transform); 79 80 //随机攻击主角 81 int rand = Random.Range(0, 20); 82 if (rand == 0) 83 { 84 //模拟攻击, 85 //向主角发送攻击消息,然后在主角对象脚本中实现HeroHrut方法,进行主角减血 86 hero.SendMessage("HeroHurt"); 87 } 88 } 89 //敌人进入巡逻状态 90 else 91 { 92 //计算敌人的思考时间 93 if (Time.time - backUptime >= AI_ATTACK_TIME) 94 { 95 //敌人开始思考 96 //备份思考的时间 97 backUptime = Time.time; 98 99 //取得0~2之间的随机数 100 int rand = Random.Range(0, 2); 101 if (rand == 0) 102 { 103 //敌人进入站立状态 104 transform.animation.Play("idle"); 105 //设置状态 106 enemState = STATE_STAND; 107 } 108 else if (rand == 1) 109 { 110 //敌人进入行走状态 111 //敌人随机旋转角度 112 Quaternion rotate = Quaternion.Euler(0, Random.Range(1, 5) * 90, 0); 113 //1秒内完成旋转 114 transform.rotation = Quaternion.Lerp(transform.rotation, rotate, Time.deltaTime * 1000); 115 //播放行走动画 116 transform.animation.Play("walk"); 117 enemState = STATE_WALK; 118 } 119 120 } 121 } 122 switch (enemState) 123 { 124 case STATE_STAND: break; 125 case STATE_WALK: 126 //敌人行走 127 transform.Translate(Vector3.forward * Time.deltaTime); 128 //gameObject.animation.Play("walk"); 129 break; 130 case STATE_RUN: 131 //敌人朝向主角奔跑,当相距2时,就不向前跑了 132 if (Vector3.Distance(transform.position, hero.transform.position) > 3) 133 { 134 transform.Translate(Vector3.forward * Time.deltaTime * 3); 135 } 136 break; 137 } 138 } 139 void OnGUI() 140 { 141 if (showBlood)//如果绘制血条 142 { 143 //绘制生命值贴图 144 GUI.DrawTexture(new Rect(5, 0, tex_hp.width, tex_hp.height), tex_hp); 145 //绘制主角生命值 146 Tools.DrawImageNumber(200, 0, HP, texmube); 147 148 //绘制敌人血条 149 int blood_width = tex_red.width * HP / 100; 150 //绘制黑色血条 即底色 151 GUI.DrawTexture(new Rect(5, 50, tex_black.width, tex_black.height), tex_black); 152 //绘制红色血条 153 GUI.DrawTexture(new Rect(5, 50, blood_width, tex_red.height), tex_red); 154 } 155 } 156 157 /// <summary> 158 /// 当在敌人上单击鼠标左键 159 /// </summary> 160 void OnMouseDown() 161 { 162 //击中敌人目标 163 if (HP > 0) 164 { 165 //减掉5点血 166 HP -= 5; 167 //被击打时,后退 168 transform.Translate(Vector3.back * 1); 169 //击中敌人后立即进入战斗状态 170 ishatred = true; 171 } 172 else//敌人死亡 173 { 174 //敌人死亡 175 Destroy(gameObject); 176 //发送死亡消息 177 hero.SendMessage("EnemyHurt"); 178 } 179 } 180 void OnMouseUp() 181 { 182 //击打后退还原 183 transform.Translate(Vector3.forward * Time.deltaTime * 1); 184 } 185 void OnMouseOver() 186 { 187 //开始绘制血条 188 showBlood = true; 189 } 190 void OnMouseExit() 191 { 192 //结束绘制血条 193 showBlood = false; 194 } 195 }
Game
1 using UnityEngine; 2 using System.Collections; 3 4 public class Game : MonoBehaviour 5 { 6 /*=============================== 7 * 主角脚本 8 *==============================*/ 9 10 //游戏状态机 11 12 //游戏中状态 13 public const int STATE_GAME = 0; 14 //游戏胜利状态 15 public const int STATE_WIN = 1; 16 //游戏失败状态 17 public const int STATE_LOSE = 2; 18 19 //枚举角色鼠标位置 20 public enum RotationAxes { MouseXAndY = 0, MouseX = 1, MouseY = 2 } 21 public RotationAxes axes = RotationAxes.MouseXAndY; 22 float rotationY = 0f; 23 24 //鼠标准心 25 public Texture2D tex_fire; 26 27 //血条资源贴图 28 public Texture2D tex_red; 29 public Texture2D tex_black; 30 31 //生命值贴图 32 public Texture2D tex_hp; 33 34 //战斗胜利资源贴图 35 public Texture2D tex_win; 36 //战斗失败资源贴图 37 public Texture2D tex_lose; 38 //游戏音乐资源 39 public AudioSource music; 40 41 //主角生命值 42 public int HP = 100; 43 44 //图片数字资源 45 Object[] texmuber; 46 47 //当前游戏状态 48 int gameState; 49 50 51 52 // Use this for initialization 53 void Start() 54 { 55 //取消默认鼠标图标 56 Screen.showCursor = false; 57 //读取图片资源 58 texmuber = Resources.LoadAll("number"); 59 //设置默认状态为游戏中 60 gameState = STATE_GAME; 61 62 if (rigidbody) //如果是刚体 63 /* 64 如果freezeRotation被启用,旋转不会被物体模拟修改。 65 * 这对于创建第一人称射击游戏时是很有用的,因为玩家需要使用鼠标完全控制旋转。 66 */ 67 rigidbody.freezeRotation = true;////冻结旋转 68 } 69 70 // Update is called once per frame 71 void Update() 72 { 73 switch (gameState) 74 { 75 case STATE_GAME: UpdateGame(); break; 76 case STATE_WIN: 77 case STATE_LOSE: 78 if (Input.GetKey(KeyCode.Escape)) 79 { 80 Application.LoadLevel("Menu"); 81 } 82 break; 83 default: 84 break; 85 } 86 } 87 88 89 void OnGUI() 90 { 91 switch (gameState) 92 { 93 case STATE_GAME: 94 RenderGame(); 95 break; 96 case STATE_WIN: 97 GUI.DrawTexture(new Rect(0, 0, tex_win.width, tex_win.height), tex_win); 98 break; 99 case STATE_LOSE: 100 GUI.DrawTexture(new Rect(0, 0, tex_lose.width, tex_lose.height), tex_lose); 101 break; 102 default: 103 break; 104 } 105 } 106 107 private void RenderGame() 108 { 109 if (tex_fire) 110 { 111 //绘制鼠标准心 112 float x = Input.mousePosition.x - tex_fire.width / 2; 113 float y = Screen.height - Input.mousePosition.y - tex_fire.width / 2; 114 115 GUI.DrawTexture(new Rect(x, y, tex_fire.width, tex_fire.height), tex_fire); 116 } 117 118 //绘制主角血条 119 int blood_width = tex_red.width * HP / 100; 120 GUI.DrawTexture(new Rect(5, Screen.height - 50, tex_black.width, tex_black.height), tex_black); 121 GUI.DrawTexture(new Rect(5, Screen.height - 50, blood_width, tex_red.height), tex_red); 122 123 //绘制生命值贴图 124 GUI.DrawTexture(new Rect(5, Screen.height - 80, tex_hp.width, tex_hp.height), tex_hp); 125 126 //绘制主角生命值 127 Tools.DrawImageNumber(200, Screen.height - 80, HP, texmuber); 128 } 129 130 /// <summary> 131 /// 主角被攻击 132 /// </summary> 133 void HeroHurt() 134 { 135 HP--; 136 if (HP <= 0) 137 { 138 HP = 0; 139 gameState = STATE_LOSE; //游戏失败 140 } 141 } 142 143 /// <summary> 144 /// 碰到道具血条加血 145 /// </summary> 146 void HeroAddBlood() 147 { 148 HP += 50; 149 if (HP >= 100) 150 { 151 HP = 100; 152 } 153 } 154 /// <summary> 155 /// 敌人被攻击 156 /// </summary> 157 void EnemyHurt() 158 { 159 //找到所有的NPC 160 GameObject[] enemy = GameObject.FindGameObjectsWithTag("enemy"); 161 //Debug.Log(enemy.Length); 162 163 //敌人对象数字长度为1表示敌人全部死亡 164 if (enemy.Length == 1) 165 { 166 167 gameState = STATE_WIN; 168 } 169 } 170 private void UpdateGame() 171 { 172 if (Input.GetKey(KeyCode.Escape)) 173 { 174 Application.LoadLevel("Menu"); 175 } 176 //计算摄像机旋转 177 if (axes == RotationAxes.MouseX) 178 { 179 //旋转角色 180 transform.Rotate(0, Input.GetAxis("Mouse X"), 0); 181 } 182 else 183 { 184 //设置角色欧拉角 185 transform.localEulerAngles = new Vector3(-rotationY, transform.localEulerAngles.y, 0); 186 } 187 } 188 189 /// <summary> 190 /// 在移动的时,当controller碰撞到collider时OnControllerColliderHit被调用。 191 /// </summary> 192 /// <param name="hit"></param> 193 void OnControllerColliderHit(ControllerColliderHit hit) 194 { 195 //获取角色控制器碰撞到的游戏对象 196 GameObject collObj = hit.gameObject; 197 198 //是否为加血的箱子对象 199 if (collObj.name == "Cube") 200 { 201 //主角加血 202 HeroAddBlood(); 203 //销毁箱子 204 Destroy(collObj); 205 } 206 } 207 208 }
Menu
1 using UnityEngine; 2 using System.Collections; 3 4 public class Menu : MonoBehaviour { 5 6 /*=============================== 7 * 主菜单脚本 8 *==============================*/ 9 10 11 //游戏界面状态机 12 13 //主菜单界面 14 public const int STATE_MAINMENU = 0; 15 //游戏设置界面 16 public const int STATE_OPTION = 1; 17 //游戏帮助界面 18 public const int STATE_HELP = 2; 19 //游戏退出界面 20 public const int STATE_EXIT = 3; 21 //GUI皮肤 22 public GUISkin mySkin; 23 24 //游戏背景贴图 25 public Texture textureBG; 26 //开始菜单贴图 27 public Texture tex_startInfo; 28 //帮助菜单贴图 29 public Texture tex_helpInfo; 30 31 //游戏音乐资源 32 public AudioSource music; 33 //当前游戏状态 34 private int gameState; 35 36 // Use this for initialization 37 void Start() 38 { 39 //初始化游戏状态为主菜单界面 40 gameState = STATE_MAINMENU; 41 } 42 43 // Update is called once per frame 44 void Update() 45 { 46 47 } 48 void OnGUI() 49 { 50 switch (gameState) 51 { 52 case STATE_MAINMENU: 53 //绘制主菜单界面 54 RenderMainMenu(); 55 break; 56 case STATE_OPTION: 57 //绘制游戏设置界面 58 RenderOption(); 59 break; 60 case STATE_HELP: 61 //绘制游戏帮助界面 62 RenderHelp(); 63 break; 64 case STATE_EXIT: 65 //绘制游戏退出界面 66 //目前直接关闭并退出游戏 67 break; 68 default: 69 break; 70 } 71 } 72 /// <summary> 73 /// 绘制游戏帮助界面 74 /// </summary> 75 private void RenderHelp() 76 { 77 GUI.skin = mySkin; 78 GUI.DrawTexture(new Rect(0, 0, Screen.width, Screen.height), tex_helpInfo); 79 //返回按钮 80 if (GUI.Button(new Rect(0, 500, 403, 78), "", "back")) 81 { 82 gameState = STATE_MAINMENU; 83 } 84 } 85 /// <summary> 86 /// 绘制游戏设置界面 87 /// </summary> 88 private void RenderOption() 89 { 90 GUI.skin = mySkin; 91 GUI.DrawTexture(new Rect(0, 0, Screen.width, Screen.height), textureBG); 92 93 //开启音乐按钮 94 if (GUI.Button(new Rect(0, 0, 403, 75), "", "music_on")) 95 { 96 if (!music.isPlaying) 97 { 98 //播放音乐 99 music.Play(); 100 } 101 } 102 //关闭音乐按钮 103 if (GUI.Button(new Rect(0, 200, 403, 75), "", "music_off")) 104 { 105 //关闭音乐 106 music.Stop(); 107 } 108 //返回按钮 109 if (GUI.Button(new Rect(0, 500, 403, 78), "", "back")) 110 { 111 gameState = STATE_MAINMENU; 112 } 113 } 114 /// <summary> 115 /// 绘制主菜单界面 116 /// </summary> 117 private void RenderMainMenu() 118 { 119 //设置界面皮肤 120 GUI.skin = mySkin; 121 //绘制游戏背景图 122 GUI.DrawTexture(new Rect(0, 0, Screen.width, Screen.height), textureBG); 123 124 //开始游戏按钮 125 if (GUI.Button(new Rect(0, 30, 623, 153), "", "start")) 126 { 127 //进入开始游戏状态 128 Application.LoadLevel("Game"); 129 } 130 //游戏选项按钮 131 if (GUI.Button(new Rect(0, 180, 623, 153), "", "option")) 132 { 133 //处于开始游戏状态 134 gameState = STATE_OPTION; 135 } 136 //游戏帮助按钮 137 if (GUI.Button(new Rect(0, 320, 623, 153), "", "help")) 138 { 139 //进入游戏帮助状态 140 gameState = STATE_HELP; 141 } 142 //游戏退出按钮 143 if (GUI.Button(new Rect(0, 470, 623, 153), "", "exit")) 144 { 145 //退出游戏 146 Application.Quit(); 147 } 148 } 149 }
Tools
1 using UnityEngine; 2 using System.Collections; 3 4 public class Tools : MonoBehaviour 5 { 6 7 /*=============================== 8 * 工具脚本 9 *==============================*/ 10 11 12 /// <summary> 13 /// 14 /// </summary> 15 /// <param name="x">绘制数字 x坐标</param> 16 /// <param name="y">绘制数字 y坐标</param> 17 /// <param name="number">需要绘制的数字</param> 18 /// <param name="texnumber">绘制图片数组资源</param> 19 public static void DrawImageNumber(int x, int y, int number, Object[] texnumber) 20 { 21 //将整数数据转换为字符数组 22 char[] chars = number.ToString().ToCharArray(); 23 //计算图片的宽度与高度,因为每张图片都是一样大。所以这里获取第一张即可 24 Texture2D tex = (Texture2D)texnumber[0]; 25 int width = tex.width; 26 int height = tex.height; 27 28 //遍历字符数组 29 foreach (char item in chars) 30 { 31 //得到每一位整型数组 32 int i = int.Parse(item.ToString()); 33 //绘制图片数字 34 GUI.DrawTexture(new Rect(x, y, width, height), texnumber[i] as Texture2D); 35 x += width; 36 } 37 } 38 39 }
注意事项:NPC需要添加标签:enemy
游戏源码: