質問するログイン新規登録
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Q&A

解決済

1回答

414閲覧

python でキャラクターをジャンプして着地させたいのですが、上手くいきません。

heimu

総合スコア1

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

1グッド

0クリップ

投稿2024/01/04 03:51

編集2024/01/04 05:36

1

0

実現したいこと

ジャンプしてfloorに接触(colliderect)したらとまる。

発生している問題・分からないこと

接触してもfloorでとまらない。
floor_rectに衝突してもそこでピッタリとまらない。30ピクセルくらい下に行ってからとまるので、
床からジャンプして着地すると床に身体が半分くらい埋まってしまう。

エラーメッセージ

error

1なし。

該当のソースコード

import pygame from pygame.locals import * from sys import exit import random pygame.init() screen = pygame.display.set_mode((1000,1000)) pygame.display.set_caption('learning_rect') clock = pygame.time.Clock() floor_surf = pygame.Surface((1000,64)) floor_rect = floor_surf.get_rect(topleft = (0,936)) floor_surf.fill('Blue') mario_x = 100 mario_y = 700 mario_y_speed = 1 mario_jump = False mario_jump_height = 20 gravity = 1 img_bg = pygame.image.load('bg.png')# 背景 mario_surface = pygame.image.load('mario1.png').convert_alpha() mario_rect = mario_surface.get_rect(topleft = (mario_x,mario_y)) while True: for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() exit() pressed_key = pygame.key.get_pressed() if pressed_key[K_RIGHT]: mario_x += 10 if pressed_key[K_LEFT]: mario_x -= 10 if pressed_key[K_SPACE]: print('jump') mario_jump = True mario_y -= mario_jump_height mario_jump_height -=gravity if mario_rect.colliderect(floor_rect): print('collision') if mario_rect.colliderect(floor_rect): #mario_jump = False jump_height = 20 print(mario_jump) screen.blit(img_bg,(0,0)) screen.blit(floor_surf,floor_rect) mario_y += mario_y_speed screen.blit(mario_surface,mario_rect) if mario_y >= 1100: mario_y = 0 mario_rect.topleft = (mario_x,mario_y) if mario_rect.colliderect(floor_rect): mario_y_speed = 0 pygame.display.update() clock.tick(60)

試したこと・調べたこと

  • teratailやGoogle等で検索した
  • ソースコードを自分なりに変更した
  • 知人に聞いた
  • その他
上記の詳細・結果
import pygame from pygame.locals import * from sys import exit import random pygame.init() screen = pygame.display.set_mode((1000,1000)) pygame.display.set_caption('learning_rect') clock = pygame.time.Clock() floor_surf = pygame.Surface((1000,64)) floor_rect = floor_surf.get_rect(topleft = (0,936)) floor_surf.fill('Blue') mario_x = 100 mario_y = 872 mario_y_speed = 1 mario_jump = False mario_jump_height = 20 gravity = 1 img_bg = pygame.image.load('bg.png')# 背景 mario_surface = pygame.image.load('mario1.png').convert_alpha() mario_rect = mario_surface.get_rect(topleft = (mario_x,mario_y)) while True: for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() exit() pressed_key = pygame.key.get_pressed() if mario_x <=936: if pressed_key[K_RIGHT]: mario_x += 10 if mario_x >= 0: if pressed_key[K_LEFT]: mario_x -= 10 if pressed_key[K_SPACE] and mario_jump ==False: mario_jump = True mario_jump_height = 20 if mario_jump: mario_y -= mario_jump_height mario_jump_height -=gravity if mario_rect.colliderect(floor_rect): mario_jump = False #mario_y = 820 print(mario_jump) screen.blit(img_bg,(0,0)) screen.blit(floor_surf,floor_rect) screen.blit(mario_surface,mario_rect) mario_rect.topleft = (mario_x,mario_y) pygame.display.update() clock.tick(60)

↑現状改善がすすんで、ジャンプはできるようになりましたが、なぜか着地位置が30ピクセルくらい元の高さから下になります。

補足

python に慣れるために、やりたいことから無理やりプログラムを作ってるため、かなり変なコードなのだとおもいます。すみません。chatGPTにも質問したりしつつ、ここまでたどりつきました。rectの使い方に慣れる為に作ってるのですが、なんか上手くいきません。

mario の画像は64×64です。

宜しくお願いします。

novelistory👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

novelistory

2024/01/04 04:37

> 上記の詳細・結果 記載が乱れてしまっております。 Markdown形式でコードを記載(「```」でコードを囲む)いただくと、見やすくなり回答を得られやすくなるかと思います。 ▼teratailヘルプ https://teratail.com/help#about-markdown
guest

回答1

0

ベストアンサー

Windows 11、Python 3.12.1で確認しました。

colliderectは、mario_rectの下辺と地面が同じ値の場合、衝突になりません。(下辺と右辺はrectの範囲に入らないため)
また、if mario_jumpの中で計算したmario_yが、colliderect判定時のmario_rectに反映されていません。(screen.blitの後に反映されている)

よって、ちょうどの時と、1回余計に回っているので、2段階のめり込んでいます。

なので、改善後のソースに対して

  • mario_yの初期値を1ピクセル下げる
  • colliderect判定前に、mario_yの値をmario_rectに反映する
    の2か所を修正しました。
# 1行変更 mario_y = 873 (略) if mario_jump: mario_y -= mario_jump_height mario_jump_height -=gravity # 1行追加 mario_rect.topleft = (mario_x,mario_y)

投稿2024/01/04 12:23

hiroki-o

総合スコア1467

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

heimu

2024/01/05 09:20

回答ありがとうございました! 2段階のめりこんでいることがわかりました。修正していただいたコードで問題なく動作しました。 ただ、このコードで高い位置にもブロックを設けて、そこに飛び乗ったり、そこから飛び降りるとのめりこむ問題が発生します。colliderectが矩形の重なりを検知するという仕組みのようなので、重なってからキャラの位置を修正する必要があるかと思いました。  あとご指摘いただいた「colliderectは、mario_rectの下辺と地面が同じ値の場合、衝突になりません。(下辺と右辺はrectの範囲に入らないため」について自分でも調べてみたのですが、矩形と矩形の重なりの判定なので下辺が他の矩形の上辺にあたった場合でも「重なりが生じている」ので衝突になるのではと思います。間違っていたらすみません。 
hiroki-o

2024/01/05 13:17 編集

何かのプログラミング言語やライブラリの使い方について、不明な点がある場合、まずは開発元のリファレンスを見ましょう。 「Returns true if any portion of either rectangle overlap (except the top+bottom or left+right edges).」 と書いてあります。実際に私のほうでも1ピクセルずつ、ずらして確認しました。 リファレンス https://www.pygame.org/docs/ref/rect.html#pygame.Rect.colliderect 上記の翻訳サイト https://westplain.sakura.ne.jp/translate/pygame/Rect.cgi#Rect.colliderect rectは(左の座標、上の座標、幅、高さ)ですが、実際の高さは「上の座標+高さ」ではなく「上の座標+高さ-1」(上の座標自体も高さに含めるので)なので、「上の座標+高さ」は衝突になりません。  0 1 2 3 0□□□□ 1□□□□ 2□□□□ 3□□□□ 4■■■■■■■■■■■■地面 キャラのrectを(0,0,4,4)だとすると、0+4は範囲外になります。理解できますか?
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.30%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問