0

我目前正在做一个学校项目,我需要开发一个等距游戏。不幸的是,由于我的老师对游戏开发一无所知(已经专注于切换到新学校),我被困住了。

现在我可以轻松绘制游戏地图,但它停止了。当我添加角色时,我看到它正在渲染,但我无法移动它。很可能我搞砸了 IsoToScreen 和 ScreenToIso 数学问题。

当我尝试将我的角色移动 1 像素时,由于某种原因,它会立即离开屏幕。

这是我用来将简单 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 位置(浮点数),但是当我将 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 做出反应时,它设置为零,并添加一个到 mapY,这意味着下一个图块将移动到下一个等距 y 坐标。

所以 x 和 y 都是同时设置的,它真的很像旋转整个地图,但它使用等距坐标,而不是仅使用 2d 瓷砖。

现在唯一的问题是,它似乎缩短了几个瓦片,但可以通过在数组中添加更多的字符串值来修复它。

如何使用它:

先声明

Texture2D[] tex = new Texture2D[2];

然后声明

MapEngine.Map地图;

2 是您拥有的不同瓷砖的数量。

第二个将 tex 设置为

tex[0] = Content.Load(@"草"); tex[1] = Content.Load(@"dirt");

然后将地图设置为(但永远不要将其放入 loadcontent 函数中)将其放入更新或绘制函数中。(它将远离视图)

地图 = 新 MapEngine.Map(tex);

0 是地图 ID,草是图像的名称。

现在要在游戏中绘制地图,使用

map.draw(spriteBatch);

于 2013-01-17T00:53:00.027 回答
0

你是如何尝试移动你的角色的?

如果它是每帧 1.0f(即在 Update 或 Draw 方法中完成),这是一个很大的移动,特别是如果您在具有非固定帧速率的 PC 上。

于 2011-04-03T10:35:39.053 回答