2

そこで、上に移動する円を生成するこのミニ パーティクル エフェクトを用意しました。煙のように見せたい。私は多くの問題を抱えています。

  1. まず、再帰的にしたいので、粒子が一番上に到達すると元の場所に戻り、再び開始されます。私が持っているものは少し機能しますが、正確ではありません。
  2. もう 1 つは、実際には煙のように見えないということです。見栄えを良くするための変更を提案できますか?
  3. また、これをゲームに追加したいのですが、これをゲームで呼び出し可能にするにはどうすればよいので、パーティクルを呼び出して場所を指定すると、そこに表示されます。誰でもこれを手伝ってもらえますか?

マイコード

import pygame,random
from pygame.locals import *

xmax = 1000    #width of window
ymax = 600     #height of window

class Particle():
    def __init__(self, x, y, dx, dy, col):
        self.x = x
        self.y = y
        self.col = col
        self.ry = y
        self.rx = x
        self.dx = dx
        self.dy = dy

    def move(self):
        if self.y >= 10:
            if self.dy < 0:
                self.dy = -self.dy

        self.ry -= self.dy
        self.y = int(self.ry + 0.5)

        self.dy -= .1
        if self.y < 1:
            self.y += 500

def main():
    pygame.init()
    screen = pygame.display.set_mode((xmax,ymax))
    white = (255, 255, 255)
    black = (0,0,0)
    grey = (128,128,128)

    particles = []
    for part in range(25):
        if part % 2 > 0: col = black
        else: col = grey
        particles.append( Particle(random.randint(500, 530), random.randint(0, 500), 0, 0, col))

    exitflag = False
    while not exitflag:
        for event in pygame.event.get():
            if event.type == QUIT:
                exitflag = True
            elif event.type == KEYDOWN:
                if event.key == K_ESCAPE:
                    exitflag = True

        screen.fill(white)
        for p in particles:
            p.move()
            pygame.draw.circle(screen, p.col, (p.x, p.y), 8)

        pygame.display.flip()
    pygame.quit()

if __name__ == "__main__":
    main()
4

2 に答える 2

4

私はあなたのコードにいくつかの主要な編集を加えました. 手始めに、私はあなたのクラスを大幅にクリーンアップしました。引数と__init__関数から始めましょう。

まず、500 下げてリセットするのではなく、パーティクルは開始点として設定された場所に移動します。__init__開始位置は、ゲーム内ではなく関数内でランダムに選択されるようになりました。あなたの不必要な議論もいくつか取り除きました。

あなたのクラスのmove機能では、かなり単純化しました。パーティクルがリセットする必要があるかどうかを検出するために、パーティクルが 0 を超えているかどうかを確認するだけです。上に行くのは、y を 1 だけ減らすだけです。追加した変更は、x がランダムに変化し、右に行くことです。そして、左。これにより、煙の見た目がより良く/よりリアルになります。

私はあなたのコードの残りの部分に多くの変更を加えていません。Particle新しい引数に合わせてクラスの呼び出しを変更しました。視覚効果のために、もう一度大量のパーティクルを作成しました。また、視覚効果のために描かれた円のサイズを大幅に縮小しました (わかりますか?)。パーティクルが超音速で移動しないように、クロックも追加しました。

これが最終的なコードです。気に入ってくれるといいな。

import pygame,random
from pygame.locals import *

xmax = 1000    #width of window
ymax = 600     #height of window

class Particle():
    def __init__(self, startx, starty, col):
        self.x = startx
        self.y = random.randint(0, starty)
        self.col = col
        self.sx = startx
        self.sy = starty

    def move(self):
        if self.y < 0:
            self.x=self.sx
            self.y=self.sy

        else:
            self.y-=1

        self.x+=random.randint(-2, 2)

def main():
    pygame.init()
    screen = pygame.display.set_mode((xmax,ymax))
    white = (255, 255, 255)
    black = (0,0,0)
    grey = (128,128,128)

    clock=pygame.time.Clock()

    particles = []
    for part in range(300):
        if part % 2 > 0: col = black
        else: col = grey
        particles.append( Particle(515, 500, col) )

    exitflag = False
    while not exitflag:
        for event in pygame.event.get():
            if event.type == QUIT:
                exitflag = True
            elif event.type == KEYDOWN:
                if event.key == K_ESCAPE:
                    exitflag = True

        screen.fill(white)
        for p in particles:
            p.move()
            pygame.draw.circle(screen, p.col, (p.x, p.y), 2)

        pygame.display.flip()
        clock.tick(50)
    pygame.quit()

if __name__ == "__main__":
    main()

アップデート

コードにパーティクルを追加するには、上記のコードで行ったことを実行するだけです。それは正常に動作します。煙の発生を示すために何かをしたい場合は、一時停止時間を引数に入れ、その時間が経過するまで煙の動きを抑制します。それが追加された新しいクラス:

class Particle():
    def __init__(self, startx, starty, col, pause):
        self.x = startx
        self.y = starty
        self.col = col
        self.sx = startx
        self.sy = starty
        self.pause = pause

    def move(self):
        if self.pause==0:
            if self.y < 0:
                self.x=self.sx
                self.y=self.sy

            else:
                self.y-=1

            self.x+=random.randint(-2, 2)

        else:
            self.pause-=1

新しいパーティクルを作成するために必要なコード:

for part in range(1, A):
    if part % 2 > 0: col = black
    else: col = grey
    particles.append( Particle(515, B, col, round(B*part/A)) )

A と B は変数です (A には約 300 をお勧めします。B は Y 値になります)

新しいコードは、開始位置でパーティクルをスポーンさせ、途切れることなく継続的に上昇させます。お楽しみください。

于 2013-02-13T20:24:20.287 に答える
1

Particle特にクラスでは、コードに多くの変更を加えました。
このコードにはかなり不可解なことがありますが、現在のコードよりも柔軟性があります。

ここで、私はあなたのクラス
をかなり文字通り書き直しました。 を変更する以外に、多くの引数(正確には7)を取るために、 三角法と粒子へのモジュールを使用して、管理を容易にしました(数学が得意な場合)。また、メソッドをに追加し、コードを読みやすくしました。@PygameNerdと 同じように、最大​​fpsを制限するための時計を追加しました。イベント処理は変更していませんが、ループでand関数を使用しています。Particle
__init__
mathmovebouncedrawParticle
bouncedrawfor p in particles:

import pygame, random, math

def radians(degrees):
    return degrees*math.pi/180

class Particle:
    def __init__(self, (x, y), radius, speed, angle, colour, surface):
        self.x = x
        self.y = y
        self.speed = speed
        self.angle = angle
        self.radius = 3
        self.surface = surface
        self.colour = colour
        self.rect = pygame.draw.circle(surface,(255,255,0),
                           (int(round(x,0)),
                            int(round(y,0))),
                           self.radius)
    def move(self):
        """ Update speed and position based on speed, angle """
        # for constant change in position values.
        self.x += math.sin(self.angle) * self.speed
        self.y -= math.cos(self.angle) * self.speed
        # pygame.rect likes int arguments for x and y
        self.rect.x = int(round(self.x))
        self.rect.y = int(round(self.y))

    def draw(self):
        """ Draw the particle on screen"""
        pygame.draw.circle(self.surface,self.colour,self.rect.center,self.radius)

    def bounce(self):
        """ Tests whether a particle has hit the boundary of the environment """

        if self.x > self.surface.get_width() - self.radius: # right
            self.x = 2*(self.surface.get_width() - self.radius) - self.x
            self.angle = - self.angle

        elif self.x < self.radius: # left
            self.x = 2*self.radius - self.x
            self.angle = - self.angle            

        if self.y > self.surface.get_height() - self.radius: # bottom
            self.y = 2*(self.surface.get_height() - self.radius) - self.y
            self.angle = math.pi - self.angle

        elif self.y < self.radius: # top
            self.y = 2*self.radius - self.y
            self.angle = math.pi - self.angle

def main():
    xmax = 640    #width of window
    ymax = 480     #height of window
    white = (255, 255, 255)
    black = (0,0,0)
    grey = (128,128,128)

    pygame.init()
    screen = pygame.display.set_mode((xmax,ymax))
    clock = pygame.time.Clock()

    particles = []

    for i in range(1000):
        if i % 2:
            colour = black
        else:
            colour = grey
        # for readability
        x = random.randint(0, xmax)
        y = random.randint(0, ymax)
        speed = random.randint(0,20)*0.1
        angle = random.randint(0,360)
        radius = 3
        particles.append( Particle((x, y), radius, speed, angle, colour, screen) )

    done = False
    while not done:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                done = True
                break
            elif event.type == pygame.KEYDOWN:
                if event.key == pygame.K_ESCAPE:
                    done = True
                    break
        if done:
            break

        screen.fill(white)
        for p in particles:
            p.move()
            p.bounce()
            p.draw()

        clock.tick(40)

        pygame.display.flip()
    pygame.quit()

if __name__ == "__main__":
    main()
于 2013-02-14T17:45:26.703 に答える