小学生からのJavaScript講座です。
前回、文字を一文字づつ表示させる方法と改行の方法を紹介しました。
今回はこのプログラムに、キー入力によって文字を切り替えられる機能をつけてみましょう。

ゲームはやっぱりキー入力で順番に物語を読んでいきたいよね

今日はそれを教えてもらえるんでしょ? 山田先生のところに行ってみようよ!

うん!
前回までのプログラムについて
前回までで、文字を一文字ずつ表示させ、改行するプログラムができています。

こんなプログラムだったべな……でも、長い文章を入力した場合、画面が文字で埋まってしまうんだべよ

そうならないようにキー入力で次の文章に切り替えられるようにして、一文ずつ表示されるようにしたいね!
配列を使って文章を作っていこう
文字を切り替えられるようにするには、配列を使って文章を入力しておくと便利です。

そういえば、そんなのがあったような……
まず、配列を使わない場合、文字を変数に代入するには以下のようにします。
const str = '吾輩は猫である。名前はまだ無い。どこで生れたかとんと見当がつかぬ。何でも薄暗いじめじめした所でニヤーニヤー泣いていた事だけは記憶して居る。';
上を配列を使うとこのようになります。
ここでは、切り替えたい文章ごとに区切っています。
const str = [ '吾輩は猫である。', '名前はまだ無い。', 'どこで生れたかとんと見当がつかぬ。何でも薄暗いじめじめした所でニヤーニヤー泣いていた事だけは記憶して居る。' ];
上の配列を使った例では、つまりこのように代入されていることになります。
str[0] : 吾輩は猫である。
str[1] : 名前はまだ無い。
str[2] : どこで生れたかとんと見当がつかぬ。何でも薄暗いじめじめした所でニヤーニヤー泣いていた事だけは記憶して居る。
つまり、配列の添字を指定することで、文字が切り替わるというふうになります。
なので、スペースキーで文字を切り替えたい時は、スペースキーが押された時に添字の数値を1増やすというふうに作ります。
配列からのデータを表示できるようにしてみよう!
このままだとまだ画面に文字は表示されません。
game.jsファイルをなおして、画面に配列からのデータを表示できるようにしてみましょう。
前回作ったgame.jsファイルのLabelクラスを変更していきます。
変更した場所は5,6行目、19行目、23行目、30行目、33行目です。
//Labelクラス class Label { //Labelの初期設定 constructor( label ) { //表示している場所の行数(追加) this._visibleLine = 0; //〜省略〜 } //Labelを表示するための関数(メインループから呼び出される) render( ctx, frame ) { ctx.fillStyle = this.color; ctx.font = this.font; ctx.textBaseline = this.baseline; //文字を表示する間隔(はやさ)が0の場合は、文字を一気に表示 if ( this.interval === 0 ) { //表示する文字数を、1行に表示する最大の文字数で割り、切り上げることで、その文字列が何行になるのかが分かる this._line = Math.ceil( this.label[ this._visibleLine ].length/this.maxLength ); //変更 //文字列の行数だけ繰り返す for( var i=0; i<this._line; i++ ) { this._text[i] = this._text[i] || ''; this._text[i] = this.label[ this._visibleLine ].substr( i*this.maxLength, this.maxLength ); //変更 //文字列の表示 ctx.fillText( this._text[i], this.x, this.y + ( i * 25 ) ); } } //文字を表示する間隔(はやさ)が0以外の場合、一文字ずつ表示していく else { if( this._displayLength < this.label[ this._visibleLine ].length && frame%this.interval === 0 ) { //変更 this._text[this._line] = this._text[this._line] || ''; //this.labelに代入されている文字列を、this._text[this._line]に一文字ずつ入れていく this._text[this._line] += this.label[ this._visibleLine ].charAt( this._displayLength ); //変更 this._displayLength++; if ( this._displayLength % this.maxLength === 0 ) { this._line++; } } for( var i=0; i<this._line+1; i++ ) { this._text[i] = this._text[i] || ''; ctx.fillText( this._text[i], this.x, this.y + ( i * 25 ) ); } } } }

上の例だとthis.label[0]を表示させていることになるんだべ

this._visibleLineには0が代入されているからだね!
実際にブラウザで見ると、このようになります。

ちなみに6行目でthis._visibleLineに1を代入すると「名前はまだ無い。」と表示され、2を代入すると「どこで生れたかとんと見当がつかぬ。何でも薄暗いじめじめした所でニヤーニヤー泣いていた事だけは記憶して居る。」と表示されるんだべ

キー入力があったらこの数値を切り替えるっていうプログラムを作ればいいんだね?
文字を切り替える関数を作ろう
文字を切り替える命令を書いていきたいのですが、今回は文字を切り替える為の関数を作る方法にしましょう。

うん!
class Label { //Labelの初期設定 constructor( label ) { //〜省略〜 } //次の行への切り替え機能 next() { this._visibleLine++; this._text = []; this._displayLength = 0; } //Labelを表示するための関数(メインループから呼び出される) render( ctx, frame ) { //〜省略〜 } }
このthis._visibleLine++;
で次の行へ、this._text = [];
やthis._displayLength = 0;
で、今代入されている文字や数値を初期化しています。

これで文章を切り替えられるようになったべ。でも3行しか入力していないべから、3回スペースキーを押すと、エラーになって何も表示されなくなってしまうべ。エラーはコンソールを見ると分かるべよ。
このエラーの回避方法はまた別の記事で学んでいくべ
枠内をクリックして、スペースキーを押してみてね!
全体のソース
最後に全体のソースを確認しておきましょう。
game.js
'use strict'; //Gameクラス class Game { constructor( width, height ) { this.objs = []; this.frame = 0; //もしもwidthやheight何も代入されていなければ、320を代入する this.width = width || 320; this.height = height || 320; this.canvas = document.getElementById( 'canvas' ); //canvasの横幅とたて幅 canvas.width = this.width; canvas.height = this.height; this.ctx = canvas.getContext( '2d' ); } //start()を呼び出すことで、メインループが開始される。 start() { this._main(); } //メインループ _main() { //背景を黒く塗りつぶす this.ctx.fillStyle = "#000"; this.ctx.fillRect( 0, 0, this.width, this.height ); //ゲームに登場するものの数だけ繰り返す for (let i=0; i<this.objs.length; i++) { //ゲームに登場するもののクラスから、render()を呼び出す this.objs[i].render( this.ctx, this.frame ); } //フレーム this.frame++; //_main()を呼び出す(ループさせる) requestAnimationFrame(this._main.bind(this)); } //ゲームにテキストなどを表示するための関数 add( obj, x, y ) { obj.x = x || 0; obj.y = y || 0; this.objs.push( obj ); } } //Labelクラス class Label { //Labelの初期設定 constructor( label ) { this._text = []; //表示している文字列の長さ this._displayLength = 0; //表示している場所の行数(追加) this._visibleLine = 0; this._line = 0; this.label = label; this.font = "20px 'ヒラギノ角ゴ Pro', 'Hiragino Kaku Gothic Pro', 'MS ゴシック', 'MS Gothic', sans-serif"; this.color = '#fff'; this.maxLength = 30; this.baseline = 'top'; this.interval = 0; } //次の行への切り替え機能 next() { this._visibleLine++; this._text = []; this._displayLength = 0; } //Labelを表示するための関数(メインループから呼び出される) render( ctx, frame ) { ctx.fillStyle = this.color; ctx.font = this.font; ctx.textBaseline = this.baseline; //文字を表示する間隔(はやさ)が0の場合は、文字を一気に表示 if ( this.interval === 0 ) { //表示する文字数を、1行に表示する最大の文字数で割り、切り上げることで、その文字列が何行になるのかが分かる this._line = Math.ceil( this.label[ this._visibleLine ].length/this.maxLength ); //文字列の行数だけ繰り返す for( var i=0; i<this._line; i++ ) { this._text[i] = this._text[i] || ''; this._text[i] = this.label[ this._visibleLine ].substr( i*this.maxLength, this.maxLength ); //文字列の表示 ctx.fillText( this._text[i], this.x, this.y + ( i * 25 ) ); } } //文字を表示する間隔(はやさ)が0以外の場合、一文字ずつ表示していく else { if( this._displayLength < this.label[ this._visibleLine ].length && frame%this.interval === 0 ) { this._text[this._line] = this._text[this._line] || ''; //this.labelに代入されている文字列を、this._text[this._line]に一文字ずつ入れていく this._text[this._line] += this.label[ this._visibleLine ].charAt( this._displayLength ); this._displayLength++; if ( this._displayLength % this.maxLength === 0 ) { this._line++; } } for( var i=0; i<this._line+1; i++ ) { this._text[i] = this._text[i] || ''; ctx.fillText( this._text[i], this.x, this.y + ( i * 25 ) ); } } } }
script.js
'use strict'; const str = [ '吾輩は猫である。', '名前はまだ無い。', 'どこで生れたかとんと見当がつかぬ。何でも薄暗いじめじめした所でニヤーニヤー泣いていた事だけは記憶して居る。' ]; //ゲームのオブジェクトを640×480サイズで作る let game = new Game( 640, 480 ); //ラベルオブジェクトを作る let label = new Label( str ); label.interval = 5; label.maxLength = 32; //add()を使って、ゲームにラベルを表示 game.add( label, 0, 0 ); //キーボードが押された時 addEventListener( "keydown", () => { const key_code = event.keyCode; //先ほど登録したスペースキーが押された時、label.next()を実行 if( key_code === 32) label.next(); event.preventDefault(); //方向キーでブラウザがスクロールしないようにする }, false); //ゲームスタート game.start();
まとめ
今回はキー入力で文字を切り替える方法を紹介しました。

これで長い文章も順番に表示できるね!

これで私と錦戸くんのラブラブノベルゲームがつくれるのね! きゃー!

またそれかよ……ちぇっ

夏は錦戸くんと海水浴、冬は私が編んだマフラーを錦戸くんにプレゼントするの

毛糸なら、わたすの毛を使って作るといいべよ。うぇ……おぇ……。はぁすっきりだべ。ほら、毛玉が出てきたべよ

……

絶対いらない……
このシリーズの一覧はこちら
- 小学生からのプログラミング入門。プログラミングってなぁに?
- Scratchの使い方と、ゲーム作りの基礎知識を学ぼう! 小学生からのプログラミング入門
- Scratchでじゃんけんゲームを作ろう! 小学生からのプログラミング入門
- Scratchでシューティングゲームを作ろう! 小学生からのプログラミング入門
- Scratchでピアノ鍵盤を作って音を鳴らそう! 小学生からのプログラミング入門
- テキストエディタ(Visual Studio Code)をインストールしてみよう! 小学生からのプログラミング入門
- Visual Studio Codeを日本語化してみよう! 小学生からのプログラミング入門
- JavaScriptでおみくじを作ろう! 小学生からのプログラミング入門
- JavaScriptで今月の残り日数を計算してみよう! 小学生からのプログラミング入門
- JavaScriptで画像を表示してみよう! 小学生からのプログラミング入門
- JavaScriptで画像を移動してみよう! 小学生からのプログラミング入門
- 【JavaScript】キー入力でキャラを動かしてみよう! 小学生からのプログラミング入門
- 【JavaScript】ファイルを分けて管理してみよう! 小学生からのプログラミング入門
- 【JavaScript】オブジェクトを使ってみよう! 小学生からのプログラミング入門
- 【JavaScript】ゲームのメインループを作ってみよう! 小学生からのプログラミング入門
- 【JavaScript】キャラを決まった間隔ずつ動かす! 小学生からのプログラミング入門
- HTML5とCanvasを使ってみよう! 小学生からのプログラミング入門
- 【JavaScript】迷路やRPGで使えるマップを作ってみよう! 小学生からのプログラミング入門
- 【JavaScript】マップでキャラを動かせるようにしよう! 小学生からのプログラミング入門
- 【JavaScript】クラスの概念をしっかりと理解しよう! 小学生からのプログラミング入門
- 【JavaScript】プログラム全体をクラスを使って作ってみよう! 小学生からのプログラミング入門
- 【JavaScript】文字を表示するクラスを作ってみよう! 小学生からのプログラミング入門
- 【JavaScript】改行と一文字ずつ画面に表示する方法! 小学生からのプログラミング入門
- 【JavaScript】ノベルゲーム風にキー入力で文字を切り替える方法! 小学生からのプログラミング入門
- JavaScriptでRPGを作ろう!スマホにも対応したゲームの作り方
- webpackを使ってゲームエンジンを作ろう!(JSライブラリの作り方)
- WindowsにPythonをインストールしてみよう!小学生からのPython入門
- MacにPythonをインストールしてみよう!小学生からのPython入門
- Pythonでじゃんけんゲームを作ってみよう!小学生からのPython入門
- Pythonのtkinterを使って、ウィンドウを表示してみよう!
- Pythonのtkinterで、画像つきのおみくじゲームを作ろう!