【Unity3D】射箭打靶游戏(简单工厂+物理引擎编程)
打靶游戏:
1.靶对象为 5 环,按环计分;
2.箭对象,射中后要插在靶上;
3.游戏仅一轮,无限 trials;
增强要求:
添加一个风向和强度标志,提高难度
游戏成品图:
UML图:
游戏设计思路&大致过程&核心代码
游戏对象主要由三个,靶、弓和箭,射出去的箭可以复用(利用简单工厂),将箭从弓的位置加上常力向某个方向射出。最后实现增强功能——添加常力作为风向并且在界面中显示出风向(只设置了界面上的左右两个不同方向)以及风力(0~50)。
1.首先设置游戏对象——靶子、弓和箭。
为了实现识别不同的环,通过五个共圆心的圆柱体(高度不同——通过设置Transform)来识别箭首先碰到的环(小环厚度较大)。
游戏的弓和箭——刚开始用圆柱体(箭身)+胶囊(箭头)实现箭,在后来进行界面优化时下载了模型。将模型直接作为预制即可。
2.大致明确类——建立在之前实验的基础上
2.1复用之前的类:不需要修改
SSDirector,Singleton,动作类——CCSequenceAction,SSAction,SSActionEvetType,SSActionManager
2.2需要修改的类:CCActionManager,FirstController,SceneController,UserGUI
3.设计基本UML图,调试好基本代码,只有空函数——不具体实现。
4.根据课堂实验5实现自由移动弓
在Bow的预制对象上挂上下述代码即可。利用方向控制键(键盘)可以控制弓的移动。
5.实现UI界面
6.实现箭的工厂类
7.实现射出箭的动作
8.实现箭插在靶上和分数识别计算
9.添加风力和风的方向
关键设置——在上述的第8点算是这次实验的一大难点,其余的基本在之前的实验都已经实现过类似的操作。
详细代码:
SSDirector.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Com.Mygame; public class SSDirector : System.Object {
private static SSDirector _instance; public ISceneController currentSceneController { get; set; }
public bool running{ get; set; } public static SSDirector getInstance() {
if (_instance == null) {
_instance = new SSDirector ();
}
return _instance;
} public int getFPS() {
return Application.targetFrameRate;
} public void setFPS(int fps) {
Application.targetFrameRate = fps;
}
}
FirstController.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using Com.Mygame;
public class FirstController : MonoBehaviour, ISceneController, IUserAction {
public IshootArrow actionManager {get; set;}
public ArrowFactory arrowfactory {get; set;}
public GameObject Arrow;
public GameObject Bow;
public Text ScoreText; // 显示得分 public int score;
void Awake() {
SSDirector director = SSDirector.getInstance ();
director.setFPS ();
director.currentSceneController = this;
director.currentSceneController.LoadResources ();
actionManager = gameObject.AddComponent<CCActionManager>();
arrowfactory = gameObject.AddComponent<ArrowFactory>();
}
public void hit(Vector3 dir) {
actionManager.playArrow(Bow.transform.position);
}
void Update() {
ScoreText.text = "Score:" + score.ToString();
}
public float getWindforce() {
return actionManager.getforce();
}
public void StartGame() {
//
}
public void ShowDetail() {
GUI.Label(new Rect(, , , ), "you can controll the bow and click mouse to emit arrow");
}
// 接口具体实现--------------------------------------------------------------------
public void LoadResources() {
Debug.Log ("load...\n");
Instantiate(Resources.Load("prefabs/Target"));
Bow = Instantiate(Resources.Load("prefabs/Bow")) as GameObject;
Arrow.transform.position = Bow.transform.position;
}
public void Pause(){
}
public void Resume(){
}
}
SceneController.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Com.Mygame; namespace Com.Mygame {
public interface ISceneController {
void LoadResources ();
float getWindforce();
}
public interface IUserAction {
void ShowDetail();
void StartGame();
void hit(Vector3 dir);
} }
UserGUI.cs
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
using Com.Mygame; public class UserGUI : MonoBehaviour { private IUserAction action; // 用户动作接口
private ISceneController queryInt; // 场景接口
public bool isButtonDown = false;
public Camera camera; public Text WindForce;
public Text WindDirection;
void Start() {
// 实例化对象
action = SSDirector.getInstance().currentSceneController as IUserAction;
queryInt = SSDirector.getInstance().currentSceneController as ISceneController;
}
void Update() {
float force = queryInt.getWindforce ();
if (force < ) {
WindDirection.text = "Wind Direction : Left";
} else if (force > ) {
WindDirection.text = "Wind Direction : Right";
} else {
WindDirection.text = "Wind Direction : No Wind";
}
WindForce.text = "Wind Force : " + queryInt.getWindforce(); //显示风力
}
void OnGUI() {
GUIStyle fontstyle1 = new GUIStyle();
fontstyle1.fontSize = ;
fontstyle1.normal.textColor = new Color(, , );
if (GUI.RepeatButton(new Rect(, , , ), "Rule")) {
action.ShowDetail();
}
if (GUI.Button(new Rect(, , , ), "Start")) {
action.StartGame();
}
if (Input.GetMouseButtonDown() && !isButtonDown) {
Ray mouseRay = camera.ScreenPointToRay (Input.mousePosition);
Debug.Log("RayDir = " + mouseRay.direction);
action.hit(mouseRay.direction);
isButtonDown = true;
}
else if(Input.GetMouseButtonDown() && isButtonDown) {
isButtonDown = false;
}
}
}
Singleton.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine; public class Singleton<T> where T: MonoBehaviour {
// 单例模式,可以在任何代码中轻松获取到单例对象 private static T instance; public static T Instance {
get {
if (instance == null) {
instance = (T)Object.FindObjectOfType(typeof(T));
if (instance == null) {
Debug.LogError("Cant find instance of "+typeof(T));
}
}
return instance;
}
}
}
Data.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[System.Serializable]
public class Data : MonoBehaviour {
public Vector3 size;
public Color color = Color.red;
public float speed = 5f;
public Vector3 director;
public play Action;
public bool hit;
}
ArrowFactory.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine; public class ArrowFactory : MonoBehaviour {
private static ArrowFactory _instance;
private List<GameObject> freeArrow; // 空闲的箭头
private List<GameObject> usedArrow;
private GameObject arrowTemplate; public FirstController sceneControler { get; set; } void Awake() {
if (_instance == null) {
_instance = Singleton<ArrowFactory>.Instance;
_instance.usedArrow = new List<GameObject>();
_instance.freeArrow = new List<GameObject>();
}
} public GameObject GetArrow1() {
GameObject newArrow;
if (freeArrow.Count == ) {
newArrow = GameObject.Instantiate(Resources.Load("Prefabs/arrow")) as GameObject;
} else {
newArrow = freeArrow[];
freeArrow.Remove(freeArrow[]);
} newArrow.transform.position = arrowTemplate.transform.position;
newArrow.transform.localEulerAngles = new Vector3(, , );
usedArrow.Add(newArrow);
return newArrow;
}
public void FreeArrow1(GameObject arrow1) {
for (int i = ; i < usedArrow.Count; i++) {
if (usedArrow[i] == arrow1) {
usedArrow.Remove(arrow1);
arrow1.SetActive(true);
freeArrow.Add(arrow1);
}
}
return;
}
// Use this for initialization
void Start () {
sceneControler = (FirstController)SSDirector.getInstance().currentSceneController;
sceneControler.arrowfactory = this;
arrowTemplate = Instantiate(Resources.Load("prefabs/arrow")) as GameObject;
arrowTemplate.SetActive (false);
//arrowTemplate.transform.parent = sceneControler.Bow.transform;
arrowTemplate.transform.localEulerAngles = new Vector3(, , );
freeArrow.Add(sceneControler.Arrow);
} // Update is called once per frame
void Update () { }
}
joystick.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine; public class joystick : MonoBehaviour {
public float speedY = 10.0F;
public float speedX = 10.0F;
//public GameObject cam; // Use this for initialization
void Start () { } // Update is called once per frame
void Update () {
//Debug.Log("p");
float translationY = Input.GetAxis("Vertical")*speedY;
float translationX = Input.GetAxis("Horizontal")*speedX;
translationY *= Time.deltaTime;
translationX *= Time.deltaTime;
transform.Translate(, translationY, );
transform.Translate(translationX, , );
/*if (Input.GetButtonDown("Fire1")) {
Debug.Log("Fired Pressed");
Debug.Log(Input.mousePosition); Vector3 mp = Input.mousePosition; //Camera ca = cam.GetComponent<Camera>();
Ray ray = ca.ScreenPointToRay(Input.mousePosition); RaycastHit hit;
if (Physics.Raycast(ray, out hit)) {
print(hit.transform.gameObject.name);
if (hit.collider.gameObject.tag.Contains("Finish")) {
Debug.Log("hit "+hit.collider.gameObject.name+"!");
}
}
}*/
}
}
target.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine; public class Target : MonoBehaviour {
public int num;//每个靶都有特定的分数
public play EmitDisk;
public FirstController sceneController;//场记
//private ScoreRecorder recorder;
public void Start() {
Debug.Log("target");
sceneController = (FirstController)SSDirector.getInstance().currentSceneController;
}
void OnTriggerEnter(Collider other) {
Debug.Log("jizhong");
Debug.Log(other.gameObject);
if (other.gameObject.tag == "Arrow") {
if (!other.gameObject.GetComponent<Data>().hit) {
other.gameObject.GetComponent<Data>().hit = true;
Debug.Log(num);
sceneController.score += num;//加分
}
EmitDisk = (play)other.gameObject.GetComponent<Data>().Action;
other.gameObject.GetComponent<Rigidbody>().velocity = Vector3.zero;//插在箭靶上
EmitDisk.Destory();//动作完成
} }
}
Aciton(动作类代码)
CCActionManager.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Com.Mygame;
public class CCActionManager : SSActionManager, ISSActionCallback, IshootArrow { public FirstController sceneController;
public ArrowFactory arrowFactory;
public play EmitArrow;
public GameObject Arrow;
public float force = 0f;
int count = ;
//public CCMoveToAction moveToA, moveToB, moveToC, moveToD; // Use this for initialization
protected new void Start () {
sceneController = (FirstController)SSDirector.getInstance().currentSceneController;
sceneController.actionManager = this;
arrowFactory = sceneController.arrowfactory;
} // Update is called once per frame
protected new void Update () {
base.Update();
}
public float getforce() {
return force;
}
public void playArrow(Vector3 dir) {
force = Random.Range(-,); //获取随机的风力
EmitArrow = play.GetSSAction();
//force = play.getWindForce();
//Debug.Log("play");
Arrow = arrowFactory.GetArrow1();
//Arrow.transform.position = new Vector3(0, 2, 0);
Arrow.transform.position = dir;
Arrow.GetComponent<Rigidbody>().AddForce(new Vector3(force, 0.3f, ), ForceMode.Impulse);
this.RunAction(Arrow, EmitArrow, this);
Arrow.GetComponent<Data>().Action = EmitArrow;
} //
public void SSActionEvent(SSAction source, SSActionEventType events = SSActionEventType.Competeted,
int intParam = , string strParam = null, Object objectParam = null) {
arrowFactory.FreeArrow1(source.gameobject);
Debug.Log("free");
source.gameobject.GetComponent<Data>().hit = false;
}
}
CCSequenceAction.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine; public class CCSequenceAction : SSAction, ISSActionCallback {
public List<SSAction> sequence;
public int repeat = -;
public int start = ; public static CCSequenceAction GetSSAction(int repeat, int start, List<SSAction> sequence) {
CCSequenceAction action = ScriptableObject.CreateInstance<CCSequenceAction>();
action.repeat = repeat;
action.sequence = sequence;
action.start = start;
return action;
} public override void Update() {
if (sequence.Count == ) return;
if (start < sequence.Count) {
sequence [start].Update();
}
} // Use this for initialization
public override void Start () {
foreach (SSAction action in sequence) {
action.gameobject = this.gameobject;
action.transform = this.transform;
action.callback = this;
action.Start();
}
} void OnDestory() {
//
} public void SSActionEvent(SSAction source, SSActionEventType events = SSActionEventType.Competeted,
int intParam = , string strParam = null, Object objectParam = null) {
source.destroy = false;
this.start++;
if (this.start >= sequence.Count) {
this.start = ;
if (repeat > ) repeat--;
if (repeat == ) {
this.destroy = true;
this.callback.SSActionEvent(this);
}
}
} }
IshootArrow.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Com.Mygame;
public interface IshootArrow {
void playArrow(Vector3 dir);
float getforce();
}
play.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine; public class play : SSAction {
int count = ;
bool enableEmit = true;
Vector3 force; public FirstController sceneControler = (FirstController)SSDirector.getInstance().currentSceneController;
public static play GetSSAction() {
play action = ScriptableObject.CreateInstance<play>();
return action;
}
// Use this for initialization
public override void Start() {
force = new Vector3(, 0.3f, );
} // Update is called once per frame
public override void Update() {
gameobject.GetComponent<Rigidbody>().velocity = Vector3.zero;
gameobject.GetComponent<Rigidbody>().AddForce(force, ForceMode.Impulse);
} public void Destory() {
this.destroy = true;
this.callback.SSActionEvent(this);
Destroy(gameobject.GetComponent<BoxCollider>());
}
}
SSAction.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine; public class SSAction : ScriptableObject {
public bool enable = true;
public bool destroy = false; public GameObject gameobject { get; set; }
public Transform transform {get; set;}
public ISSActionCallback callback {get; set;}
protected SSAction() {}
public virtual void Start() {
throw new System.NotImplementedException();
}
public virtual void Update() {
throw new System.NotImplementedException();
}
public virtual void FixedUpdate() {
throw new System.NotImplementedException();
}
}
SSActionEventType.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public enum SSActionEventType:int {Started, Competeted}
public interface ISSActionCallback {
void SSActionEvent(SSAction source, SSActionEventType events = SSActionEventType.Competeted,
int intParam = , string strParam = null, Object objectParam = null);
}
SSActionManager.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine; public class SSActionManager : MonoBehaviour { private Dictionary <int, SSAction> actions = new Dictionary <int, SSAction>();
private List<SSAction> waitingAdd = new List<SSAction>();
private List<int> waitingDelete = new List<int> (); // Use this for initialization
protected void Start () { } // Update is called once per frame
protected void Update () {
foreach (SSAction ac in waitingAdd) actions [ac.GetInstanceID()] = ac;
waitingAdd.Clear(); foreach (KeyValuePair <int, SSAction> kv in actions) {
SSAction ac = kv.Value;
if (ac.destroy) {
waitingDelete.Add(ac.GetInstanceID());
} else if (ac.enable) {
ac.Update();
}
} foreach (int key in waitingDelete) {
SSAction ac = actions[key];
actions.Remove(key);
DestroyObject(ac);
}
waitingDelete.Clear();
} public void RunAction(GameObject gameobject, SSAction action, ISSActionCallback manager) {
action.gameobject = gameobject;
action.transform = gameobject.transform;
action.callback = manager;
waitingAdd.Add(action);
action.Start();
}
}
【Unity3D】射箭打靶游戏(简单工厂+物理引擎编程)的更多相关文章
- Unity3D笔记 英保通七 物理引擎
给球体添加刚体RigidBody和球体碰撞器Sphere Collider 效果: OnTriggerEnter() 代码 using UnityEngine; using System.Collec ...
- Unity3D游戏开发初探—3.初步了解U3D物理引擎
一.什么是物理引擎? 四个世纪前,物理学家牛顿发现了万有引力,并延伸出三大牛顿定理,为之后的物理学界的发展奠定了强大的理论基础.牛顿有句话是这么说的:“如果说我看得比较远的话,那是因为我站在巨人的肩膀 ...
- 制作简单的2D物理引擎(零)
最近发现了Github上的开源物理引擎项目Matter.js,对它很感兴趣,发现源码并不算长,算上注释大约1万行左右,值得剖析一番.Matter.js实现一个最小化的2D物理引擎,性能不错,故打算用C ...
- Egret中使用P2物理引擎
游戏中的对象按照物理规律移动,体现重力.引力.反作用力.加速度等物体特性,实现自由落体.摇摆运动.抛物线运动,以及物理碰撞现象的模拟.用于模拟物理碰撞.物理运动的引擎称为物理引擎. 来自瑞典斯德哥尔摩 ...
- 物理引擎简介——Cocos2d-x学习历程(十三)
Box2D引擎简介 Box2D是与Cocos2d-x一起发布的一套开源物理引擎,也是Cocos2d-x游戏需要使用物理引擎时的首选.二者同样提供C++开发接口,所使用的坐标系也一致,因此Box2D与C ...
- Unity3D实践系列09, 物理引擎与碰撞检测
在Unity3D中,一个物体通常包含一个Collider和一个Rigidbody.Collider是碰撞体,一个物体是Collider,才可以进行碰撞检测.Collider组件中的"Is T ...
- SPRITEKIT游戏框架之关于PHYSICS物理引擎属性
Spritekit提供了一个默认的物理模拟系统,用来模拟真实物理世界,可以使得编程者将注意力从力学碰撞和重力模拟的计算中解放出来,通过简单地代码来实现物理碰撞的模拟,而将注意力集中在更需要花费精力的地 ...
- three.js cannon.js物理引擎制作一个保龄球游戏
关于cannon.js我们已经学习了一些知识,今天郭先生就使用已学的cannon.js物理引擎的知识配合three基础知识来做一个保龄球小游戏,效果如下图,在线案例请点击博客原文. 我们需要掌握的技能 ...
- 制作简单的2D物理引擎(一)——动力学基础
一切的基础 点 在二维平面中,点$P$就是坐标$(x,y)$,点集就是一系列坐标的集合$\{P_1,P_2,...,P_n\}$,不过这个集合是有序的(顺时针). 向量 加减运算 $$\vec{P}\ ...
随机推荐
- 洛谷P1018乘积最大——区间DP
题目:https://www.luogu.org/problemnew/show/P1018 区间DP+高精,注意初始化和转移的细节. 代码如下: #include<iostream> # ...
- POJ3264(线段树入门题)
Balanced LineupCrawling in process... Crawling failed Time Limit:5000MS Memory Limit:65536KB ...
- .NETFramework:DateTimeOffset
ylbtech-.NETFramework:DateTimeOffset 表示一个时间点,通常相对于协调世界时(UTC)的日期和时间来表示. 1.程序集 mscorlib, Version=4.0.0 ...
- BI 底座——数据仓库技术(Data Warehouse)
在开始喷这个主题之前,让我们先看看数据仓库的官方定义: 数据仓库(Data Warehouse)是一个面向主题的(Subject Oriented).集成的(Integrate).相对稳定的(Non- ...
- [hiho1578]Visiting Peking University
题意:签到题,不叙述了 解题关键:模拟即可. #include<bits/stdc++.h> #define inf 0x3f3f3f3f using namespace std; typ ...
- DL杂谈
好久不写了,几点这次项目经验吧,本次训练位多任务训练,主要目的训练人脸角度,具体公司项目不细谈. 讲一下主要碰到的坑: 1 最主要问题,网络结构不对称,导致主任务与辅助任务之间的梯度关系不平衡从而导致 ...
- .NET 下的 POP3 编程代码共享
前一段时间在论坛上看见有人问如何使用.net进行POP3编程,其实POP3的使用很简单,所以.net没有向SMTP那样给出相应的类来控制. 废话少说,程序员最需要的使代码. 1.打开VS.NET 20 ...
- 干货:SEO长尾关键词优化方法和技巧
在网站SEO优化上,优化比较成功的网站,根据SEO界前辈的经验结论,网站的总流量主要来源于长尾关键词,占网站总流量的80%.长尾关键词主要分布在网站的文章页,其次就是栏目页title.标签页.专题页等 ...
- Vue.js中,如何自己维护路由跳转记录?
在Vue的项目中,如果我们想要做返回.回退操作时,一般会调用router.go(n)这个api,但是实际操作中,使用这个api有风险,就是会让用户跳出当前应用,因为它记录的是浏览器的访问记录,而不是你 ...
- 小议IT公司的组织架构
IT公司的组织结构还是很相似的,常见的部门也不多.我简单地总结了下,分享给各位.每个公司都有自己独特的组织架构,本文仅供参考.很多部门和职位的职责和权力,我也不甚了解.简单地写写,有兴趣的同学可以补充 ...