Skip to content

Instantly share code, notes, and snippets.

@vinothpandian
Created December 19, 2012 15:32
Show Gist options
  • Select an option

  • Save vinothpandian/4337527 to your computer and use it in GitHub Desktop.

Select an option

Save vinothpandian/4337527 to your computer and use it in GitHub Desktop.
Classic Pong game in Python - using pygame
#PONG pygame
import random
import pygame, sys
from pygame.locals import *
pygame.init()
fps = pygame.time.Clock()
#colors
WHITE = (255,255,255)
RED = (255,0,0)
GREEN = (0,255,0)
BLACK = (0,0,0)
#globals
WIDTH = 600
HEIGHT = 400
BALL_RADIUS = 20
PAD_WIDTH = 8
PAD_HEIGHT = 80
HALF_PAD_WIDTH = PAD_WIDTH / 2
HALF_PAD_HEIGHT = PAD_HEIGHT / 2
ball_pos = [0,0]
ball_vel = [0,0]
paddle1_vel = 0
paddle2_vel = 0
l_score = 0
r_score = 0
#canvas declaration
window = pygame.display.set_mode((WIDTH, HEIGHT), 0, 32)
pygame.display.set_caption('Hello World')
# helper function that spawns a ball, returns a position vector and a velocity vector
# if right is True, spawn to the right, else spawn to the left
def ball_init(right):
global ball_pos, ball_vel # these are vectors stored as lists
ball_pos = [WIDTH/2,HEIGHT/2]
horz = random.randrange(2,4)
vert = random.randrange(1,3)
if right == False:
horz = - horz
ball_vel = [horz,-vert]
# define event handlers
def init():
global paddle1_pos, paddle2_pos, paddle1_vel, paddle2_vel,l_score,r_score # these are floats
global score1, score2 # these are ints
paddle1_pos = [HALF_PAD_WIDTH - 1,HEIGHT/2]
paddle2_pos = [WIDTH +1 - HALF_PAD_WIDTH,HEIGHT/2]
l_score = 0
r_score = 0
if random.randrange(0,2) == 0:
ball_init(True)
else:
ball_init(False)
#draw function of canvas
def draw(canvas):
global paddle1_pos, paddle2_pos, ball_pos, ball_vel, l_score, r_score
canvas.fill(BLACK)
pygame.draw.line(canvas, WHITE, [WIDTH / 2, 0],[WIDTH / 2, HEIGHT], 1)
pygame.draw.line(canvas, WHITE, [PAD_WIDTH, 0],[PAD_WIDTH, HEIGHT], 1)
pygame.draw.line(canvas, WHITE, [WIDTH - PAD_WIDTH, 0],[WIDTH - PAD_WIDTH, HEIGHT], 1)
pygame.draw.circle(canvas, WHITE, [WIDTH//2, HEIGHT//2], 70, 1)
# update paddle's vertical position, keep paddle on the screen
if paddle1_pos[1] > HALF_PAD_HEIGHT and paddle1_pos[1] < HEIGHT - HALF_PAD_HEIGHT:
paddle1_pos[1] += paddle1_vel
elif paddle1_pos[1] == HALF_PAD_HEIGHT and paddle1_vel > 0:
paddle1_pos[1] += paddle1_vel
elif paddle1_pos[1] == HEIGHT - HALF_PAD_HEIGHT and paddle1_vel < 0:
paddle1_pos[1] += paddle1_vel
if paddle2_pos[1] > HALF_PAD_HEIGHT and paddle2_pos[1] < HEIGHT - HALF_PAD_HEIGHT:
paddle2_pos[1] += paddle2_vel
elif paddle2_pos[1] == HALF_PAD_HEIGHT and paddle2_vel > 0:
paddle2_pos[1] += paddle2_vel
elif paddle2_pos[1] == HEIGHT - HALF_PAD_HEIGHT and paddle2_vel < 0:
paddle2_pos[1] += paddle2_vel
#update ball
ball_pos[0] += int(ball_vel[0])
ball_pos[1] += int(ball_vel[1])
#draw paddles and ball
pygame.draw.circle(canvas, RED, ball_pos, 20, 0)
pygame.draw.polygon(canvas, GREEN, [[paddle1_pos[0] - HALF_PAD_WIDTH, paddle1_pos[1] - HALF_PAD_HEIGHT], [paddle1_pos[0] - HALF_PAD_WIDTH, paddle1_pos[1] + HALF_PAD_HEIGHT], [paddle1_pos[0] + HALF_PAD_WIDTH, paddle1_pos[1] + HALF_PAD_HEIGHT], [paddle1_pos[0] + HALF_PAD_WIDTH, paddle1_pos[1] - HALF_PAD_HEIGHT]], 0)
pygame.draw.polygon(canvas, GREEN, [[paddle2_pos[0] - HALF_PAD_WIDTH, paddle2_pos[1] - HALF_PAD_HEIGHT], [paddle2_pos[0] - HALF_PAD_WIDTH, paddle2_pos[1] + HALF_PAD_HEIGHT], [paddle2_pos[0] + HALF_PAD_WIDTH, paddle2_pos[1] + HALF_PAD_HEIGHT], [paddle2_pos[0] + HALF_PAD_WIDTH, paddle2_pos[1] - HALF_PAD_HEIGHT]], 0)
#ball collision check on top and bottom walls
if int(ball_pos[1]) <= BALL_RADIUS:
ball_vel[1] = - ball_vel[1]
if int(ball_pos[1]) >= HEIGHT + 1 - BALL_RADIUS:
ball_vel[1] = -ball_vel[1]
#ball collison check on gutters or paddles
if int(ball_pos[0]) <= BALL_RADIUS + PAD_WIDTH and int(ball_pos[1]) in range(paddle1_pos[1] - HALF_PAD_HEIGHT,paddle1_pos[1] + HALF_PAD_HEIGHT,1):
ball_vel[0] = -ball_vel[0]
ball_vel[0] *= 1.1
ball_vel[1] *= 1.1
elif int(ball_pos[0]) <= BALL_RADIUS + PAD_WIDTH:
r_score += 1
ball_init(True)
if int(ball_pos[0]) >= WIDTH + 1 - BALL_RADIUS - PAD_WIDTH and int(ball_pos[1]) in range(paddle2_pos[1] - HALF_PAD_HEIGHT,paddle2_pos[1] + HALF_PAD_HEIGHT,1):
ball_vel[0] = -ball_vel[0]
ball_vel[0] *= 1.1
ball_vel[1] *= 1.1
elif int(ball_pos[0]) >= WIDTH + 1 - BALL_RADIUS - PAD_WIDTH:
l_score += 1
ball_init(False)
#update scores
myfont1 = pygame.font.SysFont("Comic Sans MS", 20)
label1 = myfont1.render("Score "+str(l_score), 1, (255,255,0))
canvas.blit(label1, (50,20))
myfont2 = pygame.font.SysFont("Comic Sans MS", 20)
label2 = myfont2.render("Score "+str(r_score), 1, (255,255,0))
canvas.blit(label2, (470, 20))
#keydown handler
def keydown(event):
global paddle1_vel, paddle2_vel
if event.key == K_UP:
paddle2_vel = -8
elif event.key == K_DOWN:
paddle2_vel = 8
elif event.key == K_w:
paddle1_vel = -8
elif event.key == K_s:
paddle1_vel = 8
#keyup handler
def keyup(event):
global paddle1_vel, paddle2_vel
if event.key in (K_w, K_s):
paddle1_vel = 0
elif event.key in (K_UP, K_DOWN):
paddle2_vel = 0
init()
#game loop
while True:
draw(window)
for event in pygame.event.get():
if event.type == KEYDOWN:
keydown(event)
elif event.type == KEYUP:
keyup(event)
elif event.type == QUIT:
pygame.quit()
sys.exit()
pygame.display.update()
fps.tick(60)
@usamasarwar36

usamasarwar36 commented Mar 7, 2017

Copy link
Copy Markdown

Nice and Simple code. Just one feedback. Please update all the lines having / to // as python 3 does not give back Integer with normal division symbol if the variables being used are not integer. hence creating a Type Error. for example:

ball_pos = [WIDTH/2,HEIGHT/2] to ball_pos = [WIDTH//2,HEIGHT//2]

Otherwise users will get TypeError: integer argument expected, got float
Rest is perfect.

@Actonwarrior

Copy link
Copy Markdown

yeah can someone please help I have the same issue as above and idk how to fix this of..
"Traceback (most recent call last):
File "pong.py", line 157, in
draw(window)
File "pong.py", line 111, in draw
if int(ball_pos[0]) >= WIDTH + 1 - BALL_RADIUS - PAD_WIDTH and int(ball_pos[1]) in range(paddle2_pos[1] - HALF_PAD_HEIGHT,paddle2_pos[1] + HALF_PAD_HEIGHT,1):
TypeError: 'float' object cannot be interpreted as an integer"

@joshcarter

Copy link
Copy Markdown

@Actonwarrior, @BrandedAlok, see the first comment about replacing '/' lines with '//' throughout the code. I had to change those on about about 6 or 8 lines to make the game run.

@hamdyaea

hamdyaea commented Dec 3, 2017

Copy link
Copy Markdown

I forked a version and modify it to Python 3
https://github.com/hamdyaea/Daylight-Pong-python3

ghost commented Dec 22, 2017

Copy link
Copy Markdown

mine is fine but how do you control the other person's one

@ktdee

ktdee commented Jan 25, 2018

Copy link
Copy Markdown

how do you make the ball go faster?

@GAMER26

GAMER26 commented Mar 10, 2018

Copy link
Copy Markdown

How to make pong such that the 2nd player can control it from another network.

@bencodestuff

Copy link
Copy Markdown

KhushThePatel you use z and s

@srawandawadi

Copy link
Copy Markdown

15 problems 15 PROBLEMS

@a-agarwal936

Copy link
Copy Markdown

Its good but we might need the introduction of some machine learning so the computer does something aswell

@justoboy

justoboy commented Jan 31, 2021

Copy link
Copy Markdown

Its good but we might need the introduction of some machine learning so the computer does something aswell

Working on it

@epic2305

epic2305 commented Apr 25, 2021

Copy link
Copy Markdown

uhh?
line 155, in
draw(window)
File "c:\Users\n\Desktop\ codes\games\pong.py", line 109, in draw
if int(ball_pos[0]) >= WIDTH + 1 - BALL_RADIUS - PAD_WIDTH and int(ball_pos[1]) in range(paddle2_pos[1] - HALF_PAD_HEIGHT,paddle2_pos[1] + HALF_PAD_HEIGHT,1):

@Adhiber

Adhiber commented Jul 1, 2021

Copy link
Copy Markdown

pygame 2.0.0.dev8 (SDL 2.0.12, python 3.8.3)
Hello from the pygame community. https://www.pygame.org/contribute.html
Traceback (most recent call last):
File "/data/user/0/ru.iiec.pydroid3/files/temp_iiec_codefile.py", line 155, in
draw(window)
File "/data/user/0/ru.iiec.pydroid3/files/temp_iiec_codefile.py", line 101, in draw
if int(ball_pos[0]) <= BALL_RADIUS + PAD_WIDTH and int(ball_pos[1]) in range(paddle1_pos[1] - HALF_PAD_HEIGHT,paddle1_pos[1] + HALF_PAD_HEIGHT,1):
TypeError: 'float' object cannot be interpreted as an integer

@yuvamoksha

Copy link
Copy Markdown

pygame 2.1.0 (SDL 2.0.16, Python 3.10.0)
Hello from the pygame community. https://www.pygame.org/contribute.html
Traceback (most recent call last):
File "e:\python saves#PONG pygame.py", line 157, in
draw(window)
File "e:\python saves#PONG pygame.py", line 111, in draw
if int(ball_pos[0]) >= WIDTH + 1 - BALL_RADIUS - PAD_WIDTH and int(ball_pos[1]) in range(paddle2_pos[1] - HALF_PAD_HEIGHT,paddle2_pos[1]

  • HALF_PAD_HEIGHT,1):
    TypeError: 'float' object cannot be interpreted as an integer
    PS E:\python saves>

@huskysiberia

Copy link
Copy Markdown

What this error?
Traceback (most recent call last):
File "C:\Users\anjel\OneDrive\Área de Trabalho\progamas úteis\Pong.py", line 168, in
draw(window)
File "C:\Users\anjel\OneDrive\Área de Trabalho\progamas úteis\Pong.py", line 120, in draw
if int(ball_pos[0]) >= WIDTH + 1 - BALL_RADIUS - PAD_WIDTH and int(ball_pos[1]) in range(
TypeError: 'float' object cannot be interpreted as an integer

@maxban97

Copy link
Copy Markdown

Nice and Simple code. Just one feedback. Please update all the lines having / to // as python 3 does not give back Integer with normal division symbol if the variables being used are not integer. hence creating a Type Error. for example:

ball_pos = [WIDTH/2,HEIGHT/2] to ball_pos = [WIDTH//2,HEIGHT//2]

Otherwise users will get TypeError: integer argument expected, got float Rest is perfect.

Worked like a charm! Or should I say PyCharm?! >:-}

@j40469968-lang

Copy link
Copy Markdown

Open World Action Adventure Game (Three.js)

Project Structure

open-world-game/
│
├── index.html
├── style.css
├── package.json
├── README.md
│
├── /assets
│   ├── /textures
│   ├── /models
│   ├── /sounds
│   └── /images
│
├── /js
│   ├── main.js
│   ├── player.js
│   ├── world.js
│   ├── enemy.js
│   ├── vehicle.js
│   ├── ui.js
│   ├── controls.js
│   ├── weather.js
│   ├── inventory.js
│   ├── missions.js
│   ├── saveSystem.js
│   └── audio.js
│
└── /shaders

Step 1: Create package.json

{
  "name": "open-world-game",
  "version": "1.0.0",
  "description": "Three.js Open World Game",
  "scripts": {
    "start": "vite"
  },
  "dependencies": {
    "three": "^0.165.0"
  },
  "devDependencies": {
    "vite": "^5.2.0"
  }
}

Step 2: Create index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Open World Game</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>

<div id="menu">
    <h1>OPEN WORLD GAME</h1>
    <button id="startBtn">Start Game</button>
</div>

<div id="hud">
    <div id="health">Health: 100</div>
    <div id="stamina">Stamina: 100</div>
    <div id="coins">Coins: 0</div>
</div>

<canvas id="gameCanvas"></canvas>

<script type="module" src="./js/main.js"></script>

</body>
</html>

Step 3: Create style.css

body {
    margin: 0;
    overflow: hidden;
    font-family: Arial, sans-serif;
    background: black;
}

canvas {
    display: block;
}

#menu {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    text-align: center;
    color: white;
    z-index: 10;
}

#menu button {
    padding: 15px 30px;
    font-size: 18px;
    cursor: pointer;
    border: none;
    background: crimson;
    color: white;
    border-radius: 10px;
}

#hud {
    position: absolute;
    top: 20px;
    left: 20px;
    color: white;
    z-index: 5;
}

Step 4: Create js/main.js

import * as THREE from 'three';
import { createWorld } from './world.js';
import { createPlayer, movePlayer } from './player.js';
import { setupControls, keys } from './controls.js';
import { createEnemy, updateEnemy } from './enemy.js';
import { setupUI } from './ui.js';
import { createWeather } from './weather.js';

const scene = new THREE.Scene();
scene.background = new THREE.Color(0x222222);

const camera = new THREE.PerspectiveCamera(
    75,
    window.innerWidth / window.innerHeight,
    0.1,
    1000
);

const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

const light = new THREE.DirectionalLight(0xffffff, 2);
light.position.set(10, 20, 10);
scene.add(light);

const ambient = new THREE.AmbientLight(0xffffff, 0.5);
scene.add(ambient);

createWorld(scene);
createWeather(scene);

const player = createPlayer(scene);
const enemy = createEnemy(scene);

camera.position.set(0, 5, 10);

setupControls();
setupUI();

function animate() {
    requestAnimationFrame(animate);

    movePlayer(player, keys);
    updateEnemy(enemy, player);

    camera.position.x = player.position.x;
    camera.position.z = player.position.z + 10;
    camera.lookAt(player.position);

    renderer.render(scene, camera);
}

animate();

window.addEventListener('resize', () => {
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();
    renderer.setSize(window.innerWidth, window.innerHeight);
});

Step 5: Create js/world.js

import * as THREE from 'three';

export function createWorld(scene) {

    const groundGeometry = new THREE.PlaneGeometry(500, 500);
    const groundMaterial = new THREE.MeshStandardMaterial({
        color: 0x1d5e2a
    });

    const ground = new THREE.Mesh(groundGeometry, groundMaterial);
    ground.rotation.x = -Math.PI / 2;
    scene.add(ground);

    for (let i = 0; i < 50; i++) {

        const buildingGeometry = new THREE.BoxGeometry(
            Math.random() * 5 + 2,
            Math.random() * 20 + 5,
            Math.random() * 5 + 2
        );

        const buildingMaterial = new THREE.MeshStandardMaterial({
            color: 0x555555
        });

        const building = new THREE.Mesh(
            buildingGeometry,
            buildingMaterial
        );

        building.position.set(
            (Math.random() - 0.5) * 200,
            5,
            (Math.random() - 0.5) * 200
        );

        scene.add(building);
    }
}

Step 6: Create js/player.js

import * as THREE from 'three';

export function createPlayer(scene) {

    const geometry = new THREE.BoxGeometry(1, 2, 1);
    const material = new THREE.MeshStandardMaterial({
        color: 0x00ffcc
    });

    const player = new THREE.Mesh(geometry, material);
    player.position.y = 1;

    scene.add(player);

    return player;
}

export function movePlayer(player, keys) {

    const speed = 0.2;

    if (keys['w']) player.position.z -= speed;
    if (keys['s']) player.position.z += speed;
    if (keys['a']) player.position.x -= speed;
    if (keys['d']) player.position.x += speed;
}

Step 7: Create js/controls.js

export const keys = {};

export function setupControls() {

    window.addEventListener('keydown', (e) => {
        keys[e.key.toLowerCase()] = true;
    });

    window.addEventListener('keyup', (e) => {
        keys[e.key.toLowerCase()] = false;
    });
}

Step 8: Create js/enemy.js

import * as THREE from 'three';

export function createEnemy(scene) {

    const geometry = new THREE.BoxGeometry(1, 2, 1);
    const material = new THREE.MeshStandardMaterial({
        color: 0xff0000
    });

    const enemy = new THREE.Mesh(geometry, material);

    enemy.position.set(10, 1, 10);

    scene.add(enemy);

    return enemy;
}

export function updateEnemy(enemy, player) {

    const direction = new THREE.Vector3();

    direction.subVectors(player.position, enemy.position);
    direction.normalize();

    enemy.position.add(direction.multiplyScalar(0.03));
}

Step 9: Create js/weather.js

import * as THREE from 'three';

export function createWeather(scene) {

    const rainGeometry = new THREE.BufferGeometry();
    const rainCount = 1000;

    const positions = [];

    for (let i = 0; i < rainCount; i++) {
        positions.push(
            Math.random() * 400 - 200,
            Math.random() * 200,
            Math.random() * 400 - 200
        );
    }

    rainGeometry.setAttribute(
        'position',
        new THREE.Float32BufferAttribute(positions, 3)
    );

    const rainMaterial = new THREE.PointsMaterial({
        color: 0xaaaaaa,
        size: 0.2
    });

    const rain = new THREE.Points(rainGeometry, rainMaterial);

    scene.add(rain);
}

Step 10: Create js/ui.js

export function setupUI() {

    const startBtn = document.getElementById('startBtn');
    const menu = document.getElementById('menu');

    startBtn.addEventListener('click', () => {
        menu.style.display = 'none';
    });
}

Step 11: Create js/inventory.js

export const inventory = [];

export function addItem(item) {
    inventory.push(item);
    console.log('Added:', item);
}

Step 12: Create js/missions.js

export const missions = [
    {
        id: 1,
        title: 'Reach The City Center',
        completed: false
    },
    {
        id: 2,
        title: 'Defeat Enemy',
        completed: false
    }
];

Step 13: Create js/saveSystem.js

export function saveGame(data) {
    localStorage.setItem('gameSave', JSON.stringify(data));
}

export function loadGame() {
    return JSON.parse(localStorage.getItem('gameSave'));
}

Step 14: Create js/audio.js

export function playMusic() {

    const audio = new Audio('/assets/sounds/music.mp3');
    audio.loop = true;
    audio.volume = 0.5;
    audio.play();
}

Step 15: Create README.md

# Open World Game

## Installation

1. Install Node.js
2. Open terminal
3. Run:

npm install

4. Start game:

npm run start

5. Open browser URL shown in terminal

## Controls

WASD = Move

Mouse = Camera

ESC = Pause

## Features

- Open World
- Enemy AI
- Weather System
- Inventory
- Missions
- Save System
- UI HUD

Advanced Features To Add Next

Multiplayer

Use:

  • Socket.io
  • Node.js server
  • Real-time synchronization

Realistic Characters

Use:

  • Mixamo animations
  • GLTFLoader
  • FBX models

Vehicle Physics

Use:

  • Cannon.js
  • Ammo.js

Shooting System

Add:

  • Raycasting
  • Bullet particles
  • Hit detection

AAA Graphics

Add:

  • Bloom effects
  • Shadows
  • HDR environment
  • SSAO
  • Motion blur

NPC System

Add:

  • Dialogue
  • Shops
  • AI paths
  • Random movement

Future Improvements

  • Zombie mode
  • Online multiplayer
  • Character customization
  • Trading system
  • Open world map
  • Quest tracker
  • Dynamic economy
  • Police chase system
  • Skill tree
  • Voice chat

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment