Posts Tagged ‘BeiTown’
【Unity3D】关于Vector3向量与Quaternion四元数的转换与应用
星期二, 四月 7th, 2015 3,652 views在Unity中大家对Vector3应该说是很熟悉了,这里就简单带过一下,Vector3表示一个三维向量(x,y,z),例如Vector3.forward等价于new Vectory(0,0,1),即x=0,y=0,z=1的一个向量。图就不画了,大家高中都学过。
而Quaternion表示一个四元数,何为四元数,例如ai+bj+ck+d这样一个超复数,篇幅有限高数这里也不多说了,我们只关注一下Unity的四元数类的使用就好。在Unity中Quaternion(四元数类)主要用来处理物体的旋转,其实数变量由x,y,z,w四个参数构成,区间[-1,1]。
例如绕y轴旋转180°写做(0,1,0,0),调用公式计算过程如下:
由欧拉旋转(X,Y,Z)转换为四元数(x,y,z,w)
—————————————————->
x = sin(Y/2)sin(Z/2)cos(X/2)+cos(Y/2)cos(Z/2)sin(X/2)
y = sin(Y/2)cos(Z/2)cos(X/2)+cos(Y/2)sin(Z/2)sin(X/2)
z = cos(Y/2)sin(Z/2)cos(X/2)-sin(Y/2)cos(Z/2)sin(X/2)
w = cos(Y/2)cos(Z/2)cos(X/2)-sin(Y/2)sin(Z/2)sin(X/2)
q = (x, y, z, w)
—————————————————->
X = 0
Y = 180
Z = 0
—————————————————->
x = 0
y = 1
z = 0
w = 0
在Unity中这一套转换可以直接调用方法Quaternion.Euler(0, 180, 0)或者transform.Rotate(0, 180, 0)完成。euler即欧拉角的意思,欧拉角可以用Vector进行表示,表示在x,y,z三轴上的旋转角度。
同时transform.rotation即是一个四元数,表示物体的旋转角度方向,我们可以通过Quaternion.Euler和Quaternion.eulerAngles(但这个方法在Unity4之后的版本已经过时)将欧拉角转换为四元数。
因此假设需要让一个物体的顺时针方向以y轴旋转90°有以下几种方法:
1 2 3 4 5 6 7 8 |
以上方法均可在一帧之内旋转顺时针绕y轴旋转90°。但通常游戏中有一个缓慢转动的过程,如果需要一步到位,而是慢慢旋转到90°应该如何去做呢。我们可以使用以下方法:
1 2 3 4 5 | //使用四元数的球形差值方法 在每一帧中调整与目标四元数的差值 transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(new Vector3(1, 0, 0)), 10 * Time.deltaTime); //使用Vector3的RotateTowards方法将一个向量转向另一个向量 transform.rotation = Quaternion.LookRotation(Vector3.RotateTowards(transform.forward, new Vector3(1, 0, 0), Time.deltaTime, Time.deltaTime)); |
从理论上来说球形差值Quaternion.Slerp的转向要平滑一些但相应的运算量大,每一帧都在出现误差值所以每一帧都在校调,而RotateTowards的方法要简洁但粗暴一些,但转向的平滑性不如前者好,特别是在多方向同时操作上,会出现一些不平滑的问题。
综上,建议在设计转向模块的时候,保留两种方案,在实际操作中对比两种方案的显示效果,择优选用。
本篇到此,欢迎大家补充新的方法,用以达到以上两端代码块同样的效果。
BeiTown
2015.04.07
QT拖拽文件、文件夹及遍历文件夹简单案例
星期五, 九月 19th, 2014 136 views首先是实现QT的窗体拖拽功能将文件拖拽进入Mainwindow,需要实现代码如下:
1 2 3 4 5 6 7 | MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); setAcceptDrops(true);//将Mainwindow设置成可相应拖拽事件 } |
这里的 setAcceptDrops(true); 将Mainwindow设置成可相应拖拽事件,接下来,重载dragEnterEvent和dropEvent方法,实现对拖拽内容的判断和操作,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | //拖入Mainwindow时触发 void MainWindow::dragEnterEvent(QDragEnterEvent *event){ if(event->mimeData()->hasUrls()) { foreach(QUrl url, event->mimeData()->urls()) { if(!url.isEmpty()) event->accept();//界面反馈表示可拖拽 } return; } else { event->ignore();//界面反馈表示不可拖拽 } } //松开鼠标后触发 void MainWindow::dropEvent(QDropEvent *event) { if(event->mimeData()->hasUrls()) { foreach(QUrl url, event->mimeData()->urls()) { QFileInfo fileInfo(url.toString()); QString filePath = fileInfo.filePath().remove(0, QDir::currentPath().size() + 9); if(fileInfo.fileName().contains(".")){//根据是否带"."判断是否是文件夹 //属于文件 }else{ //属于文件夹 FindFile(filePath);//遍历文件夹递归函数 } } return; } return; } |
QT实现启动画面
星期三, 九月 10th, 2014 35 views代码如下,详解见注释,效果请自行编译运行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | #include "mainwindow.h" #include <QApplication> #include <QSplashScreen> #include <QPixmap> #include <QTextCodec> #include <QElapsedTimer> int main(int argc, char *argv[]) { QApplication a(argc, argv); QTextCodec *codec = QTextCodec::codecForName("UTF-8"); QTextCodec::setCodecForLocale(codec); QSplashScreen splash(QPixmap("./images/logo.png")); splash.setDisabled(true); //禁用用户的输入事件响应 否则点击会消失 splash.show(); splash.showMessage(QString::fromUtf8("检测版本信息中..."), Qt::AlignCenter|Qt::AlignBottom,Qt::black); //实现延时2s int delayTime = 2; QElapsedTimer timer; timer.start(); while(timer.elapsed() < (delayTime * 1000)) { a.processEvents(); } MainWindow w; splash.finish(&w);//关闭启动画面 w.show(); return a.exec(); } |
BeiTown
2014.09.10
QWebView保存帐号密码功能实现
星期三, 八月 13th, 2014 238 views以下用QT模拟一下常规浏览器对帐号密码的保存
首先是获取QWebview中的表单内容,需要保存的表单中的两个input如下:
在QT中获取这两个input的值的需要使用带JS的方法,首先通过findFirstElement()方法找到目标标签,然后调用js方法获取其值,如下:
1 2 3 | //获取帐号密码 qDebug()< <ui->webView->page()->mainFrame()->findFirstElement("#username").evaluateJavaScript("this.value").toString(); qDebug()< <ui->webView->page()->mainFrame()->findFirstElement("#password").evaluateJavaScript("this.value").toString(); |
具体在何处调用以上方法视应用设计的情况而定,这里我使用了QWebview::loadStarted()信号来触发,因为提交表单时必会触发这个信号。
(更多…)
QT使用单例模式获取主窗体Mainwindow指针
星期二, 七月 22nd, 2014 220 views最近一直在用QT做项目,信号和槽机制甚是好用,但是前提需求是在connect时必须同时传入Object1和Object2的指针(见《QT 多线程(UI线程)间的signal/slot(信号与槽)通信》),这样一来,我们如果需要在其他类中绑定Mainwindow的槽函数,则必须在该类初始化时传入Mainwindow的指针,甚是麻烦。甚至有时是间隔了好几个类。
查询了网络上的一些方法,稍微可行一些的是使用parentWidget()方法,但是还是没有从根本上解决全局获取Mainwindow指针的问题。
既然是全局,我们的基本解决思路就是static化,实现起来其实也非常简单,使Mainwindow变成单例即可,代码如下:
首先是Mainwindow.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | #ifndef MAINWINDOW_H #define MAINWINDOW_H #include <qmainwindow> namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT public: static MainWindow *GetInstance();//获取单例方法 private: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); Ui::MainWindow *ui; static MainWindow *m_pInstance;//单例指针 }; #endif // MAINWINDOW_H </qmainwindow> |
QT5读取及修改cookie简单样例
星期四, 七月 3rd, 2014 334 views介于网上(中文网页)没有一篇完整的关于QT5读写cookie的简单案例,特有此篇。
①准备工作,定义cookie控制器
在开始获取cookie之前我们需要做一些准备工作,先在mainwindow下拖出一个webview,这里不上图了,以后会比较少上图,有些图华而不实,文字看得懂的自然都看得懂。
之后给这个webview定义一个networkAccessManager,#include什么的这些常识问题大家自己F1。
1 2 3 4 5 6 7 8 9 10 | MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); _cookieJar = new MyCookieJar(); //这里设置networkAccessManager ui->webView->page()->networkAccessManager()->setCookieJar( _cookieJar ); } |
上文中的_cookieJar是我们自己定义的一个MyCookieJar类,继承了QT自带的QNetworkCookieJar。
这里我自己封装了一些方法也放出来吧:
MyCookieJar.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | #ifndef MYCOOKIEJAR_H #define MYCOOKIEJAR_H #include <qnetworkcookiejar> #include <qnetworkcookie> #include <qnetworkrequest> class MyCookieJar : public QNetworkCookieJar { Q_OBJECT public: explicit MyCookieJar(QObject *parent = 0); QList<qnetworkcookie> getCookies(); void setCookies(const QList</qnetworkcookie><qnetworkcookie>& cookieList); void addCookies(QString name,QString value); void changeCookie(QString name,QString value); }; #endif // MYCOOKIEJAR_H </qnetworkcookie></qnetworkrequest></qnetworkcookie></qnetworkcookiejar> |
MyCookieJar.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | #include "mycookiejar.h" MyCookieJar::MyCookieJar(QObject *parent) : QNetworkCookieJar(parent) { } QList<qnetworkcookie> MyCookieJar::getCookies() { return this->allCookies(); } void MyCookieJar::setCookies(const QList</qnetworkcookie><qnetworkcookie>& cookieList) { if(this == NULL) return; this->setAllCookies(cookieList); } void MyCookieJar::addCookies(QString name,QString value) { QNetworkCookie cookie(name.toUtf8(),value.toUtf8()); this->insertCookie(cookie); } void MyCookieJar::changeCookie(QString name,QString value) { QNetworkCookie cookie(name.toUtf8(),value.toUtf8()); this->updateCookie(cookie); } </qnetworkcookie> |
Redis异常JedisConnectionException:Read timed out解决笔记
星期三, 六月 25th, 2014 21,504 views笔记①
异常如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | redis.clients.jedis.exceptions.JedisConnectionException: java.net.SocketTimeoutException: Read timed out at redis.clients.jedis.Protocol.process(Protocol.java:131) at redis.clients.jedis.Protocol.read(Protocol.java:187) at redis.clients.jedis.Connection.getIntegerReply(Connection.java:200) at redis.clients.jedis.BinaryJedis.incrBy(BinaryJedis.java:633) at java.util.TimerThread.mainLoop(Unknown Source) at java.util.TimerThread.run(Unknown Source) Caused by: java.net.SocketTimeoutException: Read timed out at java.net.SocketInputStream.socketRead0(Native Method) at java.net.SocketInputStream.read(Unknown Source) at java.net.SocketInputStream.read(Unknown Source) at java.net.SocketInputStream.read(Unknown Source) at redis.clients.util.RedisInputStream.fill(RedisInputStream.java:109) at redis.clients.util.RedisInputStream.readByte(RedisInputStream.java:45) at redis.clients.jedis.Protocol.process(Protocol.java:116) ... 8 more |
在服务器运行中突发异常,当时对Redis的操作并不频繁,大概一分钟一次的写数据,初步分析排除了资源竞争照成的Redis超时异常。
之后ping -t 远程Redis主机,发现当出现Read timed out异常时经常伴有ping超时情况,初步判定为网络不稳定照成。
临时解决办法是在new JedisPool(config, host, port, timeout) 初始化时,将timeout设置成更大的值(默认是2000)以便应对极端网络情况下的读取流异常情况。更进一步的分析还有待发掘,本篇未完待续。
笔记②
之前Read timed out的异常并未在修改了配置文件后有太大的改善,在外网环境下,当用户基数增长到一定量级时,再次出现Read timed out异常。
这种现象太容易让服务端程序将焦点集中在Redis的并发处理能力及连接池数量上,因此特意打印了Redis的慢查询日志,发现并无明显异常,之后观察了Redis的连接数,也不过几十个client而已,并未超过设置上限,在Jedis方面,按照网上其他朋友的建议修改了maxIdle、maxActive和maxWait的值,但问题依旧。
因此开始将排查重点放到了网络底层上,检查了与Redis主机的线路ping值,出现Read timed out的时候,并未出现延迟情况,网络ping值一直<1ms。
继续观察,这个时候注意到偶尔出现了带宽峰值突破30MB/s的情况,多亏了服务器上开启的流量监控浮动,否则很难捕捉到这一瞬间。
通过与机房确认,确定两台机器走的是外网IP,因此访问Redis时走的带宽为外网带宽,那么势必会受到机房防火墙的限制,因此出现了Jedis无法读取到后续数据流的问题。
找到根源之后,问题就很好解决了,在业务机与Redis服务器上各加了一块千兆网卡,通过内网进行直连。重新开机,导用户,测试,加大用户量,一切正常。同时实时流量显示最高峰值达到了100MB/s。
因为Redis是基于TCP连接的,而海量的数据反复交互相当于远程读写内存的操作,势必会造成带宽的使用紧张,那么在带宽吃紧的情况下,Redis客户端即Jedis拿不到连接或拿不到后续数据包也是很正常的了。
但考虑到峰值交互量有点高的可怕,针对这一问题,对并发交互数据的频率进行调整,对数据量进行精减才是解决这一问题的最佳方案。
关于redis.clients.jedis.exceptions.JedisConnectionException: java.net.SocketTimeoutException: Read timed out的这一问题我们暂且解决到这里,目前暂未再次出现。
大家如果遇到此类问题,在修改Jedis参数的情况下依旧无法解决,可以考虑一下是否是硬件及网络问题造成的。
本篇到此,欢迎交流讨论。谢谢。
Beitown
2015.04.07
在IE8下DIV margin:0 auto不居中的解决办法
星期四, 六月 5th, 2014 25 viewsRT,用<center>标签完美解决
1 2 3 4 5 6 7 8 9 |
BeiTown
2014-06-05
Java正则表达式取目标字符串简单范例
星期二, 六月 3rd, 2014 111 views本篇只讲述JAVA正则表达式类java.util.regex的取字符串的使用方法,关于正则表达式的语法及使用不在本篇的描述之中,若有需要可参看《正则表达式30分钟入门教程》。
首先做完范例需要一个待解析字符串,这里顺带把最近一个项目中的jdbcUrl拿来解析好了,字符串如下
1 | jdbc:mysql://127.0.0.1:3306/test |
这里说下目标需求,即把这段jdbcUrl分解成IP(127.0.0.1)、端口号(3306)以及数据库名(test),现将Java中的操作分为以下几步:
①书写正则表达式
正则表达式分别如下:
IP:(?<=//).*(?=:)取”//”和” :”之间的内容
PORT:(?<=\d:).*(?=/)取”数字+:”和” /”之间的内容
DBNAME:(?<=\d/).*”)取”数字+/”后面的内容
这里用正则表达式测试工具可以实时看到效果。
(更多…)
Eclipse可视化UI插件WindowBuilder的安装和使用
星期六, 五月 31st, 2014 116 views①安装
以Eclipse 4.4 Luna为例
In Eclipse:
Goto – Menu > Help > Install New Software…
Select – Work With: Luna – http://download.eclipse.org/releases/luna
The WindowBuilder items are under “General Purpose Tools” (or use the filter)
(以上摘自stackoverflow.com)
上述方法在安装前需要安装Swt Designer。
或者直接下载插件包http://ftp.osuosl.org/pub/eclipse/windowbuilder/WB/release/R201309271200/
安装完成后重启Eclipse即可。
②新建窗体
在New→Other中如图