Before we jump back into creating our snake game lets learn some physics. Collisions are fundamental to the majority of video games. In the snake game we program into the game that it should detect when it has come to a wall to end the game or to grow in length when it eats some food. Neither of these incidents result in us having to accurately code physics. But what if we were coding something like pong where a ball is hitting a paddle and we want it to bounce back accurately – how do we input the physics for that collision.
>
Lets apply this to some coding – here is a text based collision with a ball and paddle:
# Initial position and velocity of the ball
ball_position = 0
ball_velocity = 1 # Positive is rightward, negative is leftward
# Position of the stationary paddle
paddle_position = 10
# Ensure the initialization of variables happens before this point in your script
# Example loop to simulate movement (make sure this part is not before variable initialization)
for step in range(20):
print "Step {}: Ball at position {}".format(step, ball_position)
# Move the ball according to its velocity
ball_position += ball_velocity
# Check for collision with the paddle and bounce back
if ball_position >= paddle_position:
ball_velocity = -ball_velocity # Reverse direction
ball_position = paddle_position # Ensure the ball isn't beyond the paddle
print "Simulation complete."
This is not a lot of fun and not very game like though. We are going to change platforms now to Web Vpython which is a language that is very much based on Python but specifically created to create physics simulations.
Worksheet 1: Setting Up the Scene
Objective: Learn how to set up the basic 3D scene for the game.
Introduction to Display Function: GlowScript provides a display function to create a visual environment for your projects. This is where all your game objects will appear.
Code Walkthrough:
scene = display(title="BOUNCE GAME:", width=450)
sceneis a variable where we store our game window.display(title="BOUNCE GAME:", width=450)creates a new window with a title “BOUNCE GAME:” and a width of 450 pixels.
Assignment: Create a game window with a title you want to go with and a width of 600 pixels. Experiment with changing the title and width to see what happens.
Worksheet 2: Creating Game Objects
Objective: Introduce basic 3D objects and properties.
Basic 3D Objects: In GlowScript, you can create various 3D objects. We will focus on sphere for the ball and box for the paddle and boundaries.
Code Walkthrough:
ball = sphere(pos=vec(0,0,0), size=vector(3,3,1), color=vector(1,0,0), radius=5)
paddle = box(pos=vec(0,-20,0), size=vec(10,2,.2), color=vec(100,10,2))
ballis aspherepositioned at the origin(0,0,0), red in color. Itssizeandradiusdetermine its appearance.paddleis aboxplaced below the ball aty = -20. Itssizeandcolorare specified to distinguish it from the ball.
Assignment: Create a ball and a paddle. Experiment with changing their positions, sizes, and colors.
Worksheet 3: Movement and Interaction
Objective: Learn about updating object positions and basic interactions through code that moves an object and detects basic conditions like boundaries.
Background: In computer graphics and games, objects move by changing their position over time. This can be simulated by updating the position of an object in a loop, which runs continuously during the game.
Starter Code and Walkthrough:
First, let’s focus on moving the ball in a horizontal direction (left and right) and bouncing it off the walls. We’ll use a simple control structure (if statement) to reverse the ball’s direction when it hits a boundary.
# Initialize ball position and velocity
ball.pos = vec(0,0,0) # Starting position at the center
ball.velocity = vec(5,0,0) # Moving 5 units per time step to the right
# Main game loop
while True:
rate(30) # Controls the speed of the loop, making it run 30 times per second
# Update the ball's position
ball.pos = ball.pos + ball.velocity * dt
# Check for collision with the right wall
if ball.pos.x > 23: # Assuming the right boundary is at x=23
ball.velocity.x = -ball.velocity.x # Reverse the x velocity
# Check for collision with the left wall
if ball.pos.x < -23: # Assuming the left boundary is at x=-23
ball.velocity.x = -ball.velocity.x # Reverse the x velocity
Explanation:
ball.posrepresents the current position of the ball.ball.velocityis how much the ball moves each time the loop runs. Here, it’s set to move to the right (x=5).- The
while Trueloop is the game loop, constantly running to update the game state.rate(30)limits the loop to run 30 times per second, making our game’s animations smoother. - Within the loop,
ball.pos = ball.pos + ball.velocity * dtupdates the ball’s position based on its velocity.dtis a small time step (e.g.,dt = 1.0 / 30to match the rate of the loop). - The if statements check whether the ball has hit a boundary. If it has, the ball’s horizontal velocity (
ball.velocity.x) is reversed, causing the ball to bounce back.
Assignment:
- Use the provided code as a starting point to make the ball move horizontally across the screen and bounce off the left and right edges.
- Experiment with changing the ball’s initial velocity and the
rateto see how it affects the movement and the smoothness of the animation. - Make the ball also move vertically and bounce off the top and bottom edges of the scene.
Worksheet 4: Ball Physics
Objective: Implement basic physics to simulate gravity and make the ball bounce off the bottom of the scene.
Background: Physics in games often involves simulating real-world phenomena like gravity, which accelerates objects towards the Earth. By applying a constant acceleration to the ball’s vertical velocity and inverting its direction when it collides with the ground, we can simulate bouncing.
# Define initial ball properties
ball.pos = vec(0, 10, 0) # Start 10 units above the bottom
ball.velocity = vec(2, 0, 0) # Initial horizontal velocity
gravity = vec(0, -9.8, 0) # Gravity acceleration vector
dt = 0.01 # Time step
# Main game loop
while True:
rate(100) # Run this loop 100 times per second
# Apply gravity to the ball's velocity
ball.velocity = ball.velocity + gravity * dt
# Update ball position
ball.pos = ball.pos + ball.velocity * dt
# Check for collision with the bottom
if ball.pos.y < 0: # Assuming the bottom is at y=0
ball.velocity.y = -ball.velocity.y # Invert y velocity to bounce
# Optional: Add side boundaries collision for a complete example
if ball.pos.x > 23 or ball.pos.x < -23:
ball.velocity.x = -ball.velocity.x # Bounce off side walls
Explanation:
- The ball starts 10 units above the bottom of the scene, with an initial horizontal velocity.
- Gravity is defined as a vector pointing downwards (
y = -9.8), simulating Earth’s gravity. In games, you might need to adjust the magnitude for a more enjoyable experience. - In each iteration of the loop, gravity is applied to the ball’s velocity, accelerating it downwards.
- The ball’s position is updated based on its velocity.
- When the ball “collides” with the bottom (
y < 0), its vertical velocity is inverted (ball.velocity.y = -ball.velocity.y), simulating a bounce. The exact position where this should happen depends on your scene’s setup. - Additional conditionals are added to simulate bouncing off the side walls for a more comprehensive demonstration.
Assignment:
- Implement the provided physics code in your game. Observe how gravity affects the ball’s movement.
- Adjust the magnitude of gravity and the initial velocity to see how they change the ball’s trajectory and bouncing behavior.
- Consider what might happen if you apply gravity continuously without reversing the ball’s velocity on collision. How does this affect the realism of the ball’s movement?
Worksheet 5: User Input
Objective: Capture and respond to user input.
Capturing Mouse Movements: You can control the paddle’s position with the mouse’s x-position.
Code Walkthrough:
if scene.mouse.pos.x < 21 and scene.mouse.pos.x > -21:
paddle.pos.x = scene.mouse.pos.x
Explanation:
- The
scene.mouse.pos.xgives the current X position of the mouse within the game window. - In the main game loop, we continuously check the mouse’s position. The paddle’s X position (
paddle.pos.x) is updated to follow the mouse, but we use conditional statements to ensure it doesn’t exceed the defined left and right limits.
Assignment:
- Incorporate this code into your game, ensuring the paddle follows the mouse’s movement horizontally.
- Experiment with different limits for the paddle’s movement and observe how constraining the paddle’s position affects gameplay.
- As an additional challenge, try implementing functionality that only moves the paddle when the mouse is within the game scene area. This might involve checking the mouse’s Y position and determining whether it falls within the vertical bounds of the scene.
Worksheet 6: Collision Detection
Objective: Implement collision detection between objects.
Code Walkthrough: Check if the ball’s position intersects with the paddle’s position. If so, reverse the ball’s y-velocity to simulate a bounce.
if (ball.pos.x >= paddle.pos.x - paddle.length/2) and (ball.pos.x <= paddle.pos.x + paddle.length/2) and (ball.pos.y <= -18):
ball.velocity.y = -ball.velocity.y
Assignment: Implement collision detection for the ball and paddle. Extend this to detect collisions with the game’s top and side boundaries.
Worksheet 7: Game Mechanics
Objective: Implement scoring, game states (winning and losing conditions), and display dynamic messages based on the game’s state.
Background: A crucial aspect of game development is creating clear objectives and feedback for the player. This involves tracking their progress through scores, providing win or lose conditions, and giving immediate visual or textual feedback based on their actions and the game state.
Part 1: Setting Up Score and Game State Variables
Before the game loop starts, initialize variables to track the score, game state, and acceleration (for later use).
score = 0 # Tracks the player's score
gameState = True # True while the game is ongoing, False when the game ends
acceleration = 0.1 # Initial acceleration value for the ball's movement
Part 2: Displaying the Score and Acceleration
At the beginning of the game loop, update the scene’s caption to display the current score and acceleration. This provides real-time feedback to the player.
scene.caption = "Score: " + str(score) + "\nAcceleration: " + "{:.2f}".format(acceleration)
Part 3: Incrementing Score on Successful Hits
Within the game loop, check if the ball collides with the paddle. If so, increment the score and optionally increase the ball’s acceleration to raise the difficulty.
if (ball.pos.x >= paddle.pos.x - paddle.size.x/2) and \
(ball.pos.x <= paddle.pos.x + paddle.size.x/2) and \
(ball.pos.y <= paddle.pos.y + ball.radius):
ball.velocity.y = -abs(ball.velocity.y) # Ensure the ball bounces upwards
score += 1 # Increment score
acceleration += 0.1 # Increase acceleration
Part 4: Implementing Win and Lose Conditions
After handling the ball-paddle collision, check if the player has reached a winning score or a losing condition (e.g., the ball falls below the paddle).
# Win condition
if score >= 5: # Adjust the target score as needed
gameState = False
scene.caption = "You Win! Final Score: " + str(score)
# Display a win message
win_message = text(text='YOU WON!', pos=vec(0, 5, 0), align='center', color=color.green)
# Lose condition
if ball.pos.y < paddle.pos.y - 10: # Assuming the lose condition is when the ball is far below the paddle
gameState = False
scene.caption = "Game Over. Final Score: " + str(score)
# Display a game over message
game_over_message = text(text='GAME OVER', pos=vec(0, 5, 0), align='center', color=color.red)
Assignment:
- Implement the scoring system by updating the score each time the ball hits the paddle. Reflect these changes in real-time by updating the scene’s caption.
- Introduce a win condition (e.g., reaching a certain score) and a lose condition (e.g., the ball falls below a certain point). Display appropriate messages for both conditions.
- Experiment with adjusting the target score for winning and the acceleration increment to find a balance that’s challenging yet attainable.
Worksheet 8: Polish and Finishing Touches
Objective: Finalize the game with additional features and polish.
Adding a Countdown: Before the game starts, a countdown can enhance the player’s readiness.
def countdown():
for i in range(3, 0, -1):
countdown_text = text(pos=vector(0,5,0), text=str(i), align='center', color=color.green)
sleep(1)
countdown_text.visible = False
countdown()
This function creates a countdown from 3 to 1 at the center of the scene. Each number is displayed for one second before the next number appears.
Assignment: Implement the countdown function in your game. Make sure the game starts (or resumes) right after the countdown finishes.
Win and Game Over Conditions: To conclude the game logically, define conditions for winning and losing.
# Win Condition
if score == 5:
gameState = False
label(text='YOU WON', pos=vector(0,5,0), height=10, color=color.green)
# Game Over Condition
if ball.pos.y < -21: # Assuming -21 is below the paddle
gameState = False
label(text='GAME OVER', pos=vector(0,5,0), height=10, color=color.red)
These snippets check if the player has met the win condition (score of 5) or the game over condition (ball falls below the paddle). It then displays an appropriate message.
Assignment: Incorporate win and game over conditions in your game. Display a “Game Over” message if the ball falls below the paddle and a “You Win” message if the player reaches a score of 5.#
Tom’s Complete Paddle Game
Web VPython 3.2
from vpython import *
scene = canvas(title="BOUNCE GAME:", width=450, height=450)
ball = sphere(pos=vector(0, 0, 0), size=vector(3, 3, 1), color=vector(1, 0, 0), radius=5)
paddle = box(pos=vector(0, -20, 0), size=vector(10, 2, .2), color=vector(100, 10, 2))
# Initialize ball position and velocity
ball.pos = vector(0, 0, 0) # Starting position at the center
ball.velocity = vector(5, 5, 0) # Moving 5 units per time step to the right
def countdown():
for i in range(3, 0, -1):
countdown_text = text(pos=vector(0,5,0), text=str(i), align='center', color=color.green)
sleep(1)
countdown_text.visible = False
countdown()
score = 0 # Tracks the player's score
gameState = True # True while the game is ongoing, False when the game ends
acceleration = 0.1 # Initial acceleration value for the ball's movement
scene.caption = "Score: " + str(score) + "\nAcceleration: " + "{:.2f}".format(acceleration)
# Main game loop
while gameState:
rate(30) # Controls the speed of the loop, making it run 30 times per second
dt = 1 / 30
# Increase velocity gradually
ball.velocity.y += acceleration * dt
# Update the ball's position
ball.pos = ball.pos + ball.velocity * dt
# Check for collision with the right wall
if ball.pos.x > 23: # Assuming the right boundary is at x=23
ball.velocity.x = -ball.velocity.x # Reverse the x velocity
# Check for collision with the left wall
if ball.pos.x < -23: # Assuming the left boundary is at x=-23
ball.velocity.x = -ball.velocity.x # Reverse the x velocity
# Check for collision with the top wall
if ball.pos.y > 23: # Assuming the top boundary is at y=23
ball.velocity.y = -ball.velocity.y # Reverse the y velocity
# Check for collision with the paddle
if (ball.pos.y < -19) and (ball.pos.x < paddle.pos.x + 5) and (ball.pos.x > paddle.pos.x - 5):
ball.velocity.y = -ball.velocity.y # Reverse the y velocity
score += 1 # Increment score
acceleration += 0.05 # Increase acceleration gradually
scene.caption = "Score: " + str(score) + "\nAcceleration: " + "{:.2f}".format(acceleration)
# Paddle control
if scene.mouse.pos.x < 21 and scene.mouse.pos.x > -21:
paddle.pos.x = scene.mouse.pos.x
# Check if the ball has passed the paddle (missed)
if ball.pos.y < -30: # Assuming the threshold is at y=-30
print("Game Over! Final Score: ", score)
gameState = False
break
# Win condition
if score >= 5: # Adjust the target score as needed
print("You Win! Final Score: ", score)
gameState = False
break