-
Notifications
You must be signed in to change notification settings - Fork 0
add CFS for Pong Game #2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Summary of ChangesHello @franz-sweepMe, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request introduces a new, self-contained Pong game module, Highlights
🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console. Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code Review
This pull request adds a complete Pong game implementation as a SweepMe! custom function. The code is well-structured with a Main class for integration and a PongWidget for the game itself. My review focuses on improving robustness, consistency, and maintainability. Key findings include overly broad exception handling that can hide bugs, inconsistencies in how configuration parameters like paddle sizes are handled between the Main class and the PongWidget, a potential crash in the configure method, and some dead code. I've also included suggestions to align with Python best practices like moving imports and removing magic numbers.
| self.widget.player1_score = 0 # bottom paddle | ||
| self.widget.player2_score = 0 # top paddle |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The configure method directly accesses self.widget without checking if it has been initialized. If configure is called before renew_widget, this will raise an AttributeError. You should add a guard to ensure self.widget is not None before accessing its attributes, for example by wrapping these lines in an if self.widget: block.
| self.paddle1_size = 50 | ||
| self.paddle2_size = 50 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The paddle sizes are hardcoded to 50, ignoring the default values defined in the arguments dictionary. This can lead to unexpected behavior where the UI shows one value but the game uses another on startup. You should initialize self.paddle1_size and self.paddle2_size using the values from self.arguments.
| self.paddle1_size = 50 | |
| self.paddle2_size = 50 | |
| self.paddle1_size = int(self.arguments["Paddle 1 size"]) | |
| self.paddle2_size = int(self.arguments["Paddle 2 size"]) | |
| try: | ||
| w = self.widget | ||
| # apply speed update: preserve direction signs, change magnitude | ||
| if new_ball_speed is not None: | ||
| try: | ||
| sx = 1 if w.ball_dx >= 0 else -1 | ||
| sy = 1 if w.ball_dy >= 0 else -1 | ||
| w.ball_dx = sx * float(self.ball_speed) | ||
| w.ball_dy = sy * float(self.ball_speed) | ||
| w._initial_speed = float(self.ball_speed) | ||
| except Exception: | ||
| pass | ||
| # apply paddle size update: set widths and recenter horizontally | ||
| try: | ||
| w.paddle_width = int(self.paddle1_size) | ||
| w.paddle2_width = int(self.paddle2_size) | ||
| ww = w.width() | ||
| # w.paddle_x = (ww - w.paddle_width) // 2 | ||
| # w.paddle2_x = (ww - w.paddle2_width) // 2 | ||
| except Exception: | ||
| pass | ||
| # keep stored scores in sync with widget | ||
| try: | ||
| self.player1_score = int(getattr(w, 'player1_score', self.player1_score)) | ||
| except Exception: | ||
| pass | ||
| try: | ||
| self.player2_score = int(getattr(w, 'player2_score', self.player2_score)) | ||
| except Exception: | ||
| pass | ||
| except Exception: | ||
| pass |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This large try...except Exception: pass block, along with several nested ones, silently swallows all errors that might occur when updating the widget. This makes debugging extremely difficult as any issue (e.g., AttributeError, TypeError, ValueError) will be hidden. It's better to handle specific exceptions where they can be recovered from, or at least log the exceptions to aid in debugging.
| # w.paddle_x = (ww - w.paddle_width) // 2 | ||
| # w.paddle2_x = (ww - w.paddle2_width) // 2 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The code to recenter the paddles after their size is updated is commented out. This means that if the paddle sizes are changed during runtime, they will not be recentered horizontally, which is a bug. You should uncomment these lines to ensure paddles are correctly positioned after a size change.
| # w.paddle_x = (ww - w.paddle_width) // 2 | |
| # w.paddle2_x = (ww - w.paddle2_width) // 2 | |
| w.paddle_x = (ww - w.paddle_width) // 2 | |
| w.paddle2_x = (ww - w.paddle2_width) // 2 |
| def apply_updates_and_resume(self, new_speed=None, new_paddle=None): | ||
| """Apply runtime updates (speed, paddle size) and resume the game if it was paused for scoring.""" | ||
| try: | ||
| if new_speed is not None: | ||
| # preserve current direction signs but set magnitude to new_speed | ||
| sx = 1 if self.ball_dx >= 0 else -1 | ||
| sy = 1 if self.ball_dy >= 0 else -1 | ||
| self.ball_dx = sx * float(new_speed) | ||
| self.ball_dy = sy * float(new_speed) | ||
| self._initial_speed = float(new_speed) | ||
| if new_paddle is not None: | ||
| self.paddle_width = int(new_paddle) | ||
| self.paddle2_width = int(new_paddle) | ||
| ww = self.width() | ||
| # recenter paddles | ||
| self.paddle_x = (ww - self.paddle_width) // 2 | ||
| self.paddle2_x = (ww - self.paddle2_width) // 2 | ||
| except Exception: | ||
| pass | ||
| # clear waiting flag and restart timer | ||
| self.waiting_for_resume = False | ||
| # ensure ball is correctly placed (keep the spawn reset state) | ||
| # restart timer | ||
| try: | ||
| self.timer.start(16) | ||
| except Exception: | ||
| pass |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| arguments = { | ||
| "Ball speed": 5.0, | ||
| "Paddle size": 120, | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The arguments dictionary defines "Paddle size", but the script.main method expects "Paddle 1 size" and "Paddle 2 size". When script.main is called, it will not find these keys and will fall back to the default values from Main.__init__, not the intended 120. This will cause the test script to run with unexpected paddle sizes. You should update the arguments dictionary to use the correct keys. This is also related to the PongWidget only accepting a single paddle_size on initialization.
| Returns: (player1_score, player2_score) | ||
| """ | ||
| # update from kwargs for runtime parameters if provided | ||
| new_ball_speed = float(kwargs.get("Ball speed", "1")) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The main method uses a hardcoded default value of "1" for new_ball_speed when calling kwargs.get(). This is inconsistent with the default value of "5.0" defined in the arguments dictionary and initialized in __init__. It's better to use the currently configured ball speed (self.ball_speed) as the default value to avoid unexpected speed changes.
| new_ball_speed = float(kwargs.get("Ball speed", "1")) | |
| new_ball_speed = float(kwargs.get("Ball speed", self.ball_speed)) |
| from PySide2.QtWidgets import QWidget | ||
| from PySide2.QtCore import Qt, QTimer | ||
| from PySide2.QtGui import QPainter, QColor |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| from PySide2.QtGui import QPainter, QColor | ||
|
|
||
| class PongWidget(QWidget): | ||
| def __init__(self, speed=2.0, paddle_size=120): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The PongWidget's __init__ method accepts a single paddle_size parameter, which is then used for both paddles. However, the Main class and other parts of the code are designed to handle separate sizes for each paddle (paddle1_size and paddle2_size). To make the component more flexible and consistent with the rest of the application, consider updating the __init__ method to accept separate sizes for each paddle. You will also need to update the method body to store and use these separate sizes.
| def __init__(self, speed=2.0, paddle_size=120): | |
| def __init__(self, speed=2.0, paddle1_size=120, paddle2_size=120): |
|
|
||
| def game_loop(self): | ||
| # move paddles based on pressed keys (supports simultaneous input) | ||
| paddle_speed = 8 # pixels per frame; adjust to taste |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No description provided.