[c言語 Handy Graphic] クリック処理について

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら

トピックに返信する


答えを正確にご入力ください。答えられるかどうかでスパムボットか否かを判定します。

BBCode: ON
[img]: ON
[flash]: OFF
[url]: ON
スマイリー: OFF

トピックのレビュー
   

展開ビュー トピックのレビュー: [c言語 Handy Graphic] クリック処理について

Re: [c言語 Handy Graphic] クリック処理について

#6

by みけCAT » 6年前

円の中心とマウスカーソルの距離が円の半径以内ならマウスカーソルが円の中にある、
という判定ができます。

「円の面積を求めて、その範囲内を条件として処理」というのは具体的にどのような処理なのかよくわからないので、
そう考えて良いかはわかりません。

Re: [c言語 Handy Graphic] クリック処理について

#5

by BlueRose » 6年前

動いているものに対するクリック処理はどのようにすれば良いでしょうか。
円の面積を求めて、その範囲内を条件として処理を行うと考えて良いのでしょうか。

Re: [c言語 Handy Graphic] クリック処理について

#4

by みけCAT » 6年前

main関数でjudgeの範囲外にアクセスしてしまう可能性がありますね。
judge[i]ではなく、judge[cir_color[i]]とするべきような気がします。

Re: [c言語 Handy Graphic] クリック処理について

#3

by BlueRose » 6年前

指摘していただいて箇所を修正しました。
しかし、やはりクリックするとエラーが発生してしまいます。

コード:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <handy.h>

/* ウィンドウ画面サイズ */
#define WindowX 800
#define WindowY 600

/* 色球を動かす範囲(プレイエリア) */
#define AreaX 400
#define AreaY 200

/* 爆弾サイズ */
#define BombX 600.0
#define BombY 400.0

/* 爆弾とプレイエリアの幅 */
#define WideX 200
#define WideY 50

#define Time rand()%35+10 //制限時間

#define Memory 10 //配色の記憶
#define Radius 20 // 色球の半径
#define Speed rand()%10+1 //色球の移動速度

/* オープニング処理 */
void Opening(){
  HgOpen(WindowX, WindowY);
  printf("Game Start!!\n");
}

/* 爆発シーンの描画関数 */
void Explosion(){
  int gid = HgImageLoad("bakuhatsu.png");
  HgImagePut(WindowX/2, WindowY/2, gid, 1.0, 0);
}

void GameOver() {
  printf("Game Over!!\n");
  HgClear(); // 描画削除
  Explosion();
}
/* クリア画面の描画関数 */
void Fanfare(){
  int gid = HgImageLoad("fanfare.png");
  HgImagePut(WindowX/2, WindowY/2, gid, 1.0, 0);
}

/* 爆弾の描画関数 */
void DrawBomb(){
  HgSetFillColor(HG_GRAY);
  HgBoxFill(100, 0, BombX, BombY, 1);
}

/* プレイエリアの描画関数 */
void PlayArea(){
  HgSetFillColor(HG_WHITE);
  HgBoxFill(WideX, WideY, AreaX, AreaY, 1);
}

#define Burn 0 //爆発
#define Stop 1 //解除
#define More 2 //増殖

/* 爆発・解除・増殖判定の設定*/
void Shuffle(int judge[], int cir_color[]){
  int i;
  int ballcount = 3;
  for(i = 0; i < 3; i++){
    int j = rand()%3;
    int t = judge[i];
    judge[i] = judge[j];
    judge[j] = t;
  }
  /* 爆発・解除・増殖判定を各色に割り当てる */
   for(i = 0; i < ballcount; i++){
     cir_color[i] = judge[i];
   }
}

/* メイン処理 */
int main(){
  srand(time(NULL));
  double tl = Time; //制限時間
  int  fin = 0;
  /* 色球の初期位置・移動速度 */
  int x[Memory] = {220, 220, 220}, vx[Memory];
  int y[Memory] = {220, 220, 220}, vy[Memory];
  /* 色球の配色、配色を覚える配列(「増殖」判定があるので、10個分用意) */
  int color[3], cir_color[Memory] = {0, 0, 0};
  int judge[3] = {Burn, Stop, More}; //役割を配列に入れる
  int i, ballcount = 3; // カウンタ変数、球の個数

  Opening();

  color[0] = HG_RED;
  color[1] = HG_GREEN;
  color[2] = HG_BLUE;

  for(i = 0; i < ballcount; i++){
    vx[i] = Speed;// x 方向の移動速度
    vy[i] = Speed;  // y 方向の移動速度
  }
  /* 爆発・解除・増殖判定を設定する */
   Shuffle(judge, cir_color);

  HgSetEventMask(HG_MOUSE_DOWN);
  for(;;){
    HgSleep(0.1); //描画表示時間
    HgClear(); //描画削除
    DrawBomb(); //爆弾描画

    /* 制限時間表示 */
    HgSetColor(HG_BLACK);
    HgText(500, 500, "%.1f", tl);

    tl -= 0.1; //0.1秒毎に時間を減らす

    /* 制限時間終了後、爆発の演出をさせる */
    if(tl <= 0.0){
      GameOver();
      break;
    }

    PlayArea();

    for(i = 0; i < ballcount; i++){
      hgevent *event = HgEventNonBlocking();
      HgSetFillColor(color[cir_color[i]]);
      HgCircleFill(x[i], y[i], Radius, 1);
      /* 色球を選択した場合の処理 */
      if(event != NULL){
        x[i] = event->type;
        y[i] = event->type;
        /*「爆発」のとき*/
        if(judge[i] == Burn){
          fin = 2;
          HgClear();
          HgClose();
          break;
          /*「解除」のとき*/
        }else if(judge[i] == Stop){
          fin = 1;
          HgClear();
          HgClose();
          break;
          /*「増殖」のとき*/
        }else{
          printf("I Increaced Balls\n");
          printf("And Shuffle Judge Now...\n");
          ballcount++; //球の個数を増やす
          Shuffle(judge, cir_color); //役割を割り当てる
          x[i] = event->x;
          y[i] = event->y;
          HgSetFillColor(color[cir_color[i]]);
          HgCircleFill(x[i], y[i], Radius, 1);
        }
      }
      /* 色球が10以上になったら、ゲームオーバーとして終了 */
      if(ballcount > Memory){
        fin = 2;
        HgClear();
        HgClose();
        break;
      }
      /* x, y 方向に移動させる */
      x[i] += vx[i];
      y[i] += vy[i];

      /* 色球のバウンド処理 */
      if(x[i] >= AreaX + WideX - Radius){
        vx[i] = -vx[i];
      }else if(x[i] < WideX + Radius){
        vx[i] = -vx[i];
      }
      if(y[i] >= AreaY + WideY - Radius){
        vy[i] = -vy[i];
      }else if(y[i] < WideY + Radius){
        vy[i] = -vy[i];
      }

      /* 壁に当たる毎に色を変えていく */
      if(x[i] >= AreaX + WideX - Radius || x[i] < WideX + Radius
          || y[i] >= AreaY + WideY - Radius || y[i] < WideY + Radius)
      {
        cir_color[i]++;
        /* 青の次を赤にする */
        if(cir_color[i] == 3){
          cir_color[i] = 0;
        }
      }
    }

    switch (fin) {
      case 1:
        printf("Game Clear!!\n");
        HgClear(); // 描画削除 
        Fanfare();
        break;
      case 2:
        GameOver();
        break;
    }
  }

  HgGetChar();
  HgClose();
  return 0;
}

Re: [c言語 Handy Graphic] クリック処理について

#2

by みけCAT » 6年前

main関数内のx, y, vx, vyはそれぞれ3要素しか無いのに、ballcountを3から増やしてしまうと、
配列の範囲外にアクセスすることになり、危険です。
cir_colorだけでなく、色球のパラメータ全てについて、十分な要素数を確保しないといけません。
色球1個分のパラメータを構造体にまとめ、その構造体の配列を用意するのもいいかもしれません。

[c言語 Handy Graphic] クリック処理について

#1

by BlueRose » 6年前

はじめまして、c言語およびプログラミングを学び始めて1年近くになるの者です。
現在、
[時限爆弾]
・赤、緑、青色の3つの色球がそれぞれ違う速度で決まった範囲内で移動しており、それらはあらかじめ「起爆」、「解除」、「増殖」の役割を持っている。色球は壁に跳ね返るごとに、赤→緑→青→赤の順に変色していく。3つの役割は球自体にではなく、各色にランダムに割り当てられる。壁に跳ね返ると球のもつ役割も変更される。これらをすべてクリックによって選択していき「解除」の色球を選択するとクリアとなる。「起爆」の色球を選択すると、ゲームオーバーとなり、時間以内に「解除」を選択できなくても同じである。「増殖」を選沢すると、色球が1つ増加され、各役割が再度割り当てられる。また色球が10個((7個増加))になったらゲームオーバーとなる(後に変更する予定)。
のような内容の簡単なゲーム制作をしているのですが、クリック処理が思いのほか上手くいかず
1.プログラム終了時にエラーが出る。または途中で落ちる。
2.色球がおかしな場所に出現する。
といった問題が起きています。
自分だけでは、いくら考えてもどのように手をつけて良いか分からないので、本掲示板でご相談を願った次第です。
差し支えなければご教授の方お願いします。
環境は、MacOS10.14.1 です。

コード:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <handy.h>

/* ウィンドウ画面サイズ */
#define WindowX 800
#define WindowY 600

/* 色球を動かす範囲(プレイエリア) */
#define AreaX 400
#define AreaY 200

/* 爆弾サイズ */
#define BombX 600.0
#define BombY 400.0

/* 爆弾とプレイエリアの幅 */
#define WideX 200
#define WideY 50

#define Time rand()%45+10 //制限時間

#define Memory 10 //配色の記憶
#define Radius 20 // 色球の半径
#define Speed rand()%20+1 //色球の移動速度

#define Burn 0 //爆発
#define Stop 1 //解除
#define More 2 //増殖

/* 爆発シーンの描画関数 */
void Explosion(){
  int gid = HgImageLoad("bakuhatsu.png");
  HgImagePut(WindowX/2, WindowY/2, gid, 1.0, 0);
  printf("Game Over!!\n");
}

/* クリア画面の描画関数 */
void Fanfare(){
  int gid = HgImageLoad("fanfare.png");
  HgImagePut(WindowX/2, WindowY/2, gid, 1.0, 0);
  printf("Game Clear!!\n");
}

/* 爆弾の描画関数 */
void DrawBomb(){
  HgSetFillColor(HG_GRAY);
  HgBoxFill(100, 0, BombX, BombY, 1);
}
/* 爆発・解除・増殖判定の設定*/
void Shuffle(int judge[], int cir_color[]){
  int i;
  int ballcount = 3;
  for(i = 0; i < 3; i++){
    int j = rand()%3;
    int t = judge[i];
    judge[i] = judge[j];
    judge[j] = t;
  }
  /* 爆発・解除・増殖判定を各色に割り当てる */
   for(i = 0; i < ballcount; i++){
     cir_color[i] = judge[i];
   }
}

/* メイン処理 */
int main(){
  srand(time(NULL));
  double tl = Time; //制限時間
  /* 色球の初期位置・移動速度 */
  int x[3] = {220, 220, 220}, vx[3];
  int y[3] = {220, 220, 220}, vy[3];
  /* 色球の配色、配色を覚える配列(「増殖」判定があるので、10個分用意) */
  int color[3], cir_color[Memory] = {0, 0, 0};
  int judge[3] = {Burn, Stop, More}; //役割を配列に入れる
  int i, ballcount = 3; // カウンタ変数、球の個数

  HgOpen(WindowX, WindowY);

  printf("Game Start!!\n");

  color[0] = HG_RED; //赤着色
  color[1] = HG_GREEN; //青着色
  color[2] = HG_BLUE; //緑着色

  for(i = 0; i < 3; i++){
    vx[i] = Speed;// x 方向の移動速度
    vy[i] = Speed;  // y 方向の移動速度
  }
  /* 爆発・解除・増殖判定を設定する */
   Shuffle(judge, cir_color);

  HgSetEventMask(HG_MOUSE_DOWN);
  for(;;){
    HgSleep(0.1); //描画表示時間
    HgClear(); //描画削除
    DrawBomb(); //爆弾描画

    /* 制限時間表示 */
    HgSetColor(HG_BLACK);
    HgText(500, 500, "%.1f", tl);

    tl -= 0.1; //0.1秒毎に時間を減らす

    /* 制限時間終了後、爆発の演出をさせる */
    if(tl <= 0.0){
      HgClear(); //前の描画(爆弾)を削除
      Explosion(); //爆発シーン
      break;
    }

    /* プレイエリア描画 */
    HgSetFillColor(HG_WHITE);
    HgBoxFill(WideX, WideY, AreaX, AreaY, 1);

    for(i = 0; i < ballcount; i++){
      HgSetFillColor(color[cir_color[i]]);
      HgCircleFill(x[i], y[i], Radius, 1);
      /* 色球を選択した場合の処理 */
      hgevent *event = HgEventNonBlocking();
      if(event != NULL){
        x[i] = event->type;
        y[i] = event->type;
        /*「爆発」のとき*/
        if(judge[i] == Burn){
          printf("Game Over!!\n");
          HgClear(); // 描画削除
          HgClose(); // プログラム終了
          return 0;
          /*「解除」のとき*/
        }else if(judge[i] == Stop){
          printf("Game Clear!!\n");
          HgClear(); // 描画削除 
          HgClose(); // プログラム終了
          return 0;
          /*「増殖」のとき*/
        }else{
          printf("I Increaced Balls\n");
          printf("And Shuffle Judge Now...\n");
          ballcount++; //球の個数を増やす
          Shuffle(judge, cir_color); //役割を割り当てる
          HgSetFillColor(color[cir_color[i]]);
          HgCircleFill(x[i], y[i], Radius, 1);
        }
      }
      /* 色球が10以上になったら、ゲームオーバーとして終了 */
      if(ballcount == Memory){
        printf("Game Over!!\n");
        HgClear();
        HgClose();
      }

      /* x, y 方向に移動させる */
      x[i] += vx[i];
      y[i] += vy[i];

      /* 色球のバウンド処理 */
      if(x[i] >= AreaX + WideX - Radius){
        vx[i] = -vx[i];
      }else if(x[i] < WideX + Radius){
        vx[i] = -vx[i];
      }
      if(y[i] >= AreaY + WideY - Radius){
        vy[i] = -vy[i];
      }else if(y[i] < WideY + Radius){
        vy[i] = -vy[i];
      }

      /* 壁に当たる毎に色を変えていく */
      if(x[i] >= AreaX + WideX - Radius || x[i] < WideX + Radius
          || y[i] >= AreaY + WideY - Radius || y[i] < WideY + Radius)
      {
        cir_color[i]++;
        /* 青の次を赤にする */
        if(cir_color[i] == 3){
          cir_color[i] = 0;
        }
      }
    }
  }

  HgClose();
  return 0;
}

ページトップ