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

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

ただいまの
回答率

87.37%

[glfw]将来性のためキー入力はどういった形で実装するべきか?オブジェクト指向が知りたい。

解決済

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 786
退会済みユーザー

退会済みユーザー

キー入力についてなのですが場当たりなことはせず将来性を考えた設計をする際にどうやってキー入力を実装したらいいコードになるのか知りたいです。現状はWindowクラスにウインドウコンテキスト当を管理しているのですが"ここに実装するべき"コメント部に実装するべきなのでしょうか?またゲーム内容とフレームワーク部でオブジェクト指向を分けたいのでゲームプログラム内でwindowコンテキスト変数を直接触りたくなりません。現在は描画物は一つですがGame クラスを作ってそこにゲーム内容を記述してくといった規模の大きなプロジェクトになる場合どういった手法でプロ人は実装するのでしょうか?

//#define GLEW_STATIC    //スタティックリンク
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <vector>
#include <glew/include/GL/glew.h>
#include <glfw/include/GLFW/glfw3.h>



#include "Window.hpp"
#include "Shape.hpp"
#include "Shader.hpp"

Object::Vertex rectangleVertex[4] =
{
    {-0.5f,-0.5f},
    {0.5f,-0.5f},
    {0.5f,0.5f},
    {-0.5f,0.5f}
};


int main()
{
    if (glfwInit() == GL_FALSE)
    {
        std::cerr << "glfw初期化失敗。" << std::endl;
        return -1;
    }


    atexit(glfwTerminate);    //プログラム終了時の処理を登録
    Window window;

    //OpenGL Verison 3.2 Core Profile を選択する
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR,3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR,2);
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT,GL_TRUE);
    glfwWindowHint(GLFW_OPENGL_PROFILE,GLFW_OPENGL_CORE_PROFILE);

    Shape* shape = new Shape(2, 4, rectangleVertex);

    Shader shader("Test.vert","Test.frag");
    shader.setBindAttribVertex(0, "Position");
    shader.setBindAttribFragment(0, "fragment");


    glClearColor(1.0, 0.0, 0.0, 1.0);    //背景色
    while (window)
    {
        glClear(GL_COLOR_BUFFER_BIT);    //カラーバッファをクリア
        shader.Active();

        shader.setUniform2fv("location",window.getLocation());
        shader.setUniform1f("scale",window.getScale());
        shader.setUniform2fv("size",window.getSize());



        shape->Draw();    //表示物





        window.SwapBuffers();    //ダブルバッファリング
    }

}
#include "Window.hpp"

Window::Window(int width, int height, const char* title)
    :window(glfwCreateWindow(width,height,title,NULL,NULL)),
    scale(100.0f),
    location{ 0.0f,0.0f }

{
    if (window == NULL)
    {
        std::cerr << "ウインドウ生成失敗" << std::endl;
        exit(1);
    }

    glfwMakeContextCurrent(window);    //コンテキストを作成

    glewExperimental = GL_TRUE;
    if (glewInit() != GLEW_OK)
    {
        std::cerr << "GLFW 初期化失敗" << std::endl;
        exit(1);
    }

    atexit(glfwTerminate);    //プログラム終了時の処理を登録
    glfwSwapInterval(1);    //垂直同期

    glfwSetWindowUserPointer(window, this);    //このインスタンスのthis

    glfwSetWindowSizeCallback(window, Resize);    //ウインドウサイズを変更する時に呼び出す処理
    glfwSetScrollCallback(window,Wheel);        //マウスホイール操作時に呼び出す処理

    Resize(window, width, height);

}

//サイズ変更
void Window::Resize(GLFWwindow* const window, int width, int height)
{
    int fbWidth, fbHeight;
    glfwGetFramebufferSize(window, &fbWidth, &fbHeight);
    glViewport(0, 0, fbWidth, fbHeight);

    Window* const instance = (Window*)glfwGetWindowUserPointer(window);

    if (instance != NULL)
    {
        instance->size[0] = (GLfloat)width;
        instance->size[1] = (GLfloat)height;
    }
}

const glm::vec2 Window::getSize() const 
{
    return size;
}

GLfloat Window::getScale() const
{
    return scale;
}

const glm::vec2 Window::getLocation()const
{
    return location;
}


Window::~Window()
{
    glfwDestroyWindow(window);
}

void Window::Wheel(GLFWwindow* win, double x, double y)
{
    Window* const instance = (Window*)glfwGetWindowUserPointer(win);

    if (instance != NULL)
    {
        instance->scale += (GLfloat)y;
    }
}

Window::operator bool()
{
    glfwPollEvents();    //イベントを取り出す
//////////////////////////////////////////////////////////////////
//ここに書くべきか?
//////////////////////////////////////////////////////////////////

    //マウスをクリックしたとき
    if (glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_1) != GLFW_RELEASE)
    {
        //マウスカーソルの座標を取得
        double x, y;
        glfwGetCursorPos(window, &x, &y);

        //マウスカーソルの正規化デバイス座標系上での座標を求める
        location.x = (GLfloat)x * 2.0f / size.x - 1.0f;
        location.y = 1.0f - (GLfloat)y * 2.0f / size.y;
    }

    //ESCキーを押したら強制終了
    if (glfwGetKey(window, GLFW_KEY_ESCAPE))
    {
        return false;
    }

    //ウインドウを閉じる必要があれば false
    if (glfwWindowShouldClose(window) != 0)
    {
        return false;
    }
    else {
        return true;
    }
}

//ダブルバッファリング
void Window::SwapBuffers()const
{
    glfwSwapBuffers(window);
}
#ifndef ___WINDOW_HPP
#define ___WINDOW_HPP

#include <iostream>
#include <glew/include/GL/glew.h>
#include <glfw/include/GLFW/glfw3.h>
#include "glm/glm.hpp"


class Window
{
public:
    Window(int width = 640, int height = 480, const char* title = "Hello!");
    virtual ~Window();

    explicit operator bool();
    void SwapBuffers()const;    //ダブルバッファリング
    static void Resize(GLFWwindow* const window, int width, int height);    //サイズ変更
    const glm::vec2 getSize() const;
    GLfloat getScale() const;
    const glm::vec2 getLocation()const;
    static void Wheel(GLFWwindow* win, double x, double y);

    GLfloat scale;        //ワールド座標系に対するデバイス座標系の拡大率

private:

    GLFWwindow *const window;    //ウインドウコンテキスト

    glm::vec2 size;        //ウインドサイズ
    glm::vec2 location;    //図形の正規化デバイス座標上での位置


};

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

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

  • 退会済みユーザー

    2021/04/19 18:16

    複数のユーザーから「やってほしいことだけを記載した丸投げの質問」という意見がありました
    「質問を編集する」ボタンから編集を行い、調査したこと・試したことを記入していただくと、回答が得られやすくなります。

  • m.ts10806

    2021/04/19 18:47

    他人に説明出来て初めて「理解できる」わけですが、
    コード自体を適切に説明されたコメントを見たことがありません。
    「やりたいこと」だけ書いてある質問ばかりです。

    キャンセル

  • K_3578

    2021/04/20 11:19

    結局説得も通じなかった。
    何年泳げもしない河を泳いで渡ろうとしてるんだ。
    橋を架けろ。三回ぐらい飛び込んで渡ろうとしている間に作れる。

    キャンセル

回答 1

checkベストアンサー

+1

私は

プロ人

とかいう者ではないので,実際上の方法を述べられる立場にありませんから,単なる思い付きのアイデアを書くことになりますが…


「ゲーム」のロジックの側から見て,(ウィンドウやら何やらが実装されている世界の側に対して)要求したい事柄を考えて(整理して)みれば良いのではないでしょうか.

例えば,

  • キー入力状態が知りたい
  • ゲーム側の都合でプログラムを終了に向かわせたい(ゲームオーバーの時とかにプログラムが終わるようにしたい)
  • ゲーム側に必要な描画手段を伝えたい(それを使って描画処理を行ってもらう)
  • etc...

だとか.

そういった要求を行うための手段(それらのための関数群であったり,インタフェースクラスだったり)にゲームロジック側からアクセスできるならば,それらが具体的にどのように実装されているのか?なんてことは,ゲームロジック側は知る必要が無いです.例えば,キー入力について言えば

//引数で指定したキーが押されているかどうかを知る手段
bool GetKeyState( キーの種類 );

みたいな問い合わせ手段があれば,「キーの状態を実際に取得している手段は実は glfwGetKey() なる関数で,その引数には GLFWwindow* 型の何かを与える必要がある」とかいう事情を,この関数を呼ぶゲームロジック側は全く知らなくても済む.
知らなくて済むということは,ゲームロジック側の実装コードには GLFWwindow* みたいな物が現れないということ.
そしたら,

ゲームプログラム内でwindowコンテキスト変数を直接触りたくなりません

といった話が意図通りの方向に進むんじゃないでしょうか.

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2021/04/19 18:44

    windowクラスに実装することにしました。

    キャンセル

  • 2021/04/19 18:56

    とりあえず,そのコードの「将来」のことを考えるなら,
    GetKeyState()みたいなのをゲームロジック側に提供するためのインタフェースクラスを用意して,
    windowクラスそのものとかをゲームロジック側から隠すようにしとけばいいんじゃないかな.
    (最も単純には,windowクラスがそのインタフェースクラスを継承する)

    キャンセル

  • 2021/04/19 19:01

    class XXXInterface{ ... }; //GetKeyState()とかをゲームロジック側に提供する用

    class window : public XXXInterface { ... }; //XXXInterfaceの提供するメソッドの具体実装はwindowクラスにある

    とか.
    で,ゲームのロジック側は,プログラムのメインループから毎度呼ばれるメソッドを

    class GameLogic{ void Update( XXXInterfaceX & ); };

    とか何とかしとけばいいんじゃない?

    キャンセル

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

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

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

  • トップ
  • C++に関する質問
  • [glfw]将来性のためキー入力はどういった形で実装するべきか?オブジェクト指向が知りたい。