3D游戏设计第六次作业——打飞碟物理模式
1 概述
在上一次的作业实现的基础上增加了物理模式,通过给飞碟增加刚体组件,实现飞碟拥有物理特性,会发生碰撞,也会收到重力影响。
2 代码讲解
2.1 与上一次相同的部分
本次作业新增一个物理模式,因此许多代码与上一次作业相同,没有发生改变。
单实例类Singleton.cs,定义了创建并调用单实例的方法。
导演基类SSSDirector.cs,单实例的导演类,协调场景控制器的使用,保证只有一个场景控制器在运行,不过本游戏中也只有一个飞碟场景控制器。
动作控制基类SSActionManager.cs,是所有动作类的基类,控制动作序列的进行或删除。组合工作管理器CCActionManager.cs、直线飞行动作CCFlyAtion.cs,这两个脚本主要涉及的是直线飞行的动作,没有发生改变。
飞碟信息disk.cs,保存飞碟的大小、速度、方向等信息。
飞碟工厂DiskFactory.cs,生产飞碟、销毁飞碟。
场景控制器接口IISceneController.cs,定义了场景控制器的抽象方法。
动作基类SSAction.cs,定义了与动作相关的成员对象和回调方法。
动作基类回调接口IISSActionCallback.cs,定义了动作回调事件的抽象方法。
2.2 物理模式涉及的添加和修改
- 用户交互接口IIUserAction.cs
添加了一个设定模式的抽象方法。
public interface IIUserAction{
GameState getGS();
void GameOver();
void gameStart();
void Hit(Vector3 pos);
void setMode(int m);
}
- 用户交互UUserGUI
添加模式选择的按钮,普通模式与物理模式
public enum GameState{ running,start,end,beforeStart}
public class UUserGUI : MonoBehaviour
{
int score=0;
private IIUserAction action;
// Start is called before the first frame update
void Start()
{
Debug.Log("action init");
action = SSSDirector.getInstance().currentSceneController as IIUserAction;
Debug.Log("action name"+action.ToString());
}
public void setScore(int s){
score = s;
}
// Update is called once per frame
void OnGUI(){
GUI.Label(new Rect(10,10,100,50),"得分:"+score);
// if(action.getGS() != GameState.running){
if(action.getGS()!=GameState.running){
if(GUI.Button(new Rect(100,150,100,50),"开始")){
action.gameStart();
}
if(GUI.Button(new Rect(100,205,100,50),"普通模式")){
action.setMode(1);
}
if(GUI.Button(new Rect(100,310,100,50),"物理模式")){
action.setMode(2);
}
}
if(Input.GetMouseButtonDown(0)){
action.Hit(Input.mousePosition);
}
if(action.getGS()==GameState.end){
GUI.Label(new Rect(Screen.width/2-50,Screen.height/2-25,100,50),"<color=#000000>游戏结束!</color>");
}
// }
}
}
- 物理飞行动作PhysisFlyAciont.cs
给物体添加刚体组件,并设定初速度,即可实现物理模式的飞碟飞行动作。
public class PhysisFlyAction : SSSAction
{
public float speed;
public Vector3 direction;
public static PhysisFlyAction GetSSAction(Vector3 direction, float speed ){
PhysisFlyAction action = ScriptableObject.CreateInstance<PhysisFlyAction>();
action.speed = speed;
action.direction = direction;
return action;
}
// Start is called before the first frame update
public override void Start()
{
this.gameObject.AddComponent<Rigidbody>();
this.gameObject.GetComponent<Rigidbody>().velocity = speed*direction;
}
// Update is called once per frame
public override void Update()
{
if(this.gameObject.transform.position.y<-7){
Destroy(this.gameObject.transform.GetComponent<Rigidbody>());
this.destroy = true;
this.enable = false;
this.callback.SSSActionEvent(this);
}
}
}
- 物理飞行动作管理器PhysisActionManager.cs
与组合动作管理器的功能相同,就是处理动作的进行和消除。
public class PhysisActionManager : SSActionManager, IISSActionCallback
{
public DiskSceneController sceneController;
public PhysisFlyAction fly;
// Start is called before the first frame update
protected void Start()
{
sceneController = (DiskSceneController)SSSDirector.getInstance().currentSceneController;
sceneController.phyactionManager = this;
}
public void Fly(GameObject disk, float speed, Vector3 dir){
fly = PhysisFlyAction.GetSSAction(dir,speed);
RunAction(disk, fly, this);
}
// Update is called once per frame
protected new void Update()
{
base.Update();
}
#region IISSActionCallback implementation
public void SSSActionEvent(SSSAction source, SSActionEventType events = SSActionEventType.Completed,int intParam = 0,
string strParam = null, Object objectParam = null){
// Debug.Log("manager free");
sceneController.FreeDisk(source.gameObject);
}
#endregion
}
- 飞碟场景控制器DiskSceneController.cs
增加一个方法setMode
,用于在用户选择模式时改变关于模式的变量mode
。同时在扔飞盘时根据mode
选择不同的动作管理器,并且也适当调整了物理模式下的丢飞盘的频率。
public class DiskSceneController : MonoBehaviour, IISceneController, IIUserAction
{
float time = 0;
int throwCount = 0;
public int disknum = 10;
public GameState state = GameState.beforeStart;
int score = 0;
DiskFactory diskfactory;
public CCActionManager actionManager;
public PhysisActionManager phyactionManager;
UUserGUI usergui;
public int mode = 1;
//要移动的物体
public GameObject obj;
// Start is called before the first frame update
void Start(){
SSSDirector director = SSSDirector.getInstance();
director.currentSceneController = this;
gameObject.AddComponent<DiskFactory>();
gameObject.AddComponent<CCActionManager>();
gameObject.AddComponent<PhysisActionManager>();
gameObject.AddComponent<UUserGUI>();
LoadResources();
}
public void LoadResources(){
diskfactory = Singleton<DiskFactory>.Instance;
usergui = Singleton<UUserGUI>.Instance;
actionManager = Singleton<CCActionManager>.Instance;
phyactionManager = Singleton<PhysisActionManager>.Instance;
}
public void Hit(Vector3 pos){
Ray ray = Camera.main.ScreenPointToRay(pos);
RaycastHit hit;
bool isCollider = Physics.Raycast(ray, out hit);
if(isCollider){
var fa = hit.collider.gameObject.transform.parent;
fa.position = new Vector3(0,-6,0);
score += countScore(fa.gameObject.GetComponent<disk>());
usergui.setScore(score);
}
}
public GameState getGS(){
return state;
}
private int countScore(disk d){
return d.color + d.size +4- d.speed;
}
public void Pause(){
}
public void setMode(int m){
mode = m;
}
public void Resume(){
throwCount = 0;
time = 0;
score = 0;
usergui.setScore(0);
}
void Update(){
if(state==GameState.running){
if(throwCount>=20){
state = GameState.end;
}
time += Time.deltaTime;
if(mode==1)
if(time>0.5){
time = 0;
for(int i = 0;i<3;i++){
throwCount++;
ThrowDisk();
}
}
if(mode==2)
if(time>0.5){
time = 0;
throwCount++;
ThrowDisk();
}
}
}
public void ThrowDisk(){
GameObject disk = diskfactory.getDisk();
if(mode==1) actionManager.Fly(disk, disk.GetComponent<disk>().speed,disk.GetComponent<disk>().dir);
else phyactionManager.Fly(disk,disk.GetComponent<disk>().speed,disk.GetComponent<disk>().dir);
}
public void gameStart(){
Resume();
state = GameState.running;
}
public void FreeDisk(GameObject disk){
Debug.Log("scene free");
diskfactory.FreeDisk(disk.GetComponent<disk>());
}
public void GameOver(){
}
}
3展示和代码地址
视频展示地址:https://www.bilibili.com/video/BV1G14y1K77y/?spm_id_from=333.999.0.0
代码地址:https://gitee.com/k_co/3-d-games/tree/master/HW6