【问题标题】:Problem with the smoothness of the fly's movement苍蝇运动的流畅性问题
【发布时间】:2021-11-14 01:58:15
【问题描述】:

我正在学习编程并尝试编写自己的简单 pgzero 游戏。尝试在 def update(): 中对随机坐标进行平滑的飞行运动。尝试了动画,不幸的是失败了,最终使用了 randint 和 time.sleep (1)。 苍蝇从一个地方跳到另一个地方,没有流动性。我不知道该怎么办。有人可以帮我解决问题吗?

import pgzrun
from pgzero.builtins import  Actor, animate, keys
from random import Random, randint
import time
import os

WIDTH = 800
HEIGHT = 600
TITLE = 'Zabij Muchę'
ICON = 'data/mucha.png'

tlo = Actor('background')

mucha = Actor('fly')
x=randint(150, 650)
y=randint(100,500)
mucha.x = x
mucha.y = y
muchaSpeed = 2
muchaLife = True

zabitych = 0
pudlo = 0

def killed_fly():
    killed = screen.draw.text('Mucha zabita!', (280, 350), color=(255,0 ,0), fontsize=60, alpha=0.8)
    
def draw_score():
    screen.draw.text('Trafione:', (5,10), color=(0, 128, 128))
    screen.draw.text(str(zabitych), (100,10), color=(0, 128, 0))

    screen.draw.text('Pudło:', (5,30), color=(0, 128, 128))
    screen.draw.text(str(pudlo), (100,30), color=(0, 128, 0))

def on_mouse_down(pos):
    global zabitych
    global pudlo
    if mucha.collidepoint(pos):
        update()
        zabitych += 1
        mucha.image=('fly-swatter')
        time.sleep(2)
        muchaLife = False        
    else:
        pudlo += 1
        
def update():
    if muchaLife == True:
        time.sleep(1)
        x_los = randint(150, 650)
        y_los = randint(100,500)
        mucha.x = x_los
        mucha.y = y_los
        
        

def draw():
    tlo.draw()
    mucha.draw()

    draw_score()

pgzrun.go()

【问题讨论】:

  • 你只运行update() if mucha.collidepoint(pos) 所以在其他情况下它可能不会移动它,这可能会产生问题。如果你想在一个方向上平稳移动,那么你应该选择更小的值move_xmove_y 以及重复它的次数 - 如果它给出sin(angle)*move_x + cos(angle) * move_y = muchaSpeed 会很好 - 并且重复mucha.x += move_x *delta_timemucha.y += move_y *delta_time , repeate -= 1 在每个 update 直到 repeate 将为零(PL:Powodzenia :))
  • 你也可以使用mucha.x += randint(-5, 5) mucha.y += randint(-5, 5)(没有sleep(1)),它会比以前飞得更好。
  • 删除time.sleep()的所有调用。更新取决于pygame.time.get_ticks()
  • 在之前的评论中,我使用文字as @Rabbid76 already said 通知OP 我同意您的意见。我想在你的评论中添加额外的信息。这不是直接给您的信息。
  • @Rabbid76 没问题,我认为这可能是两个问题之一(1)英语不是我的母语(可能不是你的母语),我的英语可能有一些错误文本(2)你没有阅读完整的评论 - 每天都有很多问题和 cmets 所以有时我没有阅读全文(或没有仔细阅读),我希望你有同样的(我看到你的答案在许多 PyGame 问题中)。

标签: python pgzero


【解决方案1】:

我解决了这样的问题:

import pgzrun
import pygame
from pgzero.builtins import  Actor, animate, keys
from random import Random, randint
import time
import os

WIDTH = 800
HEIGHT = 600
TITLE = 'Zabij Muchę'
ICON = 'data/mucha.png'

tlo = Actor('background')

mucha = Actor('fly')
x_los=int(randint(150, 650))
y_los=int(randint(100,500))
mucha.x = x_los
mucha.y = y_los

muchaSpeed = 0.05
muchaLife = True

zabitych = 0
pudlo = 0
runda = 100

def on_mouse_down(pos):
    global zabitych
    global pudlo
    global muchaLife
    if mucha.collidepoint(pos):
        update()
        zabitych += 10
        muchaLife = False
        mucha.image=('fly-swatter')
        pygame.time.wait(5)
                   
def update():
    global x_los
    global y_los
    global runda
    global muchaSpeed
    i = int(randint(0, 3))
    t = 0
    if muchaLife == True:
        if i == 0:
            while t <= runda:
                x_los += muchaSpeed
                y_los += muchaSpeed
                mucha.x = x_los
                mucha.y = y_los
                pygame.time.wait(1)
                t += 1
        elif i == 1:
            while t <= runda:
                x_los -= muchaSpeed
                y_los -= muchaSpeed
                mucha.x = x_los
                mucha.y = y_los
                pygame.time.wait(1)
                t += 1
        elif i == 2:
            while t <= runda:
                x_los -= muchaSpeed
                y_los += muchaSpeed
                mucha.x = x_los
                mucha.y = y_los
                pygame.time.wait(1)
                t += 1
        elif i == 3:
            while t <= runda:
                x_los += muchaSpeed
                y_los -= muchaSpeed
                mucha.x = x_los
                mucha.y = y_los
                pygame.time.wait(1)
                t += 1

def draw():
    tlo.draw()
    mucha.draw()
    draw_score()
    if muchaLife == False:
        killed_draw()

def killed_draw():
    screen.draw.text('Mucha zabita!', (280, 350), color=(255,0 ,0), fontsize=60, alpha=0.8)
    
def draw_score():
    screen.draw.text('Punkty:', (5,10), color=(0, 128, 128))
    screen.draw.text(str(zabitych), (100,10), color=(0, 128, 0))

pgzrun.go()

我还想将游戏划分为难度级别。不幸的是,我不知道该怎么做,也不知道在哪里可以了解游戏关卡的基础知识。

下一个问题是用十字准线代替鼠标标记,例如,我不知道如何在任何地方做。 提前感谢您的帮助。

【讨论】:

    【解决方案2】:

    我昨天开始写这个答案,但与此同时你解决了你的问题:) 但我把我的代码,也许它对某人有用。它展示了如何使用scheduleranimate

    顺便说一句:我说波兰语,但我将所有变量重命名为英语(并转换文本),因为它是首选 - 更多信息请参阅 PEP 8 -- Style Guide for Python Code


    主要问题是您使用sleep() 会阻止所有代码,而不能阻止其他元素。

    在游戏和 GUI 框架中,您不应该使用 sleep() 和长时间运行的代码 - 它可能需要特殊的非阻塞函数来休眠 - 例如 pygame.time.get_ticks() - 或者它需要在单独的线程中运行代码(但它可以给其他问题)。


    我以前从未使用过pgzero,但我创建了代码(没有sleep),它使用小步骤随机飞行x += random.randint(-5, 5)y += random.randint(-5, 5)。我使用Clock.scheduler() 而不是sleep 在死后几秒钟重新启动/重生飞行。

    在这个版本中,苍蝇会做出许多小的随机动作。

    import pgzrun
    from pgzero.builtins import Actor, animate, keys
    import random
    import time
    import os
    
    # --- constants ---
    
    WIDTH = 800
    HEIGHT = 600
    TITLE = 'KILL FLY!'
    #ICON = 'data/fly.png'
    
    # --- functions ---
    
    def killed_fly():
        screen.draw.text('Fly killed!', (280, 350), color=(255,0 ,0), fontsize=60, alpha=0.8)
        
    def draw_score():
        screen.draw.text('Killed:', (5,10), color=(0, 128, 128))
        screen.draw.text(str(killed), (100,10), color=(0, 128, 0))
    
        screen.draw.text('Missed:', (5,30), color=(0, 128, 128))
        screen.draw.text(str(missed), (100,30), color=(0, 128, 0))
    
    def respawn():
        fly.x = random.randint(150, WIDTH-150)
        fly.y = random.randint(100, HEIGHT-100)
        fly.life = True
        fly.image = 'fly'
    
    def on_mouse_down(pos):
        global killed
        global missed
        
        if fly.collidepoint(pos):
            killed += 1
            fly.life = False        
            fly.image = 'fly-swatter'
            clock.schedule(respawn, 1.0)
        else:
            missed += 1
            
    def update():
        if fly.life:
            fly.x += random.randint(-5, 5)
            fly.y += random.randint(-5, 5)
    
            # keep inside window
            if fly.left < 0:
               fly.left = 0
            elif fly.right > WIDTH:
               fly.right = WIDTH
    
            if fly.top < 0:
               fly.top = 0
            elif fly.bottom > HEIGHT:
               fly.bottom = HEIGHT
                    
    def draw():
        background.draw()
        fly.draw()
        draw_score()
        if not fly.life:
           killed_fly()
    
    # --- main ---
    
    killed = 0
    missed = 0
    
    background = Actor('background')
    
    fly = Actor('fly')
    #fly.speed = 2
    
    respawn() # (re)set some values at start
    
    pgzrun.go()
    

    接下来我创建了使用animate() 移动飞行的版本,我不需要update() 中的代码。函数animate() 使用on_finished=... 再次运行此函数,以便进行下一步。

    import os
    import random
    import pgzrun
    from pgzero.builtins import  Actor, animate, keys
    
    # --- constants ---
    
    WIDTH = 512
    HEIGHT = 512
    TITLE = 'KILL FLY!'
    #ICON = 'data/fly.png'
    
    # --- functions ---
    
    def killed_fly():
        text_killed = screen.draw.text('Fly killed!', (280, 350), color=(255,0 ,0), fontsize=60, alpha=0.8)
        
    def draw_score():
        screen.draw.text('Killed:', (5,10), color=(0, 128, 128))
        screen.draw.text(str(killed), (100,10), color=(0, 128, 0))
    
        screen.draw.text('Missed:', (5,30), color=(0, 128, 128))
        screen.draw.text(str(missed), (100,30), color=(0, 128, 0))
    
    def respawn():
        """reset some values before every respawn"""
        fly.x = random.randint(150, WIDTH-150)
        fly.y = random.randint(100, HEIGHT-100)
        fly.life = True
        fly.image = 'fly'
        animate_fly()
        
    def animate_fly():
        global anim
        
        new_x = random.randint(5, WIDTH-5)
        new_y = random.randint(5, HEIGHT-5)
        anim = animate(fly, pos=(new_x, new_y), duration=3, on_finished=animate_fly)
        
    def on_mouse_down(pos):
        global killed
        global missed
        
        if fly.collidepoint(pos):
            
            if anim:
                anim.stop()
                
            killed += 1
            fly.life = False        
            fly.image = 'fly-swatter'
            clock.schedule(respawn, 1.0)
        else:
            missed += 1
            
    def update():
        pass
                
    def draw():
        background.draw()
        fly.draw()
        draw_score()
        if not fly.life:
           killed_fly()
    
    # --- main ---
    
    killed = 0
    missed = 0
    anim = None
    
    background = Actor('background')
    
    fly = Actor('fly')
    fly.speed = 2
    
    respawn()   # st
    
    pgzrun.go()
    

    编辑:

    使用clock.scheduler 每 5 秒更改一次级别的版本。它将新苍蝇添加到列表中并更新所有苍蝇的速度。

    为了简单起见,我创建了 Fly(Actor) 类以在类中包含所有属性和函数。

    import os
    import random
    import pgzrun
    from pgzero.builtins import  Actor, animate, keys
    
    # --- constants ---
    
    WIDTH = 512
    HEIGHT = 512
    TITLE = 'KILL FLY!'
    
    # --- classes ---
    
    class Fly(Actor):
    
        def __init__(self, *args, speed=2, **kwargs):
            super().__init__(*args, **kwargs)
            self.speed = speed
            self.reset()
            
        def reset(self):
            """reset some values before every respawn"""
            self.x = random.randint(150, WIDTH-150)
            self.y = random.randint(100, HEIGHT-100)
            self.life = True
            self.image = 'fly'
            self.animate()
    
        def animate(self):
            new_x = random.randint(5, WIDTH-5)
            new_y = random.randint(5, HEIGHT-5)
            
            distance = self.distance_to((new_x, new_y))
            duration = (distance/self.speed)/50
            
            self.anim = animate(self, pos=(new_x, new_y), duration=duration, on_finished=self.animate)
            
        def check_collision(self, pos):
            if self.collidepoint(pos) and self.life:
                
                if self.anim:
                    self.anim.stop()
    
                self.life = False        
                self.image = 'fly-swatter'
                clock.schedule(self.reset, 1.0)
    
                return True
            
            else:
                return False                
        
    # --- functions ---
    
    def killed_fly():
        screen.draw.text('Fly killed!', (280, 350), color=(255,0 ,0), fontsize=60, alpha=0.8)
        
    def draw_score():
        screen.draw.text('Killed:', (5,10), color=(0, 128, 128))
        screen.draw.text(str(killed), (100,10), color=(0, 128, 0))
    
        screen.draw.text('Missed:', (5,30), color=(0, 128, 128))
        screen.draw.text(str(missed), (100,30), color=(0, 128, 0))
    
        screen.draw.text('Level:', (WIDTH-105,10), color=(0, 128, 128))
        screen.draw.text(str(level), (WIDTH-45,10), color=(0, 128, 0))
        
    def on_mouse_down(pos):
        global killed
        global missed
    
        hit = False    
        
        for fly in flies:
            if fly.check_collision(pos):
                killed += 1
                hit = True
                
        if not hit:
            missed += 1
        
    #def on_key_down(key):
    #    global paused
    #    
    #    if key == keys.SPACE:
    #        paused = not paused    
                
    def update():
        pass
                
    def draw():
        background.draw()
        
        for fly in flies:
            fly.draw()
            
        draw_score()
    
        #if paused:
        #    screen.draw.text('PAUSE', center=(WIDTH//2, HEIGHT//2), color=(0, 0, 0), fontsize=150)
                        
        #if not fly.life:
        #   killed_fly()
    
    def level_up():
        global level
        global speed
        
        # level number 
        level += 1
        
        # bigger speed for flies
        speed += .5
        
        # add new fly with new speed (it will automaticaly run `animate` with this speed
        flies.append(Fly('fly', speed=speed))
        
        # change speed for other flies
        for fly in flies:
            fly.speed = speed
            
        # run it again after 5 seconds
        clock.schedule(level_up, 5.0)
        
    # --- main ---
    
    #paused = False
    
    level  = 1   # current level
    speed  = 2   # current speed
    
    killed = 0
    missed = 0
    
    background = Actor('background')
    
    # create list with only one fly
    flies = [
      Fly('fly'),
    ]
    
    # update level after 5 seconds
    clock.schedule(level_up, 5.0)
    
    pgzrun.go()
    

    顺便说一句:当您按下 Space 时,我尝试添加功能 Pause,但似乎 animate() 没有暂停它的方法 - 它需要创建自己的 animate()

    (使用OBS录制并使用ffmpeg转换为动画.gif


    想运行它的人的图像。

    images/background.png

    (来自维基百科的图片Lenna

    images/fly.png

    images/fly-swatter.png

    fly 在免费的Inkscape 中创建为.svg 并导出到.png

    【讨论】:

    • @SlavoHeys PyGame jest chyba najstarszym modułem do gier w Pythonie więc można oczekiwać najwięcej informatcji w internecie。 Do tego opiera się na bibliotece C/C++ SDL Simple DirectMedia Layer , która jest popularna do tworzenia gier np. w sklepie Steam więc jak znasz PyGame to łatwiej się przesiąść na SDL i C/C++ i pisać do tego sklepu - pisanie bezpośrednio w Pythonie raczej nie jest popularne。 Ale jak nazwa simple oznacz też, że ma tylko podstawowe funkcje i wiele trzeba samemu dopisać, np. mainloop(事件循环),动画,GUI。
    • @SlavoHeys modul PGZero dodaje kilka rzeczy aby ułatwić pisanie - np。动画 - ale ukrywa podstawowe funkcje SDL。 Więcej funkcji (np. GUI) można jednak dostać w module Arcade, która jest oparty na pyglet i OpenGL。 Jeśli jednak chcesz pisać na wiele urządzeń i systemów to raczej zmień język bo Python słabo tu się nadaje。 NP。 GodotEngine potrafi tworzyć na wiele systemów i posiada język skryptowy podobny do Pythona。
    【解决方案3】:

    对于更改游戏中的状态(例如状态菜单/暂停/游戏),我建议您使用 python-statemachine。 https://pypi.org/project/python-statemachine/

    如果您遇到 pgzero 文档中没有的问题

    https://pygame-zero.readthedocs.io/en/stable/

    简单地说:如果有 pgzero 不能做的事情,你必须向下一层,这意味着你需要使用 pygame( pgzero 是基于 pygame 的,所以如果你导入了 pgzero,pygame 语法应该可以正常工作,但是如果不仅仅是import pygame。)

    例如,我用这个改变了鼠标光标 pygame.mouse.set_cursor(pygame.cursors.broken_x) 基于此文档 https://www.pygame.org/docs/ref/mouse.html#pygame.mouse.set_cursor

    pygame.mouse.set_cursor(pygame.cursors.broken_x)

    pygame 本身提供了一个下水道游标,但对于自定义游标,我想你必须在谷歌上搜索更多。

    【讨论】:

      猜你喜欢
      • 2010-12-18
      • 2022-08-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多