开发者

C# XNA Isometric Tile Engine issues

I am currently working on a school project in which I need to develop an Isometric game. Unfortunately since my teachers don't know anything at all about game-development (already focusing on switching to a new school) I'm stuck.

Right now I can draw the game map with ease but there it stops. When I add the character I see it being rendered but I can't move it. Most likely I've messed up the IsoToScreen and ScreenToIso mathematical problems.

When I try to move my character just 1px it's immediately off screen for some reason.

Here is my IsoMath class which I use to convert simple 2D to 2.5D Isometric

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;
    }
}

}

My Player class is just an place holder with a Draw(SpriteBatch sp, vector2 playerPostition); method which as the name implies draws the character at the given location (this location is precalculated in the main Draw method)

This is how I draw my character to the screen. It works on an fixated x14,y14 position (Floats) but when I add just 1f to any of these two values the character is nowhere to be found.

Vector2 plPos = i开发者_如何学GosoMath.ScreenToIsoPoint(pl.X, pl.Y);
plPos.X += x;
plPos.Y += y;
pl.Draw(spriteBatch, plPos);

And I use the following code (before the character gets drawn) to render my map. The massive if statement is for culling off screen tiles.

        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);
                }
            }
        }

You can click here (1.13Mb) to download a zip archive of the entire project if you think I didn't supply enough information.


this is the code i have, and it works for any map size. it's based the the normal 2d tile display.

 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();
    }

so what is going on here?

so in the spriteBatch.draw function, there is a calculation that i finally workout, i'm not sure how exactly it does it, but i just used trial and error, to find the calculations.

so everytime it reads a mapData string, from the list, it adds to the mapX, which means the next tile will move to the isometric based x-coord, and when mapX reacts the maxX for the map, it sets to zero, and adds one to the mapY, which then means the next tile will move to the next isometric y-coord.

so both the x and y, are being set at the same time, and its really like rotating the entire map, but it uses isometric coords, instead of just using 2d tiles.

now the only problem with this, is, that it seems to short a few tiles, but it can be fixed just by adding a few more string values into the array.

how to use it:

first declare

Texture2D[] tex = new Texture2D[2];

then declare

MapEngine.Map map;

with 2 being the number of different tiles you have.

second set the tex to

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

then set map to(but NEVER put this in the loadcontent function) put it either in the update or draw function.(it will move away from view)

map = new MapEngine.Map(tex);

with 0 being the map id, and grass being the name of your image.

now to draw the map in the game, use

map.draw(spriteBatch);


How have you tried moving your character?

If it's 1.0f per frame (ie done in an Update or Draw method), this is a lot of movement, especially if you're on a PC with non-fixed frame rate.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜