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

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

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

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

OpenGL

OpenGLは、プラットフォームから独立した、デスクトップやワークステーション、モバイルサービスで使用可能な映像処理用のAPIです。

MacOS(OSX)

MacOSとは、Appleの開発していたGUI(グラフィカルユーザーインターフェース)を採用したオペレーションシステム(OS)です。Macintoshと共に、市場に出てGUIの普及に大きく貢献しました。

Q&A

解決済

2回答

999閲覧

定義した関数が動いてくれない

takadaibuoyancy

総合スコア17

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

OpenGL

OpenGLは、プラットフォームから独立した、デスクトップやワークステーション、モバイルサービスで使用可能な映像処理用のAPIです。

MacOS(OSX)

MacOSとは、Appleの開発していたGUI(グラフィカルユーザーインターフェース)を採用したオペレーションシステム(OS)です。Macintoshと共に、市場に出てGUIの普及に大きく貢献しました。

0グッド

0クリップ

投稿2021/01/07 03:15

編集2021/01/07 04:45

質問の概要

現在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

よろしくお願いいたします.m(_ _)m
イメージ説明

次なる問題

maisumakunさん,回答ありがとうございます。おかげでexchange関数は動作してくれました。
しかしパネルをクリックした後ウィンドウのサイズを変えるなどしてreshape関数を呼び出さないと変化しません。クッリクと同時にパネルが移動するようにしたいのですがどうしたら良いでしょうか。よろしくお願いします。

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

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

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

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

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

guest

回答2

0

C言語では、引数はコピーされます

void exchange(Panel p1, Panel p2)の中でp1p2を変更しても、それはコピーに対する操作となり、渡した側には何も影響しません。

void exchange(Panel* p1, Panel* p2)のようにポインタでやり取りする必要があります。

投稿2021/01/07 03:33

maisumakun

総合スコア146018

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

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

takadaibuoyancy

2021/01/07 04:46

ありがとうございます!おかげでexchangeが動作しました。もしよろしければ「次なる問題」についても回答いただけると幸いです。
maisumakun

2021/01/07 04:48

すみません、GLUT環境でのプログラミング経験がないのでよくわからないです。
takadaibuoyancy

2021/01/07 04:50

そうですか。でも、ありがとうございました。
guest

0

自己解決

次なる問題について:
glutPostRedisplay()と言う再描画を行うコールバック関数をマウスアクションに組み込んだらできました。

投稿2021/01/07 06:13

takadaibuoyancy

総合スコア17

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問