HarmonyOS开发实战:【亲子拼图游戏】

概述

本篇Codelab是基于TS扩展的声明式开发范式编程语言编写的一个分布式益智拼图游戏,可以两台设备同时开启一局拼图游戏,每次点击九宫格内的图片,都会同步更新两台设备的图片位置。效果图如下:

 说明:  本示例涉及使用系统接口,需要手动替换Full SDK才能编译通过。

搭建OpenHarmony环境

完成本篇Codelab我们首先要完成开发环境的搭建,本示例以Hi3516DV300开发板为例,参照以下步骤进行:

  1. [获取OpenHarmony系统版本]):标准系统解决方案(二进制)。

    以3.0版本为例:

  2. 搭建烧录环境。

    1. [完成DevEco Device Tool的安装]
    2. [完成Hi3516开发板的烧录]
    3. 鸿蒙开发指导:qr23.cn/AKFP8k点击或复制转到。
  3. 搭建开发环境。

    1. 开始前请参考[工具准备],完成DevEco Studio的安装和开发环境配置。
    2. 开发环境配置完成后,请参考[使用工程向导]创建工程(模板选择“Empty Ability”),选择JS或者eTS语言开发。
    3. 工程创建完成后,选择使用[真机进行调测]。
      2.鸿蒙HarmonyOS与OpenHarmony文档籽料mau123789是v直接拿

搜狗高速浏览器截图20240326151450.png

分布式组网

本章节以系统自带的音乐播放器为例(具体以实际的应用为准),介绍如何完成两台设备的分布式组网。

  1. 硬件准备:准备两台烧录相同的版本系统的Hi3516DV300开发板A、B。

  2. 开发板A、B连接同一个WiFi网络。

    打开设置–>WLAN–>点击右侧WiFi开关–>点击目标WiFi并输入密码。

  3. 将设备A,B设置为互相信任的设备。

    • 找到系统应用“音乐”。

    • 设备A打开音乐,点击左下角流转按钮,弹出列表框,在列表中会展示远端设备的id。

    • 选择远端设备B的id,另一台开发板(设备B)会弹出验证的选项框。

    • 设备B点击允许,设备B将会弹出随机PIN码,将设备B的PIN码输入到设备A的PIN码填入框中。

    配网完毕。

代码结构解读

本篇Codelab只对核心代码进行讲解,首先来介绍下整个工程的代码结构:

  • MainAbility:存放应用主页面。

    • pages/index.ets:应用主页面。
  • model:存放获取组网内的设备列表相关文件。

    • RemoteDeviceModel.ets:获取组网内的设备列表。
  • ServiceAbility:存放ServiceAbility相关文件。

    • service.ts:service服务,创建一个ServiceAbility,用于跨设备连接后通讯。
  • resources :存放工程使用到的资源文件。

    • resources/rawfile:存放工程中使用的图片资源文件。
  • config.json:配置文件。

实现页面布局和样式

在本章节中,您将学会如何制作一个简单的拼图游戏。

  1. 实现主页面布局和样式。

    • 在MainAbility/pages/index.ets 主界面文件中添加入口组件PictureGame。PictureGame组件页面布局代码如下:

      // 入口组件
      @Entry
      @Component
      struct PictureGame {@Provide imageIndexForPosition: number[] = []@Provide pictureList: string[]= []build() {Column() {Text("益智拼图游戏").fontSize(40).margin({ top: 30, bottom: 30 })PictureGrid()Row() {Button("重新开始").fontSize(20).margin({ right: 10 }).onClick(() => {...})Button("亲子协同").fontSize(20).margin({ left: 10 }).onClick(()=>{...})}.margin(30)Image($rawfile('picture.jpg')).width(300).height(300)}.width('100%').height('100%')}
      }
      
    • 给PictureGame组件添加九宫格拼图子组件PictureGrid。PictureGrid九宫格拼图组件主要是由[Grid组件]、[GridItem组件]和[Image组件]构成,页面布局代码如下:

      // 九宮格拼图组件
      @Component
      struct PictureGrid {private gridRowTemplate: string = ''@Consume imageIndexForPosition : number[]@Consume pictureList: string[]private heightValue: numberaboutToAppear() {var rows = Math.round(this.pictureList.length / 3);this.gridRowTemplate = '1fr '.repeat(rows);this.heightValue = rows * 101 ;}build() {Column() {Grid() {ForEach(this.pictureList.map((item,index)=>{return {i:index,data:item};}),(item,index) => {GridItem() {Image($rawfile(this.pictureList[item.i])).width(100).height(100).onClick(() => {...})}}, (item: string) => item.toString())}.rowsTemplate(this.gridRowTemplate).columnsTemplate('1fr 1fr 1fr').columnsGap(1).rowsGap(1).height(this.heightValue).width(303)}}
      }
      

      在入口组件的生命周期函数aboutToAppear()中调用onRandom()方法,初始化imageIndexForPosition数组。如果Ability是被其他设备拉起的,在aboutToAppear()中调用featureAbility.getWant(),可通过want中的参数重新初始化imageIndexForPosition数组和pictureList数组,入口组件的生命周期函数aboutToAppear()代码如下:

      async aboutToAppear() {let self =this;this.onRandom();// 当被拉起时,通过want传递的参数同步对端界面UIawait featureAbility.getWant((error, want) => {var status = want.parameters;if(want.parameters.pictureList){self.pictureList = JSON.parse(status.pictureList)self.imageIndexForPosition = status.imageIndexForPosition;// 远端被拉起后,连接对端的serviceif(want.parameters.remoteDeviceId) {let remoteDeviceId = want.parameters.remoteDeviceIdonConnectRemoteService(remoteDeviceId)}}});
      }
      
  2. 给"重新开始"按钮添加点击事件。

    点击"重新开始"按钮,调用onRandom()方法,打乱图片现阶段排列顺序,在onRandom()调用setupRandomPosition()方法,初始化imageIndexForPosition数组,onRandom()和setupRandomPosition()代码如下:

    onRandom() {this.setupRandomPosition();this.pictureList = []this.imageIndexForPosition.forEach(value => {if (value == 9) {this.pictureList.push("--")} else {this.pictureList.push(`picture_0` + value + `.png`)}});
    }
    // 初始化imageIndexForPosition数组
    setupRandomPosition() {let list1 = [5, 4, 3, 9, 1, 8, 6, 7, 2];let list2 = [3, 1, 6, 7, 9, 8, 4, 2, 5];let list3 = [4, 8, 3, 5, 2, 7, 9, 1, 6];let list4 = [4, 3, 5, 2, 8, 7, 6, 1, 9];let lists = [list1, list2, list3, list4];this.imageIndexForPosition = lists[Math.floor(Math.random() * 4)];
    }
    
  3. 给九宫格内的每张图片添加点击事件。

    点击九宫格内的图片,调用onchange()方法,每一次点击后,需要调用onFinish()方法校验当前imageIndexForPosition 中的元素是否是从小到大排列。其中onChange()和onFinish()方法代码如下

    onChange(index) {let self = this;// 相邻位置数组let menu = {"1": [2, 4],"2": [1, 3, 5],"3": [2, 6],"4": [1, 5, 7],"5": [2, 4, 6, 8],"6": [3, 5, 9],"7": [4, 8],"8": [5, 7, 9],"9": [6, 8]}// 被点击的图片位置let click_num = index + 1;// 空白图片位置let no_see_num = self.imageIndexForPosition.indexOf(9) + 1;// 获取点击后能够移动的图片位置let arr = menu[no_see_num];// 判断arr是否包含点击的图片if(arr.length==2){if (!(arr[0]==click_num||arr[1]==click_num)) {} else {let temp = self.imageIndexForPosition[no_see_num - 1];self.imageIndexForPosition[no_see_num - 1] = self.imageIndexForPosition[click_num - 1];self.imageIndexForPosition[click_num - 1] = temp;self.pictureList = [];self.imageIndexForPosition.forEach(value => {if (value == 9) {self.pictureList.push("--")} else {self.pictureList.push(`picture_0` + value + `.png`)}});}}else if(arr.length==3){if (!(arr[0]==click_num||arr[1]==click_num||arr[2]==click_num)) {} else {let temp = self.imageIndexForPosition[no_see_num - 1];self.imageIndexForPosition[no_see_num - 1] = self.imageIndexForPosition[click_num - 1];self.imageIndexForPosition[click_num - 1] = temp;self.pictureList = [];self.imageIndexForPosition.forEach(value => {if (value == 9) {self.pictureList.push("--")} else {self.pictureList.push(`picture_0` + value + `.png`)}});}}else if(arr.length==4){if (!(arr[0]==click_num||arr[1]==click_num||arr[2]==click_num||arr[3]==click_num)) {} else {let temp = self.imageIndexForPosition[no_see_num - 1];self.imageIndexForPosition[no_see_num - 1] = self.imageIndexForPosition[click_num - 1];self.imageIndexForPosition[click_num - 1] = temp;self.pictureList = [];self.imageIndexForPosition.forEach(value => {if (value == 9) {self.pictureList.push("--")} else {self.pictureList.push(`picture_0` + value + `.png`)}});}}// 发送消息到远端Service服务sendMessageToRemoteService(JSON.stringify(self.imageIndexForPosition));// 判断是否完成拼接self.onFinish();
    }onFinish() {let finalList = [1, 2, 3, 4, 5, 6, 7, 8, 9];if (this.equarList(this.imageIndexForPosition, finalList)) {this.pictureList = [];this.imageIndexForPosition.forEach(value => {this.pictureList.push("picture_0" + value + ".png")});prompt.showToast({message: "success"});// 完成拼接后断开Service连接onDisconnectService();}
    }
    

拉起远端FA,并连接远端Service服务

在本章节中,您将学会如何拉起在同一组网内的设备上的FA,创建并连接远端Service服务。

  1. 调用featureAbility.startAbility()方法,拉起远端FA,并同步界面UI。

    点击"亲子协同"按钮,调用RegisterDeviceListCallback()发现设备列表,并弹出设备列表选择框CustomDialogExample,选择设备后拉起远端FA。CustomDialogExample()代码如下:

    // 设备列表弹出框
    @CustomDialog
    struct CustomDialogExample {@State editFlag: boolean = false@Consume imageIndexForPosition : number[]@Consume pictureList: string[]controller: CustomDialogControllercancel: () => voidconfirm: () => voidbuild() {Column() {List({ space: 10, initialIndex: 0 }) {ForEach(DeviceIdList, (item) => {ListItem() {Row() {Text(item).width('87%').height(50).fontSize(10).textAlign(TextAlign.Center).borderRadius(10).backgroundColor(0xFFFFFF).onClick(() => {onStartRemoteAbility(item,this.imageIndexForPosition,this.pictureList);this.controller.close();})Radio({value:item}).onChange((isChecked) => {onStartRemoteAbility(item,this.imageIndexForPosition,this.pictureList);this.controller.close();}).checked(false)}}.editable(this.editFlag)}, item => item)}}.width('100%').height(200).backgroundColor(0xDCDCDC).padding({ top: 5 })}
    }
    

    点击Text组件或者Radio组件都会调用onStartRemoteAbility()方法拉起远端FA,onStartRemoteAbility()代码如下:

    function onStartRemoteAbility(deviceId,imageIndexForPosition,pictureList: string[]) {AuthDevice(deviceId);let numDevices = remoteDeviceModel.deviceList.length;if (numDevices === 0) {prompt.showToast({message: "onStartRemoteAbility no device found"});return;}var params = {imageIndexForPosition: JSON.stringify(imageIndexForPosition),pictureList : JSON.stringify(pictureList),remoteDeviceId : localDeviceId}var wantValue = {bundleName: 'com.huawei.cookbook',abilityName: 'com.example.openharmonypicturegame.MainAbility',deviceId: deviceId,parameters: params};featureAbility.startAbility({want: wantValue}).then((data) => {// 拉起远端后,连接远端serviceonConnectRemoteService(deviceId)});
    }
    

    创建ServiceAbility,步骤如下图所示:

  2. 调用featureAbility.connectAbility方法,连接远端Service服务,连接成功后返会remote对象。

    在featureAbility.startAbility()成功的回调中调用onConnectRemoteService()方法,onConnectRemoteService()方法代码如下:

    // 连接远端Service
    async function onConnectRemoteService(deviceId) {// 连接成功的回调async function onConnectCallback(element, remote) {mRemote = remote;}// Service异常死亡的回调function onDisconnectCallback(element) {}// 连接失败的回调function onFailedCallback(code) {prompt.showToast({message: "onConnectRemoteService onFailed: " + code});}let numDevices = remoteDeviceModel.deviceList.length;if (numDevices === 0) {prompt.showToast({message: "onConnectRemoteService no device found"});return;}connectedAbility = await featureAbility.connectAbility({deviceId: deviceId,bundleName: "com.huawei.cookbook",abilityName: "com.example.openharmonypicturegame.ServiceAbility",},{onConnect: onConnectCallback,onDisconnect: onDisconnectCallback,onFailed: onFailedCallback,},);
    }
    

    在配置文件config.json需要设置ServiceAbility的属性visible为true,代码如下:

    "abilities": [...{"visible": true,"srcPath": "ServiceAbility","name": ".ServiceAbility","icon": "$media:icon","srcLanguage": "ets","description": "$string:description_serviceability","type": "service"}
    ],
    

    同时,Service侧也需要在onConnect()时返回IRemoteObject,从而定义与Service进行通信的接口。onConnect()需要返回一个IRemoteObject对象,OpenHarmony提供了IRemoteObject的默认实现,通过继承rpc.RemoteObject来创建自定义的实现类。Service侧把自身的实例返回给调用侧的代码如下:

    import rpc from "@ohos.rpc";
    import commonEvent from '@ohos.commonEvent';
    class FirstServiceAbilityStub extends rpc.RemoteObject{constructor(des) {if (typeof des === 'string') {super(des);} else {return null;}}onRemoteRequest(code, data, reply, option) {if (code === 1) {let arr = data.readIntArray();reply.writeInt(100);// 发布公共事件相关流程...} else {}return true;}
    }export default {// 创建Service的时候调用,用于Service的初始化onStart() {},// 在Service销毁时调用。Service应通过实现此方法来清理任何资源,如关闭线程、注册的侦听器等。onStop() {},// 在Ability和Service连接时调用,该方法返回IRemoteObject对象,开发者可以在该回调函数中生成对应Service的IPC通信通道onConnect(want) {try {let value = JSON.stringify(want);} catch(error) {}return new FirstServiceAbilityStub("[pictureGame] first ts service stub");},// 在Ability与绑定的Service断开连接时调用onDisconnect(want) {let value = JSON.stringify(want);},// 在Service创建完成之后调用,该方法在客户端每次启动该Service时都会调用onCommand(want, startId) {let value = JSON.stringify(want);}
    };
    

RPC跨设备通讯

在本章节中,您将学会在成功连接远端Service服务的前提下,如何利用RPC进行跨设备通讯。

  1. 成功连接远端Service服务的前提下,点击"重新开始"按钮或者九宫格内的图片,都会完成一次跨设备通讯,假如在设备A端点击"重新开始"按钮,消息的传递是由设备A端的FA传递到设备B的Service服务,发送消息的方法sendMessageToRemoteService()代码如下:

    // 连接成功后发送消息
    async function sendMessageToRemoteService(imageIndexForPosition) {if (mRemote == null) {prompt.showToast({message: "mRemote is null"});return;}let option = new rpc.MessageOption();let data = new rpc.MessageParcel();let reply = new rpc.MessageParcel();data.writeIntArray(JSON.parse(imageIndexForPosition));await mRemote.sendRequest(1, data, reply, option);let msg = reply.readInt();
    }
    
  2. 在B端的Service接收消息,当A端成功连接B端Service服务后,在A端会返回一个remote对象,当A端remote对象调用sendRequest()方法后,在B端的Service中的onRemoteRequest()方法中会接收到发送的消息,其中继承rpc.RemoteObject的类和onRemoteRequest()方法代码如下:

    class FirstServiceAbilityStub extends rpc.RemoteObject{constructor(des) {if (typeof des === 'string') {super(des);} else {return null;}}onRemoteRequest(code, data, reply, option) {if (code === 1) {// 从data中接收数据let arr = data.readIntArray();// 回复接收成功标识reply.writeInt(100);// 发布公共事件相关流程...} else {}return true;}
    }
    

Service服务发布公共事件

当Service服务接收到消息后,在onRemoteRequest()发布公共事件,代码如下:

onRemoteRequest(code, data, reply, option) {if (code === 1) {// 从data中接收数据let arr = data.readIntArray();// 回复接收成功标识reply.writeInt(100);// 公共事件相关信息var params ={imageIndexForPosition: arr}var options = {// 公共事件的初始代码code: 1,// 公共事件的初始数据			data: 'init data',、// 有序公共事件 	        isOrdered: true, 	bundleName: 'com.huawei.cookbook',parameters: params}// 发布公共事件回调function PublishCallBack() {}// 发布公共事件commonEvent.publish("publish_moveImage", options, PublishCallBack);} else {}return true;}

在接收到消息后,把接收到的图片位置数组放入params中,然后发布名称为"publish_moveImage"的有序公共事件。

FA订阅公共事件

在本章节中,您将学会如何通过CommonEvent订阅公共事件。在九宫格组件PictureGrid的生命周期函数aboutToAppear()中,调用订阅公共事件方法subscribeEvent(),用来订阅"publish_moveImage"公共事件,subscribeEvent()代码如下:

 subscribeEvent(){let self = this;// 用于保存创建成功的订阅者对象,后续使用其完成订阅及退订的动作var subscriber; // 订阅者信息var subscribeInfo = {events: ["publish_moveImage"],priority: 100};// 设置有序公共事件的结果代码回调function SetCodeCallBack(err) {}// 设置有序公共事件的结果数据回调function SetDataCallBack(err) {}// 完成本次有序公共事件处理回调function FinishCommonEventCallBack(err) {}// 订阅公共事件回调function SubscribeCallBack(err, data) {let msgData = data.data;let code = data.code;// 设置有序公共事件的结果代码subscriber.setCode(code, SetCodeCallBack);// 设置有序公共事件的结果数据subscriber.setData(msgData, SetDataCallBack);// 完成本次有序公共事件处理subscriber.finishCommonEvent(FinishCommonEventCallBack)// 处理接收到的数据dataself.imageIndexForPosition = data.parameters.imageIndexForPosition;self.pictureList = [];self.imageIndexForPosition.forEach(value => {if (value == 9) {self.pictureList.push("--")} else {self.pictureList.push(`picture_0` + value + `.png`)}});self.onFinish();}// 创建订阅者回调function CreateSubscriberCallBack(err, data) {subscriber = data;// 订阅公共事件commonEvent.subscribe(subscriber, SubscribeCallBack);}// 创建订阅者commonEvent.createSubscriber(subscribeInfo, CreateSubscriberCallBack);}

在FA中订阅到Service服务发布的"publish_moveImage"事件后,在SubscribeCallBack()回调中重新赋值imageIndexForPosition数组与pictureList数组,从而同步更新界面UI。

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

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

相关文章

OWASP发布10大开源软件风险清单

3月20日,xz-utils 项目被爆植入后门震惊了整个开源社区,2021 年 Apache Log4j 漏洞事件依旧历历在目。倘若该后门未被及时发现,那么将很有可能成为影响最大的软件供应链漏洞之一。近几年爆发的一系列供应链漏洞和风险,使得“加强开…

对桥接模式的理解

目录 一、背景二、桥接模式的demo1、类型A(形状类型)2、类型B(颜色类型)3、需求:类型A要使用类型B(如:红色的方形)4、Spring的方式 一、背景 在《对装饰器模式的理解》中&#xff0…

“手撕“数组一些简单的习题

目录 1.数组转字符串 2.数组拷贝 3.求数组中元素的平均值 4.查找数组中指定元素(顺序查找) 5.查找数组中指定元素(二分查找) 6.数组排序(冒泡排序) 7.数组逆序 1.数组转字符串 先让我们看看为什么要转字符串: int[] arr {1,2,3,4,5,6}; System.out.printl…

实验案例二:配置路由器实现互通

一.实验环境 实验用具包括两台路由器(或交换机).一根双绞线缆,一台PC,一条Console线缆。 二.需求描述 如图6.14所示,将两台路由器的Gig0/0接口相连,通过一台PC连接设备的Console端口并配置IP地址&#x…

分享一个纯HTML外贸公司通用企业html网站模板源码

纯HTML外贸公司通用企业html网站模板源码 源码地址:https://download.csdn.net/download/Highning0007/89150720

Jenkins用maven风格build报错解决过程记录

1、Jenkins2.453新建项目,构建风格选的maven 2、自由风格构建部署没有任何问题,但是maven风格build一直失败,报错如下图 3、解决方案:在系统管理–系统配置–Maven项目配置,删除全局MAVEN_OPT的路径信息,…

2.4G漂移小车电子方案 酷得智能科技

漂移高速遥控车是一种专门设计用于执行高速漂移动作的遥控车模型。以下是一些关于漂移高速遥控车的功能介绍: 1、高速性能:漂移车通常配备有强力的电机和电池,以便在保持高速的同时进行漂移动作。 2、漂移能力:漂移车的轮胎和悬挂…

Samtec应用分享 | 汽车应用中的视觉系统

【前言】 视觉系统在未来的汽车设计中扮演着关键的角色。 在过去,一直是由驾驶员掌握和应对道路上的危险,但现代车辆在保障驾驶安全方面发挥着前所未有的作用。 视觉系统,无论是可见光摄像头还是先进的探测系统,如激光雷达&…

【Java】通过poi给word首页添加水印图片

背景: poi并没有提供直接插入水印图片的方法,目前需要再word的首页插入一张水印图片,于是就需要通过另一种方式,插入透明图片(png格式)并将图片设置为“浮于文字上方”的方式实现该需求。 所需jar&#xf…

使用python采集VIP会电商平台商品数据②单页数据采集

获取标头: 响应:服务器返回的数据 预览:查看响应得数据 载荷:查询参数/请求参数 标头:查看请求的网址/请求的标头/请求方法 数据包地址:https://mapi.vip.com/vips-mobile/rest/shopping/pc/product/mo…

Servlet-Filter实现反爬虫

以前用DotNetCore实现过反爬虫功能。在tomcat里面可以利用Servlet的Filter类实现请求的控制来达到反爬虫功能,进而增强JRT的web安全。 实现黑名单过滤器,对在黑名单列表的IP的所有请求都跳转到警告页面,业务各种请求自行定义加入黑名单 /* …

Yolo-world+Python-OpenCV之摄像头视频实时目标检测

上一次介绍了如何使用最基本的 Yolo-word来做检测,现在我们在加opencv来做个实时检测的例子 基本思路 1、读取离线视频流 2、将视频帧给yolo识别 3、根据识别结果 对视频进行绘制边框、加文字之类的 完整代码如下: import datetimefrom ultralytics …

电竞陪玩系统开发平台搭建(小程序,公众号,app)线上线下皆有,线下计算距离。

六大核心功能 1.游戏陪练:可以选择当下火爆的游戏内容,选择游戏大神、职业玩家进行陪练,也可约附近路人玩家或是身边的小伙伴语音组队开黑,一起享受边玩游戏边吐槽的无限乐趣。 2.约玩交友:除了游戏陪玩功能,系统还设置了单独的语…

SpringBlade dict-biz/list SQL 注入漏洞复现

0x01 免责声明 请勿利用文章内的相关技术从事非法测试,由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,作者不为此承担任何责任。工具来自网络,安全性自测,如有侵权请联系删…

Python LEGB规则

Python在查找“名称”时,是按照LEGB规则查找的: Local: 指的就是函数或者类的方法内部 Enclosed: 指的是嵌套函数(一个函数包裹另一个函数,闭包) Global: 指的是模块中的全局变量 Bu…

含多种需求响应及电动汽车的微网/虚拟电厂日前优化调度

1 主要内容 程序主要建立一个微网/虚拟电厂的日前优化调度模型,以燃气轮机运行成本、购售电费用、电动汽车电池损耗成本以及需求响应费用之和为目标,在日前经济调度模型中,加入了电动汽车模型,考虑了电动汽车出行规律以及充放电规…

python之flask安装以及使用

1 flask介绍 Flask是一个非常小的Python Web框架,被称为微型框架;只提供了一个稳健的核心,其他功能全部是通过扩展实现的;意思就是我们可以根据项目的需要量身定制,也意味着我们需要学习各种扩展库的使用。 2 python…

超越GPT-4V,苹果多模态大模型上新,神经网络形态加速MLLM(一)

4月8日,苹果发布了其最新的多模态大语言模型(MLLM )——Ferret-UI,能够更有效地理解和与屏幕信息进行交互,在所有基本UI任务上都超过了GPT-4V! 苹果开发的多模态模型Ferret-UI增强了对屏幕的理解和交互&am…

【触想智能】如何选购到一款合适的工业电脑一体机

工业电脑一体机是专为工业环境而设计的一种工业计算机。工业电脑一体机和普通的计算机不一样,它对产品的参数性能要求很高,因为它们通常会运行在高低温、电磁干扰、高粉尘、湿度大的恶劣环境中,所以相应的要求工业电脑一体机必须具备良好的宽…

UE5下载与安装

官方网站:https://www.unrealengine.com/zh-CN 1、下载启动程序安装包。 登录官网后,点击首页右侧下载按钮下载Epic Games启动程序的安装包,如下图: 2、安装启动程序。 双击步骤1所下载安装软件,如下图:…