Sign in to follow this  
thecoast47

2D Lighting

Recommended Posts

the language that i used is Java.

Here is footage of what my game looks like so far:
http://www.youtube.com/watch?v=dp31D5m5qRA

As you can see in the footage there are some collision issues.I've recently fixed them but now I'm facing a problem that i cannot solve by myself. I want to know how to go about giving my game dynamic 2D lighting. I think they call it "ray casting" or something of that nature. I've seen 3D demonstrations of raycasting and i didnt really understand the source code but from what i've seen I think it is also possible to implement this into a 2d game aswell.

Any suggestions?

Update:
Here is updated footage of what my game looks like so far:
http://www.youtube.com/watch?v=HoDEMwDrCz8
Ok well I read an article on here that really helped me out with this but now my game runs SLOW.
This is what my Light class looks like(dont look at it if you dont want to its pretty messy):
import java.awt.Color;
import java.awt.GradientPaint;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.util.ArrayList;

public class Light extends Sprite{
public static GradientPaint Shade;
public static Color RayColor;
public static int red = 255;
public static int green = 255;
public static int blue = 255;
public static int Opacity = 255;

public static double Degree;
public static double CurrentX2;
public static double CurrentY2;

public static double SlopeX;
public static double SlopeY;
public static boolean ChangeAngle = false;



public Graphics2D RenderLight (Graphics2D g , double PlayerX ,double PlayerY ,ArrayList <FloorTile> TileList ,int MaxTiles){
double PIE = 3.14;
double RADIUS = 1000;
//Degree = Degree + 1;
for (Degree = 0 ; Degree < 360 ; Degree+=2){
double CurrentX1 = PlayerX;
double CurrentY1 = PlayerY;
double Rad1 = (PIE / 180) * Degree;
CurrentX2 = (Math.sin(Rad1) * (RADIUS)*2) + CurrentX1;
CurrentY2 = (Math.cos(Rad1) * (RADIUS)*2) + CurrentY1;
SlopeX = (CurrentX2 - CurrentX1) /500;
SlopeY = (CurrentY2 - CurrentY1) /500;

//Opacity = 255;

while(true){
red = 255;
green = 255;
blue = 255;
double distance ;
distance= Math.sqrt(Math.pow(CurrentX2-this.getX(), 2) + Math.pow(CurrentY2-this.getY(), 2));
//min 1962
if(distance > 1962 ){
if (Opacity >= 255){

}else{
Opacity +=5;
RefreshPixel(red,green,blue,Opacity);
}
}
if (CurrentX1 > launchApp.FrameWidth){
Opacity = 0;
break;
}
if(CurrentX1 < 0){
Opacity = 0;
break;
}
if (CurrentY1 > launchApp.FrameHeight){
Opacity = 0;
break;
}
if (CurrentY1 < 0){
Opacity = 0;
break;
}


CurrentX1 += SlopeX;
CurrentY1 += SlopeY;


this.setX(CurrentX1);
this.setY(CurrentY1);

for(int J= 0; J <MaxTiles;J++){
if(TileList.get(J).getWidth() <=0){

}else{
double PixelX = this.getX();
double PixelY = this.getY();
double NextBottomLeftX = TileList.get(J).getBottomLeftX();
double NextBottomLeftY = TileList.get(J).getBottomLeftY();
double NextBottomRightX = TileList.get(J).getBottomRightX();
double NextTopLeftY = TileList.get(J).getTopLeftY();
if (PixelX > NextBottomLeftX && PixelX < NextBottomRightX&&PixelY > NextBottomLeftY&&PixelY > NextTopLeftY){
ChangeAngle = true;
RefreshPixel(red,green,blue,Opacity);
Opacity = 0;
break;
}
}
}

if (ChangeAngle){
ChangeAngle = false;
break;
}

g.setPaint(RayColor);
g.fillRect((int)this.getX() + 10,(int) this.getY() + 10,(int) this.getWidth(), (int)this.getHeight());
}
}
return g;
}
public void RefreshPixel( int red, int green,int blue, int opacity){
RayColor = new Color(red,green,blue,opacity);
}
}






The idea of my method is that you calculate the slope of X2 and Y2 divide the slope by an Xamount and then add the slope to the pixel's position. If you constantly draw the pixel's movement it creates a line. I did this because doing it this way would make it easier to check collision between tiles.

The FPS of the game jumps to 25FPS if I don't modify the Opacity variable of the Color object,However, i need to modify Opacity in order to create the effect of shading. Is there an alternative to Opacity?

[Edited by - thecoast47 on December 12, 2010 8:58:17 PM]

Share this post


Link to post
Share on other sites
Besides the collision inaccuracies, I'd be worried about the performance. 8fps in a 2d game is painfully low, and I don't see much room in there ATM to add lighting calculations.

Share this post


Link to post
Share on other sites
Quote:
Original post by Chris_F
Besides the collision inaccuracies, I'd be worried about the performance. 8fps in a 2d game is painfully low, and I don't see much room in there ATM to add lighting calculations.


Normally without recording software running in the background the fps would be around 30-45 fps. Which begs the question...What would be the desired FPS for a 2D game be? I've tried doing optimizations to this.One optimization that really gave a boost in performance was that it only checks collision for the tiles that are rendered.I also set it up so that only the tiles within the frame are rendered.

Share this post


Link to post
Share on other sites
Quote:
how to go about giving my game dynamic 2D lighting

Perhaps if you could better describe what results you want, it would help. It's not clear what type of effect you're trying to achieve.

For a Mario Bros. type scroller "spotlight," that would be relatively simple in a pixel shader. Are you using shaders?

With regard to FPS, a general rule of thumb is that ~27 FPS is the lower limit for a good monitor and most users. Conveniently, 30 FPS matches refresh rates nicely if you want to use vsync and avoid tearing.

Share this post


Link to post
Share on other sites
Quote:
Perhaps if you could better describe what results you want, it would help. It's not clear what type of effect you're trying to achieve.


This is what I'm trying to achieve:
http://www.youtube.com/watch?v=Tj5NV0sVtQE

But less advanced.
Just to make sure im on the same page, when you refer to a "Shader", in java that would be called a gradient right? Because ive done things with gradients but i don't know anything about shaders.Is there a difference?

An even better example:
http://www.youtube.com/watch?v=SGddIJBAEUk&feature=related

[Edited by - thecoast47 on December 12, 2010 11:52:38 AM]

Share this post


Link to post
Share on other sites
Quote:
when you refer to a "Shader", in java that would be called a gradient right?

My apologies - I skipped right over your mention of using java. I'm not a java person. But, no, a pixel shader is quite different from java gradient fill, I'm afraid.

However, (with how very little I know about java) it appears you might be able to a radial gradient for the light sources. I'm not at all familiar (apologies again) how one would raycast the opaque obstacles and draw the shadows.

Share this post


Link to post
Share on other sites
You should make a new reply instead of editing the original post. People might not notice it and ignore it. I don't know the first thing about Java but I do know a bit about C#.

What type of graphics library are you using? Is Grphics2D just a java built in Bitmap class? Is this using the equivalent of GDI, or is this a DirectX or OpenGL based library?

If you aren't using a DirectX or OpenGL library, then that is the source of your problem. If Java is anything like C#, then it can be especially slow. You should look into something like this http://en.wikipedia.org/wiki/Java_OpenGL that way you can use hardware acceleration.

Share this post


Link to post
Share on other sites
After reading this i got very interested in this matter. I produced a working example of some 2D shadows, though probally not in the "right" manners. The code would be useable for java aswell, but you would need to figure our the drawing your self :)

This is how the effect looks like:
http://img808.imageshack.us/i/shadowsn.png/

Share this post


Link to post
Share on other sites
Yup This is what i wanted to achieve.
As you can see in my first attempt i was tracing the rays, which was very slow.
So I've switched to JavaOpenGL(which I just started learning) and i cant figure out how to draw the bloody shadows.
I've only read like 3 tutorials on Opengl and in that time I managed to: Create a "camera" ,use lighting on 3d quadrics,draw pictures (such as '.gif' and others), and draw polygons.

Apparently im supposed to know vector math to calculate when to stop drawing the shadows.I've sat here for like 7 hours trying to rebuild my game with lighting but...I just cant calculate the collision between the polygon and the light.
I barely know any vector math. I'm in grade 11 and i dont know anything about it. All i know about vectors is that they have a direction and a magnitude and i learned that from physics class.I've taken the liberty of learning more and i found out how to find the dot product and magnitude from lessons on youtube but that's about it.


[Edited by - thecoast47 on December 17, 2010 5:43:38 PM]

Share this post


Link to post
Share on other sites
There's a great article here on Gamedev.net about it: http://www.gamedev.net/reference/articles/article2032.asp

I found it to hard to follow, though. The lack of code snippets was the thing that got me :( But i still wanted those damned shadows! So i took a piece of paper, and started drawing. The solution i came up with is similar to the one in the article, but probally more slow.

Basicly, i just calculate two vectors from the lights origin to the objects edeges. Then i use the angle of those vectors to draw a polygon behind the object, acting as my shadow! The hard part here was figuring out which edges to use on the object. It took me some nasty looking if statments to get it right.

The drawing part from openGl is very easy. All you need to know is how to draw a polygon, and that's it :)

The shadow calculation:

/*
* objectLogic():
* Update the shadow position.
*/

void
cube::objectLogic()
{
float thisCenterX, thisCenterY, lightCenterX, lightCenterY;
float angle[2];
float distance;

/* Set the lights position */
lightCenterX = theApp->mainScreen->aLightBall->objectCenterX();
lightCenterY = theApp->mainScreen->aLightBall->objectCenterY();

/* Center points */
thisCenterX = this->x + (this->width / 2);
thisCenterY = this->y + (this->height / 2);

/* Check if the lightsource have a greater position along the x axis */
if (lightCenterX > this->x + this->width) {
/* Check if the lightsource have a greater position along the y axis */
if (lightCenterY < this->y) {
/* Point one will be our x and y position */
this->point[0][0] = this->x;
this->point[0][1] = this->y;

/* Point two will be our x and y position plus our width and height */
this->point[1][0] = this->x + this->width;
this->point[1][1] = this->y + this->height;
} else if (lightCenterY > this->y + this->height) {
/* Point one will be our y position and x plus width position */
this->point[0][0] = this->x + width;
this->point[0][1] = this->y;

/* Point two will be our x position and y plus height position */
this->point[1][0] = this->x;
this->point[1][1] = this->y + this->height;
} else {
/* Point one will be our y position and x plus width position */
this->point[0][0] = this->x + this->width;
this->point[0][1] = this->y;

/* Point two will be our x and y position plus our width and height */
this->point[1][0] = this->x + this->width;
this->point[1][1] = this->y + this->height;
}
} else if (lightCenterX < this->x) {
/* Check if the lightsource have a greater position along the y axis */
if (lightCenterY < this->y) {
/* Point one will be our y position and x plus width position */
this->point[0][0] = this->x + this->width;
this->point[0][1] = this->y;

/* Point two will be our x position and y plus height position */
this->point[1][0] = this->x;
this->point[1][1] = this->y + this->height;
} else if (lightCenterY > this->y + this->height) {
/* Point one will be our x and y position */
this->point[0][0] = this->x;
this->point[0][1] = this->y;

/* Point two will be our x and y position plus our width and height */
this->point[1][0] = this->x + this->width;
this->point[1][1] = this->y + this->height;
} else {
/* Point one will be our x and y position */
this->point[0][0] = this->x;
this->point[0][1] = this->y;

/* Point two will be our x position and y plus height position */
this->point[1][0] = this->x;
this->point[1][1] = this->y + this->height;
}
} else {
/* Check if the lightsource have a greater position along the y axis */
if (lightCenterY < thisCenterY) {
/* Point one will be our x and y position */
this->point[0][0] = this->x;
this->point[0][1] = this->y;

/* Point two will be our y position and x plus width position */
this->point[1][0] = this->x + this->width;
this->point[1][1] = this->y;
} else {
/* Point one will be our x position and y plus height position */
this->point[0][0] = this->x;
this->point[0][1] = this->y + this->height;

/* Point two will be our x and y position plus our width and height */
this->point[1][0] = this->x + this->width;
this->point[1][1] = this->y + this->height;
}
}

/* Calculate the angle */
angle[0] = atan2(lightCenterY - this->point[0][1], lightCenterX - this->point[0][0]);
angle[1] = atan2(lightCenterY - this->point[1][1], lightCenterX - this->point[1][0]);

/*
* Now we can calculate where the shadow is supposed to end.
* Currently im setting the vectors length to -1000, but it's
* not to hard to calculate the distance to the edges of the screen,
* or even a nearby object if needed. For now, this till do.
*/

this->point[2][0] = -1000 * cos(angle[1]) + this->point[0][0];
this->point[2][1] = -1000 * sin(angle[1]) + this->point[0][1];
this->point[3][0] = -1000 * cos(angle[0]) + this->point[1][0];
this->point[3][1] = -1000 * sin(angle[0]) + this->point[1][1];

/* Calculate our alpha */
distance = sqrt(
(lightCenterX - this->x) * (lightCenterX - this->x) +
(lightCenterY - this->y) * (lightCenterY - this->y)
);
this->alpha = 1 - (distance / 300);
}



The drawing of the shadow, with immediate mode though.

/* Dont draw us if we're not needed */
if (this->alpha <= 0.0f)
return;

/* Set the shadows color */
glColor4f(0.0f, 0.0f, 0.0f, this->alpha);

/* Draw the shadow */
glBegin(GL_POLYGON);
glVertex2f(this->point[0][0], this->point[0][1]);
glVertex2f(this->point[1][0], this->point[1][1]);
glVertex2f(this->point[2][0], this->point[2][1]);
glVertex2f(this->point[3][0], this->point[3][1]);
glEnd();

...

/* Drawing of the object here */

Share this post


Link to post
Share on other sites
Finally something i can understand!
What you did makes more sense because the position and shape of shadow polygon is based off position of the square and not the angle of the ray itself.
I think this method might limit me to only using rectangles and squares(just theorizing here) but it doesn't matter because i'm making a game that made up of tiles.The comments in your code were REALLY helpful as well.

Share this post


Link to post
Share on other sites
Glad i could help! :D

Yeah, using this will limit you to simple shapes, sadly. Or a circle would work, but you'd have to do some extra math for it. So i would say only use this for simple shadows. If you want more, then it's better to do it the right way :)

Put shadows in your game now, and let us see the results! :)

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this