代码一
for循环没有{}大括号(花括号),在for语句下面是一条语句。
for(var i=0;i<3;i++) console.log(1,i); 上面的代码能无误输出:
1 0
1 1
1 2
代码二
那么,如果没有花括号的for循环下有多行语句呢?
for(var i=0;i<3;i++) console.log(1,i); console.log(2) 输出:
1 0
1 1
1 2
2
他不会把第二行也循环。
代码三
for(var i=0;i<3;i++) console.log(1,i);console.log(2) console.log(3) 如果for循环下有多条语句和多行语句呢?
1 0
1 1
1 2
2
3
只执行了第一条语句。
if if(true)console.log(1) console.log(2) //1 //2 if(false)console.log(1) console.log(2) //2 很明显,if也是如此的。
while while(true)console.log(1) 执行那一瞬间,我就尴尬了。
结论:
在绝大多数编程语言中,如果if、for、while等语句的内容中仅有一条语句,可以省略花括号。
注意:是一条语句,不是一行。
比如js用分号;表示一条语句,所以上面的例子中,虽然两条语句在同一行,但只循环了前面一条语句。
转载于:https://www.cnblogs.com/daysme/p/6287585.html
使用mysql启动时,提示了一个错误!
High Severity Error
Unhandled Exception
Root element is missing.
点击show details按钮显示
at System.Xml.XmlTextReaderImpl.Throw(Exception e)
at System.Xml.XmlTextReaderImpl.ParseDocumentContent()
at System.Xml.XmlTextReaderImpl.Read()
at System.Xml.XmlTextReader.Read()
at System.Xml.XmlReader.MoveToContent()
at System.Xml.XmlReader.ReadStartElement(String name)
at MySQL.Utility.Classes.CustomSettingsProvider.GetPropertyValues(SettingsContext context, SettingsPropertyCollection collection)
at System.Configuration.SettingsBase.GetPropertiesFromProvider(SettingsProvider provider)
at System.Configuration.SettingsBase.GetPropertyValueByName(String propertyName)
at System.Configuration.SettingsBase.get_Item(String propertyName)
at System.Configuration.ApplicationSettingsBase.GetPropertyValue(String propertyName)
at System.Configuration.ApplicationSettingsBase.get_Item(String propertyName)
at MySql.Notifier.Properties.Settings.get_AutoAddPattern()
at MySql.Notifier.Classes.Program.ChangeAutoAddPatternDefaultValue()
at MySql.Notifier.Classes.Program.Main(String[] args)
原因我不清楚
解决办法是:删除C:\Users\Administrator\AppData\Roaming\Oracle\MySQL Notifier文件夹的所有文件,重新启动就好了
参考:java核心技术
一、Java泛型的实现方法:类型擦除 前面已经说了,Java的泛型是伪泛型。为什么说Java的泛型是伪泛型呢?因为,在编译期间,所有的泛型信息都会被擦除掉。正确理解泛型概念的首要前提是理解类型擦出(type erasure)。
Java中的泛型基本上都是在编译器这个层次来实现的。在生成的Java字节码中是不包含泛型中的类型信息的。使用泛型的时候加上的类型参数,会在编译器在编译的时候去掉。这个过程就称为类型擦除。
如在代码中定义的List<object>和List<String>等类型,在编译后都会编程List。JVM看到的只是List,而由泛型附加的类型信息对JVM来说是不可见的。Java编译器会在编译时尽可能的发现可能出错的地方,但是仍然无法避免在运行时刻出现类型转换异常的情况。类型擦除也是Java的泛型实现方法与C++模版机制实现方式之间的重要区别。
可以通过两个简单的例子,来证明java泛型的类型擦除。 例1、
[java] view plain copy public class Test4 { public static void main(String[] args) { ArrayList<String> arrayList1=new ArrayList<String>(); arrayList1.add("abc"); ArrayList<Integer> arrayList2=new ArrayList<Integer>(); arrayList2.add(123); System.out.println(arrayList1.getClass()==arrayList2.getClass()); } } 在这个例子中,我们定义了两个ArrayList数组,不过一个是ArrayList<String>泛型类型,只能存储字符串。一个是ArrayList<Integer>泛型类型,只能存储整形。最后,我们通过arrayList1对象和arrayList2对象的getClass方法获取它们的类的信息,最后发现结果为true。说明泛型类型String和Integer都被擦除掉了,只剩下了 原始类型 。 例2、
[java] view plain copy public class Test4 { public static void main(String[] args) throws IllegalArgumentException, SecurityException, IllegalAccessException, InvocationTargetException, NoSuchMethodException { ArrayList<Integer> arrayList3=new ArrayList<Integer>(); arrayList3.add(1);//这样调用add方法只能存储整形,因为泛型类型的实例为Integer arrayList3.getClass().getMethod("add", Object.class).invoke(arrayList3, "asd"); for (int i=0;i<arrayList3.size();i++) { System.out.println(arrayList3.get(i)); } } 在程序中定义了一个ArrayList泛型类型实例化为Integer的对象,如果直接调用add方法,那么只能存储整形的数据。不过当我们利用反射调用add方法的时候,却可以存储字符串。这说明了Integer泛型实例在编译之后被擦除了,只保留了 原始类型 。 二、类型擦除后保留的原始类型 在上面,两次提到了原始类型,什么是原始类型?原始类型(raw type)就是擦除去了泛型信息,最后在字节码中的类型变量的真正类型。无论何时定义一个泛型类型,相应的原始类型都会被自动地提供。类型变量被擦除(crased),并使用其限定类型(无限定的变量用Object)替换。 例3:
【原创】vagrant up 异常报错,出现 There was an error while executing `VBoxManage` 的解决方法 最近在使用 vagrant homestead 时,不小心在虚拟机上使用了 exit 命令退出虚拟机,导致再使用 vagrant up 时出现以下错误:
Bringing machine 'laravel53test' up with 'virtualbox' provider... ==> laravel53test: Checking if box 'laravel/homestead' is up to date... ==> laravel53test: Clearing any previously set forwarded ports... There was an error while executing `VBoxManage`, a CLI used by Vagrant for controlling VirtualBox. The command and stderr is shown below. Command: ["modifyvm", "
between de的英语意思是介于两者之间,在sql中的意思是两个值之间的数据范围。这些值可以是数值、文本或者日期。与and 一起使用
例句1:(筛选出一张表中以某个字段两个值之间的数据范围)
select * from tab1 where name between value1 and value2 (筛选出的条件中包括value1,但是不包括vaule2,也就是说并不是包括两个边界值,(sql server))
例句2:(筛选出一张表中以某个字段两个值之间的除外的数据范围,在条件中加not)
select * from tab1 where name not between value1 and value2
一、LibCurl基本编程框架 libcurl是一个跨平台的网络协议库,支持http, https, ftp, gopher, telnet, dict, file, 和ldap 协议。libcurl同样支持HTTPS证书授权,HTTP POST, HTTP PUT, FTP 上传, HTTP基本表单上传,代理,cookies,和用户认证。想要知道更多关于libcurl的介绍,可以到官网 http://curl.haxx.se/上去了解,在这里不再详述。 win32版的libcurl下载地址:http://curl.freeby.pctools.cl/download/libcurl-7.18.0-win32-msvc.zip 在基于LibCurl的程序里,主要采用callback function (回调函数)的形式完成传输任务,用户在启动传输前设置好各类参数和回调函数,当满足条件时libcurl将调用用户的回调函数实现特定功能。下面是利用libcurl完成传输任务的流程: 1. 调用curl_global_init()初始化libcurl 2. 调用curl_easy_init()函数得到 easy interface型指针 3. 调用curl_easy_setopt()设置传输选项 4. 根据curl_easy_setopt()设置的传输选项,实现回调函数以完成用户特定任务 5. 调用curl_easy_perform()函数完成传输任务 6. 调用curl_easy_cleanup()释放内存 在整过过程中设置curl_easy_setopt()参数是最关键的,几乎所有的libcurl程序都要使用它。
二、基本的函数 1.CURLcode curl_global_init(long flags); 描述: 这个函数只能用一次。(其实在调用curl_global_cleanup 函数后仍然可再用) 如果这个函数在curl_easy_init函数调用时还没调用,它讲由libcurl库自动调用,所以多线程下最好主动调用该函数以防止在线程中curl_easy_init时多次调用。 注意:虽然libcurl是线程安全的,但curl_global_init是不能保证线程安全的,所以不要在每个线程中都调用curl_global_init,应该将该函数的调用放在主线程中。 参数:flags CURL_GLOBAL_ALL //初始化所有的可能的调用。 CURL_GLOBAL_SSL //初始化支持 安全套接字层。 CURL_GLOBAL_WIN32 //初始化win32套接字库。 CURL_GLOBAL_NOTHING //没有额外的初始化。
2 void curl_global_cleanup(void); 描述:在结束libcurl使用的时候,用来对curl_global_init做的工作清理。类似于close的函数。 注意:虽然libcurl是线程安全的,但curl_global_cleanup是不能保证线程安全的,所以不要在每个线程中都调用curl_global_init,应该将该函数的调用放在主线程中。
3 char *curl_version( ); 描述: 打印当前libcurl库的版本。
4 CURL *curl_easy_init( ); 描述: curl_easy_init用来初始化一个CURL的指针(有些像返回FILE类型的指针一样).
原文链接:http://f.dataguru.cn/thread-225664-1-1.html 有三种方法: 1. db2 "select tbsp_using_auto_storage from sysibmadm.tbsp_utilization" 查看是否值为1 TBSP_USING_AUTO_STORAGE ----------------------- 1 (1表示是automatic storage) 1 1 0 0 0 2. db2pd -d testdb -tablespace 在Tablespace Autoresize Statistics列中查找AS列是否为yes Tablespace Autoresize Statistics: Address Id AS AR InitSize IncSize IIP MaxSize LastResize LRF 0x9DCE0630 0 Yes Yes 33554432 -1 No None None No 0x9DCE0E40 1 Yes No 0 0 No 0 None No 0x9DCE3620 2 Yes Yes 33554432 -1 No None None No 0x9DCE3E30 3 No No 0 0 No 0 None No 0x9DCE47B0 4 No No 0 0 No 0 None No 0xA404B0C0 5 No No 0 0 No 0 None No 3.
Ubuntu x64 编译 Padavan 记录 近 3 个通宵尝试用 Mac OS X 进行编译,1 个通宵解决交叉编译工具链 toolchain 问题,后两个通宵执着于固件编译,随后放弃。解决了 Linux Kernel,在 uClibc 那里我知道我没法继续了。实在受不了,中途居然还因为 Mac 上文件不区分大小写少文件。装 Genymotion 的时候正好有 VBox,顺手下载了 Ubuntu Desktop 16 装上,吐血。下文为编译过程…
先更新系统是有必要的 sudo apt-get update sudo apt-get upgrade 安装必需的组件 首先是 git
sudo apt-get install git 其他组件(mc 可选,我并没有安装)
sudo apt-get install build-essential gawk pkg-config gettext automake autoconf libtool bison flex zlib1g-dev libgmp3-dev libmpfr-dev libmpc-dev texinfo python-docutils autopoint 交叉编译工具链 建议在 /opt 目录下操作
移动到 /opt 目录,cd /opt
法一:
DATA SEGMENT
MES1 DB 'Input:',0AH,0DH,'$' MES2 DB 0AH,0DH,'Output:',0AH,0DH,'$' XXX DB 10,?,10 DUP('$') DATA ENDS CODE SEGMENT ASSUME CS:CODE,DS:DATA START: MOV AX,DATA MOV DS,AX LEA DX,MES1 MOV AH,9 INT 21H INPUT: LEA DX,XXX MOV AH,0AH INT 21H LEA DX,MES2 MOV AH,9 INT 21H MOV CL,XXX+1 MOV CH,0 LEA BX,XXX+2 OUTPUT: MOV DL,[BX] SUB DL,20H MOV AH,2 INT 21H INC BX LOOP OUTPUT MOV AX,4C00H INT 21H CODE ENDS END START
在纯C环境下写程序,分分钟让你怀疑,自己到底会不会写程序的,太多常用库和类都不能用,甚至一些惯有的“随意表达”,分分钟都是错的。
我只想在VS写个纯C练练手,应该说是在.cpp写完,觉得这段代码还可以,符合标准纯C环境,改成.c看看是否能运行,万万没想到的是,这段这么简单的代码,连个刚学C语言,甚至是文科专业选修C语言的童鞋都看得懂得的代码:
#include<stdio.h> void main(){ int a=1; printf("%d",a); int b=2; printf("%d",b); }居然在.cpp过得了编译,手贱将其改成.c之后,他丫的vs2010居然给我报这样的错: 然后我瞪大我的钛合金狗眼,好好找找今天是不是这么不在状态,连个分号,都没打上去,但明明第5行,那个int b=2;,可以理解成2b,后面就是有个分号。
然后告诉我b未声明标识符?喂,???,分号我看不清楚,但你这个b之前明明有个int,三个英文???
此处应有暴漫表情,你他妈是在逗我?
之前那个莫名其妙的警告,《【C】将m~n之间的素数输出与VS2005以上版本对C语言的scanf的警告warning C4996》(点击打开链接),能过编译、能正常运行也就算了,C语言抽风也不是一天,现在你居然这么简单的程序都不给我过编译。
实质上,纯c要求局部变量定义必须在函数或局部空间的开头,然后才能有其他语句。纯c确实对变量声明的位置有要求,c++却可以随用随定义的。 说明vs是严格执行了纯C的标准。变量任意定义是C99的标准。这是C89的标准,C99也没有这个限制。问题是微软拒绝支持C99(包括VS2012),一股当年IE6的作风。可以用/tp参数把程序作为C++代码编译,就可以通过了。或者,根本没有这么麻烦,将int b拉到最顶,就没事了。
就是要你完成所有局部变量的定义,你才能写代码。如下代码,就半点问题没有了:
#include<stdio.h> void main(){ int a=1; int b=2; printf("%d",a); printf("%d",b); }如下图所示:
import nltk.tree as tree # 递归遍历 def test(t): if isinstance(t, str): print t else: for i in range(len(t)): test(t[len(t)-i-1]) # 非递归遍历 def test_2(t): stack = [] stack.append(t) current = "" while stack: current = stack.pop() if isinstance(current, tree.Tree): for i in range(len(current)): stack.append(current[i]) elif isinstance(current, str): # print "[输出] ",current print current if __name__ == "__main__": C = tree.Tree("C", ["E", "F"]) B = tree.Tree("B", [C, "D"]) H = tree.Tree("H", ["
第2章 神经网络计算 本章简要介绍了神经网络的计算方面,尤其是卷积神经网络,强调了理解和使用MatConvNet所需的概念。
2.1概述 神经网络(NN)是将数据x(例如图像)映射到输出向量y(例如图像标签)的函数。函数g = fL … f 1是较简单函数序列fl的组合,称为计算块或层。令x1; x2; :::; xL是网络中每个层的输出,并且令x0 = x表示网络输入。通过应用具有参数wl的函数fl,从先前输出xl-1计算每个中间输出xl = fl(xl-1; wl)。
在卷积神经网络(CNN)中,数据具有空间结构,是3D阵列或张量,其中第一两维H1(高度)和W1(宽度)被解释为空间维度。第三维度C1被解释为特征通道的数量。因此,张量x1表示C1维特征向量的H1 * W1字段,每个空间位置一个。张量中的第四维N1跨越多个数据样本,这些数据样本被打包在单个批次中用于效率并行处理。一个批次中的数据样本N1的数量被称为批量基数。网络被称为卷积,因为函数f1是本地和转换不变操作符(即非线性滤波器),如线性卷积。
还可以设想具有多于两个空间维度的CNN,其中附加尺寸可以表示体积或时间。 事实上,几乎没有先验对神经网络中数据格式的限制。 许多有用的NN包含卷积层与处理其他数据类型(例如文本字符串)的层的混合,或者执行不严格符合CNN假设的其他操作。
MatConvNet包括各种图层,包含在matlab /目录中,例如vl_nnconv(卷积),vl_nnconvt(卷积转置或去卷积)vl_nnpool(最大和平均池),vl_nnrelu(ReLU激活),vl_nnsigmoid(Sigmoid激活),vl_nnsoftmax(softmax运算符),vl_nnloss(分类正常丢失),vl_nnbnorm(分批正规化),vl_nnspnorm(空间规范化),vl_nnnormalize(局部响应规范化LRN)或vl_nnpdist(p距离)。 有足够多的层来实现许多有趣的最先进的网络开箱即用,甚至从其他工具箱,如caffe导入。 NNs通常用作分类器或回归。在fig. 1.1的示例中,输出^ y = f(x)是概率的向量,一个用于1000个可能的图像标签(狗,猫,三叶虫,…)中的每一个。如果y是图像x的真实标签,我们可以通过损失函数来测量CNN性能,该损失函数对分类错误赋予惩罚。然后可以调整或学习CNN参数以最小化在标记的示例图像的大数据集上的平均损失。
学习通常使用随机梯度下降(SGD)的变体。 虽然这是一个有效的方法(对于这种类型的问题),但网络可能包含几百万个参数,需要在数百万的图像上进行训练; 因此,效率是MATLAB设计中的一个重要部分,如第1.4节中进一步讨论的。 SGD还需要计算CNN导数,如下一节所述。
2.2网络结构 在最简单的情况下,NN中的层按顺序排列; 然而,更复杂的互连也是可能的,并且事实上在许多情况下非常有用。 本节讨论这种配置,并引入一个图形符号来可视化它们。
2.2.1序列 首先考虑网络中的计算块f。 这可以表示示意性地作为接收数据x和参数w作为输入并且产生数据y作为输出的框: 如上所述,在最简单的情况下,块被链接在序列f1-> f2-> … fL中,产生以下结构: 给定输入x0,评估网络是评估所有块的简单问题。从左到右,其定义复合函数xL = f(x0; w1;:::; wL)。
2.2 网络结构 2.2.2定向非循环图 一个不限于一个接一个地链接层。 事实上,评估NN唯一的要求是,当必须评估层时,在其之前已经评估了其所有输入。 当层之间的互连形成有向无环图或简称DAG时,这是可能的。 为了可视化DAG,引入用于网络变量的附加节点是有用的,fig.2.1的示例中那样。这里框表示函数,圆圈表示变量(参数被视为特殊类型的变量)。 在该示例中,x0和x4是CNN的输入,x6和x7是输出。 函数可以采取任何数量的输入(例如f3和f5取两个)并且具有任何数量的输出(例如f4具有两个)。 这个图的几个值得注意的属性: 1图表是二分的,在某种意义上,箭头总是从框到圆和 从圆圈到框。 2函数可以有任意数量的输入或输出; 变量和参数可以具有任意数量的输出(具有更多一个输出的参数被共享在不同层之间); 变量最多只有一个输入和参数无。 3没有输入箭头和参数的变量不由网络计算,但必须在评估之前设置,即它们是输入。 任何变量(或甚至参数)可以用作输出,但是这些变量通常是没有输出的变量。 4由于图是非循环的,因此可以通过对函数和函数进行排序来评估CNN一个接一个地计算它们(在该示例中,评估函数阶f1; f2; f3; f4; f5将工作)。
预编译头文件的原理:
在DXUT.cpp里include一次DXUT.h,生成一次pch,pdb文件,其他地方实际上直接用这个编译的结果,从而减少编译时间,提高编译效率。一般,我们把常用的不变的库头文件放里面,如,atlbase.h,atlcore.h,windows.h等,通常的com里import进来的dll,tlb也放这个里面,这样,它能做到,只编译一次,其他地方直接用编译出的结果。
如果预编译头文件被正确使用时,它确实大大提高我们编程的效率(你工作中,有多少时间是在等编译完成?很多吧,这个时候一般都很无聊,无奈,浪费时间)。但是他太容易用错了. 下面是几种常见的错误用法.
1) 在预编译头文件里include自己的头文件(当然, 如果你的头文件不经常变化, 也可以)
原因:自己的头文件一般会经常变, 便利后导致预编译的东东重新编译, 降低了编译速度.
2) 在其他的头文件里也include 预编译头文件
假设你的其他头文件也include了预编译头文件, 如果别人引用你的这个头文件又没有设置成预编译头文件, 那引用你头文件的这个人就煎熬了.
原因:由于你用到的.h文件里include了预编译头文件,他在他本身的project里,vs能够判断的出他是预编译头,也能找的到需要的pch,pdb文件。所以对写这个.h文件的人没影响。但是你作为他的客户,你工作在你的project下,你include了他的h头文件,而这时vs判断不出他的头文件里include的stdafx是预编译头文件,做普通文件编。那可想而知,他的stdafx里如果有import外面大型的库(如inventor的tlb,非常慢,我们犯了这个错),那编译速度简直是煎熬。最要命的是,以后你做任何简单的修改都要重编,这和预编译解决的问题恰好相反了。
下面给出一个使用预编译头文件的操作步骤, 享受一下预编译头文件给我们带来的编译速度的提升:
1) 添加一个stdafx.h文件(名字随便取, 这里用了VS默认提供的名称), 在这个.h文件里include要使用的头文件(一般是外部的库, 自己写的不常变的头文件也可以加进来)
2) 添加一个stdafx.cpp文件, 并include "stdafx.h"
3)项目属性-->c/c++-->Precompiled设置为Use Precompiled Header, stdafx.h
4)stdafx.cpp属性-->c/c++->Precompiled设置为Create Precompiled Header, stdafx.h
done!
Unity个人免费版:
使用Unity的任何工程都要输入一次账号密码
界面是灰色
UGUI的 Canvas 的UI 不能 改变 其 Rect Transform,也就不能用 UGUI 建立 人物脚下的圆环。
【Unity问题】为什么Unity 5.5.0f3(64-bit)免费版打开项目每次要输入账号密码 PRO专业版:
打开Unity不需要每次输入账号密码
界面是黑色
可以使用 UGUI ,改变 Canvas 的 图片 的坐标 相关数据,使其为 人物脚下的 特效圆环。
Timeseries Classification: KNN & DTW KNN&DTW全称为:K Nearest Neighbors & Dynamic Time Warping
以下为该文的链接:KNN&DTW
基本思想:使用DTW方法计算两个时间序列之间的距离,并将此距离作为最近邻算法中的距离函数
算法中的关键问题:1.使用距离矩阵来表示两个时间序列之间的距离
2.Warp windows大小的选取
为了并行开发多个需求,往往需要在多个代码环境下使用Eclipse。使用时间一长,发现一个问题:使用过的workspace都留在记录里面,有些已经不需要了。
方案一:
Window -> Preferences -> General -> Startup and Shuodown -> Prompt for workspace on startup
展开之后把不需要多remove掉
方案二:
1. 打开eclipse下的/configuration/.settings目录
2. 修改文件org.eclipse.ui.ide.prefs
3. 把RECENT_WORKSPACES这项修改为你需要的那些目录,以\n分隔
参考地址:http://blog.csdn.net/achun2050/article/details/8238481
case1:List()到DataFrame()的简单转化 //step1:我们首先创建一个case class case class resultset(masterhotel:Int, quantity:Double, date:String, rank:Int, frcst_cii:Double, hotelid:Int) //step2 //初始化resultset类,有很多方法,如从关系型数据库中获取数据定义resultset类、 //直接定义一个resultset的List等 val x1=List(resultset(1001,12,"2016-10-01", 1, 13.44,1001), resultset(1002,12,"2016-10-01", 3, 13.44,1002), resultset(1004,15,"2016-10-02", 10, 18.44,1004), resultset(1005,5,"2016-10-02", 40, 5.67,1005) ) val dataset1=sqlContext.createDataFrame(x1) scala> dataset1.show() +-----------+--------+----------+----+---------+-------+ |masterhotel|quantity| date|rank|frcst_cii|hotelid| +-----------+--------+----------+----+---------+-------+ | 1001| 12.0|2016-10-01| 1| 13.44| 1001| | 1002| 12.0|2016-10-01| 3| 13.44| 1002| | 1004| 15.0|2016-10-02| 10| 18.44| 1004| | 1005| 5.0|2016-10-02| 40| 5.67| 1005| +-----------+--------+----------+----+---------+-------+ case2:元组元素的数组如何转化为列表,再利用类转化为DataFrame() val x2=Array((1001,12,"2016-10-01", 1, 13.44,1001), (1002,12,"2016-10-01", 3, 13.44,1002), (1004,15,"
在之前的开发过程中一直仅仅使用到了 AnimatorStateInfo 这货,平时在做一些判断的时候还特意加入一个判断!Animator.IsInTransition(0) 来确定当前这个 Animator 没有在进行动画过渡,可是这几天同事们总是反应游戏中主角移动起步很慢和停止移动的时候会出现滑步的情况,这个不能忍,听得我很是汗颜啊。
好吧,汗颜的事情就先不表了,我们来看看这个可能是神马问题吧。通常我们游戏当中,角色都会有一个待机的动作,跑步和行走都会有相应地动作,而不同的动作之间的切换,Unity3D 会自行做动画融合,这样主角从待机动作切换到跑步的动作时,就不会出现一帧直接切换导致看起来非常机械和卡顿的问题,看起来整个过程会是非常平滑的,这个就是我们要谈到的重点了。
在之前的实现中,我在主角的移动控制脚本 PlayerMovement 中使用了一段这样的代码来判断当前女主角已经成功的从 Idle 状态切换到 Locomotion 状态了
AnimatorStateInfo animInfo = animator.GetCurrentAnimatorStateInfo (0); if (animInfo.isName ("Locomotion")) { // 这里控制角色的位置移动 } 然后在控制角色位置移动的代码段中,我们根据需要进行计算获得女主角在不同坐标上的移动位置,然后将位移作用到角色上。
但是这样做会有什么问题呢?
首先,当角色在从 Idle 切换到 Locomotion 动画的过渡中时,上面的这段代码会直接忽略动画过渡的这段时间,所以在女主角从静止起步到跑步的过程中,Animator 实际上一直都会保持为 Idle 的状态,直到整个 Transition 完成了,Animator 的 State 才会切换到 Locomotion,这样的话女主角实际上是在原地播放了这个过渡的动画,而这段时间的动画中,女主角的脚步会从静止切换到小碎步,再到大步跑,而这个时候女主角的位置不会发生变化(没有在女主角跑动动画对应的方向上移动),最终的结果就是主角看起来反应非常慢,起步的时候会出现卡顿,要在原地跑一段时间之后才会移动,这显然是不能接受的。 其次,当角色从 Locomotion 切换到 Idle 动画的过渡中时,依然会出现逻辑被忽略的情况,也就是角色实际上已经在从 Locomotion 切换到 Idle 了,角色的脚步动作越来越小了,但是因为 Animator 的设计是在切换过程中,State 的名字不会改变,会保持为状态切换之前的状态名,也就是在动画完全切换到 Idle 之前,State 的名字一直都是 Locomotion,所以主角在这个时间里头,逻辑会让主角继续运动(因为它满足上面的逻辑,所以还会计算位移,并应用到角色对象上),最终的结果就是看起来主角的跑步动画已经停止但是身体还在动画方向上做位移,出现滑步了,尼玛啊。 既然已经找到问题了,那么我们就肯定有办法来解决它。既然我们知道了动画在切换的过程中可以通过 AnimatorTransitionInfo 来获取过渡的信息,那么就有办法了,首先我们能确定 Idle 到 Locomotion 和 Locomotion 到 Idle 的 nameHash 值,通过比对这两个值就能明确知道当前 Animator 是从哪个状态切换到哪个状态了,然后根据 AnimatorTransitionInfo.
private void label1_Paint(object sender, PaintEventArgs e) { Draw(e.ClipRectangle, e.Graphics, 16); base.OnPaint(e); } private void Draw(Rectangle rectangle, Graphics g, int _radius) { Pen shadowPen = new Pen(Color.Blue); g.DrawPath(shadowPen, DrawRoundRect(rectangle.X, rectangle.Y, rectangle.Width - 2, rectangle.Height - 1, _radius)); } public static GraphicsPath DrawRoundRect(int x, int y, int width, int height, int radius) { GraphicsPath gp = new GraphicsPath(); gp.AddArc(x, y, radius, radius, 180, 90); gp.AddArc(width - radius, y, radius, radius, 270, 90); gp.
表单提交过来的数据有两种方法,一种是GET方式提交,这种提交方法会把表单需要传输的数据写在url上,一起带过去,另一种是POST方式提交,POST方式提交会把表单数据携带在request请求正文中传递过去。
针对这两种不同的提交方法,node里也有两种不同的处理方法。先看看如果用GET方式提交,我们该怎么去处理
获取GET方式提交的数据 index.html <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title></title> </head> <body> <form action="http://localhost:9998" method="get"> <input type="text" name="user" value="" /> <input type="password" name="passw" value="" /> <input type="submit" value=""/> </form> </body> </html> index.html只是一个简单的表单网页,两个输入框用作用户的账号和密码输入,还有一个submit用来提交。
下面是node实现
GETServer.js var http = require("http"); var url = require("url"); function onRequest(req,resp){ console.log(url.parse(req.url,true).query); //返回响应 resp.writeHead(200,{"ContentType":"text/html;charset=utf-8"}); resp.end(); } //创建server http.createServer(onRequest).listen(9998); 这样的话就获取到了表单使用GET方式提交过来的数据 其中req.url 是指req提交过来的url的路由 但是我们会发现一个问题,我们看一下console的打印情况。
{ user: 'asda', passw: 'asddasd' } {} 我们会发现打印了两行,第二行被打印出了一个空的JSON对象。这是怎么回事呢,听老衲缓缓道来。
在第一次request请求的时候,客户端会发送一个隐式的请求给服务器,这个请求就是为了获取到网页的图标(就是每个网页打开后Title旁边的那个小图标),所以,当我们提交表单数据的时候,实际是触发了两次请求,第一次请求favicon.ico ,第二次提交数据,所以我们打印出来的结果就是两个对象。
so?那么我们应该怎样去处理它呢?我们需要在服务端过滤掉请求favicon.ico的请求。 只需加上一段这样的if就行