Canvas绘制列表中相同GameItem时部分不显示问题求助
问题:同类型GameItem仅显示一个,其余未绘制
- 现象:战斗结果界面绘制奖励物品时,若列表存在同类型GameItem,Canvas仅绘制其中一个,其余被跳过;库存界面无此问题。
- 补充:有19秒问题演示视频。
BattleResultDialog代码
Paint fadePaint; int scrollMarginTop; int scrollPaddingTop; int frameCount; int questTextSize, completeTextSize; boolean battleWin; ArrayList<GameItem> rewards; public BattleResultDialog(boolean battleComplete, Enemy enemyObject) { super(540,1080,1080,2160); rewards = enemyObject.rewardsList; scrollMarginTop = scaling.DrawY(100); scrollPaddingTop = scaling.DrawY(100); fadePaint = new Paint(); fadePaint.setARGB(0,0,0,0); questTextSize = 0; if(MainActivity.playerData.hp > 0 && battleComplete){ battleWin = true; int count = 0; for (GameItem g: rewards) { g.updateXY(((160*count)),1080); Log.d("ITEMTYPE:",g.itemType+":: X:"+g.x+": y:"+g.y); count++; } SocketManager.myConsumableList.addAll(rewards); MainActivity.playerData.xp += SocketManager.Enemylist.get(MainActivity.playerData.currentEnemyIndex).xpReward; MainActivity.playerData.currentEnemyIndex = 0; mapSelectIcon = new MapSelectIcon(0,0,0,0,false,1,MainActivity.playerData.currentEnemyIndex); SocketManager.Enemylist.get(MainActivity.playerData.currentEnemyIndex).isDead = true; SocketManager.Enemylist.remove(enemyObject); for (Enemy e:SocketManager.Enemylist) { e.ResetMapIcons(); } MainActivity.playerData.TallyLVL(); } } public void update() { super.update(); frameCount++; if(MainActivity.playerData.justUpgradedLVL){ if(frameCount >30){ MainActivity.playerData.justUpgradedLVL = false; } } if(battleWin){ for (GameItem g:rewards) { g.update(); } } if(frameCount >30 && frameCount < 60){ questTextSize = questTextSize + 4; } if(frameCount >45 && frameCount < 75){ completeTextSize = completeTextSize + 4; } if(fadePaint.getAlpha() <= 245){ fadePaint.setAlpha(fadePaint.getAlpha()+9); }else{ fadePaint.setAlpha(255); } } public void draw(Canvas canvas) { canvas.drawBitmap(Globals.SplashBG,0,0,fadePaint); //zindex 0 canvas.drawText("BATTLE", super.rect.left + (super.rect.width() / 2), super.rect.top + scaling.DrawY(100) + scrollPaddingTop + scrollMarginTop, TextGen.getFont(android.R.color.black, questTextSize, 0, 6, R.font.grobold,255)); canvas.drawText("BATTLE", super.rect.left + (super.rect.width() / 2), super.rect.top + scaling.DrawY(100) + scrollPaddingTop + scrollMarginTop, TextGen.getFont(android.R.color.white, questTextSize, 0, 0, R.font.grobold,255)); canvas.drawText("RESULTS", super.rect.left + (super.rect.width() / 2), super.rect.top + scaling.DrawY(300) + scrollPaddingTop + scrollMarginTop, TextGen.getFont(android.R.color.black, completeTextSize, 0, 6, R.font.grobold,255)); canvas.drawText("RESULTS", super.rect.left + (super.rect.width() / 2), super.rect.top + scaling.DrawY(300) + scrollPaddingTop + scrollMarginTop, TextGen.getFont(android.R.color.white, completeTextSize, 0, 0, R.font.grobold,255)); if(battleWin){ canvas.drawText("YALL WON", super.rect.left + (super.rect.width() / 2), super.rect.top + scaling.DrawY(700) + scrollPaddingTop + scrollMarginTop, TextGen.getFont(android.R.color.black, completeTextSize, 0, 6, R.font.grobold,255)); canvas.drawText("YALL WON", super.rect.left + (super.rect.width() / 2), super.rect.top + scaling.DrawY(700) + scrollPaddingTop + scrollMarginTop, TextGen.getFont(android.R.color.white, completeTextSize, 0, 0, R.font.grobold,255)); //Show the reward Items canvas.drawText("numRewards"+rewards.size(), super.rect.centerX(), super.rect.top + scaling.DrawY(1400), TextGen.getFont(android.R.color.black, 40, 0, 6, R.font.grobold,255)); canvas.drawText("numRewards"+rewards.size(), super.rect.centerX(), super.rect.top + scaling.DrawY(1400), TextGen.getFont(android.R.color.white, 40, 0, 0, R.font.grobold,255)); for (GameItem g:rewards) { g.draw(canvas); } }else{ canvas.drawText("YALL DIED", super.rect.left + (super.rect.width() / 2), super.rect.top + scaling.DrawY(700) + scrollPaddingTop + scrollMarginTop, TextGen.getFont(android.R.color.black, completeTextSize, 0, 6, R.font.grobold,255)); canvas.drawText("YALL DIED", super.rect.left + (super.rect.width() / 2), super.rect.top + scaling.DrawY(700) + scrollPaddingTop + scrollMarginTop, TextGen.getFont(android.R.color.white, completeTextSize, 0, 0, R.font.grobold,255)); } if(MainActivity.playerData.justUpgradedLVL){ //run an level up animation } } public void onTouchEvent(MotionEvent e){ float posX = e.getX(); float posY = e.getY(); switch (e.getActionMasked()) { case MotionEvent.ACTION_UP: { if (posX >= super.rect.left && posX <= super.rect.right && posY >= super.rect.top && posY <= super.rect.bottom) { if(battleWin){ MainActivity.SaveDataConsumableList(Globals.context); MainActivity.SaveData(Globals.context); MainActivity.GLOBALS.GSM = new GameStateManager(0); //Scanner }else{ MainActivity.SaveDataConsumableList(Globals.context); MainActivity.SaveData(Globals.context); MainActivity.GLOBALS.GSM = new GameStateManager(3); //Character Screen } return; } } break; case MotionEvent.ACTION_DOWN: { } break; } }
Logcat输出
ITEMTYPE: 4:: X:-80: y:1000 ITEMTYPE: 2:: X:80: y:1000 ITEMTYPE: 4:: X:240: y:1000 ITEMTYPE: 3:: X:400: y:1000 ITEMTYPE: 4:: X:560: y:1000
问题原因排查
- 坐标适配错误:当前GameItem的x、y为固定屏幕坐标,但Dialog的显示区域从
super.rect.left=540、super.rect.top=1080开始,大部分物品的x(-80、80、240)小于540,y(1000)小于1080,均处于Dialog可视区域外,仅少数物品可能部分/完全在区域内,被误认为同类型只显示一个。 - 实例重复风险:若Enemy的
rewardsList中添加的是同一GameItem实例多次,循环更新坐标时会覆盖之前的位置,最终仅显示最后一次设置的坐标对应的物品。 - 共享资源冲突:若GameItem的
draw方法使用静态Bitmap/Paint等资源,同类型物品绘制时会互相覆盖。
解决方案
1. 修正坐标计算,适配Dialog区域
修改构造函数中GameItem的坐标设置逻辑,基于Dialog的位置计算物品坐标:
// 构造函数中替换原坐标更新代码 int startX = super.rect.left + scaling.DrawX(40); // 左侧留边,避免贴Dialog边缘 int startY = super.rect.top + scaling.DrawY(1500); // 与奖励统计文本对齐,确保在Dialog内 int count = 0; for (GameItem g: rewards) { g.updateXY(startX + (160*count), startY); Log.d("ITEMTYPE:",g.itemType+":: X:"+g.x+": y:"+g.y); count++; }
2. 确保GameItem为独立实例
若Enemy的rewardsList存在重复实例,创建独立拷贝:
// 替换原rewards赋值逻辑 rewards = new ArrayList<>(); for (GameItem original : enemyObject.rewardsList) { // 根据GameItem的属性编写拷贝逻辑,示例: GameItem copy = new GameItem(); copy.itemType = original.itemType; copy.x = original.x; copy.y = original.y; // 复制其他必要属性 rewards.add(copy); } // 再执行坐标更新逻辑
3. 检查GameItem的draw方法
确保draw方法使用实例级资源,避免静态共享:
// GameItem类的draw方法示例 public void draw(Canvas canvas) { Paint itemPaint = new Paint(); itemPaint.setAntiAlias(true); // 使用当前实例持有的Bitmap,而非静态Bitmap canvas.drawBitmap(this.itemBitmap, this.x, this.y, itemPaint); }
内容的提问来源于stack exchange,提问作者user4655559
相关产品推荐
相关产品推荐

