0
\$\begingroup\$

I am currently trying to implement simple lighting into my game. My world is represented in a 2d array of numbers, each number being a certain tile. I am changing the color parameter in the spritebatch.Draw method to dim the tiles, and that is working quite well for me(I don't know how to use shaders).Each tile can have a light level from 0 to 5, and depending on its level it will be brighter/darker. The problem I have is that I used this code to simulate lighting:

public void Update()
    {
        foreach (NonCollisionTiles tile in nonCollisionTiles)
        {
            foreach (NonCollisionTiles otherTile in nonCollisionTiles)
            {
                if (otherTile.Rectangle.X  == tile.Rectangle.X && (otherTile.Rectangle.Y / size == tile.Rectangle.Y - 1 || otherTile.Rectangle.Y / size == tile.Rectangle.Y + 1))
                {
                    if (tile.Light < otherTile.Light)
                    {
                        tile.Light = otherTile.Light - 1;
                    }
                }
                else if (otherTile.Rectangle.X / size == tile.Rectangle.Y && (otherTile.Rectangle.X / size == tile.Rectangle.X - 1 || otherTile.Rectangle.Y / size == tile.Rectangle.X + 1))
                {
                    if (tile.Light < otherTile.Light)
                    {
                        tile.Light = otherTile.Light - 1;
                    }
                }
            }
        }
    }

But I'm not sure if it works or not and it lowers my FPS to 1. I have no idea as to how I can implement my lighting system. Essentially, I want it to look like a torch in Minecraft, but in 2d. Here is the code for my tiles:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;

namespace Tile_Map
{
class Tiles
{
    protected Texture2D texture;
    protected int light = 1;
    public int Light
    {
        get { return light; }
        set
        {
            light = value;
        }
    }
    protected Color color;
    private Rectangle rectangle;
    public Rectangle Rectangle
    {
        get { return rectangle; }
        protected set { rectangle = value; }
    }
    private static ContentManager content;
    public static ContentManager Content
    {
        protected get { return content; }
        set { content = value; }
    }

    public void Update()
    {
        color = new Color(light*51,light*51,light*51);
    }
    public void Draw(SpriteBatch spriteBatch)
    {
        spriteBatch.Draw(texture, rectangle, null, color, 0, Vector2.Zero,SpriteEffects.None,0f);
    }
 }

class CollisionTiles : Tiles 
{
    public CollisionTiles(int i, Rectangle newRectangle)
    {
        texture = Content.Load<Texture2D>(@"Images\Tile" + i);
        this.Rectangle = newRectangle;
    }
}
class NonCollisionTiles : Tiles
{
    public NonCollisionTiles(int i, Rectangle newRectangle)
    {
        texture = Content.Load<Texture2D>(@"Images\Tile" + i);
        this.Rectangle = newRectangle;
    }
}
}

This is what I am trying to do: This is more or less what I am trying to do

Any help is appreciated!

\$\endgroup\$
1
\$\begingroup\$

The code is currently looping over all the tiles twice. On a 10x10 map, it calls the code inside the loops 10,000 times. That's already a very large number, and that's just on a small map. Most of these calls will be useless, as it is also checking tiles that are far away from each other.

Store things appropriately

Your tiles will always be next to the same neighbours, so why not store them that way? By using a multidimensional array, you can use tile locations on the array to your advantage.

A tile located at nonCollisionTiles[5,5], will always have the same neigbours. So if a light is placed there, it is easy to see that nonCollisionTiles[5,4] needs to be updated.

With this information you can write a recursive function like this:

private void updateLights(int X, int Y, int lightLevel)
{
    neighbourUpdate(X, Y - 1, lightLevel - 1);
    neighbourUpdate(X, Y + 1, lightLevel - 1);
    neighbourUpdate(X - 1, Y, lightLevel - 1);
    neighbourUpdate(X + 1, Y, lightLevel - 1); 
}
private void neighbourUpdate(int A, int B, int lightLevel)
{
    if (lightLevel > nonCollisionTiles[A, B].light)
    {
        nonCollisionTiles[A, B].light = lightLevel;
        updateLights(A, B, lightLevel);
    }
}

This function takes as input the X- and Y-location on the array and the light level. It then updates the neighbours (if their lightLevel is lower) and calls another UpdateLights for the location and lightLevel of the updated neighbour.

This is much faster then the double loop, all by using the storing method to our advantage.

\$\endgroup\$
0
\$\begingroup\$

Are you making sure you are only checking the visible tiles, and not the tiles for the entire map? This can greatly benefit your FPS. It looks to me as if your two foreach loops are checking every tile on the map up against every other tile. That will be VERY expensive in CPU cycles.

If your lights are in fixed positions, then I suggest you create a light-map: a doublearray of int to store the lighting. Then you can perform a check once, before the game begins to set the light-values from 0 to 5 of every tile.

When you draw the textures, you can lookup into the light-map to find how bright the texture should be.

If you have moving lights as well, then you could create another light-map which you update every time one of the moving lights actually move to another tile.

Then your draw routine would be:

foreach visible tile from the map
  get the texture
  find the corresponding tile in the the stationary light-map 
    and the moving lights light-map
  use the highest lighting value from these to draw the texture
\$\endgroup\$
  • \$\begingroup\$ Thought it would be an interesting coding excercise, so here's a little codesample link \$\endgroup\$ – Xnafan Jan 11 '14 at 10:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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