1 UI部分
Ext.define('mobile2048.view.maincontainer', {
extend: 'Ext.Container',
requires: [
'Ext.Panel',
'Ext.field.Text',
'Ext.Button'
],
config: {
height: 400,
itemId: 'maincontainer',
style: 'background:#bbada0',
width: 326,
layout: 'fit',
items: [
{
xtype: 'container',
layout: 'vbox',
items: [
{
xtype: 'panel',
height: 80,
style: '',
layout: 'hbox',
items: [
{
xtype: 'container',
border: 2,
centered: false,
height: 68,
itemId: 'g11',
margin: 5,
padding: 28,
style: 'background:rgba(238, 228, 218, 0.35)',
width: 71
},
{
xtype: 'container',
baseCls: '',
border: 2,
centered: false,
cls: 'backgroud-color:blue',
height: 68,
itemId: 'g12',
margin: 5,
padding: 28,
style: 'background:rgba(238, 228, 218, 0.35)',
width: 71
},
{
xtype: 'container',
baseCls: '',
border: 2,
centered: false,
cls: 'backgroud-color:blue',
height: 68,
itemId: 'g13',
margin: 5,
padding: 28,
style: 'background:rgba(238, 228, 218, 0.35)',
width: 71
},
{
xtype: 'container',
baseCls: '',
border: 2,
centered: false,
cls: 'backgroud-color:blue',
height: 68,
itemId: 'g14',
margin: 5,
padding: 28,
style: 'background:rgba(238, 228, 218, 0.35)',
width: 71
}
]
},
{
xtype: 'panel',
height: 80,
layout: 'hbox',
items: [
{
xtype: 'container',
border: 2,
centered: false,
height: 68,
itemId: 'g21',
margin: 5,
padding: 28,
style: 'background:rgba(238, 228, 218, 0.35)',
width: 71
},
{
xtype: 'container',
baseCls: '',
border: 2,
centered: false,
cls: 'backgroud-color:blue',
height: 68,
itemId: 'g22',
margin: 5,
padding: 28,
style: 'background:rgba(238, 228, 218, 0.35)',
width: 71
},
{
xtype: 'container',
baseCls: '',
border: 2,
centered: false,
cls: 'backgroud-color:blue',
height: 68,
itemId: 'g23',
margin: 5,
padding: 28,
style: 'background:rgba(238, 228, 218, 0.35)',
width: 71
},
{
xtype: 'container',
baseCls: '',
border: 2,
centered: false,
cls: 'backgroud-color:blue',
height: 68,
itemId: 'g24',
margin: 5,
padding: 28,
style: 'background:rgba(238, 228, 218, 0.35)',
width: 71
}
]
},
{
xtype: 'panel',
height: 80,
layout: 'hbox',
items: [
{
xtype: 'container',
border: 2,
centered: false,
height: 68,
itemId: 'g31',
margin: 5,
padding: 28,
style: 'background:rgba(238, 228, 218, 0.35)',
width: 71
},
{
xtype: 'container',
baseCls: '',
border: 2,
centered: false,
cls: 'backgroud-color:blue',
height: 68,
itemId: 'g32',
margin: 5,
padding: 28,
style: 'background:rgba(238, 228, 218, 0.35)',
width: 71
},
{
xtype: 'container',
baseCls: '',
border: 2,
centered: false,
height: 68,
itemId: 'g33',
margin: 5,
padding: 28,
style: 'background:rgba(238, 228, 218, 0.35)',
width: 71
},
{
xtype: 'container',
baseCls: '',
border: 2,
centered: false,
cls: 'backgroud-color:blue',
height: 68,
itemId: 'g34',
margin: 5,
padding: 28,
style: 'background:rgba(238, 228, 218, 0.35)',
width: 71
}
]
},
{
xtype: 'panel',
height: 80,
layout: 'hbox',
items: [
{
xtype: 'container',
border: 2,
centered: false,
height: 68,
itemId: 'g41',
margin: 5,
padding: 28,
style: 'background:rgba(238, 228, 218, 0.35)',
width: 71
},
{
xtype: 'container',
baseCls: '',
border: 2,
centered: false,
cls: 'backgroud-color:blue',
height: 68,
itemId: 'g42',
margin: 5,
padding: 28,
style: 'background:rgba(238, 228, 218, 0.35)',
width: 71
},
{
xtype: 'container',
baseCls: '',
border: 2,
centered: false,
cls: 'backgroud-color:blue',
height: 68,
itemId: 'g43',
margin: 5,
padding: 28,
style: 'background:rgba(238, 228, 218, 0.35)',
width: 71
},
{
xtype: 'container',
baseCls: '',
border: 2,
centered: false,
cls: 'backgroud-color:blue',
height: 68,
itemId: 'g44',
margin: 5,
padding: 28,
style: 'background:rgba(238, 228, 218, 0.35)',
width: 71
}
]
},
{
xtype: 'textfield',
itemId: 'score',
label: '分数',
value: 100,
readOnly: true
},
{
xtype: 'button',
itemId: 'reset',
width: 121,
text: '重新开始'
}
]
}
]
}
});
2 控制器
Ext.define('mobile2048.controller.main', {
extend: 'Ext.app.Controller',
config: {
refs: {
main: '#maincontainer'
},
control: {
"container#maincontainer": {
initialize: 'onMaincontainerInitialize'
},
"button#reset": {
tap: 'onResetTap'
}
}
},
onMaincontainerInitialize: function(component, eOpts) {
var com = component;
this.initGrid(com);
com.renderElement.addListener('swipe',this.handleSwipe,this);
return false;
},
onResetTap: function(button, e, eOpts) {
this.initGrid();
return false;
},
initGrid: function(com) {
// console.log('initGrid');
this.resetGame();
this.generateRandomNum();
return false;
},
handleSwipe: function(e,node,options) {
if(this.gameOver()){
Ext.Msg.show({
title: '游戏结束,请重新开始',
buttons: Ext.Msg.OK
});
return;
}
var direc = e.direction;
switch(direc){
case 'up':
this.processUp();
break;
case 'down':
this.processDown();
break;
case 'left':
this.processLeft();
break;
case 'right':
this.processRight();
break;
}
return false;
},
processUp: function() {
console.log('up');
for(var i=1;i<=4;i++){
var row = this.fetchRow(i,1);
this.reArrange(i,row,'UP');
}
this.generateRandomNum();
return false;
},
processDown: function() {
console.log('down');
for(var i=1;i<=4;i++){
var row = this.fetchRow(i,1).reverse();
this.reArrange(i,row,'DOWN');
}
this.generateRandomNum();
return false;
},
processLeft: function() {
console.log('left');
for(var i=1;i<=4;i++){
var row = this.fetchRow(i,0);
this.reArrange(i,row,'LEFT');
}
this.generateRandomNum();
return false;
},
processRight: function() {
console.log('right');
for(var i=1;i<=4;i++){
var row = this.fetchRow(i,0).reverse();
this.reArrange(i,row,'RIGHT');
}
this.generateRandomNum();
return false;
},
generateRandomNum: function(num) {
var main = this.getMain();
var randomNum = Math.floor((Math.random() * 2) + 2);
var count = 0;
var roundNum = Math.min(randomNum, this.getEmptyCellNum());
while(count<roundNum){
var col = Math.floor((Math.random() * 4) + 1);
var row = Math.floor((Math.random() * 4) + 1);
var cub = main.down('#g'+row+col);
if(Ext.isEmpty(cub.get('html'))){
randomNum = Math.floor((Math.random() * 2)) * 2 + 2;
cub.set('html',randomNum);
this.totalScore += randomNum;
// console.log(row,col,randomNum,count);
cub.set('style',mobile2048.Color[randomNum]);
count++;
}
}
this.updateScore();
return false;
},
gameOver: function() {
var main = this.getMain(),cell_a,a_v,cell_b,b_v, over = true;
if(this.getEmptyCellNum() !== 0){
return false;
}
for(var i=1;i<=4;i++){
var k=1;
for(var j=1;j<=4 && k<=4;j++){
var k = j+1;
cell_a = main.down('#g' + i + j);
cell_b = main.down('#g' + i + k);
a_v = (cell_a && cell_a.get('html')) ? cell_a.get('html') : null;
b_v = cell_b && cell_b.get('html') ? cell_b.get('html') : null;
if(a_v === b_v){
over = false;
break;
}
}
if(!over) break;
}
if(over){
for(var i=1;i<=4;i++){
var k=1;
for(var j=1;j<=4 && k<=4;j++){
var k = j+1;
cell_a = main.down('#g' + j + i);
cell_b = main.down('#g' + k + i);
a_v = (cell_a && cell_a.get('html')) ? cell_a.get('html') : null;
b_v = cell_b && cell_b.get('html') ? cell_b.get('html') : null;
if(a_v === b_v){
over = false;
break;
}
}
if(!over) break;
}
}
return over;
},
fetchRow: function(rowNum, flag) {
var row = [], main = this.getMain(),cube;
for(var i=1;i<5;i++){
if(flag === 0){
cube = main.down('#g' + rowNum + i);
}else{
cube = main.down('#g' + i + rowNum);
}
var val = cube.get('html');
val = val?val:0;
row.push(val);
}
// console.log('fetched '+row);
return row;
},
updateScore: function() {
var main = this.getMain();
main.down('#score').setValue(this.totalScore);
},
reArrange: function(rownum,row,direction) {
var main = this.getMain();
if(row){
switch(direction){
case 'LEFT':
row = this.merge(row);
break;
case 'RIGHT':
row = this.merge(row).reverse();
break;
case 'UP':
row = this.merge(row);
break;
case 'DOWN':
row = this.merge(row).reverse();
break;
}
// console.log('rearrange ' + row);
var len = row.length,cell;
for(var i=1;i<=len;i++){
if(direction === 'LEFT' || direction === 'RIGHT'){
cel = main.down('#g'+rownum+i);
}else{
cel = main.down('#g'+i+rownum);
}
var val = row[i-1];
cel.set('html',val !== 0 ? val : null);
cel.set('style',val !== 0 ? mobile2048.Color[val] : mobile2048.Color.defaultStyle);
}
}
},
merge: function(row) {
for(var i=0;i<row.length;i++){
if(row[i] === 0)
continue;
for(var j = i+1;j<row.length;j++){
if(row[i] === row[j] && j === i+1){
row[i] += row[j];
row[j] = 0;
i++;
}
}
}
var count = 0;
var len = row.length;
var arr = [];
for(var i=0; i<len;i++){
if(row[i] !== 0){
arr.push(row[i]);
}
}
while(arr.length<len){
arr.push(0);
}
return arr;
},
getEmptyCellNum: function() {
var row,num = 0;
for(var i=1;i<=4;i++){
row = this.fetchRow(i);
for(var j = 0;j<row.length;j++){
if(row[j] === 0)
num++;
}
}
console.log('Empty num of cell:' + num);
return num;
},
resetGame: function() {
var main = this.getMain();
this.totalScore = 0;
for(var i=1;i<5;i++){
for(j=1;j<5;j++){
cell = main.down('#g' + i + j);
cell.set('html',null);
cell.set('style',mobile2048.Color.defaultStyle);
}
}
},
getScore: function(row) {
var score = 0;
for(var i=0;i<row.length;i++){
score += row[i];
}
return score;
},
init: function(application) {
},
launch: function() {
this.totalScore = 0;
}
});
3 application
// @require @packageOverrides
Ext.Loader.setConfig({
});
Ext.application({
views: [
'maincontainer'
],
controllers: [
'main'
],
name: 'mobile2048',
launch: function() {
Ext.define('mobile2048.Color', {
singleton: true,
'defaultStyle': 'background:rgba(238, 228, 218, 0.35)',
'2': 'background:#eee4da',
'4':'background:#ede0c8',
'8':'background:#f2b179',
'16':'background:#f59563',
'32':'background:#f67c5f',
'64':'background:#f65e3b',
'128':'background:#edcf72',
'256':'background:#edcc61',
'512': 'background:#edc850',
'1024': 'background:#edc53f',
'2048':'background:edc22e'
});
Ext.create('mobile2048.view.maincontainer', {fullscreen: true});
}
});
4 效果: