当前位置: 首页 > news >正文

大学生可做的网站主题百度竞价防软件点击软件

大学生可做的网站主题,百度竞价防软件点击软件,河南网站建设公司,wordpress博客程序前言 这里使用安卓最基本的API实现双人四子棋游戏(无AI),开发语言为java,开发环境为Android Studio 2.1.2,目标SDK版本为24,最低为15;界面采用植物大战僵尸主题,图片资源来源于网络&…

@前言

  1. 这里使用安卓最基本的API实现双人四子棋游戏(无AI),开发语言为java,开发环境为Android Studio 2.1.2,目标SDK版本为24,最低为15;
  2. 界面采用植物大战僵尸主题,图片资源来源于网络,进行了PS加工,非原创;
  3. 游戏界面基本可以适配所有安卓手机分辨率,不过在分辨率太大或太小的手机上整体效果会有影响;
    Github源码: https://github.com/jiangxh1992/FourInRowGame
    视频演示: https://vimeo.com/187532089

@更新:

这里另外使用表格布局的方式又写了一个四子棋基础版本,逻辑思路和本文的也不一样了,表格布局虽然没有绝对布局灵活,但容易适配屏幕操作简单。
github源码:https://github.com/jiangxh1992/Connect4Game


1.游戏规则功能目标和界面预览

四子棋的游戏规则和五子棋不同,虽然都是横向纵向或对角线方向上有五个或四个相同的棋子即胜利,但四子棋落子有限制,必须要从棋盘底部往上堆叠,不是可以下在任意位置,就相当于将棋盘竖立起来一样,同时四子棋的棋盘是6x7宫格,横向7个,纵向6个,因此出现平局的现象很正常。

这里游戏首先有一个开始界面,点击开始界面的开始游戏按钮进入游戏界面,游戏界面需要实现提示玩家轮流下子,以及胜利平局等状态。
这里写图片描述

这里写图片描述

这里写图片描述

2.UI界面布局设计

基本的静态界面使用xml来布局,开始界面整体使用绝对布局(为了方便实现小动画),放一张背景图片,开始按钮按照sin函数上下浮动,天空中几朵云按照不同的速度来回飘动:

这里写图片描述

游戏界面主要分三部分,头部,棋盘和底部,背景图片被PS分割成三张图片作为三部分的背景,三部分按照权重高度比例为1:5:2,这样棋盘高度占屏幕高度的5/8,手机屏幕宽高比最大一般就是10:16了,这种情况下棋盘高度刚好和宽度相等,而棋盘实际宽高为6:7,可以保证棋盘足以放下所有棋子了。布局上头部使用相对布局,主要放一些按钮;棋盘因为需要获取点击的坐标进行精确定位,所以要使用绝对布局;底部布局都可以只要将剩余的空间填满就好。

这里写图片描述

3.开始界面逻辑实现(动画)

为了实现开始界面的小动画,单独开一个线程,线程放一个while循环结合sleep函数制造一个update定时更新环境:

对于开始按钮,使其按照sin正弦函数上下摆动,通过振幅参数控制上下摆动的幅度,以及每次更新增长的步幅参数来控制上下摆动的速度;

乌云动画是在界面上布置三个ImageView,然后在每次更新中按照速度参数水平移动云彩的位置,通过速度参数控制云移动的速度和方向,当云超出屏幕足够远时将其重置回合适的位置,调整让三朵云的移动速度不同从而制造一种交错运动的自然效果。

4.游戏界面逻辑实现

1.棋盘的绘制更新

这里棋盘中棋子的更换采用图片资源替换的方式,即游戏初始化时将棋盘每个棋子的位置都放置一个ImageView,图片为一张透明图片,当需要放置棋子或者更换更换棋子时,只要给出指定坐标位置,然后根据该坐标对应的棋子状态替换相应的图片资源即可。

整个棋盘的数据模型是一个二维数组,数组元素的类型是一个自定义的数据结构(包含棋子状态值和对应ImageView的引用):

/*** 棋子节点数据结构 ***/
class Piece{int value;        // 0:空 1:玩家1的棋子 2:玩家2的棋子ImageView image;  // 棋子图片// 构造Piece(){value = 0;image = null;}// 重置void Reset(){value = 0;image.setImageResource(R.drawable.empty);}

棋盘模型:

// 棋盘
private Piece[][] ChessBord = null;

棋盘初始化时:

    /*** 绘制棋盘*/public void DrawChessBoard(){// 绘制棋子洞和空棋子for(int i = 0 ; i<V_NUM ; i++){for (int j = 0 ; j<H_NUM ; j++){// 土壤ImageView view = new ImageView(this);view.setImageResource(R.drawable.chess_bg);view.setMaxHeight(CellWidth);view.setMaxWidth(CellWidth);view.setX(CellWidth*j+LEFT_GAP);view.setY(CellWidth*i);// 绘制到棋盘中CBLayout.addView(view);// 空棋子ImageView piece = new ImageView(this);piece.setImageResource(R.drawable.empty);piece.setMaxHeight(CellWidth);piece.setMaxWidth(CellWidth);piece.setX(CellWidth*j + LEFT_GAP);piece.setY(CellWidth*(V_NUM-i-1));// 棋子图片引用添加到棋盘数据ChessBord[j][i].image = piece;// 绘制棋子到棋盘CBLayout.addView(piece);}}}

更新棋子图片的方法:

ChessBord[point.x][point.y].image.setImageResource(R.drawable.chess_p1_win);

2.玩家下子事件

首先是获取在棋盘中玩家触点的坐标,坐标系原点在绝对布局的棋盘的左上角,根据坐标可以计算玩家选择的是哪一列:然后根据当前期盼状态可以定位到某个棋子,然后可以更新棋盘状态和棋盘界面:

// 开始游戏监听,其中CBLayout为棋盘的绝对布局引用,LEFT_GAP是让左边空出一部分,因为背景图片左右两边有部分墙体内容CBLayout.setOnTouchListener(new View.OnTouchListener() {@Overridepublic boolean onTouch(View v, MotionEvent event) {// 选用点击事件if (event.getAction() == MotionEvent.ACTION_DOWN){// 横坐标float touchX = event.getX() - LEFT_GAP;// 列数int column = (int)(touchX/CellWidth);// 计算并落子SetPiece(CalCoord(column));}return false;}});

3.判断是否有人赢

每当有人下棋时都要进行一次是否有人胜利检查,这里定义一个数据结构来记录以当前棋子位置为中心在横向、纵向、两个对角线四个方向上的相同棋子的个数,初始值都为1因为已经中心位置已经有一个棋子了,统计结束后如果四个方向上有数量大于4的则当前玩家胜利:

/*** 记录双方棋局状态数据结构 ***/
class CheckNode{int Horizontal; // 水平方向上相同棋子的个数int Vertical;   // 竖直方向...int MDiagonal;  // 主对角线...int ADiagonal;  // 辅对角线...// 构造CheckNode(){Horizontal = 1;Vertical = 1;MDiagonal = 1;ADiagonal = 1;}// 重置void Reset(){Horizontal = 1;Vertical = 1;MDiagonal = 1;ADiagonal = 1;}
}

具体统计过程通过一个循环即可实现,以当前点为中心向八个方向扩散,遇到对方棋子则停止,当八个方向都遇到对方棋子时循环终止:

    /*** 检查某个棋子处各个方向上相同棋子的个数,用于判断游戏胜负(返回0表示游戏继续,1表示玩家1赢,2表示玩家2赢)*/public int CheckResult(Point point) {// 检查水平和竖直方向int stopCount = 0; // 8个方向到边界停止的个数int[] stopDir = new int[8];// 八个方向是否已经终止int counter = 0;while (stopCount < 8) {stopCount = 0;++counter;// 上if ((stopDir[0]==1) || (point.y + counter >= V_NUM) || ChessBord[point.x][point.y + counter].value != gameResult) {stopDir[0]=1;//向上超出棋盘或遇到非同色棋子终止} else {checkNode[gameResult - 1].Vertical++;//纵向+1}// 下if ((stopDir[1]==1) || (point.y - counter < 0) || ChessBord[point.x][point.y - counter].value != gameResult) {stopDir[1]=1;} else {checkNode[gameResult - 1].Vertical++;}// 左if ((stopDir[2]==1) || (point.x - counter < 0) || ChessBord[point.x - counter][point.y].value != gameResult) {stopDir[2]=1;} else {checkNode[gameResult - 1].Horizontal++;}// 右if ((stopDir[3]==1) || (point.x + counter >= H_NUM) || ChessBord[point.x + counter][point.y].value != gameResult) {stopDir[3]=1;} else {checkNode[gameResult - 1].Horizontal++;}// 左上if ((stopDir[4]==1) || (point.x - counter < 0) || (point.y + counter >= V_NUM) || (ChessBord[point.x - counter][point.y + counter].value != gameResult)) {stopDir[4]=1;} else {checkNode[gameResult - 1].ADiagonal++;}// 右下if ((stopDir[5]==1) || (point.x + counter >= H_NUM) || (point.y - counter < 0) || (ChessBord[point.x + counter][point.y - counter].value != gameResult)) {stopDir[5]=1;} else {checkNode[gameResult - 1].ADiagonal++;}// 右上if ((stopDir[6]==1) || (point.x + counter >= H_NUM) || (point.y + counter >= V_NUM) || (ChessBord[point.x + counter][point.y + counter].value != gameResult)) {stopDir[6]=1;} else {checkNode[gameResult - 1].MDiagonal++;}// 左下if ((stopDir[7]==1) || (point.x - counter < 0) || (point.y - counter < 0) || (ChessBord[point.x - counter][point.y - counter].value != gameResult)) {stopDir[7]=1;} else {checkNode[gameResult - 1].MDiagonal++;}// 终止循环搜索for(int i =0 ; i<8 ;i++){stopCount += stopDir[i];}}// 判断是否有人赢if (checkNode[gameResult-1].MDiagonal>=4 || checkNode[gameResult-1].ADiagonal>=4 || checkNode[gameResult-1].Horizontal>=4 || checkNode[gameResult-1].Vertical>=4){return gameResult;}else {return 0;}}

4.悔棋功能

悔棋的实现很简单,只要每次下棋都将所下的棋子的位置入栈即可,悔棋依次将节点从栈取出然后根据节点信息更新UI,更新棋盘数据等相关状态,当所有棋子都取出即栈为空时停止悔棋响应:

// 用一个可变数组实现堆栈依次保存所下棋子的顺序
ArrayList<Point>PieceStack = null;
// 初始化栈
PieceStack = new ArrayList<Point>();
// 入栈
PieceStack.add(point);/*** 悔棋一步*/public void WithDraw(){// 异常检测if (PieceStack == null || PieceStack.size() == 0)return;// 取出最后一个坐标并出栈Point point = PieceStack.remove(PieceStack.size()-1);// 棋盘移除最后一步棋ChessBord[point.x][point.y].Reset();// 换人if (gameResult == 1){gameResult = 2;UpdateUI(gameResult);}else {gameResult = 1;UpdateUI(gameResult);}// 计数-1--pieceCount;}

5.特殊显示获胜棋子功能

要特殊显示获胜棋子难点在于要找到同一个方向上个数大于4的棋子,来对其更换图片。当然可以在当时判断是否有人赢时将可能获胜的棋子保存起来,但每次下棋都要判断都要保存,因此操作冗余太大。这里是在确定有人赢之后再根据计算得到的各方向相同棋子个数重新搜索大于4个棋子的行列来确定获胜的棋子:

这里写图片描述

    /*** 显示获胜的棋子*/public void SearchWonPieces(Point point){// 判断是哪个玩家赢了int winimg = 0;if (gameResult == 1)winimg = R.drawable.chess_p1_win;else if (gameResult == 2)winimg = R.drawable.chess_p2_win;else{System.out.print("error!");return;}// 当前下的一个棋子直接特殊显示ChessBord[point.x][point.y].image.setImageResource(winimg);// 某个方向上最多的相同棋子个数肯定不会比最大宽度或者高度棋子数多int maxStep = H_NUM > V_NUM ? H_NUM : V_NUM;for (int i=1 ; i<maxStep; i++){// 上if (checkNode[gameResult-1].Vertical >= 4 && (point.y + i < V_NUM) && ChessBord[point.x][point.y + i].value == gameResult) {// 满足不越棋盘的界,并且是当前获胜玩家的棋子UpdateWinImage(new Point(point.x, point.y+i), new Point(point.x, point.y+i-1), winimg);}// 下if (checkNode[gameResult-1].Vertical >= 4 && (point.y - i >= 0) && ChessBord[point.x][point.y - i].value == gameResult) {UpdateWinImage(new Point(point.x, point.y-i), new Point(point.x, point.y-i+1), winimg);}// 左if (checkNode[gameResult-1].Horizontal >= 4 && (point.x - i >= 0) && ChessBord[point.x - i][point.y].value == gameResult) {UpdateWinImage(new Point(point.x-i, point.y), new Point(point.x-i+1, point.y), winimg);}// 右if (checkNode[gameResult-1].Horizontal >= 4 && (point.x + i < H_NUM) && ChessBord[point.x + i][point.y].value == gameResult) {UpdateWinImage(new Point(point.x+i, point.y), new Point(point.x+i-1, point.y), winimg);}// 左上if (checkNode[gameResult-1].ADiagonal >= 4 && (point.x - i >= 0) && (point.y + i < V_NUM) && (ChessBord[point.x - i][point.y + i].value == gameResult)) {UpdateWinImage(new Point(point.x-i, point.y+i), new Point(point.x-i+1, point.y+i-1), winimg);}// 右下if (checkNode[gameResult-1].ADiagonal >= 4 && (point.x + i < H_NUM) && (point.y - i >= 0) && (ChessBord[point.x + i][point.y - i].value == gameResult)) {UpdateWinImage(new Point(point.x+i, point.y-i), new Point(point.x+i-1, point.y-i+1), winimg);}// 右上if (checkNode[gameResult-1].MDiagonal >= 4 && (point.x + i < H_NUM) && (point.y + i < V_NUM) && (ChessBord[point.x + i][point.y + i].value == gameResult)) {UpdateWinImage(new Point(point.x+i, point.y+i), new Point(point.x+i-1, point.y+i-1), winimg);}// 左下if (checkNode[gameResult-1].MDiagonal >= 4 && (point.x - i >= 0) && (point.y - i >= 0) && (ChessBord[point.x - i][point.y - i].value == gameResult)) {UpdateWinImage(new Point(point.x-i, point.y-i), new Point(point.x-i+1, point.y-i+1), winimg);}}}/*** 替换获胜棋子图片(这里要同时检验当前获胜棋子是否和上一个连续,如果中间有对方棋子间隔那么当前这个获胜玩家的棋子并不是真的获胜棋子)*/public void UpdateWinImage(Point curPoint, Point prePoint, int winimg){if (ChessBord[curPoint.x][curPoint.y].value == ChessBord[prePoint.x][prePoint.y].value){ChessBord[curPoint.x][curPoint.y].image.setImageResource(winimg);}else {// 出现不连续获胜棋子则将这一排剩下的所有获胜玩家的棋子全部排除掉(事实上顶多出现两个不连续的获胜玩家棋子,因为H_NUM为7)int delX = curPoint.x - prePoint.x;int delY = curPoint.y - prePoint.y;Point nextPoint = new Point(curPoint.x+delX, curPoint.y+delY);while (nextPoint.x>=0 && nextPoint.x<H_NUM && nextPoint.y>=0 && nextPoint.y<V_NUM){ChessBord[nextPoint.x][nextPoint.y].value = 0;nextPoint.x += delX;nextPoint.y += delY;}}}

5.声音特效的添加(MediaPlayer & SoundPool)

  1. 安卓中基本的声音组件是MediaPlayer,通过create函数初始化之后就可以调用start等函数很简单的控制声音播放暂停等等,另外可以为MediaPlayer对象添加监听事件,监听试音播放结束从而进行其他操作,比如这里开始界面在点击开始游戏按钮后播放僵尸笑的音效,然后需要在声音播放结束后再进入游戏界面,这就需要用到这个监听了,具体用法示例如下:
// 创建并初始化MeidaPlayer对象
MediaPlayer media_start = MediaPlayer.create(this, R.raw.zombiesmile);
//播放音效
media_start.start();
// 监听音效结束事件
media_start.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {@Overridepublic void onCompletion(MediaPlayer mp) {// 跳转到游戏界面// ...}});

另外可以通过监听播放结束实现背景音乐的循环播放,即在播放结束时再调用start函数重新播放该音乐。

  1. MediaPlayer虽然容易操作,但只能管理一个音乐,延迟较大,不支持多个音乐同时播放,且消耗资源较大,对于游戏中反复使用的多个短促音效通常使用SoundPool来进行管理操作,这里游戏界面用到的音效都使用SoundPool来管理了,背景音乐仍然采用MediaPlayer单独管理,具体用法如下:
// 定义音效池。第一个参数是管理的音乐片段的最大数量,系统会根据这个参数分配适当的缓存空间;第二个参数表示将音效定义为系统音效;最后一个参数是音效的品质,品质越高相应对系统消耗越大
SoundPool soundPool = new SoundPool(4, AudioManager.STREAM_SYSTEM,5);// 这里依次添加四段音效,最后一个参数指的是播放冲突时的播放优先级,加载的先后顺序决定了每段音效的ID号(从1开始),之后播放是通过ID判断播放哪一段音效
soundPool.load(this, R.raw.game_bg, 1);  // 背景音效(弃用)
soundPool.load(this, R.raw.peng, 2);     // 落子音效
soundPool.load(this, R.raw.dingdong, 3); // 玩家胜利音效
soundPool.load(this, R.raw.dingdong, 4); // 平局音效// 播放:第一个参数是音效的ID,也就是第4个加载的音效(平局音效);第23个参数分别表示左右声道的音量;第四个参数表示播放优先级,数值越大优先级越高;第五个参数表示是否循环播放,0为不循环,-1为循环;最后一个参数指定播放的比率,数值可从0.521为正常比率
soundPool.play(4,1,1,0,0,1);

6.简单游戏数据的存储

这里简单存储两个玩家各自获胜的次数两个数字,使用sharedpreferance保存维护两个键值对,sharedpreferance的基本用法如下,其中获取的时候第二个参数是在数据不存在时的默认值,正好实现当第一次获取时两个键值对还不存在,返回默认的0同时创建了该键值对,然后进行存储以及后面的数据获取,也就是默认的0有且只有使用到依次来进行初始化:

    /*** 更新数据*/public void setData(int player){// 简单数据存储SharedPreferences sharedPreferences = getSharedPreferences(PREFS_NAME,0);// 数据存储编辑器SharedPreferences.Editor editor = sharedPreferences.edit();// 获取旧数据,如果没有存储过返回默认的0int dataP1 = sharedPreferences.getInt("data_player1",0);int dataP2 = sharedPreferences.getInt("data_player2",0);// 更新数据if (player == 1){editor.putInt("data_player1", dataP1+1);}else if (player == 2){editor.putInt("data_player2", dataP2+1);}else {return;}// 提交数据editor.commit();}

这里写图片描述

7.java源码预览

MainActivity.java

这里写图片描述

package com.example.albeeert.fourinrowgame;import android.app.Dialog;
import android.content.Intent;
import android.content.SharedPreferences;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.DisplayMetrics;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;public class MainActivity extends AppCompatActivity {// 数据存储public final String PREFS_NAME = "JXHFile";// 云朵private ImageView cloud1 = null;private ImageView cloud2 = null;private ImageView cloud3 = null;// 云朵移动速度(值不可太大否则看上去不流畅)private final float cloudspeed1 = 8.0f;private final float cloudspeed2 = 15.0f;private final float cloudspeed3 = 12.0f;// 游戏准备图片private ImageView ready = null;// 开始游戏按钮和玩家数据按钮private Button startGameBtn = null;private Button dataButton = null;// 对话框private View dialogView;// 弹出窗口private Dialog dialog;// 按钮浮动幅度private final float range = 10.0f;// 计时间隔private final int Interval = 100;// sin角度private double sinAngle = 0;// 开始按钮的Y坐标private float initY = 0;// 屏幕宽高private float ScreenW = 0;private float ScreenH = 0;// 动画线程private MyThread animationThread = null;// 当前页面是否活跃private boolean isActive = true;// 音乐播放器private static MediaPlayer media_bg;    // 背景音乐private static MediaPlayer media_start; // 游戏开始音乐private static MediaPlayer media_button; // 按钮音效/*** Activity life cycle*/@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);// 界面初始化UIInit();// 音效设置AudioInit();// 事件监听setListener();// 开始按钮浮动动画animationThread = new MyThread();new Thread(animationThread).start();}// 离开当前mainactivity@Overrideprotected void onPause() {super.onPause();// 暂停背景音乐media_bg.pause();// 隐藏准备图片ready.setVisibility(View.INVISIBLE);isActive = false;}// 回到mainactivity@Overrideprotected void onRestart() {super.onRestart();isActive = true;// 继续背景音乐media_bg.start();// 开始按钮浮动动画new Thread(animationThread).start();}// 返回键@Overridepublic void onBackPressed(){System.exit(0);// 退出程序}/***  界面初始化*/public void UIInit(){// 基本静态界面setContentView(R.layout.activity_main);// 获取开始游戏按钮startGameBtn = (Button)findViewById(R.id.startbutton);// 玩家数据按钮dataButton = (Button)findViewById(R.id.databutton);// 云朵cloud1 = (ImageView) findViewById(R.id.cloud1);cloud2 = (ImageView) findViewById(R.id.cloud2);cloud3 = (ImageView) findViewById(R.id.cloud3);// 游戏准备图片ready = (ImageView) findViewById(R.id.start_ready);// 对话框dialogView= LayoutInflater.from(this).inflate(R.layout.data_dialog, null);dialog = new Dialog(MainActivity.this);dialog.setTitle("Player Data");dialog.setContentView(dialogView);dialog.setCanceledOnTouchOutside(true);// 屏幕尺寸DisplayMetrics dm = new DisplayMetrics();getWindowManager().getDefaultDisplay().getMetrics(dm);ScreenH = dm.heightPixels;ScreenW = dm.widthPixels;// 开始按钮起始Y坐标initY = ScreenH*2/3;}/*** 音效设置*/public void AudioInit(){// 1.背景音乐media_bg = MediaPlayer.create(this, R.raw.menu_bg);media_bg.start();// 实现循环播放media_bg.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {@Overridepublic void onCompletion(MediaPlayer mp) {media_bg.start();}});// 2.开始按钮音效media_start = MediaPlayer.create(this, R.raw.zombiesmile);// 监听音效结束事件media_start.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {@Overridepublic void onCompletion(MediaPlayer mp) {// 跳转到游戏界面Intent intent = new Intent(getBaseContext(),GameActivity.class);startActivity(intent);}});// 3.普通按钮音效media_button = MediaPlayer.create(this, R.raw.yoho);}/*** 事件监听*/public void setListener(){// 开始游戏按钮点击事件startGameBtn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {// 播放音效media_start.start();// 显示准备图片ready.setVisibility(View.VISIBLE);// 停止动画isActive = false;}});// 玩家数据按钮点击事件dataButton.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {// 播放音效media_button.start();// 获取本地数据SharedPreferences sharedPreferences = getSharedPreferences(PREFS_NAME,0);int dataP1 = sharedPreferences.getInt("data_player1",0);int dataP2 = sharedPreferences.getInt("data_player2",0);//System.out.print("datap1:"+dataP1+";  "+"datap2:"+dataP2+"\n");// 更新对话框文字数据TextView player1DataShow = (TextView) dialogView.findViewById(R.id.player1datashow);TextView player2DataShow = (TextView) dialogView.findViewById(R.id.player2datashow);player1DataShow.setText(String.valueOf(dataP1));player2DataShow.setText(String.valueOf(dataP2));// 弹出窗口dialog.show();}});}/*** 线程类*/class MyThread implements Runnable {@Overridepublic void run() {// 开始按钮起始位置//startGameBtn.setX(ScreenW*3/8);//startGameBtn.setY(initY);// 玩家数据按钮起始位置//dataButton.setX(ScreenW-170);//dataButton.setY(ScreenH-150);// updatewhile (isActive) {try {Thread.sleep(Interval);// 1.按钮浮动sinAngle += 0.3f;startGameBtn.setY(initY + (float)(range*Math.sin(sinAngle)));dataButton.setX((float)(range/3*Math.sin(sinAngle)));// 3.云朵移动if (cloud1.getX() < -500)cloud1.setX(ScreenW + 10.0f);cloud1.setX(cloud1.getX() - cloudspeed1);if (cloud2.getX() > ScreenW)cloud2.setX(-1000.0f);cloud2.setX(cloud2.getX()+cloudspeed2);if (cloud3.getX() > ScreenW)cloud3.setX(-1200.0f);cloud3.setX(cloud3.getX()+cloudspeed3);}catch (Exception e) {e.printStackTrace();System.out.print("thread error!");}}}}
}

GameActivity.java

package com.example.albeeert.fourinrowgame;import android.content.SharedPreferences;
import android.graphics.Point;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.SoundPool;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.DisplayMetrics;
import android.view.MotionEvent;
import android.view.View;
import android.widget.AbsoluteLayout;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;import java.util.ArrayList;/*** 1.记录双方棋局状态数据结构 ***/
class CheckNode{int Horizontal; // 水平方向上相同棋子的个数int Vertical;   // 竖直方向...int MDiagonal;  // 主对角线...int ADiagonal;  // 辅对角线...// 构造CheckNode(){Horizontal = 1;Vertical = 1;MDiagonal = 1;ADiagonal = 1;}// 重置void Reset(){Horizontal = 1;Vertical = 1;MDiagonal = 1;ADiagonal = 1;}
}/*** 2.棋子节点数据结构 ***/
class Piece{int value;        // 0:空 1:玩家1的棋子 2:玩家2的棋子ImageView image;  // 棋子图片// 构造Piece(){value = 0;image = null;}// 重置void Reset(){value = 0;image.setImageResource(R.drawable.empty);}
}/*** 游戏界面 ***/
public class GameActivity extends AppCompatActivity {// 数据存储public final String PREFS_NAME = "JXHFile";// 棋盘横竖棋子个数public static final int H_NUM = 7;public static final int V_NUM = 6;// 左部间隙private int LEFT_GAP = 10; // 至少10// 棋盘宽度(屏幕宽度)private float CBWidth = 0;// 棋盘单位宽度private int CellWidth = 0;// 获取xml的UI组件引用private Button ReStartButton = null;private Button WithDrawButton = null;private TextView StatusTop = null;private TextView StatusLeft = null;private TextView StatusRight = null;private ImageView IconLeft = null;private ImageView IconRight = null;private AbsoluteLayout CBLayout = null;// 玩家1和玩家2的棋局状态private CheckNode[] checkNode = null;// 当前游戏状态(0:平局 1:玩家1下棋 2:玩家2下棋 11:玩家1胜利 22:玩家2胜利)private int gameResult = 0;// 棋盘private Piece[][] ChessBord = null;// 用一个可变数组实现堆栈依次保存所下棋子的顺序ArrayList<Point>PieceStack = null;// 落子计数器private int pieceCount = 0;// 音效池private SoundPool soundPool = null;// 背景音乐播放器private MediaPlayer media_bg = null;/*** 游戏界面初始化入口*/@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);// 基础页面setContentView(R.layout.activity_game);// 全局初始化ActivityInit();// 游戏初始化GameInit();}/*** 返回键监听*/@Overridepublic void onBackPressed(){// 关闭背景音乐media_bg.stop();this.finish();}/*** 全局初始化(只初始化一次)*/public void ActivityInit(){// UI 初始化ReStartButton = (Button)findViewById(R.id.button_restart);WithDrawButton = (Button)findViewById(R.id.button_withdraw);StatusTop = (TextView)findViewById(R.id.topStatus);StatusLeft = (TextView)findViewById(R.id.status_left);StatusRight = (TextView)findViewById(R.id.status_right);IconLeft = (ImageView)findViewById(R.id.icon_left);IconRight = (ImageView)findViewById(R.id.icon_right);CBLayout = (AbsoluteLayout) findViewById(R.id.layout_chessboard);// 音效初始化soundPool = new SoundPool(4, AudioManager.STREAM_SYSTEM,5);soundPool.load(this, R.raw.game_bg, 1);  // 背景音效(弃用)soundPool.load(this, R.raw.peng, 2);     // 落子音效soundPool.load(this, R.raw.dingdong, 3); // 玩家胜利音效soundPool.load(this, R.raw.dingdong, 4); // 平局音效// 背景音乐media_bg = MediaPlayer.create(this, R.raw.game_bg);media_bg.start();// 循环播放media_bg.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {@Overridepublic void onCompletion(MediaPlayer mp) {media_bg.start();}});// 棋盘宽高DisplayMetrics dm = new DisplayMetrics();getWindowManager().getDefaultDisplay().getMetrics(dm);int ScreenW = dm.widthPixels;//int ScreenH = dm.heightPixels;CBWidth = ScreenW - 2*LEFT_GAP;CellWidth = (int)(CBWidth/H_NUM);// 棋盘二维数组ChessBord = new Piece[H_NUM][V_NUM];for (int h=0; h<H_NUM; h++){for (int v=0; v<V_NUM; v++){ChessBord[h][v] = new Piece();}}// 检测状态初始化checkNode = new CheckNode[2];checkNode[0] = new CheckNode();checkNode[1] = new CheckNode();// 绘制棋盘DrawChessBoard();// 监听重新开始游戏ReStartButton.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {RestartGame();}});// 开启悔棋监听WithDrawButton.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {// 悔棋一步WithDraw();}});}/*** 游戏初始化(每次重新游戏都要初始化)*/public void GameInit(){// 开始游戏监听CBLayout.setOnTouchListener(new View.OnTouchListener() {@Overridepublic boolean onTouch(View v, MotionEvent event) {// 选用点击事件if (event.getAction() == MotionEvent.ACTION_DOWN){// 横坐标float touchX = event.getX() - LEFT_GAP;// 列数int column = (int)(touchX/CellWidth);// 计算并落子SetPiece(CalCoord(column));}return false;}});// 默认玩家1先手gameResult = 1;UpdateUI(1);// 保证隐藏drawStatusTop.setText("");// 落子计数器pieceCount = 0;// 初始化栈PieceStack = new ArrayList<Point>();}/*** 游戏结束*/public void GameOver(){// 停止游戏棋盘交互CBLayout.setOnTouchListener(null);// 清空栈PieceStack = null;}/*** 重新开始游戏*/public void RestartGame(){// 重置棋盘for (int h=0; h<H_NUM; h++){for (int v=0; v<V_NUM; v++){ChessBord[h][v].Reset();}}// 重新初始化游戏GameInit();}/*** 绘制棋盘*/public void DrawChessBoard(){// 绘制棋子洞和空棋子for(int i = 0 ; i<V_NUM ; i++){for (int j = 0 ; j<H_NUM ; j++){// 土壤ImageView view = new ImageView(this);view.setImageResource(R.drawable.chess_bg);view.setMaxHeight(CellWidth);view.setMaxWidth(CellWidth);view.setX(CellWidth*j+LEFT_GAP);view.setY(CellWidth*i);// 绘制到棋盘中CBLayout.addView(view);// 空棋子ImageView piece = new ImageView(this);piece.setImageResource(R.drawable.empty);piece.setMaxHeight(CellWidth);piece.setMaxWidth(CellWidth);piece.setX(CellWidth*j + LEFT_GAP);piece.setY(CellWidth*(V_NUM-i-1));// 棋子图片引用添加到棋盘数据ChessBord[j][i].image = piece;// 绘制棋子到棋盘CBLayout.addView(piece);}}}/*** 计算落子坐标*/public Point CalCoord(int column){// 如果超出棋盘右边界视为最右边的一列if (column >= H_NUM)column = H_NUM-1;// 计算落子坐标for (int i = 0 ; i<V_NUM ; i++){if (ChessBord[column][i].value == 0){Point point = new Point(column,i);return point;} else {continue;}}return null;}/*** 落子并计算更新游戏状态*/public void SetPiece(Point point){// 该列棋子已落满或者程序出错if (point == null)return;// 入栈PieceStack.add(point);// 计数器+1++pieceCount;// 界面落子DrawPiece(point);// 游戏状态更新ChessBord[point.x][point.y].value = gameResult;// 检查输赢情况// 是否已平局if (pieceCount == V_NUM*H_NUM){// 平局UpdateUI(0);// 游戏结束GameOver();// 终止return;}// 是否有人赢int result = CheckResult(point);if (result == 0){// 换人继续if (gameResult == 1){gameResult = 2;UpdateUI(gameResult);}else {gameResult = 1;UpdateUI(gameResult);}}else {/** 已经有人赢了 **/// 显示获胜的棋子SearchWonPieces(point);// 更新数据setData(gameResult);// 更新UIif (gameResult == 1){// 玩家1赢UpdateUI(11);}else {// 玩家2赢UpdateUI(22);}// 游戏结束GameOver();}// 重置检测状态checkNode[0].Reset();checkNode[1].Reset();}/*** 显示获胜的棋子*/public void SearchWonPieces(Point point){// 判断是哪个玩家赢了int winimg = 0;if (gameResult == 1)winimg = R.drawable.chess_p1_win;else if (gameResult == 2)winimg = R.drawable.chess_p2_win;else{System.out.print("error!");return;}// 当前下的一个棋子直接特殊显示ChessBord[point.x][point.y].image.setImageResource(winimg);// 某个方向上最多的相同棋子个数肯定不会比最大宽度或者高度棋子数多int maxStep = H_NUM > V_NUM ? H_NUM : V_NUM;for (int i=1 ; i<maxStep; i++){// 上if (checkNode[gameResult-1].Vertical >= 4 && (point.y + i < V_NUM) && ChessBord[point.x][point.y + i].value == gameResult) {// 满足不越棋盘的界,并且是当前获胜玩家的棋子UpdateWinImage(new Point(point.x, point.y+i), new Point(point.x, point.y+i-1), winimg);}// 下if (checkNode[gameResult-1].Vertical >= 4 && (point.y - i >= 0) && ChessBord[point.x][point.y - i].value == gameResult) {UpdateWinImage(new Point(point.x, point.y-i), new Point(point.x, point.y-i+1), winimg);}// 左if (checkNode[gameResult-1].Horizontal >= 4 && (point.x - i >= 0) && ChessBord[point.x - i][point.y].value == gameResult) {UpdateWinImage(new Point(point.x-i, point.y), new Point(point.x-i+1, point.y), winimg);}// 右if (checkNode[gameResult-1].Horizontal >= 4 && (point.x + i < H_NUM) && ChessBord[point.x + i][point.y].value == gameResult) {UpdateWinImage(new Point(point.x+i, point.y), new Point(point.x+i-1, point.y), winimg);}// 左上if (checkNode[gameResult-1].ADiagonal >= 4 && (point.x - i >= 0) && (point.y + i < V_NUM) && (ChessBord[point.x - i][point.y + i].value == gameResult)) {UpdateWinImage(new Point(point.x-i, point.y+i), new Point(point.x-i+1, point.y+i-1), winimg);}// 右下if (checkNode[gameResult-1].ADiagonal >= 4 && (point.x + i < H_NUM) && (point.y - i >= 0) && (ChessBord[point.x + i][point.y - i].value == gameResult)) {UpdateWinImage(new Point(point.x+i, point.y-i), new Point(point.x+i-1, point.y-i+1), winimg);}// 右上if (checkNode[gameResult-1].MDiagonal >= 4 && (point.x + i < H_NUM) && (point.y + i < V_NUM) && (ChessBord[point.x + i][point.y + i].value == gameResult)) {UpdateWinImage(new Point(point.x+i, point.y+i), new Point(point.x+i-1, point.y+i-1), winimg);}// 左下if (checkNode[gameResult-1].MDiagonal >= 4 && (point.x - i >= 0) && (point.y - i >= 0) && (ChessBord[point.x - i][point.y - i].value == gameResult)) {UpdateWinImage(new Point(point.x-i, point.y-i), new Point(point.x-i+1, point.y-i+1), winimg);}}}/*** 替换获胜棋子图片(这里要同时检验当前获胜棋子是否和上一个连续,如果中间有对方棋子间隔那么当前这个获胜玩家的棋子并不是真的获胜棋子)*/public void UpdateWinImage(Point curPoint, Point prePoint, int winimg){if (ChessBord[curPoint.x][curPoint.y].value == ChessBord[prePoint.x][prePoint.y].value){ChessBord[curPoint.x][curPoint.y].image.setImageResource(winimg);}else {// 出现不连续获胜棋子则将这一排剩下的所有获胜玩家的棋子全部排除掉(事实上顶多出现两个不连续的获胜玩家棋子,因为H_NUM为7)int delX = curPoint.x - prePoint.x;int delY = curPoint.y - prePoint.y;Point nextPoint = new Point(curPoint.x+delX, curPoint.y+delY);while (nextPoint.x>=0 && nextPoint.x<H_NUM && nextPoint.y>=0 && nextPoint.y<V_NUM){ChessBord[nextPoint.x][nextPoint.y].value = 0;nextPoint.x += delX;nextPoint.y += delY;}}}/*** 更新UI显示状态*/public void UpdateUI(int gameResult){if (gameResult == 0){// 平局StatusTop.setText("Draw");StatusLeft.setText("");StatusRight.setText("");// 两个玩家都高亮IconLeft.setImageResource(R.drawable.chess_p1_win);IconRight.setImageResource(R.drawable.chess_p2_win);// 平局音效soundPool.play(4,1,1,0,0,1);}else if (gameResult == 1){// 玩家1下棋StatusLeft.setText("   !");StatusRight.setText("");// 玩家1高亮IconLeft.setImageResource(R.drawable.chess_p1_win);IconRight.setImageResource(R.drawable.chess_p2);}else if (gameResult == 2){// 玩家2下棋StatusLeft.setText("");StatusRight.setText("!   ");// 玩家2高亮IconLeft.setImageResource(R.drawable.chess_p1);IconRight.setImageResource(R.drawable.chess_p2_win);}else if(gameResult == 11){// 玩家1赢StatusLeft.setText("Win!");StatusRight.setText("");// 胜利音效soundPool.play(3,1,1,2,0,1);}else if (gameResult == 22){// 玩家2赢StatusLeft.setText("");StatusRight.setText("Win!");// 胜利音效soundPool.play(3,1,1,2,0,1);}else {return;}}/*** 绘制指定棋子*/public void DrawPiece(Point point){// 播放音效soundPool.play(2,1,1,1,0,1);// 绘制ImageView piece = ChessBord[point.x][point.y].image;if (gameResult == 1){piece.setImageResource(R.drawable.chess_p1);}else {piece.setImageResource(R.drawable.chess_p2);}}/*** 检查某个棋子处各个方向上相同棋子的个数,用于判断游戏胜负(返回0表示游戏继续,1表示玩家1赢,2表示玩家2赢)*/public int CheckResult(Point point) {// 检查水平和竖直方向int stopCount = 0; // 8个方向到边界停止的个数int[] stopDir = new int[8];// 八个方向是否已经终止int counter = 0;while (stopCount < 8) {stopCount = 0;++counter;// 上if ((stopDir[0]==1) || (point.y + counter >= V_NUM) || ChessBord[point.x][point.y + counter].value != gameResult) {stopDir[0]=1;//向上超出棋盘或遇到非同色棋子终止} else {checkNode[gameResult - 1].Vertical++;//纵向+1}// 下if ((stopDir[1]==1) || (point.y - counter < 0) || ChessBord[point.x][point.y - counter].value != gameResult) {stopDir[1]=1;} else {checkNode[gameResult - 1].Vertical++;}// 左if ((stopDir[2]==1) || (point.x - counter < 0) || ChessBord[point.x - counter][point.y].value != gameResult) {stopDir[2]=1;} else {checkNode[gameResult - 1].Horizontal++;}// 右if ((stopDir[3]==1) || (point.x + counter >= H_NUM) || ChessBord[point.x + counter][point.y].value != gameResult) {stopDir[3]=1;} else {checkNode[gameResult - 1].Horizontal++;}// 左上if ((stopDir[4]==1) || (point.x - counter < 0) || (point.y + counter >= V_NUM) || (ChessBord[point.x - counter][point.y + counter].value != gameResult)) {stopDir[4]=1;} else {checkNode[gameResult - 1].ADiagonal++;}// 右下if ((stopDir[5]==1) || (point.x + counter >= H_NUM) || (point.y - counter < 0) || (ChessBord[point.x + counter][point.y - counter].value != gameResult)) {stopDir[5]=1;} else {checkNode[gameResult - 1].ADiagonal++;}// 右上if ((stopDir[6]==1) || (point.x + counter >= H_NUM) || (point.y + counter >= V_NUM) || (ChessBord[point.x + counter][point.y + counter].value != gameResult)) {stopDir[6]=1;} else {checkNode[gameResult - 1].MDiagonal++;}// 左下if ((stopDir[7]==1) || (point.x - counter < 0) || (point.y - counter < 0) || (ChessBord[point.x - counter][point.y - counter].value != gameResult)) {stopDir[7]=1;} else {checkNode[gameResult - 1].MDiagonal++;}// 终止循环搜索for(int i =0 ; i<8 ;i++){stopCount += stopDir[i];}}// 判断是否有人赢if (checkNode[gameResult-1].MDiagonal>=4 || checkNode[gameResult-1].ADiagonal>=4 || checkNode[gameResult-1].Horizontal>=4 || checkNode[gameResult-1].Vertical>=4){return gameResult;}else {return 0;}}/*** 悔棋一步*/public void WithDraw(){// 异常检测if (PieceStack == null || PieceStack.size() == 0)return;// 取出最后一个坐标并出栈Point point = PieceStack.remove(PieceStack.size()-1);// 棋盘移除最后一步棋ChessBord[point.x][point.y].Reset();// 换人if (gameResult == 1){gameResult = 2;UpdateUI(gameResult);}else {gameResult = 1;UpdateUI(gameResult);}// 计数-1--pieceCount;}/*** 更新数据*/public void setData(int player){// 简单数据存储SharedPreferences sharedPreferences = getSharedPreferences(PREFS_NAME,0);// 数据存储编辑器SharedPreferences.Editor editor = sharedPreferences.edit();// 获取旧数据,如果没有存储过返回默认的0int dataP1 = sharedPreferences.getInt("data_player1",0);int dataP2 = sharedPreferences.getInt("data_player2",0);// 更新数据if (player == 1){editor.putInt("data_player1", dataP1+1);}else if (player == 2){editor.putInt("data_player2", dataP2+1);}else {return;}// 提交数据editor.commit();}}

orz……有问题吐槽请留言,帮到您烦请帮顶一下,谢谢^_^

http://www.wooajung.com/news/34007.html

相关文章:

  • 网站建设单位是什么社交媒体营销策略有哪些
  • 东莞建设监督网站淘宝seo是什么意思
  • 网站搭建设计 是什么疫情最新官方消息
  • 网站建设 模板搜索 引擎优化
  • 哪些网站可以做简历baidu百度
  • 商城网站建设合同书如何查看百度指数
  • 单页网站制作系统青岛关键词优化seo
  • 做会议活动的网站加速游戏流畅的软件
  • 淘宝cms建站电子商务与网络营销题库
  • 餐饮vi设计一套多少钱win10优化
  • 黑彩网站建设需要什么东西百度关键词优化方法
  • 校园网站怎么做成人教育培训机构
  • 可以做商城网站的公司吗武汉最新今天的消息
  • 柳州团购网站建设中国疾控卫生应急服装
  • 推广方法的总结移动建站优化
  • 如何在分类信息网站做推广个人如何做seo推广
  • python搭建wordpress四川网站seo
  • 萝岗网站建设网站建设小程序开发
  • 宣传片制作公司保定seo搜索引擎优化哪家好
  • 联合建设官方网站微信scrm系统
  • 做一个跨境电商网站武汉全网推广
  • 北京网站设计 培训搜狗搜索网页版
  • 常州网站制作系统上海sem
  • 做网站点击率怎么收钱杭州网络
  • 西宁建站新东方小吃培训价格表
  • 高德地图怎么看邮编百度seo优化招聘
  • 医疗网站如何做优化引擎搜索优化
  • 请问那个网站做推广好点广告推广渠道
  • 丹东做网站企业培训方案制定
  • 优化型网站建设的基本要求徐州seo企业