本帖最后由 pplboy 于 2014-10-13 12:00 编辑
一切源于 wujian001215 帅哥
版主 能不能把游戏从无到有的过程给我讲解下 就是说 一个游戏制作需要哪些元素 哪些egret方法哪些素材 刚接触 感觉很有意思,想深入研究
前天 16:14
讲解我可担当不起,只能尽自己的一些经验很浅薄的说说,抛砖引玉,希望真正的大牛来给支支招。
我感觉一个游戏肯定要有的因素是,玩法,角色,其他模式。。咳咳 写的自己都觉得寒蝉鸟。
这样吧,说说我怎么想起来做那个粘粘的过程吧。
(一)想法,当时就是觉得想做个比较耐玩的游戏,然后想啊想啊,先尝试别人已经觉得耐玩的游戏吧。正好边学Egret边实现,反正没啥坏处。
之前我也玩过一段时间 消灭星星 那个游戏,感觉上很耐玩,并且也符合我当时的目标,画面很简单么,就是些方块(俺的美术水平就是停留在能拼凑的阶段)
有了这个想法后,没有开始写程序就开始去分析 消灭星星的游戏模式
(二)简单的分析后,感觉这个游戏模式并不复杂,单就玩法分解一下
1 在一个容器里放上一些随机颜色的色块
2 点击一个色块,让与其相连的同色色块都处于被选中状态
3 再次点击色块,让被选中的色块消失掉
4 垒在色块上的色块要往下掉补掉掉下的那些色块
5 如果色块一列都消除了,那么往左平移动所有右方的色块。
6 如果容器里的所有色块都处于两个连接都没有的情况,算是过关,或者说是死局。
7 增加点难度,60秒如果没进入死局的状态,就GameOver
(三)然后就是找蔬菜啦,baidu google 到处爬,看到好看的能激发想法的图片就保存下来,然后对着电脑死盯半个小时 开始绘制原型图。把几张原型图画好,基本上也就想清楚这个游戏应该怎么倒腾了。然后把需要的素材,都切出来,保存成资源。
(四)按照第二步的分解,开始逐渐在代码中实现各个部分的功能。下面一大波代码前来助兴。
1 在一个容器里放上一些随机颜色的色块
这个简单,只要将方块往容器里填充就行了,设定x y 的坐标和颜色,行 列,就OK了。
由于之后需要移动方块,所以先得准备一个二维数组,然后将生成的方块的引用都扔到数组里
[mw_shl_code=applescript,true]
private rowNum;
private colNum;
private initMapData(){
this.rowNum = 11; //每行元素数
this.colNum = 14; //每列元素数
// this.colNum = 15; //每列元素数
this.map = [];
for(var x=0;x<this.rowNum;x++){
var tmp_array = [];
for(var y=0;y<this.colNum;y++){
var type = GameApp.random(1,7);
var obj = new Block(type,x,y);
tmp_array[y] = obj;
}
this.map[x] = tmp_array;
}
//console.log(this.map);
this.drawMap();
}
private drawMap(){
this.MapContainer = new egret.DisplayObjectContainer;
for(var x=0;x<this.rowNum;x++){
for(var y=0;y<this.colNum;y++){
this.map[x][y].draw();
this.map[x][y].x = 20+x*40;
this.map[x][y].y = 140+y*40;
this.map[x][y].touchEnabled = true;
this.map[x][y].addEventListener(egret.TouchEvent.TOUCH_TAP,this.onBlockClick,this);
this.MapContainer.addChild(this.map[x][y]);
}
}
this.addChild(this.MapContainer);
}
[/mw_shl_code]
2 点击一个色块,让与其相连的同色色块都处于被选中状态
呃,这个步骤我们再拆解一下吧,第一步是让色块可以被点中,点中后会触发一段代码[mw_shl_code=applescript,true]
this.map[x][y].addEventListener(egret.TouchEvent.TOUCH_TAP,this.onBlockClick,this);
[/mw_shl_code]
第二个步骤是找到附近相同颜色的色块,然后让他们都处于被选中的状态。
[mw_shl_code=applescript,true]
private onBlockClick(evt:egret.TouchEvent){
if(this.clickNum==1){
// 高亮当前色附近的同色色块
this.startBlock = evt.target;
try{
this.selectArea = [];
this.checkNear(evt.target);
}catch(e){
//console.log(e);
}
//console.log(this.selectArea);
if(this.selectArea.length>0){
this.clickNum=2;
this.selectArea.push(evt.target);
for(var i=0;i<this.selectArea.length;i++){
var em = egret.Tween.get( this.selectArea );
em.to( {scaleX:1.2,scaleY:1.2}, 500);
}
}
}else if(this.clickNum == 2){
//消除
this.clickNum = 1;
if(this.selectArea.length>=2 && evt.target.type == this.startBlock.type){
for(var i=0;i<this.selectArea.length;i++){
this.MapContainer.removeChild(this.selectArea);
this.map[this.selectArea.GX][this.selectArea.GY] = 0;
//刷新地图
this.resetMap();
}
// this.sounddd.play();
if(this.selectArea.length>6){
// this.soundhc.play();
}
this.score +=this.selectArea.length*this.selectArea.length;
this.scoreTextField.text = "得分:"+(this.score);
}else{
for(var i=0;i<this.selectArea.length;i++){
this.selectArea.checked = 0;
var em = egret.Tween.get( this.selectArea );
em.to( {scaleX:1,scaleY:1}, 500);
}
}
}
}
//检查相邻的元素 贪婪周边算法
private checkNear(em){
//console.log("em.GX:"+em.GX);
//console.log("em.GY:"+em.GY);
var x = em.GX;
var y = em.GY;
em.checked = 1;
var tmpArray= [];
if((y-1)>=0 && this.map[x][y-1].checked==0 && this.map[x][y-1].type==em.type ){
this.map[x][y-1].checked = 1;
tmpArray.push(this.map[x][y-1]);
//console.log("上同色");
}
if((y+1)<this.colNum && this.map[x][y+1].checked==0 && this.map[x][y+1].type==em.type){
this.map[x][y+1].checked = 1;
tmpArray.push(this.map[x][y+1]);
//console.log("下同色");
}
if((x-1)>=0&&this.map[x-1][y].checked==0 && this.map[x-1][y].type==em.type){
this.map[x-1][y].checked = 1;
tmpArray.push(this.map[x-1][y]);
//console.log("左同色");
}
if((x+1)<this.rowNum&&this.map[x+1][y].checked==0 && this.map[x+1][y].type==em.type){
this.map[x+1][y].checked = 1;
tmpArray.push(this.map[x+1][y]);
//console.log("右同色");
}
if(tmpArray.length==0){
return false;
}else{
for(var i=0;i<tmpArray.length;i++){
this.selectArea.push(tmpArray);
}
for(var i=0;i<this.selectArea.length;i++){
this.checkNear(this.selectArea);
}
}
return false;
}
[/mw_shl_code]
3 再次点击色块,让被选中的色块消失掉
当第二次点击的时候,清除色块
这个的实现在上面的 逻辑中了
[mw_shl_code=applescript,true]
if(this.clickNum == 2){
[/mw_shl_code]
4 垒在色块上的色块要往下掉补掉掉下的那些色块
这个就看出来之前需要的map了,其实就是地图存方块的那个数组,先把一列里空掉的最后一个0 往上挪动到不能挪动为止,
然后再挪动 第二个为空的元素,递归遍历一下,最后的结果就是空的被挪动上去了,则有元素的东西就掉下来了。
我这个方法很笨了,但是能用就行。
[mw_shl_code=applescript,true]
public resetMap(){
var moveCol = [];
var moveRow = [];
for(var x=0;x<this.rowNum;x++){
var colEmNum = 0;
for(var y=0;y<this.colNum;y++){
if(this.map[x][y]==0){
//查找上方元素 如有元素整体下移
if((y-1)>=0 && this.map[x][y-1]!=0 ){
moveCol[x] = x;
//console.log("下移动列"+x);
}
//查找右方元素 如有元素整体左移
}else{
colEmNum++;
};
}
if(colEmNum==0){
moveRow[x] = x;
}
}
//console.log("moveRow-");
//console.log(moveRow);
//console.log("moveRow-");
//console.log(this.map);
if(moveCol.length>0){
for(var e in moveCol){
//console.log(e);
this.moveCol(e);
}
}
if(moveRow.length>0){
for(var e in moveRow){
//console.log(e);
this.moveRow(e);
}
}
if(this.checkMap()){
console.log("死局");
// this.soundhc.play();
this.levelUp();
}
//console.log(this.map);
}
[/mw_shl_code]
5 如果色块一列都消除了,那么往左平移动所有右方的色块。
同上,这次搞右边的空方块,代码也在上面那坨里了,补上移动的方法
[mw_shl_code=applescript,true] //冒泡算法向上移动0元素
public moveCol(e){
//下落元素
for(var n=this.colNum;n>0;n--){
for(var y=this.colNum;y>0;y--){
if(this.map[e][y]==0){
this.map[e][y] = this.map[e][y-1];
this.map[e][y-1]=0;
this.map[e][y].GY +=1;
this.map[e][y].y +=40;
break;
}
}
}
}
//将e 右面的所有元素偏移到当前e列
public moveRow(e){
for(var x=e;x<this.rowNum;x++){
for(var y=this.colNum-1;y>=0;y--){
//不抛出异常就会有一个错误
try{
this.map[x][y] = this.map[parseInt(x)+1][y];
this.map[parseInt(x)+1][y]=0;
if(this.map[x][y]!=0){
this.map[x][y].GX -=1;
this.map[x][y].x -=40;
}
}catch(e){}
}
}
}[/mw_shl_code]
6 如果容器里的所有色块都处于两个连接都没有的情况,算是过关,或者说是死局。
这个游戏怎么了结呢,其实有一个很噁心的防止死局的算法,穷举所有的色块,一旦发现有两个以上相连的同色色块,就退出,否则,就往死里穷举
如果都试玩了,还没有,就算是死局啦。
[mw_shl_code=applescript,true]
public checkMap(){
var tmpArray= [];
for(var x=0;x<this.rowNum;x++){
for(var y=0;y<this.colNum;y++){
if(this.map[x][y]!=0){
var em = this.map[x][y];
if((y-1)>=0 && this.map[x][y-1].checked==0 && this.map[x][y-1].type==em.type ){
tmpArray.push(this.map[x][y-1]);
//console.log("上同色");
}
if((y+1)<this.colNum && this.map[x][y+1].checked==0 && this.map[x][y+1].type==em.type){
tmpArray.push(this.map[x][y+1]);
//console.log("下同色");
}
if((x-1)>=0&&this.map[x-1][y].checked==0 && this.map[x-1][y].type==em.type){
tmpArray.push(this.map[x-1][y]);
//console.log("左同色");
}
if((x+1)<this.rowNum&&this.map[x+1][y].checked==0 && this.map[x+1][y].type==em.type){
tmpArray.push(this.map[x+1][y]);
//console.log("右同色");
}
}
}
}
console.log(tmpArray.length);
if(tmpArray.length==0){
return true;
}
}
[/mw_shl_code]
7 增加点难度,60秒如果没进入死局的状态,就GameOver
这些属于给游戏增加难度的了,好的游戏不光要有玩法,还要有很多限制,人嘛就是要有些挑战才会玩的开心(看来自虐心人人有啊)。
[mw_shl_code=applescript,true]
private initTime(){
this.gameTime.addEventListener(egret.TimerEvent.TIMER,this.onGameTime,this);
}
private onGameTime(){
this.nowTime -=1;
var tw = egret.Tween.get( this.timeLine );
tw.to( {width this.timeLineStartWidth/120)*this.nowTime}, 1000);
//////console.log(this.nowTime);
if(this.nowTime<=0){
//Game Over
this.stopTime();
//////console.log("Time Over");
var daterEvent:GameEvent = new GameEvent(GameEvent.GAMEOVER);
daterEvent._gametype = 1;
daterEvent._score = this.score;
//时间到
daterEvent._dieType = 1;
this.dispatchEvent(daterEvent);
}
}
[/mw_shl_code]
以上就是一个游戏从无到有的过程,wujian001215 满意了吧 ~~~~~
其实啊从无到有,就是个“做”字。祝你好好学习,天天向上 。。{:6_142:学习本身就是一个很快乐的事情,自己构想,自己实现,一点点的,爽歪歪。都是些小玩意,通一则通百。
所以捏,有问题我很乐意解答哈。charlie19817 我的微信,欢迎小伙伴们一起愉快的玩耍。。。。。

最后附上 粘粘 的地址 http://isqgame.com/app/cl/nn/launcher/release.html
|