JavaFX开发植物大战僵尸:多线程高效碰撞检测方案咨询
Hey there! I’ve been where you are—trying to get collision detection right in a JavaFX game without grinding the whole thing to a halt. Let’s fix that inefficient infinite loop and get your zombies and lawnmowers interacting smoothly without the lag.
The Problem with Your Current Approach
That while(true) loop you’re using is a total CPU hog. It runs nonstop, gobbling up 100% of a core’s resources without any breaks. Even though zombies take 20+ seconds to reach the lawnmower, the loop doesn’t care—it just keeps churning through collision checks every millisecond, leaving no room for the JavaFX UI thread to update. That’s exactly why you’re seeing stutters and freezes.
Better Solutions to Try
1. Use JavaFX’s AnimationTimer (Best Fit for Game Loops)
JavaFX’s built-in AnimationTimer is made exactly for this kind of game-related per-frame logic. It triggers its handle() method once every frame (synced with the UI’s render cycle), so you only run collision checks when the screen is actually updating—no wasted cycles.
Here’s how to adapt your code:
// Add a flag to each Zombie to prevent repeated collision triggers (optional but critical) public class Zombie extends Node { private boolean isCollidingWithMower = false; // Getters and setters for the flag public boolean isCollidingWithMower() { return isCollidingWithMower; } public void setCollidingWithMower(boolean value) { isCollidingWithMower = value; } // Rest of your Zombie code... } // Set up the collision timer AnimationTimer collisionDetector = new AnimationTimer() { @Override public void handle(long timestamp) { // Only check zombies in the same row as the lawnmower for (Zombie z : zombies[0]) { // First do a quick bounding box check to avoid expensive Shape.intersect calls Bounds zombieBounds = z.getBoundsInParent(); Bounds mowerBounds = mowers[0].getBoundsInParent(); if (zombieBounds.intersects(mowerBounds)) { // Now do precise shape intersection Shape intersection = Shape.intersect(z, mowers[0]); if (intersection != null && !intersection.getBoundsInLocal().isEmpty()) { // Only trigger collision if we haven't already for this frame if (!z.isCollidingWithMower()) { mowers[0].takeHit(1); z.takeHit(100); z.setCollidingWithMower(true); } } } else { // Reset the flag when no collision is detected z.setCollidingWithMower(false); } } } }; // Start the timer when your level begins collisionDetector.start();
2. Listen to Zombie Movement Properties
Since you’re using TranslateTransition to move zombies, you could listen to the zombie’s translateX property and only run collision checks when the zombie actually moves. This is more targeted than a per-frame timer:
for (Zombie z : zombies[0]) { z.translateXProperty().addListener((obs, oldVal, newVal) -> { Bounds zombieBounds = z.getBoundsInParent(); Bounds mowerBounds = mowers[0].getBoundsInParent(); if (zombieBounds.intersects(mowerBounds)) { Shape intersection = Shape.intersect(z, mowers[0]); if (intersection != null && !intersection.getBoundsInLocal().isEmpty()) { // Handle collision (don't forget the collision flag to avoid spamming) if (!z.isCollidingWithMower()) { mowers[0].takeHit(1); z.takeHit(100); z.setCollidingWithMower(true); } } } else { z.setCollidingWithMower(false); } }); }
Key Optimizations to Remember
- Bounding Box First: Always do a quick axis-aligned bounding box check before using
Shape.intersect—it’s way faster and eliminates most impossible collision cases upfront. - Collision Flags: Adding a boolean flag to each zombie prevents your
takeHit()methods from being called hundreds of times per second while the collision is active. - Kill the Old Loop: Make sure you stop or never start that original
while(true)loop—it’s the root cause of your performance issues.
Quick Note on Your Zombie Movement Code
Your current TranslateTransition setup looks solid, but just remember that any long-running tasks (like Thread.sleep() or CountDownLatch.await()) should be run on a background thread, not the JavaFX UI thread. You’re already doing that, which is great—keep it up!
内容的提问来源于stack exchange,提问作者Jolly Roger

