unity小游戏-打飞碟

2023-11-21 14:59
文章标签 unity 小游戏 飞碟

本文主要是介绍unity小游戏-打飞碟,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、回顾

        上一个作业实现了动作分离+MVC,也就是Model+View+Controller+Action。同时,由于游戏对象自创建开始到游戏结束一直存在,游戏对象的创建、回收仍然由conroller统一管理。当游戏对象在游戏过程中提前被回收,同时又有新的游戏对象产生,对象的管理工作就不得不从controller中剥离出来,否则不但管理困难,游戏对象还难以复用。

        因此,这次在前面的框架的基础上,进一步细化:建立“游戏对象工厂”,统一管理游戏过程中游戏对象的产生、回收、复用等等。

二、游戏介绍

        在打飞碟游戏中,每一轮都会有新的飞碟产生,鼠标点中飞碟则被视为“打中飞碟”,会使飞碟消失,飞碟飞出屏幕区域同样会消失,一轮中飞碟全部消失则进入下一轮。从这里可以看到,游戏对象的创建与销毁是频繁的,而且新对象与旧对象之间没有实质性的差异,是可以复用的。

        视频链接:unity小游戏-打飞碟_单机游戏热门视频

三、实现

        代码实现部分借鉴了unity 实现简易打飞碟游戏-CSDN博客,respect。

        1、

        首先总体框架不变,Model+View+Controller+Action,对象工厂放在controller中(或许也可以提出来)。

         2、Actions

        Actions中的SSActionManager、SSAction几乎不变。

        对应的CCActionManager、CCAction逻辑如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class CCActionManager : SSActionManager, IActionCallback 
{public RoundController sceneController;//RoundController相当于FirstControllerpublic CCAction action;public DiskFactory factory;// Start is called before the first frame updatenew void Start(){sceneController = Singleton<RoundController>.Instance;sceneController.actionManager = this;factory = Singleton<DiskFactory>.Instance;}//回调函数public void SSActionEvent(SSAction source,SSActionEventType events = SSActionEventType.Completed,int intParam = 0,string strParam = null,Object objectParam = null) {//factory.FreeDisk(source.transform.gameObject);}public void MoveDisk(GameObject disk) {action = CCAction.GetSSAction(disk.GetComponent<DiskAttributes>().speedX, disk.GetComponent<DiskAttributes>().speedY);RunAction(disk, action, this);}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//飞碟从界面左右两侧飞入,离开界面时运动结束
public class CCAction : SSAction
{public float speedX;public float speedY;public static CCAction GetSSAction(float x, float y) {CCAction action = ScriptableObject.CreateInstance<CCAction>();//CCFlyAction action = SSAction.Instance;action.speedX = x;action.speedY = y;return action;}// Start is called before the first frame updatepublic override void Start(){}// Update is called once per framepublic override void Update(){//检查当前脚本所附加的游戏对象是否处于活动状态if (this.transform.gameObject.activeSelf == false) {//飞碟已经被"销毁"Debug.Log("1");this.destroy = true;this.callback.SSActionEvent(this);return;}Vector3 vec3 = Camera.main.WorldToScreenPoint (this.transform.position);if (vec3.x < -200 || vec3.x > Camera.main.pixelWidth + 200 || vec3.y < -200 || vec3.y > Camera.main.pixelHeight + 200) {Debug.Log("2");this.destroy = true;this.callback.SSActionEvent(this);return;}//更新位置//Time.deltaTime表示从上一帧到当前帧的时间间隔// += 速度*时间transform.position += new Vector3(speedX, speedY, 0) * Time.deltaTime * 2;}
}
       3、Controller

        RoundController负责管理轮次、调用对象工厂生成对象、检测鼠标是否点中飞碟,同时实现FirstController(场记)的功能。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Threading;public class RoundController : MonoBehaviour, ISceneController, IUserAction
{int round = 0;int max_round = 5;float timer = 0.5f;GameObject disk;DiskFactory factory ;public CCActionManager actionManager;public ScoreController scoreController;public UserGUI userGUI;//before Startvoid Awake() {SSDirector director = SSDirector.getInstance();director.currentSceneController = this;director.currentSceneController.LoadSource();//Add同时赋值给RoundController的CCAcM、ScoreCgameObject.AddComponent<CCActionManager>();gameObject.AddComponent<ScoreController>();gameObject.AddComponent<DiskFactory>();factory = Singleton<DiskFactory>.Instance;gameObject.AddComponent<UserGUI>();userGUI = gameObject.GetComponent<UserGUI>();}// Start is called before the first frame updatevoid Start(){}// Update is called once per framevoid Update(){if (userGUI.mode == 0) return;GetHit();gameOver();if (round > max_round) {return;}timer -= Time.deltaTime;if (timer <= 0 && actionManager.RemainActionCount() == 0) {//从工厂中得到10个飞碟,为其加上动作for (int i = 0; i < 10; ++i) {disk = factory.GetDisk(round);actionManager.MoveDisk(disk);}round += 1;if (round <= max_round) {userGUI.round = round;}timer = 4.0f;}}public void LoadSource() {}public void gameOver() {if (round > max_round && actionManager.RemainActionCount() == 0)userGUI.gameMessage = "THE END";}public void GetHit() {if (Input.GetButtonDown("Fire1")) {Vector3 mp = Input.mousePosition; //get Screen Position//create ray, origin is camera, and direction to mousepointCamera ca = Camera.main;Ray ray = ca.ScreenPointToRay(Input.mousePosition);//Return the ray's hitRaycastHit hit;if (Physics.Raycast(ray, out hit)) {//点中飞碟则加分scoreController.Record(hit.transform.gameObject);//设为不可见hit.transform.gameObject.SetActive(false);}else{//没点中飞碟则惩罚UnityEngine.Debug.Log("nope");scoreController.Publish();}}}
}

        ScoreController负责记分,包括增加飞碟对应的分数、惩罚减少分数。它在RoundController中被调用。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class ScoreController : MonoBehaviour
{int score;public RoundController roundController;public UserGUI userGUI;// Start is called before the first frame updatevoid Start(){roundController = (RoundController)SSDirector.getInstance().currentSceneController;//这行代码使得RoundController中的gameObject.AddComponent<ScoreController>();的同时,//将自身赋给了roundController.scoreController roundController.scoreController = this;userGUI = this.gameObject.GetComponent<UserGUI>();}//加分public void Record(GameObject disk) {score += disk.GetComponent<DiskAttributes>().score;userGUI.score = score;}//扣分public void Publish(){UnityEngine.Debug.Log("publish");if(score>=1)score-=1;userGUI.score = score;}}

        DiskFactory:

        功能:生产飞碟、设置飞碟属性值、管理飞碟。通过两个队列:free、used,分别管理空闲飞碟、正在被使用的飞碟。当需要新的飞碟的时候,就从空闲飞碟队列中取出一个返回,并且放到正在被使用飞碟中管理。当一个飞碟被销毁(实际上没有销毁),就从正在被使用队列移动到空闲飞碟,实现复用。

using System.IO;
using System.Diagnostics;
using System.Security.AccessControl;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MyException : System.Exception
{public MyException() { }public MyException(string message) : base(message) { }
}public class DiskFactory : MonoBehaviour
{List<GameObject> disk_used;List<GameObject> disk_free;System.Random rand;//public int miss=0;// Start is called before the first frame updatevoid Start(){disk_used = new List<GameObject>();disk_free = new List<GameObject>();rand = new System.Random();//Disk disk = GetDisk(1); }// Update is called once per framevoid Update(){}void setAttributes(GameObject disk,int round){//根据不同round设置diskAttributes的值//随意的旋转角度disk.transform.localEulerAngles = new Vector3(-rand.Next(20,40),0,0);DiskAttributes attri = disk.GetComponent<DiskAttributes>();attri.score = rand.Next(1,4);//由分数来决定速度、颜色、大小//速度(大小)attri.speedX = (rand.Next(1,5) + attri.score + round) * 0.2f;attri.speedY = (rand.Next(1,5) + attri.score + round) * 0.2f;//颜色Color[] color={Color.blue, Color.green, Color.red};disk.GetComponent<Renderer>().material.color = color[attri.score-1];//大小disk.transform.localScale += new Vector3(-0.2f * (attri.score-1), 0, -0.2f * (attri.score-1));//飞碟可从四个方向飞入(左上、左下、右上、右下)int[,] dir={{1,1},{1,-1},{-1,1},{-1,-1}};float[,] screenPos={{Screen.width*0.1f,0},{Screen.width*0.1f,Screen.height*1.1f},{Screen.width*1f,0},{Screen.width*0.8f,Screen.height*0.8f}};int direction = rand.Next(0,4);//速度方向attri.speedX *= dir[direction,0];attri.speedY *= dir[direction,1];//初始位置disk.transform.Translate(Camera.main.ScreenToWorldPoint(new Vector3(screenPos[direction,0], screenPos[direction,1], 8)));UnityEngine.Debug.Log("trans",disk.transform);}public GameObject GetDisk(int round) {GameObject disk;if (disk_free.Count != 0) {disk = disk_free[0];disk_free.Remove(disk);}else {disk=new Disk().disk;}setAttributes(disk,round);//setAttributes(disk,round);disk_used.Add(disk);disk.SetActive(true);UnityEngine.Debug.Log("generate disk");return disk;}public void FreeDisk(GameObject disk) {disk.SetActive(false);//将位置和大小恢复到预制,这点很重要!disk.transform.position = new Vector3(0, 0,0);disk.transform.localScale = new Vector3(2f,0.1f,2f);if (!disk_used.Contains(disk)) {throw new MyException("Try to remove a item from a list which doesn't contain it.");}UnityEngine.Debug.Log("free disk");disk_used.Remove(disk);disk_free.Add(disk);}
}

        Singleton:这个类并非控制器,它实现了单示例接口,保证游戏中一些实例对象的单一(比如只有一个对象工厂、记分员ScoreController、场记RoundController等等)

使用:在前面Action、Controller都有使用,比如CCActionManager中的:

        sceneController = Singleton<RoundController>.Instance;factory = Singleton<DiskFactory>.Instance;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;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;  }  }
}
4、Model、Views

        飞碟Disk

using System.Drawing;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class DiskAttributes : MonoBehaviour
{//public GameObject gameobj;public int score;public float speedX;public float speedY;
}public class Disk
{public GameObject disk;public Disk(){disk = GameObject.Instantiate(Resources.Load("Prefabs/disk", typeof(GameObject))) as GameObject;disk.AddComponent<DiskAttributes>();}
}
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class UserGUI : MonoBehaviour
{public int mode;public int score;public int miss;public int round;public string gameMessage;private IUserAction action;public GUIStyle bigStyle, blackStyle, smallStyle;//自定义字体格式public Font pixelFont;private int menu_width = Screen.width / 5, menu_height = Screen.width / 10;//主菜单每一个按键的宽度和高度// Start is called before the first frame updatevoid Start(){mode = 0;score = 0;miss = 0;round = 0;gameMessage = "";action = SSDirector.getInstance().currentSceneController as IUserAction;//pixelStyle//pixelFont = Font.Instantiate(Resources.Load("Fonts/ThaleahFat", typeof(Font))) as Font;//if (pixelFont == null) Debug.Log("null");//pixelFont.fontSize = 50;//pixelFont = Arial;//大字体初始化bigStyle = new GUIStyle();bigStyle.normal.textColor = Color.white;bigStyle.normal.background = null;bigStyle.fontSize = 50;bigStyle.alignment=TextAnchor.MiddleCenter;//blackblackStyle = new GUIStyle();blackStyle.normal.textColor = Color.black;blackStyle.normal.background = null;blackStyle.fontSize = 50;blackStyle.alignment=TextAnchor.MiddleCenter;//小字体初始化smallStyle = new GUIStyle();smallStyle.normal.textColor = Color.white;smallStyle.normal.background = null;smallStyle.fontSize = 20;smallStyle.alignment=TextAnchor.MiddleCenter;}// Update is called once per framevoid Update(){}void OnGUI() {//GUI.skin.button.font = pixelFont;GUI.skin.button.fontSize = 35;switch(mode) {case 0:mainMenu();break;case 1:GameStart();break;}       }void mainMenu() {GUI.Label(new Rect(Screen.width / 2 - menu_width * 0.5f, Screen.height * 0.1f, menu_width, menu_height), "HIT UFO", bigStyle);bool button = GUI.Button(new Rect(Screen.width / 2 - menu_width * 0.5f, Screen.height * 3 / 7, menu_width, menu_height), "START");if (button) {mode = 1;}}void GameStart() {UnityEngine.Debug.Log(Camera.main.pixelWidth);UnityEngine.Debug.Log(Screen.width*1f);GUI.Label(new Rect(Screen.width / 2 - menu_width * 0.5f, Screen.height * 0.1f, menu_width, menu_height), gameMessage,bigStyle);//, bigStyle300, 60, 50, 200GUI.Label(new Rect(Screen.width*0.8f, Screen.height * 0.8f-30, menu_width, menu_height), "Score: " + score, smallStyle);//0,0,100,50GUI.Label(new Rect(Screen.width*0.8f, Screen.height * 0.8f, menu_width, menu_height), "Round: " + round, smallStyle);}
}

这篇关于unity小游戏-打飞碟的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/403081

相关文章

Unity Post Process Unity后处理学习日志

Unity Post Process Unity后处理学习日志 在现代游戏开发中,后处理(Post Processing)技术已经成为提升游戏画面质量的关键工具。Unity的后处理栈(Post Processing Stack)是一个强大的插件,它允许开发者为游戏场景添加各种视觉效果,如景深、色彩校正、辉光、模糊等。这些效果不仅能够增强游戏的视觉吸引力,还能帮助传达特定的情感和氛围。 文档

Unity协程搭配队列开发Tips弹窗模块

概述 在Unity游戏开发过程中,提示系统是提升用户体验的重要组成部分。一个设计良好的提示窗口不仅能及时传达信息给玩家,还应当做到不干扰游戏流程。本文将探讨如何使用Unity的协程(Coroutine)配合队列(Queue)数据结构来构建一个高效且可扩展的Tips弹窗模块。 技术模块介绍 1. Unity协程(Coroutines) 协程是Unity中的一种特殊函数类型,允许异步操作的实现

Unity 资源 之 Super Confetti FX:点亮项目的璀璨粒子之光

Unity 资源 之 Super Confetti FX:点亮项目的璀璨粒子之光 一,前言二,资源包内容三,免费获取资源包 一,前言 在创意的世界里,每一个细节都能决定一个项目的独特魅力。今天,要向大家介绍一款令人惊艳的粒子效果包 ——Super Confetti FX。 二,资源包内容 💥充满活力与动态,是 Super Confetti FX 最显著的标签。它宛如一位

Unity数据持久化 之 一个通过2进制读取Excel并存储的轮子(4)

本文仅作笔记学习和分享,不用做任何商业用途 本文包括但不限于unity官方手册,unity唐老狮等教程知识,如有不足还请斧正​​ Unity数据持久化 之 一个通过2进制读取Excel并存储的轮子(3)-CSDN博客  这节就是真正的存储数据了   理清一下思路: 1.存储路径并检查 //2进制文件类存储private static string Data_Binary_Pa

Unity Adressables 使用说明(一)概述

使用 Adressables 组织管理 Asset Addressables 包基于 Unity 的 AssetBundles 系统,并提供了一个用户界面来管理您的 AssetBundles。当您使一个资源可寻址(Addressable)时,您可以使用该资源的地址从任何地方加载它。无论资源是在本地应用程序中可用还是存储在远程内容分发网络上,Addressable 系统都会定位并返回该资源。 您

Unity Adressables 使用说明(六)加载(Load) Addressable Assets

【概述】Load Addressable Assets Addressables类提供了加载 Addressable assets 的方法。你可以一次加载一个资源或批量加载资源。为了识别要加载的资源,你需要向加载方法传递一个键或键列表。键可以是以下对象之一: Address:包含你分配给资源的地址的字符串。Label:包含分配给一个或多个资源的标签的字符串。AssetReference Obj

在Unity环境中使用UTF-8编码

为什么要讨论这个问题         为了避免乱码和更好的跨平台         我刚开始开发时是使用VS开发,Unity自身默认使用UTF-8 without BOM格式,但是在Unity中创建一个脚本,使用VS打开,VS自身默认使用GB2312(它应该是对应了你电脑的window版本默认选取了国标编码,或者是因为一些其他的原因)读取脚本,默认是看不到在VS中的编码格式,下面我介绍一种简单快

Unity数据持久化 之 一个通过2进制读取Excel并存储的轮子(3)

本文仅作笔记学习和分享,不用做任何商业用途 本文包括但不限于unity官方手册,unity唐老狮等教程知识,如有不足还请斧正​​ Unity数据持久化 之 一个通过2进制读取Excel并存储的轮子(2) (*****生成数据结构类的方式特别有趣****)-CSDN博客 做完了数据结构类,该做一个存储类了,也就是生成一个字典类(只是声明)  实现和上一节的数据结构类的方式大同小异,所

【Unity小技巧】URP管线遮挡高亮效果

前言 在URP渲染管线环境下实现物体遮挡高亮显示效果,效果如下: Unity URP遮挡高亮 实现步骤 创建层级,为需要显示高亮效果的物体添加层级,比如Player 创建一个材质球,也就是高亮效果显示的材质球找到Universal Renderer Data Assets 4.在Assets上添加两个Render Objects组件 第一个做如下三处设置 指定遮挡层级指

【Unity面经】实习篇:面试官常问的一百个面试题

👨‍💻个人主页:@元宇宙-秩沅 👨‍💻 hallo 欢迎 点赞👍 收藏⭐ 留言📝 加关注✅! 👨‍💻 本文由 秩沅 原创 👨‍💻 专栏交流🧧🟥Unity100个实战基础✨🎁🟦 Unity100个精华一记✨🎁🟩 Unity50个demo案例教程✨🎁🟨 Unity100个精华细节BUG✨🎁🟨 Unity100个面试题✨🎁 文章