ウチツクシ

ゲームをしたり作ったり

近況(スターフォックス零 感想)

なんとか生きてる。ツイートは自主規制中。もうすぐ新年だし一発目はなんかゲーム作って勝手に盛り上がろうか!と思ってたら全然作れなくて今に至る。愚か過ぎる…別に誰かと約束したわけじゃないけどここまで来たらな。

f:id:K-s:20160503102906j:plain:right:w240ゲーセン通いは随分減ったけど、WiiU買ったよ。スタフォ零。
GCと一緒にアサルト買って以来のハードと同時買い。アサルトはちょっと自分に合わなくて残念だったが、零は心配も吹っ飛んだぞ!30時間、一気に勲章コンプまでプレイしてしまった。右は初クリア時の写真。やっぱり字汚い。

普通に楽しいと思うんだけど、レビューとか見るとネガティブなのも結構あって複雑な気分でもある。期待が大き過ぎたのか、今のプレイヤーのレベルが高すぎるのか分からないけど。自分はシリーズはSFCの初代、64、アサルト、と今回の零やってて、操作系や面白さの方向も結構違ってて一概に比較するのは難しいが、今のところ零が一番好き。

まず立体音響に驚かされて、パイロットビューのジャイロ操作のもどかしさに笑わされて、リアルタイムでスムーズな変形に快感して。立体音響はほんと凄い。初め音声が右側に寄ってて位置が悪いのかと思ったらバイザー表現で味方は右から聞こえるようになってたのね。今生配信時々やっててその時ヘッドセット付けるんだけど、これ異常に臨場感あって楽しいw コメント読み上げ設定しててまだコメント来たことないけど、プレイ中に来たら混乱すると思う。ジャイロ操作が特に楽しかったのがタイタニアのボス。もうちょいもうちょいって身体すごい横にひねってた。昔レースゲームやってて身体が勝手に傾く人とかいたけど、あれを自発的にやってる感じがして面白い。あと変形、これはサテライト2が良い。このステージはタイムアタックになってて、コース取りや変形タイミングを詰めていく段階で変形が楽しくなってきた。

基本やってて楽しいのだけど、自分には合わないところもあって一部スコアアタックが。ゾネスやベノムの稼ぎは時間かかる上に地味であまり楽しくない…
あと裏ルート通ると仲間との掛け合いが少なくてちょっと寂しい感じ。父さんの演出は64版が思い出補正あり過ぎてそうじゃないだろ…ってなる。
そして対戦無いのはほんとなんでなんだ。64は対戦かなりやったし、アサルトも対戦楽しいらしい(やったことない)、ネット時代の今なら絶対だろうと思ったのだが。技術的な問題なんかな。

いまいちなとこもあるけど、やってて楽しいから買って良かったと思う。ちょうど店にWiiU本体入荷してた&5kmくらい手で持って帰った経験含めてw

とスタフォ零感想な近況でした。自作ゲーム超地味だけど年内には作るぜ!(旗は舞う

マルチディスプレイで解像度などの情報を取得する

追記:修正版をQiitaに書きました。


f:id:K-s:20160618182220j:plain
HSPの ginfo_dispx(y) はメインディスプレイの解像度しか得られないため、サブディスプレイで全画面ウィンドウを作るときなどには使えない。モニタを1つしか持ってないから気にならなかったのだけど、モニタに複数入力したらマルチできると気づき興味が出て調べた。リモコンで入力モード切り替える似非マルチ。

モニタの全ハンドルを取得するのは普通コールバックを使うらしいのだが、HSPは標準ではコールバック使えないから別の関数使って気合で取得した。EnumDisplayDevices とかは複数回呼ぶと全部取得できるのになんでこれはコールバックなんだ…
ただ、 コールバック用モジュールができました - HSPTV!掲示板 のモジュールを使えばコールバックもできるので使う場合は mod_clbk3.hsp で保存して1行目のコメント部分をアレしてください。

; #define USE_CALLBACK

#ifdef USE_CALLBACK
#include "mod_clbk3.hsp"
#endif
#include "user32.as"
#include "gdi32.as"

  ; 仮想画面の原点・サイズ取得
  GetSystemMetrics $4c ; SM_XVIRTUALSCREEN
  vsOriginX = stat
  GetSystemMetrics $4d ; SM_YVIRTUALSCREEN
  vsOriginY = stat
  GetSystemMetrics $4e ; SM_CXVIRTUALSCREEN
  vsSizeX = stat
  GetSystemMetrics $4f ; SM_CYVIRTUALSCREEN
  vsSizeY = stat

  dim hmoni
  moniNum = 0

#ifdef USE_CALLBACK
  ; コールバックを使ってモニタハンドルを列挙
  newclbk3 clbk, 4, *MonitorEnumProc
  EnumDisplayMonitors 0, 0, clbk, 0
  if 0 {
  *MonitorEnumProc
    clbkargprotect prm
    hmoni(moniNum) = prm(0)
    moniNum++
    return 1
  }
#else
  ; 仮想画面上の各点を調べてモニタハンドルを列挙
  sft = 100 ; 調べる各点の間隔
  repeat
    x = vsOriginX + cnt * sft \ vsSizeX
    y = vsOriginY + cnt * sft / vsSizeX * sft
    if (y > vsSizeY) : break
    MonitorFromPoint x, y, 0 ; MONITOR_DEFAULTTONULL
    h = stat
    if (h == 0) : continue
    f = 0
    if (moniNum) {
      ; ハンドルの重複チェック
      repeat moniNum
        if (h == hmoni(cnt)) : break
        if (cnt == moniNum - 1) : f = 1
      loop
    } else {
      f = 1
    }
    if (f) {
      hmoni(moniNum) = h
      moniNum++
    }
  loop
#endif

  ; 各ディスプレイの情報取得
  dim moniInfo, 10 + 8  ; MONITORINFOEX
      moniInfo(0) = 40 + 32
  dim devMode, 44 ; DEVMODE
  dim px, moniNum
  dim py, moniNum
  dim sx, moniNum
  dim sy, moniNum
  dim bit, moniNum
  dim hz, moniNum
  dim flag, moniNum
  sdim dn, 32, moniNum
  repeat moniNum
    GetMonitorInfo hmoni(cnt), varptr(moniInfo)
    px(cnt) = moniInfo(1) ; rcMonitor.left
    py(cnt) = moniInfo(2) ; rcMonitor.top
    flag(cnt) = moniInfo(9) ; dwFlags
    getstr dn(cnt), moniInfo, 40 ; szDevice
    EnumDisplaySettings dn(cnt), -1, varptr(devMode) ; ENUM_CURRENT_SETTINGS
    sx(cnt) = devMode(27) ; dmPelsWidth
    sy(cnt) = devMode(28) ; dmPelsHeight
    bit(cnt) = devMode(26) ; dmBitsPerPel
    hz(cnt) = devMode(30) ; dmDisplayFrequency
  loop
  
  ; デスクトップ全体のビットマップを取得
  buffer 1, vsSizeX, vsSizeY
  GetDC 0
  dc = stat
  BitBlt hdc, 0, 0, vsSizeX, vsSizeY, dc, vsOriginX, vsOriginY, $40CC0020 ; SRCCOPY | CAPTUREBLT
  ReleaseDC 0, dc
  celdiv 1, , , vsSizeX / 2, vsSizeY / 2
  
  ; 以下描画
  
  ; screen 0, 1024, 768
  gsel
  winsx = ginfo_sx
  winsy = ginfo_sy
  
  if (vsSizeX > vsSizeY * winsx / winsy) {
    rate = double(winsx - 40) / vsSizeX
    dox = 20
    doy = winsy / 2 - rate * vsSizeY / 2
  } else {
    rate = double(winsy - 40) / vsSizeY
    dox = winsx / 2 - rate * vsSizeX / 2
    doy = 20
  }
  
  font "arial", 12
  
  color 220, 220, 220
  box vsOriginX, vsOriginY, vsSizeX, vsSizeY
  pos ginfo_cx, ginfo_cy - 16
  color
  mes strf("pos(%d, %d), res(%d x %d)", vsOriginX, vsOriginY, vsSizeX, vsSizeY)
  repeat moniNum
    if (flag(cnt)) {
      color 220, 170, 170
    } else {
      color 150, 200, 200
    }
    box px(cnt), py(cnt), sx(cnt), sy(cnt)
    pos ginfo_cx + 6, ginfo_cy + 4
    color
    mes strf("pos(%d, %d)", px(cnt), py(cnt))
    mes strf("res(%d x %d)", sx(cnt), sy(cnt))
    mes strf("color %d bit", bit(cnt))
    mes strf("refresh %d hz", hz(cnt))
    mes dn(cnt)
  loop
  
  gmode 5, vsSizeX, vsSizeY, 40
  pos winsx / 2, winsy / 2
  celput 1, 0, rate, rate
  
  stop

#deffunc box int _x, int _y, int _w, int _h
  x1 = rate * (_x - vsOriginX) + dox
  y1 = rate * (_y - vsOriginY) + doy
  x2 = rate * (_x + _w - vsOriginX) + dox
  y2 = rate * (_y + _h - vsOriginY) + doy
  boxf x1, y1, x2 - 1, y2 - 1
  color ginfo_r + 20, ginfo_g + 20, ginfo_b + 20
  boxf x1 + 4, y1 + 4, x2 - 5, y2 - 5
  pos x1, y1
  return

GetMonitorInfo で得られた szDevice を EnumDisplaySettings に指定してそれで得た DEVMODE を ChangeDisplaySettings(6.19修正: ChangeDisplaySettingsEx じゃないとダメ)に渡せば特定のディスプレイの解像度変更なんかも多分できる。(→できた


今回調べてて分かったのは、

  • ソフトは起動すると基本的にメインディスプレイに表示される
  • ginfo_dispx(y) はメインディスプレイの解像度
  • MonitorFromPoint の引数は3つ(https://msdn.microsoft.com/ja-jp/library/cc410472.aspxだと2つに見える…初め配列のポインタ渡してて動かなかった、ずるい)