質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Q&A

解決済

1回答

561閲覧

配列の表示する範囲を変えたい

nano_09

総合スコア15

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

0グッド

0クリップ

投稿2020/10/16 12:59

編集2020/10/16 13:44

前提・実現したいこと

forで配列を全部読みこんだ上で、canvasの表示範囲を変えずに、配列の中の左上の5から右下の5で囲んだ四角形の範囲を表示することって可能でしょうか。
ご教授よろしくお願いします。

該当のソースコード

html

1<!DOCTYPE html> 2<html> 3 <head> 4 <meta charset="utf-8"> 5 <title>sample</title> 6 <script src="../../jquery-3.5.1.min.js"></script> 7 </head> 8 <body> 9 <canvas id="canvas"></canvas> 10 <script type="text/javascript" src="main.js"></script> 11 </body> 12</html>

JavaScript

1var map = [ 2 [ 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1], 3 [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1], 4 [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1], 5 [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1], 6 [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1], 7 [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1], 8 [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1], 9 [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1], 10 [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1], 11 [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1], 12 [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1], 13 [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1], 14 [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1], 15 [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 5], 16]; 17 18 19function main(){ 20 var canvas = document.getElementById('canvas'); 21 canvas.width = 928; 22 canvas.height = 448; 23 24 var ctx = canvas.getContext('2d'); 25 26 var ground = new Image(); 27 ground.src = 'img/yuka1.png'; 28 29 ctx.fillStyle = "rgb( 0, 0, 0 )"; 30 31 ctx.fillRect(0, 0, 1056, 448); 32 33 for (var y=0; y<map.length; y++) { 34 for (var x=0; x<map[y].length; x++) { 35 if (map[y][x] === 0) 36 ctx.drawImage(ground,0,0,32,32,32*x,32*y,32,32); 37 } 38 } 39 40 41 window.requestAnimationFrame( main ); 42} 43window.addEventListener('load', main(), false);

試したこと

当たり前ですがfor文のyやxの値を変えて、表示範囲がずれる訳ではなくただ指定されなかった部分が表示されないだけでした…。
表示範囲を変える関数やら変数を作ろうと思いましたが、よくわかりませんでした。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

firegrape

2020/10/16 13:40

id = 'canvas' の部分のhtmlはありますでしょうか。
nano_09

2020/10/16 13:45

htmlはcanvasだけになります。
guest

回答1

0

ベストアンサー

配列の中の左上の5から右下の5で囲んだ四角形の範囲を表示することって可能でしょうか。

可能です。

反復処理の練習にちょうどよい題材に思いましたので、直接的な回答は避けますが、
MAP全体のデータ(二次元配列)から、表示したい指定範囲の二次元配列を抽出して複製する関数を作れば対応しやすいのではないでしょうか。

map[Y][X] とアクセスされる場合、次のような関数で目的範囲のMAPデータを取得することができます。

javascript

1const 2 X_MAX = 33, 3 Y_MAX = 14 4; 5 6function getSubMap( left, top, width=3, height=3 ) { 7 let rect = [], tmp; 8 if( top > Y_MAX - height ) { 9 top = Y_MAX - height; 10 } 11 if( left > X_MAX - width ) { 12 left = X_MAX - width; 13 } 14 15 for( let y = top; y < top+height; ++y ) { 16 for( let x = left; x < left+width; ++x ) { 17 if( x == left ) { rect.push(tmp=[]); } 18 tmp.push( map[y][x] ); 19 } 20 } 21 return rect; 22} 23 24// 右方向の index 3, 下方向の index 0 から 3 x 3 の範囲を抽出する例 25getSubMap( 3, 0 ) 26/* 27=> [ 28 [0, 5, 0], 29 [0, 0, 0], 30 [0, 0, 0] 31] 32 */

追記)

getSubMap()をどう活用していいのかがいまいちわかっておりません

ご質問のコードでは、計算済みの値をハードコードしていますが、
変化しうる値は、変数やオブジェクトにするなどしてコンピュータに計算させます。
(単純計算はコンピュータの得意とするところです)。

ご質問の main() 関数をいじってみました。

javascript

1var CHIP_WIDTH = 32; 2var CHIP_HEIGHT = 32; 3var IMG_CACHE = {}; // Image 4 5var MAP_WIDTH = 8; // 928; = 32 * 29 だが、ここでは 8 6var MAP_HEIGHT= 8; // 448 = 32 * 14 だが、ここでは 8 7 8function main() { 9 var canvas = document.getElementById('canvas'); 10 canvas.width = CHIP_WIDTH * MAP_WIDTH; 11 canvas.height = CHIP_HEIGHT * MAP_HEIGHT; 12 13 var ctx = canvas.getContext('2d'); 14 // canvas の width, height を受け付いだサイズ 15 16 //var ground = IMG_CACHE["ground"]; 17 //ground.src = 'img/yuka1.png'; 18 if( ! "ground" in IMG_CACHE ) { 19 IMG_CACHE["ground"] = new Image(); 20 IMG_CACHE["ground"].src = 'img/yuka1.png'; // サーバー問い合わせが起こる 21 } 22 23 // 黒色で完全に塗りつぶす 24 ctx.fillStyle = "rgb( 0, 0, 0 )"; 25 ctx.fillRect(0, 0, CHIP_WIDTH*32, CHIP_HEIGHT*32); 26 27 // (3,0)-(8,8) の範囲のマップデータを抽出する 28 sub = getSubMap( 3, 0, MAP_WIDTH, MAP_HEIGHT ); 29 30 for (var y=0; y<sub.length; y++) { 31 for (var x=0; x<sub[y].length; x++) { 32 if (sub[y][x] === 0) 33 ctx.drawImage(IMG_CACHE["ground"], 34 0, 0,CHIP_WIDTH, CHIP_HEIGHT, 35 CHIP_WIDTH*x,CHIP_HEIGHT*y,CHIP_WIDTH,CHIP_HEIGHT); 36 } 37 } 38 39 window.requestAnimationFrame( main ); 40}

map はグローバルに宣言されていますので、 sub という変数で抽出したMAPデータを扱い、既にできていた2重の for ループのコードは、抽出したMAPの範囲で描画します。
他にも、グローバルに宣言した変数を増やしています。

投稿2020/10/17 00:08

編集2020/10/18 08:05
AkitoshiManabe

総合スコア5434

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

nano_09

2020/10/17 07:24 編集

これはただ抽出しているだけということですか? また、今はmainの中の2重forの中で描画の指定をしていますが、getSubMapの邪魔になりますか?
AkitoshiManabe

2020/10/17 07:43

はい。単に抽出するだけの処理です。描画用の2重のforループの前に、getSubMap() で抽出することで「(抽出した)任意の範囲をCanvasに描く」ことを想定しています。ですので、邪魔にはなりません。 まずは目的の動作を実現することを考え、パフォーマンスは反復処理に十分に慣れてから考える。という答案です。
nano_09

2020/10/17 08:37

範囲といってもcanvas.width、canvas.heightに記述するわけではないですよね? なにかヒントとなるようなものを教えていただけないでしょうか。
AkitoshiManabe

2020/10/17 09:14

getSubMap() の座標はMAP(2次元配列)のインデックス座標になります。 ご自身のコードにも map[y][x] と扱っているのと同じ。 Canvasへ描画するには矩形サイズを用いて算出する必要があります。
nano_09

2020/10/17 09:46 編集

無知をさらすようで申し訳ないのですが、短形サイズを用いて算出というのはどういった感じでしょうか。 fillRectを使うということでしょうか。
AkitoshiManabe

2020/10/17 10:02

矩形サイズはご質問のコードから読み取れる 32 x 32 です。 fillRectの引数に与える数値は、座標変換のため、相似の計算をしています。
nano_09

2020/10/17 12:09

2つfillRectを用意するということでしょうか。
AkitoshiManabe

2020/10/17 23:34 編集

「MAPデータ => 2重forループで描画(ループ内でfillRect)」と、全体を表示する処理はできているのですから、分解して考えます。「MAP => 抽出 => 2重forループで描画(ループ内でfillRect)」とすれば、2つfillRect を用意する意味はありません。
think49

2020/10/18 00:49 編集

@nano_09 さん 横からですが、「質問文に書かれたコード」は理解していますか。 AkitoshiManabeさんは、質問のコードの延長で回答されていると思いますが、「理解してないコード」を改修しているのなら、前提が崩れます。 自分で理解しながら、書いたコードという前提で間違いはありませんか。
nano_09

2020/10/18 05:08

AkitoshiManabeさん>ですよね、すみません。抽出したものを表示に移すという仕組みをよく理解できていません。getSubMap()をどう活用していいのかがいまいちわかっておりません。
nano_09

2020/10/18 05:09

think49さん>質問文のコードは自分で一から書いたものなので理解しております。
think49

2020/10/18 06:26

@nano_09 さん https://teratail.com/questions/298675 のように動画の指示通りに書いたわけではなく、サンプルコードをコピペしたわけでもない。 一から調べて自分でコートを書いたので、一つ一つのコードの意味は理解している、ということですよね。 ならば、座標mapを作り、for x 2で二重ループし、ctx.drawImage()で描画するロジックを理解している事になります。 > 抽出したものを表示に移すという仕組みをよく理解できていません。getSubMap()をどう活用していいのかがいまいちわかっておりません。 そこは既に理解しているように読めて矛盾を感じてしまうのですか…。
nano_09

2020/10/18 07:01 編集

流れ等は参考にはしましたが、やはり分かった上で書かないとのちに色々実装するとなると苦しみますからね(その部分をいじれない)。 自分の理解では200×200のマップを2重ループで200×200読み込みます。次に、ctx.drawImageでgroundの左上の0,0から32,32,まで読み込みます。 そして座標は32ずつ表示しているので32*x、32*yで配列の対応するx、yのところに32×32の画像を表示します。 なので全体に画像が敷き詰められます。 ここからがわからないところで、 canvas.width&heightで100×200に指定すると、右側の100が表示されない。 右側の100を表示したいといっても、表示はmapの左上の0,0から開始するのでずらすことができない。 いかがでしょうか。間違いがあればご指摘ください。お願いします。
AkitoshiManabe

2020/10/18 07:19

回答したコードでは 右に4マス分(4*32)ずらしたデータを読んでいます。 > やはり分かった上で書かないとのちに色々実装するとなると苦しみます Canvasのサイズを物理的に小さくすると表示できる領域が狭まるのは当然ですので、「表示する範囲を絞る」処理を回答しています。
nano_09

2020/10/18 07:48

今色々試したところ表示する範囲を絞るという処理はできました。 ですが、ずらすという処理とは違うと思いますがこれでいけるのでしょうか。
AkitoshiManabe

2020/10/18 08:04

広大なMAPデータがあって、任意の範囲を絞る。その上で、MAPデータの端でループするかどうかを考える(回答した getSubMap() は、ループする場合に書き換える必要があります)。ご質問のコードにある main() について、少し弄ったものを追記しました。「表示する範囲を変えたい」という問題はひとまずの解決になるのではないでしょうか。
nano_09

2020/10/18 10:42 編集

main()にあてはめたところエラーとなるのですが……。 if( ! "ground" in IMG_CACHE ) を消したところ動きました!
AkitoshiManabe

2020/10/18 10:14

そのつもりですが、マップデータ=0の画像しか例示されていませんでしたので他の画像には対応していません。MAPのオフセット座標(表示したい範囲の左上)は (0,3) ですので、変更してみてください。 その上で、2次元配列にどのようにアクセスしているのかコードを追いかけると多少は理解が深まると思います。
nano_09

2020/10/18 10:44

できました!!最後まで丁寧に対応して頂いて誠にありがとうございました!!!
nano_09

2020/10/20 00:47

上下移動に対応することって可能でしょうか。
AkitoshiManabe

2020/10/20 03:20

できますよ。関数の引数に着目します。
nano_09

2020/10/20 04:18

sub = getSubMap( 3, 0, MAP_WIDTH, MAP_HEIGHT ); の0の値を正に増加させると変わらなく、負の増加させると真っ暗になります。 ここではないのでしょうか。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問