ios开发 多人语音聊天_在 Unity 多人游戏中实现语音对话

我们曾经不止一次为大家分享过游戏中的实时音视频,例如怎么实现游戏中的听声辨位、狼人杀游戏中的语音聊天挑战等。基本上,都是从技术原理和 Agora SDK 出发来分享的。这次我们换一个角度。我们将从 Unity 开发者的角度分享一下,在 Unity 中如何给自己的多人在线游戏增加实时语音通话功能。

我们在这里利用了 Unity 上流行的 “Tanks!!! asset reference” 坦克游戏作为多人在线游戏作为基础,相信很多人都不会陌生。大家可以在 Unity Asset Store 中搜到它。然后,我们会利用 Unity Asset Store 中的 Agora Voice SDK 为它增加多人语音聊天功能。

在开始前,你需要做以下准备:

安装 Unity 并注册 Unity 账号

了解如果在 Unity 中创建 iOS、Android 项目

一款跨移动平台多玩家的 Unity 游戏(本文中我们选择的是 Tanks)

了解 C# 和 Unity 脚本

注册一个 Agora 开发者账户

至少两个移动设备(如果有一个 iOS 设备,一个 Android 设备就再理想不过了)

安装 Xcode

新建 Unity 项目

我们默认大家都是用过 Unity 的开发者,但是为了照顾更多的人。我们还是要从头讲起。当然,开始的操作步骤很简单,所以我们会尽量以图片来说明。

首先,打开 Unity 后,让我们先创建一个新的项目。

如果你之前已经下载过 Tanks!!! ,那么我们点击页面旁边的“Add Asset Package”按钮,选择添加它即可。

如果你还未下载过 Tanks!!! 那么可以在 Unity Store 中下载它。

在将 Tanks!!! 参考项目部署到手机之前,还有几步需要做。首先,我们需要在 Unity Dashboard 中,为这个项目开启 Unity Live Mode。该设置的路径是:project → Multiplayer → Unet Config。尽管 Tanks!!! 只支持最多四个玩家4,但我们在将“Max Player per room”设置为6。

图:这个界面说明 Unity Live Mode 已经开启

Building for iOS

现在我们已经准备好来创建 iOS 版本了。打开 Build Setting,将系统平台切换到 iOS,然后 Build。在切换系统平台后,请记得更新 Bundle Identifier(如下图所示)。

图:创建了一个“Build”文件夹用于储存 iOS 项目

图:Build 完成

让我们打开 Unity-iPhone.xcodeproj,sign 并让它在测试设备上运行。

现在我们已经完成了 iOS 项目的创建。接下来我们要创建 Android 项目了。

Building for Android

Android 项目相比 iOS 来讲要更简单一些。因为 Unity 可以直接创建、sign 和部署运行,无需借助 Android Studio。我默认大家已经将 Unity 与 Android SDK 文件夹关联起来了。现在我们要打开 Build Setting,然后将系统平台切换到 Android。

在我们创建并运行之前,我们还需要对代码做出一些简单的调整。我们只需要注释掉几行代码,加一个简单的返回声明,再替换一个文件。

背景信息:Tanks!!! Android 包含了 Everyplay 插件,用以实现游戏屏幕录制和分享。问题是,Everyplay 在2018年十月停止了服务,而插件仍然存在一些未解决的问题,如果我们不对其进行处理会导致编译失败。

首先,我们要纠正一下 Everyplay 插件 build.gradle 文件中的语法错误。该文件的路径是:Plugins → Android → everyplay → build.gradle。

现在,我们打开了 gradle 文件,全选所有代码,然后将下方的代码替换上去。Tanks!!! 团队在 Github 上更新了代码,但是不知道为什么并没能更新到插件中。

// UNITY EXPORT COMPATIBLE

apply plugin: 'com.android.library'

repositories {

mavenCentral()

}

buildscript {

repositories {

mavenCentral()

}

dependencies {

classpath 'com.android.tools.build:gradle:1.0.0'

}

}

dependencies {

compile fileTree(dir: 'libs', include: ['*.jar'])

}

android {

compileSdkVersion 23

buildToolsVersion "25.0.3"

defaultPublishConfig "release"

defaultConfig {

versionCode 1600

versionName "1.6.0"

minSdkVersion 16

}

buildTypes {

debug {

debuggable true

minifyEnabled false

}

release {

debuggable false

minifyEnabled true

proguardFile getDefaultProguardFile('proguard-android.txt')

proguardFile 'proguard-project.txt'

}

}

sourceSets {

main {

manifest.srcFile 'AndroidManifest.xml'

java.srcDirs = ['src']

aidl.srcDirs = ['src']

renderscript.srcDirs = ['src']

res.srcDirs = ['res']

jniLibs.srcDirs = ['libs']

}

}

lintOptions {

abortOnError false

}

}

最后我们要做的修改就是关闭 Everyplay。你可能想问:为什么我们要关闭 Everyplay 呢?因为当插件初始化时会导致 Android 应用崩溃。我发现最快速的方法就是在 EveryPlaySettings.cs 文件中更新几行代码(该文件的路径:Assets → Plugins → EveryPlay → Scripts),如此一来,每当 Everyplay 视图检测自身是否处于开启状态时,我们都会给它返回“false”。

public class EveryplaySettings : ScriptableObject

{

public string clientId;

public string clientSecret;

public string redirectURI = "https://m.everyplay.com/auth";

public bool iosSupportEnabled;

public bool tvosSupportEnabled;

public bool androidSupportEnabled;

public bool standaloneSupportEnabled;

public bool testButtonsEnabled;

public bool earlyInitializerEnabled = true;

public bool IsEnabled

{

get

{

return false;

}

}

#if UNITY_EDITOR

public bool IsBuildTargetEnabled

{

get

{

return false;

}

}

#endif

public bool IsValid

{

get

{

return false;

}

}

}

现在我们已经准备好 Build 了。在 Unity 中打开 Build Settings,选择 Android 平台,然后按下“Switch Platform”按钮。随后,在 Player Settings 中为 Android App 修改 bundle id。在这里,我使用的是 com.agora.tanks.voicedemo。

集成语音聊天功能

接下来,我们要利用 Unity 中的 Agora voice SDK for Unity 来给跨平台项目增加语音聊天功能了。我们打开 Unity Asset Store ,搜索 Agora Voice SDK for Unity。

当插件页面完成加载后,点击“Download”开始下载。下载完成后,选择“Import”,将它集成到你的项目中。

我们需要创建一个脚本来让游戏与 Agora Voice SDK 进行交互。我们在项目中新建一个 C# 文件(AgoraInterface.cs),然后在 Visual Studio 中打开它。

在这个脚本中有两个很重要的变量:

static IRtcEngine mRtcEngine;

public static string appId = "Your Agora AppId Here";

先要将“Your Agora AppId Here” 替换成 App ID,我们可在登录 Agora.io ,进入 Agora Dashboard 获取。mRtcEngine是静态的,这样在OnUpdate 调用的时候,才不会丢失。由于游戏中的其它脚本可能会引用 App ID,所以它是public static。

考虑到节省时间,我已经将AgoraInterface.cs的代码写好了(如下所示)。大家可以直接使用,避免重复造车轮。

在这里简单解释一下代码。首先,我们在开头有一些逻辑,用于 check/requset Android Permission。然后我们用 App ID 初始化 Agora RTC Engine,然后我们附加了一些事件回调,这部分很简单易懂。

mRtcEngine.OnJoinChannelSuccess表示用户已经成功加入指定频道。

最后一个重要功能就是update,当启用了 Agora RTC Engine 时,我们想要调用引擎的.Pull()方法,它对于插件是否能运行起来很关键。

using System;

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

using UnityEngine.UI;

using UnityEngine.SceneManagement;

using agora_gaming_rtc;

#if(UNITY_2018_3_OR_NEWER)

using UnityEngine.Android;

#endif

public class AgoraInterface : MonoBehaviour

{

static IRtcEngine mRtcEngine;

// PLEASE KEEP THIS App ID IN SAFE PLACE

// Get your own App ID at https://dashboard.agora.io/

// After you entered the App ID, remove ## outside of Your App ID

public static string appId = "Your Agora AppId Here";

void Awake()

{

QualitySettings.vSyncCount = 0;

Application.targetFrameRate = 30;

}

// Start is called before the first frame update

void Start()

{

#if (UNITY_2018_3_OR_NEWER)

if (Permission.HasUserAuthorizedPermission(Permission.Microphone))

{

}

else

{

Permission.RequestUserPermission(Permission.Microphone);

}

#endif

mRtcEngine = IRtcEngine.GetEngine(appId);

Debug.Log("Version : " + IRtcEngine.GetSdkVersion());

mRtcEngine.OnJoinChannelSuccess += (string channelName, uint uid, int elapsed) => {

string joinSuccessMessage = string.Format("joinChannel callback uid: {0}, channel: {1}, version: {2}", uid, channelName, IRtcEngine.GetSdkVersion());

Debug.Log(joinSuccessMessage);

};

mRtcEngine.OnLeaveChannel += (RtcStats stats) => {

string leaveChannelMessage = string.Format("onLeaveChannel callback duration {0}, tx: {1}, rx: {2}, tx kbps: {3}, rx kbps: {4}", stats.duration, stats.txBytes, stats.rxBytes, stats.txKBitRate, stats.rxKBitRate);

Debug.Log(leaveChannelMessage);

};

mRtcEngine.OnUserJoined += (uint uid, int elapsed) => {

string userJoinedMessage = string.Format("onUserJoined callback uid {0} {1}", uid, elapsed);

Debug.Log(userJoinedMessage);

};

mRtcEngine.OnUserOffline += (uint uid, USER_OFFLINE_REASON reason) => {

string userOfflineMessage = string.Format("onUserOffline callback uid {0} {1}", uid, reason);

Debug.Log(userOfflineMessage);

};

mRtcEngine.OnVolumeIndication += (AudioVolumeInfo[] speakers, int speakerNumber, int totalVolume) => {

if (speakerNumber == 0 || speakers == null)

{

Debug.Log(string.Format("onVolumeIndication only local {0}", totalVolume));

}

for (int idx = 0; idx < speakerNumber; idx++)

{

string volumeIndicationMessage = string.Format("{0} onVolumeIndication {1} {2}", speakerNumber, speakers[idx].uid, speakers[idx].volume);

Debug.Log(volumeIndicationMessage);

}

};

mRtcEngine.OnUserMuted += (uint uid, bool muted) => {

string userMutedMessage = string.Format("onUserMuted callback uid {0} {1}", uid, muted);

Debug.Log(userMutedMessage);

};

mRtcEngine.OnWarning += (int warn, string msg) => {

string description = IRtcEngine.GetErrorDescription(warn);

string warningMessage = string.Format("onWarning callback {0} {1} {2}", warn, msg, description);

Debug.Log(warningMessage);

};

mRtcEngine.OnError += (int error, string msg) => {

string description = IRtcEngine.GetErrorDescription(error);

string errorMessage = string.Format("onError callback {0} {1} {2}", error, msg, description);

Debug.Log(errorMessage);

};

mRtcEngine.OnRtcStats += (RtcStats stats) => {

string rtcStatsMessage = string.Format("onRtcStats callback duration {0}, tx: {1}, rx: {2}, tx kbps: {3}, rx kbps: {4}, tx(a) kbps: {5}, rx(a) kbps: {6} users {7}",

stats.duration, stats.txBytes, stats.rxBytes, stats.txKBitRate, stats.rxKBitRate, stats.txAudioKBitRate, stats.rxAudioKBitRate, stats.users);

Debug.Log(rtcStatsMessage);

int lengthOfMixingFile = mRtcEngine.GetAudioMixingDuration();

int currentTs = mRtcEngine.GetAudioMixingCurrentPosition();

string mixingMessage = string.Format("Mixing File Meta {0}, {1}", lengthOfMixingFile, currentTs);

Debug.Log(mixingMessage);

};

mRtcEngine.OnAudioRouteChanged += (AUDIO_ROUTE route) => {

string routeMessage = string.Format("onAudioRouteChanged {0}", route);

Debug.Log(routeMessage);

};

mRtcEngine.OnRequestToken += () => {

string requestKeyMessage = string.Format("OnRequestToken");

Debug.Log(requestKeyMessage);

};

mRtcEngine.OnConnectionInterrupted += () => {

string interruptedMessage = string.Format("OnConnectionInterrupted");

Debug.Log(interruptedMessage);

};

mRtcEngine.OnConnectionLost += () => {

string lostMessage = string.Format("OnConnectionLost");

Debug.Log(lostMessage);

};

mRtcEngine.SetLogFilter(LOG_FILTER.INFO);

// mRtcEngine.setLogFile("path_to_file_unity.log");

mRtcEngine.SetChannelProfile(CHANNEL_PROFILE.GAME_FREE_MODE);

// mRtcEngine.SetChannelProfile (CHANNEL_PROFILE.GAME_COMMAND_MODE);

// mRtcEngine.SetClientRole (CLIENT_ROLE.BROADCASTER);

}

// Update is called once per frame

void Update ()

{

if (mRtcEngine != null) {

mRtcEngine.Poll ();

}

}

}

注意,以上代码可复用于所有 Unity 项目。

离开频道

如果你曾经使用过 Agora SDK,你可能注意到了,这里没有加入频道和离开频道。让我们先从“离开频道”开始动手,创建一个新的 C# 脚本LeaveHandler.cs,我们需要在用户返回到主菜单的时候调用 theleaveHandler。最简单的方法就是在 LobbyScene 打开后,为特定游戏对象开启该方法。

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

using agora_gaming_rtc;

public class LeaveHandler : MonoBehaviour

{

// Start is called before the first frame update

void OnEnable()

{

// Agora.io Implimentation

IRtcEngine mRtcEngine = IRtcEngine.GetEngine(AgoraInterfaceScript.appId); // Get a reference to the Engine

if (mRtcEngine != null)

{

Debug.Log("Leaving Channel");

mRtcEngine.LeaveChannel();// leave the channel

}

}

}

在这里,我们要找的游戏对象是 LeftSubPanel (如下图,MainPanel → MenuUI → LeftSubPanel )。

Tanks!!! 中有两种方法加入多人游戏,一种是创建新游戏,另一种是加入游戏。所以有两个地方,我们需要增加“加入频道”的命令。

让我们先找到 UI Script Asset 文件夹(该文件夹路径:Assets → Scripts → UI),然后打开CreateGame.cs文件。在第61行,你会找到游戏用于匹配玩家的方法,在这里我们可以加入一些逻辑用于加入频道。首先我们要做的就是应用 Agora SDK 库。

using agora_gaming_rtc;

在StartMatchmakingGame()的第78行,我们需要加入一些逻辑来获取正在运行中的Agora RTC Engine,然后将“用户输入的内容”作为频道名称(m_MatchNameInput.text)。

private void StartMatchmakingGame()

{

GameSettings settings = GameSettings.s_Instance;

settings.SetMapIndex(m_MapSelect.currentIndex);

settings.SetModeIndex(m_ModeSelect.currentIndex);

m_MenuUi.ShowConnectingModal(false);

Debug.Log(GetGameName());

m_NetManager.StartMatchmakingGame(GetGameName(), (success, matchInfo) =>

{

if (!success)

{

m_MenuUi.ShowInfoPopup("Failed to create game.", null);

}

else

{

m_MenuUi.HideInfoPopup();

m_MenuUi.ShowLobbyPanel();

// Agora.io Implimentation

var channelName = m_MatchNameInput.text; // testing --> prod use: m_MatchNameInput.text

IRtcEngine mRtcEngine = IRtcEngine.GetEngine(AgoraInterfaceScript.appId); // Get a reference to the Engine

mRtcEngine.JoinChannel(channelName, "extra", 0); // join the channel with given match name

Debug.Log("joining channel:" + channelName);

}

});

}

StartMatchmakingGame()包含了加入频道

现在我们需要打开LobbyServerEntry.cs(Assets → Scripts → UI),然后加入一些逻辑,以实现让用户可以通过“Find a Game”来加入其他人的房间。

在 Visual Studio 打开 LobbyServerEntry.cs,然后找到第63行,这里有一个 JoinMatch()。我们在第80行增加几行代码。

private void JoinMatch(NetworkID networkId, String matchName)

{

MainMenuUI menuUi = MainMenuUI.s_Instance;

menuUi.ShowConnectingModal(true);

m_NetManager.JoinMatchmakingGame(networkId, (success, matchInfo) =>

{

//Failure flow

if (!success)

{

menuUi.ShowInfoPopup("Failed to join game.", null);

}

//Success flow

else

{

menuUi.HideInfoPopup();

menuUi.ShowInfoPopup("Entering lobby...");

m_NetManager.gameModeUpdated += menuUi.ShowLobbyPanelForConnection;

// Agora.io Implimentation

var channelName = matchName; // testing --> prod use: matchName

IRtcEngine mRtcEngine = IRtcEngine.GetEngine(AgoraInterfaceScript.appId); // Get a reference to the Engine

mRtcEngine.JoinChannel(channelName, "extra", 0); // join the channel with given match name

// testing

string joinChannelMessage = string.Format("joining channel: {0}", channelName);

Debug.Log(joinChannelMessage);

}

}

);

}

完成了!

现在我们已经完成了Agora SDK 的集成,并且已经准备好进行 iOS 端和 Android 端的 Build 与测试。我们可以参照上述内容中的方法来进行 Building 与部署。

为了便于大家参考,我已经将这份 Tutorial 中的脚本上传了一份到 Github:

https://github.com/digitallys...

如果你遇到 Agora SDK API 调用问题,可以参考我们的官方文档(docs.agora.io),也欢迎在 RTC 开发者社区 的 Agora 版块与我们的工程师和更多同行交流、分享。

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

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

相关文章

搜索用计算机弹奏9277的数字,计算机基础知识参考试题(含答案)

计算机基础知识参考试题(含答案)计算机基础知识参考试题及答案解析一、单选题1.1946年诞生的世界上公认的第一台电子计算机是( ENIA)。2.第一台计算机在研制过程中采用了哪位科学家的两点改进意见(冯诺依曼)。3.第二代电子计算机所采用的电子元件是(晶体管)。4.硬盘属于(外部存…

dscp值_TOS-DSCP对照表

TOS/DSCP对照表在IP网络中&#xff0c;IPv4报文中有三种承载QoS优先级标签的方式&#xff0c;分别为基于二层的CoS字段(IEEE802.1p)的优先级、基于IP层的IP优先级字段ToS优先级和基于IP层的DSCP(Differentiated Services Codepoint)字段优先级。每种优先级的定义如下&#xff1…

2019年大学计算机基础操作题,2019年大学计算机基础试题及答案(14页)-原创力文档...

计算机基础试题及答案一、选择题1. 冯诺依曼计算机工作原理的设计思想是。(B)A. 程序设计B. 程序存储C. 程序编制D. 算法设计2. 计算机的逻辑判断能力决定于(C)A. 硬件B. 体积C. 编制的软件D. 基本字长3. 构成计算机物理实体的部件称为(C)A. 计算机软件B. 计算机程序C. 计算机硬…

python开发技术文档范文_程序员编写技术文档的新手指南

这是一篇帮助你给第一个项目写文档的指南。万事开头难&#xff0c;我希望这份指南能把你引导到正确的道路上。最后&#xff0c;你应该有一个可以公开发布的项目。请轻松地阅读完这篇文章&#xff0c;或者简单地把它当作参考。为什么要写文档&#xff1f;你将会在 6 个月后使用你…

长沙计算机中级职称分数公布,大家所期待的2020年湖南省长沙中级职称评审公示...

原标题&#xff1a;大家所期待的2020年湖南省长沙中级职称评审公示年底了&#xff0c;各大考试差不多都快结束了。唯一就是湖南长沙的土建中级职称评审结果待公示&#xff0c;湖南岳阳&#xff0c;湘潭等地方也相继公示。2019年湖南省中级职称评审(长沙市)12月24号公示&#xf…

android平台上持久化存储3种手段_深入学习Redis :持久化

前言在上一篇文章中&#xff0c;介绍了Redis的内存模型&#xff0c;从这篇文章开始&#xff0c;将依次介绍Redis高可用相关的知识——持久化、复制(及读写分离)、哨兵、以及集群。本文将先说明上述几种技术分别解决了Redis高可用的什么问题&#xff1b;然后详细介绍Redis的持久…

印刷 计算机控制系统,陶瓷印刷计算机直接制版控制系统设计与实现

摘要&#xff1a;"陶瓷印刷计算机直接制版系统"是为陶瓷印刷制作印版的高度自动化系统,它将计算机引入制版过程中,简化印版制作工序,提高印版制作质量. 首先,本文介绍计算机直接制版系统的发展现状和趋势,并提出以此为基础,开发陶瓷印刷计算机直接制版系统的必要性和…

自动驾驶芯片_自动驾驶芯片“争夺战”

伴随着智能汽车时代的加速到来&#xff0c;自动驾驶芯片“争夺战”也越演越烈。继奥迪、宝马、长安、广汽、小鹏等汽车厂商“摩拳擦掌”L3级自动驾驶后&#xff0c;近日本田扔出了一个大消息&#xff0c;L3级自动驾驶汽车将于明年3月正式开售。至此&#xff0c;全球已经进入L3级…

通信技术计算机通信方向专业,江西科技学院2014年招生通信工程(计算机通信方向)专业介绍...

专业代码&#xff1a;080703一、专业培养目标本专业培养掌握通信工程的基本理论和基本知识&#xff0c;获得计算机通信工程实践的基本训练&#xff0c;具备从事现代电子通信系统和通信网络的生产、设计、调试和应用能力的高级应用型工程技术人才。二、专业就业方向学生毕业后可…

r语言将百分数化为小数_「淮南师出」教师资格/招聘小学数学:《百分数与小数的互化》...

教学目标&#xff1a;1、利用已有知识迁移、类推、发现百分数和小数互化的规律和方法。2、理解、掌握百分数和小数互化的方法&#xff0c;并能熟练运用&#xff0c;进一步体会数学之间的内在联系&#xff0c;增强思维的深刻性。3、通过合作交流、探索发现等数学学习活动教给学生…

wps表格里面计算机在哪里,WPS的Word居然还有计算神器?在哪里能找到又是怎么进行计算呢?...

说到计算器&#xff0c;恐怕好多小伙伴第一时间会想到WPS的Excel和微软的Excel表格&#xff0c;其实&#xff0c;WPS的Word也有计算器&#xff0c;只是隐藏了起来好多人不知道而已。只要找到它&#xff0c;我们在Word里也能进行加减乘除的计算了&#xff0c;下面白豆芽就给大家…

git reset 怎么还原_如何在Git中重置、恢复,返回到以前的状态

编辑推荐:本文来自51cto&#xff0c;在本文中&#xff0c;我们将带你了解如何去重置、恢复和完全回到以前的状态&#xff0c;做到这些只需要几个简单而优雅的Git 命令。用简洁而优雅的 Git 命令撤销仓库中的改变。使用 Git 工作时其中一个鲜为人知(和没有意识到)的方面就是&…

u盘复制到计算机的文档打不开怎么办,从电脑复制到U盘的文件打不开该怎么处理...

首先我们来看看&#xff0c;怎样的操作会让复制到U盘的文件无法打开&#xff1f;一种操作是&#xff0c;打开电脑文件夹&#xff0c;在文件上点右键&#xff0c;选“发送到-桌面快捷方式”。这样&#xff0c;在电脑桌面上就出现了一个文件的快捷方式。2、桌面上新建立的快捷方式…

深入浅出:Go 语言中值传递与引用传递的原理解析

深入浅出&#xff1a;Go 语言中值传递与引用传递的原理解析 引言Go 语言中的值传递什么是值传递&#xff1f;Go 语言中值传递的工作原理代码示例 Go 语言中的引用传递什么是引用传递&#xff1f;Go 语言中引用传递的工作原理代码示例 值传递与引用传递的比较优势和劣势应用场景…

arcgis显示后台错误_死亡、税收和Esri ArcGIS 999999错误:如何修复

死亡、税收和Esri ArcGIS 999999错误&#xff1a;如何修复如何修复Esri 999999错误生活中有些事情是确定的。在Arcgis&#xff0c;是 Esri 999999 error。基本上&#xff0c;当Arcgis不能指定导致错误的原因时&#xff0c;它会发出这个一般性错误。也就是那个让你们都泪流满面的…

专科学数控还是计算机,盘点适合专科男生学的专业 哪些专业好就业

正所谓&#xff1a;男怕入错行&#xff0c;女怕嫁错郎。对于专科男生来说&#xff0c;哪些专业好就业呢&#xff1f;下面和小编一起来看看吧&#xff01;1、数控加工专业随着数控制造增多&#xff0c;我国对于数控加工专业人才严重缺乏。选择学数控加工专业的专科男生在毕业后&…

finditerable 转list_Iterable/Iterator 转 list

先简单介绍一下iterable和iterator&#xff1a;iterator为Java中的迭代器对象&#xff0c;是能够对List这样的集合进行迭代遍历的底层依赖。而iterable接口里定义了返回iterator的方法&#xff0c;相当于对iterator的封装&#xff0c;同时实现了iterable接口的类可以支持for ea…

牛顿莱布尼茨计算机公式,牛顿莱布尼茨公式

《牛顿莱布尼茨公式》由会员分享&#xff0c;可在线阅读&#xff0c;更多相关《牛顿莱布尼茨公式(17页珍藏版)》请在人人文库网上搜索。1、装订线教学过程1、复习旧知识&#xff0c;引入课题(1)复习&#xff1a;定积分的概念及几何意义原函数的概念导数的定义(2)课题引入&#…

ap设置 维盟660g_New丨维盟双频百兆11ac入墙AP:WAP-3018穿墙效果不一样!

新的9月&#xff0c;维盟新品bulingbuling闪亮登场看这里 维盟WAP-3018WAP-3018是一款入墙式无线AP&#xff0c;64M内存&#xff0c;8M闪存&#xff0c;支持智能无线技术&#xff0c;2.4G和5G双频并发&#xff0c;无线传输速率1167Mbps&#xff0c;带功率放大器&#xff0c;穿墙…

研究生夏令营计算机题目,2017计算机学科夏令营上机考试-B编码字符串

EF里单个实体的增查改删以及主从表关联数据的各种增删 改查本文目录 EF对单个实体的增查改删 增加单个实体 查询单个实体 修改单个实体 删除单个实体 EF里主从表关联数据的各种增删改查 增加(增加从表数据.增加主从表数据) 查询(根据主表找从表数据.根据从表 ...简单而又复杂的…