1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Opal (Ruby-to-JavaScript compiler)Advent Calendar 2018

Day 10

DXOpalでUndertaleっぽい画面を作る(続2)

Last updated at Posted at 2018-12-22

第三回です。前回は敵キャラを出したので、今回は自機を出しましょう。

画像を用意する

Undertaleの戦闘画面ではプレイヤーはハートの姿になるので、ハートっぽい画像を作りました。こういうのってMacの場合何で作るのが楽なんでしょうね?今回はLibreOffice Drawで作りましたが(「記号シェイプ」にハートがあったのでそれを1個置いて、赤色にして、選択してファイル→エクスポートという手順です。エクスポート時、「選択範囲」にチェックしておくとうまくハートだけpngにすることができます。)

heart.png

プレイヤーを表すクラスを作る

前回、「動くものはクラスにしよう」と書きました。プレイヤーも動くものなので、クラスにしましょう。Enemyクラスを作ったときと同じようにすればOKです。

例によって変更した箇所だけコメントを入れています。

require 'dxopal'
include DXOpal
# ハートの画像を宣言
Image.register(:player, "images/heart.png")
# ...

# プレイヤーを表すクラス
class Player < Sprite
  def initialize
    x = 300
    y = 300
    super(x, y, Image[:player])
  end
end

Window.load_resources do
  Window.bgcolor = C_BLACK
  enemy = Enemy.new
  # Playerクラスのオブジェクトを作る
  player = Player.new
  
  # ...

    enemy.update
    enemy.draw
    # プレイヤーを描画する
    player.draw
    
  # ...

これでハートが出るはず…

スクリーンショット 2018-12-14 1.06.03.png

あれ、出ませんね。

描画順序について

しばし考えたのち、以下の箇所が悪いということに気づきました。draw_thick_boxは初回で定義した太い枠線を引くメソッドですが、外側の四角を描く→内側を背景色で塗りつぶす という動作なので、プレイヤーごと塗りつぶされてしまったようです。

    player.draw

    draw_thick_box(260, 240, 380, 360, C_WHITE, 4)

ということで順序を入れ替えてやると:

    draw_thick_box(260, 240, 380, 360, C_WHITE, 4)
    player.draw

ハートが出ました。

スクリーンショット 2018-12-14 1.14.05.png

このようにDXOpalでは基本的に実行した順に描画が行われるので、順番には注意しましょう。(別解としてz値で描画順を指定する方法もありますが、今回のような簡単なプログラムなら単に順番に気をつけるだけで良いでしょう)

プレイヤーを動かす

次はキー操作でプレイヤーを動かせるようにしてみましょう。DXOpalではInput.key_push?(K_LEFT)のようにしてキーの状態が取れます…が、カーソルキーに限っては、もっと簡単にInput.x, Input.yで状態が取れるようになっています。これを使ってみましょう。

class Player < Sprite
  def initialize
    x = 300
    y = 300
    super(x, y, Image[:player])
  end

  # キー操作に応じて座標を変化させる
  def update
    self.x += Input.x
    self.y += Input.y
  end
end

# ...

    enemy.update
    enemy.draw
    draw_thick_box(260, 240, 380, 360, C_WHITE, 4)
    # キー入力を処理する
    player.update
    player.draw

Playerを動かす処理は、Enemyのときと同様、updateというメソッドでやることにします。Input.xはカーソルキーの左が押されたら-1、右が押されたら+1になるので、それをそのまま座標に足してやることで、自機が動くようになります。

範囲を制限する

とはいえこれだけだと白線の外にも出ていってしまうので、範囲をチェックする処理を追加しましょう。まず下準備として、プレイヤーの移動範囲を定数にしておきます。というのは「プレイヤーの移動範囲」と「白線で囲む範囲」は同じなので、定数を使って共通化しておけば、位置を微調整したくなったときに、定数の値を変えるだけで済むので楽になります。

require 'dxopal'
include DXOpal
Image.register(:player, "images/heart.png")
Image.register(:enemy, "images/computer_typing_hayai.png")
C_ORANGE = [233, 115, 51]
FONT_HP = Font.new(18)
# プレイヤーの移動範囲
PLAYAREA = [260, 240, 380, 360]

# ...

    enemy.update
    enemy.draw
    # 移動範囲を囲むように白線を引く
    draw_thick_box(PLAYAREA[0]-4, PLAYAREA[1]-4, PLAYAREA[2]+4, PLAYAREA[3]+4, C_WHITE, 4)

これで準備はOKです。では、このPLAYAREAを使ってプレイヤーの移動範囲を制限しましょう。Playerのupdateメソッドを修正します。

class Player < Sprite
  def initialize
    x = 300
    y = 300
    super(x, y, Image[:player])

    # x, yの最小値と最大値
    @min_x = PLAYAREA[0]
    @max_x = PLAYAREA[2] - self.image.width   # xは「プレイヤー画像の左端」なので、画像の幅を引かないと右端に移動したとき枠に被ってしまう
    @min_y = PLAYAREA[1]
    @max_y = PLAYAREA[3] - self.image.height
  end

  def update
    self.x += Input.x
    self.x = @min_x if self.x < @min_x  # 小さすぎたら@min_xにする
    self.x = @max_x if self.x > @max_x  # 大きすぎたら@max_xにする
    self.y += Input.y
    self.y = @min_y if self.y < @min_y
    self.y = @max_y if self.y > @max_y
  end
end

こんな感じでしょうか?これでもいいのですが、「数値をある範囲に制限したい」というときはRuby 2.4から追加されたclampメソッドを使うとシンプルに書けます。

  def update
    self.x = (self.x + Input.x).clamp(@min_x, @max_x)
    self.y = (self.y + Input.y).clamp(@min_y, @may_y)
  end

まとめ

今回は自機の表示と移動を実装しました。こんな感じでぴたっと止まってくれます。

スクリーンショット 2018-12-22 20.52.41.png

実際に動いているところは以下で見れます。カーソルキーで自機が移動します。

次回があれば敵の攻撃パターンを実装して、完成としたいです。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?