概要
今回はプログラミングでスマブラのジャンプの挙動をできるだけ忠実に再現してみました
事前準備
この例を試すには以下の作業が必要です。
- Pythonのインストール
- 仮想環境の構築
- pygameのインストール
- 素材の収集
最も簡易的なジャンプの実装

def set_jump_param(self):
if self.jump_frame_count < 10:
self.jumping = True
self.vel = -2 * self.VEL_CONST
elif 10 <= self.jump_frame_count:
self.vel = 2 * self.VEL_CONST
今回はプログラミングでスマブラのジャンプの挙動をできるだけ忠実に再現してみました
まず、キャラクターにジャンプをさせる最も簡単な方法として思いつくのは
ジャンプした直後から一定のスピードで上昇し始め、
ある高さに到達した直後から一定のスピードで下降するというような実装です
実装の仕方は簡単です
ジャンプ入力後、10フレームは上昇、その後は下降と分岐を行うだけです
では実際どのような挙動になるか実行してみましょう
はい。一応ジャンプらしき動作がおこなえましたがカックカクでとてもスマブラのジャンプとは程遠いですね
現実の重力を模倣したジャンプの実装

def set_jump_param(self):
if 0 == self.jump_frame_count:
self.jumping = True
self.vel = -1.5 * self.VEL_CONST
self.acc = 0.4 * self.ACC_CONST
def fall_action(self):
self.vel += self.acc
self.player_pos.y += self.vel
具体的にはジャンプした瞬間の上昇量は大きく
ジャンプの頂点に到達したあたりの上昇量は小さくするともっと自然になるでしょう
そのような挙動を実現するために現実の物理学を参考に実装してみましょう
私たちが住んでいる地球上でジャンプをするとどうなるのでしょうか
まずジャンプした瞬間に上方向の初速が与えられます
それ以降は重力によって影響を受けるので、上昇速度がどんどん減少してゆきます
ジャンプの頂点に達する瞬間に上昇速度は0になり、それ以降は上昇速度はマイナスになり、落下が始まります
そして地面に着地する直前に落下速度は最高になり、着地した瞬間に落下速度は0になります
言葉にしてみるとなかなかややこしいですが、実装は以外にも簡単です
ジャンプした瞬間、つまり0フレーム目に初速と重力加速度を設定します
初速は上向きに重力加速度は下向きの動きなのでプラスマイナスは反対になります
あとは初速から重力加速度を引き算してからキャラクターの位置に対して適応すればいいだけです。
では実際にどのような挙動になるか実行して確かめてみましょう
最初の例はカックカクでしたがそれと比べてジャンプらしい挙動になりましたね
スマブラのジャンプの解析
スマブラにお詳しい方であればジャンプの動作が現実の物理法則とは異なっていることをご存じだと思います
現実で二段ジャンプや空中で移動はできないから当然だと思うかもしれませんが、それ以外にもあります
代表的な例は、落下速度が一定でとまるという点です
先程の実装例でも見た通り、落下速度は重力の影響を受けてどんどん加速してゆきますが
スマブラでは落下速度は途中でとまります
それだけであれば簡単に実装できそうですね。しかし本当にそれ以外の違いがないのか動作を解析してみましょう

解析にはTrackerというアプリを使います。このアプリを使えば動画の物理的な動作を解析することができます
早速使ってみましょう。

まず、アプリを起動し、スマブラの動画をインポートします

その後、上のメニューからTrack、new、massを選択します。これで動画のある一点を追跡してゆきます

次に、Autotrackerを起動し、追跡する部分を選択します。

マリオの帽子のMを選択してsearchを実行すると自動で帽子を追跡し、その座標のデータを取得できます
座標データが取得出来たら速度も表示できるようにします。
早速どのような挙動をしているのか見てみましょう

最初の1、2フレームはかなりの速度で上昇していることがわかります
3、4、5フレームで急激に上昇速度は小さくなってゆき
6フレーム目以降から上昇速度の減少はゆるやかになってゆきます
速度の値がプラスからマイナスに切り替わる瞬間に落下が始まっていることがこのグラフからもわかりますね
落下中も傾きは緩やかですが、落下速度がある点に差し掛かるとそれ以降、落下速度はそれ以上はやくならなくなります
落下速度が途中で一定になるのは事前に予想した通りでした
しかし最初の6フレーム目までの動きは私にとっては結構意外でしたが、皆さんはご存じでしたでしょうか?
なぜこのような仕様になっているのでしょうか?
推測ですが、スマブラのような対戦ゲームではジャンプで相手の攻撃をよけるのにも使われますが
入力直後の上昇速度が遅いと、思った通りに攻撃がよけられないということが起こり得るので
ジャンプ開始直後のジャンプ速度を大きくしているのかもしれませんね
実装
ではこの挙動を実装してみましょう。一見複雑ですが、分岐処理を駆使するだけで実装できます

def set_jump_param(self):
if 0 == self.jump_frame_count:
self.jumping = True
self.vel = -2 * self.VEL_CONST
self.acc = 0 * self.ACC_CONST
elif 1 == self.jump_frame_count:
self.vel = -3 * self.VEL_CONST
self.acc = 0 * self.ACC_CONST
elif 2 == self.jump_frame_count:
self.vel = -2 * self.VEL_CONST
self.acc = 0 * self.ACC_CONST
elif 3 == self.jump_frame_count:
self.vel = -1.6 * self.VEL_CONST
self.acc = 0 * self.ACC_CONST
elif 4 == self.jump_frame_count:
self.vel = -1.05 * self.VEL_CONST
self.acc = 0 * self.ACC_CONST
elif 5 == self.jump_frame_count:
self.vel = -0.75 * self.VEL_CONST
self.acc = 0.4 * self.ACC_CONST
elif 6 <= self.jump_frame_count:
if 0.6 * self.VEL_CONST < self.vel:
self.acc = 0
先程のグラフから速度の値や重力加速度を取得してゆき、各フレームごとに指定してゆくだけです
では、また実行して確かめてみましょう。さっきと比べると、大分スマブラっぽくなった気がします
ジャンプひとつ実装するだけでも、スマブラにはゲームを面白くするための工夫がなされていることがわかって面白いですね
ショートジャンプ
ジャンプの仕様は他にもたくさんありますが、今回はショートジャンプ、基本的な二段ジャンプのみ解説します

def jump_input(self, events):
# print(self.before_jump_frame_count)
for event in events:
if event.type == pygame.JOYBUTTONDOWN and event.button == 5:
print("pygame.JOYBUTTONDOWN")
# flg初期化
self.short_jump_flg = False
if not self.jumping and self.player_pos.colliderect(self.stage):
self.before_jump_frame_count = 4
elif not self.jump_second:
self.jump_second = True
self.jump_frame_count = 0
print("二段ジャンプしました")
# ショートジャンプ入力受付
if event.type == pygame.JOYBUTTONUP and event.button == 5 and 1 <= self.before_jump_frame_count and self.before_jump_frame_count <= 4:
self.short_jump_flg = True
print("pygame.JOYBUTTONUP")
if self.joystick.get_axis(1) > 0.9 and self.vel > 0:
self.vel = 1 * self.VEL_CONST
self.acc = 0 * self.ACC_CONST
print("急降下")
# ジャンプ踏切フレーム
if 1 <= self.before_jump_frame_count:
self.before_jump_frame_count -= 1
self.jump_frame_count = 0
return
# ジャンプ中フレーム
if self.jump_frame_count == None:
return
self.jump_frame_count+=1
if self.short_jump_flg:
self.set_short_jump_param()
else:
self.set_jump_param()
まずはショートジャンプについて実装しましょう
スマブラではジャンプを入力すると、ジャンプ前に3Fのジャンプ踏切モーションが挟まります
スマブラSPECIAL 検証wikiによるとジャンプ踏切中もしくはその1F後にジャンプボタンを離すと小ジャンプになるようです
ではこの仕様からショートジャンプの実装を考えてみましょう
まず、ジャンプボタンを押す情報を受けとった瞬間からフレームのカウントを開始します
1Fから4Fの間にジャンプボタンを離す情報を受け取ったらショートジャンプフラグをオンにします
4F目にジャンプを開始し、初期速度を設定します
以降は通常のジャンプと同じで初期速度と重力加速度を設定してゆきます
実装が完了したら実行して確かめてみましょう
一瞬だけジャンプボタンを入力するとショートジャンプができていることが確認できます
二段ジャンプ

続いて二段ジャンプを実装してみましょう
スマブラSPECIAL 検証wikiによると空中ジャンプの場合はジャンプ踏切が存在しないとのことです
また、二段ジャンプ時の上昇速度を測定してみましたが、二段ジャンプ時はマリオが宙返りをするので正確に測れませんでした
ですので上昇速度や重力加速度の条件は通常のジャンプと同じであると仮定します
ではこの仕様から二段ジャンプの実装を考えてみましょう
まず、二段ジャンプは既に空中にいることが条件ですので、その条件分岐を記述しましょう
そして、二段ジャンプ入力時にはフレームカウントを0にしましょう
フレームを0に設定すると、ジャンプ直後の上昇速度、重力加速度が再設定されることになり再度ジャンプが始まります。
おそらくこれでいいはずですので、試しに実行して確かめてみましょう
確かに二段ジャンプが実行されていますね