成品展示



每两秒会获得一个稳定风速,玩家可以把握住这个瞬间射箭,击中不同环得分不同,不击中不扣分,60s内够100分则获胜

游戏制作

脚本挂载与预制

箭靶子预制
在一个空对象上挂载五个扁平同心圆柱,设置圆柱厚度不同以便箭识别射中第几环,空对象上挂刚体组件,其余五个圆柱挂mesh碰撞器

箭的预制
在一个空对象上,挂上两个柱体分别作箭头和箭身,两个方形作箭尾,空对象设置为刚体,箭头和箭身添加碰撞器,以便和箭靶子碰撞后触发计分和停留。

游戏设计以及代码分析

类的UML图



沿用上一次设计模式,组合动作模式、单实例模式、工厂模式

各类说明

  • 导演类:管理游戏全局状态,获取当前游戏的场景,协调各个类之间的通讯,是单实例类,不被Unity内存管理所管理
  • 界面:负责与用户交互,检测用户的设计动作
  • 场记:负责调动工厂产生和回收箭、用户设计后让动作管理者设计箭的轨迹、让记分员计分、还有管理箭与靶子的碰撞
  • 动作管理者:被场记调用,为场景中的对象设计具体动作并执行
  • 记分员:记分员按箭射中的环数据计分,拥有计分规则
  • 箭工厂:负责生产和回收箭
  • 箭的脚本:因为箭是刚体,碰撞后需要触发事件

各类具体代码

因为这次只在飞碟游戏基础上修改了很少,所以这里只给出修改过的部分的代码,其余代码与上一篇飞碟游戏对应的类一样。

  • 箭的脚本 ArrowScript
    需要OnTriggerEnter方法设置碰撞事件,另外因为在射中箭靶子后需要马上计分,所以在这里需要实例化场记中的记分员计分
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class ArrowScript : MonoBehaviour
{public string shootring;private ScoreRecorder recorder;void OnTriggerEnter(Collider other){shootring = other.gameObject.tag;//使得箭停在靶子上Destroy(GetComponent<Rigidbody>());//让记分员计分recorder.Record(shootring);}// Use this for initialization  void Awake(){recorder = (ScoreRecorder)FindObjectOfType(typeof(ScoreRecorder));}
}
  • 记分员 ScoreRecorder
    只是把之前飞碟的计分方法改一下,击中不同的环得分不同
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class ScoreRecorder : MonoBehaviour {private float score;public float getScore(){return score;}public void Record(string target_ring){switch (target_ring){case "Ring10": score += 10; break;case "Ring8": score += 8; break;case "Ring6": score += 6; break;case "Ring4": score += 4; break;case "Ring2": score += 2; break;}}public void Reset(){score = 0;}
}
  • 界面 UserGUI
    增加两个Text显示风力和风向,在update方法中显示,其余代码和之前相同
    public Text windforce;//风力public Text winddirection;//风向void Update(){//检测用户射击action.shoot();float force = actionmanager.getWindForce();if (force < 0)winddirection.text = "风向 : 左";else if (force > 0)winddirection.text = "风向 : 右";elsewinddirection.text = "风向 : 没风";windforce.text = "风力 : " + actionmanager.getWindForce();}
  • 动作管理者
    只是在RoundSSActionManager类里新增射箭的函数,其余动作的基本类与之前相同
    设置箭的朝向为摄像机与鼠标点击点所成的方向,另外设置箭速和风力大小
public class RoundSSActionManager : SSActionManager, ISSActionCallback
{public RoundController scene;public MoveToAction action1, action2;public SequenceAction saction;private float speed = 20.0f;//箭速private float force = 0f; //风力//增加射箭动作public void shootArrowAction(GameObject arrow, Vector3 dir){arrow.transform.position = new Vector3(0, 0, -9);arrow.transform.up = dir;arrow.GetComponent<Rigidbody>().velocity = dir * speed; //设置箭速}public void wind(GameObject arrow, float time){   if(time % 2 == 0)//每两秒获取随机的风力 force = UnityEngine.Random.Range(-30, 30);if(arrow != null && arrow.GetComponent<Rigidbody>() != null)//箭还没射到靶子上,还没解除刚体组件{arrow.GetComponent<Rigidbody>().AddForce(new Vector3(force, 0, 0), ForceMode.Force);}}public float getWindForce(){return force;}protected new void Start(){scene = (RoundController)SSDirector.getInstance().currentScenceController;scene.actionManager = this;}protected new void Update(){base.Update();}public void actionDone(SSAction source){Debug.Log("Done");}
}
  • 场记 RoundController
    这里修改三处地方:

    • 把之前的射飞碟回收飞碟方法,改为射箭与回收箭的方法
    • 修改用户动作接口shoot()方法的具体实现
    • 增加FixedUpdate(),在其中添加力作用于箭,因为箭是刚体,所以它的物理运动在每一帧结束后才作用,形成风力效果

    完整代码如下:

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public enum State { WIN, LOSE, PAUSE, CONTINUE, START };public interface ISceneController
{State state { get; set; }void LoadResources();void Pause();void Resume();void Restart();
}public class RoundController : MonoBehaviour, IUserAction, ISceneController {public ArrowFactory arrowFactory;public RoundSSActionManager actionManager;public ScoreRecorder scoreRecorder;public List<GameObject> arrow;public GameObject new_arrow;public GameObject target;//游戏状态public State state { get; set; }//计时器, 每关60秒倒计时public int leaveSeconds;IEnumerator DoCountDown(){while (leaveSeconds >= 0){yield return new WaitForSeconds(1);leaveSeconds--;}}void Awake(){SSDirector director = SSDirector.getInstance();director.setFPS(60);director.currentScenceController = this;SSDirector.getInstance().currentScenceController.state = State.PAUSE;arrowFactory = Singleton<ArrowFactory>.Instance;scoreRecorder = Singleton<ScoreRecorder>.Instance;state = State.PAUSE;leaveSeconds = 60;}// Use this for initializationvoid Start () {actionManager = GetComponent<RoundSSActionManager>() as RoundSSActionManager;LoadResources();}void Update(){RecycleArrow();//回收箭Judge(); //判断输赢}private void FixedUpdate(){//物理运动在每一帧结束后才作用,添加风力效果actionManager.wind(new_arrow, leaveSeconds);}public void LoadResources(){Camera.main.transform.position = new Vector3(0, 0, -10);target =  GameObject.Instantiate(Resources.Load("Prefabs/Target")) as GameObject;target.transform.position = new Vector3(0, 0, 3);}public void shoot(){if (Input.GetMouseButtonDown(0) && (state == State.START || state == State.CONTINUE)){Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);Debug.Log("鼠标点击:" + ray.direction);//从工厂得到箭new_arrow = arrowFactory.GetArrow();arrow.Add(new_arrow);//提供鼠标点击方向,箭由动作管理器射出去actionManager.shootArrowAction(new_arrow, ray.direction);}}public void RecycleArrow()//回收{for(int i = 0; i < arrow.Count; i++){if(arrow[i].transform.position.y < -10 || arrow[i].transform.position.z > 15){arrowFactory.FreeArrow(arrow[i]);//让飞碟工厂回收arrow.Remove(arrow[i]);}}}public void Judge()//判断游戏状态,是否射中以及够不够分数进入下一回合{if (leaveSeconds == 0 && scoreRecorder.getScore() < 100)//时间到,分数不够,输了{StopAllCoroutines();//停止倒数state = State.LOSE;}else if ((leaveSeconds > 0 && scoreRecorder.getScore() >= 100)){StopAllCoroutines();//停止倒数state = State.WIN;}}public void Pause(){state = State.PAUSE;StopAllCoroutines();for (int i = 0; i < arrow.Count; i++){arrow[i].SetActive(false);//暂停后飞碟不可见}}public void Resume(){StartCoroutine(DoCountDown());         //开启协程计时state = State.CONTINUE;for (int i = 0; i < arrow.Count; i++){arrow[i].SetActive(true);//恢复后飞碟可见}}public void Restart(){scoreRecorder.Reset();Application.LoadLevel(Application.loadedLevelName);SSDirector.getInstance().currentScenceController.state = State.START;}}

到这里修改就完成了,这次的修改很简单,只是箭多了个刚体的组件处理,因为和上次飞碟游戏类似,所以代码都套用上次的了。

Unity3D学习——射箭游戏(工厂模式)相关推荐

  1. Unity3D学习—打飞碟—工厂模式和适配器模式

    类图设计 工厂模式 在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象. 缺点就是每创建一个新的产品就需要创建一个新的工厂实例,会增加系统的复杂性.由于飞碟游戏中只有 ...

  2. Unity3D常用设计模式之工厂模式

    Unity3D常用设计模式<工厂模式>   工厂模式(Factory Pattern)是游戏开发中比较常用的设计模式.这种类型的设计模式属于创建型模式,它提供了一种创建对象实例的最佳方式. ...

  3. c#设计模式学习1之工厂模式

    c#设计模式学习1之简单工厂 进入程序员这个行业快一年了,写的程序就那么多,一直感觉写的程序没有质的飞跃,看看高手人家的程序,感觉和自己写的差的很大,什么n层了等,看起来都费力,仔细琢磨可能是设计模式 ...

  4. Unity学习——射箭游戏

    射箭游戏 游戏视频<https://www.bilibili.com/video/av71160101/> 游戏工程文件https://github.com/JennySRH/3DGame ...

  5. 设计模式之游戏--工厂模式详解

    工厂模式 一.简单工厂模式 二.工厂方法模式 三.抽象工厂模式 使用总结 引入问题:在面向对象编程中,创建一个对象的最常用的方法是new一个对象实例,new对象操作符就是用来构造对象实例的,但是在一些 ...

  6. 【一】Java 设计模式学习记录: 工厂模式

    文章目录 一.设计模式的分类 二.工厂模式 2.1 简单工厂模式 2.1.1 解决的问题 2.1.2 简单工厂模式是什么 2.1.3 优缺点 2.2 工厂方法模式 2.2.1 解决的问题 2.2.2工 ...

  7. javascript学习(11)——[设计模式]工厂模式

    其实学过java的人基本都知道,工厂模式,我们是基本每天都在用,只不过工厂模式也分为几种情况:简单工厂,抽象工厂和智能工厂. 简单工厂其实,大家时时刻刻都在用,个人理解,当我们在一个函数中调用另一个函 ...

  8. 设计模式学习-简单工厂模式

    模式概述: 专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类,简单工厂(Simple Factory)模式又称为静态工厂方法(Static Factory Method)模式,属 ...

  9. 设计模式再学习之简单工厂模式

    以前不明白为啥要设计模式这玩意到底有啥用呀.那么僵硬,学起来臭长.今天学了简单模式,突然发现,诶?这不是我日常运用的吗 简单工厂模式 这个模式究竟有啥用呢,我看了十章内容,觉得可以概括成一句话. 在一 ...

最新文章

  1. BZOJ-1192-[HNOI2006]鬼谷子的钱袋
  2. linux+while循环多条件,有效的while循环条件客户端选择(TCP连接在Linux - C)
  3. 遇到问题为何该自己动手
  4. CSS学习05之结构伪类选择器
  5. Fiori里的exception继承
  6. 系列TCP/IP协议-动态IP选路协议(008)
  7. 友益文书类似软件_团队成员分享 | 港中文翻译学姐:硬件不够,软件来凑;心之所愿,无所不能...
  8. HZOJ 大佬(kat)
  9. CSS尺寸和字体单位-em、px还是%
  10. Linux命令九---Linux进程管理命令---ps-kill-nohup-jobs-fg-bg-top等
  11. linux IIC子系统分析(七)——实例分析通过i2c-dev操作I2C设备
  12. 微信开发平台和微信公众平台绑定
  13. 网络游戏开发实战-坦克大战学习问题记录
  14. 二进制炸弹——拆弹实验
  15. zbbz cnk2
  16. Drop user与cascade
  17. 关于编程的自我介绍和规划。
  18. 网页源文件星号怎么显示_【亲测实用】网页隐藏密码查看方法
  19. 云米发布上市后首份财报:非GAAP净利3875万 同比增36%
  20. 曝光了,清华计算机系最牛的课!

热门文章

  1. 【考研复习】IP地址划分小题
  2. iOS软件一天八杯水“app开发过程
  3. 功率放大器的作用和工作原理是什么
  4. 在VMware ESX中使用NAS的优缺点
  5. Future与CompletableFuture
  6. ABP+AdminLTE+Bootstrap Table权限管理系统一期
  7. html兼容ios8,[插件] 兼容iOS8越狱插件推荐合集
  8. Harvest watermelon
  9. 关于tracert与traceroute的区别
  10. KiCad FPC座阻焊层设置