在 pygame 中实现 Rect 对象和球之间的碰撞检测功能 [英] Implementing a collision detect feature between a Rect object and a ball in pygame

查看:39
本文介绍了在 pygame 中实现 Rect 对象和球之间的碰撞检测功能的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

导入pygame,随机,时间# 调用所有其他函数的 main 函数,启动游戏循环,退出 pygame 并清理窗口.在里面我们创建一个游戏对象,显示表面,并通过调用游戏对象上的 play 方法开始游戏循环.还有一个带有游戏标题的固定标题.定义主():pygame.init()大小 =(500,400)表面=pygame.display.set_mode(大小)pygame.display.set_caption('Pong v2')游戏 = 游戏(表面)游戏.play()pygame.quit()# 这是我们定义类游戏的地方类游戏():# 这个类中的一个对象代表一个完整的游戏# 这里我们初始化一个游戏.self 是初始化的游戏surface 是显示窗口的surface 对象我们还设置了继续游戏和关闭窗口的默认值.我们还定义了我们运行游戏的 fps,并定义了球的速度颜色位置和半径def __init__(self,surface):# 定义表面、fps、背景颜色self.surface=表面self.FPS=120self.bg_color=pygame.Color('黑色')screen_width = surface.get_width()screen_height = surface.get_height()# 定义球属性ball_radius=10ball_pos = [random.randint(ball_radius, screen_width-ball_radius),random.randint(ball_radius, screen_height-ball_radius)]ball_color=pygame.Color('白色')ball_velocity=[2,1]self.ball=Ball(ball_pos,ball_radius,ball_color,ball_velocity,surface)# 定义桨属性rect_left=[50,450]rect_top=225rect_height=60rect_width=10self.Paddle1=Rect(rect_left[0],rect_top,rect_width,rect_height,surface)self.Paddle2=Rect(rect_left[1],rect_top,rect_width,rect_height,surface)self.game_Clock=pygame.time.Clock()self.close_clicked=Falseself.continue_game=真self.score1=0self.score2=0self.frame_counter=0定义播放(自我):# 游戏一直进行到玩家点击关闭而不是 self.close_clicked:self.handle_events()self.draw()# 如果没有设置它为假游戏将继续更新如果 self.continue_game:自我更新()self.game_Clock.tick(self.FPS)# 分数被绘制到屏幕上(不重要,这只是为下一个版本玩一个功能),我们定义分数消息的颜色字体背景等,并在得分时更新分数def draw_score(self):font_color = pygame.Color("白色")font_bg = pygame.Color("黑色")font = pygame.font.SysFont("arial", 18)text_img = font.render("玩家 1 的分数:" + str(self.score1) + ' 玩家 2 的分数:' + str(self.score2), True, font_color, font_bg)text_pos = (0,0)self.surface.blit(text_img, text_pos)# 绘制球、表面、得分和两个桨,pygame 也每帧更新一次此绘图定义绘制(自我):self.surface.fill(self.bg_color)self.draw_score()#pygame.draw.rect(self.surface,pygame.Color('blue'),(50,225,10,50))#pygame.draw.rect(self.surface,pygame.Color('red'),(450,225,10,50))self.Paddle1.draw()self.Paddle2.draw()self.ball.draw()pygame.display.update()# 得分值设置为默认值 0 我们告诉球移动并在每次更新时向帧计数器加 1.更新下一帧的游戏对象定义更新(自我):self.ball.move()self.score=0self.frame_counter+=self.frame_counter+1# 这里我们设置了一个事件循环并判断结束游戏的动作是否已经完成def handle_events(self):事件=pygame.event.get()对于事件中的事件:如果 event.type== pygame.QUIT:self.close_clicked=True# 用户定义的类球类球:# self 是要初始化的球.为初始化的球定义颜色/中心/半径def __init__(self,center,radius,color,velocity,surface):self.center=中心self.radius=半径self.color=颜色self.velocity=速度self.surface=表面# 确定屏幕尺寸并检查球的边缘是否未接触边缘.如果它接触边缘,它会反弹并反转速度定义移动(自我):screen_width=self.surface.get_width()screen_height=self.surface.get_height()屏幕尺寸=(屏幕宽度,屏幕高度)对于范围内的 i(0,len(self.center)):self.center[i]+=self.velocity[i]如果(self.center[i]<=0 + self.radius 或 self.center[i]>=screen_size[i] - self.radius):self.velocity[i]=-self.velocity[i]# 球被绘制定义绘制(自我):pygame.draw.circle(self.surface,self.color,self.center,self.radius)类矩形:def __init__(self,left,top,width,height,surface):#self.left=left#self.top=top#self.width=宽度#self.height=高度self.surface=表面self.rect=pygame.Rect(left,top,width,height)定义绘制(自我):pygame.draw.rect(self.surface,pygame.Color('red'),self.rect)定义碰撞(自我):如果 pygame.Rect.collide(x,y) == True:返回真别的:返回错误主要的()

以上是我迄今为止的工作,基本上它应该是复古街机游戏乒乓球,其中球从桨的边缘反弹,如果不是,另一侧在击中窗户边缘时得分.所以特别是项目的这一部分要求我让球从桨的前部反弹,我对如何做到这一点感到困惑.我最初的想法是在 Rect 类中使用 collidepoint 方法,如果它返回 true 将反转球的速度.但是,我无法访问类内部或类游戏中方法播放的球的中心坐标,我打算在该类游戏中对 ball 和 paddle1,paddle2 的特定实例进行这项工作,所以我没有不知道怎么做.

解决方案

Game.update 中评估球是否击中右侧的左桨,分别击中左侧的右桨.
如果球击中球拍,则分数可以增加:

class Game():# [...]定义更新(自我):self.ball.move()# 评估球是否击中右侧的左桨 (Paddle1)如果 self.ball.velocity[0] <0 和 self.Paddle1.rect.top <= self.ball.center[1] <= self.Paddle1.rect.bottom:如果 self.Paddle1.rect.right <= self.ball.center[0] <= self.Paddle1.rect.right + self.ball.radius:self.ball.velocity[0] = -self.ball.velocity[0]self.ball.center[0] = self.Paddle1.rect.right + self.ball.radiusself.score1 += 1# 评估球是否击中左侧的右侧桨 (Paddle2)如果 self.ball.velocity[0] >0 和 self.Paddle2.rect.top <= self.ball.center[1] <= self.Paddle2.rect.bottom:如果 self.Paddle2.rect.left >= self.ball.center[0] >= self.Paddle2.rect.left - self.ball.radius:self.ball.velocity[0] = -self.ball.velocity[0]self.ball.center[0] = self.Paddle2.rect.left - self.ball.radiusself.score2 += 1

通过

import pygame, random, time
# main function where we call all other functions, start the game loop, quit pygame and clean up the window. Inside we create a game object, display surface, and start the game loop by calling the play method on the game object. There is also a set caption with the title of the game.
def main():
    pygame.init()
    size =(500,400)
    surface=pygame.display.set_mode(size)
    pygame.display.set_caption('Pong v2')
    game = Game(surface)
    game.play()
    pygame.quit()
# This is where we define the class game    
class Game():
    # an object in this class represents a complete game

    # here we initialize a game. self is the game that is initialized surface is the display window surface object we also set default values for continuing the game and closing the window. we also define what fps we are running the game at, and define the velocity color position and radius of the ball
    def __init__(self,surface):

        # defining surface, fps, background color
        self.surface=surface
        self.FPS=120
        self.bg_color=pygame.Color('black')
        screen_width = surface.get_width()
        screen_height = surface.get_height()

        # defining ball attributes
        ball_radius=10
        ball_pos = [random.randint(ball_radius, screen_width-ball_radius), 
                    random.randint(ball_radius, screen_height-ball_radius)]
        ball_color=pygame.Color('white')
        ball_velocity=[2,1]
        self.ball=Ball(ball_pos,ball_radius,ball_color,ball_velocity,surface)

        # defining paddle attributes

        rect_left=[50,450]
        rect_top=225
        rect_height=60
        rect_width=10
        self.Paddle1=Rect(rect_left[0],rect_top,rect_width,rect_height,surface)
        self.Paddle2=Rect(rect_left[1],rect_top,rect_width,rect_height,surface)


        self.game_Clock=pygame.time.Clock()
        self.close_clicked=False
        self.continue_game=True
        self.score1=0
        self.score2=0
        self.frame_counter=0

    def play(self):
        # game is played until player clicks close
        while not self.close_clicked:  

            self.handle_events()

            self.draw()


            # if nothing sets this to false the game will continue to update
            if self.continue_game:
                self.update()

            self.game_Clock.tick(self.FPS)
    # score is drawn onto the screen (unimportant this is just playing with a feature for the next version), we define color font background etc of the score message and update score upon points being scored
    def draw_score(self):
        font_color = pygame.Color("white")
        font_bg    = pygame.Color("black")
        font       = pygame.font.SysFont("arial", 18)
        text_img   = font.render("Score for Player 1: " + str(self.score1) + ' Score for Player 2: ' + str(self.score2), True, font_color, font_bg)     
        text_pos   = (0,0)
        self.surface.blit(text_img, text_pos)

    # ball, surface, score, and two paddles are drawn, pygame also updates this drawing once per frame    
    def draw(self):
        self.surface.fill(self.bg_color)

        self.draw_score()
        #pygame.draw.rect(self.surface,pygame.Color('blue'),(50,225,10,50))
        #pygame.draw.rect(self.surface,pygame.Color('red'),(450,225,10,50))
        self.Paddle1.draw()
        self.Paddle2.draw()

        self.ball.draw()


        pygame.display.update()
    # score value set to default of 0 we tell ball to move and add 1 to frame counter upon each update. update game object for the next frame 
    def update(self):
        self.ball.move()
        self.score=0
        self.frame_counter+=self.frame_counter+1











    # here we setup an event loop and figure out if the action to end the game has been done
    def handle_events(self):
        events=pygame.event.get()
        for event in events:
            if event.type== pygame.QUIT:
                self.close_clicked=True
# user defined class ball            
class Ball:
    # self is the ball to intialize. color/center/radius are defined for the ball that is initialized
    def __init__(self,center,radius,color,velocity,surface):
        self.center=center
        self.radius=radius
        self.color=color
        self.velocity=velocity
        self.surface=surface
    # screen size is determined and edge of ball is checked that it is not touching the edge. if it is touching the edge it bounces and reverses velocity   
    def move(self):
        screen_width=self.surface.get_width()
        screen_height=self.surface.get_height()
        screen_size=(screen_width,screen_height)
        for i in range(0,len(self.center)):
            self.center[i]+=self.velocity[i]
            if (self.center[i]<=0 + self.radius or self.center[i]>=screen_size[i] - self.radius):
                self.velocity[i]=-self.velocity[i]
    # ball is drawn            
    def draw(self):
        pygame.draw.circle(self.surface,self.color,self.center,self.radius)


class Rect:
    def __init__(self,left,top,width,height,surface):
        #self.left=left
        #self.top=top
        #self.width=width
        #self.height=height
        self.surface=surface
        self.rect=pygame.Rect(left,top,width,height)

    def draw(self):
        pygame.draw.rect(self.surface,pygame.Color('red'),self.rect)

    def collide(self):
        if pygame.Rect.collide(x,y) == True:
            return True
        else:
            return False
















main()

Above is my work so far basically its supposed to be the retro arcade game pong where the ball bounces off of the edges of the paddles and if it doesn't the opposite side scores a point upon it hitting the edge of the window. So specifically this part of the project requires me to make the ball bounce off of the front of the paddles and I'm confused as to how to do this. My idea originally was to use the collidepoint method inside of the class Rect that if it returns true would reverse the balls velocity. However, I don't have access to the centre coordinates of the ball inside of the class or inside of the method play in the class game where I intended to make this work on the specific instances of ball and paddle1,paddle2 so I don't know how to do this.

解决方案

Evaluate if the ball hits the left paddle at the right, respectively the right paddle at the left in Game.update.
If the ball hits the paddle the the score can be incremented:

class Game():

    # [...]

    def update(self):
        self.ball.move()

        # evaluate if Ball hits the left paddle (Paddle1) at the right
        if self.ball.velocity[0] < 0 and self.Paddle1.rect.top <= self.ball.center[1] <= self.Paddle1.rect.bottom:
           if self.Paddle1.rect.right <= self.ball.center[0] <= self.Paddle1.rect.right + self.ball.radius:
                self.ball.velocity[0] = -self.ball.velocity[0]
                self.ball.center[0] = self.Paddle1.rect.right + self.ball.radius
                self.score1 += 1

        # evaluate if Ball hits the right paddle (Paddle2) at the left
        if self.ball.velocity[0] > 0 and self.Paddle2.rect.top <= self.ball.center[1] <= self.Paddle2.rect.bottom:
           if self.Paddle2.rect.left >= self.ball.center[0] >= self.Paddle2.rect.left - self.ball.radius:
                self.ball.velocity[0] = -self.ball.velocity[0]
                self.ball.center[0] = self.Paddle2.rect.left - self.ball.radius
                self.score2 += 1 

Get the state of the keys by pygame.key.get_pressed() and change the position of the paddles is Game.handle_events.

e.g. Move the left paddle by w / s and the right paddle by UP / DOWN:

class Game():

    # [...]

    def handle_events(self):
        events=pygame.event.get()
        for event in events:
            if event.type== pygame.QUIT:
                self.close_clicked=True
        keys = pygame.key.get_pressed()
        if keys[pygame.K_w]:
            self.Paddle1.rect.top = max(0, self.Paddle1.rect.top - 3)
        if keys[pygame.K_s]:
            self.Paddle1.rect.bottom = min(self.surface.get_height(), self.Paddle1.rect.bottom + 3)
        if keys[pygame.K_UP]:
            self.Paddle2.rect.top = max(0, self.Paddle2.rect.top - 3)
        if keys[pygame.K_DOWN]:
            self.Paddle2.rect.bottom = min(self.surface.get_height(), self.Paddle2.rect.bottom + 3)

这篇关于在 pygame 中实现 Rect 对象和球之间的碰撞检测功能的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆