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

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

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

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

Q&A

解決済

2回答

1943閲覧

js入門者 テトリスのブロックを一次変換で回転させたい。

退会済みユーザー

退会済みユーザー

総合スコア0

JavaScript

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

0グッド

1クリップ

投稿2021/09/24 07:18

提示コードのコメント部のコードですがなぜ参考サイトを参考に一次変換を行っているのですが画面に表示されるブロックがおかしいのでしょうか?
p5ライブラリを使っています

参考サイト: http://www.geisya.or.jp/~mwm48961/kou2/linear_image3.html

イメージ説明

const STAGE_WIDTH = 10; const STAGE_HEIGHT = 20; const STAGE_OFFSET_WIDTH = 200; const STAGE_OFFSET_HEIGHT = 150; const CELL = 30; const DONW_SPEED = 10; const PLAYER_START_POSITION_X = 3; const PLAYER_START_POSITION_Y = 0; const ColorCode = [ [0,0,0], //背景 [255,255,255], //壁 [0,255,255], //水色 [255,255,0], //黄色 [0,128,0], //緑 [255,0,0], //赤 [0,0,166], //ネイビー [255,166,0], //オレンジ [128,0,128], //紫 ]; //ブロック const Block = [ ]; class Stage { constructor() { //ステージ this.stage = [ ] } Update() { } Renderer() { for(let y = 0; y < this.stage.length; y++) { for(let x = 0; x < this.stage[y].length; x++) { fill(ColorCode[ this.stage[y][x] ][0],ColorCode[ this.stage[y][x] ][1],ColorCode[ this.stage[y][x] ][2]); rect( STAGE_OFFSET_WIDTH + x * CELL,STAGE_OFFSET_HEIGHT + y * CELL,CELL,CELL); } } } } let keyRight = false; let keyLeft = false; let keyShift = false; let holdLeft = false; let holdRight = false; let holdShift = false; function keyPressed() { if( (keyCode === LEFT_ARROW) && (holdLeft == false) ) { holdLeft = true; keyLeft = true; } else if( (keyCode === RIGHT_ARROW) && (holdRight == false) ) { holdRight = true; keyRight = true; } else if( (keyCode === SHIFT) && (holdShift == false) ) { holdShift = true; keyShift = true; } else{ keyShift = false; keyRight = false; keyLeft = false; } } function keyReleased() { keyRight = false; keyLeft = false; holdRight = false; holdLeft = false; holdShift = false; keyShift= false; } class Player { constructor() { this.position = new Vector(3,0); this.put = true; this.blockNumber = GetRandom(0,6); this.animation = 0; this.block = [4]; this.block[0] = [0,0,0,0]; this.block[1] = [0,0,0,0]; this.block[2] = [0,0,0,0]; this.block[3] = [0,0,0,0]; this.KeyPrevLeft = false; this.KeyPrevShift = false; this.KeyPrevRight = false; this.isPut = false; this.isDown = false; } KeyBoard() { if(!this.KeyPrevLeft && keyLeft) { this.position.x--; } else if(!this.KeyPrevRight && keyRight) { this.position.x++; } else if(!this.KeyPrevShift && keyShift) { console.log("ああああ"); this.Rotate(); } this.KeyPrevLeft = keyLeft; this.KeyPrevRight = keyRight; this.KeyPrefShift = keyShift; } Rotate() { for(let y = 0; y < 4; y++) { for(let x = 0; x < 4; x++) { this.block[y][x] = 0; } } //////////////////////////////////////////////////////////////////////////////////////////////////////////// for(let y = 0; y < 4; y++) { for(let x = 0; x < 4; x++) { if(Block[this.blockNumber][y][x] != 0) { let xx = (cos(PI /2) * x) + (-sin(PI /2) * x ); let yy = (sin(PI /2) * y) + (cos(PI /2) * y ); //console.log(y); console.log(x + parseInt(xx,10) + " , " + parseInt(yy,10)); this.block[ y + parseInt(yy,10)][ x + parseInt(xx,10)] = 1; }else { //this.block[y][x] = 0; } } } } //////////////////////////////////////////////////////////////////////////////////////////////////////////// Update() { this.KeyBoard(); if((this.animation % DONW_SPEED) == 0) { this.position.y++; this.isDown = true; }else { this.isDown = false; } if(this.animation > 60) { this.animation = 0; } this.animation++; //console.log(this.position.x); } UpdateStage(stage) { for(let y = 0; y < STAGE_HEIGHT; y++) { for(let x = 0; x < STAGE_HEIGHT; x++) { //stage.stage[this.position.y + y][this.position.x + x] = Block[][][]; } } } //当たり判定 Collision(stage) { //壁判定 if( (keyLeft == true) || (keyRight == true) ) { for(let yy = 0; yy < 4; yy++) { for(let xx = 0; xx < 4; xx++) { if(Block[this.blockNumber][yy][xx] == 1) { if( (stage.stage[this.position.y + yy ][this.position.x + xx] == 1) ) { if(keyLeft == true) { this.position.x++; } else if(keyRight == true) { this.position.x--; } } } } } } if( this.isPut == false) { for(let yy = 0; yy < 4; yy++) { for(let xx = 0; xx < 4; xx++) { if((Block[this.blockNumber][yy][xx] == 1) ) { if( (stage.stage[this.position.y + yy ][this.position.x + xx] == 1) || (stage.stage[this.position.y + yy ][this.position.x + xx] > 1)) { this.position.y--; this.isPut = true; } } } } } if(this.isPut == true) { for(let yy = 0; yy < 4; yy++) { for(let xx = 0; xx < 4; xx++) { if((Block[this.blockNumber][yy][xx] == 1) ) { stage.stage[this.position.y + yy ][this.position.x + xx] = this.blockNumber + 2; } } } } if(this.isPut == true) { this.blockNumber = GetRandom(0,6); this.position.x = PLAYER_START_POSITION_X; this.position.y = PLAYER_START_POSITION_Y; this.isPut = false; } } Renderer() { for(let y = 0; y < 4; y++) { for(let x = 0; x < 4; x++) { if(this.block[y][x] != 0) { fill(ColorCode[ this.blockNumber ][0],ColorCode[ this.blockNumber ][1],ColorCode[ this.blockNumber ][2]); rect( (this.position.x * CELL) + STAGE_OFFSET_WIDTH + (x * CELL),(this.position.y * CELL) + STAGE_OFFSET_HEIGHT +(y * CELL),CELL,CELL); } } } } } class Game { constructor() { this.stage = new Stage(); this.player = new Player(); } Update() { this.player.Update(); this.player.Collision(this.stage); this.stage.Update(); } Renderer() { this.stage.Renderer(); this.player.Renderer(); } }

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

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

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

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

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

guest

回答2

0

ベストアンサー

そういうときは、16枚のマスのすべてについて、回転後、どのマスに移動するのか、計算してみるといいです。
2つの座標が、同じ1つの座標に写像されていると、ブロックが消えてしまうのでダメということになります。

肝心なところは -1.5 して回転して、 最後に +1.5 で丸めです。
4x4マスなのに、なぜ2.0ではないのか。

|--0--|--1--|--2--|--3--|

この中心座標は幾つでしょうか。
1.5 です。

最初の回答で 5x5 のとき 2.5 と言いましたが間違いで、
同じ理屈で 2.0 です。わかりますか?

私は java は書かないもので C ですみません。

C

1#include <stdio.h> 2#include <math.h> 3 4#define PI 3.1415926 5 6int main(void){ 7 8 float xx, yy; 9 10 for (int r=0; r<4; r++){ 11 12 printf("---左回転 %d 度---\n", r*90); 13 for (int x=0; x<4; x++){ 14 for (int y=0; y<4; y++){ 15 16 xx = (cos(PI / 2 * r) * ((float)x - 1.5)) + (-sin(PI / 2 * r) * ((float)y - 1.5) ); 17 yy = (sin(PI / 2 * r) * ((float)x - 1.5)) + (cos(PI / 2 * r) * ((float)y - 1.5) ); 18 19 //console.log(y); 20 printf ("[%d,%d] -> [%d,%d]\n", x,y, (int)round(xx + 1.5), (int)round(yy + 1.5)); 21 } 22 } 23 24 } 25}

OUTPUT

1---左回転 0 度--- 2[0,0] -> [0,0] 3[0,1] -> [0,1] 4[0,2] -> [0,2] 5[0,3] -> [0,3] 6[1,0] -> [1,0] 7[1,1] -> [1,1] 8[1,2] -> [1,2] 9[1,3] -> [1,3] 10[2,0] -> [2,0] 11[2,1] -> [2,1] 12[2,2] -> [2,2] 13[2,3] -> [2,3] 14[3,0] -> [3,0] 15[3,1] -> [3,1] 16[3,2] -> [3,2] 17[3,3] -> [3,3] 18---左回転 90 度--- 19[0,0] -> [3,0] 20[0,1] -> [2,0] 21[0,2] -> [1,0] 22[0,3] -> [0,0] 23[1,0] -> [3,1] 24[1,1] -> [2,1] 25[1,2] -> [1,1] 26[1,3] -> [0,1] 27[2,0] -> [3,2] 28[2,1] -> [2,2] 29[2,2] -> [1,2] 30[2,3] -> [0,2] 31[3,0] -> [3,3] 32[3,1] -> [2,3] 33[3,2] -> [1,3] 34[3,3] -> [0,3] 35---左回転 180 度--- 36[0,0] -> [3,3] 37[0,1] -> [3,2] 38[0,2] -> [3,1] 39[0,3] -> [3,0] 40[1,0] -> [2,3] 41[1,1] -> [2,2] 42[1,2] -> [2,1] 43[1,3] -> [2,0] 44[2,0] -> [1,3] 45[2,1] -> [1,2] 46[2,2] -> [1,1] 47[2,3] -> [1,0] 48[3,0] -> [0,3] 49[3,1] -> [0,2] 50[3,2] -> [0,1] 51[3,3] -> [0,0] 52---左回転 270 度--- 53[0,0] -> [0,3] 54[0,1] -> [1,3] 55[0,2] -> [2,3] 56[0,3] -> [3,3] 57[1,0] -> [0,2] 58[1,1] -> [1,2] 59[1,2] -> [2,2] 60[1,3] -> [3,2] 61[2,0] -> [0,1] 62[2,1] -> [1,1] 63[2,2] -> [2,1] 64[2,3] -> [3,1] 65[3,0] -> [0,0] 66[3,1] -> [1,0] 67[3,2] -> [2,0] 68[3,3] -> [3,0]

重複なく、写像されていることがわかります。

投稿2021/09/24 11:23

編集2021/09/24 11:27
ak.n

総合スコア291

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

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

0

まず、(通常の)テト〇ス風ゲームということでしたら、0, 90, 180, 270度の4パターンしかないので、回転行列などを用いずに、各ブロックにつき、この4回転パターンの配列を予め持たせてしまった方が得策です。

以下は、お勧めしませんが、回転行列でやろうと思えばこうなる、という話です。

Rotate() で 5x5のブロックを回転させています。

3つおかしなところがあります。

1番目:

js

1let xx = (cos(PI /2) * x) + (-sin(PI /2) * x ); 2let yy = (sin(PI /2) * y) + (cos(PI /2) * y );

ですが、行列の掛け算の計算が間違っていると思います。

js

1let xx = (cos(PI /2) * x) + (-sin(PI /2) * y ); 2let yy = (sin(PI /2) * x) + (cos(PI /2) * y );

2番目:

回転後のブロックを書き込むところで、[x + xx][y + yy] に書き込む、
という処理がよくわかりません。
xx, yy は元の座標から幾らずらすか、ではありません。
(x,y) を回転させた座標が (xx,yy) になったのですから、
[xx][yy] のままでよいです。
しかし、これでも駄目です。3番目の問題があります。

3番目:

この回転は、ブロックの左下(0,0)を中心に回転させています。
これでは、回転後のブロックを配列に書き込むときに配列をはみ出してしまいます。
従いまして、まったくお勧めしませんが、
無理やりやろうとするなら(2.5,2.5)を中心に回転させないとおかしくなります。
つまり、一時的に、Int でなく Float で計算して x, y をそれぞれ 2.5 引いておいて、原点中心に回転させてから、2.5 足してやる、最後に Int に戻すという処理が必要かと思います。

投稿2021/09/24 09:12

ak.n

総合スコア291

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

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

退会済みユーザー

退会済みユーザー

2021/09/24 10:20

なるほどありがとうざいます。自分は4x4でやっているためこのようにしたのですがブロックが欠ける、位置がおかしいなどのバグが出るのですが if(Block[this.blockNumber][y][x] != 0) { let xx = (cos(PI / 2) * (x - 2.0)) + (-sin(PI / 2) * (y - 2.0) ); let yy = (sin(PI / 2) * (x - 2.0)) + (cos(PI / 2) * (y - 2.0) ); //console.log(y); console.log(Math.round(yy + 2.0) + " , " + Math.round((xx + 2.0))); this.block[Math.round(yy + 2.0)][Math.round((xx + 2.0))] = 1; }else { //this.block[y][x] = 0; }
ak.n

2021/09/24 11:24 編集

失礼 4x4 ですね。 (0,0)~(3,3)までの16枚のパネルを実際にこの方法で計算して、どの座標に移るのか、計算されてみるとよいと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問