ページ 11

タイトル画面からの遷移

Posted: 2012年11月11日(日) 12:01
by XNABeginnerです
XNAでゲームをつくっているのですが、タイトル画面がうまくいきません。

「スタート」と「やめる」の二つのボタンがあり、
スタートを選択した状態でキーを押すと、プレイ画面に移行し、
やめるを選択した状態でキーを押すと、終了するようにしたいのですが、
どのようにしたらよろしいでしょうか?

どちらのもEnterキーで決定させるようにしており、
選択されていない方は画像を半透明にしてます。

タイトル、プレイ画面はそれぞれ、クラス化しており、ISceneというクラスを継承しています。
ISceneクラスは、初期化や更新や描画、次のシーンへ移行などのメソッドを持っています。

Re: タイトル画面からの遷移

Posted: 2012年11月13日(火) 08:39
by beatle
うまくいかない、とは、どううまくいかないのでしょうか。
何かエラーが出るのでしょうか。それとも、やり方が思いつかないということでしょうか。

Re: タイトル画面からの遷移

Posted: 2012年11月13日(火) 08:59
by XNABeginnerです
やり方がわかりません。

Re: タイトル画面からの遷移

Posted: 2012年11月13日(火) 09:32
by softya(ソフト屋)
ボタンの選択を管理しているなら、ENTERキー押した時に選択している方の処理をするメソッドを呼び出すだけだと思いますが。
ソースコードが無いので、曖昧な答えしか変えませんが自分でそこまで作れたのならさほど難しいことではないはずです。

Re: タイトル画面からの遷移

Posted: 2012年11月13日(火) 09:55
by XNABeginnerです
Game1クラスにあるUpdateメソッドのthis.Exit();を使いたいのですが、使えないのです。
Titleクラス {
private int activeCursor;
~省略~
public void Update() {
if (input.IsStartButtonDown) {
isEnd = true;
}

if (input.IsDownButtonDown) activeCursor = 0;
if (input.IsUpButtonDown) activeCursor = 1;

if (activeCursor == 1 && input.IsStartButtonDown) {
~ゲームを終了するようにしたい~
}
}

public void Draw {
if (activeCursor == 0) {
スタートボタンを半透明に表示
} else {
ストーとボタンを普通にを表示
}

if (activeCursor == 1) {
終わるボタンを半透明に表示
} else {
終わるボタンを普通に表示
}
}

Re: タイトル画面からの遷移

Posted: 2012年11月13日(火) 10:36
by softya(ソフト屋)
Game1クラスでthis.Exit();するための状態フラグを設定するメソッドをGame1クラスに追加すれば良いのではないでしょうか?
問題はTitleクラスからGame1クラスのオブジェクトが参照できるかどうかですが。

Re: タイトル画面からの遷移

Posted: 2012年11月13日(火) 10:51
by XNABeginnerです
それを前に試したことがあるのですが、オブジェクト参照できなかったのでトピックを立てました。
継承はISceneがあるので不可能です

Re: タイトル画面からの遷移

Posted: 2012年11月13日(火) 11:01
by softya(ソフト屋)
それではGame1クラスからTitleクラスが保持するどのボタンが押されていたかの情報を取得するメソッドをTitleクラスに追加できませんか。
押されていない。「スタート」が押された。「やめる」が押された。の3種類が戻り値として返せれば良いと思います。

Re: タイトル画面からの遷移

Posted: 2012年11月13日(火) 11:05
by XNABeginnerです
どう実装すればよろしいですか?

Re: タイトル画面からの遷移

Posted: 2012年11月13日(火) 11:16
by softya(ソフト屋)
ボタンの押された状態を変数に保持して、問い合わせメソッドでその状態を返すだけです。

・private int activeCursor;と同じように変数を追加。isEndEnterとか。
・コンストラクタで変数を初期化。
・~ゲームを終了するようにしたい~のところで変数に代入です。
・あとは状態を返すメソッドでこの値を返すだけです。

Re: タイトル画面からの遷移

Posted: 2012年11月13日(火) 11:39
by XN
どこに返せばよろしいでしょうか?

Re: タイトル画面からの遷移

Posted: 2012年11月13日(火) 11:42
by softya(ソフト屋)
それはGame1クラスです。Game1クラスが欲しい情報ですから。
Game1クラスからTitleクラスのオブジェクトは参照できませんか?

Re: タイトル画面からの遷移

Posted: 2012年11月13日(火) 11:55
by XNABeginnerです
SceneManagerクラスを使ってオブジェクト生成しているのでできるかわかりません
sceneManager.Add(Scene.Title, new Title(input, sound));

Re: タイトル画面からの遷移

Posted: 2012年11月13日(火) 12:06
by softya(ソフト屋)
> SceneManagerクラスを使ってオブジェクト生成しているのでできるかわかりません

そういう事は先に書いてもらうと答えが迷走しなくて済みますのでお互いのためです。

SceneManagerクラスかSceneクラスでも良いのですがGame1クラスとTitleクラスのオブジェクトが同時に参照できるところでTitleクラスからメソッドで情報を得てGame1クラスにメソッドで設定してやれば良いです。それも出来ませんか?

Re: タイトル画面からの遷移

Posted: 2012年11月13日(火) 12:10
by XN
Game1クラスのオブジェクトはありません。
TempleteMethodパターンを使ってゲームを動かしているので、
Game1クラスに初期化や更新などが書かれています。

Re: タイトル画面からの遷移

Posted: 2012年11月13日(火) 12:17
by softya(ソフト屋)
SceneManagerクラスが全体の状態を統括しているなら、まずSceneManagerクラスがTitleクラスを参照して終了状態に遷移すべきです。
そして、SceneManagerクラスが終了自体に遷移したらそれを受けてGame1が終了すべきでしょう。
それぞれメソッドを使って状況を受渡してください。

※XNAのクラスの関係は3年ぐらい前にちょっとやったきりで完全に忘れていますので細かい情報を貰わないと無理なことを書いてしますかも知れません。

【補足】
途中で名前を変更することはルール上で禁止ですので前の名前に戻してくださいね。

Re: タイトル画面からの遷移

Posted: 2012年11月13日(火) 12:22
by XN
SceneManagerクラスには終了処理はありません
class SceneManager
{
private IScene currentScene = null;
private Dictionary<Scene, IScene> scenes = new Dictionary<Scene, IScene>();

/// <summary>
/// コンストラクタ
/// </summary>
public SceneManager()
{

}

/// <summary>
/// 登録
/// </summary>
/// <param name="name"></param>
/// <param name="scene"></param>
public void Add(Scene name, IScene scene)
{
scenes[name] = scene;
}

/// <summary>
/// 変更
/// </summary>
public void Change(Scene name)
{
if (currentScene != null)
{
currentScene.Shutdown();
}

currentScene = scenes[name];

currentScene.Initialize();
}

/// <summary>
/// 更新
/// </summary>
public void Update()
{
if (currentScene == null) return;

currentScene.Update();

if (currentScene.IsEnd() == true)
{
Change(currentScene.Next());
}

if (currentScene.IsEndEnter() == true)
{

}
}

/// <summary>
/// 描画
/// </summary>
/// <param name="renderer"></param>
public void Draw(Renderer renderer)
{
if (currentScene == null) return;

if (currentScene == scenes[Scene.GameOver] ||
currentScene == scenes[Scene.GameClear])
{
scenes[Scene.GamePlay].Draw(renderer);
}

currentScene.Draw(renderer);
}
}

Re: タイトル画面からの遷移

Posted: 2012年11月13日(火) 12:25
by softya(ソフト屋)
読みづらいのでcodeタグを使ってください。あと名前も戻してください。
http://dixq.net/board/board.html まず、これを全部目を通してください。

>SceneManagerクラスには終了処理はありません
SceneManagerクラスに終了状態を管理させてはいけない理由にはなっていませんが何故ダメなのですか?
Game1クラスからSceneManagerクラスの状態は参照できないのでしょうか?

【補足】
しばらく返事ができなので、今までの話をじっくり考えみて下さい。
あとフォーラムルールをご熟読下さい。

Re: タイトル画面からの遷移

Posted: 2012年11月13日(火) 15:14
by XNABeginner
SceneManagerクラスにbool型のIsEndEnterメソッドを作成し、
そこで今入っているシーンのIsEndEnterメソッドを返すようにし、
タイトルクラスのbool型のIsEndEnterメソッドでisEndEnterを返すようにし、
終わるボタンが押されたときにisEndEnterをtrueにしています。

また、Gameクラスの更新処理で

コード:

if (sceneManager.IsEndEnter() == true) this.Exit();
を書きました。

ですが、終わらないです。

Re: タイトル画面からの遷移

Posted: 2012年11月13日(火) 17:28
by softya(ソフト屋)
XNABeginner さんが書きました:SceneManagerクラスにbool型のIsEndEnterメソッドを作成し、
そこで今入っているシーンのIsEndEnterメソッドを返すようにし、
タイトルクラスのbool型のIsEndEnterメソッドでisEndEnterを返すようにし、
終わるボタンが押されたときにisEndEnterをtrueにしています。

また、Gameクラスの更新処理で

コード:

if (sceneManager.IsEndEnter() == true) this.Exit();
を書きました。

ですが、終わらないです。
ソースコードが全部ないのでOK/NGの判別はできないです。
その動作はデバッガでちゃんと確認されましたか? まず、そこからです。

Re: タイトル画面からの遷移

Posted: 2012年11月13日(火) 17:42
by XNABeginner

コード:

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace TG
{
    /// <summary>
    /// ゲームのコア
    /// </summary>
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        private Renderer renderer;
        private InputState input;
        private SceneManager sceneManager;
        private Sound sound;

        /// <summary>
        /// コンストラクタ
        /// </summary>
        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            graphics.PreferredBackBufferWidth = Screen.Width;
            graphics.PreferredBackBufferHeight = Screen.Height;

            //this.graphics.IsFullScreen = true;
        }

        /// <summary>
        /// 初期化
        /// </summary>
        protected override void Initialize()
        {
            base.Window.Title = "赤頭巾ちゃん御用心";
            
            renderer = new Renderer(Content, GraphicsDevice);
            input = new InputState();
            sceneManager = new SceneManager();
            sound = new Sound(Content);

            sceneManager.Add(Scene.Title, new Title(input, sound));
            sceneManager.Add(Scene.GamePlay, new GamePlay(input, sound));
            sceneManager.Add(Scene.GameOver, new GameOver(input, sound));
            sceneManager.Add(Scene.GameClear, new GameClear(input, sound));

            sceneManager.Change(Scene.Title);

            base.Initialize();
        }

        /// <summary>
        /// 読込
        /// </summary>
        protected override void LoadContent()
        {
            renderer.LoadTexture("title");
            renderer.LoadTexture("starttext");
            renderer.LoadTexture("endtext");
            renderer.LoadTexture("cleartext");
            renderer.LoadTexture("overtext");
            renderer.LoadTexture("stage");
            renderer.LoadTexture("chip");
            renderer.LoadTexture("playerR");
            renderer.LoadTexture("playerL");
            renderer.LoadTexture("enemyR");
            renderer.LoadTexture("enemyL");
            renderer.LoadTexture("score");
            renderer.LoadTexture("number");
            renderer.LoadTexture("itemR");
            renderer.LoadTexture("itemB");
            renderer.LoadTexture("hp");
            renderer.LoadTexture("hpW");
            renderer.LoadTexture("life");

            sound.LoadSound("title", true);
            sound.LoadSound("play", true);
            sound.LoadSound("ending", true);
            sound.LoadSound("get", false);
            sound.LoadSound("damage", false);
        }

        /// <summary>
        /// 破棄
        /// </summary>
        protected override void UnloadContent()
        {
            renderer.Unload();
            sound.Unload();
        }

        /// <summary>
        /// 更新
        /// </summary>
        /// <param name="gameTime"></param>
        protected override void Update(GameTime gameTime)
        {
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed ||
                Keyboard.GetState().IsKeyDown(Keys.Escape) ||
                sceneManager.IsEndEnter() == true)
                this.Exit();

            input.Update();
            sceneManager.Update();

            base.Update(gameTime);
        }

        /// <summary>
        /// 描画
        /// </summary>
        /// <param name="gameTime"></param>
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            renderer.Begin();
            sceneManager.Draw(renderer);
            renderer.End();

            base.Draw(gameTime);
        }
    }
}

コード:

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;

namespace TG
{
    /// <summary>
    /// タイトル
    /// </summary>
    class Title : IScene
    {
        private InputState input;
        private Sound sound;
        private bool isEnd;
        private int timer;
        private int activeCursor;
        private bool isEndEnter;

        /// <summary>
        /// コンストラクタ
        /// </summary>
        /// <param name="input"></param>
        /// <param name="sound"></param>
        public Title(InputState input, Sound sound)
        {
            this.input = input;
            this.sound = sound;
        }

        /// <summary>
        /// 初期化
        /// </summary>
        public void Initialize()
        {
            isEnd = false;
            timer = 0;
            activeCursor = 1;
            isEndEnter = false;
        }

        /// <summary>
        /// 更新
        /// </summary>
        public void Update()
        {
            sound.Play("title");

            if (input.IsStartButtonDown)
            {
                isEnd = true;
            }

            timer++;

            if (input.IsDownButtonDown) activeCursor = 0;
            if (input.IsUpButtonDown) activeCursor = 1;

            if (activeCursor == 1 && input.IsStartButtonDown)
            {
                isEndEnter = true;
            }
        }

        /// <summary>
        /// 描画
        /// </summary>
        /// <param name="renderer"></param>
        public void Draw(Renderer renderer)
        {
            renderer.DrawTexture("title", new Vector2(0, 0));

            if (activeCursor == 0)
            {
                renderer.DrawTexture("starttext", new Vector2(50, 330), new Vector2(1, 1), 150);
            }
            else
            {
                renderer.DrawTexture("starttext", new Vector2(50, 330));
            }

            if (activeCursor == 1)
            {
                renderer.DrawTexture("endtext", new Vector2(50, 400), new Vector2(1, 1), 150);
            }
            else
            {
                renderer.DrawTexture("endtext", new Vector2(50, 400));
            }
        }

        /// <summary>
        /// Enterキーの押下判定
        /// </summary>
        /// <returns></returns>
        public bool IsEndEnter()
        {
            return isEndEnter;
        }

        /// <summary>
        /// 終了判定
        /// </summary>
        /// <returns></returns>
        public bool IsEnd()
        {
            return isEnd;
        }

        /// <summary>
        /// シーン移行
        /// </summary>
        /// <returns></returns>
        public Scene Next()
        {
            return Scene.GamePlay;
        }

        /// <summary>
        /// 休止
        /// </summary>
        public void Shutdown()
        {
            sound.Stop("title");
        }
    }
}

コード:

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;

namespace TG
{
    /// <summary>
    /// シーン管理
    /// </summary>
    class SceneManager
    {
        private IScene currentScene = null;
        private Dictionary<Scene, IScene> scenes = new Dictionary<Scene, IScene>();

        /// <summary>
        /// コンストラクタ
        /// </summary>
        public SceneManager()
        {

        }

        /// <summary>
        /// 登録
        /// </summary>
        /// <param name="name"></param>
        /// <param name="scene"></param>
        public void Add(Scene name, IScene scene)
        {
            scenes[name] = scene;
        }

        /// <summary>
        /// 変更
        /// </summary>
        public void Change(Scene name)
        {
            if (currentScene != null)
            {
                currentScene.Shutdown();
            }

            currentScene = scenes[name];

            currentScene.Initialize();
        }

        /// <summary>
        /// 更新
        /// </summary>
        public void Update()
        {
            if (currentScene == null) return;

            currentScene.Update();

            if (currentScene.IsEnd() == true)
            {
                Change(currentScene.Next());
            }
        }

        /// <summary>
        /// 描画
        /// </summary>
        /// <param name="renderer"></param>
        public void Draw(Renderer renderer)
        {
            if (currentScene == null) return;

            if (currentScene == scenes[Scene.GameOver] ||
                currentScene == scenes[Scene.GameClear])
            {
                scenes[Scene.GamePlay].Draw(renderer);
            }

            currentScene.Draw(renderer);
        }

        /// <summary>
        /// Enter押下判定
        /// </summary>
        /// <returns></returns>
        public bool IsEndEnter()
        {
            return currentScene.IsEndEnter();
        }
    }
}

コード:

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;

namespace TG
{
    /// <summary>
    /// シーン操作
    /// </summary>
    interface IScene
    {
        /// <summary>
        /// 初期化
        /// </summary>
        void Initialize();

        /// <summary>
        /// 更新
        /// </summary>
        void Update();

        /// <summary>
        /// 描画
        /// </summary>
        /// <param name="renderer"></param>
        void Draw(Renderer renderer);

        /// <summary>
        /// Enterキー押下判定
        /// </summary>
        /// <returns></returns>
        bool IsEndEnter();

        /// <summary>
        /// 終了判定
        /// </summary>
        /// <returns></returns>
        bool IsEnd();

        /// <summary>
        /// シーン移行
        /// </summary>
        /// <returns></returns>
        Scene Next();

        /// <summary>
        /// 休止
        /// </summary>
        void Shutdown();
    }
}

Re: タイトル画面からの遷移

Posted: 2012年11月13日(火) 17:53
by softya(ソフト屋)
デバッガでトレースされましたか?
そちらの結果を先に聞きたいです。

【補足】
ソースコードは合っているように見えますが全部の動きは把握していなのでデバッガで調べるのが一番です。
まずタイトルクラスでちゃんとisEndEnter が trueになることと、そのtrueがsceneManager.IsEndEnter()でGame1まで戻っているのかを確認して下さい。

Re: タイトル画面からの遷移

Posted: 2012年11月13日(火) 18:33
by XNABeginner
ずっとfalseのままです

Re: タイトル画面からの遷移

Posted: 2012年11月13日(火) 18:35
by softya(ソフト屋)
if (activeCursor == 1 && input.IsStartButtonDown)が条件ですが、どちらが条件を満たしていないのですか?

Re: タイトル画面からの遷移

Posted: 2012年11月13日(火) 18:37
by Idra
ソースを見ただけなので違ってるかもしれませんが、
SceneManagerの更新処理ではシーンが終了するとすぐに次のシーンに移動するので、
SceneManager.IsEndEnter()で見ているのは次のシーンになってしまいますよね?

Re: タイトル画面からの遷移

Posted: 2012年11月13日(火) 18:40
by softya(ソフト屋)
たしかに

コード:

            if (input.IsStartButtonDown)
            {
                isEnd = true;
            }
でシーン遷移の条件を満たしてますね。
とすれば、isEndEnter時は isEnd を抑制すれば良いことになります。