Unity社交功能开发——图片上传
来源:互联网 发布:变形相机是什么软件 编辑:程序博客网 时间:2024/06/07 05:13
一、图片上传功能的意义
随着梦幻西游、大话西游、问道等回合制游戏的兴起,手游制作团队越来越重视社交功能的开发。笔者前一篇文章介绍了如何在Unity中加入语音聊天功能,本篇文章将介绍下一个社交功能——图片上传。
有了图片上传玩家就可以自定义头像、聊天发送图片甚至还可以在Unity中做一个『朋友圈』。
二、获取图片到Unity
Unity没有提供直接的Api打开移动端的相机、相册功能,所以需要调用Android/IOS的系统Api来打开移动端的相机和相册
1. Android获取相机、相册图片
主要功能实现参考雨松momo的文章Unity3D研究院之打开照相机与本地相册进行裁剪显示(三十三)
第一步,建立Unity项目对应的Android工程
如果不会可以查看雨松momo的文章Unity3D研究院之与Android相互传递消息(十九)
第二步,书写打开相机、相册代码by Android
/** * 打开相机 为什么要指定一个保存路径,是因为如果不指定onActivityResult只能从data参数中获取图片,可是获取到的是略缩图 */ public void TakePhotoChoose() { int hasCameraPermission = checkCallingOrSelfPermission(Manifest.permission.CAMERA); Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss"); File imageFile = new File(Environment.getExternalStorageDirectory().getPath() + "/DCIM/Camera/" + format.format(new Date()) + ".jpg"); intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(imageFile)); PhotoPath = imageFile.getPath(); startActivityForResult(intent, PIC_TAKE_PHOTO); } /** * 打开相册 */ public void TakePickChoose() { Intent intent = new Intent(Intent.ACTION_PICK, null); intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, IMAGE_TYPE); startActivityForResult(intent, PIC_TAKE_PICK); }
第三步,获取到图片处理图片发送到Unity
@Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode == 0) { // 取消接口 UnityPlayer.UnitySendMessage("GameMain", "CandleShowPhoto", ""); return; } if (requestCode == PIC_TAKE_PHOTO) { // 获取到图片的资源使用bitmap压缩,并且转成base64的String直接将字符串发回去 Log.e("Unity", "GetPhotoPath"); UnityPlayer.UnitySendMessage("GameMain", "GetPath", PhotoPath); Bitmap bm = PhotoUtil.getImageFromPath(PhotoPath, 40, 500, 750); Bitmap bmSmall = PhotoUtil.getImageFromPath(PhotoPath, 40, 60, 80); UnityPlayer.UnitySendMessage("GameMain", "ShowPhoto", PhotoUtil.getBitmapStrBase64(bm)); UnityPlayer.UnitySendMessage("GameMain", "SaveMiniPhoto", PhotoUtil.getBitmapStrBase64(bmSmall)); } if (requestCode == PIC_TAKE_PICK) { // 读取相册缩放图片 Bitmap bm = null; ContentResolver resolver = getContentResolver(); Uri originalUri = data.getData(); Cursor cursor = getContentResolver().query(originalUri, null, null, null, null); if (cursor != null && cursor.moveToFirst()) { String path = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA)); bm = PhotoUtil.getImageFromPath(path, 40, 500, 750); Bitmap bmSmall = PhotoUtil.getImageFromPath(path, 40, 60, 80); UnityPlayer.UnitySendMessage("GameMain", "ShowPhoto", PhotoUtil.getBitmapStrBase64(bm)); UnityPlayer.UnitySendMessage("GameMain", "SaveMiniPhoto", PhotoUtil.getBitmapStrBase64(bmSmall)); } else { try { bm = MediaStore.Images.Media.getBitmap(resolver, originalUri); } catch (IOException e) { e.printStackTrace(); } if (bm != null) { Thread thread = new YaSuoPicThread(bm); thread.start(); } } } }
在对图片处理过程中与鱼松momo有些不同,我没有将图片再次保存,而是将bitmap转成了string直接发送回了unity,省去了保存图片的时间,并且效果上看运行速度还是可以接受的。大家可以自己试试。
第四步,Unity显示图片
由于显示图片功能放在了Unity,Android和IOS是公用的所以下文IOS中不再重复
/// <summary> /// 从Android/IOS获取图片的base64串并显示图片 /// </summary> /// <param name="base64">图片的base64串</param> void ShowPhoto(string base64) { int targetHeight = 400; int targetWidth = 600; byte[] inputBytes = System.Convert.FromBase64String(base64); base64 = ""; Texture2D text = BttetoPicByByte(inputBytes); int curHeight = text.height; int curWidth = text.width; int newHeight = 0; int newWidth = 0; GetCutSize(targetHeight, targetWidth, curHeight, curWidth, ref newHeight, ref newWidth); if (BigImage != null) { BigImage.gameObject.SetActive(true); BigImage.rectTransform.sizeDelta = new Vector2(newWidth, newHeight); BigImage.texture = text; m_Stream = new MemoryStream(inputBytes); inputBytes = null; } CloseDialogJuHua(); } /// <summary> /// 工具:将string转成图片 /// </summary> /// <param name="base64"></param> /// <returns></returns> Texture2D BttetoPic(string base64) { Texture2D pic = new Texture2D(600, 400); //将base64转码为byte[] byte[] data = System.Convert.FromBase64String(base64); //加载byte[]图片 pic.LoadImage(data); return pic; } /// <summary> /// 工具:将bytes转成图片 /// </summary> /// <param name="bytes"></param> /// <returns></returns> Texture2D BttetoPicByByte(byte[] bytes) { Texture2D pic = new Texture2D(600, 400); //加载byte[]图片 pic.LoadImage(bytes); return pic; } /// <summary> /// 工具:返回给定高宽内的图片高度和宽度 比如给定400*600 肯定返回一个400*600之内的照片 /// </summary> /// <param name="targetHeight"></param> /// <param name="targetWidth"></param> /// <param name="curHeight"></param> /// <param name="curWidth"></param> /// <param name="newHeight"></param> /// <param name="newWidth"></param> public static void GetCutSize(int targetHeight, int targetWidth, int curHeight, int curWidth, ref int newHeight, ref int newWidth) { int TargetHeight = targetHeight; int TargetWidth = targetWidth; int width = curWidth; int height = curHeight; float bili = 1f; if (width > TargetWidth) { bili = (float)TargetWidth / (float)width; } newHeight = (int)((float)height * bili); if (newHeight > TargetHeight) { bili = (float)TargetHeight / (float)height; } newHeight = (int)((float)height * bili); newWidth = (int)((float)width * bili); }
2. IOS获取相机、相册图片
如果不会IOS与Unity交互的同学请戳这里
第一步,书写打开相机、相册代码by IOS
需要用到Assetslibrary.framework
//// GetPhotoControl.m// image2//// Created by tengjiang on 16/4/26.// Copyright © 2016年 All rights reserved.//#import <Foundation/Foundation.h>#import "GetPhotoManager.h"#include <sys/param.h>#include <sys/mount.h>#import <AssetsLibrary/AssetsLibrary.h>#import <AVFoundation/AVCaptureDevice.h>#import <AVFoundation/AVMediaFormat.h>extern "C"{ void _GetPhotoControl(int index);}static GetPhotoManager *getPhotoControl;void _GetPhotoControl(int index){ if(getPhotoControl == NULL) { getPhotoControl = [[GetPhotoManager alloc] init]; } [getPhotoControl GetPhotoChoose:index];}@implementation GetPhotoManagertypedef enum { kCLAuthorizationStatusNotDetermined = 0, // 用户尚未做出选择这个应用程序的问候 kCLAuthorizationStatusRestricted, // 此应用程序没有被授权访问的照片数据。可能是家长控制权限 kCLAuthorizationStatusDenied, // 用户已经明确否认了这一照片数据的应用程序访问 kCLAuthorizationStatusAuthorized // 用户已经授权应用访问照片数据} CLAuthorizationStatus;};- (void)GetPhotoChoose:(NSInteger)ChooseIndex{ UIImagePickerControllerSourceType sourceType = UIImagePickerControllerSourceTypePhotoLibrary; // 判断是否支持相机 if([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) { switch (ChooseIndex) { case 0: //来源:相机 if([self GetCameraPermission] == -1) { UnitySendMessage("GameMain", "CandleShowPhoto", ""); return; } sourceType = UIImagePickerControllerSourceTypeCamera; break; case 1: if([self GEtPickPermission] == -1) { UnitySendMessage("GameMain", "CandleShowPhoto", ""); return; } //来源:相册 sourceType = UIImagePickerControllerSourceTypePhotoLibrary; break; case 2: UnitySendMessage("GameMain", "CandleShowPhoto", ""); return; } } else { if (ChooseIndex == 2) { UnitySendMessage("GameMain", "CandleShowPhoto", ""); return; } else { if([self GEtPickPermission] == -1) { UnitySendMessage("GameMain", "CandleShowPhoto", ""); return; } sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum; } } // 跳转到相机或相册页面 UIImagePickerController *imagePickerController = [[UIImagePickerController alloc] init]; imagePickerController.delegate = self; //imagePickerController.allowsEditing = NO; imagePickerController.sourceType = sourceType; //仔细看这句话Unity中如果获取presentViewController并跳转,需要这样写 [UnityGetGLViewController() presentViewController:imagePickerController animated:YES completion:^{ }]; //↑↑↑↑↑↑↑↑↑↑↑↑↑仔细看↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑}//获取图片后的回调- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info{ [picker dismissViewControllerAnimated:YES completion:^{ }]; UIImage *image = [info objectForKey:UIImagePickerControllerOriginalImage]; NSData *fData = [self imageCompressForWidth:image targetWidth:600 targetHeight:400]; NSString *stringPhoto = [fData base64EncodedStringWithOptions:0]; UnitySendMessage("GameMain", "ShowPhoto", [stringPhoto UTF8String]); NSData *fDataSmall = [self imageCompressForWidth:image targetWidth:80 targetHeight:60]; NSString *stringPhotoSmall = [fDataSmall base64EncodedStringWithOptions:0]; UnitySendMessage("GameMain", "ShowMiniPhoto", [stringPhotoSmall UTF8String]);}//取消的回调- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker{ NSLog(@"您取消了选择图片"); [picker dismissViewControllerAnimated:YES completion:^{ }]; UnitySendMessage("GameMain", "CandleShowPhoto", "");}//工具:图片裁剪- (NSData *) imageCompressForWidth:(UIImage *)sourceImage targetWidth:(CGFloat)defineWidth targetHeight:(CGFloat)defineHeight{ CGSize imageSize = sourceImage.size; CGFloat width = imageSize.width; CGFloat height = imageSize.height; CGFloat targetWidth = defineWidth; CGFloat targetHeight = (targetWidth / width) * height; if(targetHeight > defineHeight) { targetHeight = defineHeight; targetWidth = (targetHeight / height) * width; } UIGraphicsBeginImageContext(CGSizeMake(targetWidth, targetHeight)); [sourceImage drawInRect:CGRectMake(0,0,targetWidth, targetHeight)]; UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); NSData *fData = UIImageJPEGRepresentation(newImage, 1); return fData;}//判断是否开启访问相机权限-(int) GetCameraPermission{ NSString *mediaType = AVMediaTypeVideo; AVAuthorizationStatus authStatus = [AVCaptureDevice authorizationStatusForMediaType:mediaType]; if(authStatus == AVAuthorizationStatusRestricted|| authStatus == AVAuthorizationStatusDenied){ UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"提示" message:@"请在设备的设置-隐私-相机中允许访问相机。" delegate:self cancelButtonTitle:@"确定" otherButtonTitles:nil]; [alert show]; return -1; } else if(authStatus == AVAuthorizationStatusAuthorized){//允许访问 return 0; } return 0;}//判断是否开启访问相册权限-(int) GEtPickPermission{ ALAuthorizationStatus author = [ALAssetsLibrary authorizationStatus]; if (author == kCLAuthorizationStatusRestricted || author == kCLAuthorizationStatusDenied){ UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"提示" message:@"请在设备的设置-隐私-照片中允许访问照片。" delegate:self cancelButtonTitle:@"确定" otherButtonTitles:nil]; [alert show]; return -1; } return 0;}@end
三、上传图片
已经拿到了图片文件的Steam可以直接上传到服务器,生成CDN链接,将链接分发的其他用户。
如果觉得麻烦或者觉得没有必要自己实现,可以通过云储存功能,将图片直接存到云服务。笔者用的是UCloud。当然市场上还有很多厂家提供云储存功能:七牛、阿里云、腾讯云等。。
使用云储存的好处:
1.奉行“专业的人做专业的事”原则
2.节省了开发时间,减少服务器压力
3.云储存都会提供图像再次处理功能,可以再次压缩图片,使用户下来的图片更小,节省用户流量提高用户体验。
四、下载图片并显示
成功上传到云服务器会自动生成一个链接,可以通过链接直接访问图片
Unity加载外部资源主要依靠www协议。可以直接铜鼓www协议加载图片到游戏中,但是用户不可能永远只点开一个图片一次。笔者先将图片下载到本地,然后通过www协议将本地的图片加载到Unity,如果用户再次点开,可以节省用户的流量。
public void LoadPicByUrlBySmallImage(string _url) { string url = "";#if UNITY_STANDALONE_WIN url = "file:///" + _url;#else url = "file://" + _url;#endif StartCoroutine(LoadTextureBySmallImage(url)); } /// <summary> /// load大图携程 /// </summary> /// <param name="name"></param> /// <returns></returns> IEnumerator LoadTexture(string name) { string path = name; WWW www = new WWW(path); yield return www; if (www.isDone) { Texture2D txt = www.texture; int width = txt.width; int height = txt.height; int targetHeight = 400; int targetWidth = 600; int newHeight = 0; int newWidth = 0; GetCutSize(targetHeight, targetWidth, height, width, ref newHeight, ref newWidth); if (BigImage != null) { BigImage.gameObject.SetActive(true); BigImage.rectTransform.sizeDelta = new Vector2(newWidth, newHeight); BigImage.texture = txt; } CloseDialogJuHua(); } }
最后笔者将本篇博文的源码放出来, 源码包括Android的工程、Plugins/IOS目录下的IOS代码和Unity的工程
下载地址:https://github.com/Prince-Ling/Unity_PushPhoto
- Unity社交功能开发——图片上传
- Unity社交功能开发——语音聊天
- Unity社交功能开发——移动端输入法回车事件响应
- SharePoint 2013 开发——其他社交功能
- iOS开发实现文字/图片的社交网络分享功能
- 百度编辑器 单独开发图片上传功能
- Unity上传图片
- 微信小程序开发—(四)上传图片
- web前端——实现上传图片预览功能
- 淘淘商城系列——实现图片上传功能
- 图片上传功能
- 图片上传预览功能
- 图片上传功能关闭?
- 做两张图片上传功能
- jsp 上传图片功能
- PHP上传图片功能
- php上传图片功能
- 记录图片上传功能
- HDU1995-汉诺塔V
- NGUI之UIButton"禁用"状态时置灰
- Spring访问oracle数据库配置步骤
- SpringMVC源代码学习外传(二)如何在重定向时传递参数&FlashMap
- java集合12--TreeMap源码详解
- Unity社交功能开发——图片上传
- 内存管理---slab机制 销毁对象
- Linux学习之目录处理命令
- 机器学习--最小二乘法和加权线性回归
- c++作业5
- QT 学习之路
- c# 拖拽事件
- Mac环境下svn的使用
- 程序员的十大优秀习惯