哈工大计算机科学与技术学院软件基础教研室 第二部分 Android 与工程和科研 授课教师:李治军 综合楼 411 室 第 5 讲 Android 人机交互与游戏 Lecture 5: Human-Computer Interface in Android.

Slides:



Advertisements
Similar presentations
面向侧面的程序设计 方林博士 本文下载地址:
Advertisements

立誠電腦 資訊有限公 司. 公司名 稱 立誠電腦資訊有限公司 產業領 域 ■資訊業 主要產 品 電腦周邊設備、二類電信 負責人陳鴻國 總公司所在地:台中市大 雅區學府路 76 巷 3 號 成立年 度 民國 94 年實收資本額 ( 萬 ) : 500 營運情 況 2010 年 2011 年 2012.
3.2 Java的类 Java 类库的概念 语言规则——程序的书写规范 Java语言 类库——已有的有特定功能的Java程序模块
计算机网络课程总结 一、计算机网络基础 计算机网络定义和功能、基本组成 OSI/RM参考模型(各层的功能,相关概念, 模型中数据传输 等)
《计算机网络技术》 课程整体设计介绍.
第十五章 网络编程.
对实验教学工作的认识与思考 西北工业大学 万小朋 2014年11月.
UI(用户界面)集训班 Illustrator 高级班.
位置與地圖應用 此投影片為講解Android如何取得定位經緯度和使用Google Map地圖.
第11章 Java多媒体技术.
第二章 JAVA语言基础.
探索三角形相似的条件(2).
C++中的声音处理 在传统Turbo C环境中,如果想用C语言控制电脑发声,可以用Sound函数。在VC6.6环境中如果想控制电脑发声则采用Beep函数。原型为: Beep(频率,持续时间) , 单位毫秒 暂停程序执行使用Sleep函数 Sleep(持续时间), 单位毫秒 引用这两个函数时,必须包含头文件
實驗四:單位轉換程式.
Android + JUnit 單元測試 建國科技大學資管系 饒瑞佶 2012/8/19V4.
格物资讯开放ICON库 V1R1.
Java语言程序设计 清华大学出版社 第9章 网络通信.
蓄势待发 知识准备阶段.
第一个Android程序 本讲大纲: 1、创建Android应用程序 2、Android项目结构说明 3、运行Android应用程序
第二讲 搭建Java Web开发环境 主讲人:孙娜
TCP/IP Protocol Suite TCP/IP協定 第二組 投影片製作by簡嘉宏 綦凱宏 林睿敏 滕孟哲.
ANDROID 中的 3D 繪圖 作者:陳鍾誠.
程式設計實作.
智慧家庭 組員:林祐偉 楊峻宇 陳泰宇 紀國慶.
西南科技大学网络教育系列课程 高级语程序设计(Java) 第十一章 Java 中的网络编程.
2018/12/3 面向对象与多线程综合实验-网络编程 教师:段鹏飞.
SVN服务器的搭建(Windows) 柳峰
SQL Injection.
绘制圆与多边形 椭圆形 绘制椭圆形的方法是 drawOval(x ,y , width , height), 绘制实心椭圆形的方法是
二十四、感測器.
PostgreSQL 8.3 安装要点 四川大学计算机学院 段 磊
Windows网络操作系统管理 ——Windows Server 2008 R2.
Windows网络操作系统管理 ——Windows Server 2008 R2.
9.1 程式偵錯 9.2 捕捉例外 9.3 自行拋出例外 9.4 自定例外類別 9.5 多執行緒
格物资讯开放ICON库 V0R2.
C/C++/Java 哪些值不是头等程序对象
第七章 操作符重载 胡昊 南京大学计算机系软件所.
4.2通讯服务模块线程之间传递信息 信息工程系 向模军 Tel: QQ:
宁波市高校慕课联盟课程 与 进行交互 Linux 系统管理.
Multithread 多執行緒 以GUI為例了解物件以及Event
JAVA 编 程 技 术 主编 贾振华 2010年1月.
《JAVA程序设计》 语音答疑 辅导老师:高旻.
C++语言程序设计 C++语言程序设计 第七章 类与对象 第十一组 C++语言程序设计.
C语言程序设计 主讲教师:陆幼利.
實驗九:延續實驗八, 製作一個完整音樂播放器
Location Based Services - LBS
第二章 Java基本语法 讲师:复凡.
实验七 安全FTP服务器实验 2019/4/28.
本节内容 Win32 API中的宽字符 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
2019/5/3 JAVA Socket(UDP).
第二章 Java语法基础.
iSIGHT 基本培训 使用 Excel的栅栏问题
3.16 枚举算法及其程序实现 ——数组的作用.
Chapter 18 使用GRASP的对象设计示例.
多层循环 Private Sub Command1_Click() Dim i As Integer, j As Integer
魏新宇 MATLAB/Simulink 与控制系统仿真 魏新宇
第二章 Java基本语法 讲师:复凡.
WSAAsyncSelect 模型 本节内容 视频提供:昆山爱达人信息技术有限公司 视频录制:yang
格物资讯ICON发布 V0R3.
助教:廖啟盛 JAVA Socket(UDP) 助教:廖啟盛
第2章 Java语言基础.
第4讲 类和对象、异常处理 ggao.
第十二章 Java网络编程 1.URL编程 2.Socket网络编程 3.Datagram网络编程.
创建、启动和关闭Activity 本讲大纲: 1、创建Activity 2、配置Activity 3、启动和关闭Activity
加速感測器 靜宜大學資管系 楊子青.
使用Fragment 本讲大纲: 1、创建Fragment 2、在Activity中添加Fragment
第二章 Java基础语法 北京传智播客教育
Part 8 Broadcast Receiver、Service和App Widget
第三章 图形的平移与旋转.
Summary
Presentation transcript:

哈工大计算机科学与技术学院软件基础教研室 第二部分 Android 与工程和科研 授课教师:李治军 综合楼 411 室 第 5 讲 Android 人机交互与游戏 Lecture 5: Human-Computer Interface in Android and Games

- 2 - Android Development 人机交互是计算机发展的动力之一 打孔纸带  键盘 ( 命令行 )  鼠标 ( 图形控件 )  … 对于手机来说,用手点按钮也不方便,屏幕太小 (1) 获得加速度 raw data ; (2) 建立数学模型 ( 物理、几 何 ) ; (3) 计算手臂动作; (4) 推测人的意图; (5) 根据意 图对机器进行控制; (6) 做出实际应用 可以对着手机说话,也挺费劲 … 可以做手势 因为手机有加速度传感器器,可以识别手臂活动 观察世界,形成想法,然后实现这些想法

- 3 - Android Development 得到加速度的原始数据 仍然是 Android 的广播、接收广播结构 很多传感器类型 : TYPE_LIGHT , TYPE_PRESSURE , TYPE_TEMPERATURE… SensorManager sm = getSystemService(Context.SENSOR_SERVICE); int sensorType = Sensor.TYPE_ACCELEROMETER; sm.registerListener(myAcceListener,sm.getDefau ltSensor(sensorType),SensorManager.SENSOR_DELA Y_NORMAL); 注册侦听的函数有三个参数 : 侦听程序,侦听的传感器 ( 每种类型的传感器可能有多个,所以有缺省 ) ,设置侦 听的频率 ( 多长时间发送一次数据给侦听程序 )

- 4 - Android Development 开始写侦听程序 Android 专门定义了 SensorEventListener() 只要重载其中 onSensorChanged( 有数据来 ) 方法即可 SensorEventListener myAcceListener = new SensorEventListener(){ public void onSensorChanged(SensorEvent event){ if(event.sensor.getType() == Sensor. TYPE_ACCELEROMETER){ float X_lateral = event.values[0]; float Y_longitudinal = event.values[1]; float Z_vertical = event.values[2]; 只要将这三个轴的加速度保存在数组中就可以处理

- 5 - Android Development 有了加速度原数据以后需要进行建模 就是得到一个加速度数据序列对应的 “ 动作 ” 首先画出一个序列看一看 看出什么了 ? X,Y 变化较小, Z 有明 显的变化,说明在竖 直方向上有晃动

- 6 - Android Development 就是在竖直方向上晃动 — 我想翻 PPT 开始建模 : 用一点物理知识 … 上 ( 下 ) 翻 PPT ,就是给一个短时间向上 ( 下 ) 的力量 F=ma ,所以就是 “ 短时间内向上 ( 下 ) 的加速度 ” (1) 短时间:采样可 以记录时间, W < T 这些地方就很像 (2) 有力量:加速度 累加值大, a(W) > A W 是 一个 时间 窗口 (3) 判断方向:重力 加速度 g 总向下, a 和 g 的方向

- 7 - Android Development 我们说的力量应该滤掉重力 右边的图应该是包含了重力 TYPE_LINEAR_ACCELERATION sensorType = Sensor.TYPE_LINEAR_ACCELERATION; SDK 版本 2.3 以上 应该是有一个向上的 力  让手抬起 应该紧接着一个向下 的力  让手停下 v =  ad =  v

- 8 - Android Development 有了模型就可以给出算法了 思想 : (1) 找到一个窗口 W( 从 0 开始累加直到累加 为 0) ,即  W a = 0 ; (2) 判断这个窗口是否是短促 的发力,即  W |a|/|W| > ; (3) 判断 W 时间内的手 臂旋转角度 while(AccInt >= 0){ AccInt = AccInt + AccZ[i]; i = i+1;} EndWindow = i; d =  v for(i = StartWindow; i <= EndWindow; i++) AccPower = AccPower + abs(AccZ[i]); if AccPower / (EndWindow - StartWindow) then …

- 9 - Android Development 根据重力来判断方向 对于 Z 轴,接近 9 的重力应该是手机平放,加速度 为 0 应该是手机竖直放,此时 Y 轴的值应该为 9 sensorType = Sensor.TYPE_TYPE_GRAVITY; SDK 版本 2.3 以上 Angle = arcsin((GravityZ[StartW indow] – GravityZ[EndWindow])/9); if Angle >= 80 then 发 出向上的指令

Android Development 开始用手机控制笔记本上的 PPT 就是用网络通信给笔记本发送键盘动作 首先要解决的问题是手机和笔记本进行通信 选择通信手段 : 3G 、 Wifi 、蓝牙 Wifi 选择通信手段 : 3G 、 Wifi 、蓝牙 此处让笔记本成为 Wifi 热点 热点 (AP) (1) AP 每 100ms 广播 SSID (2) Client 收到 SSID 以后,决定是否连接 (3) 发起连接,进行 WiFi 认证,通过后完成连接的建立 (4) 一旦建立 WiFi 连接,上层的数据 (TCP/IP 层 ) 就会 用这个连接 (MAC 层、物理层 ) 进行封装发送 著名的

Android Development 列出周围开启 PPT 控制服务的 Wifi 热点 列出周围的 AP 已经搞定,用程序询问是否服务 用程序连接这些 AP( 当然密码已经记录下来 ) WifiConfiguration wCfig = new WifiConfiguration(); wCfig.SSID = "\"lizhijun\""; wCfig.preSharedKey = "\" \""; wCfig.allowedKeyManagement.set(WifiConfiguration. KeyMgmt.WPA_PSK); int nWifiID = mWifiMgr.addNetwork(wCfig); boolean bWifiCon = mWifiMgr.enableNetwork(nWifiID, true); 询问某个端口 (“7777”) ,看是否收到 Hello?

Android Development 现在可以向 7777 发起询问了 就是发起数据通信,当然就是 socket 一个 socket 应该包含 IP 地址和端口 mSocket = new Socket(ServerIP, 7777); ServerSocket srvsock = new ServerSocket(7777); while (true) { Socket sock = srvsock.accept(); 这就建立一个手机到笔记本的 TCP 连接 ( 传输控制命令 ) IP 地址应该是什么 ? 本机 IP 地址是什么 ? DHCP IP 地址应该是什么 ? 当然此处的 IP 地址是服务器的 IP ,即笔记本的 服务器要侦听这个端口 Android 网络编 程也一样

Android Development 现在关键问题是如何获得服务器 IP 可以在程序中往里敲,但是这样也太笨了 手机发起扫描周围启动 PPT 控制服务的服务器 DatagramSocket socket = new DatagramSocket(); String strPptQuery="whoispptctrl"; DatagramPacket packet = new DatagramPacket(strPptQuery.getBytes(),strPptQu ery.length(),InetAddress.getByName(" "),7778); socket.send(packet); (1) 手机广播 UDP 包,内容是 “whoispptctrl” 手机发起扫描周围启动 PPT 控制服务的服务器 (2) 服务器启动一个线程,收到上述内容后回答 “iampptctrl” 并且告诉服务器的 IP 地址

Android Development 服务器端启动线程接收 UDP 询问 定义一 implements Runnable 类,放入 Thread 每当线程调度时就会执行该 runnable 类中的 run 函数 ReceiveHelloFromPhone udpReceive = new ReceiveHelloFromPhone(); Thread udpReceiver = new Thread(udpReceive); udpReceiver.start(); DatagramSocket server=new DatagramSocket(7778); DatagramPacket packet=new DatagramPacket(buffer,); while(true){ server.receive(packet); String content = new String(packet.getData(),); InetAddress clientAddr = packet.getAddress(); if(content.equals("whoispptctrl"))

Android Development 手机在收到服务器 IP 后发起 TCP 连接 一旦建立连接就象管道 : sock.getInputStream() 直接从这个管道中 read 和 write fromClient = new ObjectInputStream(sock.getInputStream()); fromServer = new ObjectOutputStream(sock.getOutputStream()); Command cmd = (Command)fromClient.readObject(); action = cmd.getAction(); if(action == DOWN) 产生键盘动作 产生键盘动作用的是 Java 的 Robot 类,这个类可以自 动产生你的各种操作

Android Development 所以 PPT 控制就成为 手机用加速度传感器 track 用户动作;在手机上 用一点 AI 的知识和算法识别上 ( 下 ) 翻动作;手机 把这个动作通过 Wifi 发给笔记本;笔记本上的服 务器收到命令以后用 Robot 产生一个键盘指令 Command cmd = new Command(DOWN); try { fromClient.writeObject(cmd); if(action == DOWN) robot.keyPress(KeyEvent.VK_DOWN); Thread.sleep(10); robot.keyRelease(KeyEvent.VK_DOWN); 手机发送命令 Robot 产生指令

Android Development 接下来编写一个用传感器控制的小游戏 一个 3D 小球在手机屏幕上 ( 按斜面原理 ) 滚来滚去 (1) 画出 3D 游戏场景,用 openGL public GameMainView mainView; onCreate() {mainView = new GameMainView(this); setContentView(mainView); (2) 根据手机姿态计算重力在屏幕斜面上分量 (3) 让小球移动起来 首先开始 openGL (open Graphics Library) 在 Activity 中 class GameMainView extends GLSurfaceView{ public GameMainView(Context context) {

Android Development 开始 OpenGL 的渲染工作 (3D 全靠渲染 ) 依靠一个 implements Render 的类来实现 其中有个方法是 onSurfaceCreated ,画布新建时调用 class GameMainView extends GLSurfaceView{ public GameMainRender mainRender; public GameMainView(Context context) { mainRender = new GameMainRender(); setRenderer(mainRender); } class GameMainRender implements Renderer{ onSurfaceCreated(GL10 gl, EGLConfig arg1) { 在画布新建时把 3D 小球初始化画出来吗 ? 其中有个方法是 onSurfaceCreated ,画布新建时调用

Android Development 开始画一个小球 实际上 Surface 创建时做初始化 ( 如背景颜色 ) 真正用来画一个实体的函数在 onDrawFrame 中 onSurfaceCreated(GL10 gl, EGLConfig arg1) { gl.glClearColor(0,0,0,0); public void onDrawFrame(GL10 gl) { Ball ball = new Ball(); initScene(gl); ball.draw(gl); 开始创建 3D 小球 gl.glVertexPointer(3,.., 0, vertexBuffer); gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, VertexNumber); 在 draw 中 开始创建 3D 小球

Android Development 3D 对象创建实际上就是创建一堆点 for(int v = -90; v <= 90; v = v + step) { for(int h = 0; h <= 360; h = h + step) { r1 = Math.cos(v * Math.PI / 180.0); h1 = Math.sin(v * Math.PI / 180.0); r2 = Math.cos((v + step) * Math.PI / 180.0); h2 = Math.sin((v + step) * Math.PI / 180.0); co = Math.cos(h * Math.PI / 180.0); si = -Math.sin(h * Math.PI / 180.0); data[m][0] = r2 * co; data[m][1] = h2; data[m][2] = r2 * si; data[m+1][0] = r1 * co; data[m+1][1] = h1; data[m+1][2] = r1 * si; 在球面上 一顿算

Android Development 3D 渲染效果表现为很多平面的填充 for(int i=0; i < nVertexCount; i++) { vertexBuffer.put(data[i]); } vertexBuffer.position(0); gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer); gl.glNormalPointer(GL10.GL_FLOAT, 0, vertexBuffer); gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, nVertexCount); 一堆球面上的三角形, 填充后就 3D 了 initScene 用来创建光源 gl.glMaterialf(GL10.GL_FRONT_AND_ BACK, GL10.GL_SHININESS, 64.0f); 0.0f

Android Development 现在让小球滚动起来 就是旋转加上位移 首先实现旋转,一句基本函数 gl.glRotatef(angle, 0.0f, 1.0f, 0.0f); data[m][0] = r2 * co + 1f; data[m][1] = h2 + 2f; 然后实现位置移动:很简单,修改坐标即可 就会往右上角移动了 用传感器控制小球的运动 : 姿态传感器 sm = getSystemService(Context.SENSOR_SERVICE); int sensorType = Sensor.TYPE_ORIENTATION; sm.registerListener(mySensorListener,...); 旋转角度 + 旋转轴

Android Development 关于姿态传感器 Yaw( 偏航 ),Pitch( 俯仰 ),Roll( 旋转 ) TYPE_ORIENTATION 不好使,方式已过期 sensorType = Sensor.TYPE_ACCELEROMETER; sensorType = Sensor.TYPE_MAGNETIC_FIELD; 实际上 Android 的姿态是用磁力计和加速度算出来的 if(event.sensor.getType()==TYPE_MAGNETIC_FIELD) magneticFieldValues = event.values; if(event.sensor.getType()==TYPE_ACCELEROMETER) accelerometerValues = event.values; controlByOrientation(); 然后注册 Listener 在 onSensorChanged 中

Android Development 获得俯仰角和旋转角并控制小球 用 getRotationMatrix 得到旋转数组,用来存放 磁场和加速度的数据,获得姿态时要用 float[] values = new float[3]; float[] R = new float[9]; sm.getRotationMatrix(R, null, accelerometerValues, magneticFieldValues); sm.getOrientation(R, values); 根据 P 角决定 Y 轴上的移动量, … 存放姿态数据,依 次是 Y,P,R V x (t) = V x (t-1) + G x (t-1)  t  S x (t) = V x (t-1)  t + G x (t-1)  t 2 /2 G x (t) = G  sin(R) G = 9.8  t = 1 onDrawFrame 会时 调用,要 gl.glClear (GL10.GL_COLOR_ BUFFER_BIT);