MonoGame开发问题:已实现移动方法的可推动方块碰撞后无法移动如何解决
问题根因
- 第一个核心问题:
Block类的Move方法仅更新了私有position字段,没有同步更新对外用于碰撞检测、绘制的公共Rectangle属性,所以逻辑上的移动不会体现在画面和碰撞逻辑里,自然看不到方块动。 - 第二个问题:工厂类生成可推动方块时,没有修改默认的
IsSolid=true属性,玩家碰撞可推动方块时会触发player.RestorePosition()回弹,同时原有碰撞逻辑顺序有问题,推动逻辑执行后马上触发固体回弹,等于操作被抵消。 - 第三个问题:第一关初始的方块列表里没有添加可推动方块,可推动方块仅在通关第一扇门后的第二关才生成,你如果在第一关测试按空格自然没有反应。
- 第四个问题:当前
i2的计数逻辑仅支持推一次方块,无法实现第一个右移、第二个左移的需求,且直接用IsKeyDown判断会导致按住空格一帧触发多次移动。
修复步骤
1. 修正Block类的移动逻辑
修改Block.cs里的Move方法,同步更新公共Rectangle属性:
public void Move(float dx, float dy) { position.X += dx; position.Y += dy; // 同步更新用于碰撞、绘制的Rectangle Rectangle = new Rectangle((int)position.X, (int)position.Y, Rectangle.Width, Rectangle.Height); }
2. 修正可推动方块的属性配置
修改blockfactory.cs里的CreatePushableBlock方法,关闭固体属性避免玩家碰撞回弹:
internal static Block CreatePushableBlock(int x, int y) { var block = new Block(x, y, 40, 40, Color.Orange); block.IsPushable = true; block.IsSolid = false; // 新增这行,可推动方块不要触发玩家回弹 return block; }
3. 调整Update里的碰撞推动逻辑
首先在Game1类里新增字段存储上一帧的键盘状态,避免按住空格重复触发:
KeyboardState lastKeyState; // 新增字段 int pushedBlockCount = 0; // 替换原来的i2,记录已经推动的方块数量
然后修改Update方法里的碰撞处理逻辑,调整执行顺序:
protected override void Update(GameTime gameTime) { var keyState = Keyboard.GetState(); base.Update(gameTime); player.StorePosition(); if (keyState.IsKeyDown(Keys.Left)) player.MoveLeft(); if (keyState.IsKeyDown(Keys.Right)) player.MoveRight(); if (keyState.IsKeyDown(Keys.Up)) player.MoveUp(); if (keyState.IsKeyDown(Keys.Down)) player.MoveDown(); // 检测空格按下的瞬间(当前帧按下、上一帧未按下) bool spacePressed = keyState.IsKeyDown(Keys.Space) && lastKeyState.IsKeyUp(Keys.Space); // 此处保留原有门相关的逻辑不变 backgroundColor = Color.CornflowerBlue; bool isCollideSolid = false; foreach (var block in blocks) { if (player.GetRectangle().Intersects(block.Rectangle)) { // 先处理可推动方块逻辑 if (block.IsPushable && spacePressed) { if (pushedBlockCount == 0) { block.MoveRight(); pushedBlockCount++; } else if (pushedBlockCount == 1) { block.MoveLeft(); pushedBlockCount++; } } // 再处理固体碰撞,排除可推动方块 if (block.IsSolid) { isCollideSolid = true; } if (block.IsEatable) { block.IsVisible = false; i++; } } if (i == 3) { if (block.IsRemovable) { block.IsSolid = false; block.IsVisible = false; } } } // 统一处理玩家回弹,避免遍历的时候中途修改位置导致逻辑异常 if (isCollideSolid) { player.RestorePosition(); } blocks.RemoveAll(block => !block.IsVisible); // 保存当前帧键盘状态给下一帧用 lastKeyState = keyState; }
4. 可选:第一关测试可加可推动方块
如果需要在第一关测试功能,在Initialize方法的blocks.Add列表里新增:
blocks.Add(BlockFactory.CreatePushableBlock(300, 300)); // 可自行调整测试位置
内容的提问来源于stack exchange,提问作者Monkeybeat
相关产品推荐
相关产品推荐

