IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 游戏开发 -> Unity中IMGUI实现井字棋小游戏 -> 正文阅读

[游戏开发]Unity中IMGUI实现井字棋小游戏

Unity中IMGUI实现井字棋小游戏

前言

这是中大计算机学院3D游戏编程课的一次作业,在这里分享一下设计思路。
主要代码上传到了gitee上,请按照后文的操作运行。
项目地址:https://gitee.com/cuizx19308024/unity-games/tree/master/hw1
成果视频:https://www.bilibili.com/video/BV13q4y1f7if?spm_id_from=333.851.dynamic.content.click

游戏说明

  • 使用IMGUI完成井字棋小游戏。
  • 使用ECS的基本理念,实现实体、系统和组件的分离。
  • 完成PVP和PVAI两个模式,可以选择先后手。

项目组成和运行环境

由于文件过大,本项目仅上传了Assets文件夹。不过其中包含了TicTacToc.cs代码文件,以及一些组件(图片、背景等)放在了Pictures文件夹中。
请按以下步骤进入项目:

  1. 在Unity Hub中创建一个新的项目,找到项目的位置,之后将Assets文件夹替换。

  2. 打开项目,选择左边栏SampleScene中的Script项。

  3. 将下方Assets/Pictures中的三张图片依次拖到右边属性栏中对应的三个位置,如图所示:(如果仍然保存这Script的属性,则不需要拖动)
    在这里插入图片描述
    在这里插入图片描述

  4. 编译,运行游戏。

设计与实现

整体思路和ECS

实体层需要设计基本的数据结构,如棋盘、玩家(可以用轮次代替)、游戏当前状态和游戏结果,此外还需要设计一些UI界面所需要的图片、背景等。
系统层需要实现游戏逻辑。设计了人机和双人两种模式,两种模式中人下棋子(检测棋子的位置)操作是完全相同的,因此可以抽象出人下棋和AI下棋两种方法。此外,还需要根据规则判断游戏结束,还需要设计初始化和修改参数的设置。
部件层需要展示交互界面,通过状态变量检测切换游戏界面(Unity的IMGUI是每一帧都要刷新一次的,因此需要利用这一机制根据变量改变自动切换)。

数据结构

数据结构如下:

private int[,] board = new int[3,3];
private int mode = 0;       //0为人人,1为人机
private int initTurn = 0;   //先手
private int turn = 0;       //当前轮次,0-玩家1,1-玩家2
private int state = -1;      //状态,1-进行中,0-结束,-1准备中
private int result = 0;     //结果,0-平局,1-玩家1获胜,2-玩家2获胜

//背景、样式、文字、棋盘位置
public Texture2D Background; 
public Texture2D X;
···

注意,由于本游戏设计简单,不需要存储玩家信息或复杂的棋盘信息,因此可以只用轮次和矩阵代替。

游戏逻辑

  1. 初始化
    void init(){
        turn = initTurn;
        for(int i=0;i<3;i++){
            for(int j=0;j<3;j++){
                board[i,j] = 0;
            }
        }
    }
    
  2. 玩家放棋子,找到对应的数组元素改变,并注意判断游戏结束和更换轮次。
    void PlayerPut(int i, int j){
        board[i,j] = turn + 1;  //放棋子
        int ret = judgeGame();  //判断
        if(ret != -1){          //状态切换
            state = 0;
            result = ret;
        }
        turn = 1-turn;          //轮换
    }
    
  3. AI放棋子策略
    AI应当做局部最优操作。对每一个方格,如果自己能赢,优先自己赢;之后如果对方能赢,优先堵住;否则,随机下。这里每一格做两个假设,即先将board[i,j]更改为1或2,得到测试结果,之后一定要将board[i,j]改回来。
    注意,应当先遍历方格判断自己赢,再遍历方格判断对方赢,否则得到的不是最优解。
    //先让自己赢(篇幅原因只展示局部代码)
    for(int i = 0; i<3;i++){
        for(int j=0;j<3;j++){
            if(board[i,j]==0){
                //假设下2,若赢,则下这。
                board[i,j] = 2;
                ret = judgeGame();
                board[i,j] = 0;
                if(ret == 2){
                    posX = i;
                    posY = j;
                    isLocated = 1;
                    break;
                }
            }
        }
        if(isLocated == 1){
            break;
        }
    }
    
  4. 判断游戏结束
    该函数应当返回不同的值来确定游戏结果,供逻辑层判断和处理。
    //行列连成,且不能均为空(部分代码)
    for(int i=0;i<3;i++){
        if(board[i,0]!=0 && board[i,0]==board[i,1] && board[i,0]==board[i,2]){
            return board[i,0];
        }
        if(board[0,i]!=0 && board[0,i]==board[1,i] && board[0,i]==board[2,i]){
            return board[0,i];
        }
    }
    

UI界面

  1. 辅助的函数为showBoard(),这个函数的设计思路也应用在PVP()PVAI()中。主要是通过IMGUI的刷新机制,实时更新每个方格按钮上的图标来展示不同的棋盘。
    void showBoard(){
        //遍历整个棋盘,每一帧都要生成
        for(int i=0;i<3;i++){
            for(int j=0;j<3;j++){
                if(board[i,j] == 0){
                    GUI.Button(new Rect(board_left + i * board_size, board_top + j * board_size, board_size, board_size), None);                       
                }
                if(board[i,j] == 1){
                    GUI.Button(new Rect(board_left + i * board_size, board_top + j * board_size, board_size, board_size), X);
                }
                if(board[i,j] == 2){
                    GUI.Button(new Rect(board_left + i * board_size, board_top + j * board_size, board_size, board_size), O);
                }
            }
        }
    } 
    
  2. Start()OnGUI()函数可以初始化UI界面和切换界面:
    private void OnGUI () 
    {        
        GUI.Label(new Rect(0, 0, 1000, 800), Background);
        GUI.Label(new Rect(260, 20, 200, 50), "井字棋小游戏", bigBlackStyle);
    
        //根据不同状态切换到不同界面
        if(state == -1){
            prepare();
        }
        else if(state == 1){
            if(mode == 0){
                PVP();
            }
            else{
                PVAI();
            }
    
            if (GUI.Button(new Rect(330, 400, 100, 50), "重新开始")){
                state = -1;
            }
        }
        else{//游戏结束
            gameOver();
    
            if (GUI.Button(new Rect(330, 400, 100, 50), "重新开始")){
                state = -1;
            }
        }
    }
    
  3. prepare()通过单选框来改变模式和先后手:
    GUI.Box(new Rect(280, 230, 200, 80), "模式:");
    mode = GUI.Toolbar (new Rect (300, 260, 150, 30), mode , toolbarModeStrings);
    
  4. PVP()PVAI()中,人的操作都是检测到被点击的按钮后,直接使用PlayerPut()函数进行处理,AI的操作都是直接调用AI()函数处理后显示棋盘。gamever()函数会显示出游戏结果。这样可以达到UI界面和其他两个层次之间的分离。

运行结果

请参考展示视频
在这里插入图片描述
在这里插入图片描述

  游戏开发 最新文章
6、英飞凌-AURIX-TC3XX: PWM实验之使用 GT
泛型自动装箱
CubeMax添加Rtthread操作系统 组件STM32F10
python多线程编程:如何优雅地关闭线程
数据类型隐式转换导致的阻塞
WebAPi实现多文件上传,并附带参数
from origin ‘null‘ has been blocked by
UE4 蓝图调用C++函数(附带项目工程)
Unity学习笔记(一)结构体的简单理解与应用
【Memory As a Programming Concept in C a
上一篇文章      下一篇文章      查看所有文章
加:2021-09-19 08:17:57  更:2021-09-19 08:19:14 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/17 17:00:49-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码