golang小游戏:飞翔的小鸟

游戏开发总体思路

首先要选取一个合适的图形化界面进行开发。该项目选取的是 ebiten 一个用于创建2D游戏和图形应用程序的游戏引擎,提供了一些简单的GUI功能。

其次明确游戏设计思路。飞翔的小鸟共分为三个场景。

第一个场景就是游戏开始前的准备阶段,让玩家点击屏幕确定游戏开始。

第二个场景就是让游戏正式开始,玩家可以操控小鸟进行游戏。

第三个场景就是游戏结束,显示分数的阶段。

一、先让窗口和背景绘制出来

先简单的让窗口显示出来,通过ebiten.RunGame(&game)启动游戏引擎,会开始初始化游戏并且开始循环执行游戏的更新和渲染逻辑。

游戏运行后 会自动调用Update函数进行屏幕刷新,然后再进行游戏绘制。

一般情况下Update函数是写游戏逻辑的,Draw函数进行游戏回话。

func main() {// 设置窗口大小是ebiten.SetWindowSize(880, 520)// 设置窗口头部,显示 飞翔的小鸟ebiten.SetWindowTitle("飞翔的小鸟")// 运行游戏err := ebiten.RunGame(&game);if err != nil {log.Fatal(err)}
}/*Layout()函数的返回值表示显示窗口里面逻辑上屏幕的大小官网上说参数outsideWidth和outsideHeight是显示在桌面的窗口大小这里是固定大小
*/
func (g *Game) Layout(outsideWidth, outsideHeight int) (screenWidth, screenHeight int) {return 880, 520
}func (g *Game) Update(screen *ebiten.Image) error {g.DrawBegin(screen)return nil
}func (g *Game) DrawBegin(screen *ebiten.Image) {DrawBackGround(screen)
}
}

这里是进行游戏背景的渲染的,screen.Fill 是将整个画面都填充完一种颜色。对于地板来说,进行一张图片通过for循环来进行反复绘制。

大概就是这个样子,for循环,每次只用让图片的x坐标进行增加就可以了,这样就把背景给渲染出来了。

在这里插入图片描述

func DrawBackGround(screen *ebiten.Image){//  背景颜色screen.Fill(color.RGBA{78, 192, 202,255})//  绘制地板f1, err := os.Open("imgs/ground.png")if err != nil {log.Fatal(err)}img1, err := png.Decode(f1)if err != nil {log.Fatal(err)}filter1 := ebiten.FilterNearest// 把Image文件转成ebiten.Image文件,用于展示eImg1, _ := ebiten.NewImageFromImage(img1,filter1)var groundX int = 0;var groundY int = 437;for i :=1;i<5;i++ {op1 := &ebiten.DrawImageOptions{}op1.GeoM.Translate(float64(groundX), float64(groundY))   // 图像坐标groundX+=250// 在屏幕上展示出图片screen.DrawImage(eImg1, op1)}

在这里插入图片描述

这样一个带有背景图片的窗口就绘制完成了。

二、游戏准备阶段

该阶段制作相对容易,因为此时只用基于上面那个画面,添加一个鼠标点击事件,让玩家点击后即可进入到下一个场景。

先传入两个照片,一个是显示游戏名,一个是点击进入到游戏的图片。

然后对第二个图片添加一个鼠标点击事件,让玩家点击图片进入到游戏中!

ebiten.IsMouseButtonPressed是鼠标点击事件,关键要确定好鼠标点击的范围!

func (g *Game) DrawReady(screen *ebiten.Image)  {g.DrawBegin(screen)imageObject1, _, _ := ebitenutil.NewImageFromFile("imgs/title.png",ebiten.FilterDefault)imageObject2, _, _ := ebitenutil.NewImageFromFile("imgs/start.png",ebiten.FilterDefault)gameReady := &GameReady{imgReady1: imageObject1,img1X: 370,img1Y: 140,imgReady2: imageObject2,img2X: 333,img2Y: 200,}op := &ebiten.DrawImageOptions{}op.GeoM.Translate(float64(gameReady.img1X),float64(gameReady.img1Y))screen.DrawImage(gameReady.imgReady1,op)op.GeoM.Reset()op.GeoM.Translate(float64(gameReady.img2X),float64(gameReady.img2Y))screen.DrawImage(gameReady.imgReady2,op)if ebiten.IsMouseButtonPressed(ebiten.MouseButtonLeft) {x,y := ebiten.CursorPosition()rect := image.Rect(gameReady.img2X,gameReady.img2Y,gameReady.img2X+200,gameReady.img2Y+30)if (x >=rect.Min.X && x<=rect.Max.X && y>=rect.Min.Y && y<= rect.Max.Y ){gameState = 1}}}

在这里插入图片描述

三、游戏开始阶段

这个场景有两个重要的对象需要进行处理。小鸟和障碍物。

小鸟:需要进行绘制,并且给小鸟添加逻辑。每次跳跃修改坐标,并且碰到天空和地面进行over处理。

小鸟的制作

绘制

首先进行小鸟的绘制。绘制其实只用读取小鸟的图片,然后给小鸟设置一个初始坐标,然后展示在屏幕中。

f, err := os.Open(g.Bird)if err != nil {log.Fatal(err)}img, err := png.Decode(f)if err != nil {log.Fatal(err)}filter := ebiten.FilterNearest// 把Image文件转成ebiten.Image文件,用于展示eImg, _ := ebiten.NewImageFromImage(img,filter)op := &ebiten.DrawImageOptions{}op.GeoM.Translate(g.LocationX,g.LocationY)// 在屏幕上展示出图片screen.DrawImage(eImg, op)
逻辑处理

小鸟因为只用上下移动,它的逻辑处理起来还是比较简单的,只用通过按键响应监听空格,每按一下空格,小鸟的坐标就减少,松开空格后坐标就想加。(这是因为 这个图像左上角的坐标是0 0,向右和向下分别增加x和y的坐标值)。

同时也要对 小鸟状态进行判断,当触碰到天空和地面时,进行over处理,然后每次按

//  按空格 跳跃if ebiten.IsKeyPressed(ebiten.KeySpace) && g.BirdState != 0 && !isSpace && gameState == 1 &&!isstop {isSpace = truelocationTemp = -5g.Bird = "imgs/up.png"}//  松开空格if !ebiten.IsKeyPressed(ebiten.KeySpace) && gameState == 1{locationTemp = 2g.Bird = "imgs/down.png"isSpace = false}//  判断是否暂停,然后判断 小鸟此时 能否移动if !isstop { // 暂停g.LocationY = g.LocationY + float64(locationTemp)}// 碰到下边界  和  上边界if (g.LocationY >= 409 || g.LocationY <= -4 ){g.Bird = "imgs/die.png"g.BirdState = 0}//  死亡不让超出下边界if (g.LocationY >= 479){g.LocationY = 479;}//  小鸟死亡if (g.BirdState == 0){g.Bird = "imgs/die.png"g.LocationY +=3locationTemp = 3}

在这里插入图片描述

障碍物的制作

障碍物的制作也分为两个方面,一个就是障碍物的绘制和逻辑处理。

障碍物的逻辑处理还是相对简单的,因为障碍物只需要一直向左边移动,所以只用改变障碍物的x坐标就可以了。

复杂的是障碍物的绘制,因为障碍物有三种形态,每种形态的绘制还是随机的,不能重复。

绘制

考虑到障碍物的长度不能一样,所以就想到了通过 随机数来确定障碍物的长度。并且也需要通过随机数来确定障碍物的哪一种形态的。

可以先获取一个随机数,来确定障碍物的长度。然后通过for循环来绘制障碍物。(通过for循环是因为障碍物 和 地方一样 它们的图片都是非常短的一截,确定长度后通过循环进行绘制)。

下面是三种障碍物的绘制方法,绘制后将其存入到切片中。

var obstacles []*NewBarrier // 切片存数组
// 下方障碍物
func (o *NewBarrier) DrawTop(screen *ebiten.Image) {for i := 1 ;i<o.TopLength;i++{op := &ebiten.DrawImageOptions{}op.GeoM.Translate(float64(o.X),float64(o.TopY+(i-1)*20))screen.DrawImage(o.Image,op)}op1 := &ebiten.DrawImageOptions{}op1.GeoM.Translate(float64(o.X-2),float64(o.TopLength*20-20))screen.DrawImage(o.BottomImage,op1)
}// 上方障碍物
func (o *NewBarrier) DrawBottom(screen *ebiten.Image) {for i := 1 ;i<19-o.TopLength;i++{op := &ebiten.DrawImageOptions{}op.GeoM.Translate(float64(o.X),float64(o.BottomY-(i-1)*20))screen.DrawImage(o.Image,op)}op1 := &ebiten.DrawImageOptions{}op1.GeoM.Translate(float64(o.X-2),float64(500-(19-o.TopLength)*20+20))screen.DrawImage(o.UpImage,op1)
}// 中间障碍物
func (o *NewBarrier) DrawMid(screen *ebiten.Image) {//fmt.Println(o.HoverUPY,o.TopLength,o.HoverBottomY)for i := 1 ;i<o.TopLength;i++{op := &ebiten.DrawImageOptions{}op.GeoM.Translate(float64(o.X),float64(o.HoverUPY+i*20))screen.DrawImage(o.Image,op)}op1 := &ebiten.DrawImageOptions{}op1.GeoM.Translate(float64(o.X-2),float64(o.HoverBottomY))screen.DrawImage(o.BottomImage,op1)op2 := &ebiten.DrawImageOptions{}op2.GeoM.Translate(float64(o.X-2),float64(o.HoverUPY))screen.DrawImage(o.UpImage,op2)
}//  绘制障碍物
func (g *Game) DrawBarrier(screen *ebiten.Image){if (gameState != 0){for _, o := range obstacles {if (o.BarrierStates ==0 || o.BarrierStates==1){o.DrawTop(screen)o.DrawBottom(screen)}else{o.DrawMid(screen)}if (o.X<200){if (!o.isScore){o.isScore = trueScore++}}}}
}
逻辑处理

障碍物的逻辑处理其实非常简单,只用遍历切片,让每个障碍物的坐标一直减小就可以了。

// 让障碍物移动起来
func obojsaasdf(obs []*NewBarrier){for i:=0;i< len(obs);i++ {obs[i].X --}
}
障碍物对象池

因为障碍物的数量考虑到非常多,并且一直有障碍物会移出屏幕,移出屏幕之后便看不见了,如果不对其进行妥善处理,我感觉会对内存有很大的消耗。所以就引入了类似于java对象池一样的池子。将超出屏幕的障碍物 修改其部分属性 然后重新添加到切片末尾,这样便只用初始化几个障碍物,然后这些障碍物反复利用,便可大大节省内存消耗。

func deal()  {if len(obstacles) > 0 {rand.Seed(time.Now().UnixNano())for i := 0; i < len(obstacles); i++{if obstacles[i].X < -50 {obstacles[i].TopLength = util.Random(15,2)// 移除超出屏幕的障碍物del := obstacles[0]del.X = obstacles[len(obstacles)-1].X+180ran := util.Random(15,2)ran1 := util.Random(180,80)del.TopLength = randel.HoverUPY = ran1del.HoverBottomY = ran1 + 20*randel.BarrierStates = util.Random(3,0)del.isScore = falseobstacles = append(obstacles[:i], obstacles[i+1:]...)// 添加新的障碍物到切片末尾obstacles = append(obstacles, del)}}}
}

在这里插入图片描述

碰撞检测处理

当小鸟和障碍物都绘制完了,就需要考虑他们之间的碰撞检测了!

碰撞检测采用的是获取小鸟四个角的坐标和障碍物的坐标,让他们的坐标没有交集。

绿色的是障碍物,蓝色的是小鸟。有一点抽象了。。。图中这几种情况是不会发生碰撞的情况。

所以,对于上下型障碍物来说,当小鸟的右边 < 障碍物的左边 或者 小鸟的左边 > 障碍物的右边 或者 小鸟的上边 > 障碍物的下面 并且小鸟的下面 < 障碍物的上面

对于悬浮障碍物来说,x 坐标考虑和上面一样,对于 y 坐标。小鸟的下面 < 障碍物的上面 或者 小鸟的上面 > 障碍物的下面

在这里插入图片描述

// 碰撞检测
func IsColliding(birdX, birdY float64, birdWidth, birdHeight float64, barrierX, barrierTopY, barrierBottomY float64, barrierWidth int,HoverUp float64,HoverBottom float64) bool {birdLeft := birdXbirdTop := birdYbirdRight := birdLeft + birdWidthbirdBottom := birdTop + birdHeightbarrierLeft := barrierXbarrierTop := barrierTopYbarrierRight := barrierLeft + float64(barrierWidth)barrierBottom := barrierBottomYif birdRight < barrierLeft || birdLeft > barrierRight || ((birdBottom < barrierBottom) && (birdTop > barrierTop)) || ((birdBottom < HoverUp) || (birdTop > HoverBottom+20)) {// 没有碰撞return false}// 有碰撞return true
}

在这里插入图片描述

分数绘制

游戏中应该在添加一个记录成绩的文本。

小鸟每次过一个障碍物让其分数 +1,考虑到小鸟一直是原地上下移动,是障碍物在一直移动,所以可以考虑通过障碍物的坐标来记录分数。每当障碍物的 x 坐标 小于 小鸟的 x 坐标的时候,便让成绩+1即可。

func (g *Game) DrawBarrier(screen *ebiten.Image){if (gameState != 0){for _, o := range obstacles {if (o.X<200){if (!o.isScore){o.isScore = trueScore++}}}}
}
func (g *Game) DrawScore(screen *ebiten.Image) {ebitenutil.DebugPrintAt(screen , Itoa(Score),100,100)
}

在这里插入图片描述

游戏暂停

这里是在游戏过程中,添加一个游戏暂停处理。

其实逻辑很简单,添加一个按键监听,当按下暂停键后,让 小鸟保持不动,障碍物不再移动即可。

那具体怎么处理呢? 小鸟的跳跃是通过按键响应来控制的,那么当调用这个按键响应的同时添加一个 判断即可,判断此时 是否暂停。

同样的,障碍物移动的时候,也添加一个判断,判断此时是否暂停。

var isstop bool = false // 游戏是否暂停
//  判断游戏是否暂停if ebiten.IsKeyPressed(ebiten.KeyS) && isPressStop && gameState ==1 && g.BirdState != 0{isPressStop = falseif (!isstop){isstop = true}else {isstop = false}}
//  判断是否暂停,然后判断 小鸟此时 能否移动if !isstop { // 暂停g.LocationY = g.LocationY + float64(locationTemp)}// 判断游戏是否暂停if ((g.LocationY != 482 || g.BirdState !=0) && !isstop && gameState != 0){ // 没有暂停obojsaasdf(obstacles)}else if  ((g.LocationY != 482 || g.BirdState != 0 ) && isstop) { // 游戏暂停//fmt.Println("暂停了 ,障碍物不能动了")}

四、游戏结束阶段

游戏结束

界面绘制

游戏结束后,需要绘制的就是 “GameOver” 和 这一局的分数了。还有就是让障碍物不在移动,这个在下面的逻辑处理细讲。

其实很简单,就是获取字符串内容,然后显示在屏幕中间即可 - -

// 绘制 GameOver方法
func (g *Game) DrawGameOver(screen *ebiten.Image) {ebitenutil.DebugPrintAt(screen , "GameOver",400,210)ebitenutil.DebugPrintAt(screen , Itoa(Score),422,240)
}// 绘制成绩
func (g *Game) DrawScore(screen *ebiten.Image) {ebitenutil.DebugPrintAt(screen , Itoa(Score),100,100)
}
逻辑处理

当游戏暂停后,停止调用障碍物移动的方法就行了。

// 判断游戏是否结束if ((g.LocationY != 482 || g.BirdState !=0) && !isstop && gameState != 0){ // 没有结束obojsaasdf(obstacles)}else if  ((g.LocationY != 482 || g.BirdState != 0 ) && isstop) { // 游戏暂停//fmt.Println("暂停了 ,障碍物不能动了")}else if(g.LocationY == 482 || g.BirdState == 0 ) {  // 游戏结束gameState = 2g.DrawBegin(screen)g.DrawGameOver(screen)}

在这里插入图片描述

游戏重开

逻辑处理

添加一个按键响应,当按下重开键后,重新开始游戏。

重点是:要将信息全部初始化:初始化障碍物的切片,初始化小鸟状态 和 坐标,初始化该局分数。

// 此时游戏结束 考虑是否重开if (gameState == 2){if ebiten.IsKeyPressed(ebiten.KeySpace) {   // 按压空格后 重开Score = 0gameState = 1g.BirdState = 1g.LocationY = 200obstacles = obstacles[:0] // 清空 原来切片中的障碍物makeBarrier()}}
界面绘制

重新调用游戏开始阶段的函数即可。

在这里插入图片描述

五、总结感想

做完这个游戏熟悉了 go 的基础语法,增加了对代码的手感。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/169938.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Javascript】不满意网上的Token无感知刷新方案,自己琢磨了个感觉还不错~

​前言 大家设想一下&#xff0c;如果有一个超级大的表单页面&#xff0c;用户好不容易填完了&#xff0c;然后点击提交&#xff0c;这个时候请求接口居然返回401&#xff0c;然后跳转到登录页。。。那用户心里肯定是一万个草泥马~~~ 所以项目里实现token无感知刷新是很有必要…

vscode Coder Runner 运行C++

1. 设置Code Runner 2. 防止输入读不到&#xff0c;把在终端运行勾上。 3. 设置minw/bin的环境变量 安装mingw教程&#xff1a;https://blog.csdn.net/fancy_male/article/details/133992000 4. 见图

ubuntu18.04双系统安装(2023最新最详细)以及解决重启后发现进不了Ubuntu问题

目录 一.简介 二.安装教程 1.首先确定了电脑的引导格式是UEFIGPT还是BIOSMBR 2. 使用Windows磁盘管理划分足够的磁盘空间 3. 开始安装 三.重启后发现自动进入WIN10系统了&#xff0c;进不了Ubuntu&#xff1f; 一.简介 Linux是一种自由和开放源代码的操作系统内核&#x…

Deno 的配置文件、框架,标准库

目录 1、配置文件 imports 和scopes tasks lint fmt lock nodeModulesDir npmRegistry compilerOptions 一个全的示例 2、Web框架 2.1 Deno 原生框架 Fresh Aleph Ultra Lume Oak 3、标准库 3.1 版本和稳定性 1、配置文件 Deno支持一个配置文件&#xff0c…

MR混合现实情景实训教学系统在旅游管理专业中的应用

在旅游管理专业中&#xff0c;MR混合现实情景实训教学系统的主要应用包括但不限于以下几个方面&#xff1a; 1. 实地考察的替代&#xff1a;对于一些无法实地考察的景点或设施&#xff0c;学生可以通过MR系统进行虚拟参观&#xff0c;从而了解其实际情况。这不仅可以减少时间和…

【C++】STL容器——【深浅拷贝】与【写时拷贝】对比详解(拷贝构造)(10)

前言 大家好吖&#xff0c;欢迎来到 YY 滴C系列 &#xff0c;热烈欢迎&#xff01; 本章主要内容面向接触过C的老铁 主要内容含&#xff1a; 目录 一.深浅拷贝浅拷贝&#xff1a;深拷贝&#xff1a; 二.写时拷贝 一.深浅拷贝 (默认拷贝构造运用 引用 防止死递归的后遗症&#…

读高性能MySQL(第4版)笔记19_云端和合规性

1. 如何构建数据库环境 1.1. 托管MySQL 1.2. VM上构建 1.3. 天下没有免费的午餐&#xff0c;每一个选择都伴随着一系列的权衡 2. 托管MySQL 2.1. 服务商提供了一个可访问的数据库设置程序&#xff0c;而不需要用户深入了解MySQL的具体细节 2.2. 使用托管MySQL将缺乏很多的…

小程序设计基本微信小程序的校园生活助手系统

项目介绍 通篇文章的撰写基础是实际的应用需要&#xff0c;然后在架构系统之前全面复习大学所修习的相关知识以及网络提供的技术应用教程&#xff0c;以校园生活助手系统的实际应用需要出发&#xff0c;架构系统来改善现校园生活助手系统工作流程繁琐等问题。不仅如此以操作者…

Python手搓C4.5决策树+Azure Adult数据集分析

前言 课上的实验 由于不想被抄袭&#xff0c;所以暂时不放完整代码 Adult数据集可以在Azure官网上找到 Azure 开放数据集中的数据集 - Azure Open Datasets | Microsoft Learn 数据集预处理 删除难以处理的权重属性fnlwgt与意义重复属性educationNum去除重复行与空行删除…

百度文心一言4.0——使用及API测试

登录百度智能云&#xff1a;百度智能云 文心一言4.0使用 开通付费&#xff1a; 创建应用&#xff1a; 自行创建应用名称&#xff1a; 对话测试&#xff1a; API测试 ERNIE-Bot-4 API&#xff1a;ERNIE-Bot-4 打开链接查看自己的API Key&#xff0c;Secret Key。 可参…

Ivs+keepalived:高可用集群

Ivskeepalived:高可用集群 keepalived为lvs应运而生的高可用服务。lvs的调度器无法做高可用&#xff0c;keepalived这个软件就是为了实现调度器的高可用。 注意&#xff1a;keepalived不是专门为lvs集群服务的&#xff0c;也可以做其他代理服务器的高可用。 lvs的高可用集群&a…

CSS 两栏布局

目录 CSS两栏布局&#xff08;左列定宽&#xff0c;右列自适应宽&#xff09; 方法一&#xff1a;浮动margin 方法二&#xff1a;定位margin 方法三&#xff1a;浮动BFC 方法四&#xff1a;Flex布局 方法五&#xff1a;able布局 CSS两栏布局&#xff08;左列不定宽&#…

模拟计算器编程教程,中文编程开发语言工具编程实例

模拟计算器编程教程&#xff0c;中文编程开发语言工具编程实例 中文编程系统化教程&#xff0c;不需英语基础。学习链接 ​​​​​​https://edu.csdn.net/course/detail/39036 课程安排&#xff1a;初级1 1 初级概述 2 熟悉构件取值赋值 3 折叠式菜单滑动面板编程 4 自定…

万宾科技智能井盖传感器怎么使用?

时代在进步&#xff0c;科技在更新&#xff0c;人们身边的万事万物都在随着时代的脚步不断的前进。各种各样高科技技术在城市基础设施建设的过程中得到应用&#xff0c;很多智能产品不仅施工方便&#xff0c;而且可以向政府部门提供精准的数据&#xff0c;提高了相关管理人员的…

Django 地址接口开发

应用 Mixin 混合类进行收货地址接口开发 python ../manage.py startapp address继承了mixins扩展类&#xff0c;进到里面可以稍微看下源码 该方法帮我们实现了获取验证及保存的功能 address/views from rest_framework.generics import GenericAPIView from rest_framewo…

STM32:GPIO功能描述和工作方式

一、STM32控制原理概要 IO端口位的基本结构 在STM32有特定功能的内存单元&#xff0c;即"寄存器"。寄存器是程序与硬件电路通信的桥梁。寄存器按照每32位二进制0/1数据为一组。存储着芯片特定电路的相关信息。我们就是通过程序对寄存器中的数据进行修改&#xff0c;…

pycharm转移缓存目录

原来的缓存目录为C:\Users\86176\AppData\Local\JetBrains&#xff0c;各种配置文件、缓存文件随着pycharm的使用堆积在这里&#xff0c;导致C盘逐渐爆满。 因此需要将缓存目录转移至D盘。首先需要了解缓存目录的知识。 PyCharm 和其他 JetBrains 的 IDE 通常会有两个关键的目…

QSPI介绍

0 Preface/Foreword 1 QSPI介绍 硬件连接框图如下&#xff1a; QSPI接口的Display data format&#xff08;显示数据格式&#xff09; 包含以下几种&#xff1a; 16.7M colors RGB 8,8,8-bits input262K colors, RGB 6,6,6-bits input65K colors, RGB 5,6,5-bits input256 c…

Mac运行Docker报错

Mac运行Docker报错 &#x1f4d4; 千寻简笔记介绍 千寻简笔记已开源&#xff0c;Gitee与GitHub搜索chihiro-notes&#xff0c;包含笔记源文件.md&#xff0c;以及PDF版本方便阅读&#xff0c;且是用了精美主题&#xff0c;阅读体验更佳&#xff0c;如果文章对你有帮助请帮我点…

LabVIEW应用开发——控件的使用(四)

接上文&#xff0c;这篇介绍时间控件。 LabVIEW应用开发——控件的使用&#xff08;三&#xff09; 1、时间控件Time Stamp control 在日常软件开发场景中&#xff0c;时间也是一种常用的控件&#xff0c;用于表达当前时间的显示、对下设置时间、时间同步等等场景。LabVIEW专门…