2017-06-15 16 views
0

私はpygameでpygameで開発されたゲームの始まりを、​​3210のチュートリアルの次のものにしています。それぞれmain.py、player.py、walls.py(プレーヤーと壁クラスがあります)があります。プレーヤークラスには、衝突の検出と移動のためのコードが含まれています。残念なことに、プレイヤーはタイルを避けますが、衝突時には予想される動き(停止のみ)ではなく、画面の右側の位置に移動します。誰もがこれの論理を助け、衝突時の誤った/望ましくない動きを修正することができますか?以下は、main.py、player.py、walls.pyの3つのファイルです。 MAIN.PYpygame不正確な衝突の検出と移動

#main.py 
import pygame 
import random 
from player import Player 
from collectable import Collectable 
from walls import Wall 

pygame.init() 
BLACK=(0,0,0) 
WHITE=(255,255,255) 
RED=(255,0,0) 
GREEN =(0,255,0) 

BLUE=(0,0,255) 
GOLD=(255,215,0) 
WIDTH=500 
HEIGHT=500 
size= (WIDTH,HEIGHT) 
screen=pygame.display.set_mode(size) 
pygame.display.set_caption("The Life Game") 


done = False 
clock=pygame.time.Clock() 
wall_list=pygame.sprite.Group() 
all_sprites = pygame.sprite.Group() 
enemy_list = pygame.sprite.Group() 
player=Player() 
player.walls=wall_list 

all_sprites.add(player) 


for i in range(random.randrange(100,200)): 
     whiteStar = Collectable(WHITE, 3, 3, "White Star", "Rect") 
     whiteStar.rect.x = random.randrange(size[0]) 
     whiteStar.rect.y = random.randrange(size[1]) 
     all_sprites.add(whiteStar) 

for i in range(50): 

    enemy = Collectable(RED,6, 6,"Enemy","Ellipse") 
    enemy.rect.x = random.randrange(300) 
    enemy.rect.y = random.randrange(300) 
    enemy_list.add(enemy) 
    all_sprites.add(enemy) 

coin1 = Collectable(GOLD,50,50,"Coin","Ellipse") 
coin1.rect.x=440 
coin1.rect.y=0 
all_sprites.add(coin1) 

coin2 = Collectable(GOLD,50,50,"Coin","Ellipse") 
coin2.rect.x=0 
coin2.rect.y=440 
all_sprites.add(coin2) 

enemy = Collectable(RED,100,100,"Enemy","Ellipse") 
enemy.rect.x=70 
enemy.rect.y=230 
all_sprites.add(enemy) 

#Make the walls (x_pos,y_pos, width, height,colour) 



wall=Wall(0,0,10,600,GREEN) 
wall_list.add(wall) 
all_sprites.add(wall_list) 

wall = Wall(50, 300, 400, 10,RED) 
wall_list.add(wall) 
all_sprites.add(wall_list) 

wall = Wall(10, 200, 100, 10,BLUE) 
wall_list.add(wall) 
all_sprites.add(wall_list) 


score=0 
health=100 

#- - - - - - - - - - - - - -Main Program Loop - - - - - - - - - - - - - - - - 
def main(): 
     done=False 
     score=0 
     health=100 
     while not done: 


        #- - - - - - Main event loop (this is where code for handling keyboard and mouse clicks will go) 
     #Loop until the user clicks the 'x' button (to close program) 
        for event in pygame.event.get(): #User does something 
          if event.type == pygame.QUIT: #If the user clicked close 
             done = True #set the done flag to 'true' to exit the loop 

        keys = pygame.key.get_pressed() #checking pressed keys 
        if keys[pygame.K_LEFT]: 
        player.moveLeft(5) 
        if keys[pygame.K_RIGHT]: 
        player.moveRight(5) 
        if keys[pygame.K_UP]: 
        player.moveUp(5) 
        if keys[pygame.K_DOWN]: 
        player.moveDown(5)     


       #>>----------DRAW SECTION ----------------------------------- 
        #Clear the screen to BLACK. Any drawing commands should be put BELOW this or they will be reased with this command 
        screen.fill(BLACK) 



        #Select the font to be used (size, bold, italics, etc) 
        font_score = pygame.font.SysFont('Calibri',20,True,False) 
        font_health = pygame.font.SysFont('Calibri',20,True,False) 
       #Printing a variable (score or health) to the screen involves converting the score (if integer) to a string first.score_label = font_score.render("Score: " + str(score),True,BLACK) 
        health_label = font_health.render("Health: "+str(health),True,WHITE) 
        score_label = font_score.render("Score: " + str(score),True, WHITE) 
       #Now we can use this line of code to put the image of the text on the screen at a given position 
        screen.blit(score_label,[100,480]) 
        screen.blit(health_label,[190,480]) 


        #>>---------UPDATE SECTION/Put the logic of your game here (i.e. how objects move, when to fire them, etc) 


        all_sprites.update() 

        if coin1.collision_with(player): 
         score=score+1 
         coin1.kill() 
         coin1.rect.x=-20 
         coin1.rect.y=-330 

        if coin2.collision_with(player): 
         score=score+1 
         coin2.kill() 
         coin2.rect.x=-20 
         coin2.rect.y=-330 

        if enemy.collision_with(player): 
         health=health-25 
         enemy.kill() 
         enemy.rect.x=-20 
         enemy.rect.y=-330 

        enemy.update() 





     #-------------PRINTING VARIABLES LIKE SCORE TO SCREEN 
        #Any drawing/graphics code should go here 
        all_sprites.draw(screen) 

        #Update the screen to show whatever you have drawn 
        pygame.display.flip() 

        #Set the frames per second (e.g. 30, 60 etc) 
        clock.tick(120) 

main() 

PLAYER.PY

import pygame 
import random 
from walls import Wall 

class Player(pygame.sprite.Sprite): 
    #-------------------Define Variables here 
    speed=0 
    #------------------Initialise Constructor 
    def __init__(self): 
     pygame.sprite.Sprite.__init__(self) 
     self.image=pygame.image.load("player.png") 
     self.rect = self.image.get_rect() 

     #SET THE INITIAL SPEED TO ZERO 
     self.change_x = 0 
     self.change_y = 0 

     #--------------Fetch the rectangle object that has the dimensions of the image 
     self.rect =self.image.get_rect() 
     #---------------Define movement 
    def moveRight(self,pixels): 
     self.rect.x+=pixels 
    def moveLeft(self,pixels): 
     self.rect.x-=pixels 
    def moveUp(self,pixels): 
     self.rect.y-=pixels 
    def moveDown(self,pixels): 
     self.rect.y+=pixels 

    # Make our top-left corner the passed-in location. 
    def settopleft(): 
     self.rect = self.image.get_rect() 
     self.rect.y = y 
     self.rect.x = x 

     # Set speed vector 
     self.change_x = 0 
     self.change_y = 0 
     self.walls = None 

    def changespeed(self, x, y): 
     """ Change the speed of the player. """ 
     self.change_x += x 
     self.change_y += y 


    def update(self): 
     # Did this update cause us to hit a wall? 
     block_hit_list = pygame.sprite.spritecollide(self, self.walls, False) 
     for block in block_hit_list: 
      # If we are moving right, set our right side to the left side of 
      # the item we hit 
      if self.change_x > 0: 
       self.rect.right = block.rect.left 
      else: 
       # Otherwise if we are moving left, do the opposite. 
       self.rect.left = block.rect.right 

     # Move up/down 
       self.rect.y += self.change_y 

     # Check and see if we hit anything 
     block_hit_list = pygame.sprite.spritecollide(self, self.walls, False) 
     for block in block_hit_list: 

      # Reset our position based on the top/bottom of the object. 
      if self.change_y > 0: 
       self.rect.top = block.rect.top 
      else: 
       self.rect.top = block.rect.bottom 

WALLS.PY

import pygame 

class Wall(pygame.sprite.Sprite): 
    #Wall a player can run into 
    def __init__(self, x, y, width, height,colour): 
     #Constructor fo rthe wall that the player can run into 
     #call the parent's constructor 
     super().__init__() 

     #Make a green wall, of the size specified in paramenters 
     self.image=pygame.Surface([width,height]) 
     self.image.fill(colour) 

     #Make the "passed-in" location ,the top left corner 
     self.rect=self.image.get_rect() 
     self.rect.y=y 
     self.rect.x=x 

添付、プレーヤーとBGのための領域も画像:playerbackground image

+2

あなたの投稿を編集し、[、最小限の完全かつ検証可能な例]を提供(https://stackoverflow.com/help/mcve)してください私たちが実行してテストすることができ、そうでなければ、あなたを助けることは非常に困難または不可能かもしれません。 – skrx

+0

@slrxご意見ありがとうございます。おそらく、それはプレーヤーファイルに単純なロジックエラーがあると思っていました。あなたのアドバイスに従って、私は今3つのファイルをすべて追加して、より正確に質問をしました。あらかじめ大変ありがとうございます – MissComputing

+1

これはまだ*最小の*例ではありません。これを取り除くにはたくさんのことがありますが、基本的にコードの概要を簡単に説明してください。 3つではなく1つのファイルにすべてを収め、無駄な敵をすべて解読してください。シンプルな「ここの選手は、壁があります。私がこのようなプレーヤーを動かしたら、どうして衝突しないのですか?私たちにあなたのコードをすべて与えるのではなく、私たちが読むことは簡単です(誰が500行を読むのが面倒なのでしょうか?)ので、より多くの助けを得ることができますが、余分なものを解析する際に間違いを認識してしまいます。 –

答えて

0

まず、動きの問題について話しましょう。 Playerの更新メソッドのコードでは、最初にプレーヤーをx軸に沿って移動させ、壁に衝突しているかどうかを確認し、衝突した場合はブロックの端に位置を設定します。その後、y軸と同じことを行います。そうしなければならないのは、そうでなければプレーヤーの方向性を知らず、正しい位置に彼の位置をリセットできないからです。 self.change_xchange_yの属性はもう使用されず、代わりにpygame.key.get_pressedでプレイヤーを移動するようにコードを変更したようです。私はpygame.key.get_pressedブロックを削除し、イベントループの動きを変更します。 update方法でも同様に固定されなければならなかったいくつかのもの、例えば:

if self.change_y > 0: 
    self.rect.bottom = block.rect.top 

衝突検出のためには、あなたはpygame.sprite.spritecollideを使用してプレーヤーとあなたがチェックしたいスプライトグループを渡すことができます。返されたリストを繰り返し処理し、衝突したすべてのスプライトに対して何かを実行します。

ここにあなたの更新されたコードです:

import sys 
import random 
import pygame as pg 


pg.init() 


class Wall(pg.sprite.Sprite): 
    """Wall a player can run into.""" 
    def __init__(self, x, y, width, height, colour): 
     super().__init__() 
     self.image = pg.Surface([width, height]) 
     self.image.fill(colour) 
     # Make the "passed-in" location the top left corner. 
     self.rect = self.image.get_rect(topleft=(x, y)) 


class Collectable(pg.sprite.Sprite): 
    """A collectable item.""" 

    def __init__(self, colour, x, y, image, rect): 
     super().__init__() 
     self.image = pg.Surface((5, 5)) 
     self.image.fill(colour) 
     self.rect = self.image.get_rect(topleft=(x, y)) 


class Player(pg.sprite.Sprite): 

    def __init__(self): 
     pg.sprite.Sprite.__init__(self) 
     self.image = pg.Surface((30, 30)) 
     self.image.fill((50, 150, 250)) 
     self.rect = self.image.get_rect() 
     #SET THE INITIAL SPEED TO ZERO 
     self.change_x = 0 
     self.change_y = 0 
     self.health = 100 

    def update(self): 
     # Move left/right. 
     self.rect.x += self.change_x 
     # Did this update cause us to hit a wall? 
     block_hit_list = pg.sprite.spritecollide(self, self.walls, False) 
     for block in block_hit_list: 
      # If we are moving right, set our right side to the left side of 
      # the item we hit 
      if self.change_x > 0: 
       self.rect.right = block.rect.left 
      else: 
       # Otherwise if we are moving left, do the opposite. 
       self.rect.left = block.rect.right 

     # Move up/down. 
     self.rect.y += self.change_y 
     # Check and see if we hit anything. 
     block_hit_list = pg.sprite.spritecollide(self, self.walls, False) 
     for block in block_hit_list: 
      # Reset our position based on the top/bottom of the object. 
      if self.change_y > 0: 
       self.rect.bottom = block.rect.top 
      else: 
       self.rect.top = block.rect.bottom 


BLACK = (0,0,0) 
WHITE = (255,255,255) 
GREEN = (0,255,0) 
RED = (255,0,0) 
BLUE = (0,0,255) 
GOLD = (255,215,0) 

size = (500, 500) 
screen = pg.display.set_mode(size) 
pg.display.set_caption("The Life Game") 

wall_list = pg.sprite.Group() 
all_sprites = pg.sprite.Group() 
enemy_list = pg.sprite.Group() 
coins = pg.sprite.Group() 

player = Player() 
player.walls = wall_list 
all_sprites.add(player) 

for i in range(random.randrange(100,200)): 
    x = random.randrange(size[0]) 
    y = random.randrange(size[1]) 
    whiteStar = Collectable(WHITE, x, y, "White Star", "Rect") 
    all_sprites.add(whiteStar) 

for i in range(50): 
    x = random.randrange(size[0]) 
    y = random.randrange(size[1]) 
    enemy = Collectable(RED, x, y, "Enemy","Ellipse") 
    enemy_list.add(enemy) 
    all_sprites.add(enemy) 

coin1 = Collectable(GOLD,240,200,"Coin","Ellipse") 
coin2 = Collectable(GOLD,100,340,"Coin","Ellipse") 
all_sprites.add(coin1, coin2) 
coins.add(coin1, coin2) 

# Make the walls. 
walls = [Wall(0,0,10,600,GREEN), Wall(50, 300, 400, 10,RED), 
     Wall(10, 200, 100, 10,BLUE)] 
wall_list.add(walls) 
all_sprites.add(walls) 


def main(): 
    clock = pg.time.Clock() 
    done = False 
    score = 0 
    font_score = pg.font.SysFont('Calibri',20,True,False) 
    font_health = pg.font.SysFont('Calibri',20,True,False) 
    while not done: 
     for event in pg.event.get(): 
      if event.type == pg.QUIT: 
       done = True 
      # Do the movement in the event loop by setting 
      # the player's change_x and y attributes. 
      elif event.type == pg.KEYDOWN: 
       if event.key == pg.K_LEFT: 
        player.change_x = -3 
       elif event.key == pg.K_RIGHT: 
        player.change_x = 3 
       elif event.key == pg.K_UP: 
        player.change_y = -3 
       elif event.key == pg.K_DOWN: 
        player.change_y = 3 
      elif event.type == pg.KEYUP: 
       if event.key == pg.K_LEFT and player.change_x < 0: 
        player.change_x = 0 
       elif event.key == pg.K_RIGHT and player.change_x > 0: 
        player.change_x = 0 
       elif event.key == pg.K_UP and player.change_y < 0: 
        player.change_y = 0 
       elif event.key == pg.K_DOWN and player.change_y > 0: 
        player.change_y = 0 

     # UPDATE SECTION/Put the logic of your game here (i.e. how 
     # objects move, when to fire them, etc). 
     all_sprites.update() 

     # spritecollide returns a list of the collided sprites in the 
     # passed group. Iterate over this list to do something per 
     # collided sprite. Set dokill argument to True to kill the sprite. 
     collided_enemies = pg.sprite.spritecollide(player, enemy_list, True) 
     for enemy in collided_enemies: 
      player.health -= 25 

     collided_coins = pg.sprite.spritecollide(player, coins, True) 
     for coin in collided_coins: 
      score += 1 

     # DRAW SECTION 
     screen.fill(BLACK) 
     all_sprites.draw(screen) 

     health_label = font_health.render("Health: "+str(player.health),True,WHITE) 
     score_label = font_score.render("Score: " + str(score),True, WHITE) 
     screen.blit(score_label,[100,480]) 
     screen.blit(health_label,[190,480]) 

     pg.display.flip() 
     clock.tick(60) 

if __name__ == '__main__': 
    main() 
    pg.quit() 
    sys.exit() 
+0

これは非常に役に立ちます - ありがとう!とても有難い。このコード行が何をしているのか説明できますか?if self.change_y> 0: self.rect.bottom = block.rect.top(私はself.rect.bottom = block.rect.topを理解できません)ビット。 – MissComputing

+0

'self.rect'と' block'はどちらも '' pygame.Rect'(http://www.pygame.org/docs/ref/rect.html)です。これらの矩形は、矩形の位置を変更するために使用できる 'topleft'、' center'、 'top'および' bottom'のような多くの仮想属性を持っています。 'self.rect.bottom = block.rect.top'は実際にはかなりわかりやすいと思います。なぜなら、rectの(self.rect.y + self.rect.height'と同じです)ブロックの先頭位置(これは 'block.y'と同じです)に移動します。 – skrx

+0

だから、あなたはこのように書くこともできます: 'self.rect.y = block.rect.y - self.rect.height'しかし、それはimoを読む方が良いわけではありません。 – skrx

関連する問題