PšNG is designed to help new game developers grasp fundamental programming concepts and design principles through an engaging and interactive experience. The game features classic gameplay mechanics, supports keyboard and Xbox controller inputs, and allows for both single-player and multiplayer modes.
- Classic Gameplay: Experience the timeless fun of ping-pong with modern enhancements, including smooth animations and responsive controls.
- Keyboard and Controller Support: Play using your keyboard or Xbox controllers, complete with vibration feedback for an immersive experience.
- Resizable and Pausable: Enjoy a flexible gameplay experience that can be paused at any time, allowing players to take breaks without losing progress.
- Single and Multiplayer Modes: Challenge yourself against a computer player or compete with friends, making the game versatile for different play styles.
- Understand the basics of game mechanics and physics, including how to simulate movement and collisions.
- Gain hands-on experience with VB.NET and game development concepts, such as state management and event handling.
- Learn how to implement user input handling, game states, sound effects, and graphical rendering.
Keyboard Controls | XBox Controllers | Code Walk Through | Top
To begin, you'll need to set up your development environment and clone the repository to get the game files.
Visual Studio is an Integrated Development Environment (IDE) created by Microsoft.
It is a powerful software development tool that provides a comprehensive set of features and tools for building a wide range of applications.
This is the IDE I use to make PšNG and I recommend that you use.
Grab Visual Studio Communityāit's free and perfect for indie devs.
Install Visual Studio from here: https://visualstudio.microsoft.com/downloads/ and include the .NET Desktop Development workload.
Click the "Code" button.
Copy the repository's URL.
Open Visual Studio.
Click "Clone a repository".
Paste the repository URL into the location field.
Click the "Clone" button.
Once the cloning process is complete, you will have your own local copy of the game that you can run and modify on your computer.
Dive into the code, experiment, and enhance the game while learning valuable programming skills!
Getting Started | XBox Controllers | Code Walk Through | Top
To play using your keyboard, use the following controls:
-
Player 1 ( š Left Paddle )
- W : Move Up
- S : Move Down
-
Player 2 ( Right Paddle š )
- Up Arrow ā¬ļø : Move Up
- Down Arrow ā¬ļø : Move Down
-
Pause/Resume Game
- Pause : Pause or Resume the game
- Escape : From pause screen Resets the game
Getting Started | Code Walk Through | Top
To play using your Xbox controllers, use the following controls:
-
š Paddle Movement š
- Thumbstick Up or DPad Up : Move Up
- Thumbstick Down or DPad Down : Move Down
-
Pause/Resume Game
- Start : Pause or Resume the game
- Back : From pause screen Resets the game
Getting Started | Keyboard Controls | XBox Controllers | Top
In this comprehensive walkthrough, we will explore the code structure and functionality of the PšNG game, a classic table tennis simulation. This guide aims to provide a detailed understanding of game programming concepts, from architecture to implementation. Whether you're a novice or an experienced developer, this walkthrough will deepen your knowledge and inspire you to create your own games.
The game begins by importing necessary namespaces and declaring the main class.
Imports System.Numerics
Imports System.ComponentModel
Imports System.Runtime.InteropServices
Imports System.Text
Imports System.IO
Public Class Form1- System.Numerics: This namespace provides mathematical types such as
Vector2, which are essential for representing 2D vectors used in game physics and positioning. - System.ComponentModel: Contains classes that are used to implement the run-time and design-time behavior of components and controls, helping manage the gameās UI.
- System.Runtime.InteropServices: Allows interaction with unmanaged code, crucial for handling Xbox controller inputs through XInput.
- System.Text: Provides classes for manipulating strings, including
StringBuilder, which is used for constructing commands sent to the multimedia API. - System.IO: Facilitates file handling operations, allowing the game to read and write sound files and other resources.
Private Enum GameStateEnum
StartScreen
Instructions
Serve
Playing
EndScreen
Pause
End EnumThis enumeration defines the various states of the game, allowing the program to manage transitions and logic based on the current state:
- StartScreen: The initial screen where players can choose to start the game.
- Instructions: Displays the rules and controls of the game.
- Serve: The state when players are preparing to serve the ball.
- Playing: The main gameplay state where the action occurs.
- EndScreen: Displays the result of the game and the winner.
- Pause: The game is temporarily halted.
Private Structure GameObject
Public Position As Vector2
Public Acceleration As Vector2
Public Velocity As Vector2
Public MaxVelocity As Vector2
Public Rect As Rectangle
End StructureThe GameObject structure represents entities in the game, such as the ball and paddles. Each object has the following properties:
- Position: A
Vector2representing the current location of the object in 2D space. - Acceleration: A
Vector2representing the change in velocity over time, allowing for smooth movement. - Velocity: A
Vector2representing the current speed and direction of the object, essential for updating its position each frame. - MaxVelocity: A
Vector2representing the maximum speed the object can achieve, ensuring that objects do not move too fast. - Rect: A
Rectanglethat defines the boundaries of the object for collision detection.
Private Ball As GameObject
Private LeftPaddle As GameObject
Private RightPaddle As GameObjectIn the example above, instances of GameObject are created for the ball and both paddles, allowing the game to track their positions and movements.
Private GameState As GameStateEnum = GameStateEnum.StartScreen
Private Serving As ServeStateEnum = ServeStateEnum.LeftPaddle
Private ServSpeed As Single = 500
Private Winner As WinStateEnum = WinStateEnum.LeftPaddle
Private NumberOfPlayers As Integer = 1- GameState: Tracks the current state of the game, determining which logic to execute.
- Serving: Indicates which paddle is currently serving (left or right), affecting ball movement.
- ServSpeed: Controls the speed at which the ball is served, influencing gameplay dynamics.
- Winner: Keeps track of the current winner of the game, used for displaying results.
- NumberOfPlayers: Indicates whether the game is single-player or multiplayer, affecting gameplay logic.
Private FlashCount As Integer = 0
Private EndScreenCounter As Integer = 0These additional variables are used to manage game transitions and visual effects during the end screen.
The game loop is a critical component of the PšNG game, ensuring that the game runs smoothly and updates in real-time. It consists of two main subroutines: UpdateGame and DrawGame.
This subroutine is called at regular intervals to update the game's state. It processes input, updates game objects, checks for collisions, and transitions between game states.
Private Sub UpdateGame()
Select Case GameState
Case GameStateEnum.Playing
UpdatePlaying()
Case GameStateEnum.StartScreen
UpdateStartScreen()
Case GameStateEnum.Instructions
UpdateInstructions()
Case GameStateEnum.Serve
UpdateServe()
Case GameStateEnum.Pause
UpdatePause()
Case GameStateEnum.EndScreen
UpdateEndScreen()
End Select
End Sub- Select Case: This structure evaluates the current game state and calls the corresponding update method.
- Each case corresponds to a different game state, allowing for specific logic to be executed based on the game's current condition.
This subroutine handles rendering the game's graphics. It draws all the game elements, such as paddles, the ball, and scores, onto the screen.
Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)
DrawGame(e.Graphics) ' Draw all game elements
UpdateFrameCounter() ' Update frame counter
End Sub- DrawGame: Responsible for rendering all visual elements of the game based on the current game state.
- UpdateFrameCounter: Keeps track of the frames per second (FPS) for performance monitoring and display.
The UpdateGame method uses a Select Case statement to determine what actions to take based on the current game state. It handles input, updates game objects, and checks for game conditions.
Private Sub UpdateGame()
Select Case GameState
Case GameStateEnum.Playing
UpdatePlaying()
' Additional cases for other states...
End Select
End SubEach state has a corresponding method that encapsulates its specific logic:
- UpdatePlaying: Handles game logic while playing, including movement, collision detection, and scoring.
- UpdateStartScreen: Manages the start screen logic, including user input for starting the game.
- UpdateInstructions: Displays and manages the instructions screen, guiding players on how to play.
- UpdateServe: Prepares the game for serving, positioning the ball and paddles appropriately.
- UpdatePause: Manages the pause state, allowing players to resume the game.
- UpdateEndScreen: Displays the end screen logic, showing the winner and allowing for a reset.
The game allows players to control the paddles using keyboard input. Here's how the left paddle's movement is handled:
Private Sub UpdateLeftPaddleKeyboard()
If WKeyDown Then
MoveLeftPaddleUp()
ElseIf SKeyDown Then
MoveLeftPaddleDown()
Else
If Not Controllers.Connected(0) Then
DecelerateLeftPaddle()
If ApplyLeftPaddleEnglish Then
ApplyLeftPaddleEnglish = False
Ball.Velocity.X = ServSpeed
Ball.Velocity.Y = 0
End If
End If
End If
End Sub- WKeyDown: Checks if the W key is pressed to move the left paddle up.
- SKeyDown: Checks if the S key is pressed to move the left paddle down.
- DecelerateLeftPaddle: If neither key is pressed and the controller is not connected, the paddle decelerates to a stop.
The game also supports Xbox controllers. The input handling function uses the XboxControllers structure to manage the state of the controllers.
Private Sub HandleControllerInput()
For ControllerNumber As Integer = 0 To 3
If Controllers.Connected(ControllerNumber) Then
DoButtonLogic(ControllerNumber)
UpdateLeftThumbstickPosition(ControllerNumber)
UpdateRightThumbstickPosition(ControllerNumber)
End If
Next
End Sub- DoButtonLogic: Processes button presses for the specified controller.
- UpdateLeftThumbstickPosition: Updates the position of the left thumbstick based on input.
- UpdateRightThumbstickPosition: Updates the position of the right thumbstick based on input.
Collision detection is essential for determining interactions between game objects. Here's how the game checks for collisions with the paddles:
Private Sub CheckForLeftPaddleHits()
If Ball.Rect.IntersectsWith(LeftPaddle.Rect) Then
PlaySound("hit")
Ball.Velocity.X = 0
Ball.Velocity.Y = 0
Ball.Rect.X = LeftPaddle.Rect.X + LeftPaddle.Rect.Width + 5
Ball.Position.X = Ball.Rect.X
ApplyLeftPaddleEnglish = True
Controllers.VibrateLeft(0, 42000)
End If
End Sub- IntersectsWith: Checks if the ball's rectangle intersects with the left paddle's rectangle, indicating a collision.
- PlaySound: Plays a sound effect when the ball hits the paddle.
- Velocity: Stops the ball's movement and sets its position to avoid overlapping with the paddle.
- ApplyLeftPaddleEnglish: A flag indicating that spin should be applied to the ball after hitting the paddle.
- Vibration Feedback: Triggers a vibration effect on the controller for tactile feedback.
Private Sub CheckForRightPaddleHits()
If Ball.Rect.IntersectsWith(RightPaddle.Rect) Then
PlaySound("hit")
Ball.Velocity.X = 0
Ball.Velocity.Y = 0
Ball.Rect.X = RightPaddle.Rect.X - (Ball.Rect.Width + 5)
Ball.Position.X = Ball.Rect.X
If NumberOfPlayers = 2 Then
ApplyRightPaddleEnglish = True
Controllers.VibrateLeft(1, 42000)
Else
DoComputerPlayerEnglish()
End If
End If
End SubThis method checks if the ball intersects with the right paddle and handles the logic for bouncing the ball back and updating its velocity.
Private Sub CheckforEndGame()
If LeftPaddleScore >= 10 Then
Winner = WinStateEnum.LeftPaddle
GameState = GameStateEnum.EndScreen
PlayWinningSound()
End If
If RightPaddleScore >= 10 Then
Winner = WinStateEnum.RightPaddle
GameState = GameStateEnum.EndScreen
PlayWinningSound()
End If
End SubThis method checks if a player has reached the winning score and transitions the game state to the end screen if so:
- Winner: Sets the winner based on the score.
- PlayWinningSound: Plays a sound to indicate the end of the game.
Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)
MyBase.OnPaint(e)
DrawGame(e.Graphics)
UpdateFrameCounter()
End SubThis method is responsible for rendering the game graphics. It calls the DrawGame method to draw all game elements and then updates the frame counter.
Private Sub DrawGame(g As Graphics)
g.Clear(Color.Black) ' Clear the background
Select Case GameState
Case GameStateEnum.Playing
DrawPlaying(g)
Case GameStateEnum.StartScreen
DrawStartScreen(g)
Case GameStateEnum.Instructions
DrawInstructions(g)
Case GameStateEnum.Serve
DrawServe(g)
Case GameStateEnum.Pause
DrawPauseScreen(g)
Case GameStateEnum.EndScreen
DrawEndScreen(g)
End Select
End Sub- g.Clear(Color.Black): Clears the previous frame by filling the background with black.
- Select Case: Determines which drawing method to call based on the current game state.
Each state has its own drawing logic:
- DrawPlaying: Renders the game elements during active gameplay, including paddles, ball, and scores.
- DrawStartScreen: Displays the start screen with options for players to choose.
- DrawInstructions: Shows the instructions for playing the game, guiding players on controls and objectives.
- DrawServe: Prepares the visual elements for the serving state, indicating which player is serving.
- DrawPauseScreen: Displays the pause screen with relevant information and options to resume or exit.
- DrawEndScreen: Shows the end screen with the winner and final scores, along with options to restart the game.
Private Sub DrawPlaying(g As Graphics)
g.Clear(Color.Black)
DrawLeftPaddle(g)
DrawRightPaddle(g)
DrawBall(g)
DrawScore(g)
DrawFPSDisplay(g)
End SubIn the DrawPlaying method, we clear the background, draw the paddles, ball, and scores, and display the current frames per second (FPS). This method is called repeatedly during the game loop to ensure a smooth visual experience.
Private Function AddSound(SoundName As String, FilePath As String) As Boolean
If Not String.IsNullOrWhiteSpace(SoundName) AndAlso IO.File.Exists(FilePath) Then
Dim CommandOpen As String = $"open ""{FilePath}"" alias {SoundName}"
Dim ReturnString As New StringBuilder(128)
If mciSendStringW(CommandOpen, ReturnString, 0, IntPtr.Zero) = 0 Then
Array.Resize(Sounds, Sounds.Length + 1)
Sounds(Sounds.Length - 1) = SoundName
Return True
End If
End If
Return False
End FunctionThis function loads sound files from specified paths and associates them with names for easy reference:
- CommandOpen: Constructs a command to open the sound file.
- mciSendStringW: Sends the command to the multimedia API to open the sound file.
Private Function PlaySound(SoundName As String) As Boolean
If Sounds IsNot Nothing AndAlso Sounds.Contains(SoundName) Then
Dim CommandSeekToStart As String = $"seek {SoundName} to start"
Dim ReturnString As New StringBuilder(128)
mciSendStringW(CommandSeekToStart, ReturnString, 0, IntPtr.Zero)
Dim CommandPlay As String = $"play {SoundName} notify"
If mciSendStringW(CommandPlay, ReturnString, 0, Me.Handle) = 0 Then
Return True
End If
End If
Return False
End FunctionThis function plays specific sounds at appropriate game events (e.g., ball hits, scoring). It ensures that audio feedback is provided to enhance the gaming experience.
- AddSound: Loads a sound file and associates it with a name.
- PlaySound: Plays a specific sound, seeking to the start of the sound file before playing.
- PauseSound: Pauses a currently playing sound.
- LoopSound: Plays a sound on repeat, useful for background music.
This detailed walkthrough provides a comprehensive overview of the PšNG game code structure and functionality, enabling you to understand and modify the game effectively. Each section delves into the specific components that make the game work, from handling user input to managing game states and rendering graphics.
- Experiment with Modifications: Try adjusting paddle speeds, changing ball physics, or implementing new gameplay mechanics.
- Enhance Features: Add power-ups, special abilities, or new game modes to increase replayability.
- Explore Networking: Implement online multiplayer functionality to allow players to compete over the internet.
- Optimize Performance: Analyze the game's performance and optimize rendering and input handling for smoother gameplay.
By understanding these components, you can enhance your coding skills and apply this knowledge to create your own games or modify existing ones.
- Game Development Tutorials: Explore online tutorials and courses focused on game development using VB.NET and other languages.
- Open Source Projects: Study other open-source game projects to learn different approaches and techniques.
- Game Design Principles: Read about game design principles to improve your understanding of creating engaging and fun gameplay experiences.
Getting Started | Keyboard Controls | XBox Controllers | Code Walk Through | Top
https://youtu.be/ppUMmJLlsDg?si=HlilqN7ddzhGwYtN
https://youtube.com/shorts/_W-7EHnru2w?si=H6w0GIQnZGHYtB_t
A heartfelt thank you to my son, Joey, for his invaluable help in developing PšNG. This project is a testament to our teamwork and shared passion for coding!

I invite all players and developers to share their experiences, thoughts, and feedback on PšNG. Your insights are essential for making this project even better. Letās collaborate and create something amazing together!
You can explore my work and projects on my GitHub: github.com/JoeLumbley and check out my tutorials on my YouTube channel: youtube.com/@codewithjoe6074.
Happy coding!






