如何从安卓图库选图并导入LibGDX纹理?游戏头像设置需求
在LibGDX安卓游戏中实现从图库选图作为头像的步骤
1. 安卓端(AndroidLauncher)配置与实现
1.1 添加权限
在AndroidManifest.xml中添加图片读取权限,兼容不同安卓版本:
<!-- Android 13+ 适配 --> <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" /> <!-- Android 12及以下 兼容 --> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" />
1.2 实现图库选择逻辑
在AndroidLauncher中使用ActivityResultContracts实现现代版图库选择,并处理权限申请:
import android.content.Intent; import android.content.pm.PackageManager; import android.net.Uri; import android.os.Build; import android.provider.MediaStore; import android.widget.Toast; import androidx.activity.result.ActivityResultLauncher; import androidx.activity.result.contract.ActivityResultContracts; import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; import com.badlogic.gdx.backends.android.AndroidApplication; import com.badlogic.gdx.backends.android.AndroidApplicationConfiguration; import java.io.IOException; import java.io.InputStream; public class AndroidLauncher extends AndroidApplication { private ActivityResultLauncher<Intent> pickImageLauncher; private MyGdxGame gameInstance; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); AndroidApplicationConfiguration config = new AndroidApplicationConfiguration(); gameInstance = new MyGdxGame(); initialize(gameInstance, config); // 初始化图片选择启动器 pickImageLauncher = registerForActivityResult( new ActivityResultContracts.StartActivityForResult(), result -> { if (result.getResultCode() == RESULT_OK && result.getData() != null) { Uri imageUri = result.getData().getData(); try { InputStream inputStream = getContentResolver().openInputStream(imageUri); gameInstance.handleSelectedImage(inputStream); } catch (IOException e) { e.printStackTrace(); } } } ); } // 供Core调用的图库启动方法 public void launchImagePicker() { // 检查权限 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.READ_MEDIA_IMAGES) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, new String[]{android.Manifest.permission.READ_MEDIA_IMAGES}, 100); return; } } else { if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, new String[]{android.Manifest.permission.READ_EXTERNAL_STORAGE}, 100); return; } } // 启动图库 Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI); intent.setType("image/*"); pickImageLauncher.launch(intent); } // 处理权限申请结果 @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == 100) { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { launchImagePicker(); } else { Toast.makeText(this, "需要读取图片权限才能设置头像", Toast.LENGTH_SHORT).show(); } } } }
2. Core模块处理图片加载与显示
在Core的游戏主类中,接收安卓端传递的输入流,加载为纹理并处理渲染:
import com.badlogic.gdx.Application; import com.badlogic.gdx.Game; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.graphics.GL20; import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.g2d.SpriteBatch; import java.io.IOException; import java.io.InputStream; public class MyGdxGame extends Game { private SpriteBatch batch; private Texture avatarTexture; @Override public void create() { batch = new SpriteBatch(); // 其他初始化逻辑 } // 接收安卓端传递的图片输入流,在GL线程加载纹理 public void handleSelectedImage(final InputStream inputStream) { Gdx.app.postRunnable(() -> { try { // 释放旧纹理,避免内存泄漏 if (avatarTexture != null) { avatarTexture.dispose(); } // 加载新纹理 avatarTexture = new Texture(inputStream); // 设置纹理过滤,优化显示效果 avatarTexture.setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear); } catch (Exception e) { e.printStackTrace(); } finally { try { inputStream.close(); } catch (IOException e) { e.printStackTrace(); } } }); } @Override public void render() { Gdx.gl.glClearColor(0, 0, 0, 1); Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); batch.begin(); // 绘制头像(示例:左上角200x200大小) if (avatarTexture != null) { batch.draw(avatarTexture, 50, Gdx.graphics.getHeight() - 250, 200, 200); } batch.end(); } @Override public void dispose() { batch.dispose(); if (avatarTexture != null) { avatarTexture.dispose(); } } }
3. 游戏内触发图库选择
在游戏的UI界面(比如设置页)中,添加按钮点击事件调用图库选择:
import com.badlogic.gdx.scenes.scene2d.ui.Button; import com.badlogic.gdx.scenes.scene2d.utils.ClickListener; import com.badlogic.gdx.Application; // 示例:设置界面的按钮点击逻辑 Button pickAvatarBtn = new Button(skin); pickAvatarBtn.addListener(new ClickListener() { @Override public void clicked(com.badlogic.gdx.scenes.scene2d.InputEvent event, float x, float y) { if (Gdx.app.getType() == Application.ApplicationType.Android) { AndroidLauncher androidLauncher = (AndroidLauncher) Gdx.app.getApplicationListener(); androidLauncher.launchImagePicker(); } } });
关键注意事项
- 内存管理:每次加载新头像时必须释放旧纹理,避免内存泄漏。
- 线程安全:LibGDX纹理必须在GL线程加载,使用
Gdx.app.postRunnable()确保操作在正确线程执行。 - 图片压缩:若用户选择大尺寸图片,可在安卓端先压缩后再传递给Core,避免内存溢出。
内容的提问来源于stack exchange,提问作者Владислав Шестернин
相关产品推荐
相关产品推荐

