知识储备
java数组、变量、方法等基础,事件监听所用API,类与对象相关部分
素材准备
2~2048素材图片(100100),空图片当作0用(100100),背景图(420*420),游戏失败图片(随意)
流程
首先必须要一个2048小游戏由哪些部分组成
1.基础的窗体
2.窗体菜单(非必要)
3.窗口的绘制
4.游戏逻辑:游戏方块碰撞并累加消除、计算得分、游戏失败的判定、随机位置生成方块
5.事件监听:移动的实现
0.类中成员变量以及构造方法
//初始方块摆放
int [][]index={
{0,0,2,4},
{0,0,0,0},
{0,0,0,0},
{0,0,0,0}
};
int losflag=0;//判断是否失败
int score=0;//初始分数
//构造方法
public MainFrame() {
initFrame();
initMenu();
paint();
//为窗体添加事件监听
this.addKeyListener(this);
setVisible(true);//要最后设置
}
1.创立窗口
public void initFrame() {
setSize(514, 538);
setLocationRelativeTo(null);//居中
setAlwaysOnTop(true);//置顶
setDefaultCloseOperation(3);//启动关闭模式
setLayout(null);//取消默认布局
setTitle("2048小游戏");
}
2.窗体菜单(简略版)
public void initMenu() {
JMenuBar menuBar = new JMenuBar();//框
JMenu menu = new JMenu("皮肤");//框上的菜单
menuBar.add(menu);
JMenuItem menu1=new JMenuItem("并没有任何皮肤");//菜单中选项的下属选项
menu.add(menu1);
}
3.方块碰撞相加消去的逻辑实现
public void Moveleft() {
//左移,需要将每一行不为零的数依次移动到左边
for(int y=0;y<4;y++){
int dex=0;//纪录移动了几个数
for(int i=0;i<4;i++){
if(index[y][i]!=0){
index[y][dex++]=index[y][i];
}
}
//再把右边的数记作0
for(int i=dex;i<4;i++){
index[y][i]=0;
}
//累加并消去
for(int j=0;j<3;j++){
if(index[y][j]==index[y][j+1]){
index[y][j]*=2;
for(int k=j+1;k<3;k++){
index[y][k]=index[y][k+1];
}
//最右边位置一定会变为0
index[y][3]=0;
}
}
}
//重新绘制界面
paint();
上移或下移可以通过顺和逆时针旋转来实现,也可以照搬左移思路,行列换一下就行
//顺时针旋转
for(int i=0;i<4;i++){
for(int j=0;j<4;j++){
copyarr[j][3-i]=index[i][j];
}
}
//转回去
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
index[3-j][i]=copyarr[i][j];
}
}
4.键盘监听部分
@Override
public void keyPressed(KeyEvent e) {
//计分也要在移动方法中移动之前计分
score=0;
for (int i = 0; i < index.length; i++) {
for (int j = 0; j < index[i].length; j++) {
score+=index[i][j];
}
}
//移动
int key=e.getKeyCode();
if(key==37){
Moveleft();
}else if(key==38){
Moveup();
} else if(key==39){
Moveright();
} else if(key==40){
Movedown();
}
//移动之后判定失败
if(fail()==true){ losflag=1; }
Score();
}
5.随机位置生成方块
public void rando() {
int []arrx={-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1};
int []arry={-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1};
int w=0;
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
if (index[i][j] == 0) {
arrx[w]=i;
arry[w]=j;
w++;
}
}
}
if(w>0) {
Random rand = new Random();
int randx = rand.nextInt(w);
index[arrx[randx]][arry[randx]] = 2;
}
else {
return;//满了就退出
}
}
6.得分的计算
你当前场上方块之和减去初始方块之和=分数
public void Score(){
int s=0;
for(int i=0;i<4;i++){
for(int j=0;j<4;j++){
s+=index[i][j];
}
}
score-=s;
}
7.失败的判定
核心思路就是每次移动之后进行一次模拟,若上下左右均无法进行移动,则失败
public boolean fail(){
if(up()&&right()&&down()&&left()) {
return true;
}
return false;
}
public boolean right(){
int [][] arr=new int[4][4];//模拟数组
copyArray(index,arr);//赋值方法,自己写
boolean flag=true;
Moveright();
for(int i=0;i<4;i++){
for(int j=0;j<4;j++){
if(arr[i][j]!=index[i][j]){ flag=false; break;}
}
}
copyArray(arr,index);//归原
paint();//不能忘记绘制!
return flag;
}
8.窗体的绘制
public void paint(){
//移除界面中所有内容
getContentPane().removeAll();//此处的getContentPane()不能省略
//失败图片展示
if(losflag==1){
JLabel loserimg = new JLabel(new ImageIcon("C:\\Users\\30887\\Desktop\\code\\java\\game2048\\src\\image\\img\\img.png"));
loserimg.setBounds(0, 0, 400, 400);
getContentPane().add(loserimg);
}
//分数展示
JLabel scorelabel = new JLabel("Score: "+score);
scorelabel.setBounds(0, 0, 100,20 );
getContentPane().add(scorelabel);
//随机位置生成
rando();
//图片
for(int i=0;i<4;i++){
for(int j=0;j<4;j++){
JLabel image = new JLabel(new ImageIcon("C:\\Users\\30887\\Desktop\\code\\java\\game2048\\src\\image\\img\\"+index[i][j]+".png"));
image.setBounds(50+100*j, 50+100*i, 90, 90);
add(image);
}
}
JLabel background=new JLabel(new ImageIcon("C:\\Users\\30887\\Desktop\\code\\java\\game2048\\src\\image\\img\\background.png"));
background.setBounds(40,40,420,420);
add(background);//直接调用父类方法,没有重写,super可以省略
//刷新界面
getContentPane().repaint();
}