当前位置:   article > 正文

Java课程设计、安卓开发(AndroidStudio):JavaScript实现贪吃蛇小游戏(手机APK)_安卓贪吃蛇java项目实现

安卓贪吃蛇java项目实现

本人一直想找时间系统整理一下之前做过的一些实验,便于后续用到的时候可以尽快的使用,po出来也便于大家交流学习,有问题欢迎交流指正,与诸君共勉!

这次是Java的课程设计,现在看起来更像是一个安卓开发的课程设计。设计了一个贪吃蛇游戏,有友好的GUI界面和较为全面的功能。

实现效果

开始动画

开启GreegySnake后,显示开始动画,如图1。

开始动画停留三秒后自动进入登录界面,如图2。

图1 开始动画

 图2 登录界面

注册

下载GreedySnake软件并打开后,首次使用需要点击登陆界面的“没有账号?点此注册”按钮进入GamePlayer用户注册界面进行用户注册,如图3。

按提示输入账号:用户名/手机号/邮箱,并设置密码:数字组合,如图4。

注册成功后弹出提示:注册成功,并跳转至登录界面,如图5。

图3 注册界面

 图4 用户注册

图5 注册成功

登录

登陆界面输入用户名和密码,勾选“我同意用户服务协议和隐私政策”,点击登录按钮,进入游戏菜单界面,如图7。

图7 游戏菜单界面

贪吃蛇游戏

从游戏菜单界面点击“新游戏“,进入贪吃蛇游戏初始界面,如图9,小蛇初始身长为4。默认开始播放游戏背景音乐。

单击“开始游戏“按钮,进入游戏主界面,如图10。用户可点击“向右”、“向左”、“向上”、“向下”四个按钮控制小蛇爬动的方向,食物随机出现在游戏界面中,食物种类从下图六种水果中随机产生。

图8 六种食物种类

游戏中,默认背景音乐暂停,小蛇每吃到食物一次,会播放相应音效。

图9 游戏初始界面     

 图10 游戏中

游戏中,点击”游戏暂停“按钮,会播放按钮点击音效并默认继续播放背景音乐,屏幕中央提示”点击按钮,继续游戏“字样,如图11。

单击主界面右上角喇叭图标,图标更换为静音模式,如图12。按钮音效和背景音乐将切换至静音模式。

图11 游戏中点击“游戏暂停”按钮

图12 游戏切换为静音模式

游戏过程中,根据不同得分,将展示不同效果,具体规则如下:

小蛇吃到一次食物加10分,每吃到一个食物,播放win音效;

得分小于250,分数每增加50,播放一次鼓掌音效;

得分大于等于300,小于400,分数每增加20,播放一次鼓掌音效;

得分大于等于400,分数每增加10,播放一次鼓掌音效,屏幕中央显示提示字样“YOU ARE A WINNER!”,中央”游戏暂停”按钮字样变为“WIN”。

分数达到500,自动跳转最终胜利界面,如图13。

查看历史最高分数

每轮游戏过后,若本轮得分超过本用户历史最高分数,将自动更新历史最高分数。在游戏菜单界面点击“查看历史最高分数”可查看最高分数记录,如图14。

在游戏菜单界面点击“退出游戏“按钮,可返回GamePlayer登录界面。

二、数据说明

本客户端无服务器,故用户账户密码数据、历史最高分数数据、游戏界面静音状态数据均存放在手机本地文件与数据库中。

国密SM4加密

对于用户注册信息,将用户密码使用国家密码管理局发布的SM4.0密码算法进行加密后存储,增强用户信息安全性。在Android Studio平台模拟运行,注册后,可看到日志信息如图15,用户密码已被加密处理。

图15 注册账户Log信息

SQLite数据库存储

用户账号密码数据统一存储在snakeUser.db数据库的user表中。

图16 snakeUser.db数据库

文件存储

用户历史最高分数、静音按键状态信息分别存储在文件名为“用户名+scorefile.xml”、“用户名+VolumeFile.xml”的文件中,如图17。

图17 最高分数、音量文件信息

代码说明

 类说明

共设计16个Java文件:

Macro:用于定义游戏界面中的固定参数、文件名称等

User:用于创建用户信息

UserService:用于用户注册、登录功能实现

StartActivity:用于软件开始动画的3秒显示

MainActivity: 用于主游戏界面小蛇移动、游戏进行状态、静音状态、得分反应的逻辑控制;

MyDatabaseHelper:用于连接SQLite数据库,创建user表,存储用户信息

SharedPre:用于用户历史最高分数、静音按钮状态信息存储的文件操作

RegisterActivity:用于注册界面的显示及按钮事件响应

LoginActivity:用于登录界面的显示及按钮事件的响应

FinalwinActivity:用于用户最终胜利界面的显示

SM4:用于国密SM4算法的工具类

Encryption:用于国密SM4算法的加解密

Images:用于游戏主界面的小蛇、食物等动态构件绘制

ChooseActivity:游戏菜单界面的显示及按钮事件响应

SoundPlay:用于游戏中的按钮音效、吃到食物音效、游戏失败音效的短音频控制

BGMServer:用于游戏中的背景音乐(长音频)控制

共设计6个布局文件:

activity_beginning.xml:开始动画界面布局

activity_finalwin.xml:最终胜利界面布局

activity_login.xml:登录界面布局

activity_main.xml:游戏主界面布局

activity_register.xml:注册界面布局

activity_start_view.xml:游戏菜单界面布局

源代码

java文件

  1. BGMServer.java
  2. package com.example.android_snake;
  3. import android.content.Context;
  4. import android.media.MediaPlayer;
  5. /**
  6. * 贪吃蛇背景音乐工具类
  7. */
  8. public class BGMserver {
  9. private static MediaPlayer mp =null;
  10. public static void play(Context context, int resource){
  11. stop(context);
  12. mp = MediaPlayer.create(context, resource);
  13. mp.setLooping(true);
  14. mp.start();
  15. }
  16. public static void stop(Context context) {
  17. // TODO Auto-generated method stub
  18. if(mp!= null){
  19. mp.stop();
  20. mp.release();
  21. mp = null;
  22. }
  23. }
  24. }
  25. ChooseActivity.java
  26. package com.example.android_snake;
  27. import androidx.appcompat.app.AppCompatActivity;
  28. import android.content.Context;
  29. import android.content.Intent;
  30. import android.media.AudioManager;
  31. import android.media.SoundPool;
  32. import android.os.Bundle;
  33. import android.view.View;
  34. import android.widget.Button;
  35. import java.util.HashMap;
  36. /**
  37. * The type Star view:游戏开始界面
  38. */
  39. public class ChooseActivity extends AppCompatActivity implements View.OnClickListener {
  40. private Button Startbutton,Sbutton,Backbutton;
  41. private String usern;
  42. /**
  43. * The Shared:实例化存储对象
  44. */
  45. SharedPre shared;
  46. @Override
  47. protected void onCreate(Bundle savedInstanceState) {
  48. super.onCreate(savedInstanceState);
  49. setContentView(R.layout.activity_start_view);
  50. Init();
  51. }
  52. /**
  53. * Init:初始化该活动界面信息
  54. */
  55. void Init(){
  56. usern = LoginActivity.usern;
  57. Startbutton =findViewById(R.id.star_game);
  58. Sbutton=findViewById(R.id.MostBUtton);
  59. Backbutton=findViewById(R.id.BackButton);
  60. shared=new SharedPre(usern,this);
  61. //soundp = new SoundPlay();
  62. //soundp.initSoundPool();//初始化声音池
  63. Startbutton.setOnClickListener(this);
  64. Sbutton.setOnClickListener(this);
  65. Backbutton.setOnClickListener(this);
  66. }
  67. /**
  68. * onClick:该界面按钮监听事件
  69. */
  70. @Override
  71. public void onClick(View v) {
  72. switch (v.getId()){
  73. case R.id.star_game:
  74. //sp.playSound(1, 0);//播放1号声音资源button,且播放一次
  75. Intent intent=new Intent(ChooseActivity.this,MainActivity.class);
  76. startActivity(intent);
  77. break;
  78. case R.id.BackButton:
  79. //sp.playSound(1, 0);//播放1号声音资源button,且播放一次
  80. finish();
  81. break;
  82. case R.id.MostBUtton:
  83. //sp.playSound(1, 0);//播放1号声音资源button,且播放一次
  84. Sbutton.setText(Macro.H_MOST_SCORE+shared.read());
  85. break;
  86. }
  87. }
  88. }
  89. SM4.java
  90. package com.example.android_snake;
  91. import java.util.Arrays;
  92. public class SM4 {
  93. private static SM4 mSm4 = null;
  94. public static SM4 getInstance() {
  95. if (mSm4 == null) {
  96. mSm4 = new SM4();
  97. }
  98. return mSm4;
  99. }
  100. public static final int DECRYPT = 0; // 解密
  101. public static final int ENCRYPT = 1; // 加密
  102. public static final int ROUND = 32;
  103. private static final int BLOCK = 16;
  104. private byte[] Sbox = { (byte) 0xd6, (byte) 0x90, (byte) 0xe9, (byte) 0xfe,
  105. (byte) 0xcc, (byte) 0xe1, 0x3d, (byte) 0xb7, 0x16, (byte) 0xb6,
  106. 0x14, (byte) 0xc2, 0x28, (byte) 0xfb, 0x2c, 0x05, 0x2b, 0x67,
  107. (byte) 0x9a, 0x76, 0x2a, (byte) 0xbe, 0x04, (byte) 0xc3,
  108. (byte) 0xaa, 0x44, 0x13, 0x26, 0x49, (byte) 0x86, 0x06,
  109. (byte) 0x99, (byte) 0x9c, 0x42, 0x50, (byte) 0xf4, (byte) 0x91,
  110. (byte) 0xef, (byte) 0x98, 0x7a, 0x33, 0x54, 0x0b, 0x43,
  111. (byte) 0xed, (byte) 0xcf, (byte) 0xac, 0x62, (byte) 0xe4,
  112. (byte) 0xb3, 0x1c, (byte) 0xa9, (byte) 0xc9, 0x08, (byte) 0xe8,
  113. (byte) 0x95, (byte) 0x80, (byte) 0xdf, (byte) 0x94, (byte) 0xfa,
  114. 0x75, (byte) 0x8f, 0x3f, (byte) 0xa6, 0x47, 0x07, (byte) 0xa7,
  115. (byte) 0xfc, (byte) 0xf3, 0x73, 0x17, (byte) 0xba, (byte) 0x83,
  116. 0x59, 0x3c, 0x19, (byte) 0xe6, (byte) 0x85, 0x4f, (byte) 0xa8,
  117. 0x68, 0x6b, (byte) 0x81, (byte) 0xb2, 0x71, 0x64, (byte) 0xda,
  118. (byte) 0x8b, (byte) 0xf8, (byte) 0xeb, 0x0f, 0x4b, 0x70, 0x56,
  119. (byte) 0x9d, 0x35, 0x1e, 0x24, 0x0e, 0x5e, 0x63, 0x58, (byte) 0xd1,
  120. (byte) 0xa2, 0x25, 0x22, 0x7c, 0x3b, 0x01, 0x21, 0x78, (byte) 0x87,
  121. (byte) 0xd4, 0x00, 0x46, 0x57, (byte) 0x9f, (byte) 0xd3, 0x27,
  122. 0x52, 0x4c, 0x36, 0x02, (byte) 0xe7, (byte) 0xa0, (byte) 0xc4,
  123. (byte) 0xc8, (byte) 0x9e, (byte) 0xea, (byte) 0xbf, (byte) 0x8a,
  124. (byte) 0xd2, 0x40, (byte) 0xc7, 0x38, (byte) 0xb5, (byte) 0xa3,
  125. (byte) 0xf7, (byte) 0xf2, (byte) 0xce, (byte) 0xf9, 0x61, 0x15,
  126. (byte) 0xa1, (byte) 0xe0, (byte) 0xae, 0x5d, (byte) 0xa4,
  127. (byte) 0x9b, 0x34, 0x1a, 0x55, (byte) 0xad, (byte) 0x93, 0x32,
  128. 0x30, (byte) 0xf5, (byte) 0x8c, (byte) 0xb1, (byte) 0xe3, 0x1d,
  129. (byte) 0xf6, (byte) 0xe2, 0x2e, (byte) 0x82, 0x66, (byte) 0xca,
  130. 0x60, (byte) 0xc0, 0x29, 0x23, (byte) 0xab, 0x0d, 0x53, 0x4e, 0x6f,
  131. (byte) 0xd5, (byte) 0xdb, 0x37, 0x45, (byte) 0xde, (byte) 0xfd,
  132. (byte) 0x8e, 0x2f, 0x03, (byte) 0xff, 0x6a, 0x72, 0x6d, 0x6c, 0x5b,
  133. 0x51, (byte) 0x8d, 0x1b, (byte) 0xaf, (byte) 0x92, (byte) 0xbb,
  134. (byte) 0xdd, (byte) 0xbc, 0x7f, 0x11, (byte) 0xd9, 0x5c, 0x41,
  135. 0x1f, 0x10, 0x5a, (byte) 0xd8, 0x0a, (byte) 0xc1, 0x31,
  136. (byte) 0x88, (byte) 0xa5, (byte) 0xcd, 0x7b, (byte) 0xbd, 0x2d,
  137. 0x74, (byte) 0xd0, 0x12, (byte) 0xb8, (byte) 0xe5, (byte) 0xb4,
  138. (byte) 0xb0, (byte) 0x89, 0x69, (byte) 0x97, 0x4a, 0x0c,
  139. (byte) 0x96, 0x77, 0x7e, 0x65, (byte) 0xb9, (byte) 0xf1, 0x09,
  140. (byte) 0xc5, 0x6e, (byte) 0xc6, (byte) 0x84, 0x18, (byte) 0xf0,
  141. 0x7d, (byte) 0xec, 0x3a, (byte) 0xdc, 0x4d, 0x20, 0x79,
  142. (byte) 0xee, 0x5f, 0x3e, (byte) 0xd7, (byte) 0xcb, 0x39, 0x48 };
  143. private int[] CK = { 0x00070e15, 0x1c232a31, 0x383f464d, 0x545b6269,
  144. 0x70777e85, 0x8c939aa1, 0xa8afb6bd, 0xc4cbd2d9, 0xe0e7eef5,
  145. 0xfc030a11, 0x181f262d, 0x343b4249, 0x50575e65, 0x6c737a81,
  146. 0x888f969d, 0xa4abb2b9, 0xc0c7ced5, 0xdce3eaf1, 0xf8ff060d,
  147. 0x141b2229, 0x30373e45, 0x4c535a61, 0x686f767d, 0x848b9299,
  148. 0xa0a7aeb5, 0xbcc3cad1, 0xd8dfe6ed, 0xf4fb0209, 0x10171e25,
  149. 0x2c333a41, 0x484f565d, 0x646b7279 };
  150. private int Rotl(int x, int y) {
  151. return x << y | x >>> (32 - y);
  152. }
  153. private int ByteSub(int A) {
  154. return (Sbox[A >>> 24 & 0xFF] & 0xFF) << 24
  155. | (Sbox[A >>> 16 & 0xFF] & 0xFF) << 16
  156. | (Sbox[A >>> 8 & 0xFF] & 0xFF) << 8 | (Sbox[A & 0xFF] & 0xFF);
  157. }
  158. private int L1(int B) {
  159. return B ^ Rotl(B, 2) ^ Rotl(B, 10) ^ Rotl(B, 18) ^ Rotl(B, 24);
  160. // return B^(B<<2|B>>>30)^(B<<10|B>>>22)^(B<<18|B>>>14)^(B<<24|B>>>8);
  161. }
  162. private int L2(int B) {
  163. return B ^ Rotl(B, 13) ^ Rotl(B, 23);
  164. // return B^(B<<13|B>>>19)^(B<<23|B>>>9);
  165. }
  166. void SMS4Crypt(byte[] Input, byte[] Output, int[] rk) {
  167. int r, mid;
  168. int[] x = new int[4];
  169. int[] tmp = new int[4];
  170. for (int i = 0; i < 4; i++) {
  171. tmp[0] = Input[0 + 4 * i] & 0xff;
  172. tmp[1] = Input[1 + 4 * i] & 0xff;
  173. tmp[2] = Input[2 + 4 * i] & 0xff;
  174. tmp[3] = Input[3 + 4 * i] & 0xff;
  175. x[i] = tmp[0] << 24 | tmp[1] << 16 | tmp[2] << 8 | tmp[3];
  176. // x[i]=(Input[0+4*i]<<24|Input[1+4*i]<<16|Input[2+4*i]<<8|Input[3+4*i]);
  177. }
  178. for (r = 0; r < 32; r += 4) {
  179. mid = x[1] ^ x[2] ^ x[3] ^ rk[r + 0];
  180. mid = ByteSub(mid);
  181. x[0] = x[0] ^ L1(mid); // x4
  182. mid = x[2] ^ x[3] ^ x[0] ^ rk[r + 1];
  183. mid = ByteSub(mid);
  184. x[1] = x[1] ^ L1(mid); // x5
  185. mid = x[3] ^ x[0] ^ x[1] ^ rk[r + 2];
  186. mid = ByteSub(mid);
  187. x[2] = x[2] ^ L1(mid); // x6
  188. mid = x[0] ^ x[1] ^ x[2] ^ rk[r + 3];
  189. mid = ByteSub(mid);
  190. x[3] = x[3] ^ L1(mid); // x7
  191. }
  192. // Reverse
  193. for (int j = 0; j < 16; j += 4) {
  194. Output[j] = (byte) (x[3 - j / 4] >>> 24 & 0xFF);
  195. Output[j + 1] = (byte) (x[3 - j / 4] >>> 16 & 0xFF);
  196. Output[j + 2] = (byte) (x[3 - j / 4] >>> 8 & 0xFF);
  197. Output[j + 3] = (byte) (x[3 - j / 4] & 0xFF);
  198. }
  199. }
  200. private void SMS4KeyExt(byte[] Key, int[] rk, int CryptFlag) {
  201. int r, mid;
  202. int[] x = new int[4];
  203. int[] tmp = new int[4];
  204. for (int i = 0; i < 4; i++) {
  205. tmp[0] = Key[0 + 4 * i] & 0xFF;
  206. tmp[1] = Key[1 + 4 * i] & 0xff;
  207. tmp[2] = Key[2 + 4 * i] & 0xff;
  208. tmp[3] = Key[3 + 4 * i] & 0xff;
  209. x[i] = tmp[0] << 24 | tmp[1] << 16 | tmp[2] << 8 | tmp[3];
  210. }
  211. x[0] ^= 0xa3b1bac6;
  212. x[1] ^= 0x56aa3350;
  213. x[2] ^= 0x677d9197;
  214. x[3] ^= 0xb27022dc;
  215. for (r = 0; r < 32; r += 4) {
  216. mid = x[1] ^ x[2] ^ x[3] ^ CK[r + 0];
  217. mid = ByteSub(mid);
  218. rk[r + 0] = x[0] ^= L2(mid); // rk0=K4
  219. mid = x[2] ^ x[3] ^ x[0] ^ CK[r + 1];
  220. mid = ByteSub(mid);
  221. rk[r + 1] = x[1] ^= L2(mid); // rk1=K5
  222. mid = x[3] ^ x[0] ^ x[1] ^ CK[r + 2];
  223. mid = ByteSub(mid);
  224. rk[r + 2] = x[2] ^= L2(mid); // rk2=K6
  225. mid = x[0] ^ x[1] ^ x[2] ^ CK[r + 3];
  226. mid = ByteSub(mid);
  227. rk[r + 3] = x[3] ^= L2(mid); // rk3=K7
  228. }
  229. // 解密时轮密钥使用顺序:rk31,rk30,...,rk0 //解密时轮密钥反向
  230. if (CryptFlag == DECRYPT) {
  231. for (r = 0; r < 16; r++) {
  232. mid = rk[r];
  233. rk[r] = rk[31 - r];
  234. rk[31 - r] = mid;
  235. }
  236. }
  237. }
  238. public int sms4(byte[] in, int inLen, byte[] key, byte[] out, int CryptFlag) {
  239. int point = 0;
  240. int[] round_key = new int[ROUND];
  241. SMS4KeyExt(key, round_key, CryptFlag);
  242. byte[] input = new byte[16];
  243. byte[] output = new byte[16];
  244. while (inLen >= BLOCK) {
  245. input = Arrays.copyOfRange(in, point, point + 16);
  246. SMS4Crypt(input, output, round_key);
  247. System.arraycopy(output, 0, out, point, BLOCK);
  248. inLen -= BLOCK;
  249. point += BLOCK;
  250. }
  251. return 0;
  252. }
  253. }
  254. Encryption.java
  255. package com.example.android_snake;
  256. import android.util.Log;
  257. public class Encryption {
  258. /**
  259. * SM4加解密封装
  260. * @param data 传入参数
  261. * @param flag 加密为1&解密为0
  262. * @param key 16字节密钥
  263. * @return 加解密结果
  264. */
  265. public static String deal(String data, int flag, byte[] key)
  266. {
  267. StringBuilder builder = new StringBuilder();
  268. SM4 sm4 = SM4.getInstance();
  269. String strData = "";
  270. byte[] bInData;
  271. byte[] bOutData = new byte[16];
  272. int nIndex;
  273. int nDataLen = data.length();
  274. int nCount = 0;
  275. int nLastLen = nDataLen%32;
  276. if (nLastLen > 0) {
  277. nCount = nDataLen/32 + 1;
  278. if (flag ==0) {
  279. Log.i("SM4", "数据长度不正确,需解密数据应是32的倍数");
  280. }
  281. } else {
  282. nCount = nDataLen/32;
  283. }
  284. for (int i = 0; i < nCount; i++) {
  285. if ((i+1) == nCount && nLastLen > 0) {
  286. nIndex = i*32;
  287. strData = data.substring(nIndex, nIndex+nLastLen);
  288. strData = zero(strData);
  289. bInData = hexStringToBytes(strData);
  290. sm4.sms4(bInData,bInData.length,key,bOutData,flag);
  291. strData = bytesToHexString(bOutData,0,16);
  292. builder.append(strData);
  293. } else {
  294. nIndex = i*32;
  295. strData = data.substring(nIndex, nIndex+32);
  296. bInData = hexStringToBytes(strData);
  297. sm4.sms4(bInData,bInData.length,key,bOutData,flag);
  298. strData = bytesToHexString(bOutData,0,16);
  299. builder.append(strData);
  300. }
  301. }
  302. return builder.toString();
  303. }
  304. /**
  305. * 补位方法,SM4 分块加密 ,每块16字节,此处不足补0. 扩展说明:有得规则是首字节补80,之后补00,还有区分左补和右补,如果此加解密不能满足要求,可以往这方面去做
  306. * @param data 需补位的数据
  307. * @return 补位后的字符串
  308. */
  309. public static String zero(String data) {
  310. StringBuilder builder = new StringBuilder();
  311. builder.append(data);
  312. int nLen = data.length();
  313. while (nLen < 32) {
  314. builder.append("0");
  315. nLen++;
  316. }
  317. return builder.toString();
  318. }
  319. /**
  320. * hexString转byte[]数组
  321. * @param str 字符串,原串为“112233”
  322. * @return 转换后的数据, 转换后为 0x11,0x22,0x33
  323. */
  324. public static byte[] hexStringToBytes(String str) {
  325. int charIndex, value;
  326. int datalen = str.length() / 2;
  327. byte[] data = new byte[datalen];
  328. for (int i = 0; i < datalen; i++) {
  329. charIndex = i * 2;
  330. value = Integer.parseInt(str.substring(charIndex, charIndex + 2), 16);
  331. data[i] = (byte) value;
  332. }
  333. return data;
  334. }
  335. /**
  336. * byte[]数组转hexString
  337. * @param data 需转换的数组 0x11,0x22,0x33
  338. * @param offset 需转换开始位置
  339. * @param len 需转换长度
  340. * @return 转换后的字符传为“112233”
  341. */
  342. public static String bytesToHexString(byte[] data, int offset, int len) {
  343. StringBuilder sb = new StringBuilder();
  344. for (int i = 0; i < len; i++)
  345. sb.append(String.format("%02X", data[i + offset] & 0xff));
  346. return sb.toString();
  347. }
  348. }
  349. FinalwinActivity.java
  350. package com.example.android_snake;
  351. import android.app.Activity;
  352. import android.os.Bundle;
  353. import android.view.Window;
  354. import android.view.WindowManager;
  355. import androidx.appcompat.app.AppCompatActivity;
  356. public class FinalwinActivity extends AppCompatActivity {
  357. protected void onCreate(Bundle savedInstanceState) {
  358. super.onCreate(savedInstanceState);
  359. //隐藏标题栏以及状态栏
  360. getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
  361. WindowManager.LayoutParams.FLAG_FULLSCREEN);
  362. requestWindowFeature(Window.FEATURE_NO_TITLE);
  363. setContentView(R.layout.activity_finalwin);
  364. }
  365. }
  366. Images.java
  367. package com.example.android_snake;
  368. import android.content.Context;
  369. import android.graphics.Bitmap;
  370. import android.graphics.BitmapFactory;
  371. import android.graphics.Canvas;
  372. import android.graphics.Paint;
  373. import android.view.View;
  374. import android.view.WindowManager;
  375. import android.util.DisplayMetrics;
  376. import java.util.Random;
  377. public class Images extends View {
  378. private int BitmapX,BitmapY;
  379. private int FoodX,FoodY;
  380. private int[] snakeX =new int[Macro.MAX_LENGTH];
  381. private int[] snakeY =new int[Macro.MAX_LENGTH];
  382. private int length;
  383. private int direction;
  384. private boolean islive;//是否存活 状态
  385. private Bitmap rbitmaphead,lbitmaphead,ubitmaphead,dbitmaphead,bitmapbody,bitmapfood;//四个方向的头及蛇的身体、食物
  386. private Bitmap bitmapfoods[] = new Bitmap [6];
  387. private Bitmap bling;
  388. public boolean isIslive() {
  389. return islive;
  390. }
  391. public void setIslive(boolean islive) {
  392. this.islive = islive;
  393. }
  394. public int getFoodX() {
  395. return FoodX;
  396. }
  397. public void setFoodX(int foodX) {
  398. FoodX = foodX;
  399. }
  400. public void setBitmapfood(int x){
  401. if(x < 6 && x >= 0)
  402. bitmapfood = bitmapfoods[x];
  403. }
  404. public int getFoodY() {
  405. return FoodY;
  406. }
  407. public void setFoodY(int foodY) {
  408. FoodY = foodY;
  409. }
  410. public int getDirection() {
  411. return direction;
  412. }
  413. public void setDirection(int direction) {
  414. this.direction = direction;
  415. }
  416. public int getLength() {
  417. return length;
  418. }
  419. public void setLength(int length) {
  420. this.length = length;
  421. }
  422. public int getBitmapX() {
  423. return BitmapX;
  424. }
  425. public void setBitmapX(int bitmapX) {
  426. BitmapX = bitmapX;
  427. }
  428. public int getBitmapY() {
  429. return BitmapY;
  430. }
  431. public void setBitmapY(int bitmapY) {
  432. BitmapY = bitmapY;
  433. }
  434. public Images(Context context) {
  435. super(context);
  436. }
  437. /**
  438. * 小蛇初始化
  439. */
  440. public void Init(){
  441. BitmapX=Macro.INIT_SNAKEX;
  442. // BitmapX = MainActivity.screenWidth/2; //手机屏幕宽度的一半
  443. BitmapY=Macro.INIT_SNAKEY;
  444. FoodX=Macro.INIT_FOODX;
  445. FoodY=Macro.INIT_FOODY;//初始坐标
  446. Random r = new Random(); //用于生成随机数
  447. int randomN = r.nextInt(3);//随机生成[0,3)的整数
  448. snakeX[0]=BitmapX;
  449. snakeY[0]=BitmapY;//蛇头的位置
  450. length =Macro.INIT_LENGHT;//蛇的初始长度
  451. islive=true;
  452. switch (randomN){//设置蛇的初始状态
  453. case 0://初始方向向右
  454. direction=Macro.Right;//蛇的初始方向
  455. //画出初始的蛇身
  456. for(int i = 1; i< length; i++){
  457. snakeX[i]= snakeX[i-1]-Macro.UNIT;
  458. snakeY[i]= snakeY[0]; //初始状态
  459. }
  460. break;
  461. case 1://初始方向向上
  462. direction=Macro.Up;//蛇的初始方向
  463. //画出初始的蛇身
  464. for(int i = 1; i< length; i++){
  465. snakeY[i]= snakeY[i-1]+Macro.UNIT;
  466. snakeX[i]= snakeX[0]; //初始状态
  467. }
  468. break;
  469. case 2://初始方向向下
  470. direction=Macro.Down;//蛇的初始方向
  471. //画出初始的蛇身
  472. for(int i = 1; i< length; i++){
  473. snakeY[i]= snakeY[i-1]-Macro.UNIT;
  474. snakeX[i]= snakeX[0]; //初始状态
  475. }
  476. break;
  477. }
  478. }
  479. /**
  480. * 引用小蛇图片,并设置图片大小
  481. */
  482. public void Size(){
  483. //避免大图片解析问题--头部
  484. BitmapFactory.Options headoptions = new BitmapFactory.Options();
  485. //调整
  486. headoptions.inSampleSize= Macro.IMAGE_HEAD_SIZE; //蛇头缩放倍数
  487. headoptions.inJustDecodeBounds=false;
  488. //避免大图片解析问题--身体
  489. BitmapFactory.Options bodyoptions = new BitmapFactory.Options();
  490. bodyoptions.inSampleSize=Macro.IMAGE_BODY_SIZE; //蛇身的缩放倍数
  491. bodyoptions.inJustDecodeBounds=false;
  492. //六种食物随机产生
  493. bitmapfoods[0]= BitmapFactory.decodeResource(this.getResources(),R.drawable.food);
  494. bitmapfoods[1]= BitmapFactory.decodeResource(this.getResources(),R.drawable.food1);
  495. bitmapfoods[2]= BitmapFactory.decodeResource(this.getResources(),R.drawable.food2);
  496. bitmapfoods[3]= BitmapFactory.decodeResource(this.getResources(),R.drawable.food3);
  497. bitmapfoods[4]= BitmapFactory.decodeResource(this.getResources(),R.drawable.food4);
  498. bitmapfoods[5]= BitmapFactory.decodeResource(this.getResources(),R.drawable.food50);
  499. rbitmaphead= BitmapFactory.decodeResource(this.getResources(),R.drawable.rhead0, headoptions); //
  500. ubitmaphead= BitmapFactory.decodeResource(this.getResources(),R.drawable.uhead0, headoptions);
  501. lbitmaphead= BitmapFactory.decodeResource(this.getResources(),R.drawable.lhead0, headoptions);
  502. dbitmaphead= BitmapFactory.decodeResource(this.getResources(),R.drawable.dhead0, headoptions);
  503. bitmapbody= BitmapFactory.decodeResource(this.getResources(),R.drawable.body_0, bodyoptions);
  504. Random r = new Random(); //用于生成随机数
  505. int randomN = r.nextInt(6);//随机生成[0,6)的整数
  506. bitmapfood= bitmapfoods[randomN];
  507. }
  508. /**
  509. * 画蛇,将蛇画在屏幕上 canvas用于绘制背景的画布
  510. * Canvas 画布
  511. * Paint 画笔
  512. */
  513. @Override
  514. protected void onDraw(Canvas canvas) {
  515. super.onDraw(canvas); //Canvas(画纸,通常称为画布)
  516. Paint paint=new Paint(); //生成一个画笔对象
  517. //画食物
  518. /**
  519. * @param bitmap The bitmap to be drawn
  520. * @param left The position of the left side of the bitmap being drawn
  521. * @param top The position of the top side of the bitmap being drawn
  522. * @param paint The paint used to draw the bitmap (may be null)
  523. */
  524. canvas.drawBitmap(bitmapfood, FoodX, FoodY, paint);//画第一食物, 第一个参数为要绘制的bitmap对象,第四个参数为Paint对象。
  525. snakeX[0]=BitmapX;
  526. snakeY[0]=BitmapY;
  527. switch (direction){
  528. case Macro.Right:
  529. canvas.drawBitmap(rbitmaphead, snakeX[0], snakeY[0],paint);//蛇头往右,读取x、y坐标,填充画笔
  530. //canvas.drawBitmap(bling, snakeX[0], snakeY[0],paint);
  531. break;
  532. case Macro.Up:
  533. canvas.drawBitmap(ubitmaphead, snakeX[0], snakeY[0],paint);
  534. // canvas.drawBitmap(bling, snakeX[0], snakeY[0],paint);//蛇头往右,读取x、y坐标,填充画笔
  535. break;
  536. case Macro.Left:
  537. canvas.drawBitmap(lbitmaphead, snakeX[0], snakeY[0],paint);
  538. break;
  539. case Macro.Down:
  540. canvas.drawBitmap(dbitmaphead, snakeX[0], snakeY[0],paint);
  541. break;
  542. }
  543. //画出小蛇身体的位置
  544. for(int i = 1; i< length; i++) {
  545. canvas.drawBitmap(bitmapbody, snakeX[i], snakeY[i], paint);
  546. }
  547. //小蛇咬住身体了 生存位置零
  548. for(int i = 1; i< length; i++){
  549. if(snakeX[0]== snakeX[i]&& snakeY[0]== snakeY[i]){
  550. islive=false;
  551. }
  552. }
  553. //身体从最后一节向前一节位置移动
  554. for(int i = length; i>0; i--){
  555. snakeX[i]= snakeX[i-1];
  556. snakeY[i]= snakeY[i-1];
  557. }
  558. /**
  559. * Returns true if this bitmap has been recycled. If so, then it is an error
  560. * to try to access its pixels, and the bitmap will not draw.
  561. **如果该位图已被回收,则返回true。如果是,则是false
  562. * *试图访问其像素,位图将不会绘制。
  563. * *如果位图已经被回收,返回true
  564. * @return true if the bitmap has been recycled
  565. */
  566. //图片回收
  567. if(rbitmaphead.isRecycled()){
  568. rbitmaphead.recycle();
  569. }
  570. if(bitmapbody.isRecycled()){
  571. bitmapbody.recycle();
  572. }
  573. if(ubitmaphead.isRecycled()){
  574. rbitmaphead.recycle();
  575. }
  576. if(lbitmaphead.isRecycled()){
  577. rbitmaphead.recycle();
  578. }
  579. if(dbitmaphead.isRecycled()){
  580. rbitmaphead.recycle();
  581. }
  582. }
  583. }
  584. LoginActivity.java
  585. package com.example.android_snake;
  586. import android.content.Intent;
  587. import android.os.Bundle;
  588. import android.util.Log;
  589. import android.view.View;
  590. import android.widget.Button;
  591. import android.widget.EditText;
  592. import android.widget.Toast;
  593. import androidx.appcompat.app.AppCompatActivity;
  594. public class LoginActivity extends AppCompatActivity{
  595. /**
  596. * 定义私有成员文本 账号密码etc
  597. */
  598. private EditText username;
  599. private EditText password;
  600. private int remarks;//初始值为0
  601. private Button Loginbutton; //登录按钮
  602. private Button goRegisterButton;//打开注册界面
  603. static public String usern; //工具字符串,用于用户分数信息存储文件命名
  604. private Button Rbtlogin;
  605. boolean agree = false;//是否同意用户协议 标志位
  606. private void findViews(){
  607. username = (EditText) findViewById(R.id.username_login);
  608. password = (EditText) findViewById(R.id.password_login);
  609. //remarks = 0;//初始化为0
  610. Loginbutton = (Button) findViewById(R.id.bt_login);
  611. goRegisterButton =(Button) findViewById(R.id.bt_goRegister);
  612. Rbtlogin = (Button) findViewById(R.id.rbt_login);
  613. }
  614. protected void onCreate(Bundle savedInstanceState){
  615. super.onCreate(savedInstanceState);
  616. setContentView(R.layout.activity_login);//即activity_login.xml
  617. findViews();
  618. //设置按钮点击监听器
  619. Rbtlogin.setOnClickListener(new View.OnClickListener() {
  620. //按钮点击
  621. @Override
  622. public void onClick(View view) {
  623. if (view.getId() == R.id.rbt_login) {//同意协议
  624. Log.i("TAG","同意用户协议");
  625. agree = true;
  626. }
  627. }
  628. });
  629. Loginbutton.setOnClickListener(new View.OnClickListener() {
  630. @Override
  631. public void onClick(View v) {
  632. //MainActivity.playSound();
  633. if(!agree) {//未勾选同意用户协议
  634. Toast.makeText(LoginActivity.this,"请先勾选同意用户协议",Toast.LENGTH_LONG).show();
  635. return;
  636. }
  637. String name = username.getText().toString().trim();
  638. //System.out.println(name);
  639. String pass = password.getText().toString().trim();
  640. //System.out.println(pass);
  641. //对密码进行国密SM4加密,密文与用户数据库中数据表字段比较
  642. String strKey = "0123456789abcdeffedcba9876543210";//密钥
  643. byte[] bKey = Encryption.hexStringToBytes(strKey);
  644. String CPass = Encryption.deal(pass,SM4.ENCRYPT,bKey);//密码加密后的密文CPass
  645. Log.i("TAG","username_"+name+"_ CPassword_"+CPass);
  646. UserService uService = new UserService(LoginActivity.this);
  647. boolean flag = uService.login(name,CPass);
  648. if(flag){
  649. Log.i("TAG","登陆成功");
  650. Toast.makeText(LoginActivity.this,"登录成功",Toast.LENGTH_LONG).show();
  651. usern = name;//便于用户最高分数文件存储 ,为了安全性,只赋值用户名
  652. //登录成功,跳转游戏选择界面
  653. Intent intent = new Intent(LoginActivity.this,ChooseActivity.class);
  654. startActivity(intent);
  655. }else{
  656. Log.i("TAG","登陆失败");
  657. Toast.makeText(LoginActivity.this,"登录失败",Toast.LENGTH_LONG).show();
  658. }
  659. }
  660. });
  661. goRegisterButton.setOnClickListener(new View.OnClickListener() {
  662. @Override
  663. public void onClick(View v) {//跳转注册界面
  664. startActivity(new Intent(LoginActivity.this,RegisterActivity.class));
  665. }
  666. });
  667. }
  668. }
  669. Macro.java
  670. package com.example.android_snake;
  671. import android.content.Context;
  672. import android.util.DisplayMetrics;
  673. import android.view.WindowManager;
  674. /**
  675. * The type Macro:宏的定义
  676. */
  677. public class Macro {
  678. /**
  679. * The constant Up:定义小蛇头部方向向上
  680. */
  681. public static final int Up=0x11;
  682. /**
  683. * The constant :定义小蛇头部方向向下
  684. */
  685. public static final int Down=0x12;
  686. /**
  687. * The constant Left:定义小蛇头部方向向左
  688. */
  689. public static final int Left=0x13;
  690. /**
  691. * The constant Right:定义小蛇头部方向向右
  692. */
  693. public static final int Right=0x14;
  694. /**
  695. * The constant UNIT:定义小蛇移动的基本单位
  696. */
  697. public static final int UNIT=50;
  698. /**
  699. * The constant LEAST_SIZE:小蛇生活区最小单位
  700. */
  701. public static final int LEAST_SIZE=1;
  702. /**
  703. * The constant DELAY:定时器响应run延时
  704. */
  705. public static final int DELAY=100;
  706. /**
  707. * The constant PERIOD:定时器启动的间隔时间
  708. */
  709. public static final int PERIOD=300;
  710. /**
  711. * The constant INIT_SNAKEX:小蛇初始头部的X坐标
  712. */
  713. // public static final int INIT_SNAKEX =600;
  714. public static final int INIT_SNAKEX =MainActivity.screenWidth/2;
  715. /**
  716. * The constant INIT_SNAKEY:小蛇初始头部的Y坐标
  717. */
  718. public static final int INIT_SNAKEY =400;
  719. /**
  720. * The constant INIT_FOODX:食物初始的X坐标
  721. */
  722. public static final int INIT_FOODX=400;
  723. /**
  724. * The constant INIT_FOODY:食物初始的Y坐标
  725. */
  726. public static final int INIT_FOODY=500;
  727. /**
  728. * The constant INIT_LENGHT:小蛇初始长度
  729. */
  730. public static final int INIT_LENGHT=4;
  731. /**
  732. * The constant IMAGE_HEAD_SIZE:小蛇头图片缩小倍数
  733. */
  734. //public static final int IMAGE_HEAD_SIZE=20;
  735. public static final int IMAGE_HEAD_SIZE=1;
  736. /**
  737. * The constant IMAGE_BODY_SIZE:小蛇身体图片缩小倍数
  738. */
  739. //public static final int IMAGE_BODY_SIZE=46;
  740. public static final int IMAGE_BODY_SIZE=1;
  741. /**
  742. * The constant SCORE_UNIT:每次加分
  743. */
  744. public static final int SCORE_UNIT=10;
  745. /**
  746. * The constant MAX_LENGTH:小蛇最大长度
  747. */
  748. public static final int MAX_LENGTH =900;
  749. /**
  750. * The constant SPEED:小蛇的初始速度
  751. */
  752. public static final int SPEED=20;
  753. /**
  754. * The constant FOOD:小蛇吃到食物就会加速的基本单位
  755. */
  756. public static final int FOOD=40;
  757. /**
  758. * The constant MAX_SPEED:小蛇移动的最大速度
  759. */
  760. public static final int MAX_SPEED =270;
  761. /**
  762. * The constant SCORE:此局的分数显示
  763. */
  764. public static final String SCORE="当前分数:";
  765. /**
  766. * The constant MOST_SCORE:历史最高分数显示
  767. */
  768. public static final String MOST_SCORE="最高分数:";
  769. /**
  770. * The constant H_MOST_SCORE:主界面查询分数显示
  771. */
  772. public static final String H_MOST_SCORE="最高分数(点击更新):";
  773. /**
  774. * The constant Pname:分数存储文件名统一名称后缀
  775. */
  776. public static final String Pname="scorefile";
  777. /**
  778. * The constant Pname:静音选中存储文件名统一名称后缀
  779. */
  780. public static final String PnameFlag="Volumefile";
  781. /**
  782. * 获得屏幕的宽度
  783. * @param ctx
  784. * @return
  785. */
  786. public static int getScreenWidth(Context ctx) {
  787. // 从系统服务中获取窗口管理器
  788. WindowManager wm = (WindowManager) ctx.getSystemService(Context.WINDOW_SERVICE);
  789. DisplayMetrics dm = new DisplayMetrics();
  790. // 从默认显示器中获取显示参数保存到dm对象中
  791. wm.getDefaultDisplay().getMetrics(dm);
  792. return dm.widthPixels; // 返回屏幕的宽度数值
  793. }
  794. /**
  795. * 获得屏幕的高度
  796. */
  797. public static int getScreenHeight(Context ctx) {
  798. // 从系统服务中获取窗口管理器
  799. WindowManager wm = (WindowManager) ctx.getSystemService(Context.WINDOW_SERVICE);
  800. DisplayMetrics dm = new DisplayMetrics();
  801. // 从默认显示器中获取显示参数保存到dm对象中
  802. wm.getDefaultDisplay().getMetrics(dm);
  803. return dm.heightPixels; // 返回屏幕的高度数值
  804. }
  805. }
  806. MainActivity.java
  807. package com.example.android_snake;
  808. import static com.example.android_snake.BGMserver.play;
  809. import static com.example.android_snake.BGMserver.stop;
  810. import androidx.appcompat.app.AppCompatActivity;
  811. import android.annotation.SuppressLint;
  812. import android.content.Context;
  813. import android.content.Intent;
  814. import android.media.AudioManager;
  815. import android.media.SoundPool;
  816. import android.os.Bundle;
  817. import android.os.Handler;
  818. import android.os.Looper;
  819. import android.os.Message;
  820. import android.view.View;
  821. import android.widget.Button;
  822. import android.widget.FrameLayout;
  823. import android.widget.ImageView;
  824. import android.widget.RelativeLayout;
  825. import android.widget.TextView;
  826. import java.util.HashMap;
  827. import java.util.Random;
  828. import java.util.Timer;
  829. import java.util.TimerTask;
  830. /**
  831. * The type Main activity:小蛇移动及方向控制逻辑处理
  832. */
  833. public class MainActivity extends AppCompatActivity implements View.OnClickListener {
  834. private String usern;
  835. private FrameLayout Living_Space;
  836. private boolean isstart =false;
  837. private boolean volumeflag = true;
  838. private Timer timer;
  839. private Button BT_isstar,BT_RIGHT,BT_UP,BT_DOWN,BT_LEFT,BT_Volume;
  840. private TextView prompt;
  841. private TextView ScoreView;
  842. private int direction;
  843. private int weight,height;
  844. public static int screenWidth,screenHeight;
  845. private int countVolume;//计数点击音量按键的次数 判断奇偶性
  846. private boolean islive;
  847. private int score,time,mostscore;
  848. Images images;
  849. MoveSnake movesnake;
  850. SharedPre shared;
  851. private Handler handler;
  852. // RelativeLayout frameLayout_add_imageview;
  853. SoundPool sp;//声明SoundPool的引用
  854. HashMap<Integer, Integer> hm;//声明HashMap来存放声音文件
  855. int currStaeamId;//当前正播放的streamId
  856. private void initSoundPool() {//初始化声音池
  857. sp = new SoundPool(4, AudioManager.STREAM_MUSIC, 0);//创建SoundPool对象
  858. hm = new HashMap<Integer, Integer>();//创建HashMap对象
  859. //加载声音文件,并且设置为1号 2号 3号声音放入hm中
  860. hm.put(1, sp.load(this, R.raw.button0, 1));
  861. hm.put(2, sp.load(this, R.raw.win, 1));
  862. hm.put(3, sp.load(this, R.raw.fail, 1));
  863. hm.put(4, sp.load(this, R.raw.applause, 1));
  864. }
  865. private void playSound(int sound, int loop) {//获取AudioManager引用
  866. AudioManager am = (AudioManager) this.getSystemService(Context.AUDIO_SERVICE);
  867. //获取当前音量
  868. float streamVolumeCurrent = am.getStreamVolume(AudioManager.STREAM_MUSIC);
  869. //获取系统最大音量
  870. float streamVolumeMax = am.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
  871. //计算得到播放音量
  872. float volume = streamVolumeCurrent / streamVolumeMax;
  873. //调用SoundPool的play方法来播放声音文件
  874. currStaeamId = sp.play(hm.get(sound), volume, volume, 1, loop, 1.0f);
  875. }
  876. //BGM设置工具函数
  877. protected void onPause() {
  878. // TODO Auto-generated method stub
  879. super.onPause();
  880. stop(this);
  881. }
  882. //BGM设置工具函数
  883. protected void onResume() {
  884. // TODO Auto-generated method stub
  885. super.onResume();
  886. play(this, R.raw.bgm);
  887. }
  888. class MoveSnake extends Thread{
  889. @SuppressLint("HandlerLeak")
  890. // @Override
  891. public void run() {
  892. Looper.prepare();//调用 Looper.prepare()来给线程创建消息循环
  893. handler=new Handler(){
  894. public void handleMessage(Message msg) {
  895. if(isstart ==true&& islive==true){
  896. //方向控制
  897. if(msg.what==Macro.Right) {
  898. images.setBitmapX(images.getBitmapX() + Macro.UNIT);//The constant UNIT:定义小蛇移动的基本单位,x轴+一个移动单位
  899. images.setBitmapY(images.getBitmapY());
  900. }
  901. if(msg.what==Macro.Up) {
  902. images.setBitmapY(images.getBitmapY()-Macro.UNIT);
  903. images.setBitmapX(images.getBitmapX());
  904. }
  905. if(msg.what==Macro.Left) {
  906. images.setBitmapX(images.getBitmapX()-Macro.UNIT);
  907. images.setBitmapY(images.getBitmapY());
  908. }
  909. if(msg.what==Macro.Down) {
  910. images.setBitmapY(images.getBitmapY()+Macro.UNIT);
  911. images.setBitmapX(images.getBitmapX());
  912. }
  913. //吃掉食物处理
  914. if((images.getBitmapX()==images.getFoodX())&&(images.getBitmapY()==images.getFoodY())){
  915. //加吃到食物的光效
  916. // ImageView imageView = new ImageView(MainActivity.this);
  917. // imageView.setImageResource(R.drawable.bling);
  918. // FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(100,
  919. // 30);//为添加图片的大小
  920. // imageView.setLayoutParams(params);
  921. // //imageView.setBackgroundColor();
  922. // frameLayout_add_imageview.addView(imageView);
  923. // if(shared.readVolumeFlag()==1) playSound(2, 0);//播放2号声音资源win,且播放一次
  924. if(volumeflag) playSound(2, 0);//播放2号声音资源win,且播放一次
  925. images.setLength(images.getLength()+1);//蛇身长度加1
  926. int FoodX=(int)(Math.random()*(weight/Macro.UNIT))*Macro.UNIT; //食物随机位置出现
  927. int FoodY=(int)(Math.random()*(height/Macro.UNIT))*Macro.UNIT;
  928. if(FoodX==images.getBitmapX()&&FoodY==images.getBitmapY()){
  929. FoodX= FoodX+Macro.UNIT;
  930. FoodY= FoodY-Macro.UNIT;
  931. }
  932. Random r = new Random(); //用于生成随机数
  933. int randomN = r.nextInt(6);//随机生成[0,6)的整数
  934. images.setBitmapfood(randomN);//随机生成食物种类
  935. images.setFoodX(FoodX);
  936. images.setFoodY(FoodY);
  937. score+=Macro.SCORE_UNIT;
  938. if(score%Macro.FOOD==0){
  939. timer.cancel();
  940. if(time<=Macro.MAX_SPEED)
  941. time+=Macro.SPEED;
  942. StartView(time); //循环任务, sendmessage
  943. }
  944. }
  945. images.invalidate();//invalidate()方法是用来刷新重绘当前的View的,如果当前View的布局尺寸、位置没有变化,仅仅是绘制内容变化了,那么我们就可以调用invalidate()方法。
  946. //线程中更新控件,用来计分
  947. runOnUiThread(new Runnable() {
  948. @Override
  949. public void run() {
  950. ScoreView.setText(Macro.SCORE+String.valueOf(score));
  951. if(shared.readVolumeFlag()==0) onPause();
  952. //if(!volumeflag)onPause();//检测到静音设置,停止播放背景音
  953. if(score % 50 == 0 && score > 0 && score < 250 && shared.readVolumeFlag()==1) //250分以下,每满50分 掌声响起一次
  954. playSound(4, 0);//播放2号声音资源applause,且播放一次
  955. if(score >= 300 && score < 400 && score%20==0 && shared.readVolumeFlag()==1) //分数满300分,小于400分 每20分 掌声响起一次
  956. {
  957. playSound(4, 0);//播放声音资源applause,且播放一次
  958. }
  959. if(score >= 400 ) //分数大于四百 提示胜利祝贺 每10分掌声响一次
  960. {
  961. if(shared.readVolumeFlag()==1) playSound(4, 0);//播放2号声音资源applause,且播放一次
  962. prompt.setText(R.string.congratulations);//屏幕提示:YOU ARE A WINNER!
  963. prompt.setVisibility(View.VISIBLE);
  964. BT_isstar.setText("WIN!");
  965. }
  966. if(score == 500 ) //分数等于五百 提示奖励祝贺
  967. {
  968. //游戏胜利,跳转奖励界面!
  969. Intent intent = new Intent(MainActivity.this,FinalwinActivity.class);
  970. startActivity(intent);
  971. }
  972. }
  973. });
  974. //死亡判断
  975. if(images.getBitmapX()>=weight||images.getBitmapX()<0
  976. ||images.getBitmapY()<0||images.getBitmapY()>=height
  977. ||images.isIslive()==false){
  978. islive=false;
  979. //小蛇死亡提醒
  980. runOnUiThread(new Runnable() {
  981. @Override
  982. public void run() {
  983. if(shared.readVolumeFlag()==1) playSound(3, 0);//播放3号声音资源fail,且播放一次
  984. BT_isstar.setText("重新开始");
  985. prompt.setText(R.string.promptrestar);
  986. prompt.setVisibility(View.VISIBLE);
  987. if(score>mostscore)
  988. mostscore=score;
  989. shared.save(usern,mostscore);//创分数新纪录 存入文件
  990. }
  991. });
  992. }
  993. }
  994. super.handleMessage(msg);
  995. }
  996. };
  997. Looper.loop();
  998. }
  999. }
  1000. @Override
  1001. protected void onCreate(Bundle savedInstanceState) {
  1002. super.onCreate(savedInstanceState);
  1003. setContentView(R.layout.activity_main);
  1004. MoveSnake movesnake =new MoveSnake();
  1005. movesnake.start(); //启动一个线程
  1006. Init();
  1007. StartView(time);
  1008. if(shared.readVolumeFlag()==1)onResume();//播放BGM
  1009. screenWidth = Macro.getScreenWidth(MainActivity.this);
  1010. screenHeight = Macro.getScreenHeight(MainActivity.this);
  1011. //将图片加载到布局中
  1012. Living_Space.addView(images);
  1013. //获取活动空间的宽和高
  1014. Living_Space.post(new Runnable() {
  1015. @Override
  1016. public void run() {
  1017. weight=Living_Space.getWidth();
  1018. height=Living_Space.getHeight();
  1019. }
  1020. });
  1021. }
  1022. @Override
  1023. protected void onDestroy() {
  1024. super.onDestroy();
  1025. handler.removeCallbacksAndMessages(null);
  1026. timer.cancel();
  1027. }
  1028. /**
  1029. * Init:初始化该界面控件及参数
  1030. */
  1031. //初始化
  1032. void Init(){
  1033. initSoundPool();//初始化声音池的方法
  1034. usern = LoginActivity.usern;
  1035. Living_Space=findViewById(R.id.framelayout);
  1036. BT_isstar=findViewById(R.id.isstar);
  1037. BT_RIGHT=findViewById(R.id.Right);
  1038. BT_UP=findViewById(R.id.Up);
  1039. BT_DOWN=findViewById(R.id.Down);
  1040. BT_LEFT=findViewById(R.id.Left);
  1041. BT_Volume = findViewById(R.id.Volume);
  1042. prompt=findViewById(R.id.prompt);
  1043. ScoreView=findViewById(R.id.Score);
  1044. TextView mostScore = findViewById(R.id.MostScore);
  1045. // if(shared.readVolumeFlag()==1){
  1046. // volumeflag = true;
  1047. // //BT_Volume.setBackground(R.drawable.volumeon);
  1048. // }else{
  1049. // volumeflag = false;
  1050. // BT_Volume.setBackgroundDrawable(getResources().getDrawable(R.drawable.volumeoff));//背景设置为静音
  1051. // }
  1052. countVolume = 0;
  1053. images=new Images(MainActivity.this);
  1054. shared=new SharedPre(usern,MainActivity.this);
  1055. direction=Macro.Right;
  1056. images.Init();
  1057. //direction = images.getDirection();
  1058. images.Size();
  1059. islive=true;
  1060. score=0;
  1061. mostscore=shared.read();
  1062. time=0;
  1063. if(shared.readVolumeFlag()==1)onResume();
  1064. BT_isstar.setOnClickListener(this);
  1065. BT_RIGHT.setOnClickListener(this);
  1066. BT_UP.setOnClickListener(this);
  1067. BT_LEFT.setOnClickListener(this);
  1068. BT_DOWN.setOnClickListener(this);
  1069. BT_Volume.setOnClickListener(this);
  1070. mostScore.setText(Macro.MOST_SCORE+shared.read());
  1071. }
  1072. /**
  1073. * onClick:该界面按钮监听事件
  1074. */
  1075. @Override
  1076. public void onClick(View v) {
  1077. switch (v.getId()){
  1078. //游戏的开始、暂停按钮
  1079. case R.id.isstar:
  1080. if(volumeflag)onResume();
  1081. if(volumeflag)playSound(1, 0);//播放1号声音资源,且播放一次
  1082. //提示播放即时音效
  1083. //Toast.makeText(MainActivity.this, "播放音效", Toast.LENGTH_SHORT).show();
  1084. isstart =!isstart;
  1085. if(isstart &&islive) {
  1086. BT_isstar.setText(R.string.stop);
  1087. onPause();//bgm停止
  1088. prompt.setVisibility(View.GONE);
  1089. }
  1090. else if(isstart ==false&&islive==true){
  1091. BT_isstar.setText("继续游戏");
  1092. prompt.setText("点击按钮继续游戏");
  1093. prompt.setVisibility(View.VISIBLE);
  1094. }
  1095. else if(islive==false){
  1096. // finish();
  1097. Intent intent=new Intent(MainActivity.this,MainActivity.class);
  1098. startActivity(intent);
  1099. }
  1100. break;
  1101. //控制小蛇方向向右
  1102. case R.id.Right:
  1103. if(isstart &&direction!=Macro.Left) {
  1104. direction = Macro.Right;
  1105. images.setDirection(direction);
  1106. }
  1107. break;
  1108. //控制小蛇方向向上
  1109. case R.id.Up:
  1110. if(isstart &&direction!=Macro.Down) {
  1111. direction = Macro.Up;
  1112. images.setDirection(direction);
  1113. }
  1114. break;
  1115. //控制小蛇方向向左
  1116. case R.id.Left:
  1117. if(isstart &&direction!=Macro.Right) {
  1118. direction = Macro.Left;
  1119. images.setDirection(direction);
  1120. }
  1121. break;
  1122. //控制小蛇方向向下
  1123. case R.id.Down:
  1124. if(isstart &&direction!=Macro.Up) {
  1125. direction = Macro.Down;
  1126. images.setDirection(direction);
  1127. }
  1128. break;
  1129. case R.id.Volume:
  1130. countVolume++;
  1131. if(countVolume%2!=0){
  1132. volumeflag = false;
  1133. shared.saveFlag(volumeflag); //存入文件
  1134. BT_Volume.setBackgroundDrawable(getResources().getDrawable(R.drawable.volumeoff));//背景设置为静音
  1135. }
  1136. else
  1137. {
  1138. volumeflag = true;
  1139. shared.saveFlag(volumeflag); //存入文件
  1140. BT_Volume.setBackgroundDrawable(getResources().getDrawable(R.drawable.volumeon));//背景设置
  1141. }
  1142. }
  1143. }
  1144. /**
  1145. * 定时器,定时发送小蛇方向信息,控制小蛇速度
  1146. * @param time
  1147. */
  1148. void StartView(int time) {
  1149. timer=new Timer();
  1150. TimerTask task = new TimerTask() {
  1151. @Override
  1152. public void run() {
  1153. handler.sendEmptyMessage(direction);
  1154. }
  1155. };
  1156. timer.schedule(task,Macro.DELAY,Macro.PERIOD-time);
  1157. }
  1158. }
  1159. MydatabaseHelper.java
  1160. package com.example.android_snake;
  1161. import android.database.sqlite.SQLiteDatabase;
  1162. import android.database.sqlite.SQLiteDatabase.CursorFactory;
  1163. import android.database.sqlite.SQLiteOpenHelper;
  1164. import android.content.Context;
  1165. import android.widget.Toast;
  1166. public class MyDatabaseHelper extends SQLiteOpenHelper {
  1167. public static final String CREATE_User = "create table user ("
  1168. + "id integer primary key autoincrement, "
  1169. + "userName varchar(20), "
  1170. + "Password varchar(40), "
  1171. + "Remarks integer)";
  1172. private Context mContext;
  1173. static int dbVersion = 1;//版本
  1174. static String name = "snakeUser.db";//数据库名
  1175. /**
  1176. *
  1177. * @param context
  1178. */
  1179. public MyDatabaseHelper( Context context) {
  1180. super(context, name, null, dbVersion);
  1181. mContext = context;
  1182. }
  1183. @Override
  1184. public void onCreate(SQLiteDatabase db) {
  1185. db.execSQL(CREATE_User);
  1186. // Toast.makeText(mContext, "用户信息创建成功", Toast.LENGTH_SHORT).show();
  1187. }
  1188. @Override
  1189. public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
  1190. }
  1191. }
  1192. RegisterActivity.java
  1193. package com.example.android_snake;
  1194. import android.content.Intent;
  1195. import android.os.Bundle;
  1196. import android.util.Log;
  1197. import android.view.View;
  1198. import android.widget.Button;
  1199. import android.widget.EditText;
  1200. import android.widget.Toast;
  1201. import androidx.appcompat.app.AppCompatActivity;
  1202. public class RegisterActivity extends AppCompatActivity {
  1203. private EditText username;
  1204. private EditText password;
  1205. private Button register;
  1206. private void findViews(){
  1207. username = (EditText) findViewById(R.id.username_register);
  1208. password = (EditText) findViewById(R.id.password_register);
  1209. register = (Button) findViewById(R.id.registerButton);
  1210. }
  1211. protected void onCreate(Bundle savedInstanceState){
  1212. super.onCreate(savedInstanceState);
  1213. setContentView(R.layout.activity_register);
  1214. findViews();
  1215. register.setOnClickListener(new View.OnClickListener(){
  1216. public void onClick(View v){
  1217. //MainActivity.playSound();
  1218. String name = username.getText().toString().trim();
  1219. String pass = password.getText().toString().trim();
  1220. //对密码进行国密SM4加密,密文存入数据库
  1221. String strKey = "0123456789abcdeffedcba9876543210";//密钥
  1222. //String strKey = "0123456789abcdef";//密钥
  1223. byte[] bKey = Encryption.hexStringToBytes(strKey);
  1224. String CPass = Encryption.deal(pass,SM4.ENCRYPT,bKey);//密码加密后的密文CPass
  1225. int remarks = 0;
  1226. Log.i("TAG","username_"+name+"_ CPassword_"+CPass);
  1227. Log.i("TAG","注册成功");
  1228. UserService uService = new UserService(RegisterActivity.this);
  1229. User user = new User();
  1230. user.setUsername(name);
  1231. user.setPassword(CPass);
  1232. uService.register(user);
  1233. Toast.makeText(RegisterActivity.this,"注册成功",Toast.LENGTH_LONG).show();
  1234. //注册成功,跳转登录界面
  1235. Intent intent = new Intent(RegisterActivity.this,LoginActivity.class);
  1236. startActivity(intent);
  1237. }
  1238. });
  1239. }
  1240. }
  1241. SharedPre.java
  1242. package com.example.android_snake;
  1243. import android.content.ContentValues;
  1244. import android.content.Context;
  1245. import android.content.SharedPreferences;
  1246. import android.database.sqlite.SQLiteDatabase;
  1247. /**
  1248. * 用户最高分数记录信息
  1249. */
  1250. public class SharedPre {
  1251. private int mostscore;
  1252. private Context context;
  1253. String FileName;
  1254. String FileNameVolume;
  1255. private boolean volumeflag;//是否选中静音
  1256. public SharedPre() {
  1257. }
  1258. public SharedPre(String usern,Context context) {
  1259. FileName = usern+Macro.Pname; //文件名:用户名加scorefile
  1260. FileNameVolume = usern+Macro.PnameFlag; //文件名:用户名加VolumeFile
  1261. this.context = context;
  1262. volumeflag = true; //默认选中
  1263. }
  1264. public void setvolumeFlag(boolean flag){
  1265. volumeflag = flag;
  1266. }
  1267. /**
  1268. * 存储最高游戏分数记录
  1269. * @param usern 用户名
  1270. * @param mscore 最高分数
  1271. */
  1272. public void save(String usern,int mscore) {
  1273. SharedPreferences sp = context.getSharedPreferences(FileName, Context.MODE_PRIVATE);
  1274. SharedPreferences.Editor editor = sp.edit();
  1275. editor.putInt("score",mscore);
  1276. editor.apply();//文件存储结束
  1277. //更新用户数据库
  1278. UserService uService = new UserService(context);
  1279. uService.updateRemarks(usern,mscore);
  1280. // //更新用户数据库
  1281. // MyDatabaseHelper dbHelper = new MyDatabaseHelper(context);
  1282. //
  1283. // SQLiteDatabase db = dbHelper.getWritableDatabase();
  1284. // /*实例化内容值*/
  1285. // ContentValues values = new ContentValues();
  1286. //
  1287. // /*在values中添加内容*/
  1288. // values.put("Remarks", mscore);
  1289. // /*修改条件*/
  1290. // String whereClause = "userName=?";
  1291. // /*修改添加参数*/
  1292. // String[] whereArgs = {usern};
  1293. // /*修改*/
  1294. // db.update("user", values, whereClause, whereArgs);
  1295. // db.close();
  1296. }
  1297. //读出并显示最高游戏分数记录
  1298. public int read(){
  1299. SharedPreferences sharedPreferences=context.getSharedPreferences(FileName,Context.MODE_PRIVATE);
  1300. mostscore=sharedPreferences.getInt("score",0);
  1301. return mostscore;
  1302. }
  1303. /**
  1304. * 存储静音开关是否选中信息
  1305. * @param flag
  1306. */
  1307. public void saveFlag(boolean flag) {
  1308. SharedPreferences sp = context.getSharedPreferences(FileNameVolume, Context.MODE_PRIVATE);
  1309. SharedPreferences.Editor editor = sp.edit();
  1310. if(flag) editor.putInt("state",1);//选中存1
  1311. else editor.putInt("state",0);
  1312. editor.apply();//文件存储结束
  1313. }
  1314. /**
  1315. * 读出静音开关状态
  1316. * @return
  1317. */
  1318. public int readVolumeFlag(){
  1319. SharedPreferences sharedPreferences=context.getSharedPreferences(FileNameVolume,Context.MODE_PRIVATE);
  1320. int state=sharedPreferences.getInt("state",1);//默认1
  1321. return state;
  1322. }
  1323. }
  1324. SoundPlay.java
  1325. package com.example.android_snake;
  1326. import android.content.Context;
  1327. import android.media.AudioManager;
  1328. import android.media.SoundPool;
  1329. import androidx.appcompat.app.AppCompatActivity;
  1330. import java.util.HashMap;
  1331. /**
  1332. * 贪吃蛇button/win/fail音效工具类
  1333. */
  1334. public class SoundPlay extends AppCompatActivity {
  1335. static SoundPool sp;//声明SoundPool的引用
  1336. static HashMap<Integer, Integer> hm;//声明HashMap来存放声音文件
  1337. static int currStaeamId;//当前正播放的streamId
  1338. public void initSoundPool() {//初始化声音池
  1339. sp = new SoundPool(4, AudioManager.STREAM_MUSIC, 0);//创建SoundPool对象
  1340. hm = new HashMap<Integer, Integer>();//创建HashMap对象
  1341. //加载声音文件,并且设置为1号 2号 3号声音放入hm中
  1342. hm.put(1, sp.load(this, R.raw.button0, 1));
  1343. hm.put(2, sp.load(this, R.raw.win, 1));
  1344. hm.put(3, sp.load(this, R.raw.fail, 1));
  1345. hm.put(4, sp.load(this, R.raw.applause, 1));
  1346. }
  1347. public void playSound(int sound, int loop) {//获取AudioManager引用
  1348. AudioManager am = (AudioManager) this.getSystemService(Context.AUDIO_SERVICE);
  1349. //获取当前音量
  1350. float streamVolumeCurrent = am.getStreamVolume(AudioManager.STREAM_MUSIC);
  1351. //获取系统最大音量
  1352. float streamVolumeMax = am.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
  1353. //计算得到播放音量
  1354. float volume = streamVolumeCurrent / streamVolumeMax;
  1355. //调用SoundPool的play方法来播放声音文件
  1356. currStaeamId = sp.play(hm.get(sound), volume, volume, 1, loop, 1.0f);
  1357. }
  1358. }
  1359. StartActivity.java
  1360. package com.example.android_snake;
  1361. import android.app.Activity;
  1362. import android.content.Intent;
  1363. import android.os.Bundle;
  1364. import android.os.Handler;
  1365. import android.view.Window;
  1366. import android.view.WindowManager;
  1367. public class StartActivity extends Activity {
  1368. private final int SPLASH_DISPLAY_LENGHT = 3000; //延迟3秒
  1369. protected void onCreate(Bundle savedInstanceState){
  1370. super.onCreate(savedInstanceState);
  1371. //隐藏标题栏以及状态栏
  1372. getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
  1373. WindowManager.LayoutParams.FLAG_FULLSCREEN);
  1374. requestWindowFeature(Window.FEATURE_NO_TITLE);
  1375. setContentView(R.layout.activity_beginning);
  1376. new Handler().postDelayed(new Runnable() {
  1377. @Override
  1378. public void run() {
  1379. Intent intent = new Intent(StartActivity.this, LoginActivity.class);
  1380. StartActivity.this.startActivity(intent);
  1381. StartActivity.this.finish();
  1382. }
  1383. }, SPLASH_DISPLAY_LENGHT);
  1384. }
  1385. // private Handler handler = new Handler() {
  1386. // @Override
  1387. // public void handleMessage(Message msg) {
  1388. // super.handleMessage(msg);
  1389. // }
  1390. // };
  1391. /**
  1392. * 跳转至选择界面
  1393. */
  1394. public void getHome(){
  1395. Intent intent = new Intent(StartActivity.this, ChooseActivity.class);
  1396. startActivity(intent);
  1397. finish();
  1398. }
  1399. }
  1400. User.java
  1401. package com.example.android_snake;
  1402. import java.io.Serializable;
  1403. public class User implements Serializable {
  1404. private int id;
  1405. private String username;
  1406. private String password;
  1407. private int remarks;
  1408. public User(){
  1409. super();
  1410. }
  1411. public User(String username,String password,int remarks){
  1412. super();
  1413. this.username = username;
  1414. this.password = password;
  1415. this.remarks = remarks;
  1416. }
  1417. public int getId(){
  1418. return id;
  1419. }
  1420. public void setId(int id) {
  1421. this.id = id;
  1422. }
  1423. public String getUsername(){
  1424. return username;
  1425. }
  1426. public void setUsername(String username) {
  1427. this.username = username;
  1428. }
  1429. public String getPassword(){
  1430. return password;
  1431. }
  1432. public void setPassword(String password) {
  1433. this.password = password;
  1434. }
  1435. public int getRemarks(){
  1436. return remarks;
  1437. }
  1438. public void setRemarks(int remarks) {
  1439. this.remarks = remarks;
  1440. }
  1441. /**
  1442. * 描述用户信息
  1443. * @return
  1444. */
  1445. public String desString(){
  1446. return "User [id="+id+",username=" + username +",password="
  1447. +password+",remarks="+remarks+"]";
  1448. }
  1449. }
  1450. UserService.java
  1451. package com.example.android_snake;
  1452. import android.content.Context;
  1453. import android.database.Cursor;
  1454. import android.database.sqlite.SQLiteDatabase;
  1455. /**
  1456. * 本类用于用户注册登录/更新数据库user表中最高分数功能的实现
  1457. */
  1458. public class UserService {
  1459. private MyDatabaseHelper dbHelper;
  1460. public UserService(Context context){
  1461. dbHelper = new MyDatabaseHelper(context);
  1462. }
  1463. public boolean login(String username,String password){
  1464. SQLiteDatabase sdb = dbHelper.getReadableDatabase();
  1465. String sql = "select * from user where username=? and password=?";
  1466. Cursor cursor = sdb.rawQuery(sql, new String[]{username,password});
  1467. if(cursor.moveToFirst()==true){
  1468. cursor.close();
  1469. return true;
  1470. }
  1471. return false;
  1472. }
  1473. public boolean register(User user){
  1474. SQLiteDatabase sdb = dbHelper.getReadableDatabase();
  1475. String sql = "insert into user(username,password,remarks) values(?,?,?)";
  1476. Object[] obj = {user.getUsername(),user.getPassword(),user.getRemarks()};
  1477. sdb.execSQL(sql,obj);
  1478. return true;
  1479. }
  1480. public void updateRemarks(String username,int remarks){
  1481. SQLiteDatabase sdb = dbHelper.getReadableDatabase();
  1482. String remarksS = String.valueOf(remarks);
  1483. String updateSql = "update user set Remarks=? where userName=?";
  1484. sdb.execSQL(updateSql, new String[]{remarksS, username});
  1485. }
  1486. }

布局文件

  1. activity_beginning.xml
  2. <?xml version="1.0" encoding="utf-8"?>
  3. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  4. xmlns:app="http://schemas.android.com/apk/res-auto"
  5. android:layout_width="match_parent"
  6. android:layout_height="match_parent"
  7. android:orientation="vertical"
  8. android:background="@drawable/cover_02">
  9. <ImageView
  10. android:id="@+id/imageView6"
  11. android:layout_width="match_parent"
  12. android:layout_height="575dp"
  13. app:srcCompat="@drawable/cover_02" />
  14. <!-- <TextView-->
  15. <!-- android:id="@+id/textView2"-->
  16. <!-- android:layout_width="match_parent"-->
  17. <!-- android:layout_height="200dp"-->
  18. <!-- android:layout_weight="1"-->
  19. <!-- android:text="Play games to please yourself!"-->
  20. <!-- android:textColor="@color/black"-->
  21. <!-- android:textSize="25dp" />-->
  22. <TextView
  23. android:id="@+id/txt_1"
  24. android:layout_width="match_parent"
  25. android:layout_height="wrap_content"
  26. android:layout_marginStart="10dp"
  27. android:layout_marginLeft="10dp"
  28. android:layout_marginTop="70dp"
  29. android:text="Game player ⭐⭐⭐小游戏"
  30. android:textSize="30sp"
  31. android:textColor="@color/white"/>
  32. </LinearLayout>
  33. Activity_finalwin.xml
  34. <?xml version="1.0" encoding="utf-8"?>
  35. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  36. xmlns:app="http://schemas.android.com/apk/res-auto"
  37. android:layout_width="match_parent"
  38. android:layout_height="match_parent">
  39. <ImageView
  40. android:id="@+id/imageView"
  41. android:layout_width="252dp"
  42. android:layout_height="445dp"
  43. android:layout_centerInParent="true"
  44. android:layout_weight="1"
  45. app:srcCompat="@drawable/finalwin" />
  46. <TextView
  47. android:id="@+id/textView"
  48. android:layout_width="wrap_content"
  49. android:layout_height="wrap_content"
  50. android:layout_weight="1"
  51. android:text="@string/finalwin"
  52. android:layout_centerHorizontal="true"
  53. android:textColor="@color/purple_500"
  54. android:textSize="22sp" />
  55. </RelativeLayout>
  56. activity_login.xml
  57. <?xml version="1.0" encoding="utf-8"?>
  58. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  59. xmlns:tools="http://schemas.android.com/tools"
  60. android:orientation="vertical"
  61. android:layout_width="match_parent"
  62. android:layout_height="match_parent">
  63. <TextView
  64. android:id="@+id/top_login"
  65. android:layout_width="match_parent"
  66. android:layout_height="180dp"
  67. android:background="@drawable/pic_top2" />
  68. <TextView
  69. android:id="@+id/login_tip"
  70. android:layout_width="match_parent"
  71. android:layout_height="wrap_content"
  72. android:layout_marginStart="10dp"
  73. android:layout_marginLeft="10dp"
  74. android:layout_marginTop="70dp"
  75. android:text="@string/welcome"
  76. android:textSize="25sp" />
  77. <EditText
  78. android:id="@+id/username_login"
  79. android:layout_width="match_parent"
  80. android:layout_height="50dp"
  81. android:layout_below="@id/top_login"
  82. android:layout_marginLeft="35dp"
  83. android:layout_marginTop="20dp"
  84. android:layout_marginRight="35dp"
  85. android:background="@drawable/input_line1"
  86. android:hint="@string/login_tip1"
  87. android:inputType="text"
  88. android:paddingStart="10dp"
  89. android:paddingEnd="10dp"
  90. android:textSize="18sp"
  91. tools:ignore="autofill" />
  92. <EditText
  93. android:id="@+id/password_login"
  94. android:layout_width="match_parent"
  95. android:layout_height="50dp"
  96. android:layout_below="@id/username_login"
  97. android:layout_marginLeft="35dp"
  98. android:layout_marginTop="10dp"
  99. android:layout_marginRight="35dp"
  100. android:background="@drawable/input_line1"
  101. android:hint="@string/login_tip2"
  102. android:inputType="textPassword"
  103. android:paddingStart="10dp"
  104. android:paddingEnd="10dp"
  105. android:textSize="18sp"
  106. tools:ignore="autofill" />
  107. <Button
  108. android:id="@+id/bt_login"
  109. android:layout_width="match_parent"
  110. android:layout_height="50dp"
  111. android:layout_below="@id/password_login"
  112. android:layout_marginLeft="35dp"
  113. android:layout_marginTop="15dp"
  114. android:layout_marginRight="35dp"
  115. android:background="@drawable/start_button"
  116. android:text="@string/login_tip3"
  117. android:textColor="@color/white" />
  118. <RadioButton
  119. android:id="@+id/rbt_login"
  120. android:layout_width="wrap_content"
  121. android:layout_height="wrap_content"
  122. android:layout_below="@id/bt_login"
  123. android:layout_marginStart="25dp"
  124. android:layout_marginLeft="25dp"
  125. android:layout_marginTop="10dp"
  126. android:checked="false"
  127. android:text="@string/login_tip5"
  128. android:textSize="14sp" />
  129. <Button
  130. android:id="@+id/bt_goRegister"
  131. android:layout_width="match_parent"
  132. android:layout_height="18dp"
  133. android:layout_below="@id/rbt_login"
  134. android:layout_marginLeft="145dp"
  135. android:layout_marginTop="19dp"
  136. android:layout_marginRight="35dp"
  137. android:background="@null"
  138. android:text="@string/login_tip6"
  139. android:textColor="@color/grey"
  140. android:textSize="14sp" />
  141. <TextView
  142. android:id="@+id/txt_loginother"
  143. android:layout_width="match_parent"
  144. android:layout_height="25dp"
  145. android:layout_below="@id/rbt_login"
  146. android:layout_centerVertical="true"
  147. android:layout_gravity="center"
  148. android:layout_marginLeft="65dp"
  149. android:layout_marginTop="145dp"
  150. android:layout_marginRight="65dp"
  151. android:gravity="center"
  152. android:text="@string/login_tip4"
  153. android:textSize="14sp" />
  154. <Button
  155. android:id="@+id/bt_wechat"
  156. android:layout_width="50dp"
  157. android:layout_height="50dp"
  158. android:layout_below="@id/txt_loginother"
  159. android:layout_marginStart="65dp"
  160. android:layout_marginTop="30dp"
  161. android:background="@drawable/logo_login4"
  162. android:layout_marginLeft="65dp" />
  163. <Button
  164. android:id="@+id/bt_QQ"
  165. android:layout_width="50dp"
  166. android:layout_height="50dp"
  167. android:layout_below="@id/txt_loginother"
  168. android:layout_marginStart="55dp"
  169. android:layout_marginLeft="55dp"
  170. android:layout_marginTop="30dp"
  171. android:layout_toEndOf="@id/bt_wechat"
  172. android:layout_toRightOf="@id/bt_wechat"
  173. android:background="@drawable/logo_login5" />
  174. <Button
  175. android:id="@+id/bt_weibo"
  176. android:layout_width="55dp"
  177. android:layout_height="55dp"
  178. android:layout_below="@id/txt_loginother"
  179. android:layout_toEndOf="@id/bt_QQ"
  180. android:layout_marginStart="55dp"
  181. android:layout_marginTop="30dp"
  182. android:background="@drawable/logo_login1"
  183. android:layout_toRightOf="@id/bt_QQ"
  184. android:layout_marginLeft="55dp" />
  185. </RelativeLayout>
  186. activity_main.xml
  187. <?xml version="1.0" encoding="utf-8"?>
  188. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  189. xmlns:tools="http://schemas.android.com/tools"
  190. android:id="@+id/main_layout"
  191. android:layout_width="match_parent"
  192. android:layout_height="match_parent"
  193. android:background="@color/white"
  194. android:orientation="vertical"
  195. tools:context="com.example.android_snake.MainActivity">
  196. <FrameLayout
  197. android:id="@+id/framelayout"
  198. android:layout_width="match_parent"
  199. android:layout_height="match_parent"
  200. android:layout_alignBottom="@id/RelativeLayout"
  201. android:layout_marginBottom="145dp"
  202. android:background="@color/pink_1">
  203. <TextView
  204. android:id="@+id/prompt"
  205. android:layout_width="wrap_content"
  206. android:layout_height="wrap_content"
  207. android:layout_gravity="center"
  208. android:text="点击按钮,开始游戏!"
  209. android:textColor="@color/red_1"
  210. android:textSize="25sp" />
  211. <TextView
  212. android:id="@+id/Score"
  213. android:layout_width="wrap_content"
  214. android:layout_height="wrap_content"
  215. android:text="当前分数"
  216. android:textColor="#000000"
  217. android:textSize="20sp" />
  218. <TextView
  219. android:id="@+id/MostScore"
  220. android:layout_width="wrap_content"
  221. android:layout_height="wrap_content"
  222. android:layout_marginLeft="200dp"
  223. android:text="@string/MOSTSCORE"
  224. android:textColor="#000000"
  225. android:textSize="20sp" />
  226. <Button
  227. android:id="@+id/Volume"
  228. android:layout_width="30dp"
  229. android:layout_height="30dp"
  230. android:layout_marginLeft="350dp"
  231. android:background="@drawable/volumeon" />
  232. <RelativeLayout
  233. android:id="@+id/addBling"
  234. android:layout_width="110dp"
  235. android:layout_height="60dp"
  236. android:layout_marginTop="70dp"
  237. />
  238. </FrameLayout>
  239. <RelativeLayout
  240. android:id="@+id/RelativeLayout"
  241. android:layout_width="match_parent"
  242. android:layout_height="wrap_content"
  243. android:layout_alignParentBottom="true">
  244. <Button
  245. android:id="@+id/isstar"
  246. android:layout_width="wrap_content"
  247. android:layout_height="wrap_content"
  248. android:layout_below="@id/Up"
  249. android:layout_centerHorizontal="true"
  250. android:background="@drawable/downbutton"
  251. android:text="@string/star" />
  252. <Button
  253. android:id="@+id/Up"
  254. android:layout_width="wrap_content"
  255. android:layout_height="wrap_content"
  256. android:layout_centerHorizontal="true"
  257. android:layout_gravity="center"
  258. android:background="@drawable/upbutton"
  259. android:text="@string/UP" />
  260. <Button
  261. android:id="@+id/Left"
  262. android:layout_width="wrap_content"
  263. android:layout_height="wrap_content"
  264. android:layout_below="@id/Up"
  265. android:layout_toStartOf="@id/Up"
  266. android:layout_toLeftOf="@id/Up"
  267. android:background="@drawable/leftbutton"
  268. android:text="@string/LEFT" />
  269. <Button
  270. android:id="@+id/Down"
  271. android:layout_width="wrap_content"
  272. android:layout_height="wrap_content"
  273. android:layout_below="@id/Left"
  274. android:layout_centerHorizontal="true"
  275. android:background="@drawable/upbutton"
  276. android:text="@string/DOWN" />
  277. <Button
  278. android:id="@+id/Right"
  279. android:layout_width="wrap_content"
  280. android:layout_height="wrap_content"
  281. android:layout_below="@id/Up"
  282. android:layout_toEndOf="@id/Up"
  283. android:layout_toRightOf="@id/Up"
  284. android:background="@drawable/rightbutton"
  285. android:text="@string/RIGHT" />
  286. </RelativeLayout>
  287. </RelativeLayout>
  288. activity_register.xml
  289. <?xml version="1.0" encoding="utf-8"?>
  290. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  291. xmlns:tools="http://schemas.android.com/tools"
  292. android:orientation="vertical"
  293. android:layout_width="match_parent"
  294. android:layout_height="match_parent">
  295. <TextView
  296. android:id="@+id/top_register"
  297. android:layout_width="match_parent"
  298. android:layout_height="180dp"
  299. android:background="@drawable/pic_top2" />
  300. <TextView
  301. android:id="@+id/register_tip"
  302. android:layout_width="match_parent"
  303. android:layout_height="wrap_content"
  304. android:layout_marginStart="10dp"
  305. android:layout_marginLeft="10dp"
  306. android:layout_marginTop="70dp"
  307. android:text="@string/welcomeregister"
  308. android:textSize="25sp" />
  309. <EditText
  310. android:id="@+id/username_register"
  311. android:layout_width="match_parent"
  312. android:layout_height="50dp"
  313. android:layout_below="@id/top_register"
  314. android:layout_marginLeft="35dp"
  315. android:layout_marginTop="20dp"
  316. android:layout_marginRight="35dp"
  317. android:background="@drawable/input_line1"
  318. android:hint="@string/login_tip1"
  319. android:inputType="text"
  320. android:paddingStart="10dp"
  321. android:paddingEnd="10dp"
  322. android:textSize="18sp"
  323. tools:ignore="autofill" />
  324. <EditText
  325. android:id="@+id/password_register"
  326. android:layout_width="match_parent"
  327. android:layout_height="50dp"
  328. android:layout_below="@id/username_register"
  329. android:layout_marginLeft="35dp"
  330. android:layout_marginTop="10dp"
  331. android:layout_marginRight="35dp"
  332. android:background="@drawable/input_line1"
  333. android:hint="@string/register_tip1"
  334. android:inputType="textPassword"
  335. android:paddingStart="10dp"
  336. android:paddingEnd="10dp"
  337. android:textSize="18sp"
  338. tools:ignore="autofill" />
  339. <Button
  340. android:id="@+id/registerButton"
  341. android:layout_width="match_parent"
  342. android:layout_height="50dp"
  343. android:layout_below="@id/password_register"
  344. android:layout_marginLeft="35dp"
  345. android:layout_marginTop="15dp"
  346. android:layout_marginRight="35dp"
  347. android:background="@drawable/start_button"
  348. android:text="@string/register_tip5"
  349. android:textColor="@color/white" />
  350. <!-- <RadioButton-->
  351. <!-- android:id="@+id/rbt_register"-->
  352. <!-- android:layout_width="wrap_content"-->
  353. <!-- android:layout_height="wrap_content"-->
  354. <!-- android:layout_below="@id/registerButton"-->
  355. <!-- android:layout_marginStart="25dp"-->
  356. <!-- android:layout_marginLeft="25dp"-->
  357. <!-- android:layout_marginTop="10dp"-->
  358. <!-- android:checked="false"-->
  359. <!-- android:text="@string/login_tip5"-->
  360. <!-- android:textSize="14sp" />-->
  361. <TextView
  362. android:id="@+id/txt_2"
  363. android:layout_width="match_parent"
  364. android:layout_height="25dp"
  365. android:layout_below="@id/registerButton"
  366. android:layout_centerVertical="true"
  367. android:layout_gravity="center"
  368. android:layout_marginLeft="65dp"
  369. android:layout_marginTop="145dp"
  370. android:layout_marginRight="65dp"
  371. android:gravity="center"
  372. android:text="@string/login_tip4"
  373. android:textSize="14sp" />
  374. <Button
  375. android:id="@+id/bt_wechat"
  376. android:layout_width="50dp"
  377. android:layout_height="50dp"
  378. android:layout_below="@id/txt_2"
  379. android:layout_marginStart="65dp"
  380. android:layout_marginLeft="65dp"
  381. android:layout_marginTop="30dp"
  382. android:background="@drawable/logo_login4" />
  383. <Button
  384. android:id="@+id/bt_QQ"
  385. android:layout_width="50dp"
  386. android:layout_height="50dp"
  387. android:layout_below="@id/txt_2"
  388. android:layout_marginStart="55dp"
  389. android:layout_marginLeft="55dp"
  390. android:layout_marginTop="30dp"
  391. android:layout_toEndOf="@id/bt_wechat"
  392. android:layout_toRightOf="@id/bt_wechat"
  393. android:background="@drawable/logo_login5" />
  394. <Button
  395. android:id="@+id/bt_weibo"
  396. android:layout_width="55dp"
  397. android:layout_height="55dp"
  398. android:layout_below="@id/txt_2"
  399. android:layout_toEndOf="@id/bt_QQ"
  400. android:layout_marginStart="55dp"
  401. android:layout_marginTop="30dp"
  402. android:background="@drawable/logo_login1"
  403. android:layout_toRightOf="@id/bt_QQ"
  404. android:layout_marginLeft="55dp" />
  405. </RelativeLayout>
  406. activity_start_view.xml
  407. <?xml version="1.0" encoding="utf-8"?>
  408. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  409. xmlns:app="http://schemas.android.com/apk/res-auto"
  410. xmlns:tools="http://schemas.android.com/tools"
  411. android:layout_width="match_parent"
  412. android:layout_height="match_parent"
  413. tools:context="com.example.android_snake.ChooseActivity"
  414. android:orientation="vertical"
  415. android:background="@color/white"
  416. >
  417. <TextView
  418. android:id="@+id/top_1"
  419. android:layout_width="match_parent"
  420. android:layout_height="180dp"
  421. android:background="@drawable/pic_top2" />
  422. <TextView
  423. android:id="@+id/txt_1"
  424. android:layout_width="match_parent"
  425. android:layout_height="wrap_content"
  426. android:layout_marginStart="10dp"
  427. android:layout_marginLeft="10dp"
  428. android:layout_marginTop="70dp"
  429. android:text="Game player\n贪吃蛇小游戏"
  430. android:textSize="40sp" />
  431. <Button
  432. android:id="@+id/star_game"
  433. android:layout_width="match_parent"
  434. android:layout_height="wrap_content"
  435. android:layout_gravity="center"
  436. android:layout_marginLeft="50dp"
  437. android:layout_marginTop="100dp"
  438. android:layout_marginRight="50dp"
  439. android:background="@drawable/start_button"
  440. android:text="@string/stargame" />
  441. <Button
  442. android:id="@+id/MostBUtton"
  443. android:layout_width="match_parent"
  444. android:layout_height="wrap_content"
  445. android:layout_marginLeft="50dp"
  446. android:layout_marginTop="10dp"
  447. android:layout_marginRight="50dp"
  448. android:background="@drawable/start_button"
  449. android:text="@string/historyscore" />
  450. <Button
  451. android:id="@+id/BackButton"
  452. android:layout_width="match_parent"
  453. android:layout_height="wrap_content"
  454. android:text="@string/back"
  455. android:layout_marginLeft="50dp"
  456. android:layout_marginRight="50dp"
  457. android:layout_marginTop="10dp"
  458. android:background="@drawable/start_button"/>
  459. </LinearLayout>

个人体会及存在的问题

本次课程设计目的在于使用java语言设计一款手机贪吃蛇小游戏,为了达到最好的用户体验效果,我学习使用Android Studio进行项目开发,在项目开发过程中,学到了很多新的知识与技能,切实体会到项目开发的完整流程,并在此过程中不断增加需求、完善功能、优化结构,从最开始的游戏逻辑到用户界面一步步进行完善与修改,从数据库连接、文件操作到apk打包等种种操作,见证自己的第一个apk诞生的全过程,获得感颇丰。

下面例举一些项目开发中遇到的问题及解决方案:

一些资源文件引用、调用错误:如引入png图片文件时文件路径不能有中文,value中的颜色 定义文件colors.xml中定义了一个格式不支持的颜色;音频文件引用时的后缀名称问题,提示编码错误,改为.text后缀类型即可正常使用

一些代码逻辑需要学习巩固:如贪吃蛇游戏中的多线程处理、Android Studio中的SQLite连接及文件操作、布局xml文件的代码编写方法、布局与构件种类、SM4国密密码算法等。

一些小功能实现需要去学习:隐藏标题栏、隐藏手机状态栏、开机动画停留3秒、各个界面之间的自动跳转、获取手机屏幕宽度、音频导入与播放、APK打包、APK属性信息设置。

一些小bug需要一个个改正:如贪吃蛇初始化时头的方向若向左,初始运动方向设置为向右便会出场阵亡;食物的图标尺寸大于运动单元,则会出现小蛇看上去吃到食物实际上却并没有到达那个坐标;小蛇的初始位置太偏不容易调整初始进入游戏的状态;由于未在AndroidManifest.xml文件中注册界面的Activity,导致界面跳转时出现软件闪退情况;游戏菜单界面的三个按钮都加音效会导致软件闪退等等……

解决各种问题的过程正是自我提高的过程,弥足珍贵。

开发过程中遇到的这样各种各样的小问题还有很多,现已难以尽数列出……

GreedySnake这个程序虽然已经尽力去完善与改进了,但仍然存在一些小问题,如游戏界面中背景音乐播放使用了MediaPlayer类,按钮音效等短音频处理使用了SoundPool,而MediaPlayer仅支持同时播放一个音频,故播放背景音乐时按钮音效并不能体现……

错误和bug不让人感觉快乐,但程序员的乐趣就在于解决一个又一个报错,修改一个又一个bug。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/菜鸟追梦旅行/article/detail/595733
推荐阅读
相关标签
  

闽ICP备14008679号