• 恶搞好友?十五分钟学会编写这款原创安卓小游戏


     

     ---------纯原创,完整的源代码-->落坨翔子安卓小游戏Androidstudio源代码资源-CSDN文库

    c44c1c8f40d84f46b689711548b5b35c.png

     资源包含Java代码文件以及相关配置文件

    想整蛊你的好友吗?,想让你讨厌的人吃xiang吗?这款小游戏值得一试!

    一、功能简介

     《落坨翔子》(Poop Dodger)是一款基于安卓平台的简单避障类游戏,玩家通过控制小人左右移动,避开不断下落的障碍物,尽可能地躲避障碍物并保持存活时间的长度。游戏提供了多个游戏模式可供选择,难度逐级增加。游戏中实时显示得分,并在游戏结束后展示最终得分。

    二、需求分析

    游戏界面和控制:

    游戏界面应包含小球、障碍物、得分显示等元素,并提供游戏开始和结束的交互按钮。

    玩家可以自定义小球外观,将其设置为好友的照片,增加个性化和趣味性。

    玩家通过触摸屏幕左右区域来控制小球的左右移动。

    障碍物生成和移动:

    障碍物以一定的速度从屏幕顶部向下移动,玩家需要避开障碍物。

    障碍物的外观为一坨大便形象,增加游戏的趣味性。

    障碍物应以不同的大小呈现,增加游戏的难度和多样性。

    碰撞检测和游戏结束:

    游戏应实时检测小球与障碍物的碰撞,若发生碰撞则游戏结束。

    游戏结束后应显示最终得分,并提供重新开始游戏的选项。

    得分计算和显示:

    根据存活时间计算得分,得分应以秒为单位计算并实时显示在游戏界面上。

    游戏界面应提供清晰的得分显示和计时器。

    三、详细设计

    MainActivity:

    - 游戏开始按钮:通过点击按钮,弹出对话框,让玩家选择游戏模式。

     - 游戏模式选择:根据玩家选择的游戏模式,设置障碍物的下落速度,并启动游戏。

    部分相关代码:

    1. public void startGame(View view) {
    2.     AlertDialog.Builder builder = new AlertDialog.Builder(this);
    3.     builder.setTitle("选择游戏模式")
    4.             .setItems(new CharSequence[]{"简单", "一般", "困难", "地狱"}, new DialogInterface.OnClickListener() {
    5.                 @Override
    6.                 public void onClick(DialogInterface dialog, int which) {
    7.                     int obstacleSpeed;
    8.                     switch (which) {
    9.                         case 0: // 简单
    10.                             obstacleSpeed = 20;
    11.                             break;
    12.                         case 1: // 一般
    13.                             obstacleSpeed = 30;
    14.                             break;
    15.                         case 2: // 困难
    16.                             obstacleSpeed = 40;
    17.                             break;
    18.                         case 3: // 地狱
    19.                             obstacleSpeed = 50;
    20.                             break;
    21.                         default:
    22.                             obstacleSpeed = 20;
    23.                             break;
    24.                     }
    25.                     Intent intent = new Intent(MainActivity.this, GameActivity.class);
    26.                     intent.putExtra("obstacleSpeed", obstacleSpeed);
    27.                     startActivity(intent);
    28.                 }
    29.             })
    30.             .setCancelable(true)
    31.             .show();
    32. }

    6246112292894787af27a5ad965e8be7.png

     开始界面 

    cee7aa56693d4e9ea88897c295a34bd4.png

     模式选择界面

     GameActivity:

    - 初始化界面:设置游戏界面,包括游戏布局、小球视图、得分显示等。

    - 小球移动:通过监听触摸事件,根据玩家触摸屏幕的位置,控制小球的左右移动。

    - 障碍物生成:使用定时器与矢量图,在随机位置生成障碍物,并将其加入游戏界面。 - 得分计算:根据存活时间计算得分,并实时更新得分显示。

    - 碰撞检测:在游戏进行过程中,实时检测小球与障碍物的碰撞情况,若发生碰撞则游戏结束。

    - 游戏结束:停止障碍物生成,清空游戏界面,并计算存活时间,传递给结果页面进行显示。

    部分相关代码:

    1. private void resetGame() {
    2. if (obstacleTimer != null) {
    3. obstacleTimer.cancel();
    4. obstacleTimer.purge();
    5. }
    6. score = 0;
    7. }
    8. @Override
    9. protected void onRestart() {
    10. super.onRestart();
    11. // 重置得分为初始值
    12. score = 0;
    13. }
    14. private void generateObstacle() {
    15. if (gameLayout != null) {
    16. int x = random.nextInt(getScreenWidth());
    17. // 设置障碍物大小
    18. ObstacleView obstacleView = new ObstacleView(this, x, obstacleSize, handler,obstacleSpeed);
    19. // ...
    20. FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
    21. gameLayout.post(new Runnable() {
    22. @Override
    23. public void run() {
    24. gameLayout.addView(obstacleView, layoutParams);
    25. }
    26. });
    27. }
    28. }
    29. public void increaseScore() {
    30. score++;
    31. handler.post(new Runnable() {
    32. @Override
    33. public void run() {
    34. scoreTextView.setText("得分:" + score);
    35. }
    36. });
    37. }
    38. public void removeObstacleView(final ObstacleView obstacleView) {
    39. if (obstacleView != null) {
    40. obstacleView.post(new Runnable() {
    41. @Override
    42. public void run() {
    43. ViewGroup parent = (ViewGroup) obstacleView.getParent();
    44. if (parent != null) {
    45. parent.removeView(obstacleView);
    46. }
    47. }
    48. });
    49. }
    50. }
    51. public BallView getBallView() {
    52. return ballView;
    53. }
    54. public void endGame() {
    55. if (obstacleTimer != null) {
    56. obstacleTimer.cancel();
    57. obstacleTimer.purge();
    58. }
    59. new Handler().post(new Runnable() {
    60. @Override
    61. public void run() {
    62. gameLayout.removeAllViews();
    63. }
    64. })
    65. long survivalTime = System.currentTimeMillis() - startTimeMillis;
    66. int seconds = (int) (survivalTime / 1000);
    67. Intent intent = new Intent(this, ResultActivity.class);
    68. intent.putExtra("score", seconds);
    69. intent.putExtra("mode", obstacleSpeed);
    70. startActivity(intent);
    71. finish();
    72. }
    73. @Override
    74. protected void onDestroy() {
    75. super.onDestroy();
    76. if (mediaPlayer != null) {
    77. mediaPlayer.stop();
    78. mediaPlayer.release();
    79. mediaPlayer = null;
    80. }
    81. if (obstacleTimer != null) {
    82. obstacleTimer.cancel();
    83. obstacleTimer.purge();
    84. }
    85. gameLayout.removeAllViews();
    86. }
    87. private int getScreenWidth() {
    88. return getResources().getDisplayMetrics().widthPixels;
    89. }
    90. }

    b239d08d5fa24b7ea8eaf5ec7e7cbda9.png

     游戏界面(一般模式)

    BallView:

    - 小球视图:绘制小球的位置和图像,并处理小球的移动操作。

    - 小球移动:根据玩家触摸屏幕的位置,实现小球的左右移动。

    - 重置位置:在游戏重新开始时,将小球的位置重置为初始位置。

    - 获取小球位置:提供方法获取小球的当前位置。

    部分相关代码:

    1. public class BallView extends View {
    2. private int screenWidth;
    3. private float ballX;
    4. private float ballY;
    5. private int radius;
    6. private Drawable ballDrawable;
    7. public BallView(Context context) {
    8. super(context);
    9. init();
    10. }
    11. public BallView(Context context, AttributeSet attrs) {
    12. super(context, attrs);
    13. init();
    14. }
    15. public BallView(Context context, AttributeSet attrs, int defStyleAttr) {
    16. super(context, attrs, defStyleAttr);
    17. init();
    18. }
    19. private void init() {
    20. ballX = 0;
    21. ballY = 0;
    22. radius = 75;
    23. ballDrawable = getResources().getDrawable(R.drawable.wzk);
    24. }
    25. @Override
    26. protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    27. super.onSizeChanged(w, h, oldw, oldh);
    28. ballX = (w - radius) / 2; // 将小球水平位置设置在屏幕中央
    29. ballY = h - 2*radius; // 将小球位置设置在屏幕底部
    30. }
    31. @Override
    32. protected void onDraw(Canvas canvas) {
    33. super.onDraw(canvas);
    34. ballDrawable.setBounds((int) ballX, (int) ballY, (int) (ballX + radius *2), (int) (ballY + radius * 2));
    35. ballDrawable.draw(canvas);
    36. }
    37. public void setScreenWidth(int width) {
    38. this.screenWidth = width;
    39. }
    40. public void moveLeft() {
    41. ballX -= 10;
    42. if (ballX < 0) {
    43. ballX = 0;
    44. }
    45. invalidate();
    46. }
    47. public void moveRight() {
    48. ballX += 10;
    49. if (ballX > screenWidth - radius * 2) {
    50. ballX = screenWidth - radius * 2;
    51. }
    52. invalidate();
    53. }
    54. public void resetPosition() {
    55. ballX = (screenWidth - radius) / 2;
    56. ballY = getHeight() - 2 * radius;
    57. invalidate();
    58. }
    59. public float getBallX() {
    60. return ballX;
    61. }
    62. public float getBallY() {
    63. return ballY;
    64. }
    65. }

     ObstacleView:

    - 障碍物视图:绘制障碍物的位置和图像,并处理障碍物的下落和碰撞检测。

    - 障碍物下落:随着时间的推移,障碍物以一定的速度向下移动。

    - 碰撞检测:检测障碍物与小球的碰撞情况,若发生碰撞则触发游戏结束。

    部分相关代码:

    1. public ObstacleView(Context context, int x, int obstacleSize, Handler handler, int obstacleSpeed) {
    2. super(context);
    3. this.x = x;
    4. this.obstacleSize = obstacleSize; // 设置障碍物大小
    5. this.handler = handler;
    6. this.obstacleSpeed = obstacleSpeed; // 设置障碍物下落速度
    7. // 加载 SVG 文件
    8. try {
    9. obstacleSvg = SVG.getFromResource(context, R.raw.shi);
    10. if (obstacleSvg != null) {
    11. obstaclePicture = obstacleSvg.renderToPicture();
    12. calculateObstacleSize();
    13. } else {
    14. // 处理SVG图像加载失败的情况
    15. // 可以打印日志或采取其他错误处理措施
    16. }
    17. } catch (SVGParseException e) {
    18. e.printStackTrace();
    19. }
    20. // 添加视图树监听器
    21. getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
    22. @Override
    23. public void onGlobalLayout() {
    24. getViewTreeObserver().removeOnGlobalLayoutListener(this);
    25. startAnimation();
    26. }
    27. });
    28. }
    29. private void calculateObstacleSize() {
    30. obstacleWidth = obstacleSize;
    31. obstacleHeight = obstacleSize;
    32. }
    33. private boolean checkCollision(BallView ballView) {
    34. float ballX = ballView.getBallX();
    35. float ballY = ballView.getBallY();
    36. float ballRadius =60;
    37. float obstacleCenterX = x;
    38. float obstacleCenterY = y + obstacleHeight / 2;
    39. float obstacleHalfWidth = obstacleWidth / 2;
    40. float obstacleHalfHeight = obstacleHeight / 2;
    41. float dx = Math.abs(ballX - obstacleCenterX);
    42. float dy = Math.abs(ballY - obstacleCenterY);
    43. if (dx > obstacleHalfWidth + ballRadius || dy > obstacleHalfHeight + ballRadius) {
    44. return false;
    45. }
    46. if (dx <= obstacleHalfWidth || dy <= obstacleHalfHeight) {
    47. return true;
    48. }
    49. float cornerDistanceSq = (dx - obstacleHalfWidth) * (dx - obstacleHalfWidth)
    50. + (dy - obstacleHalfHeight) * (dy - obstacleHalfHeight);
    51. return cornerDistanceSq <= ballRadius * ballRadius;
    52. }
    53. private void startAnimation() {
    54. handler.post(new Runnable() {
    55. @Override
    56. public void run() {
    57. invalidate();
    58. }
    59. });
    60. }
    61. @SuppressLint("DrawAllocation")
    62. @Override
    63. protected void onDraw(Canvas canvas) {
    64. super.onDraw(canvas);
    65. y += obstacleSpeed;
    66. // 绘制 SVG 图形
    67. if (obstaclePicture != null) {
    68. canvas.save();
    69. canvas.translate(x - obstacleWidth / 2, y);
    70. float scale = 0.1f;
    71. scale= (float) (scale*obstacleSpeed*0.05);// 设置缩放因子
    72. canvas.scale(scale, scale); // 缩放障碍物图像的大小
    73. canvas.drawPicture(obstaclePicture);
    74. canvas.restore();
    75. }
    76. if (y > getHeight()) {
    77. // 当障碍物移动到屏幕底部时,执行相应的操作
    78. ((GameActivity) getContext()).increaseScore();
    79. } else {
    80. BallView ballView = ((GameActivity) getContext()).getBallView();
    81. if (((x-ballView.getBallX() ) ==0 && Math.abs(y - ballView.getBallY())
    82. ((GameActivity) getContext()).endGame();
    83. }
    84. startAnimation();
    85. }
    86. }
    87. }

     ResultActivity:

    -获取得分数据:通过 getIntent() 方法获取上一个活动传递的得分数据。

    -显示得分:将得分显示在界面上的 scoreTextView TextView 中。

    部分相关代码:

    1. public class ResultActivity extends AppCompatActivity {
    2. @Override
    3. protected void onCreate(Bundle savedInstanceState) {
    4. super.onCreate(savedInstanceState);
    5. setContentView(R.layout.activity_result);
    6. setTheme(androidx.appcompat.R.style.Theme_AppCompat);
    7. Intent intent = getIntent();
    8. int seconds = intent.getIntExtra("score", 0);
    9. TextView scoreTextView = findViewById(R.id.scoreTextView);
    10. scoreTextView.setText("得分:" + seconds );
    11. }
    12. }

    f2b26956fdd14d58ad3fa9dca4e11b02.png

    游戏结束界面

    四、总结

    《落坨翔子》(Poop Dodger)是一款基于安卓平台的避障类游戏,具有个性化和趣味化的特点。玩家可以将小球的外观自定义为好友的照片,增加游戏的个性化和趣味性。通过控制小球左右移动,玩家需要躲避不断下落的障碍物,尽可能延长存活时间并获得高分。游戏提供多个游戏模式,难度逐级增加,增加了游戏的挑战性和持久性。通过实时得分显示和游戏结束后的最终得分展示,玩家能够实时了解自己的游戏表现,并进行比较和挑战。《落坨翔子》(Poop Dodger)具备清晰明了的界面设计和易于上手的操作方式,适合各个年龄段的玩家进行休闲娱乐和挑战。   

  • 相关阅读:
    Seata源码研读#01-详解配置管理机制
    【抽样技术】CH2 简单随机抽样补充——比率估计与回归估计
    第2 章 战略管理
    怎么开启22端口访问权限,让别的机器通过ssh或者向日葵等远程控制工具链接
    一个类在什么时候会被加载
    快速幂:acwing 875. 快速幂
    如何检测Windows服务停止后自动启动?自动运行.bat批处理文件?
    Windows CSC服务特权提升漏洞(CVE-2024-26229)
    图 - 06 关键路径
    服务器三种虚拟化技术
  • 原文地址:https://blog.csdn.net/wzkwzk1/article/details/133178550