Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

Below is how far I've got. I just made a simple block with user primitives to test it. But I haven't found a way to crop the spritesheet.

textureLava = frames[activeFrame];

This line is how I want it but off course this doesn't work. Is there a way to crop this spritesheet or is there another way to animate the texture of a model?

public void CreateFrames()
{
    for (int i = 0; i < 64; i++)
    {
        frames.Add(new Rectangle(WIDTH + i, i, WIDTH, HEIGHT));
    }
}

public override void Update(GameTime gameTime)
{
    if (System.Environment.TickCount - lastFrameTime > TIME_BETWEEN_FRAMES)
    {
        activeFrame++;
        lastFrameTime = System.Environment.TickCount;

        if (activeFrame > 15)
        {
            activeFrame = 0;
        }
    }

    textureLava = frames[activeFrame]; --> DOESN'T WORK

    base.Update(gameTime);
}

public override void Draw(GameTime gameTime)
{
    effect.TextureEnabled = true;
    effect.World = Matrix.Identity;
    effect.View = Camera.ActiveCamera.View;
    effect.Projection = Camera.ActiveCamera.Projection;

    effect.Texture = textureLava;

    foreach (EffectPass pass in effect.CurrentTechnique.Passes)
    {
        pass.Apply();

        GraphicsDevice.SetVertexBuffer(vertexBuffer);

        GraphicsDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, 10);
    }
}
share|improve this question
2  
Yep definitely possible, your problem seems to be a simple XNA syntax one, I can't help you with that, but you should consider editing your question to reflect that it is a more basic problem. Also, "doesn't work" is not an adequate description. Is it a compilation error or a runtime error? What is the error message? If it does run but doesn't do as you would like describe in detail both what happens and what you desire. –  eBusiness Jan 7 '12 at 13:42

1 Answer 1

up vote 2 down vote accepted

The problem is probably that textureLava is of type Texture2D while frames is an array of Rectangle objects. Obviously, you can't assign a Rectangle to a Texture2D. This is due to the fact that you're using a spritesheet for your lava animation directly. Three ways I cant think of to solve this:

Solution 1 - Put each frame in a separate file

The most simple solution for this problem would be to move each frame of the animation into a separate file and load each of them into a separate texture object (e.g. into an array of Texture2D objects).

Solution 2 - Copy regions of the spritesheet into separate Textures

If really want to use the spritesheet, another solution is to use the Texture2D.GetData and Texture2D.SetData methods to create the individual texture objects using a subset of the data contained in the original spritesheet texture. In other words, copy rectangles of data from the spritesheet into separate textures.

Something like this (which I have wrote from memory so it's untested but should be close enough):

Texture2D spritesheet = Content.Load("lavaSpritehseet");
List<Texture2D> frames = new List<Texture2D>();
List<Rectangle> rectangles = new List<Rectangle>(); // Load your rectangles here

foreach(Rectangle rectangle in rectangles)
{
    // Get data from spritesheet using the frame rectangle as a source
    Color[] data = new Color[rectangle.Width * rectangle.Height];
    spritesheet.GetData(0, rectangle, data, 0, rectangle.Width * rectangle.Height);

    // Create a new texture and assign the data to it
    Texture2D texture = new Texture2D(GraphicsDevice, rectangle.Width, rectangle.Height);
    texture.SetData(data);

    // Store frame
    frames.Add(texture);
}

// Now you can do lavaTexture = frames[activeFrame]
// Because they're both of the same type

Solution 3 - Modify the vertices' texture coordinates

There's also another alternative which would basically be modifying the texture coordinates of your vertices to match the cropped region. This could either be done on the GPU with a custom vertex shader that would receive the source rectangle and texture size as inputs and perform the cropping internally, or on the CPU by changing them directly on your vertex buffer.

This is not too complicated, but since the solutions above are probably enough for you, I'll leave it just at a general description:

  • Your vertices have a Vector2 holding the texture coordinates. A value of (0, 0) represents the top-left corner of the texture and a value of (1, 1) represents the bottom right corner of the texture.
  • If you want to only draw a portion of the texture, you'd change those texture coordinates to something else.
  • For instance, if the spritesheet had size (w, h) and you wanted to texture using only the rectangle (x, y, rw, rh), then instead of using a texture coordinate of (0, 0) for the top-left corner you'd use (x/w, y/h) and instead of (1, 1) for the bottom-right corner you'd use ((x+rw)/w, (y+rh)/h)).

PS: Your way of updating the animation rate is also very bad. Don't use System.Environment.TickCount. Make use of the gameTime parameter of the Update method which carries information about how much time passed since the previous frame. I do it similar to this:

int totalFrames = 5;
int currentFrame = 0;
int framerate = 12;     // Animate at 12 frames per second
float timer = 0.0f;

public void Update(GameTime gameTime)
{
    timer += (float)gameTime.ElapsedGameTime.TotalSeconds;
    if (timer >= (1.0f / framerate ))
    {
        timer -= 1.0f / framerate ;
        currentFrame = (currentFrame + 1) % totalFrames;
    }
}
share|improve this answer
    
Thank you, the third solution seems the best and I'm obligated to use System.Environment.TickCount by my teacher. On projects of my own i use gameTime. –  Steve Van Opstal Jan 7 '12 at 15:44
    
Alright then :) –  David Gouveia Jan 7 '12 at 15:56

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.