libGDX开发先绘制水面再绘制船但船不显示问题求解
问题根因
你遇到的问题核心是Water类绘制水面后,没有将共享的SpriteBatch的投影矩阵恢复为像素坐标系的状态,导致后续绘制船只时使用了错误的坐标空间:
- 绘制水面时,你调用了
batch.setProjectionMatrix(IDT),将投影矩阵设置为了标准化设备坐标(NDC),坐标范围是x/y轴均为[-1, 1],水面刚好铺满整个屏幕 - 绘制完成后你只重置了Shader为null,但没有还原投影矩阵,导致Player绘制时,原本像素级的坐标(比如1080P屏幕下船的坐标是几百上千)远大于NDC的1的上限,直接被裁剪到屏幕外,因此看不见
- 单独画船时投影矩阵是正确的像素坐标,所以可以正常显示
修复方案
修改Water类的Draw()方法,在绘制完成水面后,恢复SpriteBatch原本的投影矩阵:
public void Draw() { time += Gdx.graphics.getDeltaTime(); shaderProgram.bind(); float screenRatio = ((float)Gdx.graphics.getWidth()) / ((float)Gdx.graphics.getHeight()); shaderProgram.setUniformf("u_texCoordScale", TEXTURE_REPEATS_HORIZONTAL, TEXTURE_REPEATS_HORIZONTAL / screenRatio); shaderProgram.setUniformf("u_noise_scale", 0.1f); shaderProgram.setUniformf("u_noise_scroll_velocity", NOISE_SPEED_HORIZONTAL, NOISE_SPEED_HORIZONTAL / screenRatio); shaderProgram.setUniformf("u_distortion", 0.04f); shaderProgram.setUniformf("u_time", time); noiseTexture.bind(0); // 先保存原来的投影矩阵 Matrix4 oldProjection = batch.getProjectionMatrix().cpy(); batch.begin(); batch.setProjectionMatrix(IDT); batch.enableBlending(); batch.setShader(shaderProgram); batch.draw(waterTexture, -1f, 1f, 2f, -2f); batch.end(); batch.setShader(null); // 恢复原有的投影矩阵 batch.setProjectionMatrix(oldProjection); }
另外建议你将GameScreen中的逻辑调整为先更新逻辑再绘制,避免操作延迟一帧:
public void render(float delta) { Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); Gdx.gl.glClearColor(0.2f, 0.3f, 1.0f, 1.0f); // 先更新逻辑 player.Movement(delta); // 再按从后到前的顺序绘制 water.Draw(); player.DrawSprite(); }
多元素层级绘制原理
libGDX的2D渲染默认使用画家算法:后绘制的内容会覆盖在先绘制的内容之上,只要你保证绘制顺序是从底层到上层(水面→垃圾道具→船只),就可以实现正确的层级关系,开发时注意两个要点:
- 共享SpriteBatch时,修改了投影矩阵、混合模式、Shader等全局状态后,绘制完成必须恢复原状态,避免影响后续其他元素的绘制
- 如果不同元素的渲染状态差异较大,也可以给不同层级用独立的SpriteBatch,避免频繁修改状态影响性能
内容的提问来源于stack exchange,提问作者LancesLance
相关产品推荐
相关产品推荐

