Android开发:实现小球弹跳高度-时间曲线及弹跳次数统计
Fixing the Bouncing Ball Height-Time Graph for Your Android App
Hey there! I see you're working on an Android app to visualize a bouncing ball's height over time, and you want to add support for custom initial height, bounce coefficient, and track the total bounce count. Let's fix up your current code to properly model the physics and meet all your requirements.
First, let's address the issues in your current code:
- Your loop doesn't model the actual physics of falling and bouncing—right now it just decrements height by 10% every 0.1 seconds, which doesn't reflect how a ball accelerates downward or decelerates upward.
- Time calculation is disconnected from the physical motion (you're just adding 0.1 each iteration instead of calculating how long each fall/rise takes).
- There's no way for users to input initial height or adjust the bounce coefficient, and no tracking of total bounces.
Here's the complete solution:
First, update your layout (activity_main.xml) to add UI controls for user input and bounce count display:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:padding="16dp"> <!-- User Input Fields --> <EditText android:id="@+id/et_initial_height" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Enter Initial Height (m)" android:inputType="numberDecimal"/> <EditText android:id="@+id/et_bounce_coeff" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Enter Bounce Coefficient (0-1)" android:inputType="numberDecimal"/> <Button android:id="@+id/btn_generate_graph" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Generate Graph"/> <!-- Bounce Count Display --> <TextView android:id="@+id/tv_bounce_count" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="16dp" android:textSize="18sp"/> <!-- Graph View --> <com.jjoe64.graphview.GraphView android:id="@+id/graphView" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginTop="16dp"/> </LinearLayout>
Now, update your MainActivity.java to handle the physics, user input, and graph rendering:
import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; import androidx.appcompat.app.AppCompatActivity; import com.jjoe64.graphview.GraphView; import com.jjoe64.graphview.series.DataPoint; import com.jjoe64.graphview.series.LineGraphSeries; public class MainActivity extends AppCompatActivity { private EditText etInitialHeight; private EditText etBounceCoeff; private TextView tvBounceCount; private GraphView graphView; private LineGraphSeries<DataPoint> series; // Physics constants private final double GRAVITY = 10.0; // m/s² private final double TIME_STEP = 0.01; // Smaller step for smoother curve private final double MIN_HEIGHT = 0.1; // Stop when bounce height is below this @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // Initialize UI elements etInitialHeight = findViewById(R.id.et_initial_height); etBounceCoeff = findViewById(R.id.et_bounce_coeff); tvBounceCount = findViewById(R.id.tv_bounce_count); graphView = findViewById(R.id.graphView); Button btnGenerate = findViewById(R.id.btn_generate_graph); // Set default values for input fields etInitialHeight.setText("20.0"); etBounceCoeff.setText("0.8"); // Generate graph on button click btnGenerate.setOnClickListener(v -> generateBounceGraph()); } private void generateBounceGraph() { // Get user input values double initialHeight; double bounceCoeff; try { initialHeight = Double.parseDouble(etInitialHeight.getText().toString()); bounceCoeff = Double.parseDouble(etBounceCoeff.getText().toString()); // Validate input if (initialHeight <= 0 || bounceCoeff <= 0 || bounceCoeff >= 1) { tvBounceCount.setText("Please enter valid values: Height >0, Coeff 0-1"); return; } } catch (NumberFormatException e) { tvBounceCount.setText("Please enter valid decimal numbers"); return; } // Reset graph and bounce count graphView.removeAllSeries(); series = new LineGraphSeries<>(); double currentTime = 0.0; double currentHeight = initialHeight; int bounceCount = 0; // Add initial point (time=0, initial height) series.appendData(new DataPoint(currentTime, currentHeight), true, Integer.MAX_VALUE); while (currentHeight > MIN_HEIGHT) { // Phase 1: Ball falls from currentHeight to ground // Calculate time to fall: h = 0.5*g*t² → t = sqrt(2h/g) double timeToFall = Math.sqrt(2 * currentHeight / GRAVITY); // Simulate each time step during fall double fallStartTime = currentTime; while (currentTime < fallStartTime + timeToFall) { currentTime += TIME_STEP; // Height during fall: h(t) = currentHeight - 0.5*g*(t - fallStartTime)² double timeElapsedInFall = currentTime - fallStartTime; double fallHeight = currentHeight - 0.5 * GRAVITY * Math.pow(timeElapsedInFall, 2); // Ensure we don't go below ground level fallHeight = Math.max(fallHeight, 0.0); series.appendData(new DataPoint(currentTime, fallHeight), true, Integer.MAX_VALUE); } // Ball hits ground, increment bounce count bounceCount++; // Phase 2: Ball bounces up to new height currentHeight *= bounceCoeff; // Calculate time to reach peak: v = u - g*t → t = u/g, where u = sqrt(2*g*currentHeight) double timeToPeak = Math.sqrt(2 * currentHeight / GRAVITY); // Simulate each time step during rise double riseStartTime = currentTime; while (currentTime < riseStartTime + timeToPeak) { currentTime += TIME_STEP; // Height during rise: h(t) = sqrt(2*g*currentHeight)*(t - riseStartTime) - 0.5*g*(t - riseStartTime)² double timeElapsedInRise = currentTime - riseStartTime; double riseHeight = Math.sqrt(2 * GRAVITY * currentHeight) * timeElapsedInRise - 0.5 * GRAVITY * Math.pow(timeElapsedInRise, 2); series.appendData(new DataPoint(currentTime, riseHeight), true, Integer.MAX_VALUE); } } // Add the final point at ground level series.appendData(new DataPoint(currentTime, 0.0), true, Integer.MAX_VALUE); // Configure graph graphView.addSeries(series); graphView.setTitle("Height vs Time Graph"); graphView.getGridLabelRenderer().setHorizontalAxisTitle("Time (s)"); graphView.getGridLabelRenderer().setVerticalAxisTitle("Height (m)"); // Display bounce count tvBounceCount.setText("Total Bounces: " + bounceCount); } }
Key improvements explained:
- Accurate Physics Simulation: We split each bounce into two phases—falling to the ground and rising to the new bounce height—using the correct kinematic equations. This gives a realistic curve that matches the expected bouncing ball motion.
- User Input Support: Added
EditTextfields for initial height and bounce coefficient, with input validation to ensure valid values. - Bounce Count Tracking: We increment the count each time the ball hits the ground, then display it in a
TextView. - Smoother Curve: Used a smaller
TIME_STEP(0.01s) to make the graph line smoother, and ensured we don't plot values below ground level. - Reusable Graph Generation: The
generateBounceGraph()method handles all logic, so users can adjust inputs and regenerate the graph anytime.
Just make sure you have the GraphView library added to your build.gradle (Module level):
dependencies { implementation 'com.jjoe64:graphview:4.2.2' }
内容的提问来源于stack exchange,提问作者Alton Dsouza
相关产品推荐
相关产品推荐

