0

for my last year in high school i need to make this project. It is the game "pong" but instead of buttons you use your hand to move the paddles. I tried writing the code but i am stuck, it recognizes my hand but the ball and paddle only move 1 step at a time. Does anyone know how i can make it go fluent. This is my code and the part i think it is about is "p1_controls".

import pgzero, pgzrun, pygame
import math, sys, random
from enum import Enum
import mediapipe
import cv2
import time


WIDTH = 800
HEIGHT = 480
TITLE = "Hand pong"

HALF_WIDTH = WIDTH // 2
HALF_HEIGHT = HEIGHT // 2

PLAYER_SPEED = 6
MAX_AI_SPEED = 6

def normalised(x, y):
    length = math.hypot(x, y)
    return (x / length, y / length)

def sign(x):
    return -1 if x < 0 else 1


class Impact(Actor):
    def __init__(self, pos):
        super().__init__("blank", pos)
        self.time = 0

    def update(self):
        self.image = "impact" + str(self.time // 2)
        self.time += 1


class Ball(Actor):
    def __init__(self, dx):
        super().__init__("ball", (0,0))
        self.x, self.y = HALF_WIDTH, HALF_HEIGHT
        self.dx, self.dy = dx, 0
        self.speed = 5

    def update(self):
        for i in range(self.speed):
            original_x = self.x
            self.x += self.dx
            self.y += self.dy
            if abs(self.x - HALF_WIDTH) >= 344 and abs(original_x - HALF_WIDTH) < 344:
                if self.x < HALF_WIDTH:
                    new_dir_x = 1
                    bat = game.bats[0]
                else:
                    new_dir_x = -1
                    bat = game.bats[1]

                difference_y = self.y - bat.y

                if difference_y > -64 and difference_y < 64:
                    self.dx = -self.dx
                    self.dy += difference_y / 128
                    self.dy = min(max(self.dy, -1), 1)
                    self.dx, self.dy = normalised(self.dx, self.dy)
                    game.impacts.append(Impact((self.x - new_dir_x * 10, self.y)))
                    self.speed += 1
                    game.ai_offset = random.randint(-10, 10)
                    bat.timer = 10

            if abs(self.y - HALF_HEIGHT) > 220:
                self.dy = -self.dy
                self.y += self.dy

                game.impacts.append(Impact(self.pos))

    def out(self):
        return self.x < 0 or self.x > WIDTH


class Bat(Actor):
    def __init__(self, player, move_func=None):
        x = 30 if player == 0 else 760
        y = HALF_HEIGHT
        super().__init__("blank", (x, y))
        self.player = player
        self.score = 0

        if move_func != None:
            self.move_func = move_func
        else:
            self.move_func = self.ai
            
        self.timer = 0

    def update(self):
        self.timer -= 1
        y_movement = self.move_func()
        self.y = min(400, max(80, self.y + y_movement))
        frame = 0
        if self.timer > 0:
            if game.ball.out():
                frame = 2
            else:
                frame = 1

        self.image = "bat" + str(self.player) + str(frame)

    def ai(self):
        x_distance = abs(game.ball.x - self.x)
        target_y_1 = HALF_HEIGHT
        target_y_2 = game.ball.y + game.ai_offset
        weight1 = min(1, x_distance / HALF_WIDTH)
        weight2 = 1 - weight1
        target_y = (weight1 * target_y_1) + (weight2 * target_y_2)
        return min(MAX_AI_SPEED, max(-MAX_AI_SPEED, target_y - self.y))


class Game:
    def __init__(self, controls=(None, None)):
        self.bats = [Bat(0, controls[0]), Bat(1, controls[1])]
        self.ball = Ball(-1)
        self.impacts = []
        self.ai_offset = 0

    def update(self):
        for obj in self.bats + [self.ball] + self.impacts:
            obj.update()
        for i in range(len(self.impacts) - 1, -1, -1):
            if self.impacts[i].time >= 10:
                del self.impacts[i]

        if self.ball.out():
            scoring_player = 1 if self.ball.x < WIDTH // 2 else 0
            losing_player = 1 - scoring_player

            if self.bats[losing_player].timer < 0:
                self.bats[scoring_player].score += 1
                self.bats[losing_player].timer = 20

            elif self.bats[losing_player].timer == 0:
                direction = -1 if losing_player == 0 else 1
                self.ball = Ball(direction)

    def draw(self):
        screen.blit("table", (0,0))

        for obj in self.bats + [self.ball] + self.impacts:
            obj.draw()

        for p in (0,1):
            score = "{0:02d}".format(self.bats[p].score)
            for i in (0,1):
                colour = "0"
                other_p = 1 - p
                if self.bats[other_p].timer > 0 and game.ball.out():
                    colour = "2" if p == 0  else "1"
                image = "digit" + colour + str(score[i])
                screen.blit(image, (255 + (160 * p) + (i * 55), 46))

def p1_controls():
    move = 0
    drawingModule = mediapipe.solutions.drawing_utils
    handsModule = mediapipe.solutions.hands
    cap = cv2.VideoCapture(0)
    fourcc = cv2.VideoWriter_fourcc('m', 'p', '4', 'v')
    with handsModule.Hands(static_image_mode=False, min_detection_confidence=0.7, min_tracking_confidence=0.7, max_num_hands=2) as hands:
         while True:
               ret, frame = cap.read() 
               frame1 = cv2.resize(frame, (640, 480))       
               results = hands.process(cv2.cvtColor(frame1, cv2.COLOR_BGR2RGB))
           
               if results.multi_hand_landmarks != None:
                  for handLandmarks in results.multi_hand_landmarks:
                      drawingModule.draw_landmarks(frame1, handLandmarks, handsModule.HAND_CONNECTIONS)
                  
                  
                      for point in handsModule.HandLandmark:
                          normalizedLandmark = handLandmarks.landmark[point]
                          pixelCoordinatesLandmark= drawingModule._normalized_to_pixel_coordinates(normalizedLandmark.x, normalizedLandmark.y, 640, 480)
                      
                          while point == 8:
                              if normalizedLandmark.y < 0.5 or keyboard.up:
                                  move = -PLAYER_SPEED
                                  print("richting is up")
                                   
                                  
                              if normalizedLandmark.y > 0.5 or keyboard.down:
                                  move = PLAYER_SPEED
                                  print("richting is down")
                              return move
                             


def p2_controls():
    move = 0
    if keyboard.s:
        move = PLAYER_SPEED
    elif keyboard.w:
        move = -PLAYER_SPEED
    return move

class State(Enum):
    MENU = 1
    PLAY = 2
    GAME_OVER = 3

num_players = 1

space_down = False

def update():
    global state, game, num_players, space_down
    space_pressed = False
    if keyboard.space and not space_down:
        space_pressed = True
    space_down = keyboard.space

    if state == State.MENU:
        if space_pressed:
            state = State.PLAY
            controls = [p1_controls]
            controls.append(p2_controls if num_players == 2 else None)
            game = Game(controls)
        else:
            if num_players == 2 and keyboard.up:
                num_players = 1
            elif num_players == 1 and keyboard.down:
                num_players = 2
                
            game.update()

    elif state == State.PLAY:
        if max(game.bats[0].score, game.bats[1].score) > 9:
            state = State.GAME_OVER
        else:
            game.update()

    elif state == State.GAME_OVER:
        if space_pressed:

            state = State.MENU
            num_players = 1
            game = Game()

def draw():
    game.draw()

    if state == State.MENU:
        menu_image = "menu" + str(num_players - 1)
        screen.blit(menu_image, (0,0))

    elif state == State.GAME_OVER:
        screen.blit("over", (0,0))

state = State.MENU
game = Game()
pgzrun.go()
Rabbid76
  • 202,892
  • 27
  • 131
  • 174
  • maybe in `p1_controls` you shouldn't use `while`-loop to detect hand but always `return move` - if it didn't detect new hand then maybe it should return previous value. – furas May 15 '22 at 18:21
  • first you could use `print()` to see which part of code is executed and what you have in variables - it is called `"print debuging"` and it helps to see what code is doing. – furas May 15 '22 at 18:25
  • it is impossible to run it - because it needs some images - so we can't test it and you will have to debug it on your own. OR you have to reduce code to minimal working code with the same problem but without images - so we could simply copy and run it. – furas May 15 '22 at 19:01
  • the thing is that the problem is in the code for recognizing the hands. – AWwwYeEAHh May 15 '22 at 21:09
  • code in `p1_controls` should work like in `p2_controls` - it shouldn't use loop but always `return move`. But we can't run code to test it - you have to create code without images. At this moment you have to resolve this problem on your own – furas May 15 '22 at 21:26
  • you should create `cap = cv2.VideoCapture(0)` at start, not inside function `p1_controls` - and then you can run `p1_controls` many times (without `loop`) – furas May 15 '22 at 21:27
  • here is a video to show what happens: https://youtu.be/JwTO6qqWgoM – AWwwYeEAHh May 15 '22 at 21:35
  • I don't want to watch video. I would like to run code and make modifications - to test what is the probelm – furas May 15 '22 at 21:38
  • @furas i did what you said, and it works... the only thing is that the ball only moves when i move my paddle so is there to do that? – AWwwYeEAHh May 15 '22 at 21:39
  • the thing is you can't run the code without the images thats what this all is about. i need the images without it it works fine – AWwwYeEAHh May 15 '22 at 21:40
  • if we can't run it then we can't help you. And I can only suggert to use `print()` to debug code. – furas May 15 '22 at 21:41
  • maybe you should create repo on GitHub so we could download with images to test it. – furas May 15 '22 at 21:52

0 Answers0