<think>
这是一个Android打地鼠游戏的项目代码,主要包含一个Activity(playmouse.java)和布局文件(activity_main.xml)以及样式文件(styles.xml)的代码。下面我将详细解释代码,并给出实现步骤。
### 1. 项目结构
- **playmouse.java**:主Activity,包含游戏逻辑。
- **activity_main.xml**:布局文件,定义游戏界面。
- **styles.xml**:样式文件,用于设置无标题栏。
### 2. 代码解释
#### playmouse.java
```java
package com.example.playmouse;
import android.content.pm.ActivityInfo;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import java.util.Random;
public class playmouse extends AppCompatActivity {
private int i = 0; // 记录打到的地鼠个数
private ImageView mouse; // 地鼠ImageView
private TextView info1; // 用于查看洞穴坐标的TextView(调试用)
private Handler handler; // 用于处理消息的Handler
// 地鼠出现的12个位置的坐标数组
public int[][] position = new int[][]{
{277, 200}, {535, 200}, {832, 200},
{1067,200}, {1328, 200}, {285, 360},
{645, 360}, {1014,360}, {1348, 360},
{319, 600}, {764, 600}, {1229,600}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 设置全屏
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
// 设置横屏
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
// 绑定控件
mouse = (ImageView) findViewById(R.id.imageView1);
info1 = findViewById(R.id.info);
// 获取洞穴位置(调试用,通过触摸屏幕打印坐标)
info1.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
float x = event.getRawX();
float y = event.getRawY();
Log.i("坐标", "x:" + x + ", y:" + y);
break;
default:
break;
}
return false;
}
});
// 创建Handler,用于处理地鼠位置更新的消息
handler = new Handler() {
@Override
public void handleMessage(@NonNull Message msg) {
if (msg.what == 0x101) {
int index = msg.arg1; // 获取位置索引
// 设置地鼠的位置
mouse.setX(position[index][0]);
mouse.setY(position[index][1]);
mouse.setVisibility(View.VISIBLE); // 显示地鼠
}
super.handleMessage(msg);
}
};
// 创建一个线程,用于随机生成地鼠位置
Thread t = new Thread(new Runnable() {
@Override
public void run() {
int index = 0;
while (!Thread.currentThread().isInterrupted()) {
// 随机生成一个位置索引
index = new Random().nextInt(position.length);
Message m = handler.obtainMessage();
m.what = 0x101; // 消息标识
m.arg1 = index; // 传递索引
handler.sendMessage(m); // 发送消息
try {
// 随机休眠500-1000毫秒
Thread.sleep(new Random().nextInt(500) + 500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
t.start(); // 启动线程
// 设置地鼠的触摸事件
mouse.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
v.setVisibility(View.INVISIBLE); // 点击后隐藏地鼠
i++; // 计数增加
Toast.makeText(playmouse.this, "打到[ " + i + " ]只地鼠!", Toast.LENGTH_SHORT).show();
return false;
}
});
}
}
```
#### activity_main.xml
```xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/fl"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/background" > <!-- 设置背景图片 -->
<!-- 地鼠ImageView,初始位置不重要,因为代码中会动态设置 -->
<ImageView
android:id="@+id/imageView1"
android:layout_width="72dp"
android:layout_height="72dp"
android:src="@drawable/mouse1" />
<!-- 用于调试的TextView,覆盖全屏,用于获取坐标 -->
<TextView
android:id="@+id/info"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
</FrameLayout>
```
#### styles.xml
```xml
<resources>
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
</resources>
```
### 3. 实现步骤
1. **创建Android项目**:使用Android Studio创建一个新项目,选择Empty Activity。
2. **准备资源**:将背景图片(background.png)和地鼠图片(mouse1.png)放入res/drawable目录。
3. **修改布局文件**:创建activity_main.xml,使用FrameLayout,包含一个ImageView(地鼠)和一个TextView(用于调试坐标)。
4. **修改样式**:在styles.xml中设置无标题栏(NoActionBar)。
5. **编写Activity代码**:在MainActivity(这里重命名为playmouse)中编写游戏逻辑。
6. **运行测试**:在模拟器或真机上运行。
### 4. 关键点说明
- **全屏和横屏设置**:在onCreate中设置全屏和横屏模式。
- **坐标获取**:通过TextView的触摸事件获取坐标,用于确定地鼠位置(调试用)。
- **Handler机制**:用于在子线程中更新UI,子线程随机选择位置,通过Handler发送消息给主线程更新地鼠位置。
- **地鼠触摸事件**:点击地鼠后,地鼠消失,并显示打到的地鼠数量。
### 5. 注意事项
- 坐标数组`position`中的坐标是根据具体屏幕尺寸调试得到的,不同设备可能需要调整。
- 调试用的TextView在最终版本中可以隐藏或移除。
- 地鼠图片的大小(72dp)可能需要根据实际效果调整。
### 6. 相关资源
- 背景图片(background.png):需要一张背景图,例如有多个洞穴的图片。
- 地鼠图片(mouse1.png):地鼠的图片。
### 7. 完整项目代码获取
上述代码已经给出,但需要结合资源文件。如果需要完整项目,请按照上述步骤创建,并添加资源图片。
### 相关问题
§§相关问题§§:
1. 如何在Android中实现全屏显示?
2. Handler在Android中的作用是什么?它是如何工作的?
3. 如何获取触摸事件的坐标?
4. 在Android中如何设置横屏模式?
</think>### 打地鼠游戏实现详解与手把手教学
这是一个基于Android平台的打地鼠游戏实现。下面我将详细解释代码,并提供完整的实现步骤:
#### 核心实现原理
1. **全屏横屏显示**:设置全屏和横屏模式
2. **随机位置生成**:使用线程随机选择洞穴位置
3. **Handler消息机制**:用于更新UI线程的地鼠位置
4. **触摸事件处理**:检测用户点击地鼠的动作
### 完整实现步骤(手把手教学)
#### 步骤1:创建Android项目
1. 在Android Studio中创建新项目
2. 选择"Empty Activity"模板
3. 设置包名为`com.example.playmouse`
#### 步骤2:准备资源文件
1. 在`res/drawable`文件夹中添加:
- `background.png`(游戏背景图)
- `mouse1.png`(地鼠图片)
2. 在`res/layout`中创建`activity_main.xml`
```xml
<!-- res/layout/activity_main.xml -->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/fl"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/background">
<ImageView
android:id="@+id/imageView1"
android:layout_width="72dp"
android:layout_height="72dp"
android:src="@drawable/mouse1"/>
<TextView
android:id="@+id/info"
android:layout_width="fill_parent"
android:layout_height="fill_parent"/>
</FrameLayout>
```
#### 步骤3:修改样式文件
```xml
<!-- res/values/styles.xml -->
<resources>
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
</resources>
```
#### 步骤4:实现主游戏逻辑
```java
// src/main/java/com/example/playmouse/PlayMouseActivity.java
package com.example.playmouse;
import android.content.pm.ActivityInfo;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import java.util.Random;
public class PlayMouseActivity extends AppCompatActivity {
private int score = 0; // 分数计数器
private ImageView mouse; // 地鼠ImageView
private Handler handler; // 消息处理器
// 地鼠位置坐标数组(12个位置)
private final int[][] position = {
{277, 200}, {535, 200}, {832, 200},
{1067,200}, {1328, 200}, {285, 360},
{645, 360}, {1014,360}, {1348, 360},
{319, 600}, {764, 600}, {1229,600}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 设置全屏显示
getWindow().setFlags(
WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN
);
// 设置横屏模式
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
// 绑定UI元素
mouse = findViewById(R.id.imageView1);
TextView info = findViewById(R.id.info);
// 调试用:获取屏幕坐标
info.setOnTouchListener((v, event) -> {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
float x = event.getRawX();
float y = event.getRawY();
Log.i("坐标", "X: " + x + ", Y: " + y);
}
return false;
});
// 初始化Handler
handler = new Handler(getMainLooper()) {
@Override
public void handleMessage(Message msg) {
if (msg.what == 0x101) {
int index = msg.arg1;
mouse.setX(position[index][0]);
mouse.setY(position[index][1]);
mouse.setVisibility(View.VISIBLE);
}
}
};
// 启动地鼠生成线程
new Thread(() -> {
while (!Thread.interrupted()) {
int index = new Random().nextInt(position.length);
Message msg = handler.obtainMessage();
msg.what = 0x101;
msg.arg1 = index;
handler.sendMessage(msg);
try {
Thread.sleep(new Random().nextInt(500) + 500);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}).start();
// 设置地鼠点击事件
mouse.setOnTouchListener((v, event) -> {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
v.setVisibility(View.INVISIBLE);
score++;
Toast.makeText(PlayMouseActivity.this,
"打到[" + score + "]只地鼠!",
Toast.LENGTH_SHORT).show();
}
return true;
});
}
}
```
#### 步骤5:修改AndroidManifest.xml
```xml
<!-- AndroidManifest.xml -->
<application
android:theme="@style/AppTheme">
<activity
android:name=".PlayMouseActivity"
android:screenOrientation="landscape">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
```
### 代码详细解释
1. **初始化设置**:
- 全屏显示:`FLAG_FULLSCREEN`
- 横屏模式:`SCREEN_ORIENTATION_LANDSCAPE`
- 无标题栏:`NoActionBar`主题
2. **坐标系统**:
- `position`数组存储12个洞穴的(x,y)坐标
- 使用`getRawX()`和`getRawY()`获取绝对坐标
3. **Handler消息机制**:
- 子线程生成随机位置索引(0-11)
- 发送消息`what=0x101`给主线程
- 主线程更新地鼠位置
4. **地鼠生成逻辑**:
- 随机休眠500-1000毫秒
- 使用`setX()`和`setY()`设置位置
- `setVisibility(View.VISIBLE)`显示地鼠
5. **点击事件处理**:
- 点击时设置地鼠不可见
- 分数计数器+1
- 显示Toast提示
### 优化建议
1. **游戏难度控制**:
```java
// 动态调整出现速度
int speed = 1000 - (score * 10);
if (speed < 200) speed = 200;
Thread.sleep(speed);
```
2. **添加游戏计时**:
```java
// 60秒倒计时
new CountDownTimer(60000, 1000) {
public void onTick(long millisUntilFinished) {
timerText.setText("时间: " + millisUntilFinished/1000);
}
public void onFinish() {
Toast.makeText(GameActivity.this, "游戏结束! 分数: " + score,
Toast.LENGTH_LONG).show();
}
}.start();
```
3. **添加音效**:
```java
// 点击时播放音效
MediaPlayer.create(this, R.raw.hit_sound).start();
```
### 常见问题解决
1. **坐标不准问题**:
- 不同设备分辨率不同
- 解决方案:使用相对坐标
```java
// 获取屏幕尺寸
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
int screenWidth = metrics.widthPixels;
int screenHeight = metrics.heightPixels;
// 计算相对位置
position[0][0] = (int)(screenWidth * 0.2);
position[0][1] = (int)(screenHeight * 0.15);
```
2. **内存泄漏问题**:
- 在`onDestroy()`中停止线程
```java
@Override
protected void onDestroy() {
handler.removeCallbacksAndMessages(null);
super.onDestroy();
}
```
3. **点击响应问题**:
- 确保地鼠图片有透明背景
- 使用`setOnTouchListener`替代`setOnClickListener`
###