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

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

ただいまの
回答率

87.37%

canvasで文字数の大きさに合わせて図形を自動で合わせるには?

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,150

score 16

イメージ説明

前提・実現したいこと

作って覚えるC#2017のサンプルアプリで
1文字の漢字と同じ漢字の円を探して同じ色の円をクリックすると
正解の〇がでるというアプリがあり、
それを元に

CANVASを使い図形内の文字が2文字でもボールが流れるように移動させたい
(現在は跳ね返りなどは正確だが追加分の文字が残る)

発生している問題・エラーメッセージ

(現在は跳ね返りなどは正確だが追加分の文字が残る
不正解の文字を配列からランダムに表示させようとしたがエラーになる
あとは、不正解の文字をランダムに出現させようと
配列にしましたが取り出せなくなりました
(画像はランダムにしていないものです)

試したこと

半径の大きさを2倍にした
→円が大きくなるだけでした

補足情報(FW/ツールのバージョンなど)

ここにより詳細な情報を記載してください。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace MoveCircle
{
    public partial class FormBallGame : Form
    {
        // クラス共通の変数
        private Bitmap canvas;                  // 画面下の描画領域
        private Ball[] balls;                   // 複数のボールを管理する配列
        private string[] kanjis;                // ボールに描く漢字の配列
        private Brush[] brushes;                // ボールを塗る色の配列
        private string fontName = "HG教科書体"; // 表示する漢字のフォント名
        private string correctText = "福嶋";      // 正解の文字:1つだけ
        string[] ary = {
"福隝",
"福嶌",
"幅嶋",
"幅隝",
"副隝",
"副嶋",
"福島",
"愊隝",
"楅嶋",
"服隝",
"伏島",
"福縞"};
        private string mistakeText = ary[];      // 間違いの文字:ボールの個数分並ぶ


        private string circleText = "○";       // 正解した場合背景の文字を○にする
        private double nowTime = 0;             // 経過時間
        private int ballCount = 5;              // ボールの数
        private int randomResult = 0;           // 正解の番号:0~ボールの数のいずれか

        public FormBallGame()
        {
            InitializeComponent();
        }

        //--------------------------------------------------------------------
        // イベントハンドラ
        //--------------------------------------------------------------------

        // フォーム起動時に実行するLoad イベントに対応するイベントハンドラ
        private void FormBallGame_Load(object sender, EventArgs e)
        {
            InitGraphics();
            SetStartPosition();
        }

        // restartButtonのClick イベントに対応するイベントハンドラ
        private void restartButton_Click(object sender, EventArgs e)
        {
            InitGraphics();
            SetStartPosition();
        }

        // 上のselectPictureBoxのMouseClick イベントに対応するイベントハンドラ
        private void selectPictureBox_MouseClick(object sender, MouseEventArgs e)
        {
            // 再スタートボタンが操作可能な場合は何もせずに処理終了
            if (restartButton.Enabled)
            {
                return;
            }
            // 押されたX座標で正解判定
            //<判定> 押されたボタンがマウスの左ボタン?
            if (e.Button == MouseButtons.Left)
            {
                // どの円を選択したかを計算で算出(クリックしたX座標の位置/PictureBoxの横幅)
                int selectCircle = e.X / selectPictureBox.Height;
                if (randomResult == selectCircle) // 正解の円を選んだ
                {
                    timer1.Stop();
                    DrowMainPictureBox(Brushes.Red, circleText, true);
                    restartButton.Enabled = true; // 再スタートボタンを操作可能に
                }
                else // 失敗
                {
                    DrowMainPictureBox(Brushes.Red, correctText, false);
                    // 移動の割合を減少させる
                    for (int i = 0; i < ballCount; i++)
                    {
                        balls[i].pitch = balls[i].pitch - balls[i].pitch / 2;
                    }
                    nowTime = nowTime + 10; // ペナルティー
                }
            }
        }

        // 下のmainPictureBoxのMouseClick イベントに対応するイベントハンドラ
        private void mainPictureBox_MouseClick(object sender, MouseEventArgs e)
        {
            // 再スタートボタンが操作可能な場合は何もせずに処理終了
            if (restartButton.Enabled)
            {
                return;
            }
            SetBalls(e.X, e.Y); // マウスをクリックした位置にボールをセット
        }

        // TimerコントロールのTick イベントに対応するイベントハンドラ
        private void timer1_Tick(object sender, EventArgs e)
        {
            for (int i = 0; i < ballCount; i++)
            {
                balls[i].Move();
            }

            nowTime = nowTime + 0.02;
            textTimer.Text = nowTime.ToString("0.00");
        }

        //--------------------------------------------------------------------
        // 独自のメソッド
        //--------------------------------------------------------------------

        // 上のselectPictureBoxに円を描く
        private void DrowCircleSelectPictureBox()
        {
            int height = selectPictureBox.Height; // 高さ
            int width = selectPictureBox.Width; // 幅
            Bitmap selectCanvas = new Bitmap(width, height);
            using (Graphics g = Graphics.FromImage(selectCanvas))
            {
                //g.FillEllipse(Brushes.LightBlue, 0, 0, height, height);
                for (int i = 0; i < ballCount; i++)
                {
                    g.FillEllipse(brushes[i], i * height, 0, height, height);
                }
                selectPictureBox.Image = selectCanvas;
            }
        }

        // 下のPictureBoxに描画する
        private void DrowMainPictureBox(Brush color, string text, bool trueFlag)
        {
            int height = mainPictureBox.Height; // 高さ
            int width = mainPictureBox.Width; // 幅
                                              //描画先とするImageオブジェクトを作成する
            if (canvas == null)
            {
                canvas = new Bitmap(width, height);
            }
            using (Graphics g = Graphics.FromImage(canvas))
            {
                // 正解用の背景色にする
                if (trueFlag)
                {
                    g.FillRectangle(Brushes.LightPink, 0, 0, width, height);
                }
                else
                {
                    g.FillRectangle(Brushes.White, 0, 0, width, height);
                }
                //背景に引数で指定した文字列を描画する
                g.DrawString(text,
                new Font(fontName, height - height / 4),
                color, 0, 0, new StringFormat());
                //MainPictureBoxに表示する
                mainPictureBox.Image = canvas;
            }
        }

        // 配列の初期化、画面の初期設定を行う
        private void InitGraphics()
        {
            brushes = new Brush[ballCount];
            kanjis = new string[ballCount];
            balls = new Ball[ballCount];
            // ブラシの色の設定

            // 色の詳細はこちら: https://msdn.microsoft.com/ja-JP/Library/aa358802.aspx
            brushes[0] = Brushes.LightPink;
            brushes[1] = Brushes.LightBlue;
            brushes[2] = Brushes.LightGray;
            brushes[3] = Brushes.LightCoral;
            brushes[4] = Brushes.LightGreen;
            // 上のImageオブジェクト
            DrowCircleSelectPictureBox();
            // 下のImageオブジェクト
            DrowMainPictureBox(Brushes.Gray, correctText, false);
            restartButton.Enabled = false; // 再スタートボタンを操作できないようにする
            textHunt.Text = correctText;

        }


        // ボールのインスタンスの作成とランダムな位置にボールを描く
        private void SetStartPosition()
        {
            // 漢字の設定
            for (int i = 0; i < ballCount; i++)
            {
                kanjis[i] = mistakeText; // 間違いの文字をセット
            }
            randomResult = new Random().Next(ballCount); //ボールの数分の乱数を取得
            kanjis[randomResult] = correctText; // 正解の文字の文字をセット
                                                // ボールクラスのインスタンス作成
            for (int i = 0; i < ballCount; i++)
            {
                balls[i] = new Ball(mainPictureBox, canvas, brushes[i], kanjis[i]);
            }
            // ランダムな位置にボールを描く
            int rndXMax = mainPictureBox.Width;
            int rndYMax = mainPictureBox.Height;
            SetBalls(new Random().Next(rndXMax), new Random().Next(rndYMax));
            // タイマーをスタートさせる
            nowTime = 0;
            timer1.Start();
        }


        // 引数の位置情報を利用してランダムにボールを描く
        private void SetBalls(int x, int y)
        {
            int rndXMax = mainPictureBox.Width;
            int rndYMax = mainPictureBox.Height;
            int rndX;
            int rndY;
            for (int i = 0; i < ballCount; i++)
            {
                rndX = new Random(i * x).Next(rndXMax);
                rndY = new Random(i * y).Next(rndYMax);
                balls[i].DeleteCircle(); // 以前のボールを削除
                balls[i].PutCircle(rndX, rndY); // 新しい位置にボールを描く
            }
        }
    }
}
  • 気になる質問をクリップする

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • y_waiwai

    2019/10/15 13:14

    これではコードが見づらいので、質問を編集し、<code>ボタンを押し、出てくる’’’の枠の中にコードを貼り付けてください

    キャンセル

  • SUGAKI

    2019/10/15 13:19

    大変申し訳ございません。
    失礼いたしました。
    これから修正します

    キャンセル

  • SUGAKI

    2019/10/15 13:24

    直しました、質問の仕方も色々間違えているかもしれないので
    お手数でなければまた教えてください

    キャンセル

  • SUGAKI

    2019/10/15 13:33

    今気づいたのですが今回テンプレートを使うのを忘れていたようです・・・
    見づらくて申し訳ございません

    キャンセル

回答 1

check解決した方法

0

自己解決しましたありがとうございました

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

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

  • ただいまの回答率 87.37%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る