質問の概要
現在MacOSで、純粋なC言語で、OpenGLを使ってルービックレース(スライドパズルに近いもの)を作っています。(不便ですが大学の課題の制約なので仕方ないです。)
結論から言うとコード内のmove関数のなかで呼び出すexchange関数が動いてくれません.
ゲームを作ること自体が初めてで、非常に汚いコードとなってしまったのですがどうかお付き合いお願いします.
トライしようとしていること
スライドパズルのパネルをクリックするとそのパネルを動かすようにしたいです.構造体Panelで作られたp[25]は空白も含めた25個のパネルを現し,メンバに色と位置(ColorとPosition)があります.
moveはクリックしたところのパネルを(動かせる方向は必然的に一つしかないので)動かす関数で,その働きを,二つのパネルを交換するexchange関数で細分化して実装しようとしています.
トライしようとしていること
僕の見立てでは,表示された画面で空白の列にある左側のパネルを押せばそのパネルと空白が交換されるはずなのですが,そうなりません.
押した位置に対し「右に空白があります」などを出力するようにしているので試した限りでは,move関数の定義にある複雑なif文や入子構造に問題はないと思っています.
C
1//描画座標とマウス座標でy軸の向きが逆であることに注意!! 2#include<stdio.h> 3#include<stdlib.h> 4#include<time.h> 5#include <GLUT/glut.h> 6typedef struct{ 7 double Color[3]; 8 int Position[2]; 9}Panel; 10Panel p[25]; 11double white[3] ={1.0, 1.0, 1.0}; 12double yellow[3]={1.0, 1.0, 0.0}; 13double blue[3] ={0.0, 0.0, 1.0}; 14double green[3] ={0.0, 1.0, 0.0}; 15double red[3] ={1.0, 0.0, 0.0}; 16double orange[3]={1.0, 0.5, 0.0}; 17double black[3] ={0.0, 0.0, 0.0}; 18int position[25][2]=//パネルの左上の座標 19{ 20 {200,200},{240,200},{280,200},{320,200},{360,200}, 21 {200,160},{240,160},{280,160},{320,160},{360,160}, 22 {200,120},{240,120},{280,120},{320,120},{360,120}, 23 {200, 80},{240, 80},{280, 80},{320, 80},{360, 80}, 24 {200, 40},{240, 40},{280, 40},{320, 40},{360, 40} 25}; 26int WINDOW_WIDTH = 500; // ウィンドウの横幅 27int WINDOW_HEIGHT = 500; // ウィンドウの高さ 28int emp; 29void move(int x,int y); 30void exchange(Panel p1, Panel p2); 31void init(void){ 32 glClearColor(0.0, 0.0, 0.0, 1.0); 33} 34 35void display() { 36 int i; 37 // ウィンドウ表示内容のクリア 38 glClear(GL_COLOR_BUFFER_BIT); 39 40 // 枠線 41 glColor3d(1.0, 1.0, 1.0); 42 glLineWidth(10.0); 43 glBegin(GL_LINES); 44 glVertex2d(200, 40); 45 glVertex2d(200, 240); 46 glEnd(); 47 glBegin(GL_LINES); 48 glVertex2d(200, 240); 49 glVertex2d(400, 240); 50 glEnd(); 51 glBegin(GL_LINES); 52 glVertex2d(400, 240); 53 glVertex2d(400, 40); 54 glEnd(); 55 glBegin(GL_LINES); 56 glVertex2d(400, 40); 57 glVertex2d(200, 40); 58 glEnd(); 59 glLineWidth(1.0); 60 61 //中央9×9の枠線 62 glColor3d(1.0, 0.0, 1.0); 63 glLineWidth(10.0); 64 glBegin(GL_LINES); 65 glVertex2d(240, 80); 66 glVertex2d(240, 200); 67 glEnd(); 68 glBegin(GL_LINES); 69 glVertex2d(240, 200); 70 glVertex2d(360, 200); 71 glEnd(); 72 glBegin(GL_LINES); 73 glVertex2d(360, 200); 74 glVertex2d(360, 80); 75 glEnd(); 76 glBegin(GL_LINES); 77 glVertex2d(360, 80); 78 glVertex2d(240, 80); 79 glEnd(); 80 glLineWidth(1.0); 81 82 for(i=0;i<25;i++){ 83 glColor3d(p[i].Color[0], p[i].Color[1], p[i].Color[2]); 84 glRectd(p[i].Position[0], p[i].Position[1], p[i].Position[0]+39, p[i].Position[1]+39); 85 //最初二つが左上,あと二つが右下. 86 } 87 glFlush(); 88} 89 90void mouse(int button, int state, int x, int y) { 91 //クッリクしたところを動かす 92 if(button==GLUT_LEFT_BUTTON && state==GLUT_DOWN){ 93 move(x,y); 94 } 95} 96 97 98void reshape(int width, int height) { 99 // OpenGLウィンドウの描画範囲を設定 100 // 下記は描画範囲が[0, width] x [0, height]となるように設定している 101 glViewport(0, 0, width*2, height*2); 102 glMatrixMode(GL_PROJECTION); 103 glLoadIdentity(); 104 gluOrtho2D(0.0, (double)width, 0.0, (double)height); 105 WINDOW_WIDTH = width; 106 WINDOW_HEIGHT = height; 107} 108 109int main(int argc, char **argv) { 110 time_t t; 111 int i,j,tmp; 112 char move; 113 int panel[25]={1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,6,6,6,6,0}; 114 int goal[24] ={1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,6,6,6,6}; 115 //初期配置をランダムシャッフルで決める. 116 for(i=24;i>0;i--){ 117 time(&t); 118 srand(t); 119 j=rand()%(i+1); 120 tmp=panel[i]; 121 panel[i]=panel[j]; 122 panel[j]=tmp; 123 } 124 //↑(フィッシャーイエーツシャッフルの改良版であるダステンフェルドのアルゴリズムを使用.) 125 126 //コマンドベースコードの初期配列とGUIの初期配置の対応づけ 127 for(i=0;i<25;i++){ 128 if(panel[i]==1){ 129 for(j=0;j<3;j++){ 130 p[i].Color[j]=white[j]; 131 } 132 for(j=0;j<2;j++){ 133 p[i].Position[j]=position[i][j]; 134 } 135 }else 136 if(panel[i]==2){ 137 for(j=0;j<3;j++){ 138 p[i].Color[j]=yellow[j]; 139 } 140 for(j=0;j<2;j++){ 141 p[i].Position[j]=position[i][j]; 142 } 143 }else 144 if(panel[i]==3){ 145 for(j=0;j<3;j++){ 146 p[i].Color[j]=blue[j]; 147 } 148 for(j=0;j<2;j++){ 149 p[i].Position[j]=position[i][j]; 150 } 151 }else 152 if(panel[i]==4){ 153 for(j=0;j<3;j++){ 154 p[i].Color[j]=green[j]; 155 } 156 for(j=0;j<2;j++){ 157 p[i].Position[j]=position[i][j]; 158 } 159 }else 160 if(panel[i]==5){ 161 for(j=0;j<3;j++){ 162 p[i].Color[j]=red[j]; 163 } 164 for(j=0;j<2;j++){ 165 p[i].Position[j]=position[i][j]; 166 } 167 }else 168 if(panel[i]==6){ 169 for(j=0;j<3;j++){ 170 p[i].Color[j]=orange[j]; 171 } 172 for(j=0;j<2;j++){ 173 p[i].Position[j]=position[i][j]; 174 } 175 }else 176 if(panel[i]==0){ 177 emp=i; 178 for(j=0;j<3;j++){ 179 p[i].Color[j]=black[j]; 180 } 181 for(j=0;j<2;j++){ 182 p[i].Position[j]=position[i][j]; 183 } 184 } 185 } 186 187 // GLUTの初期化 188 glutInit(&argc, argv); 189 // ウィンドウのサイズを設定 190 glutInitWindowSize(WINDOW_WIDTH, WINDOW_HEIGHT); 191 // ウィンドウの作成 (引数はウィンドウのタイトル) 192 glutCreateWindow("RubicRace"); 193 // 描画に使う関数の登録 194 glutDisplayFunc(display); 195 // ウィンドウのサイズ変更時に呼ばれる関数の登録 196 glutReshapeFunc(reshape); 197 // マウス操作時に呼ばれる関数の登録 198 glutMouseFunc(mouse); 199 //初期化処理 200 init(); 201 // 描画ループの開始 202 glutMainLoop(); 203} 204//------------ 205 206//関数定義 207void move(int x, int y){ 208 if(x>=200 && x<=400 && y>=260 && y<=460/*200px四方かどうかの判断*/){ 209 210 if(((x>=p[emp].Position[0] && x<=p[emp].Position[0]+40) || (WINDOW_HEIGHT-y>=p[emp].Position[1] && WINDOW_HEIGHT-y<=p[emp].Position[1]+40)) && !(x>p[emp].Position[0] && x<p[emp].Position[0]+40 && WINDOW_HEIGHT-y>p[emp].Position[1] && WINDOW_HEIGHT-y<p[emp].Position[1]+40)){ 211 if(x<p[emp].Position[0]){//クッリクの右側に空きがある時(右へスライド) 212 exchange(p[(5*(y-260)/40)+(x-200)/40], p[emp]);//実験的に空白と,押した位置パネルのみ交換するようにしている. 213 printf("右に空白があります\n"); 214 }else 215 if(x>p[emp].Position[0]+40){//左へ 216 exchange(p[(5*(y-260)/40)+(x-200)/40], p[emp]); 217 printf("左に空白があります\n"); 218 }else 219 if(WINDOW_HEIGHT-y<p[emp].Position[1]){//上へ 220 exchange(p[(5*(y-260)/40)+(x-200)/40], p[emp]); 221 printf("上に空白があります\n"); 222 }else 223 if(WINDOW_HEIGHT-y>p[emp].Position[1]+40){//下へ 224 exchange(p[(5*(y-260)/40)+(x-200)/40], p[emp]); 225 printf("下に空白があります\n"); 226 } 227 //emp=(5*(y-260)/40)+(x-200)/40;//右辺はクリックをしたパネルのインデント 228 //↑予定で行けばクリックしたところが新たな空白にするのですが, 229 //exchangeがうまく行われないのでコメントアウトしています. 230 } 231 232 } 233} 234void exchange(Panel p1, Panel p2){ 235 int i; 236 double tmp; 237 //色を交換 238 for(i=0;i<3;i++){ 239 tmp=p1.Color[i]; 240 p1.Color[i]=p2.Color[i]; 241 p2.Color[i]=tmp; 242 } 243} 244
次なる問題
maisumakunさん,回答ありがとうございます。おかげでexchange関数は動作してくれました。
しかしパネルをクリックした後ウィンドウのサイズを変えるなどしてreshape関数を呼び出さないと変化しません。クッリクと同時にパネルが移動するようにしたいのですがどうしたら良いでしょうか。よろしくお願いします。
回答2件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2021/01/07 04:46
2021/01/07 04:48
2021/01/07 04:50