Tutorial:Baseline 2D Platformer (日本語)

概要

第一部: 演壇
第二部: 自機
第三部: 自機の移動
第四部: 跳躍
第五部: コード全体

この教本では、 "ベースライン 2D アクションゲーム" を作成します。この文脈における "ベースライン" とは、基本的な関数を意味します。したがって、 "ベースライン 2D アクションゲーム" では、次のことを参照または経験することができます:

  • 自機が動き回るアクションゲーム。
  • 遊戯者の化身・自機。
  • 自機の左右への移動をできるようにする。
  • 自機の跳躍をできるようにする。

第一部: 演壇

最初に、演壇を作成します。教本の目的である演壇は、ゲームウィンドウ下半分の領域を占める白色の長方形です。

platform = {}

function love.load()
        -- これは演壇の高さと幅です。
	platform.width = love.graphics.getWidth()    -- これは演壇の広さをゲーム・ウィンドウ全体と同じ広さにします。
	platform.height = love.graphics.getHeight()  -- これは演壇の高さをゲーム・ウィンドウ全体と同じ高さにします
        
        -- これは演壇を表示する座標です。
	platform.x = 0                               -- これはゲーム・ウィンドウの左端から演壇の描画を開始します。
	platform.y = platform.height / 2             -- これはまさしくゲーム・ウィンドウの中央から演壇の描画を開始します。
end

function love.update(dt)

end

function love.draw()
	love.graphics.setColor(255, 255, 255)        -- これは演壇の色を設定します (引数は RGB 色形式です)。

        -- さて、演壇は上記で宣言した変数を受け入れている間は白色の長方形として描画されます。
	love.graphics.rectangle('fill', platform.x, platform.y, platform.width, platform.height)
end

したがって、このように見えるものがあります:

Part 1 The Platform.PNG

素晴らしい! これで、単純な白色の演壇ができました!

第二部: 自機

次は自機についてです。 教本の意図において、自機は 32x32 から成る紫色の積木です。 今回は love.graphics.rectangle を使用する代わりに、 love.graphics.draw を使用します。この理由は紫色の積木は外部ファイルだからです。この様に、 "外部画像" の描画方法に加えて "内部画像" を描画する方法も習得できます。ここで紫色の積木を入手できます。

注釈: 手っ取り早く言うと、 love.graphics.rectangle はゲームのウィンドウに長方形を描画します。ゲームのコードで仮引数として宣言しているため(可能であれば)、これを "内部ファイルの表示" 形式と考えることができます (正確か、あるいは固有用語ではなく)。 love.graphics.draw はウィンドウに画像を表示します。 ― 対応ファイル形式である場合に限り。用意した画像はゲームのコードにより呼び出される外部ファイルであるため、これを "外部ファイルの表示" 形式 (また、正確か、あるいは適切な用語ではなく) と考えることができます。
...
player = {}  -- これを platform 変数の下に追加します。

function love.load()
	...
        -- これを platform 変数の下に追加します。

        -- これは自機の描画座標です。
	player.x = love.graphics.getWidth() / 2   -- これはゲーム・ウィンドウの幅に基づき画面中央へ時期を設置します。
	player.y = love.graphics.getHeight() / 2  -- これはゲーム・ウィンドウの高さに基づき画面中央へ時期を設置します。
        -- これはファイル "purple.png" を呼び出してから変数 player.img へ代入します。
	player.img = love.graphics.newImage('purple.png')
end

function love.update(dt)

end

function love.draw()
	...
        -- これを love.graphics.rectangle のある行の下へ追加します。
        
        -- これは自機を描画します。
	love.graphics.draw(player.img, player.x, player.y, 0, 1, 1, 0, 32)
end

さて、このように見えるものがあります:

Part 2 The Player Character.PNG

申し分ない! これで自機は登場しました!

第三部: 自機の移動

演壇があり、自機が登場しています! いまこそ、この箱田箱男(!?)さんを動かす時ッ!です。言い忘れていましたが 2D アクションゲームにおいて、自機は "左右に移動できるようにする必要がある!" ため、自機は絶えず右側へ移動可能にしないことに留意しておいてください。これを行うには、遊戯者がボタンを押したときに左側または右側へ自機を移動させるためには、キーボード入力の割り当てだけではなく自機の移動速度をコードで宣言する必要があります。

function love.load()
	...
	player.speed = 200    -- これは自機の移動速度です。この値は好みに応じて変更できます。
end

function love.update(dt)
        -- これはキーボード入力を割り当てる方法です。
        
	if love.keyboard.isDown('d') then                    -- 遊戯者が "D" ボタンを押し下げて、そのまま押し続る場合:
		player.x = player.x + (player.speed * dt)    -- 自機は右側へ移動します。
	elseif love.keyboard.isDown('a') then                -- 遊戯者が "A" ボタンを押し下げて、そのまま押し続る場合:
		player.x = player.x - (player.speed * dt)    -- 自機は右側へ移動します。
	end
end

コードを実行した場合は、これで自機は左右に移動できます! しかし! このコードは問題があります。見えない壁がないので自機を右側 (または左側) へ移動し続けると、自機は猪突猛進してゲーム・ウィンドウから出て行ってしまい、遊戯者の視覚から消えてしまいます。これはゲームの実装としては間違いです! したがって love.update() 関数内で:

function love.update(dt)
	if love.keyboard.isDown('d') then
		-- これは自機がゲーム・ウィンドウの右端から出て行かないようにします。
		if player.x < (love.graphics.getWidth() - player.img:getWidth()) then
			player.x = player.x + (player.speed * dt)
		end
	elseif love.keyboard.isDown('a') then
		-- これは自機がゲーム・ウィンドウの左端から出て行かないようにします。
		if player.x > 0 then 
			player.x = player.x - (player.speed * dt)
		end
	end
end

Part 3- Player Movement.gif

これで自機は画面から出て行くことができなくなりました。このように自機は常にゲーム・ウィンドウ内に拘束されます。

第四部: 跳躍

さて残り全てのものは跳躍です。跳躍をせずに 2D アクションゲームを成立させることはできません。実際、自機は跳躍なしで穴や壁といった障害物を乗り超えることができません。ちょっとした基本物理学のお時間です。ちょっとした跳躍をしてから落下をするために、オブジェクト (この場合は、遊戯者の自機) が Y 軸の速度、跳躍の高さ、および重力を有する必要があります。教本の目的として、たとえ任意のオブジェクトへ質量を付与することは物理特性の動作方法を変更できることに言及する価値があるとしても、物体の質量を考慮に入れません。最初に、以前言及した三つの事柄について宣言します。同様に変数 "ground" を追加します。これは地面の場所を示します。それは足が接地しており、跳躍後に着地をする場所であると考えてください。

function love.load()
	...
        -- これは player.img の下に追加します。
	player.ground = player.y     -- これは自機を演壇へ着地させます。

	player.y_velocity = 0        -- まだ自機が跳躍していない時は何時でも、 Y 軸の速度は常に 0 です。

	player.jump_height = -300    -- 自機が跳躍する時はいつでも、この高さへ到達することができます。
	player.gravity = -500        -- 自機が落下する時はいつでも、この比率で落下します。
end
注釈: 好みに応じて player.jump_height および player.gravity の値を自由に変更してください。ゲームの物理特性において通常の方法で動作しないことを希望しない限り、 player.gravity > player.jump_height を行うことに大方留意してください。

さて、変数宣言後に、自機の跳躍を行うので次に進みます。これを行うには、跳躍を行うキーを割り当てる必要があります。

...
function love.update(dt)
	...
        -- これは右キー割り当ての下に追加します。

        -- これは自機の跳躍を担当しています。
	if love.keyboard.isDown('space') then                     -- 遊戯者がスペースキーを押すか、または押し続づけているときはいつでも判定を行います。

                -- 自機が地面にいるかどうかをゲームで確認します。自機は Y 軸の速度 = 0 の時は地面にいることに留意してください。
		if player.y_velocity == 0 then
			player.y_velocity = player.jump_height    -- 自機に関する Y 軸の速度は跳躍の高さとして設定されます。
		end
	end
end

これでも、完了していません。跳躍をしようとしても、自機は跳躍を行いません。これは跳躍の物理特性を書き足していないからです。

...
function love.update(dt)
	...
        -- 跳躍キーの割り当ての下に追加してください。

        -- これは跳躍の物理特性を担当しています。
        if player.y_velocity ~= 0 then                                      -- ゲームは自機が "跳躍" して地面から離れたかどうかを調べます。
		player.y = player.y + player.y_velocity * dt                -- これは自機を上げる・跳躍させます。
		player.y_velocity = player.y_velocity - player.gravity * dt -- これは自機に重力を適用します。
	end
        
        -- これは自機が地面へ着地するのを確認するために、衝突を担当しています。
        if player.y > player.ground then    -- ゲームは自機が跳躍したかどうかを調べます。
		player.y_velocity = 0       -- この意味は再び自機は地面にあるため、 Y 軸座標の速度を 0 へ戻して設定します。
    		player.y = player.ground    -- この意味は再び自機は地面にあるため、 Y 軸座標の速度を 0 へ戻して設定します。
	end
end

そして最終的に、これで自機は跳躍できるようになりました!

Part 4- Jumping.gif

第五部: コード全体

おめでとうございます! これで 2D アクションゲームを作成できました! さて参考までに、コード全体を掲載しておきます:

platform = {}
player = {}

function love.load()
	platform.width = love.graphics.getWidth()
	platform.height = love.graphics.getHeight()

	platform.x = 0
	platform.y = platform.height / 2

	player.x = love.graphics.getWidth() / 2
	player.y = love.graphics.getHeight() / 2

	player.speed = 200

	player.img = love.graphics.newImage('purple.png')

	player.ground = player.y
	
	player.y_velocity = 0

	player.jump_height = -300
	player.gravity = -500
end

function love.update(dt)
	if love.keyboard.isDown('d') then
		if player.x < (love.graphics.getWidth() - player.img:getWidth()) then
			player.x = player.x + (player.speed * dt)
		end
	elseif love.keyboard.isDown('a') then
		if player.x > 0 then 
			player.x = player.x - (player.speed * dt)
		end
	end

	if love.keyboard.isDown('space') then
		if player.y_velocity == 0 then
			player.y_velocity = player.jump_height
		end
	end

	if player.y_velocity ~= 0 then
		player.y = player.y + player.y_velocity * dt
		player.y_velocity = player.y_velocity - player.gravity * dt
	end

	if player.y > player.ground then
		player.y_velocity = 0
    	player.y = player.ground
	end
end

function love.draw()
	love.graphics.setColor(255, 255, 255)
	love.graphics.rectangle('fill', platform.x, platform.y, platform.width, platform.height)

	love.graphics.draw(player.img, player.x, player.y, 0, 1, 1, 0, 32)
end

この教本を読み、試行することに関して、なにかの場合で読者の役に立ったなら、筆者に感謝していただると幸いです。


そのほかの言語