论如何在没有压感屏幕的手机上实现压力感应
_THIS_IS_START_OF_ARTICLE_
_THIS_IS_END_OF_ARTICLE_
------------------------------------------------------------------
这几天闲的没事玩谷歌手写输入的时候突然get到了在普通手机上实现压力感应的方法...
于是用Qt quick写了个demo来玩
具体来说是一个小游戏
一个弹幕射击游戏
界面大概就像下面这样
丶、
(上图依据按压力度不同的三种自机弹幕(蓝色的),第一张是轻按,第二张是重按,第三张是手指抬起来然后重按)
效果嘛...我感觉还可以,不过毕竟不是真正的压力感应...勉强还能用吧...
------------------------------------------------------------------
原理吧...其实很简单...
就是把按压面积当做压力
嗯...没了...
因为人的手指是软绵绵的,所以按压力度越大按压面积就越大
本来我也以为可能效果不会很明显的,结果这样做出来竟然意外地好用...
参数的话...我是用自己的手指测的...重按和轻按的分界线大概是3000像素的样子
不过不同的人手指长得不一样,惯用的触摸方法可能也不一样,所以参数可能不同...所以真要用这个原理去做软件的话加一个压力校准环节比较好...(可以,比如说多次采样,然后枚举分界线,使得重按和轻按落在各自区间内的频率都在某个值以上,或者如果这样行不通的话就干脆直接把平均值的平均值当做分界线应该也不差...<-纯属YY,我自己没试过...,我是多次采样然后目测的分界线...)
------------------------------------------------------------------
代码放这里好了:(对QML和ECMAScript不是很熟悉 很不熟悉 完全不会,写得非常丑,有大神看到的话求轻喷)
main.cpp:
#include <QGuiApplication> #include <QQmlApplicationEngine> void do_befo(int a,char * b[]) { QGuiApplication app(a,b); QQmlApplicationEngine engine; engine.load(QUrl(QStringLiteral("qrc:///game_befo.qml"))); app.exec(); } void do_game(int a,char * b[]) { QGuiApplication app(a,b); QQmlApplicationEngine engine; engine.load(QUrl(QStringLiteral("qrc:///game_main.qml"))); app.exec(); } int main(int argc, char *argv[]) { do_befo(argc,argv); do_game(argc,argv); return 0; }
game_befo.qml(这个博客似乎不兹磁qml...所以语法就选的XML,高亮可能会怪怪的...)
import QtQuick 2.2 import QtQuick.Window 2.1 Window { visible: true; width: Screen.desktopAvailableWidth; //1080 height: Screen.desktopAvailableHeight; //1860 id: root; Text { x: 0; y: 0; text: "背景故事和操作" font.pixelSize: 100; } Text { id: tex1; visible: false; x: 0; y: 100; text: "1999年12月,地球人与萨比星人\n的战斗已经进入尾声,作为地球\n先锋部队的成员,你被指派前往\n萨比星人的老巢,给予他们最后的一击..." font.pixelSize: 50; } Text { id: tex2; visible: false; x: 0; y: 350; text: "历经千辛万苦,你终于扫除了杂兵\n,当你驾驶飞船来到萨比星人\n的头领的房间,你发现所谓的\n最终boss竟然是..." font.pixelSize: 50; } Text { id: tex3; visible: false; x: 0; y: 600; text: "YYY!" font.pixelSize: 50; } Text { id: tex4; visible: false; x: 0; y: 650; text: "操作方法:滑动手指来移动自机,躲开\nYYY的攻击,重按屏幕以发\n射不同类型的子弹,使劲点屏幕\n以释放boom(你敢一直放\nboom,你的手机就敢死机)" font.pixelSize: 50; } Text { id: tex5; x: 0; y: root.height - 50; text: "轻触屏幕继续..." font.pixelSize: 50; } MultiPointTouchArea { anchors.fill: parent; touchPoints: [ TouchPoint { id: you_touch; } ] onPressed: { if(tex1.visible == false) tex1.visible = true; else if(tex2.visible == false) tex2.visible = true; else if(tex3.visible == false) tex3.visible = true; else if(tex4.visible == false) { tex4.visible = true; tex5.text = "轻触屏幕以开始游戏" } else Qt.quit(); } } }
game_main.qml:
import QtQuick 2.2 import QtQuick.Window 2.1 Window { visible: true; width: Screen.desktopAvailableWidth; //1080 height: Screen.desktopAvailableHeight; //1860 property double lim1: 3000.; property double lim2: 3000.; id: root; property int but_r: 20; property variant but_x : []; property variant but_y : []; property variant but_ang : []; property variant but_step : []; property variant but_bel : []; //true : yyy false : you Canvas { id: drawer; anchors.fill: parent; contextType: "2d"; onPaint: { var ctx = getContext("2d"); ctx.lineWidth = 1; ctx.strokeStyle = "white"; ctx.fillStyle = "white"; ctx.beginPath(); ctx.moveTo(0,0); ctx.lineTo(root.width,0 ); ctx.lineTo(root.width , root.height); ctx.lineTo(0 , root.height); ctx.closePath(); ctx.fill(); ctx.stroke(); ctx.save(); for(var i = 0;i < but_x.length;i++) { if(root.but_bel[i] == true) ctx.fillStyle = "black"; else ctx.fillStyle = "blue"; ctx.beginPath(); ctx.arc(root.but_x[i] , root.but_y[i] , root.but_r , 0 , Math.PI*2); ctx.fill(); ctx.restore(); } } } function push_a_but(x,y,ang,stp,bel) { var dyn = root.but_x; dyn.push(x); root.but_x = dyn; dyn = root.but_y; dyn.push(y); root.but_y = dyn; dyn = root.but_ang; dyn.push(ang); root.but_ang = dyn; dyn = root.but_step; dyn.push(stp); root.but_step = dyn; dyn = root.but_bel; dyn.push(bel); root.but_bel = dyn; } Rectangle { property int hp_max: 6; property int hp: hp_max; property int len: 50; x: parent.width / 2. - len / 2; y: 2. * parent.height / 3.; width: len; height: len; radius: len / 2; color: "gray"; id: you_bar; Text { anchors.centerIn: parent; text: "你"; color: "white" font.pixelSize: parent.len - 5; } property int but_sped: 30; property int but_inte: 300; Timer { id: you_biu_1; running: true; interval: you_bar.but_inte; repeat: true; onTriggered: { var xx = you_bar.x + + you_bar.len / 2; var yy = you_bar.y + + you_bar.len / 2; push_a_but(xx - 1.5 * root.but_r,yy,1.5 * Math.PI,you_bar.but_sped,false) push_a_but(xx + 1.5 * root.but_r,yy,1.5 * Math.PI,you_bar.but_sped,false) } } Timer { id: you_biu_2; running: false; interval: you_bar.but_inte; repeat: true; onTriggered: { var xx = you_bar.x + + you_bar.len / 2; var yy = you_bar.y + + you_bar.len / 2; push_a_but(xx,yy,1.25 * Math.PI,you_bar.but_sped,false) push_a_but(xx,yy,1.5 * Math.PI,you_bar.but_sped,false) push_a_but(xx,yy,1.75 * Math.PI,you_bar.but_sped,false) } } function boom() { var xx = you_bar.x + + you_bar.len / 2; var yy = you_bar.y + + you_bar.len / 2; var r = root.but_r * 3; for(var i = 0;i < 4;i++) { for(var j = 0;j < 10;j++) push_a_but(xx - r * (i-2),yy - r * j,1.5 * Math.PI,you_bar.but_sped / 4,false) } yyy_bar.hp -= 50; if(yyy_bar.hp <= 0) { you_win.visible = true; you_win_tex.visible = true; you_win_tim.running = true; } } } Rectangle { property int len: 120; property int hp_max: 1000; property int hp: hp_max; x: parent.width / 2.; y: parent.height / 3.; width: len; height: len; radius: len / 2; color: "gray"; id: yyy_bar; Text { anchors.centerIn: parent; text: "YYY"; color: "white" font.pixelSize: 30; } property int step: 100; property int move_interval: 100; property int do_move_interval: 1; Timer { property int cnt: 0; property int call: 0; id: move_up; running: false; repeat: true; interval: yyy_bar.do_move_interval; onCallChanged: { running = true; cnt = yyy_bar.step; } onTriggered: { cnt --; yyy_bar.y --; if(cnt == 0) running = false; } } Timer { property int cnt: 0; property int call: 0; id: move_down; running: false; repeat: true; interval: yyy_bar.do_move_interval; onCallChanged: { running = true; cnt = yyy_bar.step; } onTriggered: { cnt --; yyy_bar.y ++; if(cnt == 0) running = false; } } Timer { property int cnt: 0; property int call: 0; id: move_left; running: false; repeat: true; interval: yyy_bar.do_move_interval; onCallChanged: { running = true; cnt = yyy_bar.step; } onTriggered: { cnt --; yyy_bar.x --; if(cnt == 0) running = false; } } Timer { property int cnt: 0; property int call: 0; id: move_right; running: false; repeat: true; interval: yyy_bar.do_move_interval; onCallChanged: { running = true; cnt = yyy_bar.step; } onTriggered: { cnt --; yyy_bar.x ++; if(cnt == 0) running = false; } } Timer { id: yyy_biu; running: true; repeat: true; interval: 1000; onTriggered: { for(var ang = 0;ang < 2 * Math.PI;ang += (Math.PI / 4)) root.push_a_but(parent.x + yyy_bar.len / 2,parent.y + yyy_bar.len / 2,ang,10,true) } } Timer { running: true; repeat: true; triggeredOnStart: true; interval: yyy_bar.move_interval; onTriggered: { var way = 0; while(true) { way = Math.floor(Math.random() * 4); var new_x = parent.x; var new_y = parent.y; if(way == 0) new_x += parent.step; else if(way == 1) new_x -= parent.step; else if(way == 2) new_y += parent.step; else if(way == 3) new_y -= parent.step; if(new_x >= 0 && new_x <= root.width - parent.width && new_y >= 0 && new_y <= root.height - parent.height) break; } if(way == 0) move_right.call ++; if(way == 1) move_left.call ++; if(way == 2) move_down.call ++; if(way == 3) move_up.call ++; } } } property int font_size: 50; Text { function get_string() { var a = "YYY Hp : "; a += yyy_bar.hp.toString(); return a; } id: yyy_hp_show; x: 0; y: 0; text: get_string(); color: "black"; font.pixelSize: root.font_size; } Text { function get_string() { var a = "You Hp : "; a += you_bar.hp.toString(); return a; } id: you_hp_show; x: 0; y: root.height - root.font_size; text: get_string(); color: "black"; font.pixelSize: root.font_size; } MultiPointTouchArea { anchors.fill: parent; property int now_x : 0; property int now_y : 0; property int now_bx : 0; property int now_by : 0; touchPoints: [ TouchPoint { id: you_touch; } ] onPressed: { var now_press = you_touch.area.height * you_touch.area.width; now_x = you_touch.x; now_y = you_touch.y; now_bx = you_bar.x; now_by = you_bar.y; if(now_press > root.lim2) you_bar.boom(); } onUpdated: { var now_press = you_touch.area.height * you_touch.area.width; if(now_press <= root.lim1) { you_biu_1.running = true; you_biu_2.running = false; } else { you_biu_1.running = false; you_biu_2.running = true; } you_bar.x = now_bx + (you_touch.x - now_x); you_bar.y = now_by + (you_touch.y - now_y); } } Rectangle { id: you_die; visible: false; anchors.fill: parent; Text { id: you_die_tex; visible: false; anchors.fill: parent; text: "You Die." font.pixelSize: 100; } Timer { id: you_die_tim; running: false; interval: 3000; onTriggered: { Qt.quit(); } } } Rectangle { id: you_win; visible: false; anchors.fill: parent; Text { id: you_win_tex; visible: false; anchors.fill: parent; text: "You Win." font.pixelSize: 100; } Timer { id: you_win_tim; running: false; interval: 3000; onTriggered: { Qt.quit(); } } } Timer { function dis(x1,y1,x2,y2) { return Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)) } id: deal_buts; running: true; interval: 50; repeat: true; onTriggered: { var but_x = root.but_x; var but_y = root.but_y; var but_ang = root.but_ang; var but_step = root.but_step; var but_bel = root.but_bel; var del = []; for(var i = 0;i < but_x.length;i++) { but_x[i] += but_step[i] * Math.cos(but_ang[i]); but_y[i] += but_step[i] * Math.sin(but_ang[i]); if(but_bel[i]) { if(dis(root.but_x[i],root.but_y[i],you_bar.x + you_bar.len / 2,you_bar.y + you_bar.len / 2) <= root.but_r + you_bar.radius) { you_bar.hp --; if(you_bar.hp <= 0) { you_die.visible = true; you_die_tex.visible = true; you_die_tim.running = true; yyy_bar.hp = 9999; } del[i] = true; } } else { if(dis(root.but_x[i],root.but_y[i],yyy_bar.x + yyy_bar.len / 2,yyy_bar.y + yyy_bar.len / 2) <= root.but_r + yyy_bar.radius) { yyy_bar.hp --; if(yyy_bar.hp <= 0) { you_win.visible = true; you_win_tex.visible = true; you_win_tim.running = true; } del[i] = true; } } if(but_x[i] <= 0 || but_x[i] >= root.width || but_y[i] <= 0 || but_y[i] >= root.height) del[i] = true; } var _but_x = []; var _but_y = []; var _but_ang = []; var _but_step = []; var _but_bel = []; for(var i = 0;i < but_x.length;i++) { if(!del[i]) { _but_x.push(but_x[i]); _but_y.push(but_y[i]); _but_ang.push(but_ang[i]); _but_step.push(but_step[i]); _but_bel.push(but_bel[i]); } } root.but_x = _but_x; root.but_y = _but_y; root.but_ang = _but_ang; root.but_step = _but_step; root.but_bel = _but_bel; drawer.requestPaint(); } } }
------------------------------------------------------------------
2017年2月09日 20:21
强强强!
2017年2月10日 01:22
@zrq: 哪里有琦爷的万分之一强
2017年2月11日 18:17
@YYY:yyy的强大又怎是窝们这些菜鸡能够比的qwq
2017年3月30日 13:25
不上课没事来%yyy