介绍:尽管数字不总是那么惹人们注意,但是也千万不小忽略数字的重要性。数字的种类各种各样,从二进制到十六进制,每种数字的表达形式都有合适的使用环境,比如十六进制一般用来表达RGB颜色,因为通过十六进制的颜色我们就很容易能区分颜色的各个组成部分。
和数字紧密联系的就是数学运算,如果没有数学运算符,flash影片就显得非常的单调和无聊,简单的加合减的操作是一些ActionScript程序的基础操作,更高级一些的操作比如math类,随机数的产生,三角计算等就是高级的运用。
ActionScript3.0有三种基本的数字类型:number,int,unit。任何浮点类型的数字都是numbre,int和unit都是整型类型。Int和unit的区别之处是int代表了所有的整数,不管是正的还是负的而uint代表的是无符号的整数unsiged int。
用不同的形式表达数字
问题:你想声明一个二进制,八进制和十六进制的变量。
解决:十六进制字符以0x开头(注意开头是一个数字0而不是字母o),八进制以0开头,二进制数字不能直接表示,你可以用八进制或者十六进制来代替这个二进制数字,或者使用parseInt()函数把二进制转换成一个number类型。
讨论:你可以在ActionScript用任何你觉得方便的格式来表达数字,比如十进制或者十六进制概念。例如,如果你要设定Sprite.rotation属性,最方便的选择是使用十进制。
RectangleSprite.rotation=180;
但是十六进制和适合用来指定RGB颜色,比如你可以给ColorTransform对象的rgb属性设置一个十六进制的颜色:
Var pink:ColorTransform=new ColorTransform();
Pink.rgb=0xF612AB;
任何数字串如果以0x开头的话,都会被认为是十六进制的数字,允许的数字是0-9和A到F(这里大小写不作区分,所以大写和小写的是等同的)。
任何以0开头的数字都被认为是八进制的数字,允许的数字是0到7。很多的开发者基本上在ActionScript里不使用八进制,对大多数的开发者来说,最方便使用的应该就是十进制了,除了表示RGB类型的颜色。这里也没有合适的例子来说明在什么场合下使用八进制比较合适。
二进制数字允许使用的数字是0和1,尽管你不能直接指定二进制数自,但是你可以使用十六进制或者八进制,他们是等同的,四位的二进制等同于一位的十六进制,二进制数在ActionScript的移位运算符中使用的最多(&,|,^,>>,<<)。
数字类型之间的转换
问题:你想在上节介绍的几种数字类型之间转换格式。
解决:使用parseInt(radix)方法来从各种类型到十进制类型的转换,radix是数基。使用toString(radix)方法来从一个十进制到其他类型的转换。
讨论:在ActionScript中,无论你使用什么类型的数字,结果是他们都被转换成了十进制数:
// Create a Color object
var pink:ColorTransform = new ColorTransform( );
// Set the RGB value as a hexadecimal
pink.rgb = 0xF612AB;
// This displays the value as decimal: 16126635
trace(pink.rgb);
然而,如果你想输出不同类型的数字,就必须使用toString(radix)方法,把一个number,int或者uint转换成你想表示的形式。
// The radix is 2, so output as binary
trace(new uint(51).toString(2)); // Displays: 110011
// The radix is 16, so output as hex
trace(new uint(25).toString(16)); // Displays: 19
下边的例子使用RGB颜色给ColorTransform对象的rgb属性赋值,结果是显示为十六进制的字符串,而不是数字
// Create a Color object
var pink:Color = new ColorTransform( );
// Set the RGB value as a hexadecimal
pink.rgb = 0xF612AB;
trace(pink.rgb.toString(16)); // Displays: f612ab
radix的有效选项是2到36,如果你在调用toString()方法的时候没有给指定任何参数,那么默认的就按十进制处理。
你可以使用parseInt()来或者和toString()方法相反的操作,parseInt()方法接受一个字符串,返回一个数字,如果你想使用其他类型的数字的时候,这个方法很方便,看例子:
trace(parseInt("110011", 2)); // Displays: 51
trace(parseInt("19", 16)); // Displays: 25
trace(parseInt("17", 10)); // Displays: 17
如果不指定radix参数,那么默认的就认为是十进制,除非你的字符串是以0或者0x开头的:
trace(parseInt("0x12")); // The radix is implicitly 16. Displays: 18
trace(parseInt("017")); // The
radix
is implicitly 8. Displays: 15
显示的radix参数的指定就会覆盖掉隐式的这个参数,看下边的例子,结果是0而不是12,因为这个数字被当作十进制处理,但是在数字里边发现了一些能解析的字符,所以停止,返回0:
// The number is treated as a decimal, not a hexadecimal number
trace(parseInt("0x12", 10)); // Displays: 0 (not 12 or 18)
下边的这个例子,虽然字符串是以0开头的,但是它没有被当作八进制来处理,而是当作十进制来处理:
// The number is treated as a decimal, not an octal number
trace(parseInt("017", 10));
// Displays: 17 (not 15)
不要忘记0或者0x或者使用显示的radix参数的指定,下边的例子中返回NaN,因为A不能被转换成整数:
trace(parseInt("A9FC9C")); // NaN
对字符串进行格式化
问题:想对一些字符串的显示进行格式化
解决:使用本书提供的类NumberFormat类,在使用这个类的format()方法的时候,传递一个mask进去。
讨论:当然我们如果自己去做一些算法也可以实现对一些要以一定格式显示的字符串进行格式化,但是最直接和有效的方法还是使用本书提供的代码中的NumberFormat类的format方法。比如我们要输出一定格式的时间,现在是六点三分,我想要得到6:03或者06:03而不是6:3这样的格式。
使用的时候当然要把相应的类包含进来,使用下边的语句(在这之前去下载我们提供的程序包,地址:
http://www.rightactionscript.com/ascb):
import ascb.util.NumberFormat;
接下来,你需要决定你使用的mask来格式化数字。Mask可以由0,#,逗点 .,以及逗号, ,组成;任何其它的字符都不会被接受。
逗号:占位符,可以被数字或者0代替
#号:占位符,可以被相应的数字或者空格代替
点号:十进制的小数点;可以被本地化的一些相应的符号代替
逗号:分组符号,可以被本地化的相应的符号代替。
为了很好的理解这些符号的具体含义,下边我们来看一些例子,这些例子中我们使用的mask为:##,###.0000,我们用这个mask类格式化1.2345,12.345,123.45,1234.5,12345五个数字,得到的结果如下(假设默认的本地设定为:分组符号是逗号,小数点符号是.):
1.2345
12.3450
123.4500
1,234.5000
12,345.0000
我们既可以在初始化NumberFormat类的时候给它传递相应的mask,也可以通过一个可读写的属性mask来改变这个mask 字符串的值,比如:
var styler:NumberFormat = new NumberFormat("##,###.0000");
然后:styler.mask = "##.00";
一旦mask设定到某个NumberFormat对象,我们就可以使用这个对象来格式化字符串,调用相应的方法format(),传递给这个方法你想格式化的参数:
trace(styler.format(12345);
默认的,NumberFormat类自动本地化格式化返回的值,如果Flash Player播放器运行在一个英文的操作系统上,NumberFormat类使用逗号作为分组符号,使用dots作为小数点符号。但是,如果播放器运行在法语的操作系统上,这两个符号的代表的意义就会反过来。这里有一些足够的理由来促使我们重写默认的格式化行为:
l 你想让字符串的格式化标准化,而不用考虑运行在什么操作系统上。
l 自动格式化不总是合适,这种情况发生在以下两种情况:第一种,Locale类可能不包含一些国家和地区(这个类被NumberFormat类使用来设置一些格式化的信息)第二种是Flash播放器不总是能检测到精确的本地信息,它只报告本地语言代码,有的时候这样的信息不足以来正确的格式化字符串。
这里有好几种发放类解决这个问题:
l 使用format函数的时候,给第二个参数传递一个Locale对象。这个对象默认的构造器是检测系统的本地信息,所以你应该在实例化Locale的时候传递两个参数,第一个参数是语言代码(如en),第二个参数是国家代号,比如us。你因该只在某一种语言存在于多个区域的时候使用第二个参数,比如mexico和spain都有spanish,但是这两种语言使用不同的符号。
l 设定全局的参数Locale.slanguage和Locale.svariant。这两个属性是静态,如果设置了这两个参数,任何后续的调用都会按照这个设置来格式化
l 在format方法的第二参数的位置使用一个标示符号。这个标示符号应该有两个参数:gounp和decimal。这连个参数允许你在格式化的时候设置适当的格式化信息,比如在Local类不能表示这样的国家或者地区的时候。
下边的例子表明了上边讨论的集中方法的使用:
var styler:NumberFormat = new NumberFormat("#,###,###,###.00");
Locale.slanguage = "fr";
trace(styler.format(1234));
trace(styler.format(12345, {group: ",", decimal: "."}));
trace(styler.format(123456));
Locale.slanguage = "en";
trace(styler.format(1234567));
trace(styler.format(12345678, new Locale("es", "ES")));
trace(styler.format(123456789, {group: "|", decimal: ","}));
结果是:
1.234,00
12,345.00
123.456,00
1,234,567.00
12.345.678,00
123|456|789,00
不使用
mask
来格式化字符串
问题:你想格式化一个字符串,而不使用mask
解决:创建一个NumberObject类的对像,然后调用format()
讨论:在上一节我们讨论这个类一些复杂的用法,但是也有些时候我们不需要这样复杂的使用,这个时候只要初始化一个没有任何参数给它的NumberObject类,然后调用format方法,默认的,这个类会读本地的设置,然后来初始化传递给它的字符串。但是有的时候我们也想重写本地的设置,如同上节讨论的一样,我们可以有以下几中做法:
var styler:NumberFormat = new NumberFormat( );
Locale.slanguage = "fr";
trace(styler.format(1234, new Locale("en")));
trace(styler.format(12345, {group: ":", decimal: "|"}));
trace(styler.format(123456));
结果是:
1,234
12:345
123.456
格式化货币数值
问题:你想把一个数值格式化为某种货币为单位的数值,比如美元
解决:使用NumberFormat.currencyFormat()方法。
讨论:不想起他的一些语言,比如coldFusion,ActionScript并没有内建的格式化字符串的一些方法,比如格式化为货币值。所以我们在本书的代码里提供了这些有用的类。
CurrencyFormat方法最少需要一个参数,就是你需要格式化的数值。下边的例子展示了如何使用这个方法:
var styler:NumberFormat = new NumberFormat( );
trace(styler.currencyFormat(123456));
默认的,如果在一个英语的操作系统上,结果是$123,456.00.
就如同前边讨论的,默认的不总是正确或者合适,我们可以通过三种方法来改变默认的设置,方法和前边的一样,唯一有一点不同的是使用symbols的时候,我们必须设置四个参数:
Group,decimal,currency,before。前两个参数的意思和前边讨论的一样,currency参数是我们要表达的货币符号,before参数是一个bool类型的值,表示货币符号出现的位置。例子:
var styler:NumberFormat = new NumberFormat( );
trace(styler.currencyFormat(123456));
Locale.slanguage = "nl";
trace(styler.currencyFormat(123456));
trace(styler.currencyFormat(123456, new Locale("sv")));
trace(styler.currencyFormat(123456, {group: ",", decimal: ".", currency: "@", before: false}));
运行结果是:
$123,456.00
123.456,00
123,456.00kr
123,456.00@
创建随机数
问题:使用ActionScript来创建随机数
解决:Math.random()方法可以产生0到0.9999999的数字,使用NumberUtilities.random可以产生任何去见的随机数字。
讨论:Math类的random方法只能产生0到0.9999999的数字的随机数字,这在我们的日常的使用中有时候很不方便,比如我们需要1到100之间的随机数字,当然我们可以通过一定的逻辑达到这种需求。在我们提供的类里边有这样的一个方法可以完成同样的事情。这个类就是NumerUtilities,这个类有个方法random(),最多可以接受三个参数:
Minimum:指定最小下限
Maximum:指定最大上限
RoundtoInterval:最后一个可选的参数是用来舍入的,如果忽略,产生的数字就被精确到最近的整数。当然你可以指定一个舍入值。当然也可以指定小于一的数。例子:
// Generate a random integer from 0 to 100.
trace(NumberUtilities.random(0, 100));
// Generate a random multiple of 5 from 0 to 100.
trace(NumberUtilities.random(0, 100, 5));
// Generate a random number from -10 to 10, rounded to the
// nearest tenth.
trace(NumberUtilities.random(-10, 10, .1));
// Generate a random number from -1 to 1, rounded to the
// nearest five-hundredth.
trace(NumberUtilities.random(-1, 1, .05));
使用随机函数模拟投硬币
package {
import flash.display.Sprite;
import flash.text.TextField;
import flash.events.MouseEvent;
import ascb.util.NumberUtilities;
public class CoinExample extends Sprite {
private var _field:TextField;
public function CoinExample( ) {
_field = new TextField( );
_field.autoSize = "left";
addChild(_field);
var circle:Sprite = new Sprite( );
circle.graphics.beginFill(0, 100);
circle.graphics.drawCircle(100, 100, 100);
circle.graphics.endFill( );
circle.addEventListener(MouseEvent.CLICK, onClick);
addChild(circle);
}
private function onClick(event:MouseEvent):void {
var randomNumber:Number = NumberUtilities.random(0, 1);
_field.text = (randomNumber == 0) ? "heads" : "tails";
}
}
}
注意random方法如果不指定最后的一个参数,那么产生的数就会舍入到最接近它的整数上。
模仿
骰子
(
Dice
)
问题:模仿骰子游戏
解决:使用随机函数产生随机数来模仿
讨论:NumberUtilities.random(1,12)不能很好的模仿骰子游戏,因为骰子游戏有两个骰子,两个和的值范围是2到12而不是1到12。那么我们使用NumberUtilities.random(2,12)能很好的模仿吗?答案是否定的,因为这个函数产生的随机数比较平均的分布在2到12之间,而如果用两个骰子的话,7出现的频率会非常的高。例子:
package {
import flash.display.Sprite;
import flash.text.TextField;
import flash.events.MouseEvent;
import ascb.util.NumberUtilities;
public class NumbersAndMath extends Sprite {
var _die:Sprite;
var _value:uint;
public function NumbersAndMath( ) {
_die = new Sprite( );
addChild(_die);
_die.addEventListener(MouseEvent.CLICK, rollDie);
rollDie(null);
}
private function rollDie(event:MouseEvent):void {
_value = NumberUtilities.random(1, 6);
_die.graphics.clear( );
_die.graphics.lineStyle( );
_die.graphics.beginFill(0xFFFFFF);
_die.graphics.drawRect(0, 0, 50, 50);
_die.graphics.endFill( );
_die.graphics.beginFill(0x000000);
if(_value == 1 || _value == 3 || _value == 5) {
_die.graphics.drawCircle(25, 25, 4);
}
if(_value == 2 || _value == 3 || _value == 4 ||
_value == 5 || _value == 6)
{
_die.graphics.drawCircle(11, 11, 4);
_die.graphics.drawCircle(39, 39, 4);
}
if(_value == 4 || _value == 5 || _value == 6) {
_die.graphics.drawCircle(11, 39, 4);
_die.graphics.drawCircle(39, 11, 4);
}
if(_value == 6) {
_die.graphics.drawCircle(11, 25, 4);
_die.graphics.drawCircle(39, 25, 4);
}
}
}
}
模仿纸牌游戏
问题:你想使用ActionScript来模仿纸牌游戏(52张纸牌)
解决:使用下载的代码中的Cards类
讨论:你可以像下边的样子创建一个Cards类:var cards=new Cards();默认的,Cards对象会创建一副52张纸牌。我们可以调用deal()方法来返回一组CardHand对象,你必须至少指定一个参数来表示要发多少手牌。
默认的,一副牌中的所有的纸牌都会被发放,但是有些游戏第一次不是将所有的纸牌发放出去,比如每个人的手里只有六张纸牌。这种情况下,我们可以指定第二个参数来表示一次发放多少张纸牌到每个人的手里:
// Deal four hands with five cards each.
var hands:Array = cards.deal(4, 5);
每个CardHand类都由一组Card对象组成,这个类也提供了发牌和出牌的方法,发牌的方法是draw,这个方法从原始的那幅牌的顶部弹出一张牌,到用户的手里。而discard方法把手里的牌返回到原始那幅牌中,这两个方法都可以每次处理多于一张的牌:
// Discard the cards with indices 0 and 4 from the CardHand object
// stored in the first element of the aHands array.
hands[0].discard(0, 4);
// Draw one card from the top of the deck, and add it to the
// hand stored in the first element of the hands array.
hands[0].draw( );
// Draw four cards from the top of the deck, and add them to
// the hand stored in the fourth element of the aHands array.
hands[3].draw(4);
在类CardHand中可以使用属性length来获得手里有几张牌,你也可以使用getCardAt()方法来获得某一个位置的牌。
Card类由四个属性组成:value,name,suit,display。Value是牌的值,从0到12,0代表2而12代表Ace。Name属性从2到10到Q或者A。suit属性是纸牌的分类,有红桃,黑桃,方块,梅花。Display属性返回一个name和suit组合的字符串。下边的例子是完整的代码:
package {
import flash.display.Sprite;
import ascb.play.Cards;
import flash.util.trace;
public class CardExample extends Sprite {
public function CardExample( ) {
var cards:Cards = new Cards( );
var hands:Array = cards.deal(4, 10);
var i:uint;
var j:uint;
for(i = 0; i < hands.length; i++) {
trace("hand " + i);
for(j = 0; j < hands[i].length; j++) {
trace(hands[i].getCardAt(j));
}
}
}
}
}
产生唯一数
问题:有些时候我们区要产生唯一数,比如给一个url添加一个数字来防止这个url被缓存。
解决:使用NumberUtilities.getUnique()方法
讨论:唯一数在产生唯一的URL的时候很有用,也就是,把这个唯一数添加到一个url的后边,然后在访问的时候我们就可以从新从其他地方下载这个url,而不会去本机的缓存里去找同样的页面。NumberUtilities.getUnique()方法产生随机数的方法是根据目前的时间的毫秒数。也有一些情况下我们可能在一毫秒内产生一组唯一数,你会发现系统自动的在每个产生的随机数的后边添加了一个随机数来保证产生的唯一数的唯一。
for(var i:Number = 0; i < 100; i++) {
trace(NumberUtilities.getUnique( ));
}
角度转换
问题:你想在ActionScript中使用角度,但是你又必须把角度转换成合适的uints
解决:使用Unit和Converter类
讨论:影片剪辑的_rotation属性是用度数衡量的,在ActionScript中,其它情况下衡量角度都是是用弧度(radian)。这里会有两个问题,第一,如果你想从另外一个三角函数中返回一个计算结果来设置_rotation属性,你就必须把弧度转换成角度。第二,人们很喜欢使用角度,在我们作任何三角运算之前必须把角度转换成弧度然后才能运算。当然这样的转换可能根本难不到你,你可以使用角度乘以180/Math.PI来获得弧度,或者向相反的方向转换。但是如果有这样的方法,那不是会更简单一些。下载代码中有两个类Unit和Converter可以完成这样的工作。
这两个类是可以转换degrees,radians,gradians。第一步就是创建一个Unit实例来描述你想转换到的类型,Unit类有很多的常量,Unit.DEGREE,Unit.RADIAN,Unit.GRADIAN常量返回Unit对象分别表示Degreens,gradians,和radians。Unit还有很多属性可以使用,如下:
var degree:Unit = Unit.DEGREE;
trace(degree.name); // Displays: degree
trace(degree.category); // Displays: angle
trace(degree.label); // Displays: degree
trace(degree.labelPlural); // Displays: degrees
然后我们可以根据得到
Unit
对象创建
Converter
对象,比如:
var converter:Converter = Unit.DEGREE.getConverterTo(Unit.RADIAN);
一旦获得了Converter对象,你就可以使用这个对象的convert方法来转换数据:
trace(converter.convert(90));
例子:
var converterToRadians:Converter = Unit.DEGREE.getConverterTo(Unit.RADIAN);
var converterToDegrees:Converter = Unit.RADIAN.getConverterTo(Unit.DEGREE);
trace(converterToRadians.convertWithLabel(1));
trace(converterToRadians.convertWithLabel(57.2957795130823));
trace(converterToDegrees.convertWithLabel(1));
trace(converterToDegrees.convertWithLabel(0.0174532925199433));
/*
Displays:
0.0174532925199433 radians
1 radian
57.2957795130823 degrees
1 degree
*/
在有些情况下,你可能发现相反方向的转换会比较有用,那你就可以使用getConvertFrom()方法:
var converter:Converter = Unit.DEGREE.getConverterFrom(Unit.GRADIAN);
trace(converter.convert(100));
trace(converter.convert(23));
计算两点之间的距离
问题:计算两点之间的距离
解决:使用Math.pow()或者Math.sqrt在联合使用勾股定理。
讨论:使用勾股定理来计算两点之间的距离,勾股定理表述为任何直角三角形的两个直角边的平方和等于斜边的平方,常常表述为a2 + b2 = c2
你可以使用上边的式子计算任何两点之间的距离:
var c:Number = Math.sqrt(Math.pow(a, 2) + Math.pow(b, 2));
a代表两点之间x坐标的距离,b代表两点之间y坐标的距离。C就是最后计算的结果。
确定一个圆上各点的坐标:略。
各种计量单位之间的转换
问题:比如我们想在华式温度和摄氏度之间,磅和千克之间转换
解决:Converter类和Unit类
讨论:世界上由很多种的计量单位,比如我们可以使用华氏温度来表示温度,也可以使用摄氏度来表示,重量很多情况下会被表示为磅,但是在米制系统中常常用千克来表示。还有距离等等,由很多的单位。所以很多情况下我们必须在一些单位之间转换。
当然我们可以通过一些简单的运算达到目的,但是还有简单的方法就是通过我们提供的代码中的Unit类和Converter类。
使用Unit.getCategories()可以获得所有的支持的计量单位的列表:
angle,temperature,weightmass,distance,volume
使用Unit.getUnits("temperature")可以获得某一个计量单位所有可用的单位:
CELCIUS,FAHRENHEIT,KELVIN
。
在进行转换的时候我们可以使用两个函数getConverterTo( )和 getConverterFrom( )来进行,例子:
定义:var converter:Converter = Unit.CELCIUS.getConverterTo(Unit.FAHRENHEIT);
使用:trace(converter.convert(0)); // Displays: 32