インタラクティブデモPS5.js
これは、このチュートリアルで作成するJavaScriptおよびCSSアニメーションで作成されたPS5UIのデモです。インタラクティブな例は、元の記事で触れることができます 。
アスタリスクまたはforkniteプロジェクト置き ps5.js 35.9キロバイトGitHubの上を。
私が書いた PS3のデモについてのつぶやき私はPSの基本的なバージョン構築された3 JavaScriptでコンソールUIを 。コードはまだありませんが、投稿する予定です。さらに、このチュートリアルは、最初のジョブの作成中に得られた知識に基づいて構築されています。
トレーニング
私たちの生活を複雑にしないために、私たちはフレームワークを使用しません。
ただし、フレームワークやライブラリを使用している場合でも、問題を解決するための独自のパターンを開発する必要があります。このUIチュートリアルでは、開発の背後にある概念そのものについて説明します。このアプローチは、React、Vue、またはAngularに簡単に適合させることができます。
私が使用 このテンプレートのHTMLファイル事前に構築されたフレックススタイルを持つが。必要なものすべてと、開始するためのアプリケーションの一般的な構造が含まれています。これはReactまたはVueではありませんが、これはアプリケーションを作成するために必要な最小限の構成です。新しいバニラアプリやウェブサイトで作業を開始する必要があるたびに、この空白を使用します。
HTMLとCSS
このセクションでは、HTMLファイルのスタブの基本について説明します。
シンプルなDIYCSSフレームワーク
私はCSSフレームワークの大ファンではなく、最初から始めることを好みます。ただし、数千時間のコーディングの後、とにかく頻繁に繰り返されるパターンに気付くようになります。最も一般的なケースをカバーするために、いくつかの簡単なクラスを作成してみませんか?これにより、同じプロパティ名と値を何百回も入力できなくなります。
.rel { position: relative }
.abs { position: absolute }
.top { top: 0 }
.left { left: 0 }
.right { right: 0 }
.bottom { bottom: 0 }
/* flex */
.f { display: flex; }
.v { align-items: center }
.vs { align-items: flex-start }
.ve { align-items: flex-end }
.h { justify-content: center }
.hs { justify-content: flex-start }
.he { justify-content: flex-end }
.r { flex-direction: row }
.rr { flex-direction: row-reverse }
.c { flex-direction: column }
.cr { flex-direction: column-reverse }
.s { justify-content: space-around }
.zero-padding { padding: 0 }
.o { padding: 5px }
.p { padding: 10px }
.pp { padding: 20px }
.ppp { padding: 30px }
.pppp { padding: 50px }
.ppppp { padding: 100px }
.m { margin: 5px }
.mm { margin: 10px }
.mmm { margin: 20px }
.mmmm { margin: 30px }
これらのCSSクラスはそれ自体を物語っています。
私たちの最初のCSSスタイル
基本的なCSSの設定が完了したので、いくつかのスタイルを追加して、非表示および表示のメニューコンテナの外観を変更しましょう。メニューはたくさんあり、それらを切り替えることができるので、どのメニューが「オン」でどれが「オフ」であるかを何らかの方法で指定する必要があることを忘れないでください。
複数のメニューとは、各メニューに個別のHTML要素で定義された独自の画面があることを意味します。次のメニューに切り替えると、前のコンテナが非表示になり、新しいコンテナが表示されます。 CSSトランジションを使用して、不透明度、位置、スケールを変更することで、スムーズなUXトランジションを作成することもできます。 デフォルトの
クラス
.menu
を持つすべてのコンテナ は「オフ」状態(つまり、非表示)になります。クラスを持つ要素
.menu
そして
.current
、「オン」状態になり、画面に表示されます。
メニューで選択可能なボタンなどの他の要素自体はクラスを使用し
.current
ますが、CSS階層のコンテキストは異なります。チュートリアルの次のパートでは、CSSスタイルについて説明します。
#ps5 {
width: 1065px;
height: 600px;
background: url('https://semicolon.dev/static/playstation_5_teaser_v2.jpg');
background-size: cover;
}
/* default menu container - can be any UI screen */
#ps5 section.menu {
display: none;
opacity: 0;
// gives us automatic transitions between opacities
// which will create fade in/fade out effect.
// without writing any additional JavaScript
transition: 400ms;
}
#ps5 section.menu.current {
display: flex;
opacity: 1;
}
section.menu
これも、作成するすべてのメニューレイヤーの標準の親コンテナです。これは、「ゲームブラウザ」画面または「設定」画面である可能性があります。
classlist
クラスを要素 プロパティに適用するまで、デフォルトでは表示されません
.current
。
A
section.menu.current
は現在選択されているメニューを示します。他のすべてのメニューは非表示にする必要があり、クラスを
.current
同時に複数のメニューに適用しないでください。
HTML
私たちの自家製の小さなCSSフレームワークは、HTMLを大幅に簡素化します。主なスケルトンは次のとおりです。
<body>
<section id = "ps5" class = "rel">
<section id = "system" class = "menu f v h"></section>
<section id = "main" class = "menu f v h"></section>
<section id = "browser" class = "menu f v h"></section>
<section id = "settings" class = "menu f v h"></section>
</section>
</body>
要素
ps5
は、アプリケーションのメインコンテナです。
主要部分
flex
は
f v h
要素を中央 に配置するためのものであるため、この組み合わせがよく見られます。
また、の
f r
代わりに
flex-direction:row;
、の
f c
代わりに 会い
flex-direction:column;
ます。
サブセクションは、クラスを必要とするメニューの個別の領域です
menu
。それらを切り替えることができます。
コードでは、それらはフリーズされたオブジェクトによって列挙されます(これは以下に表示されます)。
背景を置き換える
私が最初にやりたかったタスクの1つは、バックグラウンド変更機能でした。最初に実装できれば、後で背景を変更する必要のあるすべての将来の機能に統合します。このために、2つ作成することにしました
div
。
新しい背景がアクティブになったら、2つ
div
を交換して、プロパティ値
style.background
を新しい画像のURLに置き換え 、新しい背景にクラスを適用
.fade-in
して、前の背景 から削除します。
私は次のCSSから始めました:
#background-1, #background-2 {
position: absolute;
top: 0;
left: 0;
width: inherit;
height: inherit;
background: transparent;
background-position: center center;
background-size: cover;
pointer-events: none;
transition: 300ms;
z-index: 0;
opacity: 0;
transform: scale(0.9)
}
/* This class will be applied from Background.change() function */
.fade-in { opacity: 1 !important; transform: scale(1.0) !important; z-index: 1 }
/* set first visible background */
#background-2 { background-image: url(https://semicolon.dev/static/playstation_5_teaser_v2.jpg); }
次に、2つを交換 してフェードインまたはフェードアウトする
.change
クラスから発生 するヘルパー静的関数を作成しました (関数は1つの引数、次の画像のURLを取ります):
Background
div
class Background {constructor() {}}
Background.change = url => {
console.log(`Changing background to ${url}`)
let currentBackground = $(`.currentBackground`);
let nextBackground = $(`.nextBackground`);
// set new background to url
nextBackground.style.backgroundImage = `url(${url})`
// fade in and out
currentBackground.classList.remove('fade-in')
nextBackground.classList.add('fade-in')
// swap background identity
currentBackground.classList.remove('currentBackground')
currentBackground.classList.add('nextBackground')
nextBackground.classList.remove('nextBackground')
nextBackground.classList.add('currentBackground')
}
これで、新しい背景を表示する必要があるたびに、表示する画像のURLを使用してこの関数を呼び出すだけです。
Background.change('https://semicolon.dev/static/background-1.png')
フェードイン
transform: 300ms
はすでに各バックグラウンドに適用されており、クラス
.fade-in
が残りを実行している ため、自動的にフェードインが実行されます 。
メインナビゲーションメニューの作成方法
基本的なフレームワークの準備ができたので、残りのUIの構築を開始できます。ただし、UIを管理するためのクラスも作成する必要があります。このクラスを呼びましょう
PS5Menu
。使い方を以下に説明します。
システム画面
シンプルなCSSを使用して[スタート]ボタンを作成しました 。ユーザーがボタンを押した後、PS5のメインメニューに移動します。画面の最初のメニュー(システムメニュー)に[スタート]ボタンを配置しましょう。
<section id = "system" class = "menu f v h">
<div id = "start" class = "f v h">Start</div>
</section>
同様に、他のすべてのメニューのコンテンツは、対応する親コンテナ要素に配置されます。
これについては後で説明します。次に、複数のメニュー画面を整理する方法を理解する必要があります。
この時点で、複数のメニューをキューに入れるという概念について学ぶ必要があります。 PS5には、さまざまなナビゲーションUIのいくつかのレイヤーがあります。たとえば、[設定]を選択すると、まったく異なる新しいメニューが開き、キーボードコントロールがこの新しいメニューに引き継がれます。
常に開いたり閉じたりして、新しいメニューまたは以前のメニューに置き換えられているこれらすべてのメニューを追跡するためのオブジェクトが必要です。
組み込みメソッドを使用できます
push
キューに新しいメニューを追加するためのJavaScriptの配列オブジェクト。また、戻る必要がある場合は、
pop
arrayメソッドを呼び出して前のメニューに戻ることができ ます。 要素
属性ごとにメニューを一覧表示します
id
。
const MENU = Object.freeze({
system: `system`,
main: `main`,
browser: `browser`,
settings: `settings`,
/* add more if needed*/
});
Object.freeze()
設定後もプロパティが変わらないように使用しまし た。一部の種類のオブジェクトは、最適に冷凍されます。これらは、アプリケーションの存続期間中に絶対に変更されるべきではないオブジェクトです。
ここで、各値は文字列形式のプロパティの名前です。このようにして、
MENU.system
またはで メニュー項目にリンクできます
MENU.settings
。このアプローチには構文上の美学しかありません。また、すべてのメニューオブジェクトを「1つのバスケット」に格納することを回避する簡単な方法でもあります。
PS5Menuクラス
まず、クラスを作成しました
PS5Menu
。そのコンストラクターは
this.queue
type プロパティを使用します
Array
。
// menu queue object for layered PS5 navigation
class PS5Menu {
constructor() {
this.queue = []
}
set push(elementId) {
// hide previous menu on the queue by removing "current" class
this.queue.length > 0 && this.queue[this.queue.length - 1].classList.remove(`current`)
// get menu container
const menu = $(`#${elementId}`)
// make the new menu appear by applying "current" class
!menu.classList.contains(`current`) && menu.classList.add(`current`)
// push this element onto the menu queue
this.queue.push( menu )
console.log(`Pushed #${elementId} onto the menu queue`)
}
pop() {
// remove current menu from queue
const element = this.queue.pop()
console.log(`Removed #${element.getAttribute('id')} from the menu queue`)
}
}
PS5Menuクラスを使用するにはどうすればよいですか?
このクラスには、setterとstatic関数の2つのメソッドがあり ます 。それらは配列メソッドとほぼ同じこと を 行い、私たちの配列で行います 。 たとえば、クラスメニューのインスタンスを作成し、それをスタックのメニューに追加または削除するには、メソッドを 呼び出して、クラスのインスタンスから直接呼び出すことができます 。
push(argument)
pop()
.push()
.pop
this.queue
push
pop
// instantiate the menu object from class
const menu = new PS5Menu()
// add menu to the stack
menu.push = `system`
// remove the last menu that was pushed onto the stack from it
menu.pop()
このようなクラスセッター関数
set push()
は、で呼び出すことはできません
()
。代入演算子を使用して値を代入します
=
。クラスセッター関数
set push()
は、このパラメーターを使用して実行されます。
すでに行ったすべてを組み合わせてみましょう。
/* Your DOM just loaded */
window.addEventListener('DOMContentLoaded', event => {
// Instantiate the queable menu
const menu = new PS5Menu()
// Push system menu onto the menu
menu.push = `system`
// Attach click event to Start button
menu.queue[0].addEventListener(`click`, event => {
console.log(`Start button pressed!`)
// begin the ps5 demo!
menu.push = `main`
});
});
ここでは、クラスのインスタンスを作成し、
PS5Menu
そのオブジェクトインスタンスを変数に格納しました
menu
。
次に、IDを持つ最初のメニューで複数のメニューをキューに入れました
#system
。
次に、スタートボタンにイベント を添付しました
click
。このボタンをクリックすると、メインメニュー(と
id
、等しい
main
)が現在のメニューになります。この場合、システムメニューは非表示になり(メニューは現在メニューキューにあります)、コンテナが表示されます
#menu
。
メニューコンテナクラス
.menu.current
にはプロパティがあるため、
transform: 400ms;
次に
.current
、要素からクラス を追加または削除するだけで、新しく追加または削除されたプロパティが0.4ミリ秒以内にアニメーション化されます。
次に、メインメニューのコンテンツを作成する方法について考える必要があります。
このステップは、「Content Loaded」(
DOMContentLoaded
)DOMイベントで実行されることに注意してください 。これは、UIアプリケーションのエントリポイントである必要があります。2番目のエントリポイントはイベント
window.onload
ですが、このデモでは必要ありません。メディア(画像など)のダウンロードが完了するのを待ちます。これは、DOM要素が使用可能になるよりもはるかに遅く発生する可能性があります。
スプラッシュ画面
最初、メインUIは一連のいくつかの要素です。画面の右端から行全体が表示されます。最初に表示されるときは、左にドラッグしてアニメーション化します。
私はこれらの要素を次の
#main
ようにコンテナに埋め込みました :
<section id = "main" class = "menu f v h">
<section id = "tab" class = "f">
<div class = "on">Games</div>
<div>Media</div>
</section>
<section id = "primary" class = "f">
<div class = "sel t"></div>
<div class = "sel b current"></div>
<div class = "sel a"></div>
<div class = "sel s"></div>
<div class = "sel d"></div>
<div class = "sel e"></div>
<div class = "sel"></div>
<div class = "sel"></div>
<div class = "sel"></div>
<div class = "sel"></div>
<div class = "sel"></div>
</section>
</section>
最初のPS5メニューは、次のようにスタイル設定された親コンテナ内に配置されます。
#primary {
position: absolute;
top: 72px;
left: 1200px;
width: 1000px;
height: 64px;
opacity: 0;
/* animate at the rate of 0.4s */
transition: 400ms;
}
#primary.hidden {
left: 1200px;
}
デフォルトでは、非表示の状態
#primary
では、意図的に表示されていません。右に十分に移動します(1200px)。
試行錯誤を繰り返し、直感を使わなければなりませんでした。 1200pxがぴったりのようです。このコンテナも
opacity:0
クラスから継承 し
.menu
ます。
その
#primary
ため、初めて表示されるときは、スライドすると同時に明るさが増します。
ここでも、ほとんどのマイクロアニメーションは。で見栄えがするため、値
transform:400ms;
(同等
0.4s
)が使用され
0.4s
ます。値
0.3s
また、うまく機能しますが、速
0.5s
すぎたり遅すぎたりする可能性があります 。
CSSトランジションを使用してUIアニメーションを制御する
UIブロックのスタイルや位置を変更する必要があるたびにCSSスタイルを手動で操作する代わりに、クラスを割り当てたり削除したりするだけです。
// get element:
const element = $(`#primary`)
// check if element already contains a CSS class:
element.style.classList.contains("menu")
// add a new class to element's class list:
element.style.classList.add("menu")
// remove a class from element's class list:
element.style.classList.remove("menu")
これは、多くの時間を節約し、あらゆるバニラプロジェクトでコードをクリーンに保つ重要な戦略です。プロパティを変更する代わりに 、要素から
style.left
クラス
.hidden
を 削除するだけ
#primary
です。が付いている
transform:400ms;
ので、アニメーションが自動的に再生されます。
この戦術を使用して、UI要素のほぼすべての状態を変更します。
二次スライドアウトアニメーション
UXデザインを使用する場合、さまざまな種類のアニメーションがあります。一部のアニメーションは、新しいメニューに切り替えるとトリガーされます。これらは通常、新しい画面に切り替えた直後の短い時間の後に開始されます。
マウスまたはコントローラーが現在のナビゲーションメニューで新しい隣接アイテムを選択したときに起動するホバーアニメーションもあります。
特に高品質の製品を作成しようとしている場合は、細部に注意を払うことが重要です。
setTimeout関数を使用してアニメーションの状態を制御する
アイテムが引き出されると、小さなセカンダリアニメーションが再生さ れます。この二重効果をシミュレートするため
setTimeout
に、DOMツリーが完全にロードされた直後にJavaScript関数が使用さ れました。
これは[スタート]ボタンをクリックした直後に表示される最初のメニュー画面であるため、直後 のDOMContentLoadedイベントの[スタート
click
]ボタンイベント を更新する必要があり ます 。 次のコードは、既存のイベント関数の下部に配置されます (上記のソースコードの例を参照)。
menu.push = `main`
DOMContentLoaded
/* Your DOM just loaded */
window.addEventListener('DOMContentLoaded', event => {
/* Initial setup code goes here...see previous source code example */
// Attach click event to Start button
menu.queue[0].addEventListener(`click`, event => {
console.log(`Start button pressed!`)
// begin the ps5 demo!
menu.push = `main`
// new code: animate the main UI screen for the first time
// animate #primary UI block within #main container
primary.classList.remove(`hidden`)
primary.classList.add(`current`)
// animate items up
let T1 = setTimeout(nothing => {
primary.classList.add('up');
def.classList.add('current');
// destroy this timer
clearInterval(T1)
T1 = null;
}, 500)
});
});
何が起こったのか
私たちが書いたすべてのコードは、この最初のアニメーションになりました。
選択可能なアイテムを作成する
選択可能な要素(クラス
.sel
)のCSSはすでに作成されてい ます。
しかし、それでも素朴に見え、PS5インターフェースほど光沢はありません。
次のセクションでは、より優れたインターフェイスを作成するための可能性について説明します。UIをPlayStation5ナビゲーションシステムのプロフェッショナルなルックアンドフィールにまで高めます。
「選択された」または「現在の」要素の標準アニメーション
現在選択されているアイテムの3種類のアニメーション
PS5コンソールUIでは、現在選択されているアイテムには3つの視覚効果があります。回転する輪郭-「ハロー」、背景を移動する光のランダムなスポット、そして最後に「光の波」-コントローラーで押された方向ボタンの方向に移動する波のように見える効果。
このセクションでは、背景に光のスポットと光の波を使用して、クラシックなPS5ボタンのアウトライン効果を作成する方法を学習します。以下は、各タイプのアニメーションと、これらすべてのタイプに必要なCSSクラスの分析です。
グラデーション付きのアニメーションハロー
このエフェクトは、選択したアイテムを中心に回転するアニメーションの境界線を追加します。
CSSでは、これはテーパーグラデーションを回転させることでシミュレートできます。
選択可能な要素の一般的なCSSの概要は次のとおりです。
.sel {
position: relative;
width: 64px;
height: 64px;
margin: 5px;
border: 2px solid #1f1f1f;
border-radius: 8px;
cursor: pointer;
transition: 400ms;
transform-style: preserve-3d;
z-index: 3;
}
.sel.current {
width: 100px;
height: 100px;
}
.sel .under {
content:'';
position: absolute;
width: calc(100% + 8px);
height: calc(100% + 8px);
margin: -4px -4px;
background: #1f1f1f;
transform: translateZ(-2px);
border-radius: 8px;
z-index: 1;
}
.sel .lightwave-container {
position: relative;
width: 100%;
height: 100%;
transition: 400ms;
background: black;
transform: translateZ(-1px);
z-index: 2;
overflow: hidden;
}
.sel .lightwave {
position: absolute;
top: 0;
right: 0;
width: 500%;
height: 500%;
background: radial-gradient(circle at 10% 10%, rgba(72,72,72,1) 0%, rgba(0,0,0,1) 100%);
filter: blur(30px);
transform: translateZ(-1px);
z-index: 2;
overflow: hidden;
}
疑似要素
::after
と を使用しようとしました
::before
が、簡単な方法で目的の結果を得ることができず、ブラウザーによるそれらのサポートに疑問があります。さらに、JavaScriptには疑似要素にアクセスするためのネイティブな方法がありません。
代わりに、新しい要素を作成し、;
.under
を使用してそのZ位置を-1減らす ことにしました
transform: translateZ(-1px)
。したがって、カメラから離して、親がカメラの上に表示されるようにしました。 要素の3D空間でZオーダーを有効にするに
は、要素で識別される親要素に
.sel
プロパティ を追加する必要がある場合もあり
transform-style: preserve-3d;
ます。
理想的には
.under
、レイヤーを要素に ペアレント化し、実際のボタン要素を含む光のスポットを作成します。しかし、トリックの
translateZ
優先度は高く、それが私がUIの構築を始めたきっかけでもあります。再加工することはできますが、この段階では必要ありません。
HTMLは非常に単純です。ここで重要なのは、新しい要素があるということ
.under
です。これは、回転する円錐形のグラデーションをレンダリングして、微妙に光る境界線を作成する要素です。
.lightwave-container
で光を動かす効果を実装するのに役立ちます
overflow: hidden
。
.lightwave
-これは、エフェクトがレンダリングされる要素です。ボタンの境界を超え、オフセットされた放射状グラデーションを含む、より大きなdivです。
<div id = "o0" data-id = "0" class = "sel b">
<div class = "under"></div>
<div class = "lightwave-container">
<div class = "lightwave"></div>
</div>
</div>
2021年3月初旬の時点で、CSSアニメーションはグラデーションの背景回転をサポートしていません。
この問題を回避するために、組み込みのJavaScript関数を使用しました
window.requestAnimationFrame
。モニターのフレームレート(通常は60FPS)に従って、バックグラウンドプロパティをスムーズにアニメーション化します。
// Continuously rotate currently selected item's gradient border
let rotate = () => {
let currentlySelectedItem = $(`.sel.current .under`)
let lightwave = $(`.sel.current .lightwave`)
if (currentlySelectedItem) {
let deg = parseInt(selectedGradientDegree);
let colors = `#aaaaaa, black, #aaaaaa, black, #aaaaaa`;
// dynamically construct the css style property
let val = `conic-gradient(from ${deg}deg at 50% 50%, ${colors})`;
// rotate the border
currentlySelectedItem.style.background = val
// rotate lightwave
lightwave.style.transform = `rotate(${selectedGradientDegree}deg)`;
// rotate the angle
selectedGradientDegree += 0.8
}
window.requestAnimationFrame(rotate)
}
window.requestAnimationFrame(rotate)
この関数は、回転する境界線とより大きな光波要素をアニメーション化する役割を果たします。
イベントリスナーパラダイム
Reactやその他のフレームワークを使用していないため、イベントリスナーを自分で処理する必要があります。メニューを切り替えるたびに、前のメニューの親コンテナ内のすべてのアイテムからすべてのマウスイベントを切り離し、新しく選択したメニューの親コンテナ内のすべてのインタラクティブアイテムにマウスイベントリスナーをアタッチする必要があります。
各画面は一意です。最も簡単な方法は、各画面のイベントをハードコーディングすることです。これはハッキングではなく、それぞれの固有のナビゲーションシステムに固有のコードです。いくつかのことについては、単に便利な解決策がありません。
次の2つの機能は、異なる画面からのイベントを有効または無効にします。 PS5.jsの完全なソースコードを
見る すべてが一般的にどのように機能するかを理解する。
function AttachEventsFor(parentElementId) {
switch (parentElementId) {
case "system":
break;
case "main":
break;
case "browser":
break;
case "settings":
break;
}
}
function RemoveEventsFrom(parentElementId) {
switch (parentElementId) {
case "system":
break;
case "main":
break;
case "browser":
break;
case "settings":
break;
}
}
これにより、UXコードが個々のメニュー画面ごとに最適に実行されるように、マウスイベントをこれまで以上にリッスンすることがなくなります。
キーボードでナビゲートする
キーボードコントロールは、WebアプリケーションやWebサイトではめったに使用されません。そこで、基本的なキーを認識し、キーを押すイベントを簡単に接続できるバニラJSキーボードライブラリを作成しまし た。
次のキーを傍受する必要があります。
- 入力またはスペース-現在選択されている項目を選択します。
- 左、右、上、下-現在選択されているメニューのナビゲーション。
- エスケープ-現在キューに入れられているメニューをキャンセルし、前のメニューに戻ります。
次のように、すべての基本キーを変数にバインドできます。
// Map variables representing keys to ASCII codes
const [ A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z ] = Array.from({ length: 26 }, (v, i) => 65 + i);
const Delete = 46;
const Shift = 16;
const Ctrl = 17;
const Alt = 18;
const Left = 37;
const Right = 39;
const Up = 38;
const Down = 40;
const Enter = 13;
const Return = 13;
const Space = 32;
const Escape = 27;
次に、キーボードイベントハンドラーを作成します。
function keyboard_events_main_menu(e) {
let key = e.which || e.keyCode;
if (key == Left) {
if (menu.x > 0) menu.x--
}
if (key == Right) {
if (menu.x < 3) menu.x++
}
if (key == Up) {
if (menu.y > 0) menu.y--
}
if (key == Down) {
if (menu.y < 3) menu.y++
}
}
そして、それをドキュメントオブジェクトに接続します。
document.body.addEventListener("keydown", keyboard_events_main_menu);
サウンドAPI
まだ取り組んでいます...
それまでの間、バニラJSの簡単なサウンドAPIライブラリをここからダウンロードできます 。