Unity 3D游戏五:打飞碟

前言

中山大学数据科学与计算机学院3D游戏课程学习记录博客。
游戏代码: gitee
游戏视频: bilibili
参考师兄的博客: 师兄博客

游戏内容

  • 游戏有 n 个 round,每个 round 都包括10 次 trial;
  • 每个 trial 的飞碟的色彩、大小、发射位置、速度、角度、同时出现的个数都可能不同。它们由该 round 的 ruler 控制;
  • 每个 trial 的飞碟有随机性,总体难度随 round 上升;
  • 鼠标点中得分,得分规则按色彩、大小、速度不同计算,规则可自由设定。

游戏要求

  • 使用带缓存的工厂模式管理不同飞碟的生产与回收,该工厂必须是场景单实例的!具体实现见参考资源 Singleton 模板类
  • 近可能使用前面 MVC 结构实现人机交互与游戏模型分离

游戏分析

在本次的设计中:

  • 动作管理方面可以使用之前游戏四的动作管理器。但是需要增加与打飞碟相关的类。
  • 需要修改游戏界面,改进UI相关的类。
  • 需要修改FirstController类,改变游戏的进程。
  • 要使用单例模式和工厂模式。

单例模式:
单例模式的目的是为了实现只能有一个实例的类。好处是可以节省资源和防止错误。

工厂模式:
工厂模式是用一个类作为工厂,生产创建不同的产品,也就是其他对象。好处是方便代码的扩展以及减少代码编写。

游戏实现

  • 动作管理相关实现:
    飞碟的动作管理除了之前的代码外,用了新的两个类来实现飞碟的运动,分别是用来管理飞碟动作的FlyActionManager类和实现飞碟动作的类DiskFlyAction。
  1. FlyActionManager类:
    FlyActionManager类需要关联到FirstController类和DiskFlyAction类;
    一方面方便调用DiskFlyAction类的功能,一方面方便被FirstController类调用;
    FlyActionManager类需要实现初始化函数和管理飞行动作的函数。
public class FlyActionManager : SSActionManager {    
    public DiskFlyAction fly;      
    public FirstController sceneController;
    
    //初始化函数
    protected void Start() {        
        sceneController = (FirstController)SSDirector.GetInstance().CurrentScenceController;
        sceneController.action_manager = this;         
    }
    //管理飞行动作
    public void DiskFly(GameObject disk, float angle, float power) {        
    	//根据参数创建DiskFlyAction对象
    	//调用DiskFlyAction对象的功能
    }
}
  1. DiskFlyAction类:
    DiskFlyAction类需要实现飞碟的动作,所以需要一系列和移动相关的参数;
    DiskFlyAction类需要重载父类的部分函数。
public class DiskFlyAction : SSAction {    
    public float gravity = -5; //向下加速度    
    private Vector3 start_vector; //初速度   
    private Vector3 gravity_vector = Vector3.zero; //加速度  
    private Vector3 current_angle = Vector3.zero; //欧拉角    
    private float time; //时间
    
    //禁用默认构造函数
    private DiskFlyAction() { }    
    //提供使用三个参数创建DiskFlyAction实例的方法
    public static DiskFlyAction GetSSAction(int lor, float angle, float power) {       
	//根据参数初始化相关的变量
	//创建DiskFlyAction对象并返回
    }
    public override void Update() {          
	//根据变量改变物体的位置
    }
    //重载Start函数
    public override void Start() { }
}
  • UI界面改进实现:
    UI界面使用标签和按钮进行构造;
    未开始游戏时需要有游戏开始的按钮;
    开始游戏后需要显示游戏Round和Trial以及分数;
    UI界面详细代码见gitee仓库。

  • 工厂模式设计:
    工厂模式是用来生成飞碟的,所以具体包括Disk类和DiskFactory类。

1.Disk类:
Disk类只包含三个变量,用来创建飞碟。

public class Disk : MonoBehaviour {    
    public int type = 1;    
    public int score = 1;                                   
    public Color color = Color.white;                    
}

2.DiskFactory类:
DiskFactory类需要用容器存储飞碟,因此需要链表作为成员变量;
DiskFactory类需要实现生成飞碟和释放飞碟的函数。

public class DiskFactory : MonoBehaviour {    
    private List<Disk> used = new List<Disk>(); //将使用的
    private List<Disk> free = new List<Disk>(); //使用过的
    
    public GameObject GetDisk(int type) {        
	//寻找需要被释放的飞碟
	//根据type由预设生成飞碟
	//把产生的飞碟加入容器
	//返回产生的飞碟
    }    

    public void FreeDisk() {
        //释放所有飞碟
    }
    public void Reset() {        
        FreeDisk();    
    }
}
  • 单例模式设计:
    DiskFactory类和ScoreReconder类只需要一个实例;
    DiskFactory类用来生成飞碟;
    ScoreRecorder类用来记录分数;
    使用模板类Singleton的代码即可。

1.Singleton类代码:

public class Singleton<T> : MonoBehaviour where T : MonoBehaviour {    
    protected static T instance;    
    public static T Instance {        
        get {            
            if (instance == null) {                
                instance = (T)FindObjectOfType(typeof(T));
                if (instance == null) {                    
                    Debug.LogError("An instance of " + typeof(T)                        
                    + " is needed in the scene, but there is none.");
                }            
            }            
            return instance;        
        }    
    }
}

2.ScoreRecorder类代码:

//记录分数
public class ScoreRecorder : MonoBehaviour {    
    private float score;    
    void Start () {        
        score = 0;    
    }    
    public void Record(GameObject disk) {        
        score += disk.GetComponent<Disk>().score;    
    }    
    public float GetScore() {        
        return score;    
    }    
    public void Reset() {        
        score = 0;    
    }
}
  • FirstController类的实现:
    FirstController类需要一些成员变量存储正常游戏的数据信息;
    FirstController类需要实现游戏对象创建的函数;
    FirstController类需要实现点击飞盘的函数;
    FirstController类需要实现初始化函数;
    FirstController类需要其他相关函数。
public class FirstController : MonoBehaviour, ISceneController, IUserAction {    
    public FlyActionManager action_manager;    
    public DiskFactory disk_factory;    
    public UserGUI user_gui;    
    public ScooreRecorder score_recorder;    
    private int round = 1;                                                      
    private int trial = 0;    
    private float speed = 1f;                                                 
    private bool running = false;    
    public int count = 0;

    void Start () {        
        //下列两个成员用单例模式创建
        disk_factory = Singleton<DiskFactory>.Instance;        
        score_recorder = Singleton<ScoreRecorder>.Instance;
        //其他成员正常创建        
    }
    
    void Update () {
    	//游戏运行才进入        
	if(running) {            
	    count++;            
	    //检测鼠标点击
	    if (Input.GetButtonDown("Fire1")) {                
	        Vector3 pos = Input.mousePosition;                
	        Hit(pos);            
	    }       
	    //根据round的不同创建不同的飞碟
	    //产生不同的难度
	    //使用SendDisk函数产生飞碟
	}
    }
    //资源加载
    public void LoadResources() {        
        disk_factory.GetDiskoound);        
        disk_factory.FreeDisk();    
    }
    //产生飞碟
    private void SendDisk(int type) {
        //从工厂中拿一个飞碟        
	//通过随机的方式确定飞碟位置和角度
	//给游戏增加不确定性
    }
    
    public void Hit(Vector3 pos) {        
	//撞击发生事件
    }
    public float GetScore() {        
        return score_recorder.GetScore();    
    }    
    public int GetRound() {        
	return round;   
    }    
    public int GetTrial() {        	
	return trial;   
    }    
    public void ReStart() {        
        running = true;        
        score_recorder.Reset();        
        disk_factory.Reset();        
        round = 1;        
        trial = 1;        
        speed = 2f;    
    }    
    //游戏结束    
    public void GameOver() {        
        running = false;    
    }
}

至此,游戏设计完成。
详细代码见gitee仓库。

简答题

  • 编写一个简单的自定义 Component 。
    可以通过脚本来实现,编写一个DiskData.cs的脚本:
public class DiskData : MonoBehaviour{    
    public int score;    
    public Vector3 direction;    
    public Vector3 scale = new Vector3(1,1,1);
}

这样把它拉到预设上会出现这样的Component :
在这里插入图片描述

练习完成了!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值