关于单例模式的写法和理解

网上或者在群里看到的单例写法蛮多,我也随便写点,也好给别人点参考。 目前作者常用的单例写法: [codesyntax lang=”actionscript3”]

package
{
public class Test
{
private static var instance:Test=null;
public function Test(p:Param)
{
}
public static function getInstance():Test{
return instance=new Test(new Param());
}
}
}
class Param{}

[/codesyntax] “=”如果你觉得不好用,或者有问题的话,也可以换成常规的if判断。 作者使用单例写法历经了三个阶段: 第一阶段:仅加个getInstance。如下: [codesyntax lang=”php”]

package
{
public class Test
{
private static var instance:Test=null;
public function Test()
{
}
public static function getInstance():Test{
if(instance==null){
instance=new Test();
}
return instance;
}
}
}

[/codesyntax] 这种单例写法算是入门级的吧,无法防止别人通过new创建,只能靠人为的记住这个类是单例。   第二阶段:在构造函数抛错误 [codesyntax lang=”actionscript3”]

package
{
public class Test
{
private static var instance:Test=null;
public function Test()
{
if(instance!=null){
throw new Error(“this is a singleton class”);
}
}
public static function getInstance():Test{
if(instance==null){
instance=new Test();
}
return instance;
}
}
}

[/codesyntax] 这种写法,虽然可以防止别人通过new创建,但这要到运行的时候才会抛出错误。 第三阶段:加包外类参数 [codesyntax lang=”actionscript3”]

package
{
public class Test
{
private static var instance:Test=null;
public function Test(p:Param)
{
}
public static function getInstance():Test{
if(instance==null){
instance=new Test(new Param());
}
return instance;
}
}
}
class Param{}

[/codesyntax] 这种写法可以在编写代码的时候就避免别人通过new来创建实例,比起运行时才报错要更好一些。   单例,感觉在系统里比较适合同于一些管理器之类的功能,比如资源加载管理器,声音管理器等等。当然整个系统架构里面也会经常用到。单例模式应该算是最常用的设计模式之一。当然,单例也不能滥用!

AIR使用Admob广告小结

最近在研究移动应用,现在Andriod做点应用试试,花了一点时间做了个火车票查询的应用,上了几个平台看看效果,跑跑流程。 顾名思义,应用是实时查询火车票的官网余票信息,应用做好了,免费的,就也想着放点广告试试,这时候就发现AS3的苦逼。搞广告需要ANE,还好在网上找到了一个Admob的广告ANE,是个谷歌开源项目,具体我就不详细说了,做着写的有例子,就是替换下jar文件,添加ANE到项目直接调用就可以了,自己简单封装了一个工具类,顺便分享下(有待完善)。 [codesyntax lang=”actionscript3”]

package{
import so.cuo.anes.admob.AdAlign;
import so.cuo.anes.admob.AdEvent;
import so.cuo.anes.admob.AdType;
import so.cuo.anes.admob.Admob;

public class ADAdmob
{
/**
*是否在显示广告
*/
public var isShowAd:Boolean=false;
private var myAdmobId:String = “a150eeaece2a62e“;
private static var m_instance:ADAdmob=null;
public function ADAdmob(p:Param)
{
}

public static function get instance():ADAdmob{
return m_instance=new ADAdmob(new Param());
}

/**
*显示广告
* @param x X坐标
* @param y Y坐标
* @param type 广告类型
* @param isAlgin 是否按照align来部分,如果true 以align为准 xy无效 否则false 则以 xy为准 align无效
* @param align 位置
*
*/
public function showAd(x:int=0,y:int=0,type:String=AdType.BANNER,isAlgin:Boolean=false,align:int = AdAlign.ALIGN_BOTTOM):void
{
var admob:Admob=Admob.getInstance();
if(admob.isSupported){
admob.setUnitId(myAdmobId);
admob.dispatcher.addEventListener(AdEvent.onReceiveAd,this.adHandler);
admob.dispatcher.addEventListener(AdEvent.onFailedToReceiveAd,this.ad2Handler);
admob.dispatcher.addEventListener(AdEvent.onDismissScreen,c1Handler);
admob.dispatcher.addEventListener(AdEvent.onPresentScreen,pressHandler);
admob.dispatcher.addEventListener(AdEvent.onLeaveApplication,levelHandler);
if(isAlgin){
admob.showRelation(align,type);
}else{
admob.show(x,y,type);
}
}else{
trace(“not support”);
}
}

/**
*释放广告
*
*/
public function disposeAd():void{
var admob:Admob=Admob.getInstance();
admob.dispatcher.removeEventListener(AdEvent.onReceiveAd,this.adHandler);
admob.dispatcher.removeEventListener(AdEvent.onFailedToReceiveAd,this.ad2Handler);
admob.dispatcher.removeEventListener(AdEvent.onDismissScreen,c1Handler);
admob.dispatcher.removeEventListener(AdEvent.onPresentScreen,pressHandler);
admob.dispatcher.removeEventListener(AdEvent.onLeaveApplication,levelHandler);
admob.dispose();
isShowAd = false;
}

private function levelHandler(e:AdEvent):void
{
trace(“level”);
}

private function pressHandler(e:AdEvent):void
{
trace(“press”);

}

private function ad2Handler(e:AdEvent):void
{
trace(“fail”);
}

private function c1Handler(e:AdEvent):void
{
trace(“Dismiss”);
}

protected function adHandler(event:AdEvent):void
{
trace(“receive ad”);
isShowAd = true;
}
}
}
class Param{}

[/codesyntax] 广告类,还有待完善,有需要的朋友可以直接拿走,至于广告id,可以到admob上注册下,建个项目就有id了,很简单的。 下面说下,我用Admob的时候遇到的问题,我按照作者的方法,做了demo,广告却一直出不来,不知道怎么回事,折腾了好几天也没搞明白,在我近乎放弃admob的时候,终于发现原因了,原来是因为我的手机刷了rom,然后host文件了加了一万多条广告屏蔽记录,当然,admob的广告就显示不出来了,改了host,终于,看广告条了,鸡冻啊!!! 如果你的广告也显示不出来,不妨看下是不是host被屏蔽了,另外360之类的手机杀毒软件也有可能会屏蔽你的广告。 下面是广告的效果,我直接截图我的应用: 0 train2 下面再贴一些相关的资料,有需要的朋友: admobANE:(Andriod+ios)http://code.google.com/p/flash-for-mobile/ 作者建的群:56892018   感谢作者[珠峰看雪]的无私奉献! 我的应用:火车票查询 http://www.mumayi.com/android-264372.html(木蚂蚁),实时查询火车票的,有兴趣的朋友也可以看下。 ANE作者的一篇admob的使用文章: flash 加载admob广告ane  http://bbs.9ria.com/forum.php?mod=viewthread&tid=141414&fromuid=107509 还有一些其他的广告ANE:http://ane.qiow.net/ (这些没用过,有兴趣的朋友可以试试) 在使用广告的过程中有什么问题,也可以在此留言交流,抑或加作者的群一起讨论。

TexturePacker两三事

学习Starling,不可避免的涉及到素材格式的问题,虽然Flash CS6也可以导出Sprite sheet 但是,还是没有TexturePacker给力。TexturePacker功能还是蛮全面的,可以导出多种格式,不只限于Starling。 使用完整版的话需要激活码,不过可以免费得到,作者的建议是 就像我这样写个文章介绍下,今天已经收到了做着的激活码,虽然作者也说不是必须的,但是做人要厚道,还是帮作者写下,另外,这个工具也确实挺不错的,有些功能是Flash CS6不具备的,比如多张图片合并等。 TexturePackerICO 相关网址:http://www.codeandweb.com

starling 粒子系统学习(Particle-System)

学习Starling的粒子效果,做了个关于火柴燃烧效果的小应用。 火柴效果 主要代码如下: [codesyntax lang=”actionscript3”]

package
{
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;

import starling.core.Starling;
[SWF(width=”480”, height=”800”, frameRate=”60”, backgroundColor=”0x333333”)]
public class ParticlesTest extends Sprite
{
public function ParticlesTest()
{
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;

var myStarling:Starling = new Starling(Game,stage);
myStarling.showStats = true;
myStarling.start();
}
}
}

[/codesyntax] [codesyntax lang=”actionscript3”]

package
{
import starling.core.Starling;
import starling.display.Image;
import starling.display.Sprite;
import starling.events.Event;
import starling.events.TouchEvent;
import starling.extensions.PDParticleSystem;
import starling.extensions.ParticleSystem;
import starling.textures.Texture;

public class Game extends Sprite
{
[Embed(source=”../assets/match_fire.pex”, mimeType=”application/octet-stream”)]
private static const MatchFireConfig:Class;

[Embed(source=”../assets/match_fire.png”)]
private static const FirePng:Class;

[Embed(source=”../assets/match_begin.png”)]
private static const MatchBeginPng:Class;
[Embed(source=”../assets/match_ing.png”)]
private static const MatchIngPng:Class;
[Embed(source=”../assets/match_end.png”)]
private static const MatchEndPng:Class;

private var particleSystem:ParticleSystem;
private var matchBegin:Image;
private var matchIng:Image;
private var matchEnd:Image;
private var status:String;
private const STATUS_BEGIN:String = “BEGIN”;
private const STATUS_ING:String = “ING”;
private const STATUS_END:String = “END”;

public function Game()
{
addEventListener(Event.ADDED_TO_STAGE,addToStage);
}

private function addToStage(e:Event):void
{
this.matchBegin = new Image(Texture.fromBitmap(new MatchBeginPng()));
this.matchIng = new Image(Texture.fromBitmap(new MatchIngPng()));
this.matchEnd = new Image(Texture.fromBitmap(new MatchEndPng()));
addChild(matchBegin);
addChild(matchIng);
addChild(matchEnd);

var config:XML = XML(new MatchFireConfig());
var texture:Texture = Texture.fromBitmap(new FirePng());
this.particleSystem = new PDParticleSystem(config,texture);
particleSystem.stop();
addChild(particleSystem);
particleSystem.emitterX = 98;
particleSystem.emitterY = 140;
particleSystem.alpha = 0.5;
particleSystem.scaleX = particleSystem.scaleY = 2.5;
Starling.juggler.add(particleSystem);

addEventListener(TouchEvent.TOUCH,touchHandler);
this.status = STATUS_BEGIN;
updateStatus();
}

private function touchHandler(e:TouchEvent):void
{
if(status == STATUS_BEGIN){
status = STATUS_ING;
}else if(status ==STATUS_ING){
status = STATUS_END;
}else if(status ==STATUS_END){
status = STATUS_BEGIN;
}
updateStatus();
}

private function updateStatus():void{
this.matchBegin.visible = status ==STATUS_BEGIN;
this.matchIng.visible = status ==STATUS_ING;
this.matchEnd.visible = status ==STATUS_END;

if(status == STATUS_ING){
particleSystem.start();
}else{
particleSystem.pause();
}
}
}
}

[/codesyntax]   发布了一个apk,有Andriod的朋友可以试试,设定的60帧/s,最低会掉到30帧/s,没优化.(手机是htc g12的,480x800 如果手机屏幕不一样的话 可能坐标略有差别) 下载(apk): [download id=”14” format=”2”] 项目源码下载:[download id=”15”]  (环境: Flash Builder 4.7  两个类库(starling和particle system)没有打包,可以在下面的地址下载下) 相关学习资料: starling源码:https://github.com/PrimaryFeather/Starling-Framework 粒子系统:https://github.com/PrimaryFeather/Starling-Extension-Particle-System 粒子系统在线编辑器:http://onebyonedesign.com/flash/particleeditor/

贝塞尔曲线学习---QQ部落箭塔弓箭飞行模拟

本文部分素材来自QQ部落(http://bl.qq.com),仅作研究学习之用,如有侵权,请与本站联系。 SWF效果如下: 本实例用的是二次贝塞尔曲线,详情见代码。   逻辑类如下: [codesyntax lang=”php”]

package com.sqstudio.study.qqbl.archer
{
import com.sqstudio.study.util.Bezier;

import flash.display.Sprite;
import flash.display.Stage;
import flash.events.Event;
import flash.geom.Point;
/**
*QQ部落箭塔之弓箭飞行
* @author Nestor
* @website sqstudio.com
*
*/
public class ArcherStudy extends Sprite
{
private var arrow:UI_Arrow;
private var drawPathSp:Sprite;

private var startPoint:Point;

private var endPoint:Point;

private var controlPoint:Point;
private var tower:UI_Tower;
private var monster:UI_Monster;
private var steps:uint;
private var crtStep:int;
public function ArcherStudy()
{
//塔
tower = new UI_Tower();
tower.shooterLeft.stop();
tower.shooterRight.stop();
this.addChild(tower);
tower.x = 100;
tower.y = 150;

//怪
monster = new UI_Monster();
this.addChild(monster);
monster.x = 400;
monster.y = 300;
//箭头
this.arrow = new UI_Arrow();
this.addChild(arrow);
//初始化数据
startPoint = new Point(tower.x,tower.y-30);
controlPoint = new Point(monster.x-200,tower.y-130);
endPoint = new Point(monster.x,monster.y-20);
steps = Bezier.init(startPoint,controlPoint,endPoint,8);
this.crtStep = 0;//当前步

this.addEventListener(Event.ENTER_FRAME,loopEfHandler);
//路径绘制SP
drawData();
}
/**
*循环帧频函数
* @param e
*
*/
private function loopEfHandler(e:Event):void
{
var tmpArr:Array = Bezier.getAnchorPoint(crtStep);
arrow.x = tmpArr[0];
arrow.y = tmpArr[1];
arrow.rotation = tmpArr[2];
this.crtStep++;
if(crtStep>steps){
crtStep=0;
if(Math.random()>0.5){
tower.shooterLeft.gotoAndPlay(2);
}else{
tower.shooterRight.gotoAndPlay(2);
}
}
}
/**
*绘制路线
*
*/
private function drawData():void{
this.drawPathSp = new Sprite();
this.addChild(drawPathSp);
drawPathSp.graphics.lineStyle(1,0,0.5);
drawPathSp.graphics.moveTo(startPoint.x, startPoint.y);
drawPathSp.graphics.curveTo(controlPoint.x, controlPoint.y,endPoint.x, endPoint.y);
drawPathSp.graphics.endFill();
drawP(startPoint);
drawP(endPoint);
drawP(controlPoint);
drawPathSp.graphics.moveTo(startPoint.x,startPoint.y);
drawPathSp.graphics.lineTo(endPoint.x,endPoint.y);
drawPathSp.graphics.lineTo(controlPoint.x,controlPoint.y);
drawPathSp.graphics.lineTo(startPoint.x,startPoint.y);
}
/**
*生成顶点
* @param p
* @param type
* @return
*
*/
public function drawP(p:Point):Sprite{
var sp:Sprite = new Sprite();
this.addChild(sp);
sp.graphics.beginFill(0xffffff*Math.random());
sp.graphics.drawCircle(0,0,4);
sp.graphics.endFill();
sp.x = p.x;
sp.y = p.y;
return sp;

}
}
}

[/codesyntax]   实例中,怪物的位置是固定,贝塞尔曲线的控制点也是手动调整的,这两个因素在实际游戏中是不一样的,尤其是控制的点,也应该有计算公式,具体的算法就留待你来扩展了,具体表现效果可以到QQ部落游戏中去体验(声明,我不是托儿,QQ部落也是抄袭国外一款塔防游戏的Kingdom Rush) 工具类(来自网上,略作整理): [codesyntax lang=”php”]

package com.sqstudio.study.util
{
import flash.geom.Point;

public class Bezier
{

// ===================================== 属性

// 对外变量
private static var p0:Point;// 起点
private static var p1:Point;// 控制点
private static var p2:Point;// 终点
private static var step:uint;// 分割份数

// 辅助变量
private static var ax:int;
private static var ay:int;
private static var bx:int;
private static var by:int;

private static var A:Number;
private static var B:Number;
private static var C:Number;

private static var total_length:Number;// 长度

// ===================================== 方法

// 速度函数
private static function s (t:Number):Number
{
return Math.sqrt(A * t * t + B * t + C);
}

// 长度函数
private static function L (t:Number):Number
{
var temp1:Number = Math.sqrt(C + t * (B + A * t));
var temp2:Number = (2 * A * t * temp1 + B *(temp1 - Math.sqrt(C)));
var temp3:Number = Math.log(B + 2 * Math.sqrt(A) * Math.sqrt(C));
var temp4:Number = Math.log(B + 2 * A * t + 2 * Math.sqrt(A) * temp1);
var temp5:Number = 2 * Math.sqrt(A) * temp2;
var temp6:Number = (B * B - 4 * A * C) * (temp3 - temp4);

return (temp5 + temp6) / (8 * Math.pow(A, 1.5));
}

// 长度函数反函数,使用牛顿切线法求解
private static function InvertL (t:Number, l:Number):Number
{
var t1:Number = t;
var t2:Number;
do
{
t2 = t1 - (L(t1) - l)/s(t1);
if (Math.abs(t1-t2) < 0.000001) break;
t1 = t2;
}while(true);
return t2;
}

// ===================================== 封装

// 返回所需总步数
/**
*获得所需步数
* @param $p0
* @param $p1
* @param $p2
* @param $speed
* @return
*
*/
public static function init ($p0:Point, $p1:Point, $p2:Point, $speed:Number):uint
{
p0 = $p0;
p1 = $p1;
p2 = $p2;
//step = 30;

ax = p0.x - 2 * p1.x + p2.x;
ay = p0.y - 2 * p1.y + p2.y;
bx = 2 * p1.x - 2 * p0.x;
by = 2 * p1.y - 2 * p0.y;

A = 4*(ax * ax + ay * ay);
B = 4*(ax * bx + ay * by);
C = bx * bx + by * by;

// 计算长度
total_length = L(1);

// 计算步数
step = Math.floor(total_length / $speed);
if (total_length % $speed > $speed / 2)step ++;

return step;
}

// 根据指定nIndex位置获取锚点:返回坐标和角度
public static function getAnchorPoint (nIndex:Number):Array
{
if (nIndex >= 0 && nIndex <= step)
{
var t:Number = nIndex/step;
// 如果按照线行增长,此时对应的曲线长度
var l:Number = t*total_length;
// 根据L函数的反函数,求得l对应的t值
t = InvertL(t, l);

// 根据贝塞尔曲线函数,求得取得此时的x,y坐标
var xx:Number = (1 - t) * (1 - t) * p0.x + 2 * (1 - t) * t * p1.x + t * t * p2.x;
var yy:Number = (1 - t) * (1 - t) * p0.y + 2 * (1 - t) * t * p1.y + t * t * p2.y;

// 获取切线
var Q0:Point = new Point((1 - t) * p0.x + t * p1.x, (1 - t) * p0.y + t * p1.y);
var Q1:Point = new Point((1 - t) * p1.x + t * p2.x, (1 - t) * p1.y + t * p2.y);

// 计算角度
var dx:Number = Q1.x - Q0.x;
var dy:Number = Q1.y - Q0.y;
var radians:Number = Math.atan2(dy, dx);
var degrees:Number = radians * 180 / Math.PI;

return new Array(xx, yy, degrees);
}
else
{
return [];
}
}
}
}

[/codesyntax] 延伸阅读:http://zh.wikipedia.org/zh-cn/%E8%B4%9D%E5%A1%9E%E5%B0%94%E6%9B%B2%E7%BA%BF