[转载]flex 联机游戏开发 - 中国象棋游戏:(一)核心逻辑

mikel阅读(979)

[转载]flex 联机游戏开发 – 中国象棋游戏:(一)核心逻辑 – 博弈居 – 开放的第三方应用游戏开发测试平台 – 博客园.

在开发四国军棋的游戏中,通过 flex联机游戏开发- 四国军棋游戏(五)-提炼棋类开发api,我们提炼出了第一个关于棋类游戏开发的api-FlexChessAPI,这个api设计的方针就是基于状态机 与事件驱动的flex主要机制,使开发工作简洁易行。现在,我们第一次使用这个api来开发一款中国象棋游戏,对一个成熟的开发工作者来说,我相信,你大 概只需要半天时间就可以让这个象棋游戏运作起来。

现在,我们将中国象棋的逻辑出来。

1)中国象棋由9*10个方格,与四国军棋不同,棋子本身并无行棋路线,

也就是说我们只需要简单扩展ipostion 形成posiitonVO类即可

2)中国象棋的棋子本身无大小,但每个子有自己的行棋路线,吃子的方式是目标子正好处于该子的行棋路线上,另外,其它的子的行为会对目标子的行棋路线造成影响。

也就是说,不论是移动,吃子等,我们都无法立即获得该子的可移动路线,只有等对方行完棋后才能确定行棋路线,所以我们选择的计算行棋路线的方式应该定位在 选中源棋子的时候。

下面,我设计一个ChinaChessHelp类,类中的所有方法与变量都是静态类。

2.1 列出所有棋子,(注意,红方的相与黑方的象不但显示名称不同,行棋路线也不同,这样,我就将他们处理成两上不同的棋子),至于棋子的值,并不重要,只是一个区别作用。

//棋子
public static const PIECE_RED_CHE:int=56;
public static const QIZHI_RED_MA:int=57;
public static const QIZHI_RED_XIAN:int=58;
public static const QIZHI_RED_SHI:int=59;
public static const QIZHI_RED_JIAN:int=60;
public static const QIZHI_RED_BING:int=55;
public static const QIZHI_RED_PAO:int=54;

public static const PIECE_BLACK_CHE:int=156;
public static const QIZHI_BLACK_MA:int=157;
public static const QIZHI_BLACK_XIAN:int=158;
public static const QIZHI_BLACK_SHI:int=159;
public static const QIZHI_BLACK_SUAN:int=160;
public static const QIZHI_BLACK_ZHU:int=155;
public static const QIZHI_BLACK_PAO:int=154;

2.2 设计棋子的移动路线,这是中国象棋最核心的逻辑。请参与这个图,我设计出每个子的行棋路线,对于一些行棋路线有限而且透明的棋子,我直接索引出值(如士, 象,师),对一些行棋路线不确定的棋子,我们计算出他的行棋路线,如车,马,炮等。所有的索引请参照下面这个图像(棋盘的绘制我在下一节将讲到)。

2.2.1 函数 initMoveRedJian():ArrayCollection

将的行棋路线 用switch case来描述就是如下

/**
* 紅方將的行棋路線
* @param posindex
* @return
*
*/
public static function initMoveRedJian(posindex:int):ArrayCollection{
var temp:ArrayCollection;
switch(posindex){
case 3:
temp=new ArrayCollection([4,12]);
break;
case 4:
temp=new ArrayCollection([3,5,13]);
break;
case 5:
temp=new ArrayCollection([4,14]);
break;
case 12:
temp=new ArrayCollection([3,13,21]);
break;
case 13:
temp=new ArrayCollection([4,12,14,22]);
break;
case 14:
temp=new ArrayCollection([5,13,23]);
break;
case 21:
temp=new ArrayCollection([12,22]);
break;
case 22:
temp=new ArrayCollection([13,21,23]);
break;
case 23:
temp=new ArrayCollection([14,22]);
break;
default:
break;
}
return temp;
}

2.2.2 函数 initMoveRedShi():ArrayCollection

士的行棋路线 用switch case来描述就是如下

/**
* 紅方士的行棋路線
* @param posindex
* @return
*
*/
public static function initMoveRedShi(posindex:int):ArrayCollection{
var temp:ArrayCollection;
switch(posindex){
case 3:
temp=new ArrayCollection([13]);
break;
case 5:
temp=new ArrayCollection([13]);
break;
case 13:
temp=new ArrayCollection([3,5,21,23]);
break;
case 21:
temp=new ArrayCollection([13]);
break;
case 23:
temp=new ArrayCollection([13]);
break;
default:
break;
}
return temp;
}

逻辑是这样,但上面的写法是错误的,flex中当数组只有一个元素时,最好不要直接用arraycollection进行初始化。您可以修改一下:)

2.2.3 红方象的行棋路线 initMoveRedXian

/**
* 紅方象的行棋路線
* 注意蹩脚路线。
* @param posindex
* @return
*
*/
public static function initMoveRedXian(posindex:int,pieceMap:HashMap):ArrayCollection{
var temp:ArrayCollection=new ArrayCollection();
switch(posindex){
case 2:
if ((pieceMap.get(10) as PieceVO).deskpos==-1)
temp.addItem(18);
if ((pieceMap.get(12) as PieceVO).deskpos==-1)
temp.addItem(22);
break;
case 6:
if ((pieceMap.get(14) as PieceVO).deskpos==-1)
temp.addItem(22);
if ((pieceMap.get(16) as PieceVO).deskpos==-1)
temp.addItem(26);
break;
case 18:
if ((pieceMap.get(10) as PieceVO).deskpos==-1)
temp.addItem(2);
if ((pieceMap.get(28) as PieceVO).deskpos==-1)
temp.addItem(38);
break;
case 22:
if ((pieceMap.get(12) as PieceVO).deskpos==-1)
temp.addItem(2);
if ((pieceMap.get(14) as PieceVO).deskpos==-1)
temp.addItem(6);
if ((pieceMap.get(30) as PieceVO).deskpos==-1)
temp.addItem(38);
if ((pieceMap.get(32) as PieceVO).deskpos==-1)
temp.addItem(42);
break;
case 26:
if ((pieceMap.get(16) as PieceVO).deskpos==-1)
temp.addItem(6);
if ((pieceMap.get(34) as PieceVO).deskpos==-1)
temp.addItem(42);

break;
case 38:
if ((pieceMap.get(28) as PieceVO).deskpos==-1)
temp.addItem(18);
if ((pieceMap.get(30) as PieceVO).deskpos==-1)
temp.addItem(22);
break;
case 42:
if ((pieceMap.get(32) as PieceVO).deskpos==-1)
temp.addItem(22);
if ((pieceMap.get(34) as PieceVO).deskpos==-1)
temp.addItem(26);
break;
default:
break;
}
return temp;
}

2.2.4 红方兵的行棋路线 public static function initMoveRedBing():ArrayCollection

注意的是,并没有过河时,只能向前走,过河后则可以有三个位置可以走。

利用posindex的值进行判断

/**
* 紅方并的行棋路線
* @param posindex
* @return
*
*/
public static function initMoveRedBing(posindex:int,pieceMap:HashMap):ArrayCollection{
var temp:ArrayCollection=new ArrayCollection();
if (posindex%9-1>=0&&posindex>=45) temp.addItem(posindex-1);
if (posindex%9+1<9&&posindex>=45) temp.addItem(posindex+1);
if (posindex+9<90) temp.addItem(posindex+9);
return temp;
}

2.2.5 马的行棋路线 public static function initMoveRedBing():ArrayCollection

车,马,炮属于自由移动棋子,对红黑双方是对等存在,所以可以使用公用函数进行处理。

马的游戏逻辑主要就是判断目标点位是否在棋盘中以及是不是有蹩脚点位存在。

/**
* 马的行棋路線
* 每个马有八个行棋位置,有四个蹩脚点位,
* @param posindex
* @return
*
*/
public static function initMoveMa(posindex:int,pieceMap:HashMap):ArrayCollection{
var temp:ArrayCollection=new ArrayCollection();

//左方向
if (posindex%9-2>=0) {
if ((pieceMap.get(posindex-1) as PieceVO).deskpos==-1)
{
if ((posindex-11)>=0)
{
temp.addItem(posindex-11);
}
if ((posindex+7)<89)
{
temp.addItem(posindex+7);
}

}
}
//右方向
if (posindex%9+2<9) {

if ((pieceMap.get(posindex+1) as PieceVO).deskpos==-1)
{
if ((posindex-7)>=0)
{
temp.addItem(posindex-7);
}
if ((posindex+11)<89)
{
temp.addItem(posindex+11);
}

}
}
//上方向
if (posindex-18>=0) {
if ((pieceMap.get(posindex-9) as PieceVO).deskpos==-1)
{
if ((posindex-19)%9<posindex%9)
{
temp.addItem(posindex-19);
}
if ((posindex-17)%9>posindex%9)
{
temp.addItem(posindex-17);
}

}
}
//下方向
if (posindex+18<90) {
if ((posindex+19)%9>posindex%9)
{
temp.addItem(posindex+19);
}
if ((posindex+17)%9<posindex%9)
{
temp.addItem(posindex+17);
}
}
return temp;
}

2.2.6 车的行棋路线

车的行棋逻辑就是查看四个方向是否有空的位置,如果找到一个棋子,则结束寻找,将当前找到的棋子也加入索引。

/**
* 车的行棋路線
* @param posindex
* @return
*
*/
public static function initMoveChe(posindex:int,pieceMap:HashMap):ArrayCollection{
var temp:ArrayCollection=new ArrayCollection();
//模方向
for (var xr:int=posindex%9+1;xr<9;xr++)
{
if ((pieceMap.get(posindex+xr-posindex%9) as PieceVO).deskpos==-1)
{
temp.addItem(posindex+xr-posindex%9);
}
else
{
//将找到最后一子的位置也加入
temp.addItem(posindex+xr-posindex%9);
break;
}
}
for (var xl:int=posindex%9-1;xl>=0;xl–)
{
if ((pieceMap.get(posindex+xl-posindex%9) as PieceVO).deskpos==-1)
{
temp.addItem(posindex+xl-posindex%9);
}
else
{
temp.addItem(posindex+xl-posindex%9);
break;
}
}
//竖方向
for (var yb:int=Math.floor(posindex/9)+1;yb<10;yb++)
{
if ((pieceMap.get(posindex+9*(yb-Math.floor(posindex/9))) as PieceVO).deskpos==-1)
{
temp.addItem(posindex+9*(yb-Math.floor(posindex/9)));
}
else
{
temp.addItem(posindex+9*(yb-Math.floor(posindex/9)));
break;
}
}
for (var yt:int=Math.floor(posindex/9)-1;yt>=0;yt–)
{
if ((pieceMap.get(posindex+9*(yt-Math.floor(posindex/9))) as PieceVO).deskpos==-1)
{
temp.addItem(posindex+9*(yt-Math.floor(posindex/9)));
}
else
{
temp.addItem(posindex+9*(yt-Math.floor(posindex/9)));
break;
}
}
return temp;
}

2.2.7 炮的行棋路线

炮的行棋路线相对复杂些,不过也很好处理,基本情况与车相同,只不过当你在某一方向找到第一个棋子后,设置一个判断,判断为找到一个棋子后,对空余的位置不再添加,则再找第二个棋子,如果找到第二个棋子,将第二个棋子加入索引

/**
* 炮的行棋路線
* @param posindex
* @return
*
*/
public static function initMovePao(posindex:int,pieceMap:HashMap):ArrayCollection{
var temp:ArrayCollection=new ArrayCollection();

//模方向
var findOne:Boolean=false;
for (var xr:int=posindex%9+1;xr<9;xr++)
{
if ((pieceMap.get(posindex+xr-posindex%9) as PieceVO).deskpos==-1)
{
if (!findOne)
temp.addItem(posindex+xr-posindex%9);
}
else
{
if (!findOne)
{
findOne=true;
continue;
}
else
{
//将找到子的下一子的位置也加入
temp.addItem(posindex+xr-posindex%9);
break;
}

}
}
findOne=false;
for (var xl:int=posindex%9-1;xl>=0;xl–)
{
if ((pieceMap.get(posindex+xl-posindex%9) as PieceVO).deskpos==-1)
{
if (!findOne)
temp.addItem(posindex+xl-posindex%9);
}
else
{
if (!findOne)
{
findOne=true;
continue;
}
else
{
//将找到子的下一子的位置也加入
temp.addItem(posindex+xl-posindex%9);
break;
}

}
}
//竖方向
findOne=false;
for (var yb:int=Math.floor(posindex/9)+1;yb<10;yb++)
{
if ((pieceMap.get(posindex+9*(yb-Math.floor(posindex/9))) as PieceVO).deskpos==-1)
{
if (!findOne)
temp.addItem(posindex+9*(yb-Math.floor(posindex/9)));
}
else
{
if (!findOne)
{
findOne=true;
continue;
}
else
{
//将找到子的下一子的位置也加入
temp.addItem(posindex+9*(yb-Math.floor(posindex/9)));
break;
}

}
}
findOne=false;
for (var yt:int=Math.floor(posindex/9)-1;yt>=0;yt–)
{
if ((pieceMap.get(posindex+9*(yt-Math.floor(posindex/9))) as PieceVO).deskpos==-1)
{
if (!findOne)
temp.addItem(posindex+9*(yt-Math.floor(posindex/9)));
}
else
{
if (!findOne)
{
findOne=true;
continue;
}
else
{
//将找到子的下一子的位置也加入
temp.addItem(posindex+9*(yt-Math.floor(posindex/9)));
break;
}

}
}
return temp;
}

3)中国象棋的游戏控制引擎与四国军棋并无太大差异,我们在扩展 BaseGameEngine 后,只需要覆写 CheckWin()方法,就基本可以完成大量的工作。当然,别忘了棋盘不家个初始布局,我们只需要设计一个静态布局与一个初始化方法即可。

//默认的棋盘布局
private const DEFAULT_LAYOUT:Array=[56,57,58,59,60,59,58,57,56,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,54,-1,-1,-1,-1,-1,54,-1,55,-1,55,-1,55,-1,55,-1,55,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,155,-1,155,-1,155,-1,155,-1,155,-1,154,-1,-1,-1,-1,-1,154,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,156,157,158,159,160,159,158,157,156];

public function initLayout():void{
for (var i:int=0;i<this.DEFAULT_LAYOUT.length;i++)
{
var pieceVO:PieceVO=pieceMap.get(i) as PieceVO;
pieceVO.value=DEFAULT_LAYOUT[i];
if (int(DEFAULT_LAYOUT[i])>0&&int(DEFAULT_LAYOUT[i])<100)
{
pieceVO.deskpos=getNextPlayer(1).deskpos;
}
else if (int(DEFAULT_LAYOUT[i])>=100)
{
pieceVO.deskpos=currentDeskpos;
}
}
}

在完成以上这些逻辑工作后,得到的结果就是下面这个,这个是点击炮后我们可以清楚地看到行棋路线索引。

核心逻辑基本就是这些,在这个寒冷的冬天里,我打算利用这些时间开发与优化一些有趣的棋牌类游戏,我的下一个目标是扎金花游戏,这是一个牌类游戏, 我打算接着写一个flexcardapi,当然,本文的下一节我将提供中国象棋的扩展类的设计与显示设计。如果时间允许的话,会很快,当然,如果您是一名 flex开发者,您也可以直接给我发消息,让您来完成下面的开发,我会把已经完成的设计工作教给你,您也可以学会如何使用这个api,我相信,您会找到乐 趣的,您也可以开发一些更简单或复杂的游戏,如乖三棋,动物棋,或者跳棋。

[转载]Silverlight+WCF 实战-网络象棋最终篇之解决重复的消息提示(八)

mikel阅读(899)

[转载]Silverlight+WCF 实战-网络象棋最终篇之解决重复的消息提示(八) – 路过秋天 – 博客园.

前言:

最近有网友经常会问,在跟着做象棋对战的通讯中,在重复退出进入的时候,消息会重复出现,本节就这问题进行解说与优化。

一:分析问题产生的原因?

1:首先看App.xaml,里面定义了一个全局客户端回调:

public static GameService.ServiceClient client;//回调的客户端

并且这个回调我们全局只实例化一次,并且默认加载时定位到登陆页面:

private void Application_Startup(object sender, StartupEventArgs e)
{
this.RootVisual = root;
root.Children.Add(
new Login());//默认定位到登录页面。
}

2:再看登录页面Login.xaml里,构造函数的初始化:

public Login()
{
InitializeComponent();
App.client.LoginCompleted
+= new EventHandler<System.ComponentModel.AsyncCompletedEventArgs>(client_LoginCompleted);
Load();
}

我们对App.client.LoginCompleted初始化了一次事件,这时一切是正常的,接着我们进入房间,之后,我们返回系统回到登陆。

3:接着看退出系统的按钮是怎么返回到登陆页面的:

//退出系统
private void btnLogout_Click(object sender, RoutedEventArgs e)
{
if (App.chess.IsGaming)
{
btnGameLose_Click(
null, null);//发送认输
App.chess.IsGaming = false;
}
App.client.OutRoomAsync(App.player, App.player.RoomID, App.player.AttachInfo);
((App)Application.Current).RedirectTo(
new Login());
}

看最后一行,我们又New Login了,这种情况,刚才第二步中的:App.client.LoginCompleted事件将被重复注册,因此,重复的事件注册引发了重复的消息提示。

问题总结说明:

对于消息的重复提示,基本都属于事件的重复注册造成的,我们之前的代码很多转向都使用new 控件()的方式在各个页面切换时,于是容易产生这种问题。

二:解决消息重复问题

从第一步中,我们分析到问题产生的根源,于是,我们可以想出很多方式,来解决这种问题,这里我介绍两种方式:

先来看一下错误任法:注册事件前加先减,再加,示例代码如下:

App.client.LoginCompleted -= new EventHandler<System.ComponentModel.AsyncCompletedEventArgs>(client_LoginCompleted);
App.client.LoginCompleted
+= new EventHandler<System.ComponentModel.AsyncCompletedEventArgs>(client_LoginCompleted);

网上有人说:每次注册前先去掉一下,然后再增加,逻辑上看起来好像没问题,刚自己试了下,纯忽悠型。

现在介绍下我想到的两种方式:

1:定义全局变量List<事件名称>,保存注册过的事件名称

逻辑:在每次事件产生前,先判断一下事件是否存在,不存在则添加,存在则跳过,此方法实现简单,大伙一说就应该会了,所以直接跳过了。

2:定义全局变量保存所有房间,于是在RedirectTo切换房间的时候,避免使用New 控件() 来避免再次执行事件注册事件

下面进行代码整改:

A:App.xaml全局定义每个房间的变量,并改造成属性,所幸控件就几个,定义也费不了多少力,代码如下:

private static Login loginObj;
public static Login LoginObj
{
get
{
if (loginObj == null)
{
loginObj
= new Login();
}
//loginObj.Reset();
return loginObj;
}
}
private static Room roomObj;
public static Room RoomObj
{
get
{
if (roomObj == null)
{
roomObj
= new Room();
}
//roomObj.Reset();
return roomObj;
}
}
private static Index indexObj;
public static Index IndexObj
{
get
{
if (indexObj == null)
{
indexObj
= new Index();
}
//indexObj.Reset();
return indexObj;
}
}

说明:

这里有两点:1是改造属性方式,这样在调用时不用再写判断语句,2是注册的Reset()方法,后面会开启到。

B:查找调用RedirectTo切换界面的代码,替换为:App.xxxxObj

随便找个RedirectTo,右键查找所有引用,看看有几个要修改的地方,所幸也不多,如下图:

说明:

按上面的查找出来的代码,一个一个更改即可,如把new Index()换成App.IndexObj。

OK,消息提示重复的问题,至此,是解决了,但是,将产生一点副作用,就是切回去的时候,状态需要重置。

简单的示例说明就是:

点登陆时,把按钮设置为不可用,然后你进去,再退出,看到的是“不可用”的按钮就没法再进去了。

OK,状态重置的问题,就留到下节解决了。

本节没关联啥好看图片,就随便挂一张在下面让大伙欣赏了:

[转载]android开发我的新浪微博客户端-OAuth篇(2.1)

mikel阅读(938)

[转载]android开发我的新浪微博客户端-OAuth篇(2.1) – 遇见未知的自己 – 博客园.

本篇说说关于OAuth授权认证的事情,新浪开放api都必须在这个基础上才能调用,所以有必要专门来讲讲,前面的文章中已经提到过关于新浪微博提供了 OAuth和Base OAuth两种认证方式,并且本项目采用OAuth认证方式,至于为什么采用这个OAuth认证而不采用Base OAuth认证原因很简单,自从Twitter只支持OAuth认证方式以来,各大应用都纷纷转向OAuth认证方式,而新浪微博的开放平台也将在近日停 止Base OAuth的认证方式。

OAuth的基本概念,OAUTH协议为用户资源的授权提供了一个安全的、开放而又简易的标准。与以往的授权方式不同之处是OAUTH的授权不会使第 三方触及到用户的帐号信息(如用户名与密码),即第三方无需使用用户的用户名与密码就可以申请获得该用户资源的授权,因此OAUTH是安全的。同样新浪微 博提供OAuth认证也是为了保证用户账号和密码的安全,在这里通过OAuth建立普通新浪微博用户、客户端程序(我们正在开发的这个Android客户 端程序)、新浪微博三者之间的相互信任关系,让客户端程序(我们正在开发的这个Android客户端程序)不需要知道用户的账号和密码也能浏览、发布微 博,这样有效的保护了用户账号的安全性不需要把账号密码透露给客户端程序又达到了通过客户端程序写微博看微博目的。这个是OAuth的作用。

结合新浪微博的OAuth认证来说说具体的功能实现,首先罗列一下关键字组,下面四组关键字跟我们接下来OAuth认证有非常大的关系。

第一组:(App Key和App Secret),这组参数就是本系列文本第一篇提到的建一个新的应用获取App Key和App Secret。

第二组:(Request Token和Request Secret)

第三组:(oauth_verifier

第四组:(user_id、Access Token和Access Secret)

新浪微博的OAuth认证过程,当用户第一次使用本客户端软件时,客户端程序用第一组作为参数向新浪微博发起请求,然后新浪微博经过验证后返回第二组参数给客户端软件同时表示新浪微博信任本客户端软件,当客户端软件获取第二组参数时作为参数引导用户浏览器跳至新浪微博的授权页面, 然后用户在新浪的这个授权页面里输入自己的微博账号和密码进行授权,完成授权后根据客户端设定的回调地址把第三组参数返回给客户端软件并表示用户也信任本 客户端软件,接下客户端软件把第二组参数和第三组参数作为参数再次向新浪微博发起请求,然后新浪微博返回第四组参数给客户端软件,第四组参数需要好好的保 存起来这个就是用来代替用户的新浪账号和密码用的,在后面调用api时都需要。从这个过程来看用户只是在新浪微博的认证网页输入过账户和密码并没有在客户 端软件里输入过账户和密码,客户端软件只保存了第四组数据并没有保存用户的账户和密码,这样有效的避免了账户和密码透露给新浪微博之外的第三方应用程序, 保证 了安全性。

本项目用为了方便开发采用了oauth-signpost开源项目进行OAuth认证开发,新建OAuth.java 类文件对OA进行简单的封装,OAuth类主要有RequestAccessToken、GetAccessToken、SignRequest三个方 法,第一个方法RequestAccessToken就是上面过程中用来获取第三组参数用的,GetAccessToken方法是用来获取第四组参数 用,SignRequest方法是用来调用api用。由于采用了oauth-signpost开源项目简单了很多。具体代码如下:

代码

public class OAuth {
private CommonsHttpOAuthConsumer httpOauthConsumer;
private OAuthProvider httpOauthprovider;
public String consumerKey;
public String consumerSecret;

public OAuth()
{
// 第一组:(App Key和App Secret)
// 这组参数就是本系列文本第一篇提到的建一个新的应用获取App Key和App Secret。
this(3315495489,e2731e7grf592c0fd7fea32406f86e1b);
}
public OAuth(String consumerKey,String consumerSecret)
{
this.consumerKey=consumerKey;
this.consumerSecret=consumerSecret;
}

public Boolean RequestAccessToken(Activity activity,String callBackUrl){
Boolean ret
=false;
try{
httpOauthConsumer
= new CommonsHttpOAuthConsumer(consumerKey,consumerSecret);
httpOauthprovider
= new DefaultOAuthProvider(http://api.t.sina.com.cn/oauth/request_token,http://api.t.sina.com.cn/oauth/access_token,http://api.t.sina.com.cn/oauth/authorize);
String authUrl
= httpOauthprovider.retrieveRequestToken(httpOauthConsumer, callBackUrl);
activity.startActivity(
new Intent(Intent.ACTION_VIEW, Uri.parse(authUrl)));
ret
=true;
}
catch(Exception e){
}
return ret;
}

public UserInfo GetAccessToken(Intent intent){
UserInfo user
=null;
Uri uri
= intent.getData();
String verifier
= uri.getQueryParameter(oauth.signpost.OAuth.OAUTH_VERIFIER);
try {
httpOauthprovider.setOAuth10a(
true);
httpOauthprovider.retrieveAccessToken(httpOauthConsumer,verifier);
}
catch (OAuthMessageSignerException ex) {
ex.printStackTrace();
}
catch (OAuthNotAuthorizedException ex) {
ex.printStackTrace();
}
catch (OAuthExpectationFailedException ex) {
ex.printStackTrace();
}
catch (OAuthCommunicationException ex) {
ex.printStackTrace();
}
SortedSet
<String> user_id= httpOauthprovider.getResponseParameters().get(user_id);
String userId
=user_id.first();
String userKey
= httpOauthConsumer.getToken();
String userSecret
= httpOauthConsumer.getTokenSecret();
user
=new UserInfo();
user.setUserId(userId);
user.setToken(userKey);
user.setTokenSecret(userSecret);
return user;
}

public HttpResponse SignRequest(String token,String tokenSecret,String url,List params)
{
HttpPost post
= new HttpPost(url);
//HttpClient httpClient = null;
try{
post.setEntity(
new UrlEncodedFormEntity(params,HTTP.UTF_8));
}
catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
//关闭Expect:100-Continue握手
//100-Continue握手需谨慎使用,因为遇到不支持HTTP/1.1协议的服务器或者代理时会引起问题
post.getParams().setBooleanParameter(CoreProtocolPNames.USE_EXPECT_CONTINUE, false);
return SignRequest(token,tokenSecret,post);
}

public HttpResponse SignRequest(String token,String tokenSecret,HttpPost post){
httpOauthConsumer
= new CommonsHttpOAuthConsumer(consumerKey,consumerSecret);
httpOauthConsumer.setTokenWithSecret(token,tokenSecret);
HttpResponse response
= null;
try {
httpOauthConsumer.sign(post);
}
catch (OAuthMessageSignerException e) {
e.printStackTrace();
}
catch (OAuthExpectationFailedException e) {
e.printStackTrace();
}
catch (OAuthCommunicationException e) {
e.printStackTrace();
}
//取得HTTP response
try {
response
= new DefaultHttpClient().execute(post);
}
catch (ClientProtocolException e) {
e.printStackTrace();
}
catch (IOException e) {
e.printStackTrace();
}
return response;
}
}

这样就完成了OAuth功能类的开发,后面都会用到这个类相关的方法。本篇到这里就算是完结请继续关注后面的文章。

[转载]QQ协议辅助分析工具(QQAnalyzer)

mikel阅读(2223)

[转载]QQ协议辅助分析工具(QQAnalyzer) – shiqishe – 博客园.

最近研究了一把QQ的通讯协议,发现没有什么好的分析工具,特别是在抓包处理这一块上。所以自己写了个比较方便的工具。

软件写得比较粗糙,BUG还不少,欢迎试用。有什么问题可以发邮件给我修改。

下载地址:http://u.115.com/file/f77cbe0dbe

本软件用于辅助分析QQ协议。

软件能够自动识别并抓取QQ数据包,自动分析QQ登录过程数据包。支持QQ UDP、TCP、代理模式的数据包抓取与分析。

同时支持wireshark抓取的PCAP数据格式文件的读取。

使用方法:

1.启动QQAnalyzer,点击“抓包设置”按钮设置抓包使用的网卡及过滤器。

2.抓包设置确定后,任务栏的“开始抓包”按钮已激活。点击开始抓取数据包,打开QQ软件并登录,软件会自动识别QQ的数据包并过滤掉不需要的数据包,抓取的数据包会实时显示在软件界面上,包括协议,IP地址,端口等五元组信息。

3.停止抓包后,即可分析抓取的数据包了。QQ登录过程中有很多次密钥生成和传递,为方便分析,可以标记不同的密钥,并在需要的时刻使用这些密钥,最新版本的QQAnalyzer已经

完成了自动分析功能。可以在需要的分析的数据包点右键,直接选择自动分析。

4.需要使用已标记的密钥解密时可以直接使用。解密后的数据会突出已红色显示。当选择自动分析后,程序会自动分析当前QQ数据包的命令,并将其密文解密出来,

将相关信息直接批注在密文后面。

5.软件可将当前数据保存为RTF或TXT或者PCAP格式。方便下次接着处理。同时支持PCAP,TXT,RFT格式文件读取。

6.软件提供专门的TEA加解密模块,以及各种字符串编解码、MD5计算、QQ十六进制、IP十六进制、时间十六进制相互转换等功能。

7.QQAnalyzer最新版本为1.3.0.0,欢迎下载试用。

[转载]asp.net文本编辑器FCKeditor使用方法详解

mikel阅读(1059)

[转载]asp.net文本编辑器FCKeditor使用方法详解 – 记录.net – 博客园.

效果图:

那么为什么说是FCKeditor的冰冷之心呢?这不是哗众取宠,主要是说它使用起来有点麻烦,下文就详细说明如何搞定这玩意儿。

1.FCKeditor的官方网站是:http://www.fckeditor.net/download
目前最新的FCKeditor 2.4.2版本。
请在此页下载:http://sourceforge.net/project/showfiles.php?group_id=75348
如图所示:

要下载FCKeditor2.4.2.zip和   FCKeditor.NET版的2个zip包。

说明:
FCKeditor2.4.2.zip是其最新的JavaScript文件和图片什么的;
FCKeditor.NET.zip是ASP.NET调用的DLL在里面。

2.分别解压后把FCKeditor2.4.2.zip里的fckeditor目录整个复制到网站中。

3.解压FCKeditor.NET.zip包后在FCKeditor.Net_2.2\bin\Debug目录里找到FredCK.FCKeditorV2.dll。其他文件没用,把FredCK.FCKeditorV2.dll复制到我们的网站,建立一个Bin目录

4.引用FredCK.FCKeditorV2.dll。
第一步:

第二步:

5.导入工具箱。
在“工具箱”下右键

点击“选择项”。弹出如图窗口:

点击浏览,找到dll所在目录。

这时发现工具箱里多出FCKeditor控件。

6.拖拽FCKeditor到页面上

7.配置WebConfig
<?xml version=”1.0″?>
<!–
注意: 除了手动编辑此文件以外,您还可以使用
Web 管理工具来配置应用程序的设置。可以使用 Visual Studio 中的
“网站”->“ASP.NET 配置”选项。
设置和注释的完整列表在
machine.config.comments 中,该文件通常位于
\Windows\Microsoft.Net\Framework\v2.x\Config 中
–>
<configuration>
<appSettings>

<add key=”FCKeditor:BasePath” value=”~/fckeditor/”/>

<add key=”FCKeditor:UserFilesPath” value=”/Files/” />

</appSettings>

<connectionStrings/>
<system.web>

说明:BasePath是fckeditor所在路径,fckeditor由于我们直接放网站目录下这样写就可以,如果您的网站多放几层适当调整即可。
UserFilesPath所有上传的文件的所在目录。为什么要设置成/Files这样而不是~/Files因为FCKeditor使用这个值来返回你上传后的文件的相对路径到客户端。否则的话客户访问的时候就会取客户的机器目录而不是http形式的目录。

建议:Files要单独做wwwroot目录下的一个站点比较好,和我们的站点FCKEditor平行。不要把它放FCKEditor里,为什么呢?因为Files是要让客户有写的权限的,如果放FCKEditor下很危险。

8.Files目录要有的权限。你根据自己网站需求设置那个帐号,本文为方便设置User实际中你可能用ASP.NET帐号更合理。

9.修改fckeditor/fckconfig.js文件
在第182行的位置
var _FileBrowserLanguage = ‘asp’ ; // asp | aspx | cfm | lasso | perl | php | py
var _QuickUploadLanguage = ‘asp’ ; // asp | aspx | cfm | lasso | php
改为
var _FileBrowserLanguage = ‘aspx’ ; // asp | aspx | cfm | lasso | perl | php | py
var _QuickUploadLanguage = ‘aspx’ ; // asp | aspx | cfm | lasso | php

10.FCKeditor给其瘦身。以_打头的的都是范例文件或源文件,不过建议小心。

11.下面以上传图片示例说明如何使用,

点击“浏览服务器”。

弹出窗口很容易报错

如果报错XML request error: Internal Server Error(500),很可能就是目录路径不对和写权限没有。

选择图像



最后效果

前台代码:

<%@ Page Language=”C#validateRequest=false AutoEventWireup=”true” CodeFile=”Default.aspx.cs” Inherits=”_Default” %>

<%@ Register Assembly=”FredCK.FCKeditorV2″ Namespace=”FredCK.FCKeditorV2″ TagPrefix=”FCKeditorV2″ %>

<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd“>

<html xmlns=”http://www.w3.org/1999/xhtml” >
<head runat=”server”>
<title>FCKeditor文本编辑器</title>
</head>
<body>
<form id=”form1″ runat=”server”>
<div>
<fckeditorv2:fckeditor id=”FCKeditor1″ runat=”server” DefaultLanguage=”zh-cn” Height=”400px” Width=”660px”
></fckeditorv2:fckeditor>

</div>
</form>
</body>
</html>

怎么样获取结果呢?FCKeditor1.Value就是。

[转载]使用cookies实现浏览历史记录功能

mikel阅读(1115)

[转载]使用cookies实现浏览历史记录功能 – muzhiye – 博客园.

1.创建历史记录的实体类

public class LastProducts
{
private int _productid;
private int _categoryid;
private string _imgsrc;
private string _productname;

public LastProducts(int id,int typeid,string imgsrc,string restorename)
{
_productid = id;
_categoryid = typeid;
_imgsrc = imgsrc;
_productname = restorename;
}

public int ProductId
{
get { return _productid; }
}

public int CategoryId
{
get { return _categoryid; }
}

public string ImgSrc
{
get { return _imgsrc; }
}

public string ProductName
{
get { return _productname; }
}
}

2.定义存储cookies的方法

public void HistoryRestore(string cookieName,int objectID)
{
HttpRequest Request = HttpContext.Current.Request;
HttpResponse Response = HttpContext.Current.Response;

if (Request.Cookies[cookieName] != null)
{
HttpCookie tempCurBuyerList = Request.Cookies[cookieName];
string tempstr = tempCurBuyerList.Value;
if (tempstr.IndexOf(“,”) > 0)
{
string[] sArray = tempstr.Split(‘,’);
bool hasthis = false;

foreach (string s in sArray)
{
if (s == objectID.ToString())
{
hasthis = true;
break;
}
else
{
hasthis = false;
}
}

if (!hasthis)   //如果没有ID,则加入
{
if (sArray.Length > 3) //3为存储浏览记录数的数量,实际数量为7
{
// 超过数量,去掉最先入队的元素
tempstr = tempstr.Substring(0, tempstr.LastIndexOf(“,”));
}
// 队列
tempstr = objectID.ToString() + “,” + tempstr;
}
}
else
{
//tempstr += “,” + objectID.ToString();
if (tempstr != objectID.ToString())
{
tempstr = objectID.ToString() + “,” + tempstr;
}
}
tempCurBuyerList.Value = tempstr;
tempCurBuyerList.Expires = DateTime.Now.AddDays(1);
Response.Cookies.Add(tempCurBuyerList);
//或者 Response.Cookies[cookieName].Value = tempstr;
}
else
{
HttpCookie addToCookies = new HttpCookie(cookieName);
addToCookies.Value = objectID.ToString();
addToCookies.Expires = DateTime.Now.AddDays(1);
Response.Cookies.Add(addToCookies);
}
}

3.读取cookies存储数据

public List<LastProducts> GetLastProducts()
{
HttpRequest Request = HttpContext.Current.Request;

List<LastProducts> list = null;

if (Request.Cookies[“restoreid”] != null)
{
HttpCookie tempCurBuyerList = Request.Cookies[“restoreid”];

string[] strArr = tempCurBuyerList.Value.Split(‘,’);
list = new List<LastProducts>();

foreach (string s in strArr)
{
ShopProduct model = dal.GetProById(int.Parse(s)); //商品的实体类
if (model != null)
{
list.Add(new Model.Shop.LastProducts(model.ProductID, model.CategoryID, model.ImageHref, model.Name));
}
}
}

return list;
}

4.在用户浏览某产品时记录到cookies中:

HistoryRestore(“restoreid”,productId);

5.数据源的绑定

Repeater1.DataSource = GetLastProducts();
Repeater1.DataBind();

[转载]android开发我的新浪微博客户端-载入页面sqlite篇(1.2)

mikel阅读(876)

[转载]android开发我的新浪微博客户端-载入页面sqlite篇(1.2) – 遇见未知的自己 – 博客园.

通过上一篇文章(Android开发我的新浪微博客户端-载入页面UI篇(1.1))已经完成了载入页面的UI部分的实现,效果如上图,接下来在上面的基础上完成载入页面的功能代码。

首先说明一下新浪微博提供了OAuth和Base OAuth两种认证方式(如果不知道什么是OAuth和Base OAuth请自己google一下恶补,同时接下来的2篇随笔也会对这方面进行详细的说明以及具体实现),本项目是采用OAuth认证方式,采用这种方式 就需要有用户的新浪UserID、Access Token、Access Secret这3样东西才能自由便利的调用新浪的开放接口,本项目是这样做的当用户第一次使用软件时进行授权认证获取这3样东西的时候存储到SQLite 库中以便用户下次使用时不需要重新进行繁琐的授权认证操作直接从SQLite库中读取出来即可,由于这样的需求载入页面的功能设定是这样:当用户打开软件 显示载入页面时开始检查SQLite库中是否已经保存有用户的新浪微博的UserID号、Access Token、Access Secret的记录,如果一条记录都没有那就说明用户是第一次使用本软件那么跳到认证授权页面进行授权认证操作(认证授权功能在接下来的两篇中进行实现讲 解)获取这3个值保存到sqlite库中,如果已经包括了记录,那么读取这些记录的UserID号、Access Token、Access Secret值然后根据这3个值调用新浪的api接口获取这些记录对应的用户昵称和用户头像图标等信息。

上面功能设定中涉及到sqlite数据库的创建、数据表的创建、数据记录的添加、数据记录的读取等操作,这里新建名为SqliteHelper.java类文件提供sqlite数据表的创建、更新等,代码如下:

代码

public class SqliteHelper extends SQLiteOpenHelper{
//用来保存

UserID、Access Token、Access Secret

的表名
public static final String TB_NAME=users;
public SqliteHelper(Context context, String name, CursorFactory factory, int version) {
super(context, name, factory, version);
}
//创建表
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(
CREATE TABLE IF NOT EXISTS +
TB_NAME
+(+
UserInfo.ID
+ integer primary key,+
UserInfo.USERID
+ varchar,+
UserInfo.TOKEN
+ varchar,+
UserInfo.TOKENSECRET
+ varchar,+
UserInfo.USERNAME
+ varchar,+
UserInfo.USERICON
+ blob+
)
);
Log.e(
Database,onCreate);
}
//更新表
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL(
DROP TABLE IF EXISTS + TB_NAME);
onCreate(db);
Log.e(
Database,onUpgrade);
}
//更新列
public void updateColumn(SQLiteDatabase db, String oldColumn, String newColumn, String typeColumn){
try{
db.execSQL(
ALTER TABLE +
TB_NAME
+ CHANGE +
oldColumn
+ + newColumn +
+ typeColumn
);
}
catch(Exception e){
e.printStackTrace();
}
}
}

接下来新建名为DataHelper.java类文件实现用户记录的创建、更新、删除等,代码如下:

代码

public class DataHelper {
//数据库名称
private static String DB_NAME = mysinaweibo.db;
//数据库版本
private static int DB_VERSION = 2;
private SQLiteDatabase db;
private SqliteHelper dbHelper;

public DataHelper(Context context){
dbHelper
=new SqliteHelper(context,DB_NAME, null, DB_VERSION);
db
= dbHelper.getWritableDatabase();
}

public void Close()
{
db.close();
dbHelper.close();
}
//获取users表中的UserID、Access Token、Access Secret的记录
public List<UserInfo> GetUserList(Boolean isSimple)
{
List
<UserInfo> userList = new ArrayList<UserInfo>();
Cursor cursor
=db.query(SqliteHelper.TB_NAME, null, null, null, null, null, UserInfo.ID+ DESC);
cursor.moveToFirst();
while(!cursor.isAfterLast()&& (cursor.getString(1)!=null)){
UserInfo user
=new UserInfo();
user.setId(cursor.getString(
0));
user.setUserId(cursor.getString(
1));
user.setToken(cursor.getString(
2));
user.setTokenSecret(cursor.getString(
3));
if(!isSimple){
user.setUserName(cursor.getString(
4));
ByteArrayInputStream stream
= new ByteArrayInputStream(cursor.getBlob(5));
Drawable icon
= Drawable.createFromStream(stream, image);
user.setUserIcon(icon);
}
userList.add(user);
cursor.moveToNext();
}
cursor.close();
return userList;
}

//判断users表中的是否包含某个UserID的记录
public Boolean HaveUserInfo(String UserId)
{
Boolean b
=false;
Cursor cursor
=db.query(SqliteHelper.TB_NAME, null, UserInfo.USERID + = + UserId, null, null, null,null);
b
=cursor.moveToFirst();
Log.e(
HaveUserInfo,b.toString());
cursor.close();
return b;
}

//更新users表的记录,根据UserId更新用户昵称和用户图标
public int UpdateUserInfo(String userName,Bitmap userIcon,String UserId)
{
ContentValues values
= new ContentValues();
values.put(UserInfo.USERNAME, userName);
// BLOB类型
final ByteArrayOutputStream os = new ByteArrayOutputStream();
// 将Bitmap压缩成PNG编码,质量为100%存储
userIcon.compress(Bitmap.CompressFormat.PNG, 100, os);
// 构造SQLite的Content对象,这里也可以使用raw
values.put(UserInfo.USERICON, os.toByteArray());
int id= db.update(SqliteHelper.TB_NAME, values, UserInfo.USERID + = + UserId, null);
Log.e(
UpdateUserInfo2,id+“”);
return id;
}

//更新users表的记录
public int UpdateUserInfo(UserInfo user)
{
ContentValues values
= new ContentValues();
values.put(UserInfo.USERID, user.getUserId());
values.put(UserInfo.TOKEN, user.getToken());
values.put(UserInfo.TOKENSECRET, user.getTokenSecret());
int id= db.update(SqliteHelper.TB_NAME, values, UserInfo.USERID + = + user.getUserId(), null);
Log.e(
UpdateUserInfo,id+“”);
return id;
}

//添加users表的记录
public Long SaveUserInfo(UserInfo user)
{
ContentValues values
= new ContentValues();
values.put(UserInfo.USERID, user.getUserId());
values.put(UserInfo.TOKEN, user.getToken());
values.put(UserInfo.TOKENSECRET, user.getTokenSecret());
Long uid
= db.insert(SqliteHelper.TB_NAME, UserInfo.ID, values);
Log.e(
SaveUserInfo,uid+“”);
return uid;
}

//删除users表的记录
public int DelUserInfo(String UserId){
int id= db.delete(SqliteHelper.TB_NAME, UserInfo.USERID +=+UserId, null);
Log.e(
DelUserInfo,id+“”);
return id;
}
}

完成上面的代码后,我们需要在载入页面中调用上面的方法实现sqlite库中是否已经保存有用户的新浪微博的UserID号、Access Token、Access Secret的记录的功能在MainActivity的onCreate方法添加代码:

代码

public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

……

//获取账号列表
dbHelper=new DataHelper(this);
List
<UserInfo> userList= dbHelper.GetUserList(true);
if(userList.isEmpty())//如果为空说明第一次使用跳到AuthorizeActivity页面进行OAuth认证
{
Intent intent
= new Intent();
intent.setClass(MainActivity.
this, AuthorizeActivity.class);
startActivity(intent);
}
else//如果不为空读取这些记录的UserID号、Access Token、Access Secret值
//然后根据这3个值调用新浪的api接口获取这些记录对应的用户昵称和用户头像图标等信息。
{
for(UserInfo user:userList){
……
}
}
}

关于载入页面的sqlite就说到这里了,下一篇说说OAuth认证实现。

[转载]用jquery让.hover(over,out)代替css中的:hover来实现悬停效果

mikel阅读(1042)

[转载]用jquery让.hover(over,out)代替css中的:hover来实现悬停效果 – 天堂电影 – 博客园.

话不多说,直接上菜。

.scpItem:hover{ background-color: #F4D0D0;}

<div class=”scpItem”>悬停看这</div>

在ie6-中没有反应。

可以将.scpItem:hover{ background-color: #F4D0D0;}从css文件中删除了,

而在js文件使用JQuery框架的hover()来模仿鼠标悬停事件。如:

$(“.scpItem”).hover(

function(){$(this).css(“background-color”,”#F4D0D0″);}

,function(){$(this).css(“background-color”,”white”);}

);

这样要的效果实现了。

[转载]android开发我的新浪微博客户端-载入页面UI篇(1.1)

mikel阅读(1031)

[转载]android开发我的新浪微博客户端-载入页面UI篇(1.1) – 遇见未知的自己 – 博客园.

本软件设定用户第一个接触到的功能就是页面载入等待功能,这个功能对使用者来说就是一个持续1、2秒钟的等待页面,在用户等待的同时程序做一些必要的检 查以及数据准备工作,载入页面分为UI篇和功能篇,从表及里首先是UI的实现,一个软件除功能之外还得有一个光鲜的外表也是非常重要的,尽管本人设计水平 一般但是还是亲自操刀用ps先做了一下设计效果图如下:

一、接下来的任务就是在Android中实现这样的效果显示,从这个效果的设计分别把图片分成背景版本号部分软件名称和图标作者名称和blog四 个部分,按照这样的思路把分别生成4张png的图片,背景部分考虑实现横屏和竖屏切换额外添加一张横屏背景图,然后新建Android工程,我这里的名称 为MySinaWeibo,android版本勾选2.2,并且创建名为MainActivity的Activity作为整个软件的起始页面,然后把上面 的这些图片保存到项目的res/drawable-mdpi文件夹下,关于res目录下的drawable-mdpi、drawable-ldpi,、 drawable-hdpi三个文件夹的区别,mdpi 里面主要放中等分辨率的图片,如HVGA (320×480)。ldpi里面主要放低分辨率的图片,如QVGA (240×320)。hdpi里面主要放高分辨率的图片,如WVGA (480×800),FWVGA (480×854)。android系统会根据机器的分辨率来分别到这几个文件夹里面去找对应的图片,在开发程序时为了兼容不同平台不同屏幕,建议各自文 件夹根据需求均存放不同版本图片,我这里就不进行这么多的考虑了。

二、完成图片资源的准备后接下就是layout文件的编写, 在res/layout文件夹下新建main.xml文件,这个layout采用LinearLayout控件作为顶层控件,然后用ImageView控件分别实现版本号图片顶部靠左对齐显示、软件名称和图标图片居中对齐、作者名称和blog图片底部靠右对齐。注意在版本号图片显示ImageView控件下面添加一个RelativeLayout控件作为软件名称和图标图片ImageVIew和作者名称和blog图片ImageView的父控件用来控制居中对齐已经底部对齐的实现具体代码如下:代码

<?xml version=”1.0″ encoding=”utf-8″?>
<LinearLayout xmlns:android=”http://schemas.android.com/apk/res/android”
android:id
=”@+id/layout”
android:orientation
=”vertical”
android:layout_width
=”fill_parent”
android:layout_height
=”fill_parent”>
<ImageView
android:layout_width=”wrap_content”
android:layout_height
=”wrap_content”
android:src
=”@drawable/ver”
android:layout_marginTop
=”15dip”
android:layout_marginLeft
=”15dip”>
</ImageView>
<RelativeLayout
android:layout_width=”fill_parent”
android:layout_height
=”fill_parent”>
<ImageView
android:layout_width=”wrap_content”
android:layout_height
=”wrap_content”
android:src
=”@drawable/logo”
android:layout_centerInParent
=”true”>
</ImageView>

<ImageView
android:layout_width=”wrap_content”
android:layout_height
=”wrap_content”
android:src
=”@drawable/dev”
android:layout_alignParentBottom
=”true”
android:layout_alignParentRight
=”true”
android:layout_marginRight
=”5dip”
android:layout_marginBottom
=”35dip”>
</ImageView>
</RelativeLayout>
</LinearLayout>

三、在ec打开名为MainActivity的Activity源代码文件进行编辑,onCreate部分代码如下:

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}

然后运行项目可以在模拟器中显示,上面的几个图片都按照设计的位置和效果进行显示只是整个页面的背景还是黑色的,接下来就是背景部分的显示实现,由于为了实现横竖屏切换显示,背景图的显示采用代码进行控制显示,首先用如下方法获取当前手机是横屏还是竖屏:

代码

//获取屏幕方向
public static int ScreenOrient(Activity activity)
{
int orient = activity.getRequestedOrientation();
if(orient != ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE && orient != ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) {
//宽>高为横屏,反正为竖屏
WindowManager windowManager = activity.getWindowManager();
Display display
= windowManager.getDefaultDisplay();
int screenWidth = display.getWidth();
int screenHeight = display.getHeight();
orient
= screenWidth < screenHeight ? ActivityInfo.SCREEN_ORIENTATION_PORTRAIT : ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
}
return orient;
}

然后编写一个名为AutoBackground的公共方法用来实现屏幕背景的自动切换,后面的几乎每一个功能页面都需要用到这个方法:

代码

public static void AutoBackground(Activity activity,View view,int Background_v, int Background_h)
{
int orient=ScreenOrient(activity);
if (orient == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) { //纵向
view.setBackgroundResource(Background_v);
}
else{ //横向
view.setBackgroundResource(Background_h);
}
}

完成上述两方法后在 MainActivity的onCreate方法中调用AutoBackground方法进行屏幕自动切换:

LinearLayout layout=(LinearLayout)findViewById(R.id.layout);
//背景自动适应
AndroidHelper.AutoBackground(this, layout, R.drawable.bg_v, R.drawable.bg_h);

到此完成了载入页面的UI部分的实现,测试运行模拟器中查看效果,基本上跟最上面的设计效果图相符,测试效果图如下:

[转载]ActionScript3框架集合

mikel阅读(1231)

Cairngorm (download)

Cairngorm是一个最早最为成熟的FLEX框架,现在已归为ADOBE门下.

PureMVC (download)

它其实是一个ActionScript 3框架,不像Cairngorm,它并不是针对FLASH,FLEX或者其它ADOBE AS3.0类。它是一个用于开发基于FLASH的AS 3.0的任何程序.

Model-Glue: Flex (download)

Model-Glue是一种简单的MVC的FLEX框架,Model-Glue拥有COLDFUSION接口.它相比以上两款更为轻巧.

Foundry (download)
ServeBox Foundry ( sbasfoundry )是一个ActionScript 3 / Java框架针对Flex 2应用开发者.

Spring Actionscript

比利时的Christophe HerremanSpring ActionScript框架(以前的pranaframework)的创始人和主要开发成员之一,Spring ActionScript的当前版本是0.81。

当前版本的Spring ActionScript已经实现了IOC,反射编程框架,集成了Cairngorm和PureMVC框架。接下来会开发一个MVCS( Model-View-Controller-Service)的架构,并且加入AOP(Aspect Oriented Programming)面向切面编程。

Guasax Flex Framework (download)

Guasax是一个易用的程序框架,为保证新老FLEX应用的扩展.

ARP (download)

ARP (Ariaware RIA Platform)是一个基于ActionScript的框架,它是一个Open Source Flash 项目.

Flest Framework (download)

Flest 是一个ActionScript3 / Flex框架.

以上的框架可以从EasyMVC, Adobe FASTJoeberkovitz’s framework签出.

其它的一些还有

FlexUnit (一个用于ActionScript 3单元测试框架)

AS3CoreLib (一个 ActionScript 3.0 库包含强大的JSON 的包)

Granite DS (一个免费开源的,可以替代Adobe Data Services J2EE应用服务器 EJB3/Spring/Pojo 服务支持)

Soma v2 AS3 MVC

Soma v2的已经用于许多项目,使用它是一种极大的乐趣。我首先为自己建立这个框架,作为一种工具。如果我不认为Soma 可帮助您用最少的时间学习和 “框架冲突” ,我不会发布它,我希望…使用它们有很多乐趣!

相比第2版这一概念是类似的,许多已得到改善和增加。
首先是SomaUI演示!

~W8UT 1EWVHZ7{I)SF@V@IN

Aswing 国人iiley写的纯AS的UI框架,结构类似于 Java Swing,体积小巧。

weemvc ,国人写的,继Aswing之后的又一开源框架,值得学习,适合小项目。

  • 超级微型,简洁、简单,上手快,适合新手学习和开发小型项目;
  • 整合 PureMVC 与 Cairngorm 的优点进行设计;
  • FLASH 友好设计,对于 FLASH 的相关小型项目开发效率较高;
  • 在解耦上做了优化处理,使得 model 和 view 复用更容易。neatframework ,国人写的
  • 面向Flash项目开发,目标明确,实现灵活
  • 轻量,编译体积更小,架构清晰,简洁易用,适合快速开发
  • 核心基于MVC模式构建,模块间采用事件模型进行通讯,低耦合
  • 事件追踪,自动宏命令jdhMVC(Version 1.0.0),国人的自我总结:
    此框架并不影响以前写代码的风格, 只是将相关的类用继承框架中指定的类来达到事件播等,也许算不上MVC框架,之所以还是叫他MVC也就是因为确实把显示对象和控制对象分开来处理,至于数 据层几乎和控制层相同,可以根据自己不同的习惯来定了. (参考pureMVC框架)
    优点:简单易用, 只需要建立几个关联和重写几个方法就能实现事件广播, 重复代码量少;
    缺点:个人摸索的框架不够成熟, 测试量较少, 还需要更好地优化, 各事件发送与接收如果不做记录在数量多的情况下很找到其间的关联;

    一些FLASH游戏的框架

    1.Citrus 介绍:

    Citrus 是一个由Actionscript 3.0 语言和 Box2D物理引擎实现的卷轴类游戏 引擎。
    设计师和开发者可以利用Citrus 快速的构建卷轴(平台)类游戏。

    O%O57$GI)I46QYJ8EE8E$ 8

    http://blueflamedev.com/

    2.Yogurt3D

    http://www.yogurt3d.com/en/

    感觉flash现在对3D方面还不能很好的支持,虽然已经有很多的3D 框架的支持,但是运行效率还是不好,仅仅限于展示阶段

    还不能很好的用于一些应用里面。

    3.Teris game Engine

    Teris的介绍不多,

    http://code.google.com/p/bigroom/

    4.FFlimation

    介绍:

    The FFilmation Engine is an AS3 isometric programing engine , focused mainly on game development. The aim of the project is providing a robust development platform , where game designers can work on the game’s details and forget about the render engine. It is intended to be really usable from a “real production scenario” point of view. This means:

    B9B09OCW4Z]A5GZ5FCA{RT7

    demo http://www.ffilmation.org/website/demos/example-1/

    5.openspace

    介绍:

    OpenSpace is a powerful Flash based isometric engine and framework for rapid development of multi-user virtual worlds and MMO communities.
    The engine leverages the power of ActionScript 3 and SmartFoxServer , offering an unprecedented level of features and customizations.

    4R$O)CWN ~WE@[]JZBK7U5H

    demo: http://showcase.smartfoxserver.com/openspace2/

    和FFlimation 一样也是 isometric类 游戏,但是不是开源的。

    6. pushbutton engine

    介绍:

    The PushButton Engine is an Open Source , Flash game engine and framework that’s designed for a new generation of games. PushButton Engine makes it easy to bring together great existing libraries and components for building Flash games. Spend less time on code, more time on building fun games .


    webbus flashweb 框架 第一版(国人的)

    1.webbus FLASH框架将 SWF类库与主程序分开,完美控制类库加载. 在调用时自动加载类库SWF.或初始化时一次性加载必需类库.
    2.完美的单线程列队加载.只需抛一个事件流,剩下的事件交给框架来完成.
    3.系统配置方便,只需修改config.xml.
    4.自行扩展类库方便,可同时使用多个类库.
    5.每次只需编译相关功能应用SWF,单次编译文件最小,提高工作效率.
    6.框架采用分步加载. APP功能 类库功能分离,节省大量带宽资源,速度快.
    7.自行修改各加载LOADING,可不用LOADING.
    DEMO:http://www.webbus.com.cn/demo/flashweb/main.swf