Raycasting visibility in 2D game

  • (2 Pages)
  • +
  • 1
  • 2

28 Replies - 1915 Views - Last Post: 19 December 2013 - 07:49 PM Rate Topic: -----

#1 Orami  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 22
  • Joined: 09-December 13

Raycasting visibility in 2D game

Posted 09 December 2013 - 11:59 PM

My code does what it is supposed to do most of the time, but I end up with small glitches while drawing my triangles sometimes it will make a projection when it shouldn't while reloading the area fixes the issue.

An example of the game is here: https://www.youtube....h?v=SeKz2GrMo28

I have posted on other sites, but got no responses:
http://cboard.cprogr...ion-engine.html
https://www.allegro....s/thread/613568

I haven't determined why I get projections from certain points of walls which is something I would like to know. I would also like to know how to handle a wall being split in half by where my raytrace starts ie the wall to the right is cut in half. I tried to fix it by checking if the first and last vertices were on the same wall, but it doesn't seem to work and I don't understand why.



#ifndef VISIBILITY_H
#define VISIBILITY_H

#include <allegro.h>
#include <winalleg.h>
#include <vector>

#include "Line_Segment_2D.h"


class Visibility
{
    public:
        Visibility(int x, int y);
        BITMAP* Get_Visibility(int max, int x, int y, std::vector <Line_Segment_2D *> &Walls);
        ~Visibility();
    private:
        bool TESTING;
        int size_x; int size_y;
        BITMAP* VIS_MAP;
};

#endif




#include "Visibility.h"

#include <allegro.h>
#include <iostream>
#include <winalleg.h>
#include <vector>
#include <algorithm>
#include <math.h>

#include "Line_Segment_2D.h"
#include "Point_2D.h"

bool sortByAngle(const Point_2D &lhs,const Point_2D &rhs){return lhs.Last_Angle < rhs.Last_Angle;}
bool sortByDistance(const Line_Segment_2D *lhs, const Line_Segment_2D *rhs){return lhs->dist < rhs->dist;}

bool PointIsVisible(Point_2D ori, Point_2D p, std::vector <Line_Segment_2D *> &w)
{
    Line_Segment_2D t(ori,p);
    Point_2D intersect;
    for(unsigned int i = 0;i < w.size();i++)
    {
        if(p != w[i]->A && p != w[i]->B && ori != w[i]->A && ori != w[i]->B )  //if we don't belong to this line; basicly line should not interfere with itself or other walls that end at the same point.
        {
            if(t.Segments_Intersect(w[i],intersect))return false;
        }
    }
    return true;
}

bool SameWall(Point_2D p1, Point_2D p2, std::vector <Line_Segment_2D *> &W)
{
    for(int i = 0; i < W.size();i++)
    {
        if((W[i]->A == p1 || W[i]->A == p2) && (W[i]->B == p1 || W[i]->B == p2))return true;
    }
    return false;
}

Point_2D Find_Projection_Intersection(Point_2D Ori, Point_2D ver, std::vector <Line_Segment_2D *> W)
{
    Point_2D intersect(0,0);

    Line_Segment_2D *Line_Of_Sight;
    Line_Of_Sight = new Line_Segment_2D(ver,Ori);
    Line_Of_Sight->Resize(3072);        //need a big number here to extend to at least the outer bounding box.
    for(unsigned int i = 0;i < W.size();i++)
    {
        if(Line_Of_Sight->Segments_Intersect(W[i],intersect))
        {   //ok wall intersects with LOS!  Lets make sure it isn't our origonal wall now or one that ends at the same spot.
            intersect.isProjection = true;
            intersect.Last_Angle = ver.Last_Angle;
            if(intersect != ver)
            {
                intersect.isProjection = true;
                return intersect;
            }
        }
    }
}
Visibility::Visibility(int x, int y)
{
    TESTING = true;
    size_x = x;
    size_y = y;
    VIS_MAP = create_bitmap(x,y);
}

BITMAP* Visibility::Get_Visibility(int max, int x,int y, std::vector <Line_Segment_2D *> &Walls)
{

    Point_2D Ori(x,y);
    std::vector <Point_2D> Endpoints;
    rectfill(VIS_MAP,0,0,size_x,size_y,makecol(0,0,0));     //put fog of war up over everything!

    for(unsigned int i = 0;i < Walls.size();i++)        //populate Endpoints from the walls in the nearby area.
    {
        Walls[i]->DistanceToPoint(Ori);
        Endpoints.push_back(Walls[i]->A);
        Ori.Angle_In_Degrees(Endpoints[i*2]);
        Endpoints.push_back(Walls[i]->B)/>;
        Ori.Angle_In_Degrees(Endpoints[(i*2)+1]);
    }
    std::sort(Walls.begin(),Walls.end(),sortByDistance);        //sort walls by distance
    std::sort(Endpoints.begin(),Endpoints.end(),sortByAngle);   //sort vertices by angle

    std::vector <Point_2D> Final_Points;                        //container for vertices
    for(unsigned int i = 0; i < Endpoints.size();i++)
    {
        while(i+1 < Endpoints.size() && Endpoints[i] == Endpoints[i+1])Endpoints.erase(Endpoints.begin()+i);   //only one of each vertex
        bool has_start = false;
        bool has_end = false;
        if((i == 0 || i == Endpoints.size()-1))//first or last point and they share the same wall
        {
            has_end = true;
            has_start = true;
        }
        for(unsigned int j = 0; j < Walls.size();j++)
        {
            if(Walls[j]->A == Endpoints[i] || Walls[j]->B == Endpoints[i])
            {
                if(Walls[j]->Active == true)
                {
                    Walls[j]->Active = false;
                    has_end = true;
                }else
                {
                    Walls[j]->Active = true;
                    has_start = true;
                }
            }
        }
        if(PointIsVisible(Ori,Endpoints[i],Walls))
        {
            if(has_end && has_start)      //if a wall starts and ends here then it is a hard point with no projections
            {
                Final_Points.push_back(Endpoints[i]);
            }else
            {
                if(has_end) //end has projection second
                {
                    Final_Points.push_back(Endpoints[i]);
                    Final_Points.push_back(Find_Projection_Intersection(Ori,Endpoints[i],Walls));
                }
                else //start has projection first
                {
                    Final_Points.push_back(Find_Projection_Intersection(Ori,Endpoints[i],Walls));
                    Final_Points.push_back(Endpoints[i]);
                }
            }
        }
    }
    for(unsigned int i = 0;i + 1 < Final_Points.size();i++)
    {
        triangle(VIS_MAP,Final_Points[i].x,Final_Points[i].y,Final_Points[i+1].x,Final_Points[i+1].y,Ori.x,Ori.y,makecol(255,0,255));
        line(VIS_MAP,Final_Points[i+1].x,Final_Points[i+1].y,Final_Points[i].x,Final_Points[i].y,makecol(255,0,0));
        circlefill(VIS_MAP,Final_Points[i].x,Final_Points[i].y,5,makecol(255,255,0));
    }
    triangle(VIS_MAP,Final_Points[Final_Points.size() -1].x,Final_Points[Final_Points.size()-1].y,Final_Points[0].x,Final_Points[0].y,Ori.x,Ori.y,makecol(255,0,255));
    circlefill(VIS_MAP,Final_Points[Final_Points.size() -1].x,Final_Points[Final_Points.size() -1].y,5,makecol(255,255,0));
    //EVERYTHING FOLLOWING IS DEBUG OUTPUT TO THE SCREEN 
    
    
    if(TESTING) //draw lines to all my vertices
    {
        for(unsigned int i = 0;i < Final_Points.size();i++)
        {
            line(VIS_MAP,x,y,Final_Points[i].x,Final_Points[i].y,makecol(0,255,0));
        }
        for(unsigned int i = 0;i < Walls.size();i++)
        {
            line(VIS_MAP,Walls[i]->A.x,Walls[i]->A.y,Walls[i]->B.x,Walls[i]->B.y,makecol(0,0,255));
        }
        std::string str;
        char temp[15];
        str.assign("Number Of Visible Vertices: ");
        str.append(itoa(Final_Points.size(),temp,10));
        textout_ex(VIS_MAP,font,str.c_str(),x-500,y-380,makecol(0,255,0),makecol(50,50,50));
        for(int i = 0; i < Final_Points.size();i++)
        {
            str.assign("Vertice");
            str.append(itoa(i,temp,10));
            str.append( ":  X:");
            str.append(itoa(Final_Points[i].x,temp,10));
            str.append( " Y:");
            str.append(itoa(Final_Points[i].y,temp,10));
            str.append( " ANGLE:");
            str.append(itoa(Final_Points[i].Last_Angle,temp,10));
            str.append( " Proj: ");
            if(Final_Points[i].isProjection)str.append( "YES");
            else str.append( "NO");
            textout_ex(VIS_MAP,font,str.c_str(),x-500,y-(360 - i*10),makecol(0,255,0),makecol(50,50,50));
        }
        str.assign("Number Of Walls: ");
        str.append(itoa(Walls.size(),temp,10));
        textout_ex(VIS_MAP,font,str.c_str(),x+20,y-380,makecol(0,255,0),makecol(50,50,50));
        for(int i = 0; i < Walls.size();i++)
        {
            str.assign("WALL ");
            str.append(itoa(i,temp,10));
            str.append( ":  X1:");
            str.append(itoa(Walls[i]->A.x,temp,10));
            str.append( " Y1:");
            str.append(itoa(Walls[i]->A.y,temp,10));
            str.append( " X2:");
            str.append(itoa(Walls[i]->B.x,temp,10));
            str.append( " Y1:");
            str.append(itoa(Walls[i]->B.y,temp,10));
            str.append( ":  DISTANCE:");
            str.append(itoa(Walls[i]->dist,temp,10));
            textout_ex(VIS_MAP,font,str.c_str(),x+20,y-(360 - i*10),makecol(0,255,0),makecol(50,50,50));
        }
    }
    return VIS_MAP;
}

Visibility::~Visibility()
{
    destroy_bitmap(VIS_MAP);
}




Is This A Good Question/Topic? 0
  • +

Replies To: Raycasting visibility in 2D game

#2 snoopy11  Icon User is offline

  • Engineering ● Software
  • member icon

Reputation: 766
  • View blog
  • Posts: 2,227
  • Joined: 20-March 10

Re: Raycasting visibility in 2D game

Posted 10 December 2013 - 09:28 AM

Well,

The first thing I see is this
Point_2D Find_Projection_Intersection(Point_2D Ori, Point_2D ver, std::vector <Line_Segment_2D *> W)
	{
	    Point_2D intersect(0,0);
	 
	    Line_Segment_2D *Line_Of_Sight;
        Line_Of_Sight = new Line_Segment_2D(ver,Ori);
	    Line_Of_Sight->Resize(3072);        //need a big number here to extend to at least the outer bounding box.
	    for(unsigned int i = 0;i < W.size();i++)
	    {
	        if(Line_Of_Sight->Segments_Intersect(W[i],intersect))
	        {   //ok wall intersects with LOS!  Lets make sure it isn't our origonal wall now or one that ends at the same spot.
	            intersect.isProjection = true;
	            intersect.Last_Angle = ver.Last_Angle;
	            if(intersect != ver)
	            {
	                intersect.isProjection = true;
	                return intersect;
	            }
	        }
	    }
		
		
	}



if(intersect equals ver) then there is no return value for Find_Projection_Intersection

perhaps it should be something like

Point_2D Find_Projection_Intersection(Point_2D Ori, Point_2D ver, std::vector <Line_Segment_2D *> W)
	{
	    Point_2D intersect(0,0);
	 
	    Line_Segment_2D *Line_Of_Sight;
        Line_Of_Sight = new Line_Segment_2D(ver,Ori);
	    Line_Of_Sight->Resize(3072);        //need a big number here to extend to at least the outer bounding box.
	    for(unsigned int i = 0;i < W.size();i++)
	    {
	        if(Line_Of_Sight->Segments_Intersect(W[i],intersect))
	        {   //ok wall intersects with LOS!  Lets make sure it isn't our origonal wall now or one that ends at the same spot.
	            intersect.isProjection = true;
	            intersect.Last_Angle = ver.Last_Angle;
	            if(intersect != ver)
	            {
	                intersect.isProjection = true;
	                return intersect;
	            }
	        }
	    }
		
		//return intersect or other Point_2D variable.
	}


Regards

Snoopy.

This post has been edited by snoopy11: 10 December 2013 - 09:29 AM

Was This Post Helpful? 1
  • +
  • -

#3 Orami  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 22
  • Joined: 09-December 13

Re: Raycasting visibility in 2D game

Posted 10 December 2013 - 10:01 AM

Hi and thanks for the reply. In the context of which the function is used we already know that it will intersect another line. I guess I should have added that the entire area is bounded by walls that the player can never see. What the code tries to do here is check to see if walls only start at this point or only end at this point if either case is true then we need to make a projection to the next wall because it is a convex corner. Should the corner be concave it will have both a start and a end at the point where the walls meet meaning do not cast the ray for a projection. There is no case where the projection line will not intersect a wall so while your compiler will tell you "Hey man this can get to where there is no return" it really can't. If it makes you feel better we can return a null pointer for no intersect found.

if(PointIsVisible(Ori,Endpoints[i],Walls))
        {
            if(has_end && has_start)      //if a wall starts and ends here then it is a hard point with no projections
            {
                Final_Points.push_back(Endpoints[i]);
            }else
            {
                if(has_end) //end has projection second
                {
                    Final_Points.push_back(Endpoints[i]);
                    Final_Points.push_back(Find_Projection_Intersection(Ori,Endpoints[i],Walls));
                }
                else //start has projection first
                {
                    Final_Points.push_back(Find_Projection_Intersection(Ori,Endpoints[i],Walls));
                    Final_Points.push_back(Endpoints[i]);
                }
            }
        }


Was This Post Helpful? 0
  • +
  • -

#4 snoopy11  Icon User is offline

  • Engineering ● Software
  • member icon

Reputation: 766
  • View blog
  • Posts: 2,227
  • Joined: 20-March 10

Re: Raycasting visibility in 2D game

Posted 10 December 2013 - 10:16 AM

Well,

No one knows your code like you do.

Are you sure all your walls are on grid boundaries ?

Snoopy.
Was This Post Helpful? 0
  • +
  • -

#5 Orami  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 22
  • Joined: 09-December 13

Re: Raycasting visibility in 2D game

Posted 10 December 2013 - 10:29 AM

Yes, actually I use ints for my point_2D class to prevent floats from doing their oddball trailing .000000001 imprecision. I know this code looks a little hacky maybe even a lot. But the outer bounds are there. As for the zone...

#include "world.h"
#include "textures.h"
#include "Wall.h"
#include <fstream>
#include <string.h>
#include "Visibility.h"

using namespace std;

    World::World(string s,Resource_Manager *r)
{
    path.assign(s);
    BUFFER = create_bitmap(3072,3072);
    Vis = new Visibility(3072,3072);
}

void World::Draw_Scenery(BITMAP* PDRAW, int x,int y,int sx,int sy,Resource_Manager *r)   //shall draw to BUFFER the scenery based on the screen centered at x,y with a scrx of sx and scry of sy
{
    string t_name;

    if(last_x != (x - x % 1024) / 1024 || last_y != (y - y % 1024) / 1024)  //if x or y changed we need to buffer new area to the map.
    {
        Walls.clear();
        rectfill(BUFFER,0,0,3072,3072,makecol(255,255,255));
        last_x = (x - x % 1024) / 1024;
        last_y = (y - y % 1024) / 1024;
        int start_x = x - 1024;
        int start_y = y - 1024;
        for(int i = 0;i < 3;i++)
        {
            for(int j = 0; j < 3;j++)
            {
                char str[255];
                t_name.assign(path);
                t_name.append("x");
                t_name.append(itoa(floor(start_x / 1024) + i,str,10));
                t_name.append("y");
                t_name.append(itoa(floor(start_y / 1024) + j,str,10));
                t_name.append(".txt");
                Zone *z = new Zone(t_name,r);
                blit(z->Get_Zone_Bitmap(),BUFFER,0,0,i * 1024,j * 1024 , 1024, 1024);
                vector <Line_Segment_2D *> walls;
                z->Get_Zone_Walls(walls);
                for(unsigned int q = 0;q < walls.size();q++)     //converts from a zone standpoint to a cluster standpoint
                {
                    Walls.push_back(new Line_Segment_2D(walls[q]->A.x + 1024 * i,walls[q]->A.y + 1024 * j, walls[q]->B.x + 1024 * i, walls[q]->B.y + 1024 * j));
                }
                delete z;
            }
        }
        //Setting the OUTER LIMITS - we control the vertical and the horizontal from the inner mind to the outer limits.
        Line_Segment_2D *boundery = new Line_Segment_2D(0,0,3072,0);
        Walls.push_back(boundery);
        boundery = new Line_Segment_2D(3072,0,3072,3072);
        Walls.push_back(boundery);
        boundery = new Line_Segment_2D(3072,3072,0,3072);
        Walls.push_back(boundery);
        boundery = new Line_Segment_2D(0,0,0,3072);
        Walls.push_back(boundery);
    }
    blit(BUFFER,PDRAW,1024 + x % 1024 - sx / 2,1024 + y % 1024 - sy / 2,0,0,sx,sy);
    masked_blit(Vis->Get_Visibility(0,1024 + x % 1024,1024 + y % 1024,Walls),PDRAW,1024 + x % 1024 - sx / 2,1024 + y % 1024 - sy / 2,0,0,sx,sy);
}

World::~World()
{
    destroy_bitmap(BUFFER);
    delete Vis;
}




Zone::Zone(std::string path, Resource_Manager *r )
{
    zone_layout = create_bitmap(1024,1024);
    std::ifstream load;
    load.open(path.c_str());
    if(!load.good())
    {
        rectfill(zone_layout,0,0,1024,1024,makecol(255,255,255));
    }
    else
    {
        while(!load.eof())
        {
            string temp;
            load>>temp;
            if(temp.compare("TEXTURE") == 0)
            {
                int x,y;
                load>>temp>>x>>y;
                r->Load_Texture(temp,temp);
                blit(r->Get_Texture(temp),zone_layout,0,0,x,y,r->Get_Texture(temp)->w,r->Get_Texture(temp)->h);
            }else
            if(temp.compare("WALL") == 0)
            {
                int x1,y1,x2,y2;
                load>>x1>>y1>>x2>>y2;
                Line_Segment_2D *t = new Line_Segment_2D(x1,y1,x2,y2);
                Walls.push_back(t);
            }else break;
        }
    }
}
void     Zone::Get_Zone_Walls(vector <Line_Segment_2D *> &walls)
{
    for(unsigned int i = 0;i < Walls.size();i++)
    {
        walls.push_back(Walls[i]);
    }
}
BITMAP*  Zone::Get_Zone_Bitmap()
{
    return zone_layout;
}
Zone::~Zone()
{
    destroy_bitmap(zone_layout);
}


Was This Post Helpful? 0
  • +
  • -

#6 Orami  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 22
  • Joined: 09-December 13

Re: Raycasting visibility in 2D game

Posted 10 December 2013 - 11:29 PM

I did a little tweaking of the code what was happening on the right hand side was it was checking vs points on the bounding box that surrounds the current player's area. It is kind of like a bubble that follows the player so I never check against walls that are too far away to matter. I have identified the cause of one of the glitches being that when the two points of a wall and the player's position all form a perfect line the code gets confused as to which points are visible. I am thinking I need to take both points still, but the order in which the points are put into the vector really depends on what quadrant the points lie in as in: Front Back; Back Front; Front Back; Back Front (respective to I II III IV from the origin point). Since I already have angles saved I think I can just use those to determine the quadrants and go from there. Unfortunately my code for projecting off convex angles broke during my fix for the right walls. Hopefully this brings me a little closer.

BITMAP* Visibility::Get_Visibility(int max, int x,int y, std::vector <Line_Segment_2D *> &Walls)
{

    Point_2D Ori(x,y);
    std::vector <Point_2D> Endpoints;
    rectfill(VIS_MAP,0,0,size_x,size_y,makecol(0,0,0));     //put fog of war up over everything!

    for(unsigned int i = 0;i < Walls.size();i++)        //populate Endpoints from the walls in the nearby area.
    {
        Walls[i]->DistanceToPoint(Ori);
        Endpoints.push_back(Walls[i]->A);
        Ori.Angle_In_Degrees(Endpoints[i*2]);
        Endpoints.push_back(Walls[i]->B)/>;
        Ori.Angle_In_Degrees(Endpoints[(i*2)+1]);
    }
    std::sort(Walls.begin(),Walls.end(),sortByDistance);        //sort walls by distance
    std::sort(Endpoints.begin(),Endpoints.end(),sortByAngle);   //sort vertices by angle

    std::vector <Point_2D> Final_Points;                        //container for vertices
    for(unsigned int i = 0; i < Endpoints.size();i++)
    {
        Endpoints[i].isStart = false;
        Endpoints[i].isEnd = false;
        Endpoints[i].isMulti = false;
        while(i+1 < Endpoints.size() && Endpoints[i] == Endpoints[i+1]){Endpoints.erase(Endpoints.begin()+i);Endpoints[i].isMulti = true;}   //only one of each vertex



        for(unsigned int j = 0; j < Walls.size();j++)
        {
            if(Walls[j]->A == Endpoints[i] || Walls[j]->B == Endpoints[i])
            {
                if(Walls[j]->Active == true)
                {
                    Walls[j]->Active = false;
                    Endpoints[i].isEnd = true;
                }else
                {
                    Walls[j]->Active = true;
                    Endpoints[i].isStart = true;
                }
            }
        }
        if(!PointIsVisible(Ori,Endpoints[i],Walls)) //if we can not see the point remove it from the algo
        {
            Endpoints.erase(Endpoints.begin()+i);   //can't see it?  We won't need it any more.
            i--;                                    //make sure we check the new point that is in our spot now.
        }
    }
    if(SameWall(Endpoints[0],Endpoints[Endpoints.size()-1],Walls))//if they are the same wall we know it is a special case.
    {
        if(Endpoints[0].isMulti)        //we already know it must be a start but now it is also an end.
        {
            Endpoints[0].isEnd = true;
        }else
        {
            //not multiple points then we need to project as if it is only an end point.
            Endpoints[0].isStart = false;
            Endpoints[0].isEnd = true;
        }
        if(Endpoints[Endpoints.size()-1].isMulti)
        {
            Endpoints[Endpoints.size()-1].isStart = true;
        }else
        {
            Endpoints[Endpoints.size()-1].isStart = true;
            Endpoints[Endpoints.size()-1].isEnd = false;
        }
    }
    for(unsigned int i = 0;i < Endpoints.size();i++)
    {
        if(Endpoints[i].isEnd && Endpoints[i].isStart)      //if a wall starts and ends here then it is a hard point with no projections
        {
            Final_Points.push_back(Endpoints[i]);
        }else
        {
            if(Endpoints[i].isEnd) //end has projection second
            {
                Final_Points.push_back(Endpoints[i]);
                Final_Points.push_back(Find_Projection_Intersection(Ori,Endpoints[i],Walls));
            }
            else //start has projection first
            {
                Final_Points.push_back(Find_Projection_Intersection(Ori,Endpoints[i],Walls));
                Final_Points.push_back(Endpoints[i]);
            }
        }
    }

    for(unsigned int i = 0;i + 1 < Final_Points.size();i++)
    {
        triangle(VIS_MAP,Final_Points[i].x,Final_Points[i].y,Final_Points[i+1].x,Final_Points[i+1].y,Ori.x,Ori.y,makecol(255,0,255));
        line(VIS_MAP,Final_Points[i+1].x,Final_Points[i+1].y,Final_Points[i].x,Final_Points[i].y,makecol(255,0,0));
        circlefill(VIS_MAP,Final_Points[i].x,Final_Points[i].y,5,makecol(255,255,0));
    }
    triangle(VIS_MAP,Final_Points[Final_Points.size() -1].x,Final_Points[Final_Points.size()-1].y,Final_Points[0].x,Final_Points[0].y,Ori.x,Ori.y,makecol(255,0,255));
    circlefill(VIS_MAP,Final_Points[Final_Points.size() -1].x,Final_Points[Final_Points.size() -1].y,5,makecol(255,255,0));
    
    return VIS_MAP;
}


Was This Post Helpful? 0
  • +
  • -

#7 snoopy11  Icon User is offline

  • Engineering ● Software
  • member icon

Reputation: 766
  • View blog
  • Posts: 2,227
  • Joined: 20-March 10

Re: Raycasting visibility in 2D game

Posted 11 December 2013 - 12:02 AM

Are you applying the 'all points on the line make above the line' rule.

As it does sound like you are experiencing the 'point in polygon' problem.

It is a special case of point location problems, where the ray-casting algorithm has difficulty with points on a boundary or vertex.

If you test if it is on a vertex or boundary is true then consider the point to be above the line of the ray.

Regards

Snoopy.
Was This Post Helpful? 0
  • +
  • -

#8 Orami  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 22
  • Joined: 09-December 13

Re: Raycasting visibility in 2D game

Posted 11 December 2013 - 05:47 AM

View Postsnoopy11, on 11 December 2013 - 12:02 AM, said:

Are you applying the 'all points on the line make above the line' rule.

As it does sound like you are experiencing the 'point in polygon' problem.

It is a special case of point location problems, where the ray-casting algorithm has difficulty with points on a boundary or vertex.

If you test if it is on a vertex or boundary is true then consider the point to be above the line of the ray.

Regards

Snoopy.


'all points on the line make above the line'

If I understand what you are saying, no we ignore the line because looking at it's vertex would cause a collision with the line. I have seen people use floats then subtract .0001 or something from the coordinates, but the way the code works that could sometimes extend a line, so I haven't figured out how to make it take into account for that.
Was This Post Helpful? 0
  • +
  • -

#9 snoopy11  Icon User is offline

  • Engineering ● Software
  • member icon

Reputation: 766
  • View blog
  • Posts: 2,227
  • Joined: 20-March 10

Re: Raycasting visibility in 2D game

Posted 11 December 2013 - 09:55 AM

View PostOrami, on 11 December 2013 - 12:47 PM, said:

If I understand what you are saying, no we ignore the line because looking at it's vertex would cause a collision with the line. I have seen people use floats then subtract .0001 or something from the coordinates, but the way the code works that could sometimes extend a line, so I haven't figured out how to make it take into account for that.


Right,

Say you fire off a ray and the ray's intersection point is on a vertex, then the intersection point only counts if the second vertex of the side lies below the ray.

This is effectively equivalent to considering vertices on the ray as lying slightly above the ray. If you see what I mean.

Regards

Snoopy.
Was This Post Helpful? 0
  • +
  • -

#10 Orami  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 22
  • Joined: 09-December 13

Re: Raycasting visibility in 2D game

Posted 11 December 2013 - 05:38 PM

Ah, I think my code was ignoring the entire wall from that point on. Instead I should ignore it only if the intersect is on the vertex that I am checking? Will give that a shot shouldn't be too hard.
Was This Post Helpful? 0
  • +
  • -

#11 Orami  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 22
  • Joined: 09-December 13

Re: Raycasting visibility in 2D game

Posted 12 December 2013 - 06:33 AM

That is kind of what the start and end parts of the code should do I think. If lines only start(or end) at this point as we sweep around via the angle we project through the point because it doesn't actually block the sight. I guess the best way to picture it is if we take a square. Now lets toss some coordinates in with normal numbers we can work with....
A B C D
(5,5) (7,5) (7,7) (5,7)

So we have 4 line segments now... I will call them AB BC CD DA.

So lets put the player at (8,3)

We collect all the vertices and sort them by the angle to the player.

We start our sweep on the X axis facing positive the sweep goes counter clockwise. The first vertex we see is A what we do is mark A as the start and since it is the first point for both AB and DA we set the "start" flag, and on the two line segments we set them to "active"

Now we look at point D it is the second point(since the line segment is active) it ends line DA so we set the end flag for D and starts line CD so we set start and active on the segment as well.

Now we go to point B it ends line AB and begins line BC so we set both start and end flags.

Now finally point C it ends line CD and BC so we only set end.

So we purge any points we can not see which in this case is only point D.

So when we go back over looking what points we need to just look at start and end flags.

Does this do what you were saying to do or something similar at least? I have some of the projections working, but for some reason on convex angles when it should have just two start points I end up with what I call a hard point which is a start and end flag set. The rest is in the code I can probably comment it a little heavier. I remember coming across some code that would tell if two segments overlap so I am going to search for that and then if they overlap I will just call it a intersection.
Was This Post Helpful? 0
  • +
  • -

#12 snoopy11  Icon User is offline

  • Engineering ● Software
  • member icon

Reputation: 766
  • View blog
  • Posts: 2,227
  • Joined: 20-March 10

Re: Raycasting visibility in 2D game

Posted 13 December 2013 - 02:27 AM

Well its sort of like that,

but lets go back to the beginning with a clearer example.

Do For each pixel in image {
Create ray from eyepoint passing through this pixel
Initialize NearestT to INFINITY and NearestObject to NULL

Do For every object in scene {
If ray intersects this object {
If t of intersection is less than NearestT {
Set NearestT to t of the intersection
Set NearestObject to this object
}
}
}
If NearestObject is NULL {
Fill this pixel with background color
} Else {
Shoot a ray to each light source to check if in shadow
If surface is reflective, generate reflection ray: recurse
If surface is transparent, generate refraction ray: recurse
Use NearestObject and NearestT to compute shading function
Fill this pixel with color result of shading function
   }
}



The above psuedocode is how you are supposed to do it.

you dont need the transparency or shading so it can be simplified in your case to

Do For each pixel in image {
Create ray from eyepoint passing through this pixel
Initialize NearestT to INFINITY and NearestObject to NULL

Do For every object in scene {
[u]If[/u] ray intersects this object {
If t of intersection is less than NearestT {
Set NearestT to t of the intersection
Set NearestObject to this object
}
}
}
If NearestObject is NULL {
Fill this pixel with background color
} Else {
 generate reflection ray: recurse

Fill this pixel with color result of reflection function
   }
}


Snoopy.
Was This Post Helpful? 0
  • +
  • -

#13 Orami  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 22
  • Joined: 09-December 13

Re: Raycasting visibility in 2D game

Posted 13 December 2013 - 03:36 AM

Wouldn't going via pixels be incredibly slow? I figured since really the only time things can change is at the vertices since, well I am just considering line segments since really anything can be broken into triangles why not a vision engine. I was trying to do something like this page: http://www.redblobga...les/visibility/ I feel as though I am close, but so far away lol. I was also going to use this code to do lighting as well, but I don't know shaders yet. I just don't want to go off on one tangent while working out the current problem.

The trick with sorting all the walls by distance is that when you are checking against walls the first wall you come to that you intersect is _Always_ the nearest wall of intersection. So while you are correct about casting a line to infinity (or maybe just outside our little cluster of zones.) there is a more effective way to check for the nearest wall. Maybe these two methods could mesh a little bit there...

The problem with the idea of shooting out 1000+ rays is the larger the distance out you want to scan the more rays you need. I will try to code something using just mass ray casting and see if it really hurts the FPS or not.
Was This Post Helpful? 0
  • +
  • -

#14 Orami  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 22
  • Joined: 09-December 13

Re: Raycasting visibility in 2D game

Posted 13 December 2013 - 03:55 AM

This is the code with extra comments to help make it easier to follow my train of thought. Like you said I know my code better than anyone else so I tried to think how best to describe it.

BITMAP* Visibility::Get_Visibility(int max, int x,int y, std::vector <Line_Segment_2D *> &Walls)
{

    Point_2D Ori(x,y);                                  //the player's eye point
    std::vector <Point_2D> Endpoints;                   //container for all the endpoints of the line segments
    rectfill(VIS_MAP,0,0,size_x,size_y,makecol(0,0,0)); //Set everything to black so it looks dark we blit this image over our layout later outside the function.

    for(unsigned int i = 0;i < Walls.size();i++)        //populate Endpoints from the walls in the nearby area.
    {
        Walls[i]->DistanceToPoint(Ori);                 //Figure out the distance from the walls this uses code to find the nearest point might not be the endpoint
        Endpoints.push_back(Walls[i]->A);               //add the first vertex
        Ori.Angle_In_Degrees(Endpoints[i*2]);           //calculate the angle for the first vertex
        Endpoints.push_back(Walls[i]->B)/>;               //add second vetex
        Ori.Angle_In_Degrees(Endpoints[(i*2)+1]);       //calculate the angle for the second vertex
    }
    std::sort(Walls.begin(),Walls.end(),sortByDistance);        //sort walls by distance
    std::sort(Endpoints.begin(),Endpoints.end(),sortByAngle);   //sort vertices by angle

    std::vector <Point_2D> Final_Points;                        //container for vertices that are our final points to make triangles with
    for(unsigned int i = 0; i < Endpoints.size();i++)           //start adding points
    {
        Endpoints[i].isStart = false;                           //clear our flags.
        Endpoints[i].isEnd = false;                             //
        Endpoints[i].isMulti = false;                           //
        while(i+1 < Endpoints.size() && Endpoints[i] == Endpoints[i+1]){Endpoints.erase(Endpoints.begin()+i);Endpoints[i].isMulti = true;}   //only one of each vertex purge any extras we might have.

        for(unsigned int j = 0; j < Walls.size();j++)       //go through all of our walls
        {
            if(Walls[j]->A == Endpoints[i] || Walls[j]->B == Endpoints[i])      //if the endpoint we are looking at is an endpoint to this wall
            {
                if(Walls[j]->Active == true)        //if this is the second endpoint to the wall
                {
                    Walls[j]->Active = false;       //the wall is no longer "active"
                    Endpoints[i].isEnd = true;      //the endpoint is an end to a segment from our perspective
                }else                               //if it isn't the second point it must be the first
                {
                    Walls[j]->Active = true;        //the wall still has one more point out there somewhere.
                    Endpoints[i].isStart = true;    //set the start flag
                }
            }
        }
        if(!PointIsVisible(Ori,Endpoints[i],Walls)) //if we can not see the point remove it from the list since we can not draw to a point we can not see.
        {
            Endpoints.erase(Endpoints.begin()+i);   //just removing it
            i--;                                    //make sure we check the new point that is in our spot now since the old one is gone.
        }
    }
    //this if statement is an exception to the rules.
    if(SameWall(Endpoints[0],Endpoints[Endpoints.size()-1],Walls))      //if thefirst endpoint and the last endpoint belong to the same wall
    {
        if(Endpoints[0].isMulti)        //we already know it must be a start but now it is also an end.
        {
            Endpoints[0].isEnd = true;
        }else
        {
            //not multiple points then we need to project as if it is only an end point.
            Endpoints[0].isStart = false;
            Endpoints[0].isEnd = true;
        }
        if(Endpoints[Endpoints.size()-1].isMulti)
        {
            Endpoints[Endpoints.size()-1].isStart = true;
        }else
        {
            Endpoints[Endpoints.size()-1].isStart = true;
            Endpoints[Endpoints.size()-1].isEnd = false;
        }
    }
    //ok now back to the rest of the endpoints!
    for(unsigned int i = 0;i < Endpoints.size();i++)
    {
        if(Endpoints[i].isEnd && Endpoints[i].isStart)      //if a wall starts and ends here then it is a hard point with no projections think of a concave corner
        {
            Final_Points.push_back(Endpoints[i]);           //just push it onto the stack with nothing special
        }else
        {
            if(Endpoints[i].isEnd) //end has projection second because as we pas across it the triangle must stop here then start further out for the next one
            {                      //if this was backwards we would see through walls all the time and not be able to see the open area.
                Final_Points.push_back(Endpoints[i]);
                Final_Points.push_back(Find_Projection_Intersection(Ori,Endpoints[i],Walls));
            }
            else //start has projection first
            {
                Final_Points.push_back(Find_Projection_Intersection(Ori,Endpoints[i],Walls));
                Final_Points.push_back(Endpoints[i]);
            }
        }
    }

    for(unsigned int i = 0;i + 1 < Final_Points.size();i++)//just draw triangles using our points
    {
        triangle(VIS_MAP,Final_Points[i].x,Final_Points[i].y,Final_Points[i+1].x,Final_Points[i+1].y,Ori.x,Ori.y,makecol(255,0,255));
        line(VIS_MAP,Final_Points[i+1].x,Final_Points[i+1].y,Final_Points[i].x,Final_Points[i].y,makecol(255,0,0));     //draw lines as a guide to troubleshooting to our vertices
        circlefill(VIS_MAP,Final_Points[i].x,Final_Points[i].y,5,makecol(255,255,0));                                   //put a yellow circle on the vertices as well
    }
    triangle(VIS_MAP,Final_Points[Final_Points.size() -1].x,Final_Points[Final_Points.size()-1].y,Final_Points[0].x,Final_Points[0].y,Ori.x,Ori.y,makecol(255,0,255));  //last triangle from the first point to the last point.
    circlefill(VIS_MAP,Final_Points[Final_Points.size() -1].x,Final_Points[Final_Points.size() -1].y,5,makecol(255,255,0)); //just so we don't miss this vertice
    return VIS_MAP;
}


Was This Post Helpful? 0
  • +
  • -

#15 snoopy11  Icon User is offline

  • Engineering ● Software
  • member icon

Reputation: 766
  • View blog
  • Posts: 2,227
  • Joined: 20-March 10

Re: Raycasting visibility in 2D game

Posted 14 December 2013 - 07:03 PM

Hmm,

I am not clear why you are using i*2 in your Endpoints Angle calculations

Ori.Angle_In_Degrees(Endpoints[i*2]);

why isnt it just i.

Also I am going to post a very simple raycaster written in direct2d, which illustrates my ideas. Those are shoot rays in 360 deg if hit wall draw wall block on grid boundary. All walls must lie on grid boundaries. Needs windows 7 sdk and directx sdk. for visual studio.

resource.rc


#include <Windows.h>


//Level One Images
sprite  Image  "sprite.png"

//end Level One Images



#include <Windows.h>


//Level One Images
sprite  Image  "sprite.png"

//end Level One Images




Essentials.h


#ifndef ESSENTIALS_H_INCLUDED
#define ESSENTIALS_H_INCLUDED
#define WIN32_LEAN_AND_MEAN     // Exclude rarely-used stuff from Windows headers
// Windows Header Files:
#include <windows.h>

// C RunTime Header Files
#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include <wchar.h>
#include <math.h>
#include <sstream>
#include <string>
#include <d2d1.h>
#include <d2d1helper.h>
#include <dwrite.h>
#include <wincodec.h>

/******************************************************************
*                                                                 *
*  Macros                                                         *
*                                                                 *
******************************************************************/

template<class Interface>
inline void
SafeRelease(
    Interface **ppInterfaceToRelease
    )
{
    if (*ppInterfaceToRelease != NULL)
    {
        (*ppInterfaceToRelease)->Release();

        (*ppInterfaceToRelease) = NULL;
    }
}

#ifndef Assert
#if defined( DEBUG ) || defined( _DEBUG )
#define Assert(B)/>/> do {if (!(B)/>/>) {OutputDebugStringA("Assert: " #b "\n");}} while(0)
#else
#define Assert(B)/>/>
#endif //DEBUG || _DEBUG
#endif


#ifndef HINST_THISCOMPONENT
EXTERN_C IMAGE_DOS_HEADER __ImageBase;
#define HINST_THISCOMPONENT ((HINSTANCE)&__ImageBase)
#endif 

#endif


levelone.h

//LevelOne.h
#ifndef LEVELONE_H_INCLUDED
#define LEVELONE_H_INCLUDED


#pragma once

// Modify the following defines if you have to target a platform prior to the ones specified below.
// Refer to MSDN for the latest info on corresponding values for different platforms.
#ifndef WINVER              // Allow use of features specific to Windows 7 or later.
#define WINVER 0x0700       // Change this to the appropriate value to target other versions of Windows.
#endif

#ifndef _WIN32_WINNT        // Allow use of features specific to Windows 7 or later.
#define _WIN32_WINNT 0x0700 // Change this to the appropriate value to target other versions of Windows.
#endif

#ifndef UNICODE
#define UNICODE
#endif

#pragma once

#include "Essentials.h"

#endif
class LevelOne
{
public:
    LevelOne();
    ~LevelOne();

    




    
float Gamex;
float Gamey;
int blockWidth;
int direction;
float radius;
float twopi; 

int  P[819][460];


    HRESULT CreateDeviceIndependentResources();
    HRESULT CreateDeviceResources(HWND hwnd);
	HRESULT Initialize(HWND hwnd,int Score, int Lives);
   
	void GameLoop();
	void IlluminateArea(float a, float B)/>/>;
    void DiscardDeviceResources();
	void Move(int x, int y);
	void InitGameOver();
    HRESULT OnRender(HWND hwnd);

    

    

    HRESULT LoadResourceBitmap(
        ID2D1RenderTarget *pRenderTarget,
        IWICImagingFactory *pIWICFactory,
        PCWSTR resourceName,
        PCWSTR resourceType,
        UINT destinationWidth,
        UINT destinationHeight,
        ID2D1Bitmap **ppBitmap
        );

    

	// Direct2d
    HWND m_hwnd;
    ID2D1Factory *m_pD2DFactory;
    IWICImagingFactory *m_pWICFactory;
    IDWriteFactory *m_pDWriteFactory;
    ID2D1HwndRenderTarget *m_pRenderTarget;
	ID2D1SolidColorBrush* pYellowBrush;
	ID2D1SolidColorBrush* pLightGreenBrush;
	ID2D1SolidColorBrush* pWhiteBrush;
	ID2D1SolidColorBrush* pGreenBrush;
    // DirectWrite
    IDWriteFactory* pDWriteFactory_;
    IDWriteTextFormat* pTextFormat_;
	HRESULT DrawScore();
    std::wstring wszText_;
	std::wstringstream ScoreText;
    UINT32 cTextLength_;
	ID2D1PathGeometry* m_pTriangles;
	ID2D1Bitmap *m_pBitmap;
    
private:
	int counter1;
    int counter2;
	
	BOOL spacebar;
};

     


levelone.cpp

//levelone.cpp

#include "levelone.h"



LevelOne::LevelOne() :


m_hwnd(NULL),
	m_pD2DFactory(NULL),
	m_pWICFactory(NULL),
	m_pDWriteFactory(NULL),
	m_pRenderTarget(NULL)
	
{

	Gamex=150;
	Gamey=150;
	blockWidth =20;
	radius =100;
	twopi= 3.14159*2;
	direction =2;
	//create maze block
	for(int i=200;i<300;i++)
	{
		for(int j=200;j<300;j++)
		{
		P[i][j]=1;
	    
		}
	}
	for(int i=200;i<300;i++)
	{
		for(int j=20;j<120;j++)
		{
		P[i][j]=1;
	    
		}
	}

	for(int i=400;i<500;i++)
	{
		for(int j=20;j<120;j++)
		{
		P[i][j]=1;
	    
		}
	}
    for(int i=400;i<500;i++)
	{
		for(int j=200;j<300;j++)
		{
		P[i][j]=1;
	    
		}
	}
}

LevelOne::~LevelOne()
{
	
	SafeRelease(&m_pD2DFactory);
	SafeRelease(&m_pWICFactory);
	SafeRelease(&m_pDWriteFactory);
	SafeRelease(&m_pRenderTarget);
	
	SafeRelease(&pYellowBrush);
	SafeRelease(&pWhiteBrush);
	SafeRelease(&pGreenBrush);
	SafeRelease(&pDWriteFactory_);
	SafeRelease(&pTextFormat_);
	
}

void LevelOne::Move(int x, int y)
{
	Gamex = Gamex+x;
	Gamey = Gamey+y;

}

//
// Creates a Direct2D bitmap from a resource in the
// application resource file.
//
HRESULT LevelOne::LoadResourceBitmap(
	ID2D1RenderTarget *pRenderTarget,
	IWICImagingFactory *pIWICFactory,
	PCWSTR resourceName,
	PCWSTR resourceType,
	UINT destinationWidth,
	UINT destinationHeight,
	ID2D1Bitmap **ppBitmap
	)
{
	IWICBitmapDecoder *pDecoder = NULL;
	IWICBitmapFrameDecode *pSource = NULL;
	IWICStream *pStream = NULL;
	IWICFormatConverter *pConverter = NULL;
	IWICBitmapScaler *pScaler = NULL;

	HRSRC imageResHandle = NULL;
	HGLOBAL imageResDataHandle = NULL;
	void *pImageFile = NULL;
	DWORD imageFileSize = 0;

	// Locate the resource.
	imageResHandle = FindResourceW(HINST_THISCOMPONENT, resourceName, resourceType);
	HRESULT hr = imageResHandle ? S_OK : E_FAIL;
	if (SUCCEEDED(hr))
	{
		// Load the resource.
		imageResDataHandle = LoadResource(HINST_THISCOMPONENT, imageResHandle);

		hr = imageResDataHandle ? S_OK : E_FAIL;
	}
	if (SUCCEEDED(hr))
	{
		// Lock it to get a system memory pointer.
		pImageFile = LockResource(imageResDataHandle);

		hr = pImageFile ? S_OK : E_FAIL;
	}
	if (SUCCEEDED(hr))
	{
		// Calculate the size.
		imageFileSize = SizeofResource(HINST_THISCOMPONENT, imageResHandle);

		hr = imageFileSize ? S_OK : E_FAIL;

	}
	if (SUCCEEDED(hr))
	{
		// Create a WIC stream to map onto the memory.
		hr = pIWICFactory->CreateStream(&pStream);
	}
	if (SUCCEEDED(hr))
	{
		// Initialize the stream with the memory pointer and size.
		hr = pStream->InitializeFromMemory(
			reinterpret_cast<BYTE*>(pImageFile),
			imageFileSize
			);
	}
	if (SUCCEEDED(hr))
	{
		// Create a decoder for the stream.
		hr = pIWICFactory->CreateDecoderFromStream(
			pStream,
			NULL,
			WICDecodeMetadataCacheonload,
			&pDecoder
			);
	}
	if (SUCCEEDED(hr))
	{
		// Create the initial frame.
		hr = pDecoder->GetFrame(0, &pSource);
	}
	if (SUCCEEDED(hr))
	{
		// Convert the image format to 32bppPBGRA
		// (DXGI_FORMAT_B8G8R8A8_UNORM + D2D1_ALPHA_MODE_PREMULTIPLIED).
		hr = pIWICFactory->CreateFormatConverter(&pConverter);
	}
	if (SUCCEEDED(hr))
	{
		// If a new width or height was specified, create an
		// IWICBitmapScaler and use it to resize the image.
		if (destinationWidth != 0 || destinationHeight != 0)
		{
			UINT originalWidth, originalHeight;
			hr = pSource->GetSize(&originalWidth, &originalHeight);
			if (SUCCEEDED(hr))
			{
				if (destinationWidth == 0)
				{
					FLOAT scalar = static_cast<FLOAT>(destinationHeight) / static_cast<FLOAT>(originalHeight);
					destinationWidth = static_cast<UINT>(scalar * static_cast<FLOAT>(originalWidth));
				}
				else if (destinationHeight == 0)
				{
					FLOAT scalar = static_cast<FLOAT>(destinationWidth) / static_cast<FLOAT>(originalWidth);
					destinationHeight = static_cast<UINT>(scalar * static_cast<FLOAT>(originalHeight));
				}

				hr = pIWICFactory->CreateBitmapScaler(&pScaler);
				if (SUCCEEDED(hr))
				{
					hr = pScaler->Initialize(
						pSource,
						destinationWidth,
						destinationHeight,
						WICBitmapInterpolationModeCubic
						);
					if (SUCCEEDED(hr))
					{
						hr = pConverter->Initialize(
							pScaler,
							GUID_WICPixelFormat32bppPBGRA,
							WICBitmapDitherTypeNone,
							NULL,
							0.f,
							WICBitmapPaletteTypeMedianCut
							);
					}
				}
			}
		}
		else
		{

			hr = pConverter->Initialize(
				pSource,
				GUID_WICPixelFormat32bppPBGRA,
				WICBitmapDitherTypeNone,
				NULL,
				0.f,
				WICBitmapPaletteTypeMedianCut
				);
		}
	}
	if (SUCCEEDED(hr))
	{
		//create a Direct2D bitmap from the WIC bitmap.
		hr = pRenderTarget->CreateBitmapFromWicBitmap(
			pConverter,
			NULL,
			ppBitmap
			);

	}

	SafeRelease(&pDecoder);
	SafeRelease(&pSource);
	SafeRelease(&pStream);
	SafeRelease(&pConverter);
	SafeRelease(&pScaler);

	return hr;
}




HRESULT LevelOne::CreateDeviceIndependentResources()
{


	// Create a Direct2D factory.

	HRESULT hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &m_pD2DFactory);


	if (SUCCEEDED(hr))
	{
		// Create WIC factory.
		hr = CoCreateInstance(
			CLSID_WICImagingFactory,
			NULL,
			CLSCTX_INPROC_SERVER,
			IID_PPV_ARGS(&m_pWICFactory)
			);

	}
	// Create a shared DirectWrite factory.
	if (SUCCEEDED(hr))
	{
		hr = DWriteCreateFactory(
			DWRITE_FACTORY_TYPE_SHARED,
			__uuidof(IDWriteFactory),
			reinterpret_cast<IUnknown**>(&pDWriteFactory_)
			);
	}



	// Create a text format using Sans serif with a font size of 22.
	// This sets the default font, weight, stretch, style, and locale.
	if (SUCCEEDED(hr))
	{
		hr = pDWriteFactory_->CreateTextFormat(
			L"Arial",                // Font family name.
			NULL,                       // Font collection (NULL sets it to use the system font collection).
			DWRITE_FONT_WEIGHT_BOLD,
			DWRITE_FONT_STYLE_NORMAL,
			DWRITE_FONT_STRETCH_NORMAL,
			18.0f,
			L"en-us",
			&pTextFormat_
			);
	}

	// Center align (horizontally) the text.
	if (SUCCEEDED(hr))
	{
		hr = pTextFormat_->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER);
	}

	if (SUCCEEDED(hr))
	{
		hr = pTextFormat_->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER);
	}


	return hr;
}



HRESULT LevelOne::CreateDeviceResources(HWND hwnd)
{
	HRESULT hr = S_OK;

	
		RECT rc;
		GetClientRect(hwnd, &rc);
		float dpix, dpiy;
		m_pD2DFactory->GetDesktopDpi(&dpix,&dpiy);
		D2D1_SIZE_U size = D2D1::SizeU(
			(UINT32)(rc.right),
			(UINT32)(rc.bottom)
			);

		// Create a Direct2D render target.
		hr = m_pD2DFactory->CreateHwndRenderTarget(
			D2D1::RenderTargetProperties(),
			D2D1::HwndRenderTargetProperties(hwnd, size),
			&m_pRenderTarget
			);
		
		// Create a yellow brush.
		if (SUCCEEDED(hr))
		{
			hr = m_pRenderTarget->CreateSolidColorBrush(
				D2D1::ColorF(D2D1::ColorF::Yellow),
				&pYellowBrush
				);
		}

		// Create a green brush.
		if (SUCCEEDED(hr))
		{
			hr = m_pRenderTarget->CreateSolidColorBrush(
				D2D1::ColorF(D2D1::ColorF::OliveDrab),
				&pGreenBrush
				);
		}
		// Create a light green brush.
		if (SUCCEEDED(hr))
		{
			hr = m_pRenderTarget->CreateSolidColorBrush(
				D2D1::ColorF(D2D1::ColorF::Green),
				&pLightGreenBrush
				);
		}
		 if (SUCCEEDED(hr))
        {
            // Create a White brush.
            hr = m_pRenderTarget->CreateSolidColorBrush(
                D2D1::ColorF(D2D1::ColorF::White),
                &pWhiteBrush
                );
        }



		// Create a sprite from an application resource.
		hr = LoadResourceBitmap(
			m_pRenderTarget,
			m_pWICFactory,
			L"sprite",
			L"Image",
			0,
			0,
			&m_pBitmap
			);
		
		
		
	

	return hr;
}
HRESULT LevelOne::DrawScore()
{


	// Create a D2D rect that is the same size as the window.
	D2D1_RECT_F layoutRect = D2D1::RectF(
		0.0f,
		12.0f,
		143.0f,
		18.0f
		);

	// Use the DrawText method of the D2D render target interface to draw.
	m_pRenderTarget->DrawText(
		wszText_.c_str(),        // The string to render.
		cTextLength_,    // The string's length.
		pTextFormat_,    // The text format.
		layoutRect,       // The region of the window where the text will be rendered.
		pYellowBrush     // The brush used to draw the text.
		);

	return S_OK;
}

HRESULT LevelOne::OnRender(HWND hwnd)
{
	HRESULT hr = S_OK;

	    RECT rc;
		GetClientRect(hwnd, &rc);
		float dpix, dpiy;
		m_pD2DFactory->GetDesktopDpi(&dpix,&dpiy);
		



	if (SUCCEEDED(hr))
	{

		D2D1_SIZE_F renderTargetSize = m_pRenderTarget->GetSize();

		m_pRenderTarget->BeginDraw();


		m_pRenderTarget->Clear(D2D1::ColorF(D2D1::ColorF::Black));



		D2D1_SIZE_F size = m_pBitmap->GetSize();

		

		//Draw the Score
		ScoreText.str(L"");
		wszText_= L"";
		ScoreText<< L"Score: " ;

		//draw lives and Score
		wszText_= ScoreText.str();
		cTextLength_ = (UINT32)wszText_.length();
		DrawScore();

	    D2D1_SIZE_F rtSize = m_pRenderTarget->GetSize();
		// Draw a grid background.
        int width = static_cast<int>(rtSize.width);
        int height = static_cast<int>(rtSize.height);

		for (int x = 0; x < width; x += blockWidth)
        {
            m_pRenderTarget->DrawLine(
                D2D1::Point2F(static_cast<FLOAT>(x), 0.0f),
                D2D1::Point2F(static_cast<FLOAT>(x), rtSize.height),
                pWhiteBrush,
                0.5f
                );
        }

        for (int y = 0; y < height; y += blockWidth)
        {
            m_pRenderTarget->DrawLine(
                D2D1::Point2F(0.0f, static_cast<FLOAT>(y)),
                D2D1::Point2F(rtSize.width, static_cast<FLOAT>(y)),
                pWhiteBrush,
                0.5f
                );
        }

		//Illuminate
		IlluminateArea(Gamex+(size.width/2), Gamey+(size.height/2));

		// Draw a sprite in the window.
		m_pRenderTarget->DrawBitmap(
			m_pBitmap,
			D2D1::RectF(Gamex,Gamey,  size.width+Gamex, size.height+Gamey)
			);

		hr = m_pRenderTarget->EndDraw();
			// end draw/rendering..
			if (hr == D2DERR_RECREATE_TARGET)
			{
				hr = S_OK;
				DiscardDeviceResources();
			}
		}



		return hr;
	}         

	

	void LevelOne::DiscardDeviceResources()
	{
		
		SafeRelease(&m_pD2DFactory);
		SafeRelease(&m_pWICFactory);
		SafeRelease(&m_pDWriteFactory);
		SafeRelease(&m_pRenderTarget);
		SafeRelease(&m_pBitmap);
		SafeRelease(&pYellowBrush);
	    SafeRelease(&pWhiteBrush);
	    SafeRelease(&pGreenBrush);
		SafeRelease(&pDWriteFactory_);
		SafeRelease(&pTextFormat_);
		
	}

	HRESULT LevelOne::Initialize(HWND hwnd, int Score, int Lives)
	{

		// Initialize device-indpendent resources, such
		// as the Direct2D factory.
		m_hwnd  =  hwnd;
		CreateDeviceIndependentResources();
		HRESULT hr = CreateDeviceResources(hwnd);
		
		
		return hr;


	}

	void LevelOne::IlluminateArea(float a, float B)/>/>

	{
	    
		//begin  firing off  rays in  360 degrees
		for(float t = 0.0f; t<=twopi; t=t+(twopi/360))
		{
		//calcs
		float x = a+(radius*cos(t));//end of ray
		float y = b+(radius*sin(t));//end of ray
		float slope = (y-B)/>/>/(x-a);
		float intercept = y - (slope * x);

		

	    
	
	    D2D_POINT_2F pnt, pnt2, pnt3;
		pnt.x  =x;
		pnt.y  =y;
		pnt2.x =a;
		pnt2.y =b;
		bool reflect = false;		
		float yy =0;
		
		
		m_pRenderTarget->DrawLine(pnt,pnt2,pYellowBrush,0.1f,NULL);
		// calculate reflected rays along line and put a block down if reflected
	    if(a<x)
		{
		for(float xx = a; xx < x; xx=xx+0.05)//step  in 0.05 for better resolution
		{
			yy =  (slope*xx)+intercept;

			if(P[(int)xx][(int)yy]==1)
			{
              reflect  =  true;
			  pnt3.x = xx;
			  pnt3.y = yy;
			  break;
			}

           
		}
		
		//if  reflected draw block
		if(reflect)
		{
			D2D1_RECT_F Rect;
			
			Rect.left =   pnt3.x;
			Rect.top  =   pnt3.y;
			Rect.right =  pnt3.x+blockWidth;
			Rect.bottom = pnt3.y+blockWidth;
			m_pRenderTarget->FillRectangle(&Rect,pGreenBrush);
			
		
		}
		}

		if(x<a)
		{
		for(float xx = a; xx > x; xx=xx-0.05)
		{
			
             yy =  (slope*xx)+intercept;
			if(P[(int)xx][(int)yy]==1)
			{
              reflect  =  true;
			  pnt3.x = xx;
			  pnt3.y = yy;
			  break;
			}
			
           
		}
		
		//if reflected draw block
		if(reflect)
		{
			D2D1_RECT_F Rect;
			
			Rect.left =   pnt3.x;
			Rect.top  =   pnt3.y;
			Rect.right =  pnt3.x+blockWidth;
			Rect.bottom = pnt3.y+blockWidth;
			m_pRenderTarget->FillRectangle(&Rect,pGreenBrush);
			
		
		}
		}
		
		

		}
		
	 
	}

	



main.cpp

#include "levelone.h"
#pragma comment(lib,"WinMM.lib")
#pragma message("linking with Microsoft's Multimedia library ...")
#pragma comment(lib,"d2d1.lib")
#pragma message("linking with Microsoft's Direct 2d library ...")
#pragma comment(lib,"dwrite.lib")
#pragma message("linking with Microsoft's Direct Write library ...")
#pragma comment(lib,"windowscodecs.lib")
#pragma message("linking with Microsoft's Codecs library ...")
#pragma comment(lib,"dxgi.lib")
#pragma message("linking with Microsoft's Direct X library ...")
#pragma comment(lib, "dsound.lib")
#pragma message("linking with Microsoft's DirectSound library ...")
#pragma comment(lib, "d3d10_1.lib")
#pragma message("linking with Microsoft's Direct3d library ...")



LevelOne level;



/*  Declare Windows procedure  */
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);


int WINAPI WinMain (HINSTANCE hThisInstance,
	HINSTANCE hPrevInstance,
	LPSTR lpszArgument,
	int nCmdShow)
{
	HWND hwnd;               /* This is the handle for our window */
	MSG msg;            /* Here messages to the application are saved */
	/* Data structure for the windowclass */
	HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0);
	CoInitialize(NULL);
	HRESULT hr = level.CreateDeviceIndependentResources();
	if (SUCCEEDED(hr))
	{
		// Register the window class.
		WNDCLASSEX wcex = { sizeof(wcex) };
		wcex.style         = CS_HREDRAW | CS_VREDRAW;
		wcex.lpfnWndProc   = WindowProcedure;
		wcex.cbWndExtra    = sizeof(LONG_PTR);
		wcex.hInstance     = HINST_THISCOMPONENT;
		wcex.hCursor       = LoadCursor(NULL, IDC_ARROW);
		wcex.lpszClassName = L"D2DGame";

		RegisterClassEx(&wcex);

		// Create the application window.
		//
		// Because the CreateWindow function takes its size in pixels, we
		// obtain the system DPI and use it to scale the window size.
		FLOAT dpiX, dpiY;
		level.m_pD2DFactory->GetDesktopDpi(&dpiX, &dpiY);

		// Create the application window.
		hwnd = CreateWindowEx(
			NULL,
			L"D2DGame",
			L"RayCaster",
			WS_OVERLAPPEDWINDOW,
			CW_USEDEFAULT,
			CW_USEDEFAULT,
			819,
			460,
			NULL,
			NULL,
			HINST_THISCOMPONENT,
			NULL
			);
		hr = hwnd ? S_OK : E_FAIL;

		if (SUCCEEDED(hr))
		{
			
			
			ShowWindow(hwnd, SW_MAXIMIZE);
			SetWindowPos(hwnd,HWND_TOP,275,150,819,460,SWP_SHOWWINDOW);
			UpdateWindow(hwnd);
			level.Initialize(hwnd,0,3);
			/* Make the window visible on the screen */
		}






	}





	//



	/* Run the message loop. It will run until GetMessage() returns 0 */
	//message pump
	while(1)	
	{



		//look for a message
		if(PeekMessage(&msg,NULL,0,0,PM_REMOVE|PM_NOYIELD))
		{
			//there is a message

			//check that we arent quitting
			if(msg.message==WM_QUIT) 
				break;

			//translate message
			TranslateMessage(&msg);

			//dispatch message
			DispatchMessage(&msg);

		}

		
		
	}
	/* The program return-value is 0 - The value that PostQuitMessage() gave */
	return msg.wParam;

}


/*  This function is called by the Windows function DispatchMessage()  */

LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{

	switch (message)
	{	

	

	case WM_KEYDOWN:
		{
			
			if(wParam==VK_RIGHT)
			{
				level.Move(10,0);
				if(level.P[(int)level.Gamex+10][(int)level.Gamey]==1)
                level.Move(-10,0);
			}
			if(wParam==VK_LEFT)
			{
				level.Move(-10,0);
			    if(level.P[(int)level.Gamex-10][(int)level.Gamey]==1)
                level.Move(10,0);
			}
			if(wParam==VK_UP)
			{
				level.Move(0,-10);
			    if(level.P[(int)level.Gamex][(int)level.Gamey-10]==1)
                level.Move(0,10);
			}
			if(wParam==VK_DOWN)
			{
				level.Move(0,10);
			    if(level.P[(int)level.Gamex][(int)level.Gamey+10]==1)
                level.Move(0,-10);
			}
			InvalidateRect(hwnd,NULL,false);
			break;
		}

	case WM_PAINT://the window needs repainting
		{
			
			  level.OnRender(hwnd);
			
			break ;
		}




	case WM_DESTROY:
		
		
		
		level.DiscardDeviceResources();
		
		CoUninitialize();
		

		PostQuitMessage (0);       /* send a WM_QUIT to the message queue */
		break;
	default:                      /* for messages that we don't deal with */
		return DefWindowProc (hwnd, message, wParam, lParam);
	}


	return 0;
}






I am not asking you to post your entire game just a small complete program which illustrates your problem. Right now its very difficult to understand whats going wrong, without getting a handle on it.

I have attached a sprite.png

Regards
Snoopy.

Attached image(s)

  • Attached Image

Was This Post Helpful? 0
  • +
  • -

  • (2 Pages)
  • +
  • 1
  • 2