ページ 1 / 1
敵クラスから自機クラスの情報を得たい
Posted: 2020年11月14日(土) 22:47
by arita
こんにちは。
c++でゲームを作ろうとしています。そこで敵クラスから自機クラスの関数を呼ぶ必要が出てきました。
少し前の同じようなスレッドを読み、そのかたの参考にしていたサイト()。そこで敵クラスから自機クラスの関数を呼ぶ必要が出てきました。
少し前の同じようなスレッドを読み、そのかたの参考にしていたサイト(
https://bituse.info/game/shot/13)も見てみましたがうまくいきません。
そこで改めて同じような質問をさせて頂きます、ご容赦ください。
具体的な内容に入ります。
まず環境を述べます。OSはWindows、コンパイラはVisual Studio、ライブラリはOpensiv3dです。
今までcを使っていて最近c++を使い始めました。基本的なクラスの概念が理解できる程度です。また、ポインタはアドレスを持つことを知っている程度であまり使えません。c++の設計を今回の簡単なゲームを通して学ぼうと思っています。
設計はGameクラスの中にPlayerクラスのインスタンスplayer,Enemyクラスのインスタンスの配列enemyです。
またGameクラスはOpensiv3dのシーンマネージャーという機能から呼ばれるため、GameクラスがMyAppを継承していたり、独自のコンストラクタがありますが内容はGameクラス自体で完結しているので影響はないと思いますが念のため書かせていただいてます。また、Arrayは動的配列です。
以下コードです。関係がないところは割愛しています。
Game.hpp
コード:
#include"Player.hpp"
#include"Enemy.hpp"
class Game: public MyApp::Scene{
private:
Player player;
Array<Enemy*> enemy;
public:
Game(const InitData& init);
void update() override;
void draw() const override;
}
Game.cpp
コード:
#include"Game.hpp"
Game::Game(const InitData& init)
: IScene(init){
}
void Game::update()
{
player.update();
for (size_t i = 0; i < enemy.size(); i++) {
enemy[i]->update();
}
}
void Game::draw(){
}
Player.hpp
コード:
class Player{
private:
int _x;
public:
void update();
void draw() const;
}
Player.cpp
コード:
#include"Player.hpp"
void Player::update(){
}
void Player::draw()const{
}
Enemy.hpp
コード:
class Enemy{
private:
int _x;
public:
void update();
void draw() const;
void shot();
}
Enemy.cpp
コード:
#include"Enemy.hpp"
void Enemy::update(){
}
void Enemy::draw()const{
}
void Enemy::shot(){
//ここでplayerの情報を扱いたいです。
}
PlayerやEnemyのメンバー変数は10個ほど扱う予定です。
よろしくお願いいたします。
Re: 敵クラスから自機クラスの情報を得たい
Posted: 2020年11月15日(日) 07:53
by あたっしゅ
Windows 10 Pro 64bit 、Visual Studio2019 Community に OpenSiv3D v0.4.3 をインストールしましたが、
’MyApp’ 識別子がクラス名でも名前識別子でもありません。
と出て、ビルドできませんでした。
Re: 敵クラスから自機クラスの情報を得たい
Posted: 2020年11月15日(日) 13:36
by arita
あたっしゅさん、返信ありがとうございます。
siv3dのインストールまでしていただきお手数をおかけします。
MyAppの部分は割愛したところに書かれていました。また、;が抜けているところなどが見つかったため改めて単体で実行できるものを再提示させていただきます、失礼しました。
設計としてはMain.cppのMainの関数から始まり、while文のSystem::Updateがsiv3d独自のシーンマネージャーを毎ループ呼び、登録されたGameクラスが更新していく形になっています。また、シーンマネージャーを使うために共通の処理を書いたCommon.hppを各々のクラスでインクルードしています。
Main.cpp
コード:
#include"Common.hpp"
#include"Game.hpp"
void Main() {
// シーンを設定
MyApp manager;
manager
.add<Game>(State::Game);
while (System::Update()) {
if (!manager.update())
{
break;
}
}
}
Common.hpp
コード:
#pragma once
# include <Siv3D.hpp> // OpenSiv3D v0.4.2
// シーンの名前
enum class State
{
Game
};
// ゲームデータ
struct GameData
{
};
// シーン管理クラス
using MyApp = SceneManager<State, GameData>;
Gameクラス
Game.hpp
コード:
#pragma once
#include"Common.hpp"
#include"Player.hpp"
#include"Enemy.hpp"
class Game : public MyApp::Scene {
private:
Player player;
Array<Enemy*> enemy;
public:
Game(const InitData& init);
void update() override;
void draw() const override;
};
Gameクラス
Game.cpp
コード:
#include "Game.hpp"
Game::Game(const InitData& init)
: IScene(init) {
}
void Game::update()
{
player.update();
for (size_t i = 0; i < enemy.size(); i++) {
enemy[i]->update();
}
}
void Game::draw()const {
}
Playerクラス
player.hpp
コード:
#include"Common.hpp"
class Player {
private:
int _x;
public:
void update();
void draw() const;
};
Playerクラス
player.cpp
コード:
#include "Player.hpp"
void Player::update() {
Print << U"ok";
}
void Player::draw()const {
}
Enemyクラス
Enemy.hpp
コード:
#include"Common.hpp"
class Enemy {
private:
int _x;
public:
void update();
void draw() const;
void shot();
};
Enemyクラス
Enemy.cpp
コード:
#include "Enemy.hpp"
void Enemy::update() {
}
void Enemy::draw()const {
}
void Enemy::shot() {
//ここでplayerの情報を扱いたいです。
}
よろしくお願いします。
Re: 敵クラスから自機クラスの情報を得たい
Posted: 2020年11月16日(月) 18:38
by usao
Enemy::Shot()メソッドで情報が欲しいならば,最も単純な話としては,このメソッドの引数に情報を取ればよいだけではないでしょうか?
そうしない理由があるのであれば,質問に際して明言すべきでしょう.
GameがEnemyを保有しているということから,Enemyの公開メソッドはGameが呼ぶことになるのだと思われ,
また,GameはPlayerをも保有している存在なのであるから,
GameからEnemyの各メソッドに引数としてPlayerに関する必要な情報を渡すことは簡単に実現できるのではないかと思うのですが.
Re: 敵クラスから自機クラスの情報を得たい
Posted: 2020年11月16日(月) 22:28
by あたっしゅ
とりあえず、ビルドは出来ました。
以下は、ネット検索してみつかったもの
https://qiita.com/tyanmahou/items/595ff692573f4f0b2490
Siv3D から OpenSiv3D に乗り換えよう - Qiita(ja)
https://shizenkarasuzon.hatenablog.com/ ... /28/211339
【C++】Visual Studio 2019 に OpenSiv3D を導入する - とある科学の備忘録(ja)
https://siv3d.github.io/ja-jp/community/community/
コミュニティ - Siv3D(ja)
https://siv3d.jp/bbs/patio.cgi
Siv3D ユーザー助け合い所(ja)
https://siv3d.jp/bbs/patio.cgi?read=474&ukey=0
STLの描画(ja)
https://qiita.com/Reputeless/items/5bc7 ... 9%E3%82%8B
Siv3D の 3D プログラムテクニック集 - Qiita(ja)
https://qiita.com/yagiri000/items/d07afd84934d5c62bc7c
C++Siv3D 入門講座 Vol.00 はじめに - Qiita(ja)
https://siv3d.jp/bbs/patio.cgi?read=396
OpenSiv3d 専用 BBS(ja)
で、渋3D の機能を使っていないプログラムだが、
コード:
class TXY {
protected:
float _x;
float _y;
public:
TXY(): _x( 0.0f ), _y( 0.0f ) {}
TXY(const float xx, const float yy ): _x(xx), _y(yy) {}
float getR2(TXY& a) {
const float xx = a._x - _x;
const float yy = a._y - _y;
return xx * xx + yy * yy;
}
};
class Player: public TXY {
public:
void update();
void draw() const;
};
class Enemy: public TXY {
public:
void update();
void draw() const;
void shot();
};
class Game : public MyApp::Scene {
private:
Player player;
Array<Enemy*> enemy;
public:
Game(const InitData& init);
void update() override;
void draw() const override;
};
//
// 以下、どっかで...
//
const int R2=1*1;
for (size_t i = 0; i < enemy.size(); i++) {
if( player.getR2(enemy[ i ])<R2 ) {
// player と enemy[ i ] の衝突処理
}
}
上記のままではコンパイルできませんが、こんな感じで、どうでしょう。
Re: 敵クラスから自機クラスの情報を得たい
Posted: 2020年11月17日(火) 18:15
by arita
usaoさん、あたっしゅさん。返信ありがとうございます。
usaoさんの仰った引数に情報を渡す方法の場合、今後playerの座標以外も渡す必要がでた場合もすべて引数に渡していく感じなのでしょうか?C++による設計方法をあまり見たことないので知識がありません。ぜひご教授をお願いします。
あたっしゅさん、多くのサイトの提示ありがとうございます。最後の衝突処理の部分ですがGameクラスの中のメゾットとして入れていくのでしょうか。また、入れる場合Gameクラスの中のオブジェクト同士の判定や処理はすべてGameクラスのメンバとして扱っていくのでしょうか、それとも別のファイルか何かに分けるのセオリーでしょうか?ご教授していただけると幸いです。
Re: 敵クラスから自機クラスの情報を得たい
Posted: 2020年11月17日(火) 20:32
by usao
arita さんが書きました: ↑4年前
usaoさんの仰った引数に情報を渡す方法の場合、今後playerの座標以外も渡す必要がでた場合もすべて引数に渡していく感じなのでしょうか?C++による設計方法をあまり見たことないので知識がありません。ぜひご教授をお願いします。
単純に引数で渡すことで話が済むなら問題はないのでは.
(それでは何かしらの問題があるならば別の手を考える必要があるが)
引数の個数が増えたときに「たくさん並んでて嫌」とかならstructとか何かである程度の塊の形で渡してやれば
引数の個数という見た目はとりあえずどうとでもなるし,
playerに関する複数の情報が必要とかなら Player 型(の参照とか)をまるっと渡すとかでも良いかもしれないし.
Re: 敵クラスから自機クラスの情報を得たい
Posted: 2020年11月18日(水) 02:33
by arita
usaoさん、回答ありがとうございます。
引数に構造体を使用できるのを知りませんでした。これでプログラムが先に進めそうです。ありがとうございました。
Re: 敵クラスから自機クラスの情報を得たい
Posted: 2020年11月18日(水) 11:06
by usao
Enemy::Shot()とかEnemy::Update()とかが,実際にどれだけの情報を必要とすることになるのかがまだ定まっていないような状態なら,
(綺麗じゃないかもしれないけど)例えば,とりあえずこんな形にでもしておくとか.
コード:
//Player
class Player
{
public:
//現在の位置を返す
int GetPosition() const { return m_Position; }
private:
int m_Position; //位置
};
//ゲームデータへのアクセス手段
class IGameContext
{
public: //必要な情報の取得手段を提供
//Playerに関する情報の取得手段を返す
virtual const Player &GetPlayer() const = 0;
//※例えば,
//現在のスコアだとか経過時間だとかを参照して動きを変えるようなEnemyを実装したくなったとしたら,
//以下のようなメソッドをここに増やせばいい
//現在のゲームスコアを返す
virtual unsigned int GetGameScore() const = 0:
//現在のステージ開始時刻からの経過時間を返す
virtual unsigned int GetElapsedTimeStepFromStageStart() const = 0;
};
//Enemy::Update()は,引数に与えらえたオブジェクトを介して必要な情報を取得する
void Enemy::Update( const IGameContext &IGC )
{
//Playerの現在の位置を取得
int CurrentPlayerPosition = IGC.GetPlayer().GetPosition();
//...
}
Re: 敵クラスから自機クラスの情報を得たい
Posted: 2020年11月18日(水) 20:23
by arita
usaoさん、返信ありがとうございます。
書いて頂いたコードでゲームの根幹がきれいにまとまりそうです。自分一人では確実にここまで至れませんでした、ありがとうございます。
Re: 敵クラスから自機クラスの情報を得たい
Posted: 2020年11月18日(水) 21:17
by あたっしゅ
とりあえず、動くコードを。参考:OpenSiv3D プロジェクトのテンプレート
// Common.h
コード:
#pragma once
// Common.h
//
//
#include <Siv3D.hpp> // OpenSiv3D v0.4.2
// シーンの名前
enum class State
{
Game
};
// ゲームデータ
struct GameData
{
};
// シーン管理クラス
using MyApp = SceneManager<State, GameData>;
//
class TXY {
public:
Vec2 m_xy;
TXY() { m_xy = RandomVec2(Scene::Rect() ); }
TXY(const float xx, const float yy ): m_xy(xx, yy) {}
double getR2(TXY& a) {
const double xx = a.m_xy.x - m_xy.x;
const double yy = a.m_xy.y - m_xy.y;
return xx * xx + yy * yy;
}
};
// end.
// Player.h
コード:
#pragma once
// Player.h
//
//
#include <Siv3D.hpp> // OpenSiv3D v0.4.3
#include "Common.h"
//
//
//
class Player: public TXY {
public:
void update();
void draw() const;
};
// end.
// Player.cpp
コード:
// Player.cpp
//
//
#include <Siv3D.hpp> // OpenSiv3D v0.4.3
#include "Common.h"
#include "Player.h"
void Player::update() {
m_xy = Cursor::Pos();
}
void Player::draw()const {
}
// end.
// Game,h
コード:
#pragma once
// Game.h
//
//
#include <Siv3D.hpp> // OpenSiv3D v0.4.3
#include "Common.h"
#include "Player.h"
#include "Enemy.h"
//
//
//
class Game : public MyApp::Scene {
private:
Texture cat;
Player player;
public:
Array<Enemy*> enemy;
Game(const InitData& init);
void update() override;
void draw() const override;
};
// end.
// Game.cpp
コード:
#include "Game.h"
// Game.cpp
//
//
Game::Game(const InitData& init): IScene(init)
{
// 猫のテクスチャを用意
cat = Texture(Emoji(U"🐛"));
enemy << new Enemy();
enemy << new Enemy();
enemy << new Enemy();
enemy << new Enemy();
enemy << new Enemy();
}
void Game::update()
{
player.update();
for (size_t i = 0; i < enemy.size(); i++) {
enemy[ i ]->update();
const double R2 = 20.0 * 20.0;
if (player.getR2( *enemy[ i ] ) < R2 ) {
System::Exit();
}
}
}
void Game::draw() const {
//Print << enemy.size();
for (size_t i = 0; i < enemy.size(); i++) {
// 大きさをアニメーションさせて猫を表示する
cat.resized(100 + Periodic::Sine0_1(1s) * 20).drawAt(enemy[ i ]->m_xy);
}
}
// end.
// Enemy.h
コード:
#pragma once
// Enemy.h
//
//
#include <Siv3D.hpp> // OpenSiv3D v0.4.3
#include "Common.h"
//
//
//
class Enemy: public TXY {
public:
void update();
void draw() const;
void shot();
};
// end.
// Enemy.cpp
コード:
// Enemy.cpp
//
//
#include"Enemy.h"
//
//
//
// 猫のテクスチャを用意
//const Texture cat(Emoji(U"🐈"));
void Enemy::update() {
}
void Enemy::draw() const {
}
void Enemy::shot() {
//ここでplayerの情報を扱いたいです。
}
// end.
// Main.cpp
コード:
// Main.cpp
//
// https://dixq.net/forum/viewtopic.php?f=3&t=21022&sid=3967390df6b7a989c5de300db2c021df
//
#include <Siv3D.hpp> // OpenSiv3D v0.4.3
#include "Common.h"
#include "Game.h"
//
//
//
void Main()
{
// シーンを設定
MyApp manager;
manager.add<Game>(State::Game);
// 背景を水色にする
Scene::SetBackground(ColorF(0.8, 0.9, 1.0));
// 大きさ 60 のフォントを用意
const Font font(60);
// 猫のテクスチャを用意
const Texture cat(Emoji(U"🐈"));
// 猫の座標
Vec2 catPos(640, 450);
while (System::Update())
{
// テキストを画面の中心に描く
font(U"Hello, Siv3D!🐣").drawAt(Scene::Center(), Palette::Black);
// 大きさをアニメーションさせて猫を表示する
cat.resized(100 + Periodic::Sine0_1(1s) * 20).drawAt(catPos);
// マウスカーソルに追従する半透明の赤い円を描く
Circle(Cursor::Pos(), 20).draw(ColorF(1, 0, 0, 0.5));
// [A] キーが押されたら
if (KeyA.down())
{
// Hello とデバッグ表示する
Print << U"Hello!";
}
// ボタンが押されたら
if (SimpleGUI::Button(U"Move the cat", Vec2(600, 20)))
{
// 猫の座標を画面内のランダムな位置に移動する
catPos = RandomVec2(Scene::Rect());
}
// 現在のシーンを実行
if (!manager.update())
{
break;
}
}
}
//
// = アドバイス =
// Debug ビルドではプログラムの最適化がオフになります。
// 実行速度が遅いと感じた場合は Release ビルドを試しましょう。
// アプリをリリースするときにも、Release ビルドにするのを忘れないように!
//
// 思ったように動作しない場合は「デバッグの開始」でプログラムを実行すると、
// 出力ウィンドウに詳細なログが表示されるので、エラーの原因を見つけやすくなります。
//
// = お役立ちリンク =
//
// OpenSiv3D リファレンス
// https://siv3d.github.io/ja-jp/
//
// チュートリアル
// https://siv3d.github.io/ja-jp/tutorial/basic/
//
// よくある間違い
// https://siv3d.github.io/ja-jp/articles/mistakes/
//
// サポートについて
// https://siv3d.github.io/ja-jp/support/support/
//
// Siv3D ユーザコミュニティ Slack への参加
// https://siv3d.github.io/ja-jp/community/community/
//
// 新機能の提案やバグの報告
// https://github.com/Siv3D/OpenSiv3D/issues
//
// end.
マウスカーソルを、虫の中央付近に合わせると、プログラムを終了します。
Re: 敵クラスから自機クラスの情報を得たい
Posted: 2020年11月19日(木) 00:18
by arita
あたっしゅさん、返信ありがとうございます。
送って頂いたコードを動かしたところ無事(?)怪しいプログラムが動きました。siv3dをここまで使ってくださりありがとうございます。