0

私は現在、等尺性ゲームを開発する必要がある学校のプロジェクトに取り組んでいます。残念ながら、私の先生はゲーム開発について何も知らないので (すでに新しい学校への切り替えに集中しています)、行き詰まっています。

今は簡単にゲーム マップを描くことができますが、そこで止まってしまいます。キャラクターを追加すると、レンダリングされているのがわかりますが、動かすことができません。おそらく、IsoToScreen と ScreenToIso の数学的問題を台無しにしてしまったのでしょう。

キャラクターを 1px だけ動かそうとすると、何らかの理由ですぐに画面から外れてしまいます。

これは、単純な 2D を 2.5D Isometric に変換するために使用する IsoMath クラスです。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
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 Beowulf
{
class IsoMath
{
    private double tw, th, tx, ty, sx, sy;

    public IsoMath(double width, double height)
    {
        tw = width;
        th = height;
    }

    public Vector2 ScreenToIsoTile(Vector2 start, Vector2 offset, Vector2 screenOriginPoint)
    {
        Vector2 ret = new Vector2(0, 0);

        sx = start.X - (screenOriginPoint.X + offset.X);
        sy = start.Y - (screenOriginPoint.Y + offset.Y);

        tx = System.Math.Round((sx / (tw * 2)) + (sy / (th * 2))) - 1;
        ty = System.Math.Round((-sx / (tw * 2)) + (sy / (th * 2)));

        ret.X = (float)tx;
        ret.Y = (float)ty;

        return ret;
    }
    public Vector2 ScreenToIsoPoint(float x, float y)
    {
        Vector2 ret = new Vector2(0, 0);

        tx = (x - y) * tw;
        ty = (x + y) * th;

        ret.X = (float)tx * .5f;
        ret.Y = (float)ty * .5f;

        return ret;
    }
    public Vector2 IsoToScreenPoint(float x, float y)
    {
        Vector2 ret = new Vector2(0, 0);

        tx = (x + y) / tw;
        ty = (x - y) / th;

        ret.X = (float)tx / .5f;
        ret.Y = (float)ty * -1;

        return ret;
    }
    public Vector2 ScreenToIso(float x, float y)
    {
        Vector2 ret = new Vector2(0, 0);

        tx = (x - y);
        ty = (x + y);

        ret.X = (float)tx;
        ret.Y = (float)ty;

        return ret;
    }
    public Vector2 IsoToScreen(float x, float y)
    {
        Vector2 ret = new Vector2(0, 0);

        tx = (x + y);
        ty = (x - y);

        ret.X = (float)tx * .5f;
        ret.Y = -(float)ty / 2;

        return ret;
    }
}

}

私の Player クラスは、 Draw(SpriteBatch sp, vector2 playerPostition); を持つ単なるプレースホルダーです。名前が示すように、指定された位置に文字を描画するメソッド (この位置は、メインの Draw メソッドで事前に計算されます)

これが私のキャラクターを画面に描く方法です。固定された x14,y14 位置 (浮動小数点数) で動作しますが、これら 2 つの値のいずれかに 1f を追加すると、文字がどこにも見つかりません。

Vector2 plPos = isoMath.ScreenToIsoPoint(pl.X, pl.Y);
plPos.X += x;
plPos.Y += y;
pl.Draw(spriteBatch, plPos);

そして、(キャラクターが描画される前に) 次のコードを使用してマップをレンダリングします。大規模な if ステートメントは、画面のタイルをカリングするためのものです。

        for (int i = 0; i < scene.width; i++)
        {
            for (int j = 0; j < scene.height; j++)
            {
                Vector2 p = isoMath.ScreenToIsoPoint(i, j);

                Rectangle r = new Rectangle(0, 0, graphics.PreferredBackBufferWidth, graphics.PreferredBackBufferHeight);
                if (r.Contains(new Point((int)(((p.X) + x)), (int)((p.Y) + y))) || r.Contains(new Point((int)((p.X) + x) + tile.Width, (int)((p.Y) + y + tile.Height))) || r.Contains(new Point((int)((p.X) + x) + tile.Width, (int)((p.Y) + y))) || r.Contains(new Point((int)((p.X) + x), (int)((p.Y) + y + tile.Height))))
                {
                    spriteBatch.Draw(tile, new Rectangle((int)((p.X) + x), (int)((p.Y)  + y), (int)(tile.Width * 1.02), (int)(tile.Height * 1.02)), Color.White);
                }
            }
        }

十分な情報が提供されていないと思われる場合は、ここ (1.13Mb) をクリックして、プロジェクト全体の zip アーカイブをダウンロードできます。

4

2 に答える 2

1

これは私が持っているコードで、どのマップ サイズでも機能します。通常の 2D タイル表示に基づいています。

 Texture2D[] texture;
    Rectangle rec;
    int[] mapData = {
                    0,0,1,1,
                    0,0,0,0,
                    0,0,0,0};
    int mapWidth = 4;
    int mapY = 0;
    int mapX = 0;

    public Map(Texture2D[] tex)
    {
        texture = tex;
        rec = new Rectangle(200, 10, tex[0].Width, tex[0].Height);
    }

    public void draw(SpriteBatch spriteBatch)
    {
        spriteBatch.Begin();
            for (int i = 1; i < mapData.Length; i++)
            {
                if (mapX >= mapWidth)
                {
                    mapY++;
                    mapX = 0;
                }
                else
                {
                    mapX++;
                        spriteBatch.Draw(texture[mapData[i]], new Rectangle((200 - ((rec.Width / 2) * (mapX))) + (rec.X + ((rec.Width / 2) * (mapY))), (rec.Y + (16 * (mapX))) + (16) * mapY, rec.Width, rec.Height), Color.White);

                }
        }
        spriteBatch.End();
    }

ここで何が起こっているのですか?

そのため、spriteBatch.draw 関数には、最終的にワークアウトする計算があります。正確にどのように実行するかはわかりませんが、試行錯誤を使用して計算を見つけました。

そのため、リストから mapData 文字列を読み取るたびに、mapX に追加されます。これは、次のタイルが等角投影ベースの x 座標に移動することを意味し、mapX がマップの maxX に反応するとゼロに設定され、追加されます。これは、次のタイルが次のアイソメトリック y 座標に移動することを意味します。

したがって、x と y の両方が同時に設定され、マップ全体を回転させるのと同じように、2D タイルを使用する代わりに等角座標を使用します。

現在、これに関する唯一の問題は、いくつかのタイルがショートしているように見えることですが、配列にさらにいくつかの文字列値を追加するだけで修正できます。

それの使い方:

最初に宣言する

Texture2D[] tex = new Texture2D[2];

次に宣言する

MapEngine.Map マップ;

2 はあなたが持っている異なるタイルの数です。

次にtexをに設定します

tex[0] = Content.Load(@"草"); tex[1] = Content.Load(@"ダート");

次に、マップをに設定します(ただし、loadcontent 関数には決して入れないでください)。 update または draw 関数に入れます(ビューから離れます)。

map = new MapEngine.Map(tex);

0 はマップ ID、grass は画像の名前です。

ゲームでマップを描画するには、次を使用します

map.draw(spriteBatch);

于 2013-01-17T00:53:00.027 に答える
0

どのようにキャラクターを動かしてみましたか?

フレームごとに 1.0f の場合 (つまり、Update または Draw メソッドで実行された場合)、これは多くの動きであり、フレーム レートが固定されていない PC を使用している場合は特にそうです。

于 2011-04-03T10:35:39.053 に答える