Welcome, Guest. Please login or register.

Login with username, password and session length

 
Advanced search

1411511 Posts in 69375 Topics- by 58430 Members - Latest Member: Jesse Webb

April 26, 2024, 01:06:01 PM

Need hosting? Check out Digital Ocean
(more details in this thread)
TIGSource ForumsDeveloperTechnical (Moderator: ThemsAllTook)2d Shadows trouble
Pages: [1]
Print
Author Topic: 2d Shadows trouble  (Read 6111 times)
xhunterko
Level 2
**



View Profile
« on: August 08, 2010, 06:49:08 PM »

Hi there!

I've gone against trying to join yet another forum, but I have no clue where I could turn next for help. And since I'm using the forums resources I thought this it'd be the best place to ask for help.

So I've been following this tutorial:

http://forums.tigsource.com/index.php?topic=8803.0

For at least a few times now with very bad results. When I start adding it to a game state, flashdevelop gives me this error:

Error: Type was not found or was not a compile-time constant: b2Vec2.

When I add it to a game state file that isn't going to be run at all, I get no error. So I was wondering if anyone has used this before and how did they get it to work with their project. Can anybody lend me a hand here?

Thanks in advance.
Logged

ChevyRay
Guest
« Reply #1 on: August 08, 2010, 08:02:25 PM »

b2Vec2 is a class of Box 2D, so you'll have to download Box 2D and import that class to use it.
Logged
xhunterko
Level 2
**



View Profile
« Reply #2 on: August 08, 2010, 08:44:15 PM »

Okay.

That is not the problem. The problem occurs when I attempt to run a playstate with any part of any method/function/whatevertherecalled being called. Lets take the first function that appears in the tutorial.

Code:
private function projectPoint(point_:b2Vec2, light_:b2Vec2):b2Vec2
{
var lightToPoint:b2Vec2 = point_.Copy();
lightToPoint.Subtract(light_);
var projectedPoint:b2Vec2 = point_.Copy();
projectedPoint.Add(lightToPoint);
return projectedPoint;
}


I have a menustate that I can go to any level state from. If I tell the menu to go to any state other then a state that has that function in it, I get no errors. If I tell it to go to a state that DOES have that function in it, I get an error. So, obviously I have to try and either import a file with that function in it, or use only box2D to create my project(which, i'd rather not do). So, I was wondering if anyone else has had success in getting this effect in their flash projects and if any of them are open source that they'd be willing to share with me. Or there are some open source projects on here that use the effect and I could be pointed to them. Either one would be helpful.
(there really does need to be a smiley that is hitting his head against a brick wall, which is what I've been doing the past month and a half)
Logged

Sam
Level 3
***



View Profile WWW
« Reply #3 on: August 09, 2010, 04:42:10 AM »

Hi!  (I wrote that tutorial)

Those code examples use Box2D's vector class (named b2Vec2) just because it's a nice working vector, and because the example goes on to piggy-back on Box2D's shape classes.

The aim of that tutorial was to teach the theory needed for that kind of 2D shadow effect, rather than give a full code example.  For instance I completely skipped over the code for iterating through the sides of a Box2D shape, because that would really be teaching how to use Box2D which is quite a different subject (and one with plenty of tutorials already.)  Instead my hope was to teach techniques that could be applied to whatever system you're using.

That function you quoted can be converted to use the built-in class Point instead of Box2D's vector.  It's a bit easier to read, too:
Code:
private function projectPoint(pointToProjectFrom:Point, lightPosition:Point):Point
{
var fromLightToPoint:Point = pointToProjectFrom.subtract(lightPosition);
var projectedPoint:Point = pointToProjectFrom.add(fromLightToPoint);
return projectedPoint;
}

You'd use that in a function like the following, to produce the shadow from a single edge - as in the diagram:


Code:
private function drawShadowFromEdge(edgeStart:Point, edgeEnd:Point, lightPosition:Point):Shape
{
var projectedStart:Point = projectPoint(edgeStart, lightPosition);
var projectedEnd:Point = projectPoint(edgeEnd, lightPosition);

var shadow:Shape = new Shape();
shadow.graphics.beginFill(0);
shadow.graphics.moveTo(edgeStart.x, edgeStart.y);
shadow.graphics.lineTo(projectedStart.x, projectedStart.y);
shadow.graphics.lineTo(projectedEnd.x, projectedEnd.y);
shadow.graphics.lineTo(edgeEnd.x, edgeEnd.y);
        shadow.graphics.endFill();

return shadow;
}

drawShadowFromEdge returns a Shape object, so you'd use it like:
Code:
var myLineStart:Point = new Point(50,50);
var myLineEnd:Point = new Point(55, 80);
var myLight:Point = new Point(5, 65);

var myShadow:Shape = drawShadowFromEdge(myLineStart, myLineEnd, myLight);
addChild(myShadow);

I get the feeling all of that is easier to read than the code in the tutorial.  Hopefully a sign of my improving!

I hope that helps it make more sense, and that things can start working for you.  I'll do my best to give more support if you need it.
Logged
bateleur
Level 10
*****



View Profile
« Reply #4 on: August 09, 2010, 06:27:22 AM »

The problem occurs when I attempt to run a playstate with any part of any method/function/whatevertherecalled being called.

Are you perhaps missing one or more "import" statements?

For example:

import Box2D.Common.Math.*;

...would get you b2Vec2. (Assuming you saved the unpacked Box2D classes in your project's base folder.)
Logged

xhunterko
Level 2
**



View Profile
« Reply #5 on: August 09, 2010, 09:16:44 AM »

@salt: Sorry for being such a bother, I didn't expect to get that kind of response. I'll have to look at it all in more detail after I finish getting up today. But thank you!

@bateleur: Again. That is not the problem. I also followed a tutorial on implementing box2D in flixel from the FlashGameDojo site. Which included importing several key statements. Then I attempted to run that as well and got the error. So apparently I'm doing something wrong on one or two ends and I don't know what.

(i don't mean to snap at anyone in particular. i've just been dealing with this for a while now and it's just starting to get to me. so apologies if i sounded harsh or snippish.)
Logged

xhunterko
Level 2
**



View Profile
« Reply #6 on: August 09, 2010, 02:45:42 PM »

Well, this occurs:

http://www.majhost.com/gallery/rob/Blip/darksquare1.png

So apparently I'm doing something correct finally. Now for the next part.
Logged

xhunterko
Level 2
**



View Profile
« Reply #7 on: August 09, 2010, 05:38:13 PM »

One more thing. Just a couple of quick questions, if you will.

What do you mean by "draw all the other shapes"?

What lines of code control the four corners and the sides?

Why do you not have the shadows simply cover the entire screen?

Thanks in advance if these could be answered.
Logged

Sam
Level 3
***



View Profile WWW
« Reply #8 on: August 10, 2010, 04:00:08 AM »

-Draw all the other shapes
I'm afraid I don't know what part you're referring to in particular.  I probably mean something like "repeat the same procedure for any other shape that you want to be casting shadows".

-Four corners and sides
Judging from your screenshot, you want shadows to be cast from square tiles.  You will need information on the edges of all the tiles.  How you generate and store that is up to you!  Your basic two options are to do it on a per-tile basis every frame; or to generate a big list of edges when the map is first loaded and use that to draw shadows from.

Either way, it'd be a good idea to make a custom class to represent an edge.  All it needs to do is store the start and end points of the edge.  You don't need to separately store the position of the corners of your tiles, as that information is a part of the edge.
Code:
package  
{
import flash.geom.Point;

public class Edge
{
public var start:Point;
public var end:Point;
public function Edge(startPoint_:Point, endPoint_:Point)
{
//just store the given points
start = startPoint_;
end = endPoint_;
}
}
}

To find the edges of a single tile, you can use something like:
Code:
private function edgesOfTile(tileTopLeft:Point, tileSize:Number):Array
{
//find the corners of this tile
var tileTopRight:Point = tileTopLeft.add(new Point(tileSize, 0));
var tileBottomLeft:Point = tileTopLeft.add(new Point(0, tileSize));
var tileBottomRight:Point = tileTopLeft.add(new Point(tileSize, tileSize));

//create edges linking those corners in a clockwise direction
var topEdge:Edge = new Edge(tileTopLeft, tileTopRight);
var rightEdge:Edge = new Edge(tileTopRight, tileBottomRight);
var bottomEdge:Edge = new Edge(tileBottomRight, tileBottomLeft);
var leftEdge:Edge = new Edge(tileBottomLeft, tileTopLeft);

var edgesInArray:Array = [topEdge, rightEdge, bottomEdge, leftEdge];
return edgesInArray;
}

Use that together with the earlier example code for drawing the shadow for a single edge to draw the shadow of a square tile by drawing the shadows for all four of its edges.

Once you have that working, you can move on to having it read your map data and draw shadows for all the tiles in your map.  There will also be plenty of improvements you can make to the speed, as it will be drawing the shadows for a lot more edges than is actually required.

-Shadows covering the whole screen
Main reason I don't have unlimited length shadows is I've still not found a 'neat' way of making them just the right length.  One wants the shadow to at least reach the edge of the screen, but not go miles further than the edge, as Flash will waste time drawing all of that shadow which is off screen and never seen.

In retrospect I've probably overestimated how much of an issue having Flash draw a slightly larger shape than needed actually is.

You can edit the projectPoint function so that the point is projected a fixed distance instead of a distance proportional to the distance of the light source from the point.  Set that distanceToProject large enough, and the shadows will reach the edge of the screen.

To be totally sure the shadow will always reach the edge of the screen, the distance should be √(screenWidth² + screenHeight²)  ..unless you have stuff off-screen that's casting shadows over the screen area, in which case it'll need to be something larger.
Code:
private const distanceToProject:Number = 500;
private function projectPoint(pointToProjectFrom:Point, lightPosition:Point):Point
{
var fromLightToPoint:Point = pointToProjectFrom.subtract(lightPosition);

//normalize sets the length of the vector to whatever you like
var toAddToPoint:Point = fromLightToPoint;
toAddToPoint.normalize(distanceToProject);

var projectedPoint:Point = pointToProjectFrom.add(toAddToPoint);

return projectedPoint;
}
Logged
xhunterko
Level 2
**



View Profile
« Reply #9 on: August 10, 2010, 02:32:38 PM »

 Shocked.....Wow, head hurts, ow.

Even though I really want to use something like this, I don't think I'll be using something like this for this game. Even though I really want to, I don't think I'm capable of pulling this off. At least not yet. I still think I can get the effect that I want though. But it'll be more like, 'oh is that it?', instead of 'hey, that was cool!' kind of thing. What I basically decided on was drawing a large square and creating a transparent hole in the center that then expands inside said square revealing the background. Which is kind of dissapointing to me.

But still, what you did there salt, that is awesome. Seriously. Thanks for answering those.
(i really hope I'm not sounding like an ungrateful d* head here)
Logged

Sam
Level 3
***



View Profile WWW
« Reply #10 on: August 10, 2010, 03:04:12 PM »

Not at all! Smiley

Very good idea to concentrate on getting your game working rather than spending forever trying to get fancy effects working.  This has also given me ideas for improving the original tutorial, which is always good.

Best of luck with the game!
Logged
Tycho Brahe
Level 10
*****

λx.x


View Profile
« Reply #11 on: August 15, 2010, 01:03:37 PM »

If you want I can post up my shadows code as well, its more or less identical (its in c++ though) and I *think* it uses the same techniques. You never know, it might be helpful to compare the two Shrug

I created my implementation by reading through the hard shadows section of this tutorial. And I think its the one that Salt based his tutorial on. You can safely ignore ALL the opengl specific rendering stuff, and just look at the code on hard shadows, once you get your head around it you'll be able to work through a solution.

Most of all I would say, don't give up!! unless you want to work on other parts of your game more, keep hacking at it, and it will eventually work. When it does you'll have it in your repertoire for ever more, and feel really good about it.
Logged
xhunterko
Level 2
**



View Profile
« Reply #12 on: August 17, 2010, 11:18:52 AM »

Oh, I forgot about this.

Well, if you want to 14113. I don't know how I'd be able to integrate something like that into flashDevelop and Flixel though.

I was able to come up with a rather simple solution. It does what I want, I'm still just dissapointed that I couldn't do it like this.

But by all means, I wouldn't mind looking at your code at all.  Gentleman
Logged

Tycho Brahe
Level 10
*****

λx.x


View Profile
« Reply #13 on: August 19, 2010, 04:14:13 AM »

ah, sorry for taking so long to reply; heres my code:
.cpp file:
Code:
#include "Box2dShadowEngine.h"
#include "GLOBAL.h"
using namespace std;
//Light struct
Light::Light(void)
{
}
Light::Light(float x, float y, float Radius)
{
centre.x = x;
centre.y = y;
radius = Radius;
}
void Light::SetColour(float Red, float Green, float Blue, float Brightness)
{
red = Red;
green = Green;
blue = Blue;
brightness = Brightness;
}
void Light::Move(float x, float y)
{
centre.x = x;
centre.y = y;
}
void Light::Resize(float Radius)
{
radius = Radius;
}

//Shadow engine class
Box2dShadowEngine::Box2dShadowEngine(void)
{
}

Box2dShadowEngine::~Box2dShadowEngine(void)
{

}
void Box2dShadowEngine::AddLight(Light aLight)
{
LightList.push_back(aLight);
}
void Box2dShadowEngine::PrintLightList(void)
{
Light OLight;
for(unsigned int i = 0;i<LightList.size();i++)
{
OLight = LightList[i];
printf("Light:%i\n",i);
printf(" Red:%f\n",OLight.red);
printf(" Green:%f\n",OLight.green);
printf(" Blue:%f\n",OLight.blue);
printf(" Brightness:%f\n",OLight.brightness);
printf(" Radius:%f\n",OLight.radius);
printf(" Centre:X:%f Y:%f\n",OLight.centre.x,OLight.centre.y);
}
}
void Box2dShadowEngine::RenderLights(void)
{
Light OLight;
float radius, red, green, blue, brightness;
b2Vec2 centre;
glBlendFunc(GL_SRC_ALPHA, GL_ONE);

for(unsigned int i = 0;i<LightList.size();i++)
{
OLight = LightList[i];
radius = OLight.radius;
red = OLight.red;
green = OLight.green;
blue = OLight.blue;
brightness = OLight.brightness;
centre = OLight.centre;
b2Vec2 POINT(0,radius);

glBegin(GL_TRIANGLE_FAN);
glColor4f(red,green,blue,brightness);
glVertex3f(centre.x,centre.y,0.0);

glColor4f(red,green,blue,0.0);
for(float x = 0;x<M_PI*2;x+=M_PI/20)
{
b2Vec2 C1( -sin(x),cos(x));
b2Vec2 C2(cos(x),sin(x));
b2Mat22 ROTMATRIX(C2,C1);
b2Vec2 rPOINT = b2Mul(ROTMATRIX,POINT);
rPOINT = rPOINT+centre;
glVertex3f(rPOINT.x,rPOINT.y,0.0);
}

b2Vec2 C1( -sin(0.0),cos(0.0));
b2Vec2 C2(cos(0.0),sin(0.0));
b2Mat22 ROTMATRIX(C2,C1);
b2Vec2 rPOINT = b2Mul(ROTMATRIX,POINT);
rPOINT = rPOINT+centre;
glVertex3f(rPOINT.x,rPOINT.y,0.0);

glColor4f(red,green,blue,brightness);
glVertex3f(centre.x,centre.y,0.0);
glEnd();
}
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}


void Box2dShadowEngine::RenderShadows(void)
{
glColor4f(0.0,0.0,0.0,0.1);
glBegin(GL_POLYGON);
glVertex3f(-1000,-1000,0.0);
glVertex3f(1000,-1000,0.0);
glVertex3f(1000,1000,0.0);
glVertex3f(-1000,1000,0.0);
glEnd();

for(unsigned int i = 0;i<LightList.size();i++)
{
Light CLight = LightList[i];
for (b2Body* b = ShadowEngineWorld->GetBodyList(); b; b = b->GetNext())
{
b2Fixture* GetFixtureList();
for (b2Fixture* f = b->GetFixtureList(); f; f = f->GetNext())
{
b2Shape* s = f->GetShape();
b2ShapeType SHAPETYPE = s->GetType();
if(SHAPETYPE == -1){
//printf(" Unknown Shape\n");
}
if(SHAPETYPE == 0){
//b2CircleShape* c = (b2CircleShape*)s;
//printf(" Circle Shape shadow\n");
}
if(SHAPETYPE == 1){
b2PolygonShape* p = (b2PolygonShape*)s;
RenderPolygonShadow(p,b,CLight);
//printf(" Polygon Shape shadow\n");
}
if(SHAPETYPE == 2){
b2EdgeShape* e = (b2EdgeShape*)s;
RenderLineShadow(e,b,CLight);
//printf("static shape shadow\n");
}
if(SHAPETYPE == 3){
//printf("unknown shape error!\n");
}
}
}
}
}
void Box2dShadowEngine::RenderPolygonShadow(b2PolygonShape* p,b2Body* b,Light CLight)
{
bool Facing;
bool PrevFacing;
b2Vec2 sbv1(0,0);
b2Vec2 sbv2(0,0);
b2Vec2 ssv1(0,0);
b2Vec2 ssv2(0,0);
for(int i = 0;i<p->GetVertexCount();i++)
{
float angle = b->GetAngle();
//creating a Rotation Matrix
//Top Row
b2Vec2 C1( -sin(angle),cos(angle));
//Bottom Row
b2Vec2 C2(cos(angle),sin(angle));
//Put it together
b2Mat22 ROTMATRIX(C2,C1);
b2Vec2 FaceVert1 = p->GetVertex(i);
b2Vec2 FaceVert2;
//printf("%i\n",i);
if(i == p->GetVertexCount()-1)
{
FaceVert2 = p->GetVertex(0);
}else{
FaceVert2 = p->GetVertex(i+1);
}
FaceVert1 = b2Mul(ROTMATRIX,FaceVert1)+b->GetWorldCenter();
FaceVert2 = b2Mul(ROTMATRIX,FaceVert2)+b->GetWorldCenter();
b2Vec2 Normal(FaceVert1.x-FaceVert2.x,FaceVert1.y-FaceVert2.y);

b2Vec2 nC1(0,1);
b2Vec2 nC2(-1,0);
b2Mat22 nROTMATRIX(nC1,nC2);
Normal = b2Mul(nROTMATRIX,Normal);
b2Vec2 Midpoint = (FaceVert2+FaceVert1);
Midpoint.x = Midpoint.x/2;Midpoint.y = Midpoint.y/2;
b2Vec2 VecToLight = CLight.centre-Midpoint;
{
float DotProd = b2Dot(Normal, VecToLight);
if(DotProd>0)
{
Facing = true;
if(DebugMode==true){
glColor4f(1.0,0.0,0.0,0.2);
glBegin(GL_POLYGON);
glVertex3f(Midpoint.x+0.5,Midpoint.y+0.5,0.0);
glVertex3f(Midpoint.x-0.5,Midpoint.y+0.5,0.0);
glVertex3f(Midpoint.x-0.5,Midpoint.y-0.5,0.0);
glVertex3f(Midpoint.x+0.5,Midpoint.y-0.5,0.0);
glEnd();
}
}else{
Facing = false;
{
b2Vec2 V1vtl = 100*(FaceVert1-CLight.centre);
b2Vec2 V2vtl = 100*(FaceVert2-CLight.centre);
if(DebugMode == true)
{
glBegin(GL_LINES);
glVertex3f(FaceVert1.x,FaceVert1.y,0.0);
glVertex3f(FaceVert1.x+V1vtl.x,FaceVert1.y+V1vtl.y,0.0);
glVertex3f(FaceVert2.x,FaceVert2.y,0.0);
glVertex3f(FaceVert2.x+V2vtl.x,FaceVert2.y+V2vtl.y,0.0);
glEnd();
}
glBlendFunc(GL_ZERO, GL_ZERO);
glBegin(GL_POLYGON);
glColor4f(0.0,0.0,0.0,1.0);
glVertex3f(FaceVert1.x,FaceVert1.y,0.0);
glVertex3f(FaceVert2.x,FaceVert2.y,0.0);
glVertex3f(FaceVert2.x+V2vtl.x,FaceVert2.y+V2vtl.y,0.0);
glVertex3f(FaceVert1.x+V1vtl.x,FaceVert1.y+V1vtl.y,0.0);
glEnd();
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

if(DebugMode== true)
{
glColor4f(0.0,1.0,0.0,0.2);
glBegin(GL_POLYGON);
glVertex3f(Midpoint.x+0.5,Midpoint.y+0.5,0.0);
glVertex3f(Midpoint.x-0.5,Midpoint.y+0.5,0.0);
glVertex3f(Midpoint.x-0.5,Midpoint.y-0.5,0.0);
glVertex3f(Midpoint.x+0.5,Midpoint.y-0.5,0.0);
glEnd();
}
}
}
}
PrevFacing = Facing;
}
}
void Box2dShadowEngine::RenderLineShadow(b2EdgeShape* e,b2Body* b, Light CLight)
{
//get end points and then cast shadow. YAY!;
float angle = b->GetAngle();

b2Vec2 C1( -sin(angle),cos(angle));
b2Vec2 C2(cos(angle),sin(angle));
b2Mat22 ROTMATRIX(C2,C1);

b2Vec2 End1 = e->GetVertex1();
b2Vec2 End2 = e->GetVertex2();

End1 = b2Mul(ROTMATRIX,End1);
End2 = b2Mul(ROTMATRIX,End2);

glColor4f(0.0,1.0,0.0,0.2);
    b2Vec2 V1vtl = 100*(End1-CLight.centre);
    b2Vec2 V2vtl = 100*(End2-CLight.centre);

    glColor4f(0.0,0.0,0.0,1.0);
    glBegin(GL_POLYGON);
    glVertex3f(End1.x,End1.y,0.0);
    glVertex3f(End2.x,End2.y,0.0);
    glVertex3f(End2.x+V2vtl.x,End2.y+V2vtl.y,0.0);
    glVertex3f(End1.x+V1vtl.x,End1.y+V1vtl.y,0.0);
    glEnd();
}
void Box2dShadowEngine::RenderCircleShadow(void)
{
}
void Box2dShadowEngine::Render(b2World *world,float x, float y,bool Debug)
{
//glTranslatef(x,y,0);
DebugMode = Debug;
ShadowEngineWorld = world;
RenderLights();
RenderShadows();
}

.h (header) file
Code:
#pragma once
#include "GLOBAL.h"
using namespace std;
struct Light
{
public:
Light(void);
Light(float x, float y, float Radius);
void SetColour(float Red, float Green, float Blue,float Brightness);
void Move(float x, float y);
void Resize(float Radius);

float radius;
b2Vec2 centre;

float red;
float green;
float blue;
float brightness;
};
class Box2dShadowEngine
{
public:
Box2dShadowEngine(void);
~Box2dShadowEngine(void);

void AddLight(Light aLight);
void PrintLightList(void);
void Render(b2World *world,float x, float y,bool Debug);

void RenderLights(void);
void RenderShadows(void);

void RenderPolygonShadow(b2PolygonShape* p,b2Body* b,Light CLight);
void RenderCircleShadow(void);
void RenderLineShadow(b2EdgeShape* e,b2Body* b,Light CLight);

bool DebugMode;
b2World *ShadowEngineWorld;
vector<Light> LightList;
};

hope this helps, its kind of messy, but there are a couple of functions (render polygon shadow, and render line shadow in particular) which do most of the work.
Logged
xhunterko
Level 2
**



View Profile
« Reply #14 on: August 19, 2010, 09:38:01 PM »

 That looks interesting. If I ever get stuff working with box2D I'll have to try and see what you used for it here more closely.

"its kind of messy"
I was going to post a rant about that but thought better of it. I think I'm good now.
Logged

Tycho Brahe
Level 10
*****

λx.x


View Profile
« Reply #15 on: August 20, 2010, 01:21:48 AM »

"its kind of messy"
I was going to post a rant about that but thought better of it. I think I'm good now.
Yeah, sorry about that. What I meant was not much stuff is organized into separate functions, and I could easily refactor/optimize a lot of other stuff. I didn't mean it had a load of unwieldy hacks thrown in.
Logged
xhunterko
Level 2
**



View Profile
« Reply #16 on: August 24, 2010, 04:39:51 PM »

Eh, no biggie. My problem is that when people usually say that, well it's mostly about attitude more then anything. I should do a videolog about it.
Logged

Pages: [1]
Print
Jump to:  

Theme orange-lt created by panic