存档

2013年8月 的存档

参加2013中国软件开发者大会(SDCC)会,听软件开发趋势

2013年8月30日 没有评论

1、SDCC

      盛大召开的会议,既然参加了,就写篇博客记一下。

2、蒋公子

    首先向大会主席台走来的是csdn老大…… 额,好像不是走过来的。蒋涛采用了个特殊的上台方式呢~    

     参加2013中国软件开发者大会(SDCC)会,听软件开发趋势   参加2013中国软件开发者大会(SDCC)会,听软件开发趋势

    在台上蒋公子就软件及其未来的发展方向提出了些自己看法。穿戴设备的兴起是一个有目共睹的趋势,比如眼镜、手表,这些日常用品都纷纷加入电子化的行列。其核心在于:便捷 。眼镜也好,手表也好,都是一个智能终端的扩展,或者说是互联网的扩展。这些穿戴设备可以更好的将信息“推”到人们更容易获得的地方,而不仅仅是口袋中的那块大砖头。在整个软件行业,API将成为企业业务拓展的重要方式。在未来,企业向外拓展不仅仅是一个广告页的网站那么简单了,更可行的发展方向是积极提供接入服务,让更多的App使用,这是一条捷径,也是必然的趋势。另外,面对未来的挑战,csdn也在积极应对,推出了许多的产品。战略方面,csdn与百度、阿里等知名云服务企业合作,推出多种基于云的产品。产品方面,有很多上线的新产品。比如:
     Code 网址:https://code.csdn.net 开源代码托管平台,中国自己的github。
     share 网址:http://share.csdn.net 一个文档分享的平台,这次大会的ppt都可以在上面找到。
     geek  网址:http://geek.csdn.net  一个geek新闻的平台。
  另外,蒋公子还透露在未来几个月,csdn平台会有一次比较大的更新。也很值得期待。

3、MIUI设计成长之路:洪峰

    参加2013中国软件开发者大会(SDCC)会,听软件开发趋势
    
    小米的副总裁洪峰带来的分享是小米的MIUI的整个设计历程。MIUI经历了1~5的版本更迭,在v1版本中,设计的核心是拟物化。所有的设计以写实为主,比如折纸、木纹的效果。随之而来的v2版本,更多的尝试了立体和色彩。为Icon和界面加入了透明度。不可避免的,小米也走了写弯路,比如,不同应用,采用不同的颜色。由于颜色的选用并没有经过深入探讨,导致并没有达到想要的效果。在这个版本中加入了动态天气的特性,这一特性在后来的版本中,一直保持,并被证为是成功的设计。
    经过这两个版本的尝试,v3版本更像是一个重新的思考,将先前版本的设计与界面统一起来。色彩方面采取了保守的策略,即黑白灰的核心配色,辅以小米的主色橙色。另外,添加了很多功能性应用,如天气,计时器等。这个版本中最重要的革新是提出了主题的概念。个性主题、百变解锁,这些特性赋予了小米系统更灵动的特质。它将更多的优秀设计师的潜能发挥出来,建立了一个设计师的生态圈,所有元素可定制,可以将设计师的潜能更大的发挥出来,同时主题商店的出现,构成了闭环,将变现的渠道变得更稳固。
    v4版本的理念是平面化。滑动的扁平化,纹理更加的写实。同时开发出了沉浸式的体验,例如小米的音乐。这边版本还添加了很多工具应用,例如手电、录音机。由于采用自由桌面,这个版本也涌现了很多精彩的主题。
    经过先前的成功,v5版本更像是“斗罢艰险又出发”。经过先前数据的沉淀,分析用户行为,将用户分为四种类型:追求效率、追求实用性、追求视听享受、追求新鲜软件功能。

    参加2013中国软件开发者大会(SDCC)会,听软件开发趋势

    更好的贯彻了中T型结构,空出更多的空间,显示用户的头像等内容:

    参加2013中国软件开发者大会(SDCC)会,听软件开发趋势

  加入了更多的动画效果比如顺次进入,错层滑动,花瓣散开等。元素以圆形为核心元素,更平,更注重材质感。关注点从写实,变成了写意。Icon方面,引入了动态的Icon,同时Icon滤镜的出现,可以将图标的风格一体化,解决了多种不同Icon对主体风格的影响。

4、总结

     正如《程序员》杂志的总编刘江提到的一个词:工具化思维。程序员总是喜欢自己开发工具,而不是用工具。虽然说这样做并不是错,但不能不说是一种生产力的浪费。当今的社会要讲究效率。一个快节奏的时代,是不养慢节奏的人的。在高效狂奔的同时,细节与设计的专注也必不可少。  用更好的工具,干更精致的活,这才是程序未来的方向。


Ps: 在微博上借了几张图 大家可以去看原图 哈 大会所有的PPT都在share.csdn.net上有,有兴趣可以看看。另外,感谢胡老师的盛情款待~  


本篇博客出自阿修罗道,转载请注明出处:http://blog.csdn.net/fansongy/article/details/10594507
分类: 未分类 标签:

明星总动员

2013年8月30日 没有评论

itunes:https://itunes.apple.com/cn/app/ming-xing-zong-dong-yuan/id687165983?mt=8

一个周末做的小游戏,所以难免很多瑕疵。


里面用到了微信的应用发布接口,可以在微信内帮助其他人回答问题。

明星总动员 明星总动员


内容提要

根据一张图猜出是哪位明星名人,快来挑战一下你认识多少!

各路人马齐上场! 历史名人,文学家,经典电视人物,画家,网络红人,当红明星,科学家,发明家,卡通人物等等。

尼玛…这货尽然是…乔…乔帮主…

没有坑X的内购,没错,你没看错,真的没有内购。

***特色功能***
支持微信朋友互动答题,不仅仅是分享哦,还能互动答题哦,亲,互动哦。在微信内即可帮助朋友回答,成功帮助朋友回答题目会有意想不到的奖励哦。

(悄悄告诉你: 不会的题目可以分享到微信求助;同时在微信看到别人的求助题目,可以直接点击回答,成功帮助朋友后,嘿嘿,你懂得…)

赶紧下载,加入明星总动员的挑战之中吧! 

我们只为您提供最好的游戏体验,游戏内容持续更新。

分类: 未分类 标签:

用Html5结合Qt制作一款本地化EXE游戏-太空大战(Space War)

2013年8月23日 没有评论

本次来说一说如何利用lufylegend.js引擎制作一款html5游戏后将其通过Qt转换成EXE程序。步骤其实非常简单,接下来就一步步地做一下解释和说明。

首先我们来开发一个有点类似于太空大战的游戏,游戏截图如下:

用Html5结合Qt制作一款本地化EXE游戏-太空大战(Space War)

游戏介绍:这个游戏原本是七十一雾央前辈用Cocos2d-x开发的android小游戏。由于我看到这个游戏实现起来比较简单,因此就把apk下载下来,并且在雾央的指导下,把它当rar压缩文件解开了,把素材偷走了……嘿嘿。由于我最近的开发涉及html5领域,因此就用html5+lufylegend.js把这个游戏移植到浏览器平台上了。当然,效率不能和雾央的原版游戏比,因为html5的效率众所周知是很低的。

操作说明:用鼠标点击界面,发出子弹攻击迎面飞来的敌人。

游戏目标:不放过任何一个迎面飞来的敌人。

游戏测试地址:

http://www.cnblogs.com/yorhom/articles/3274940.html

注:演示地址中没有背景音乐,是因为我觉得音乐太占空间了,所以去掉了。下载包里含有音乐,各位可以欣赏一下。另外也感谢一下雾央兄弟,感谢他给我提供那么好,那么多的素材。


接下来就来说说这个游戏的制作步骤。


准备工作

首先你需要下载lufylegend.js游戏引擎。这个引擎是一个html5开源库件,利用他可以仿照了As 3.0的语法进行html5开发,使用起来非常方便。当然,你说你不是flasher,不懂As 3.0,那也无妨,可以参照官方API文档进行学习。具体的介绍还是去官方网站看看吧,免得lufy说我乱介绍他的引擎,嘿嘿~

引擎官方网站:

http://lufylegend.com/lufylegend

引擎API文档:

http://lufylegend.com/lufylegend/api

因为本次开发要用到这个引擎,所以各位先看看这个引擎的一些API介绍吧,避免文中用到的一些API大伙看不懂。


制作过程

首先要读取一下游戏中的数据。本次开发要用到的数据如下:

/**加载变量*/
var loadData = [
	{path:"./js/Bullet.js",type:"js"},
	{path:"./js/Plain.js",type:"js"},
	{path:"./js/Background.js",type:"js"},
	{name:"bullet",path:"./images/bullet.png"},
	{name:"sky.1",path:"./images/gamebg0.png"},
	{name:"sky.2",path:"./images/gamebg1.png"},
	{name:"over_text",path:"./images/gameover.png"},
	{name:"player",path:"./images/hero.png"},
	{name:"monster",path:"./images/monster.png"},
	{name:"over_bg",path:"./images/overbg.png"},
	{name:"start_bg",path:"./images/startbg.png"},
	{name:"start_button_normal",path:"./images/startNormal.png"},
	{name:"start_button_selected",path:"./images/startSelected.png"}
];

由于加载完成后要保存这些加载好的数据,所以还要用一个变量:

var datalist;

接下来把一些定义的变量放在下面,都写了注释,大家慢慢看喔~

/**层变量*/
var backLayer,
plainLayer,
enemyLayer,
bulletLayer,
textLayer,
loadingLayer;

/**分数变量*/
var score;

/**频率变量*/
var maxFrame = 30;
var frameIndex = 0;

/**游戏进行时间*/
var gameTime;

/**对象变量*/
//显示分数对象
var scoreText;
//玩家
var player;
//音乐对象
var startMusic,
overMusic,
playingMusic,
dieMusic;

然后用到init初始化游戏,因为游戏是要跨平台的,所以要在手机上全屏显示,为了实现这些,我们在Main.js顶部加入如下的代码:

//设置全屏
LSystem.screen(LStage.FULL_SCREEN);
//初始化游戏
init(30,"mylegend",800,480,main);

init的用法和LSystem.screen的用法都可以参照API文档。

接下来我们来看看main函数,这个函数是用来加载图片和设置一些信息用的,比如开启debug模式等,代码如下:

function main(){
	//设置debug模式
	LStage.setDebug(true);
	//如果是移动端,就将body标签margin调为0px 0px 0px 0px
	if(LStage.canTouch == true){
		document.body.style.margin = "0px 0px 0px 0px";
	}
	
	//初始化加载层
	loadingLayer = new LoadingSample3();
	addChild(loadingLayer);
	
	//加载游戏数据
	LLoadManage.load(
		loadData,
		function(progress){
			//显示加载进度
			loadingLayer.setProgress(progress);
		},
		gameInit
	);
}

上面的代码中,用了库件中的LLoadManage类读取,这个类可以读取js文件和图片、音频文件等,大家可以自己去看看API文档。

接下来看看gameInit里的代码,这个函数是用来保存加载数据,加入音乐,加入开始场景用的。代码如下:

function gameInit(result){
	//保存加载的数据
	datalist = result;
	//清空加载层
	removeChild(loadingLayer);
	
	//加入地板层
	backLayer = new LSprite();
	addChild(backLayer);
	
	//初始化音乐
	initMusic();
	
	//加入开始界面
	addStartPage();
}

其中调用到的函数代码分别如下:

function initMusic(){
	//开场音乐
	startMusic = new LSound("./music/startbg.mp3");
	//结束音乐
	overMusic = new LSound("./music/overbg.mp3");
	//游戏开始后的音乐
	playingMusic = new LSound("./music/gamebg.wav");
	//死亡后的音乐
	dieMusic = new LSound("./music/die.wav");
}
function addStartPage(){
	//播放音乐
	startMusic.play(0,100000000000000000000000000000000);
	//加入背景
	var bitmapData = new LBitmapData(datalist["start_bg"]);
	var bitmap = new LBitmap(bitmapData);
	backLayer.addChild(bitmap);
	
	//按钮普通时的样式
	var normalBtnStyleData = new LBitmapData(datalist["start_button_normal"]);
	var normalBtnStyle = new LBitmap(normalBtnStyleData);
	//按钮盘旋时的样式
	var selectedBtnStyleData = new LBitmapData(datalist["start_button_selected"]);
	var selectedBtnStyle = new LBitmap(selectedBtnStyleData);
	//加入开始按钮
	var startBtn = new LButton(normalBtnStyle,selectedBtnStyle);
	startBtn.x = (LStage.width-startBtn.getWidth())*0.5;
	startBtn.y = (LStage.height-startBtn.getHeight())*0.5;
	backLayer.addChild(startBtn);
	
	//加入开始事件
	startBtn.addEventListener(LMouseEvent.MOUSE_DOWN,startGame);
}

代码都加上了注释,可以参照API文档看看。在上面的addStartPage代码中,加入一个开始按钮后,我们给这个按钮加了一个鼠标事件,这个事件是用来触发游戏开始用的。开始游戏我们用的是startGame函数,代码如下:

function startGame(event){
	//清空界面
	backLayer.removeAllChild();
	
	//分数调零
	score = 0;
	//游戏时间调零
	gameTime = 0;
	
	//停止开始界面的音乐音乐
	startMusic.close();
	//播放游戏进行中的音乐
	playingMusic.play(0,100000000000000000000000000000000);
	
	//加入滚动背景
	var background = new Background();
	backLayer.addChild(background);
	
	//初始化层变量
	initLayer();
	//加入玩家飞机
	player = new LBitmap(new LBitmapData(datalist["player"]));
	player.x = 20;
	player.y = (LStage.height-player.getHeight())*0.5
	plainLayer.addChild(player);
	
	//加入分数文字
	addText();
	
	//加入事件
	backLayer.addEventListener(LMouseEvent.MOUSE_DOWN,onmousedown);
	backLayer.addEventListener(LEvent.ENTER_FRAME,onframe);
}

这个函数中我们首先初始化一些值,比如分数和游戏时间。在这里顺便说说这个游戏时间有什么用:因为我们的游戏随着时间的推进,难度应该越来越难,所以我们要保存下这个时间,方便以后的计算。

在startGame中,我们为了加入一个滚动的背景,我们用到了一个Background类。这个类代码如下:

/**
* Background.js
* @author Yorhom
* @date 2013/8/10/23:42
*/

function Background(){
	var s = this;
	base(s,LSprite,[]);
	
	//设置移动速度
	s.speed = 10;
	
	var skyBitmapData1 = new LBitmapData(datalist["sky.1"]);
	var skyBitmapData2 = new LBitmapData(datalist["sky.2"]);

	//记录每块背景的长度
	s.lastObjX = skyBitmapData1.image.width;
	
	//实例化第一块背景
	s.skyBitmap1 = new LBitmap(skyBitmapData1);
	//实例化第二块背景
	s.skyBitmap2 = new LBitmap(skyBitmapData2);
	//将第二块背景移动到第一块的后面
	s.skyBitmap2.x = s.lastObjX; 
	
	//加入两块背景
	s.addChild(s.skyBitmap1);
	s.addChild(s.skyBitmap2);
	
	//加入时间轴事件
	s.addEventListener(LEvent.ENTER_FRAME,s.run);
}
Background.prototype.run = function(s){
	//将背景向前移动
	s.skyBitmap1.x -= s.speed;
	s.skyBitmap2.x -= s.speed;
	
	//如果第一块背景移除到屏幕之外就移到另一块的后面
	if(s.skyBitmap1.x < -1 * s.lastObjX){
		s.skyBitmap1.x = s.skyBitmap2.x + s.lastObjX;
	}
	//如果第二块背景移除到屏幕之外就移到另一块的后面
	if(s.skyBitmap2.x < -1 * s.lastObjX){
		s.skyBitmap2.x = s.skyBitmap1.x + s.lastObjX;
	}
};

原理很简单,就是先将第二块背景接到第一块背景的后面,如果第一块背景已经移除屏幕了,那就把第一块背景加到第二块后面,以此类推,就实现了画面不段移动的感觉。

在startGame函数中,我们还用到了实例化层的函数initLayer(),这个函数代码如下:

function initLayer(){
	//加入飞机层
	plainLayer = new LSprite();
	backLayer.addChild(plainLayer);
	//加入敌机层
	enemyLayer = new LSprite();
	backLayer.addChild(enemyLayer);
	//加入子弹
	bulletLayer = new LSprite();
	backLayer.addChild(bulletLayer);
	//加入文字层
	textLayer = new LSprite();
	backLayer.addChild(textLayer);
}

另外还有个addText函数,负责显示分数文字用的。

function addText(){
	//实例化LTextField对象
	scoreText = new LTextField();
	scoreText.font = "Tekton Pro";
	scoreText.size = 20;
	scoreText.text = "Score: " + score;
	scoreText.x = LStage.width - scoreText.getWidth() - 20;
	scoreText.y = 20;
	//加到显示层中
	textLayer.addChild(scoreText);
}

还有就是在startGame中加的两个事件:时间轴事件,鼠标点击事件。鼠标事件触发的函数代码如下:

function onmousedown(event){
	//计算子弹飞出的角度
	var height = (player.y + player.getHeight()*0.5) - event.offsetY;
	var width = event.offsetX - (player.x + player.getWidth()*0.5);
	var angle = Math.atan2(height,width);
	//实例化一个子弹
	var bullet = new Bullet(angle);
	bulletLayer.addChild(bullet);
}

代码很简单,就是先取出当前点击位置离人物的宽度与高度,然后通过Math.atan2算出这个点与玩家飞机的直线距离和通过玩家飞机的水平直线的夹角度数,并将这个值当参数传入Bullet类中。Bullet类代码如下:

/**
* Bullet.js
* @author Yorhom
* @date 2013/8/12/21:14
*/

function Bullet(angle){
	var s = this;
	base(s,LSprite,[]);
	
	//计算子弹角度
	s._angle = angle * 180 / Math.PI;
	//保存子弹移动速度
	s._speed = 10;
	//保存当前子弹到玩家飞机的距离
	s._r = 0;
	
	//计算出初始位置
	s.x = player.x + player.getWidth()*0.5;
	s.y = player.y + player.getHeight()*0.5;
	
	//保存初始位置
	s._startX = s.x;
	s._startY = s.y;

	//添加子弹对象
	var bitmapData = new LBitmapData(datalist["bullet"]);
	s.bitmap = new LBitmap(bitmapData);
	s.addChild(s.bitmap);
	
	//添加射击时的音频对象
	var attackMusic = new LSound("./music/attack.wav");
	attackMusic.play();
}
Bullet.prototype.onframe = function(){
	var s = this;
	//更改当前子弹到玩家飞机的距离
	s._r += s._speed;
	
	//计算y轴移动距离
	var speedy = Math.sin(s._angle * Math.PI / 180) * s._r;
	//计算x轴移动距离
	var speedx = Math.cos(s._angle * Math.PI / 180) * s._r;
	//更改子弹位置
	s.x = s._startX + speedx;
    s.y = s._startY - speedy;
};

这个类主要负责显示一个子弹,并且让子弹往点击的方向飞去。显示一个子弹就是用一个LBitmap来实现。移动子弹的原理就是先把子弹到玩家飞机的直线距离设置为0,然后每当要移动子弹时,就将这个距离先加上移动速度,找到要到的位置,然后通过传进来的那个角度参数配合Math.cos和Math.sin算出要到的位置的x,y坐标,然后让子弹移动到那个位置上去。这个对于大伙儿应该很简单,但对于我这个只有初二水平的学生来说,连cos和sin都没学过,查了很多资料才搞出来的。

上面还提到了时间轴事件,触发的函数如下:

function onframe(){
	//增加游戏时间
	gameTime ++;
	//添加敌人
	if(frameIndex > maxFrame){
		var enemy = new Plain();
		enemyLayer.addChild(enemy);
		frameIndex = 0;
	}else{
		frameIndex ++;
	}
	//移除敌人
	for(var key in enemyLayer.childList){
		if(enemyLayer.childList[key].mode == "die"){
			enemyLayer.removeChild(enemyLayer.childList[key]);
			//增加分数
			score += 10;
			//显示新分数
			changeText();
			return;
		}
		if(enemyLayer.childList[key].mode == "complete"){
			gameOver();
			enemyLayer.removeChild(enemyLayer.childList[key]);
		}
	}
	//移除飞出屏幕的子弹
	for(var key in bulletLayer.childList){
		bulletLayer.childList[key].onframe();
		if(
			bulletLayer.childList[key].x > LStage.width
			|| bulletLayer.childList[key].x < 0
			|| bulletLayer.childList[key].y < 0
			|| bulletLayer.childList[key].y > LStage.height
		){
			bulletLayer.removeChild(bulletLayer.childList[key]);
		}
	}
}

每段代码都加了注释,结合API文档看一些就能明白的。其中有个Plain类,这个是一个用来实现敌机的类,包括敌机移动,检测碰撞等,代码如下:

/**
* Plain.js
* @author Yorhom
* @date 2013/8/15/12:10
*/

function Plain(){
	var s = this;
	base(s,LSprite,[]);
	
	//设置飞机移动速度
	s.speed = Math.floor(gameTime/100) + 7;
	s.mode = "";
	
	//添加敌人的图片
	var bitmapData = new LBitmapData(datalist["monster"]);
	s._bitmap = new LBitmap(bitmapData);
	s.x = LStage.width + s._bitmap.getWidth();
	s.y = Math.floor(Math.random()*(LStage.height-s._bitmap.getHeight()));
	s.addChild(s._bitmap);
	
	//通过时间轴事件实现不断移动
	s.addEventListener(LEvent.ENTER_FRAME,s.run);
}
Plain.prototype.run = function(s){
	//移动飞机对象
	s.x -= s.speed;
	
	//检测碰撞
	s.checkHit();
	
	//判断是否移除屏幕。如果是,就将mode属性设置为"complete"
	if(s.x < -1 * s.getWidth()){
		s.mode = "complete";
	}
};
Plain.prototype.checkHit = function(){
	var s = this;
	
	//判断碰撞
	for(var key in bulletLayer.childList){
		if(LStage.hitTestArc(s,bulletLayer.childList[key])){
			//将mode属性改为"die"
			s.mode = "die";
			//移除碰撞子弹
			bulletLayer.removeChild(bulletLayer.childList[key]);
		}
	}
};

可以在上面的构造器代码中看到,我们通过游戏时间变量gameTime计算了飞机移动的速度,达到改变游戏的难度。其他的代码就直接看注释和API文档就能看懂。

实现了这个类,我们的游戏基本上就搞定了。不过还有些细节部分不可忽视。

为了移除一些对象避免效率低下,我们在onframe中加入了移除对象的功能。为了实现这个功能,我们遍历了每个飞机对象,然后判断遍历到的飞机对象的mode属性是否为die,如果是,就移除掉。在onframe中,实现这个效果的代码如下:

//移除敌人
for(var key in enemyLayer.childList){
	if(enemyLayer.childList[key].mode == "die"){
		enemyLayer.removeChild(enemyLayer.childList[key]);
		//增加分数
		score += 10;
		//显示新分数
		changeText();
		return;
	}
	if(enemyLayer.childList[key].mode == "complete"){
		gameOver();
		enemyLayer.removeChild(enemyLayer.childList[key]);
	}
}
//移除飞出屏幕的子弹
for(var key in bulletLayer.childList){
	bulletLayer.childList[key].onframe();
	if(
		bulletLayer.childList[key].x > LStage.width
		|| bulletLayer.childList[key].x < 0
		|| bulletLayer.childList[key].y < 0
		|| bulletLayer.childList[key].y > LStage.height
	){
		bulletLayer.removeChild(bulletLayer.childList[key]);
	}
}

为了及时更改分数,我们在时间轴事件中还加入了调用changeText函数。代码如下:

function changeText(){
	//更改显示文字
	scoreText.text = "Score: " + score;
	//更改文字坐标
	scoreText.x = LStage.width - scoreText.getWidth() - 20;
}

还有就是游戏结束时调用的代码,如下:

function gameOver(){
	//消除事件
	backLayer.die();
	
	var bitmap;
	//加入游戏结束层
	var gameOverLayer = new LSprite();
	backLayer.addChild(gameOverLayer);
	//加入背景
	bitmap = new LBitmap(new LBitmapData(datalist["over_bg"]));
	gameOverLayer.addChild(bitmap);
	//加入文字
	bitmap = new LBitmap(new LBitmapData(datalist["over_text"]));
	bitmap.x = (LStage.width - bitmap.getWidth()) * 0.5;
	bitmap.y = (LStage.height - bitmap.getHeight()) * 0.5;
	gameOverLayer.addChild(bitmap);
	
	//将游戏结束层移除屏幕
	gameOverLayer.y = -1 * gameOverLayer.getHeight();
	//通过缓动将游戏结束层移到屏幕上
	LTweenLite.to(gameOverLayer,0.7,{
		y:0,
		ease:Quad.easeInOut,
		onComplete:function(){
			//加入鼠标事件,来应对游戏重开
			backLayer.addEventListener(LMouseEvent.MOUSE_DOWN,restart);
		}
	});
	
	//关掉游戏进行中的音乐
	playingMusic.close();
	//播放游戏结束时候的音乐
	dieMusic.play(0,1);
	overMusic.play(0,100000000000000000000000000000000);
}

最后就是游戏重开函数:

function restart(){
	//清除界面
	backLayer.die();
	backLayer.removeAllChild();
	//关掉游戏结束时候的音乐
	overMusic.close();
	//开始游戏
	startGame();
}

上面基本上把整个游戏制作过程简略地讲了一遍,代码讲解有点不详细,大家可以结合注释看看。另外如果有感兴趣的朋友,可以到下面链接里下载。下载包里还有我打包好的apk文件,大家可以在手机上玩玩。打包apk的话,可以看看这篇文章:《用HTML5来开发一款android本地化App游戏-宝石碰碰》

源代码下载地址:http://files.cnblogs.com/yorhom/SpaceWar.rar

结合Qt实现本地化EXE游戏

下载和安装Qt等一些基础的东西这里就不多说了,Google一下或者百度一下就可以了。接下来就直接讲方法。

首先你需要在Qt Creater中创建一个Qt项目,创建项目的方法如下。

首先点开File->New File or Project,出现以下对话框,选择如图所示的几个选项:

用Html5结合Qt制作一款本地化EXE游戏-太空大战(Space War)

点击Choose…按钮,进入如下界面:

用Html5结合Qt制作一款本地化EXE游戏-太空大战(Space War)

上面的信息随便添就可以。点击Next,出现如下界面:

用Html5结合Qt制作一款本地化EXE游戏-太空大战(Space War)

上面是在选择配置,根据自己下载的选择一些就ok,点击Next继续。出现如下界面

用Html5结合Qt制作一款本地化EXE游戏-太空大战(Space War)

按照上面的添法填写好后,再继续按下Next,进入下一个界面。

用Html5结合Qt制作一款本地化EXE游戏-太空大战(Space War)

然后按下Finish就已经创建好项目了。得到以下的目录树,大家可以看看操作对没有:

用Html5结合Qt制作一款本地化EXE游戏-太空大战(Space War)

然后把装有html5游戏的文件夹复制到执行文件目录下。如下图:

用Html5结合Qt制作一款本地化EXE游戏-太空大战(Space War)

注意:貌似游戏加了音乐就会运行不出来了,把有用到音乐的地方全部删掉就ok没事了

打开mainwindow.h,写入以下代码:

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

class MainWindow : public QMainWindow
{
	Q_OBJECT
	
public:
	MainWindow(QWidget *parent = 0);
	~MainWindow();
};

#endif // MAINWINDOW_H

接着在mianwindow.cpp加入以下代码:

#include <QtWebKit/QWebView>
#include "mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
	: QMainWindow(parent)
{
	setWindowTitle(QString(""));
	setMaximumSize(QSize(800, 480));
	setMinimumSize(QSize(800, 480));
	showMaximized();
	setWindowIcon(QIcon("./SpaceWar/images/logo.jpg"));

	QWebView *pWebView = new QWebView(this);
	setCentralWidget(pWebView);

	pWebView->load("file:///"+QUrl(QFileInfo("./SpaceWar/index.html").absoluteFilePath()));
}

MainWindow::~MainWindow()
{
	
}

注意,QUrl里面的路径要是绝对路径,并且要在取出的绝对路径前面加上file:///。

再打开main.cpp,加入以下代码:

#include <QApplication>
#include "mainwindow.h"

int main(int argc, char *argv[])
{
	QApplication a(argc, argv);
	MainWindow w;
	w.show();
	
	return a.exec();
}

按下如图所示的按钮运行程序:

用Html5结合Qt制作一款本地化EXE游戏-太空大战(Space War)

运行效果如下:

用Html5结合Qt制作一款本地化EXE游戏-太空大战(Space War)

最后要发布的时候,要找到几个dll,如下:

  1. libgcc_s_dw2-1.dll
  2. libstdc++-6.dll
  3. QtCore4.dll
  4. QtGui4.dll
  5. QtNetwork4.dll
  6. QtWebKit4.dll
把这几个dll放在执行文件目录下面,就可以了。

如下图所示:
用Html5结合Qt制作一款本地化EXE游戏-太空大战(Space War)
over,exe就打包完成了。是不是很简单?

本次讲解就到这里了,欢迎大家捧场~~支持就是最大的鼓励!

如果文中有疏漏的地方或者大家有任何疑问都欢迎在文章下面留言。

—————————————————————-

欢迎大家转载我的文章。

转载请注明:转自Yorhom’s Game Box

http://blog.csdn.net/yorhomwang

欢迎继续关注我的博客

分类: 未分类 标签:

使用VBA,20行代码 将Excel数据导出

2013年8月15日 没有评论

1、满足需求

    程序员免不了与策划或运维打交道。通常情况是有配置数据的更改。但是即便是程序员也有写错的时候。更改一个配置,使用更直观的excel,成为了单写配置工具的替代方案。这里介绍一个将Excel的数据导出生成文件的方法。

2、设计Excel

      我们以植物大战僵尸2为例。其中有植物图鉴,这些数据明显是配置的,而且描述部分可能会更改。假设,我们有这样的一个Excel。
    
    使用VBA,20行代码 将Excel数据导出

    数据直观也简单。假设这就是全部要输出的信息啦。

3、VBA

    使用VBA,首先我们要打开VBA的编辑界面,找到Excel选项,进行设置,我使用的是Excel2010,在文件->excel选项中:
    使用VBA,20行代码 将Excel数据导出
    勾选开发工具,这样上面的菜单栏中就会出现开发工具菜单。
  
  使用VBA,20行代码 将Excel数据导出

    点击Visual Basic,就进入vba编辑界面了。

    右击Excel对象文件夹,添加一个模块:

    使用VBA,20行代码 将Excel数据导出

    在右侧的模块编辑框中加入代码:
    
Option Explicit
Sub writeOutData()
    Dim result As String
    Dim i As Integer
    Dim j As Integer
    For i = 3 To 10
        For j = 2 To 10
            If Len(Sheet1.Cells(i, j).Value) > 0 Then
                result = result & Sheet1.Cells(2, j) & " = " & Sheet1.Cells(i, j).Value & Chr(10)
            End If
        Next
    Next
    Open ThisWorkbook.Path & "/OutPut.txt" For Binary As #1
        Put #1, , result
        Close #1
    MsgBox "OutPut Success!"
End Sub

    很清爽是吧。保存,遇到这个对话框:
    使用VBA,20行代码 将Excel数据导出
    
    这里微软出于安全性的考虑默认excel是不加载宏的。因此这里我们选否,在接下来的界面里将其保存为.xlsm

    使用VBA,20行代码 将Excel数据导出

    保存之后。我们vba的编辑就完成了。

4、添加操作按钮

     接下来我们要在界面上放一个大按钮来调用这个宏方法。
    首先选取开发工具->插入->表单控件的第一个。拖动鼠标,绘制一个按钮。

    使用VBA,20行代码 将Excel数据导出

    拖动后,在弹出的界面选择刚才我们写的宏
使用VBA,20行代码 将Excel数据导出
  
    点击确定。我们就能看到这个按钮啦,再右击,选择编辑名称,将其改为“导出”。
   使用VBA,20行代码 将Excel数据导出

  好了,现在点击这个按钮,你会看到弹出的对话框,并且在次Excel同级目录会有一个名为output.txt的文件,记录我们的信息。生成了文件是这样的:
  使用VBA,20行代码 将Excel数据导出

5、总结

    经过设计表格、编写vba脚本、添加界面操作这些步骤,我们就可以导出Excel的信息了。整个过程非常方便。如果用c++来实现这样一个需求,还是很麻烦的。而这种方法只需要不超过20行代码。当然我们也可以增加逻辑,定制化数据的处理与输出。

    Excel文件下载地址:http://download.csdn.net/detail/fansongy/5955971


本篇博客出自阿修罗道,转载请注明出处:http://blog.csdn.net/fansongy/article/details/9988127
  
    
分类: 未分类 标签:

iOS Native Project Integrates Vuforia Unity Project

2013年8月13日 没有评论

I have two projects. One is native iOS app (UIKIT) and the other is AR Vuforia project which was made by Unity3D.

I can export AR project into XCODE project, but I am wondering how to link them together.

For example, I have a button on native iOS app. I want to trigger AR project when button is pressed and it can go back to native iOS app as well.

I finally worked it out by myself. Unity project must be rootviewcontroller, but you could add a separate navigation controller on the top of unity. You could add native code into AppController.m

Communication between native and unity is quiet simple.

Call

UnitySendMessage (gameObj, methodName, msg);

to send message to unity method

Use

extern “C”

to receive call back from unity.

I can provide some sample code if someone needs it.

分类: cocos2d, stackoverflow精选 标签:

cocos2d-x 使用 CCScale9Sprite 实现微信对话框

2013年8月11日 没有评论

1、有底框的文字

    微信的对话框特点在于它有一个可变大小的底图衬托,显得非常舒服,怎么实现的呢?先上图,然后慢慢说:

    cocos2d-x 使用 CCScale9Sprite 实现微信对话框

2、什么是九宫格构图?

    有个概念叫九宫格构图,说的就是这种会变化背景的情况。大家都知道图片是不可以随便拉抻的,无论是缩小还是放大,都会使图形虚化,影响显示效果。如果不能拉抻,就进行拼接。这就是这种策略的思路。
    首先它会将一个图分成九份:
      cocos2d-x 使用 CCScale9Sprite 实现微信对话框

    为了能够看清楚,我进行了缩放。大家也看到了,缩放产生的虚化问题。
    拼接是如何进行的呢?当显示应该超过图片原有大小时,四个边的顶点图像不会改变,四个边的中间部分进行拼接,这样就扩展了图片的大小。中间空出来的部分由中间来进行拼接。因此这张基础图不应该有花纹在上面,不然就会拼乱了。

3、编码九宫格

    原来缩放可以这么简单的实现。而且令人高兴的是cocos2d-x已经对这种模型进行封装,不需要大家自己来构建。下面就动手编码。

    更改helloWorld中的init。相信大家都知道是哪里:
		std::string str = "You are lucky as you can choose to love me or not.But for me,I can only choose to love you or more. ";
		CCLabelTTF* pLabel = CCLabelTTF::create(str.c_str(), "Arial", 24);
		CC_BREAK_IF(! pLabel);
		pLabel->setColor(ccc3(0,0,0));
		pLabel->setAnchorPoint(CCPointZero);

		CCScale9Sprite* sp = CCScale9Sprite::create("green_edit.png");
		CCSize extenSize = CCSizeMake(pLabel->getContentSize().width+10,pLabel->getContentSize().height+10);

		sp->setContentSize(extenSize);
		sp->addChild(pLabel);
		pLabel->setPosition( ccpAdd(sp->getPosition(),ccp(4,1)));
		sp->setPosition(ccp(250,100));
		this->addChild(sp, 1);

  大体说一下。首先创建一个CCLabelTTF。然后取它的大小,作为九宫格的大小。由于不希望文字刚刚好贴在边框显示,我用一个extenSize将九宫格扩大了一圈。最后将Label添加为九宫格的子节点。并为其设定位置。

  看起来不错,不过编译运行,出现的界面似乎有些问题:

   cocos2d-x 使用 CCScale9Sprite 实现微信对话框

    是的,没有自动换行。

4、文字换行

    文字换行怎么办?有个好消息是CCLabelTTF会为字符串中有/n的地方换行。所以,我就人为的在其中加入/n。可以写个函数做字符串转换。如果有更好的解决方法欢迎留言告诉我。
    编写一个这样的函数:
std::string HelloWorld::convertString( std::string str ,int length)
{
	unsigned int before = 0;
	vector<std::string > subStrs;
	do 
	{
		subStrs.push_back(str.substr(before,length));
		if (before+length >str.size())
		{
			break;
		}
		else
		{
			before = before+length;
		}
		
	} while (true);
	std::string resultStr;
	for (unsigned int i = 0;i<subStrs.size();++i)
	{
		resultStr.append(subStrs[i]).append("/n");
	}
	resultStr.pop_back();
	resultStr.pop_back();	
	return resultStr;
}

   先将字符串按固定长度切成子串,加上/n,并拼起来,最后去掉多余的/n。然后再更改创建Label那行:

    CCLabelTTF* pLabel = CCLabelTTF::create(convertString(str,32).c_str(), "Arial", 24);

    编译运行,就可以了。

5、总结

    通过使用CCScale9Sprite这个类,创建一个可变大小的背景,然后创建固定宽度的Label,并将两者关联。如果想进一步封装的话,可以创建一个类将两者作为一个复合对象,具体可参照之前的文章:子类化CCNode,扩展一个多功能的对象    。


本篇博客出自阿修罗道,转载请注明出处:http://blog.csdn.net/fansongy/article/details/9903117


分类: 未分类 标签:

『HTML5梦幻之旅』-缤纷多姿的烟花效果

2013年8月9日 没有评论

天花无数月中开,五采祥云绕绛台。堕地忽惊星彩散,飞空旋作雨声来。怒撞玉斗翻晴雪,勇踏金轮起疾雷。更漏已深人渐散,闹竿挑得彩灯回。

——明·瞿佑·《烟火戏》

记得每年过春节的那段时间,除了欣赏隆冬的景色,剩下的就是欣赏天空中美丽的烟花了。

成都的冬天,天空中总是灰蒙蒙的,像是织了一层薄薄的轻纱,把阳光挡走了一部分。路边的枫树上,没有了夏日整天“知了”,“知了”的小家伙,是否有鸟儿,我却也忘了。树上的枫叶寥寥无几,可能是在某一时候,悄无声息地飘落了;有时路过一棵年岁已高的树,也不知是地球引力还是什么的原因,一片叶子会自然地落下来,不留神的话就会掉到你头顶上,顶着它走几里路了,还没发现。

大冷的天,躲在屋里,有时大风挂起,看着不停散落的枫叶,都开始害怕他们会冻成冰。有时敲代码不知不觉就到了傍晚,天更灰了,回身看看窗外的枫树,只见一片片的红云飘逸在眼前,随着风起而凋零。

除夕夜里,一般是在亲戚家过的,吃完了饭,一家人便一边欣赏提前放飞的烟花,一边聊天。屋里暖暖的,想到还在外面劳作的人们,不觉得会为他们打个寒战。

有时我和父母还有哥哥会提前回家,告别了众亲戚,便往屋里赶,希望还能赶上春节联欢晚会的开始(虽然现在很多人讨厌看春节联欢晚会,但我想这是一种传统,搞得不好可以提意见,但是好的传统应该继续传承下去,就像类的继承一样)。父亲是个不爱花冤枉钱的人,去某个地方从来不打车,要不自己走,要不就自己骑车,或者自己开车。因此在走回去的路上,我又可以观赏这隆冬的华丽夜景了。

回家后,第一件事就是把年货拿出来,不停地吃,父亲一向不许我吃零食,但是过节的时候从来不阻止。记得有一年,父亲叫我和哥哥把所有吃剩的瓜子壳,橘子皮都扔在地上,我说难道不难收拾吗?父亲则说到时候扫一下就可以了,仍在地上才有节日的气氛。到现在来想想,过节不就是要气氛吗?没了气氛,也就没了温馨,没了温馨,这节日还有什么好过的呢?

当钟上的时针和分针都指在12点的位置上的时候,就是该观看烟花的时候了。各种各样的烟花被撒如天幕,绽放出各种五颜六色,奇形怪状的烟花粒子。有的升入云霄,忽地不见了,过一眨眼的功夫,便突然呈现为一点金色的小花,像夜幕中的星星一般。有的就给子弹一样,不停地连发出去,飞到一定高度也消失了,有人说这就是传说中的“冲天炮”,我觉得与其叫“冲天炮”,还不如叫火箭“喀秋莎”算了。烟花的声音可不是一般的混乱,轰隆隆的声响里,总少不了嗖嗖地烟花升天的声音。这些声音倒也吵人,倘若靠近声源处,旁边的人说话是听不见的。

可惜最近几年迷上了编程序,烟花也懒得看了,几年没欣赏烟花了,心里也惦记起来了。最近用html5做了一个拖尾效果,想到用拖尾可以做一个烟花效果,也就尝试做了一下,没想到不做不知道,原来实现起来这么简单。上面瞎扯了一大堆,大家见谅一下,接下来就给大家介绍一下是如何实现的。

先看一下游戏截图:

『HTML5梦幻之旅』-缤纷多姿的烟花效果

『HTML5梦幻之旅』-缤纷多姿的烟花效果

『HTML5梦幻之旅』-缤纷多姿的烟花效果

测试地址:http://www.cnblogs.com/yorhom/articles/3244140.html

用支持html5的浏览器打开就可以。


本次开发和上次一样,用到了开源引擎lufylegend,详细信息如下

lufylegend官方网站:http://lufylegend.com/lufylegend

lufylegend API文档:http://lufylegend.com/lufylegend/api

※注意:在了解了引擎lufylegend的前提下阅读本文方可没有障碍。


接下来是实现过程。

一,改进拖尾类

在上一节《『HTML5梦幻之旅』-炫丽的流星雨效果》中,我们讲解了Smearing这个类,这个类主要用于现实拖尾等效果。上一节中,我们讲到了Smearing.to()方法里的时候,谈到如果对象移动完毕时,自动将自己的mode设置为"complete"。实现这个方面的时候,我们直接将缓动的数据的onComplete进行更改,以达到效果。后来发现这样做不好,因此改进了一下:想将原数据的onComplete保存到一个变量中,再更改onComplete里的数据,更改为先调用先前保存的onComplete,然后再将mode改为"complete",这样的话,用户就可以自己设定onComplete里的内容了。Smearing.to()方法里的代码改为如下:

Smearing.prototype.to = function($duration,$vars){	
	var self = this;
	
	var customFunc = $vars.onComplete || function(){};
	
	$vars.onComplete = function(){
		customFunc();
		self.mode = "complete";
	}
	LTweenLite.to(self.originalSprite,$duration,$vars);
};

代码清单1

二,烟花类Fireworks

为了实现烟花效果,我们封装一个叫Fireworks的类,类的构造器如下:

function Fireworks(x,y,color){
	var self = this;
	base(self,LSprite,[]);
	
	self.fireworksX = x;
	self.fireworksY = y;
	
	self.angle = 20;
	self.count = 18;
	
	self.smearingColor = color;
	
	self._showFireworks();
}

代码清单2

这段代码其实不难理解,首先和拖尾类一样,继承自LSprite,然后把前三个参数保存进自身属性里面,中间有一段代码,如下:

self.angle = 20;
self.count = 18;

代码清单3

这两行代码看似平凡,却十分重要。由于我们的烟花是一圈一圈的,所以,我们在现实烟花喷出来的粒子的时候,要计算出每个烟花的位置。要确定位置,就要确定每个烟花的角度,以及所有烟花粒子的个数,为了实现这个,我们设置这两个属性。angle属性是当前烟花粒子要到达的位置与圆心的连线和上一个烟花粒子要到达的位置与圆心的连线的夹角。count属性是所有烟花粒子的个数。可以看到,如果angle和count想乘,积是360,也就是一圈的度数。

我们每个粒子要到达的位置图示如下:

『HTML5梦幻之旅』-缤纷多姿的烟花效果

这一点想通了就不难了,最后我们调用成员函数_showFireworks(),通过掉用这个函数实现显示烟花。具体代码如代码清单4:

Fireworks.prototype._showFireworks = function(){
	var self= this;
	var kaku;
	
	for(var i=0; i<self.count; i++){
		kaku = i*self.angle;
		var toX = 100*Math.sin(kaku * Math.PI / 180);
		var toY = 100*Math.cos(kaku * Math.PI / 180);
		
		var smearingLayer = new LGraphics();
		smearingLayer.drawArc(0,"",[0,0,5,0,2*Math.PI],true,self.smearingColor);
		
		var spreadingSmearing = new Smearing(smearingLayer);
		spreadingSmearing.x = self.fireworksX;
		spreadingSmearing.y = self.fireworksY;
		spreadingSmearing.to(1,{
			x: toX,
			y: toY,
			onComplete:function(){
				self.mode = "complete";
			}
		});
		self.addChild(spreadingSmearing);
	}
};

代码清单4

前两行代码跳过,因为js程序员都应该知道。然后我们跳到最重要的循环环节,整理后代码如下:

for(var i=0; i<self.count; i++){
	kaku = i*self.angle;
	var toX = 100*Math.sin(kaku * Math.PI / 180);
	var toY = 100*Math.cos(kaku * Math.PI / 180);
	
	var smearingLayer = new LGraphics();
	smearingLayer.drawArc(0,"",[0,0,5,0,2*Math.PI],true,self.smearingColor);
	
	var spreadingSmearing = new Smearing(smearingLayer);
	spreadingSmearing.x = self.fireworksX;
	spreadingSmearing.y = self.fireworksY;
	spreadingSmearing.to(1,{
		x: toX,
		y: toY,
		onComplete:function(){
			self.mode = "complete";
		}
	});
	self.addChild(spreadingSmearing);
}

代码清单5

首先我们为了达到粒子环形围绕效果,我们通过循环,取出每个点的角度,并且通过Math.sin()和Math.cos()两个函数确定该粒子的位置。然后我们画出一个圆形,颜色是我们实例化时给的color参数的值,上面我们已经把它保存起来了,所以这里直接用。画好之后,我们给这个粒子建立拖尾效果。该粒子拖尾的位置是我们保存好的x,y参数。接着通过to方法让改拖尾移动到我们指定的位置。当移动到位后,我们就通过onComplete加入完成时的函数,将该烟花类的mode设置为"complete",因为我们在上面更改了to方法,所以可以自定义onComplete里的东西了。

烟花类就Over了,接下来是有了这些封装之后,如何实现的方法。

三,溅入空中的烟花

先把所有代码放在下面:

init(10,"mylegend",500,500,main);
var backLayer,fireworksLayer;
var back;
//烟花颜色集
var colorArray = new Array(
	"yellow",
	"orangered",
	"red",
	"pink"
);
//加入烟花最大数量
var maxFrame = 4;
//当前加入烟花数量
var frameIndex = 0;
var sound;
function main(){
	LStage.setDebug(true);
	
	//加入音乐
	sound = new LSound("http://stream20.qqmusic.qq.com/34962638.mp3");
	
	//加入底板层
	backLayer = new LSprite();
	addChild(backLayer);
	//加入烟花层
	fireworksLayer = new LSprite();
	addChild(fireworksLayer);
	
	//画一个黑色矩形作为背景
	back = new LGraphics();
	back.drawRect(0,"",[0,0,LStage.width,LStage.height],true,"black");
	backLayer.addChild(back);
	
	//加入时间轴事件
	backLayer.addEventListener(LEvent.ENTER_FRAME,onframe)
}
function addFireworks(){
	var toY = Math.floor(Math.random() * (-350 + 250) - 250);
	
	var colorIndex = Math.floor(Math.random() * 4)
	//画一个黄色矩形作为一颗升天的烟花
	var fireworks = new LSprite();
	fireworks.x = Math.floor(Math.random() * (480 - 20) + 20);
	fireworks.y = 500;
	fireworks.graphics.drawRect(0,"",[0,0,10,10],true,colorArray[colorIndex]);
	
	//为升起的烟花添加一个拖尾
	var smearing = new Smearing(fireworks,50);
	//移动烟花
	smearing.to(1,{
		x: 0,
		y: toY,//-300
		onComplete:function(){
			//添加扩散开的烟花
			var spreading = new Fireworks(fireworks.x,fireworks.y+toY,colorArray[colorIndex]);
			fireworksLayer.addChild(spreading);
		}
	});
	fireworksLayer.addChild(smearing);
}
function onframe(){
	//加入烟花
	if(frameIndex < maxFrame){
		frameIndex ++;
		addFireworks();
	}
	//播放音乐
	if(sound.playing == false){
		sound.play();
	}
	//移除烟花
	for(var key in fireworksLayer.childList){
		if(fireworksLayer.childList[key].mode == "complete"){
			//通过缓动更改烟花透明度
			LTweenLite.to(fireworksLayer.childList[key],0.3,{
				alpha:0,
				onComplete:function(o){
					//移除对象
					fireworksLayer.removeChild(o);
					//如果界面上没有烟花,将已经加入数量设为0
					if(fireworksLayer.childList.length == 0){
						frameIndex = 0;
					}
				}
			});
		}
	}
}

代码清单6

代码都加了注释,我只讲一下设计方案:因为我们的烟花是五颜六色的,所以我们将要有的颜色全部放入colorArray中,然后我们在main中初始化层,并加入背景,音乐,时间轴事件。在时间轴事件触发的onframe函数中,我们通过addFireworks来加烟花。在addFireworks中,我们首先取出一个烟花的颜色,并以这种颜色画出相应的烟花,然后通过拖尾效果中的to方法送这个烟花上天,然后在上天动作完成的时候,我们加入散开的粒子效果,如果我们反复调用addFireworks就会反复出现烟花。由于我们的界面上不能出现太多的烟花,因为一方面会显得拥挤看不清楚效果,另一方面就是会导致界面很卡。为了解决这个问题,我们通过,maxFrame和frameIndex两个变量来控制。当onframe每触发一次,我们就将frameIndex加一,然后判断是否小于maxFrame,如果是,就调用addFireworks(),因为我们在上面定义的maxFrame为4,所以最多加4个烟花到界面上。但是如果我们不把frameIndex重新设置为0的话,且不移除烟花的话,那4个烟花就会一直在屏幕上,一不会消失,而不会重新加入。为了实现这些,我们加入循环,在循环里通过判断mode是否为"complete"来移除对象,通过判断fireworksLayer里的对象是否被移除完了来判断是否把frameIndex重新设置为0。通过这一个系统,就会在画面上不断地出现烟花并消失。这个效果就搞定了~~~~


最后运行出来,连我都感叹道:“这不是久违不见的烟花君吗?”

lufy长者也曰到:“效果很漂亮啊。”

嘿嘿,既然专家都说漂亮了,大家不赶快试试?


最后奉上源代码:http://files.cnblogs.com/yorhom/fireworks.rar

话说这烟花效果效率不高,先截了一次放20个烟花的截图:

『HTML5梦幻之旅』-缤纷多姿的烟花效果

最后我冒着卡死的风险搞了一次放1000个烟花的效果,居然还可以运行,截图如下:

『HTML5梦幻之旅』-缤纷多姿的烟花效果

如果大家要测试效率的话,用把变量maxFrame调大些就可以了。


本篇文章就到此结束了。文章如有什么地方写得不妥,欢迎提出。另外,如果有任何不解的地方,可以在博客下方留言或者新浪微博@Yorhom,当然也可以发邮件,邮箱:wangyuehao1999@gmail.com,我会尽我所能帮你解决。

支持就是最大的鼓励!

—————————————————————-

欢迎大家转载我的文章。

转载请注明:转自Yorhom’s Game Box

http://blog.csdn.net/yorhomwang

欢迎继续关注我的博客

分类: 未分类 标签:

程序员 与 Excel

2013年8月6日 没有评论

    作为一个程序员,我们可以随心开发自己想要程序。给计算机说一个规则,它就会毫无怨言的的去做。这就是我们想要的效果。不过有个前提——这是个简单的规则。当这个规则,即程序,需要频繁的调整与改变时,问题就来了。程序需要有能够随时更改的数据定义。因此配置就应运而生。各种配置文件都出现了。程序去读一个配置文件,然后运行自己的逻辑。很好的解决方案,但特别麻烦问题就从这里出来了。
配置文件是需要人来维护的,而且这个人通常不是程序员。程序员当结束了开发之后,更多的问题随着配置的复杂性增加。多个有关联的配置、更改数据类型的错误、格式的错误… 只有想不到,没有做不到。最后这个程序员忍无可忍了,着手再做一个配置工具。配置工具做好了,自然就不会有问题了。不过维护这个工具又是个费神的工作,甚至这个配置工具还需要配置文件。然后又是坑爹的轮回。
所以解决这个问题的一个好办法是用Excel?Excel所做的其实也是开发配置工具的作用。
但这个配置工具会更加好用,也更容易开发。首先,数值分析与统计都是用Excel或可以用Excel来做的。在Excel的基础上对数据进行更高级的分析处理,再与配置进行关联无疑会更加方便。另外,Excel有强大的纠错能力,更改产生的错误会减到最低。最后,可以导出各种格式的配置文件来供程序使用,具有通用性。
最近才逐渐发现Excel的强悍之处,准备好好研究一下,还望路过的各路神仙共同探讨。
分类: 未分类 标签:

『HTML5梦幻之旅』-炫丽的流星雨效果

2013年8月6日 没有评论

徐家破镜昏如雾。半面人间露。等闲相约是看灯。谁料人间天上、似流星。朱门帘影深深雨。憔悴新人舞。天涯海角赏新晴。惟有桥边卖镜、是闲行。

——宋·刘辰翁·《虞美人》

流星出现的时候,人们都喜欢对着它们许愿,因为传说对着流星许下愿望后,愿望就能实现。不过流星很少见,至少我没有见到过,因此从来没有对着它许愿。最近出于兴趣,制作一个拖尾效果,后来想到可以通过拖尾效果来实现一下流星雨的效果。因此今天就来实现一下,也好让我等没有看到过流星的童鞋长长见识。

先发几个截图吧:

『HTML5梦幻之旅』-炫丽的流星雨效果

『HTML5梦幻之旅』-炫丽的流星雨效果

偶美工不好,所以看上去没什么感觉,不过把背景图换一换,就好看了(就是没有找到合适的图片)。

测试链接:http://www.cnblogs.com/yorhom/articles/3237944.html

大家不妨对着流星许个愿吧,说不定愿望能实现呢。『HTML5梦幻之旅』-炫丽的流星雨效果

一,准备工作

本次开发需要用到开源引擎lufylegend.js,引擎的下载地址&详细信息如下

引擎官方网站:

http://lufylegend.com/lufylegend

引擎API网站:

http://lufylegend.com/lufylegend/api

二,拖尾效果

实现流星雨,要用到拖尾效果,但lufylegend中没有添加拖尾的功能,所以只有自己写了,其实实现起来也不难,就是lufy太懒了,没有封装而已(愿lufy不要看到这句话啊……)。今天我就帮他老人家来实现一下这个效果。

拖尾这个效果在游戏中很常见,比如人物移动时的幻影,子弹等。因此我们把它封装为一个Smearing类,这个类主要负责实现拖尾效果。代码如下:

/**
* Smearing
* @param $object 添加拖尾的对象
*/
function Smearing($object){
	var self = this;
	base(self,LSprite,[]);
	
	self.x = 0;
	self.y = 0;
	
	self.mode = "";
	
	self.smearingSprite = new LSprite();
	self.addChild(self.smearingSprite);
	
	self.object = $object;
	
	self.originalSprite = new LSprite();
	self.addChild(self.originalSprite);
	self.originalSprite.addChild(self.object);
	
	self.addEventListener(LEvent.ENTER_FRAME,self.smeared);
}

代码清单1

接下来由我逐字逐句地解释一番。

第一行代码就不讲解了,地球上的IT人都知道。因此从第二行开始说起。

首先我们将这个类用base继承自LSprite,如代码清单2(至于base和LSprite是什么,可以到API文档里去看看,或者看看我以前的文章)。

base(self,LSprite,[]);

代码清单2

接下来,我们加入一个用来添加拖尾的层。如代码清单3

self.smearingSprite = new LSprite();
self.addChild(self.smearingSprite);

代码清单3

然后我们保存一下添加拖尾效果的对象,这样方便以后使用。如代码清单4所示

self.object = $object;

代码清单4

然后添加放置要添加拖尾效果对象的层,并将它显示出来。如代码清单5

self.originalSprite = new LSprite();
self.addChild(self.originalSprite);
self.originalSprite.addChild(self.object);

代码清单5

最后添加一个时间轴事件,方便添加拖尾。

self.addEventListener(LEvent.ENTER_FRAME,self.smeared);

代码清单6

到这里,Smearing构造器就写完了,也解释完了,看不懂的话可能是你不了解lufylegend,里面的addChild,LSprite都是lufylegend中封装的。

我们在上面的代码中已经加入了时间轴事件。为什么要加入呢?因为我不妨说一下拖尾的原理。拖尾其实就是不断地将原对象克隆出来,然后放在现在所在的位置上,相当于不断地向画面上盖章。当原对象移开时,我们克隆的对象并没有移开,而原对象移开了,如果我们增加的对象有很多,那就会形成一条链接原对象的线。这时我们再遍历一下这个线里的每个成员,通过缓动来改变当前对象的透明度。然后判断该对象的透明度是否为0,如果是就移除,避免占太多空间。因此,我们添加时间轴事件用来不断添加拖尾对象。

Smearing成员函数smeared起到这点作用,代码如下:

Smearing.prototype.smeared = function(self){	
	var smearingChild = new SmearingChild(self.originalSprite,self.object);
	self.smearingSprite.addChild(smearingChild);

	for(var key in self.smearingSprite.childList){
		LTweenLite.to(self.smearingSprite.childList[key],0.5,{
			alpha: 0,
			onComplete:function(o){
				self.smearingSprite.removeChild(o);
			}
		});
	}
};

代码清单7

这些代码按照我在上面所说的原理执行。可以看到我们在最后遍历了拖尾层的成员,然后改变遍历到的对象的透明度,并且在缓动结束后移除自身。其中的缓动类用的是lufylegend中封装好了的LTweenLite,可以去API文档里看看,写得很详细。

主要是上面两行代码,如代码清单8:

var smearingChild = new SmearingChild(self.originalSprite,self.object);
self.smearingSprite.addChild(smearingChild);

代码清单8

可以看到又用到了一个名为SmearingChild的类,这个便是传说中的拖尾类。这个类不容忽视,虽然代码很少,但是很重要,里面的代码如代码清单9:

/**
* SmearingChild
* @param $parent 确定拖尾位置的对象
* @param $object 要添加拖尾效果的对象
*/
function SmearingChild($parent,$object){
	var self = this;
	base(self,LSprite,[]); 
	
	self.addChild($object);
	
	self.x = $parent.x;
	self.y = $parent.y;
	self.alpha = 0.8;
}

代码清单9

以上的类实例化时有两个参数,第一个用来确定这个拖尾位置的,第二个是原对象。首先来解释一下“用来确定这个拖尾位置的”是神马意思,其实我们对象的移动,不是让整个Smearing对象移动,而是让他里面的originalSprite对象移动,所以不干smearingSprite的事,为什么这样设计呢?其实是有原因的(废话,请忽略),原因所在就是,如果我们的拖尾的坐标设置为整个Smearing对象的坐标位置,那加到smearingSprite的对象也会跟着移动,拖尾就会错位,从而达不到效果。所以我采取了以上的办法:不移动本身,而是移动originalSprite。因此,我们要把originalSprite的数据传到SmearingChild中,因此就通过$parent来获取。

讲了一通,大伙应该也明白了些。后面放出代码,大家可以拿下去研究,或者在文章下方提出问题或者用新浪微博@Yorhom,还可以用邮箱,邮箱地址:wangyuehao1999@gmail.com。(联系方式多多啊 (^o^))

Smearing这个类还差个功能,那就是让对象缓缓移动,实现起来也很简单,加入to函数:

Smearing.prototype.to = function($duration,$vars){	
	var self = this;
	
	$vars.onComplete = function(){
		self.mode = "complete";
	}
	LTweenLite.to(self.originalSprite,$duration,$vars);
};

代码清单10

第一个参数是移动执行的时间;第二个参数是执行缓动的数据,和LTweenLite.to方法最后一个参数是一样的,参照API文档即可。不过值得注意的是,为了方便操作,我们在移动结束时,将该对象的mode属性改为“complete”。这样做是为了让大家根据mode属性的值来决定是否作出其他的操作,比如移除该对象,或者往其他地方移动。

Smearing这个类封装好了,使用起来就简单了,如下:

init(10,"mylegend",500,400,main);
var back;
function main(){
	LStage.setDebug(true);
	
	back = new LSprite();
	back.graphics.drawRect(0,"",[0,0,50,50],true,"blue");
	
	smearing = new Smearing(back);
	smearing.to(2,{
		x: 200,
		y: 200
	});
	addChild(smearing);
}

代码清单11

演示效果图如下:

『HTML5梦幻之旅』-炫丽的流星雨效果

测试链接:http://www.cnblogs.com/yorhom/articles/3237266.html

三,炫丽的流星雨效果

有了,Smearing这个类,我们的流星雨就简单多了。首先把所有代码展示一下:

init(10,"mylegend",500,400,main);
var backLayer,meteorLayer;
var back,meteor;
var maxFrame = 40,indexFrame = 0;
function main(){
	LStage.setDebug(true);
	
	//加入底板层
	backLayer = new LSprite();
	addChild(backLayer);
	//加入流星层
	meteorLayer = new LSprite();
	addChild(meteorLayer);
	
	//画一个黑色矩形作为背景
	back = new LGraphics();
	back.drawRect(0,"",[0,0,LStage.width,LStage.height],true,"black");
	backLayer.addChild(back);
	
	//画一个黄色矩形作为一颗流星
	meteor = new LSprite();
	meteor.graphics.drawRect(0,"",[0,0,10,10],true,"yellow");
	
	
	
	backLayer.addEventListener(LEvent.ENTER_FRAME,onframe);
}
function onframe(){
	if(indexFrame > maxFrame){
		indexFrame = 0;
		//为每个流星添加一个拖尾
		var smearing = new Smearing(meteor,50);
		smearing.x = Math.floor(Math.random() * 250);
		smearing.y = 0;
		smearing.to(2,{
			x: Math.floor(Math.random() * (500 - 480) + 480),
			y: 400
		});
		meteorLayer.addChild(smearing);
	}
	for(var key in meteorLayer.childList){
		if(meteorLayer.childList[key].mode == "complete"){
			meteorLayer.removeChild(meteorLayer.childList[key]);
		}
	}
	indexFrame ++;
}

代码清单12

每行代码都加入了注释,理解起来一定很简单了。如果实在是理解不到,可能是因为你没有了解lufylegend罢了。可以参照API文档学习一下。

最后是代码打包,下载地址:http://files.cnblogs.com/yorhom/Smearing.rar

本篇文章就到此结束了。文章如有什么地方写得不妥,欢迎提出。另外,如果有任何不解的地方,可以在博客下方留言,我会尽我所能帮你解决。

支持就是最大的鼓励!

—————————————————————-

欢迎大家转载我的文章。

转载请注明:转自Yorhom’s Game Box

http://blog.csdn.net/yorhomwang

欢迎继续关注我的博客

分类: 未分类 标签:

Cocos2D-x HelloCpp for Android unable to build apk from Windows due to permission denied on asset file

2013年8月5日 没有评论

I was trying to run cocos2dx HelloCpp sample project on Android, building from Windows-7 64 bit with Cygwin 64 bit, however, everytime I try to build and run, it complains that permission was denied on “Marker Felt.fnt” file in assets/font folder.

I checked that there’s no permission on that file and chmod to give it proper permission, but everytime I try to run again, that file seems to be regenerated and has no permission again…

Does anyone has the same problem? I have been googling and the nearest problem I’ve found is this:

Cocos2dx Android: Get data from file(assets/*) failed

However, it is quite different. I’ve tried disabling UAC on my Windows machine, but the problem doesn’t go away

Any help is highly appreciated

Check the proj.android/build_native.sh, every time you run the build, the entire assets/* folder will be re-created, and thus, your chmod is nullified.

You can chmod after the copy process itself in the build_native.sh, place the chmod somewhere after cp the assets/*

in my case, put

chmod 777 -R "$APP_ANDROID_ROOT"/assets 

after copying the assets folder in build_native.sh like this:

if [ -f "$file" ]; then
    cp "$file" "$APP_ANDROID_ROOT"/assets
fi

chmod 777 -R "$APP_ANDROID_ROOT"/assets
done
分类: cocos2d, stackoverflow精选 标签: