├── screenshot.PNG ├── RaycastEngine ├── Icon.ico ├── Content │ ├── Textures │ │ ├── floor.png │ │ ├── sky.png │ │ ├── stone.png │ │ ├── wood.png │ │ ├── left_bot_house.png │ │ ├── left_top_house.png │ │ ├── right_bot_house.png │ │ └── right_top_house.png │ ├── Effects │ │ └── SpriteCuller.fx │ └── Content.mgcb ├── Program.cs ├── Raycaster │ ├── TextureHandler.cs │ ├── Map.cs │ └── Camera.cs ├── Properties │ └── AssemblyInfo.cs ├── app.manifest ├── RaycastEngine.csproj └── MainGame.cs ├── README.md ├── RaycastEngine.sln ├── .gitattributes └── .gitignore /screenshot.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Owlzy/OwlRaycastEngine/HEAD/screenshot.PNG -------------------------------------------------------------------------------- /RaycastEngine/Icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Owlzy/OwlRaycastEngine/HEAD/RaycastEngine/Icon.ico -------------------------------------------------------------------------------- /RaycastEngine/Content/Textures/floor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Owlzy/OwlRaycastEngine/HEAD/RaycastEngine/Content/Textures/floor.png -------------------------------------------------------------------------------- /RaycastEngine/Content/Textures/sky.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Owlzy/OwlRaycastEngine/HEAD/RaycastEngine/Content/Textures/sky.png -------------------------------------------------------------------------------- /RaycastEngine/Content/Textures/stone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Owlzy/OwlRaycastEngine/HEAD/RaycastEngine/Content/Textures/stone.png -------------------------------------------------------------------------------- /RaycastEngine/Content/Textures/wood.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Owlzy/OwlRaycastEngine/HEAD/RaycastEngine/Content/Textures/wood.png -------------------------------------------------------------------------------- /RaycastEngine/Content/Textures/left_bot_house.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Owlzy/OwlRaycastEngine/HEAD/RaycastEngine/Content/Textures/left_bot_house.png -------------------------------------------------------------------------------- /RaycastEngine/Content/Textures/left_top_house.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Owlzy/OwlRaycastEngine/HEAD/RaycastEngine/Content/Textures/left_top_house.png -------------------------------------------------------------------------------- /RaycastEngine/Content/Textures/right_bot_house.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Owlzy/OwlRaycastEngine/HEAD/RaycastEngine/Content/Textures/right_bot_house.png -------------------------------------------------------------------------------- /RaycastEngine/Content/Textures/right_top_house.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Owlzy/OwlRaycastEngine/HEAD/RaycastEngine/Content/Textures/right_top_house.png -------------------------------------------------------------------------------- /RaycastEngine/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace RaycastEngine 4 | { 5 | #if WINDOWS || LINUX 6 | /// 7 | /// The main class. 8 | /// 9 | public static class Program 10 | { 11 | /// 12 | /// The main entry point for the application. 13 | /// 14 | [STAThread] 15 | static void Main() 16 | { 17 | using (var game = new MainGame()) 18 | game.Run(); 19 | } 20 | } 21 | #endif 22 | } 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # OwlRaycastEngine 2 | Basic MonoGame raycast engine 3 | 4 | Provides a few simple classses to raycast a pseudo 3D world. 5 | 6 | Largely built around the same tutorial everyone uses:- 7 | http://lodev.org/cgtutor/raycasting.html 8 | 9 | Moved accross to use modern drawing methods with a bit of OOP to keep things neater. 10 | Would provide a nice start to anyone wanting to build this kind of engine. 11 | 12 | Also includes the ability to renderer multiple levels. 13 | 14 | A good exercise if wanted to extend the engine would be to implement binary space partioning to improve performance. 15 | Currently walls on other levels that are not visible are actually getting rendered behind those you can see! 16 | 17 | Sprite casting is part implemented, and I will likely add this shortly. Other than that I will clean up the code in parts, but will leave it to the community 18 | if anyone is intrestred in improving it. 19 | 20 | ![alt text](https://github.com/Owlzy/OwlRaycastEngine/blob/master/screenshot.PNG?raw=true) 21 | 22 | https://www.youtube.com/watch?v=mX6k5XAzS8E&feature=emb_title - Youtube video. 23 | -------------------------------------------------------------------------------- /RaycastEngine/Raycaster/TextureHandler.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Owain Bell - 2017 3 | * */ 4 | using Microsoft.Xna.Framework; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | using System.Text; 9 | using System.Threading.Tasks; 10 | 11 | /** 12 | * Class splits textures into frames among other things 13 | */ 14 | namespace RaycastEngine 15 | { 16 | class TextureHandler 17 | { 18 | //--store our "slice" rects--// 19 | Rectangle[] slices; 20 | 21 | public TextureHandler(int texWidth) 22 | { 23 | //--init array--// 24 | slices = new Rectangle[texWidth]; 25 | 26 | //--for clarity in slice loop--// 27 | int texHeight = texWidth; 28 | 29 | //--loop through creating a "slice" for each texture x--// 30 | for (int x = 0; x < texWidth; x++) 31 | { 32 | //tex width and height are always equal so safe to use tex width instead of height here 33 | slices[x] = new Rectangle(x, 0, 1, texHeight); 34 | } 35 | } 36 | 37 | public Rectangle[] getSlices() 38 | { 39 | return slices; 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /RaycastEngine.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26730.15 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RaycastEngine", "RaycastEngine\RaycastEngine.csproj", "{42B8E572-3206-4CD7-B229-4CE9E446E305}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{D5FDD3F2-05CB-40F9-A0EE-EB3A69A56AE5}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|x86 = Debug|x86 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {42B8E572-3206-4CD7-B229-4CE9E446E305}.Debug|x86.ActiveCfg = Debug|x86 17 | {42B8E572-3206-4CD7-B229-4CE9E446E305}.Debug|x86.Build.0 = Debug|x86 18 | {42B8E572-3206-4CD7-B229-4CE9E446E305}.Release|x86.ActiveCfg = Release|x86 19 | {42B8E572-3206-4CD7-B229-4CE9E446E305}.Release|x86.Build.0 = Release|x86 20 | EndGlobalSection 21 | GlobalSection(SolutionProperties) = preSolution 22 | HideSolutionNode = FALSE 23 | EndGlobalSection 24 | GlobalSection(ExtensibilityGlobals) = postSolution 25 | SolutionGuid = {D67DDDC1-E8E1-401F-BAE8-95D4CBA415BE} 26 | EndGlobalSection 27 | EndGlobal 28 | -------------------------------------------------------------------------------- /RaycastEngine/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("RaycastEngine")] 9 | [assembly: AssemblyProduct("RaycastEngine")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyDescription("")] 12 | [assembly: AssemblyCompany("")] 13 | [assembly: AssemblyCopyright("Copyright © 2017")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("04c508b8-e41d-477a-b74d-f7e18e7bbef1")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /RaycastEngine/Content/Effects/SpriteCuller.fx: -------------------------------------------------------------------------------- 1 | /** 2 | * Owain Bell - 2017 3 | * */ 4 | #if OPENGL 5 | #define SV_POSITION POSITION 6 | #define VS_SHADERMODEL vs_3_0 7 | #define PS_SHADERMODEL ps_3_0 8 | #else 9 | #define VS_SHADERMODEL vs_4_0_level_9_1 10 | #define PS_SHADERMODEL ps_4_0_level_9_1 11 | #endif 12 | 13 | uniform float startXScreen; 14 | uniform float endX; 15 | uniform float viewWidth; 16 | 17 | matrix WorldViewProjection; 18 | 19 | struct VertexShaderInput 20 | { 21 | float4 Position : POSITION0; 22 | float4 Color : COLOR0; 23 | }; 24 | 25 | struct VertexShaderOutput 26 | { 27 | float4 Position : SV_POSITION; 28 | float4 Color : COLOR0; 29 | float2 ScreenPosition : TEXCOORD0; 30 | }; 31 | 32 | VertexShaderOutput MainVS(in VertexShaderInput input) 33 | { 34 | VertexShaderOutput output = (VertexShaderOutput)0; 35 | 36 | output.Position = mul(input.Position, WorldViewProjection); 37 | output.Color = input.Color; 38 | output.ScreenPosition = output.Position.xy / output.Position.w; 39 | 40 | return output; 41 | } 42 | 43 | float4 main(VertexShaderOutput input) : COLOR0 44 | { 45 | /* 46 | // float2 scCoord = input.Position.xy / input.Position.w; 47 | float2 tCoord = (scCoord + 1.0f) / 2.0f;//tex coord 48 | tCoord.y = 1.0f - tCoord.y;//-- 49 | 50 | float2 pixel = tCoord * viewWidth; 51 | 52 | clip(startX - pixel.x); 53 | */ 54 | if (input.ScreenPosition.x < startXScreen) 55 | return 0; 56 | return input.Color; 57 | } 58 | 59 | technique BasicColorDrawing 60 | { 61 | pass P0 62 | { 63 | VertexShader = compile vs_4_0 MainVS(); 64 | PixelShader = compile ps_4_0 main(); 65 | } 66 | }; -------------------------------------------------------------------------------- /RaycastEngine/app.manifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | true/pm 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /RaycastEngine/RaycastEngine.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | x86 7 | 8.0.30703 8 | 2.0 9 | {42B8E572-3206-4CD7-B229-4CE9E446E305} 10 | WinExe 11 | Properties 12 | RaycastEngine 13 | RaycastEngine 14 | 512 15 | Windows 16 | v4.5 17 | 18 | 19 | x86 20 | true 21 | full 22 | false 23 | bin\$(MonoGamePlatform)\$(Platform)\$(Configuration)\ 24 | DEBUG;TRACE;WINDOWS 25 | prompt 26 | 4 27 | 28 | 29 | x86 30 | pdbonly 31 | true 32 | bin\$(MonoGamePlatform)\$(Platform)\$(Configuration)\ 33 | TRACE;WINDOWS 34 | prompt 35 | 4 36 | 37 | 38 | Icon.ico 39 | 40 | 41 | app.manifest 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | $(MonoGameInstallDirectory)\MonoGame\v3.0\Assemblies\Windows\MonoGame.Framework.dll 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 74 | -------------------------------------------------------------------------------- /RaycastEngine/Content/Content.mgcb: -------------------------------------------------------------------------------- 1 | 2 | #----------------------------- Global Properties ----------------------------# 3 | 4 | /outputDir:bin/$(Platform) 5 | /intermediateDir:obj/$(Platform) 6 | /platform:Windows 7 | /config: 8 | /profile:Reach 9 | /compress:False 10 | 11 | #-------------------------------- References --------------------------------# 12 | 13 | 14 | #---------------------------------- Content ---------------------------------# 15 | 16 | #begin Effects/SpriteCuller.fx 17 | /importer:EffectImporter 18 | /processor:EffectProcessor 19 | /processorParam:DebugMode=Auto 20 | /build:Effects/SpriteCuller.fx 21 | 22 | #begin Textures/floor.png 23 | /importer:TextureImporter 24 | /processor:TextureProcessor 25 | /processorParam:ColorKeyColor=255,0,255,255 26 | /processorParam:ColorKeyEnabled=True 27 | /processorParam:GenerateMipmaps=False 28 | /processorParam:PremultiplyAlpha=True 29 | /processorParam:ResizeToPowerOfTwo=False 30 | /processorParam:MakeSquare=False 31 | /processorParam:TextureFormat=Color 32 | /build:Textures/floor.png 33 | 34 | #begin Textures/left_bot_house.png 35 | /importer:TextureImporter 36 | /processor:TextureProcessor 37 | /processorParam:ColorKeyColor=255,0,255,255 38 | /processorParam:ColorKeyEnabled=True 39 | /processorParam:GenerateMipmaps=False 40 | /processorParam:PremultiplyAlpha=True 41 | /processorParam:ResizeToPowerOfTwo=False 42 | /processorParam:MakeSquare=False 43 | /processorParam:TextureFormat=Color 44 | /build:Textures/left_bot_house.png 45 | 46 | #begin Textures/left_top_house.png 47 | /importer:TextureImporter 48 | /processor:TextureProcessor 49 | /processorParam:ColorKeyColor=255,0,255,255 50 | /processorParam:ColorKeyEnabled=True 51 | /processorParam:GenerateMipmaps=False 52 | /processorParam:PremultiplyAlpha=True 53 | /processorParam:ResizeToPowerOfTwo=False 54 | /processorParam:MakeSquare=False 55 | /processorParam:TextureFormat=Color 56 | /build:Textures/left_top_house.png 57 | 58 | #begin Textures/right_bot_house.png 59 | /importer:TextureImporter 60 | /processor:TextureProcessor 61 | /processorParam:ColorKeyColor=255,0,255,255 62 | /processorParam:ColorKeyEnabled=True 63 | /processorParam:GenerateMipmaps=False 64 | /processorParam:PremultiplyAlpha=True 65 | /processorParam:ResizeToPowerOfTwo=False 66 | /processorParam:MakeSquare=False 67 | /processorParam:TextureFormat=Color 68 | /build:Textures/right_bot_house.png 69 | 70 | #begin Textures/right_top_house.png 71 | /importer:TextureImporter 72 | /processor:TextureProcessor 73 | /processorParam:ColorKeyColor=255,0,255,255 74 | /processorParam:ColorKeyEnabled=True 75 | /processorParam:GenerateMipmaps=False 76 | /processorParam:PremultiplyAlpha=True 77 | /processorParam:ResizeToPowerOfTwo=False 78 | /processorParam:MakeSquare=False 79 | /processorParam:TextureFormat=Color 80 | /build:Textures/right_top_house.png 81 | 82 | #begin Textures/sky.png 83 | /importer:TextureImporter 84 | /processor:TextureProcessor 85 | /processorParam:ColorKeyColor=255,0,255,255 86 | /processorParam:ColorKeyEnabled=True 87 | /processorParam:GenerateMipmaps=False 88 | /processorParam:PremultiplyAlpha=True 89 | /processorParam:ResizeToPowerOfTwo=False 90 | /processorParam:MakeSquare=False 91 | /processorParam:TextureFormat=Color 92 | /build:Textures/sky.png 93 | 94 | #begin Textures/stone.png 95 | /importer:TextureImporter 96 | /processor:TextureProcessor 97 | /processorParam:ColorKeyColor=255,0,255,255 98 | /processorParam:ColorKeyEnabled=True 99 | /processorParam:GenerateMipmaps=False 100 | /processorParam:PremultiplyAlpha=True 101 | /processorParam:ResizeToPowerOfTwo=False 102 | /processorParam:MakeSquare=False 103 | /processorParam:TextureFormat=Color 104 | /build:Textures/stone.png 105 | 106 | #begin Textures/wood.png 107 | /importer:TextureImporter 108 | /processor:TextureProcessor 109 | /processorParam:ColorKeyColor=255,0,255,255 110 | /processorParam:ColorKeyEnabled=True 111 | /processorParam:GenerateMipmaps=False 112 | /processorParam:PremultiplyAlpha=True 113 | /processorParam:ResizeToPowerOfTwo=False 114 | /processorParam:MakeSquare=False 115 | /processorParam:TextureFormat=Color 116 | /build:Textures/wood.png 117 | 118 | -------------------------------------------------------------------------------- /RaycastEngine/Raycaster/Map.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Owain Bell - 2017 3 | * */ 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | 10 | namespace RaycastEngine 11 | { 12 | class Map 13 | { 14 | int[,] worldMap ={ 15 | {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, 16 | {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, 17 | {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, 18 | {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,2,3,1}, 19 | {1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,3,2,3,2,1}, 20 | {1,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,1}, 21 | {1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1}, 22 | {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, 23 | {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, 24 | {1,0,0,0,0,0,0,1,1,1,0,0,2,3,0,0,0,0,0,0,0,0,0,1}, 25 | {1,0,0,0,0,0,0,0,0,0,0,0,3,2,0,0,0,0,0,0,0,0,0,1}, 26 | {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, 27 | {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, 28 | {1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1}, 29 | {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1}, 30 | {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1}, 31 | {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1}, 32 | {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, 33 | {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, 34 | {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, 35 | {1,0,0,1,0,0,0,0,0,1,1,0,1,1,0,0,0,0,0,1,1,0,1,1}, 36 | {1,0,1,0,1,0,0,0,0,1,1,0,1,1,0,0,1,0,0,1,0,0,0,1}, 37 | {1,0,0,0,0,0,0,0,0,1,1,0,1,1,0,0,0,0,0,1,0,0,0,1}, 38 | {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1} 39 | }; 40 | 41 | int[,] midMap ={ 42 | {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, 43 | {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, 44 | {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, 45 | {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,5,4,3,1}, 46 | {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,4,5,2,1}, 47 | {1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1}, 48 | {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, 49 | {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, 50 | {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, 51 | {1,0,0,0,0,0,0,0,0,0,0,0,4,5,0,0,0,0,0,0,0,0,0,1}, 52 | {1,0,0,0,0,0,0,0,0,0,0,0,5,4,0,0,0,0,0,0,0,0,0,1}, 53 | {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, 54 | {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, 55 | {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, 56 | {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, 57 | {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, 58 | {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, 59 | {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, 60 | {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, 61 | {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, 62 | {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,1,1}, 63 | {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1}, 64 | {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1}, 65 | {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1} 66 | }; 67 | 68 | int[,] upMap ={ 69 | {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, 70 | {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, 71 | {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, 72 | {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, 73 | {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, 74 | {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, 75 | {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, 76 | {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, 77 | {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, 78 | {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, 79 | {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, 80 | {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, 81 | {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, 82 | {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, 83 | {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, 84 | {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, 85 | {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, 86 | {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, 87 | {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, 88 | {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, 89 | {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, 90 | {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, 91 | {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, 92 | {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, 93 | }; 94 | 95 | public Map() 96 | { 97 | } 98 | 99 | public int[,] getGrid() 100 | { 101 | return worldMap; 102 | } 103 | 104 | public int[,] getGridUp() 105 | { 106 | return upMap; 107 | } 108 | 109 | public int[,] getGridMid() 110 | { 111 | return midMap; 112 | } 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | bld/ 21 | [Bb]in/ 22 | [Oo]bj/ 23 | [Ll]og/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | project.fragment.lock.json 46 | artifacts/ 47 | 48 | *_i.c 49 | *_p.c 50 | *_i.h 51 | *.ilk 52 | *.meta 53 | *.obj 54 | *.pch 55 | *.pdb 56 | *.pgc 57 | *.pgd 58 | *.rsp 59 | *.sbr 60 | *.tlb 61 | *.tli 62 | *.tlh 63 | *.tmp 64 | *.tmp_proj 65 | *.log 66 | *.vspscc 67 | *.vssscc 68 | .builds 69 | *.pidb 70 | *.svclog 71 | *.scc 72 | 73 | # Chutzpah Test files 74 | _Chutzpah* 75 | 76 | # Visual C++ cache files 77 | ipch/ 78 | *.aps 79 | *.ncb 80 | *.opendb 81 | *.opensdf 82 | *.sdf 83 | *.cachefile 84 | *.VC.db 85 | *.VC.VC.opendb 86 | 87 | # Visual Studio profiler 88 | *.psess 89 | *.vsp 90 | *.vspx 91 | *.sap 92 | 93 | # TFS 2012 Local Workspace 94 | $tf/ 95 | 96 | # Guidance Automation Toolkit 97 | *.gpState 98 | 99 | # ReSharper is a .NET coding add-in 100 | _ReSharper*/ 101 | *.[Rr]e[Ss]harper 102 | *.DotSettings.user 103 | 104 | # JustCode is a .NET coding add-in 105 | .JustCode 106 | 107 | # TeamCity is a build add-in 108 | _TeamCity* 109 | 110 | # DotCover is a Code Coverage Tool 111 | *.dotCover 112 | 113 | # NCrunch 114 | _NCrunch_* 115 | .*crunch*.local.xml 116 | nCrunchTemp_* 117 | 118 | # MightyMoose 119 | *.mm.* 120 | AutoTest.Net/ 121 | 122 | # Web workbench (sass) 123 | .sass-cache/ 124 | 125 | # Installshield output folder 126 | [Ee]xpress/ 127 | 128 | # DocProject is a documentation generator add-in 129 | DocProject/buildhelp/ 130 | DocProject/Help/*.HxT 131 | DocProject/Help/*.HxC 132 | DocProject/Help/*.hhc 133 | DocProject/Help/*.hhk 134 | DocProject/Help/*.hhp 135 | DocProject/Help/Html2 136 | DocProject/Help/html 137 | 138 | # Click-Once directory 139 | publish/ 140 | 141 | # Publish Web Output 142 | *.[Pp]ublish.xml 143 | *.azurePubxml 144 | # TODO: Comment the next line if you want to checkin your web deploy settings 145 | # but database connection strings (with potential passwords) will be unencrypted 146 | #*.pubxml 147 | *.publishproj 148 | 149 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 150 | # checkin your Azure Web App publish settings, but sensitive information contained 151 | # in these scripts will be unencrypted 152 | PublishScripts/ 153 | 154 | # NuGet Packages 155 | *.nupkg 156 | # The packages folder can be ignored because of Package Restore 157 | **/packages/* 158 | # except build/, which is used as an MSBuild target. 159 | !**/packages/build/ 160 | # Uncomment if necessary however generally it will be regenerated when needed 161 | #!**/packages/repositories.config 162 | # NuGet v3's project.json files produces more ignoreable files 163 | *.nuget.props 164 | *.nuget.targets 165 | 166 | # Microsoft Azure Build Output 167 | csx/ 168 | *.build.csdef 169 | 170 | # Microsoft Azure Emulator 171 | ecf/ 172 | rcf/ 173 | 174 | # Windows Store app package directories and files 175 | AppPackages/ 176 | BundleArtifacts/ 177 | Package.StoreAssociation.xml 178 | _pkginfo.txt 179 | 180 | # Visual Studio cache files 181 | # files ending in .cache can be ignored 182 | *.[Cc]ache 183 | # but keep track of directories ending in .cache 184 | !*.[Cc]ache/ 185 | 186 | # Others 187 | ClientBin/ 188 | ~$* 189 | *~ 190 | *.dbmdl 191 | *.dbproj.schemaview 192 | *.jfm 193 | *.pfx 194 | *.publishsettings 195 | node_modules/ 196 | orleans.codegen.cs 197 | 198 | # Since there are multiple workflows, uncomment next line to ignore bower_components 199 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 200 | #bower_components/ 201 | 202 | # RIA/Silverlight projects 203 | Generated_Code/ 204 | 205 | # Backup & report files from converting an old project file 206 | # to a newer Visual Studio version. Backup files are not needed, 207 | # because we have git ;-) 208 | _UpgradeReport_Files/ 209 | Backup*/ 210 | UpgradeLog*.XML 211 | UpgradeLog*.htm 212 | 213 | # SQL Server files 214 | *.mdf 215 | *.ldf 216 | 217 | # Business Intelligence projects 218 | *.rdl.data 219 | *.bim.layout 220 | *.bim_*.settings 221 | 222 | # Microsoft Fakes 223 | FakesAssemblies/ 224 | 225 | # GhostDoc plugin setting file 226 | *.GhostDoc.xml 227 | 228 | # Node.js Tools for Visual Studio 229 | .ntvs_analysis.dat 230 | 231 | # Visual Studio 6 build log 232 | *.plg 233 | 234 | # Visual Studio 6 workspace options file 235 | *.opt 236 | 237 | # Visual Studio LightSwitch build output 238 | **/*.HTMLClient/GeneratedArtifacts 239 | **/*.DesktopClient/GeneratedArtifacts 240 | **/*.DesktopClient/ModelManifest.xml 241 | **/*.Server/GeneratedArtifacts 242 | **/*.Server/ModelManifest.xml 243 | _Pvt_Extensions 244 | 245 | # Paket dependency manager 246 | .paket/paket.exe 247 | paket-files/ 248 | 249 | # FAKE - F# Make 250 | .fake/ 251 | 252 | # JetBrains Rider 253 | .idea/ 254 | *.sln.iml 255 | 256 | # CodeRush 257 | .cr/ 258 | 259 | # Python Tools for Visual Studio (PTVS) 260 | __pycache__/ 261 | *.pyc -------------------------------------------------------------------------------- /RaycastEngine/MainGame.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Owain Bell - 2017 3 | * */ 4 | using Microsoft.Xna.Framework; 5 | using Microsoft.Xna.Framework.Graphics; 6 | using Microsoft.Xna.Framework.Input; 7 | using System; 8 | using System.Diagnostics; 9 | 10 | namespace RaycastEngine 11 | { 12 | /// 13 | /// This is the main type for your game. 14 | /// 15 | public class MainGame : Game 16 | { 17 | //--set constant, texture size to be the wall (and sprite) texture size--// 18 | private static int texSize = 256; 19 | 20 | //--create slicer and declare slices--// 21 | private static TextureHandler slicer = new TextureHandler(texSize); 22 | private static Rectangle[] slices; 23 | 24 | //--viewport and width / height--// 25 | private static Viewport view; 26 | private static int width; 27 | private static int height; 28 | 29 | //--define camera--// 30 | private Camera camera; 31 | 32 | //--graphics manager and sprite batch--// 33 | private GraphicsDeviceManager graphics; 34 | private SpriteBatch spriteBatch; 35 | 36 | Texture2D[] textures = new Texture2D[5]; 37 | 38 | //--test texture--// 39 | Texture2D floor; 40 | Texture2D sky; 41 | 42 | //-test effect--// 43 | Effect effect; 44 | 45 | //test sprite 46 | Texture2D sprite; 47 | 48 | //--array of levels, levels reffer to "floors" of the world--// 49 | Level[] levels; 50 | 51 | //--struct to represent rects and tints of a level--// 52 | public struct Level 53 | { 54 | public Rectangle[] sv; 55 | public Rectangle[] cts; 56 | 57 | //--current slice tint (for lighting)--// 58 | public Color[] st; 59 | public int[] currTexNum; 60 | } 61 | 62 | public MainGame() 63 | { 64 | graphics = new GraphicsDeviceManager(this); 65 | Content.RootDirectory = "Content"; 66 | 67 | graphics.GraphicsProfile = GraphicsProfile.HiDef; 68 | graphics.PreferredBackBufferWidth = 1024; // set these values to the desired width and height of your window 69 | graphics.PreferredBackBufferHeight = 700; // (if your computer struggles, either turn down number of levels rendered or turn this to something low, like 800 x 600) 70 | // graphics.IsFullScreen = true; 71 | graphics.ApplyChanges(); 72 | } 73 | 74 | /// 75 | /// Allows the game to perform any initialization it needs to before starting to run. 76 | /// This is where it can query for any required services and load any non-graphic 77 | /// related content. Calling base.Initialize will enumerate through any components 78 | /// and initialize them as well. 79 | /// 80 | protected override void Initialize() 81 | { 82 | //--get viewport--// 83 | view = graphics.GraphicsDevice.Viewport; 84 | 85 | //--set view width and height--// 86 | width = view.Bounds.Width; 87 | height = view.Bounds.Height; 88 | 89 | //--init texture slices--// 90 | slices = slicer.getSlices(); 91 | 92 | //--inits the levels--// 93 | levels = createLevels(4); 94 | 95 | //--init camera--// 96 | camera = new Camera(width, height, texSize, slices, levels); 97 | 98 | base.Initialize(); 99 | } 100 | 101 | /// 102 | /// LoadContent will be called once per game and is the place to load 103 | /// all of your content. 104 | /// 105 | protected override void LoadContent() 106 | { 107 | // Create a new SpriteBatch, which can be used to draw textures. 108 | spriteBatch = new SpriteBatch(GraphicsDevice); 109 | 110 | // TODO: use this.Content to load your game content here 111 | textures[0] = getTexture("stone"); 112 | textures[1] = getTexture("left_bot_house"); 113 | textures[2] = getTexture("right_bot_house"); 114 | textures[3] = getTexture("left_top_house"); 115 | textures[4] = getTexture("right_top_house"); 116 | 117 | floor = getTexture("floor"); 118 | sky = getTexture("sky"); 119 | } 120 | 121 | /// 122 | /// UnloadContent will be called once per game and is the place to unload 123 | /// game-specific content. 124 | /// 125 | protected override void UnloadContent() 126 | { 127 | // TODO: Unload any non ContentManager content here 128 | } 129 | 130 | /// 131 | /// Allows the game to run logic such as updating the world, 132 | /// checking for collisions, gathering input, and playing audio. 133 | /// 134 | /// Provides a snapshot of timing values. 135 | protected override void Update(GameTime gameTime) 136 | { 137 | if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape)) 138 | Exit(); 139 | 140 | // TODO: Add your update logic here 141 | camera.update(); 142 | } 143 | 144 | /// 145 | /// This is called when the game should draw itself. 146 | /// 147 | /// Provides a snapshot of timing values. 148 | protected override void Draw(GameTime gameTime) 149 | { 150 | GraphicsDevice.Clear(Color.Black); 151 | 152 | //--draw sky and floor--// 153 | spriteBatch.Begin(); 154 | spriteBatch.Draw(floor, 155 | new Rectangle(0, (int)(height * 0.5f), width, (int)(height * 0.5f)), 156 | new Rectangle(0, 0, texSize, texSize), 157 | Color.White); 158 | spriteBatch.Draw(sky, 159 | new Rectangle(0, 0, width, (int)(height * 0.5f)), 160 | new Rectangle(0, 0, texSize, texSize), 161 | Color.White); 162 | spriteBatch.End(); 163 | 164 | //--draw walls--// 165 | spriteBatch.Begin(); 166 | 167 | for (int x = 0; x < width; x++) 168 | { 169 | for (int i = levels.Length - 1; i >= 0; i--) 170 | { 171 | spriteBatch.Draw(textures[levels[i].currTexNum[x]], levels[i].sv[x], levels[i].cts[x], levels[i].st[x]); 172 | } 173 | } 174 | 175 | spriteBatch.End(); 176 | 177 | base.Draw(gameTime); 178 | } 179 | 180 | //returns an initialised Level struct 181 | public Level[] createLevels(int numLevels) 182 | { 183 | Level[] arr = new Level[numLevels]; 184 | for (int i = 0; i < numLevels; i++) 185 | { 186 | arr[i] = new Level(); 187 | arr[i].sv = SliceView(); 188 | arr[i].cts = new Rectangle[width]; 189 | arr[i].st = new Color[width]; 190 | arr[i].currTexNum = new int[width]; 191 | 192 | for (int j = 0; j < arr[i].currTexNum.Length; j++) 193 | { 194 | arr[i].currTexNum[j] = 1; 195 | } 196 | } 197 | return arr; 198 | } 199 | 200 | /// 201 | /// Creates rectangle slices for each x in width. 202 | /// 203 | public Rectangle[] SliceView() 204 | { 205 | Rectangle[] arr = new Rectangle[width]; 206 | for (int x = 0; x < width; x++) 207 | { 208 | arr[x] = new Rectangle(x, 0, 1, height); 209 | } 210 | return arr; 211 | } 212 | 213 | /// 214 | /// Returns texture by texture name string 215 | /// 216 | /// Texture name string. 217 | public Texture2D getTexture(string textureName) 218 | { 219 | return Content.Load("Textures/" + textureName); 220 | } 221 | } 222 | } 223 | -------------------------------------------------------------------------------- /RaycastEngine/Raycaster/Camera.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Owain Bell - 2017 3 | * Code reworked into some simple OOP classes from the well known tutorial - http://lodev.org/cgtutor/raycasting.html 4 | * */ 5 | using Microsoft.Xna.Framework; 6 | using Microsoft.Xna.Framework.Graphics; 7 | using Microsoft.Xna.Framework.Input; 8 | using System; 9 | using System.Collections.Generic; 10 | using System.Linq; 11 | using System.Text; 12 | using System.Threading.Tasks; 13 | using static RaycastEngine.MainGame;//annoying dependancy 14 | 15 | /** 16 | * Class that represents a camera in terms of raycasting. 17 | * Contains methods to move the camera, and handles projection to, 18 | * set the rectangle slice position and height, 19 | */ 20 | namespace RaycastEngine 21 | { 22 | class Camera 23 | { 24 | 25 | //--camera position, init to start position--// 26 | private static Vector2 pos = new Vector2(22.5f, 11.5f); 27 | 28 | //--current facing direction, init to values coresponding to FOV--// 29 | private static Vector2 dir = new Vector2(-1.0f, 0.0f); 30 | 31 | //--the 2d raycaster version of camera plane, adjust y component to change FOV (ratio between this and dir x resizes FOV)--// 32 | private static Vector2 plane = new Vector2(0.0f, 0.66f); 33 | 34 | //--viewport width and height--// 35 | private static int w; 36 | private static int h; 37 | 38 | //--world map--// 39 | private static Map map; 40 | private static int[,] worldMap; 41 | private static int[,] upMap; 42 | private static int[,] midMap; 43 | 44 | //--texture width--// 45 | private static int texWidth; 46 | 47 | //--slices--// 48 | private static Rectangle[] s; 49 | 50 | //--move speed--// 51 | private static double moveSpeed = 0.06; 52 | 53 | //--rotate speed--// 54 | private static double rotSpeed = 0.03; 55 | 56 | //--cam x pre calc--// 57 | private static double[] camX; 58 | 59 | //--structs that contain rects and tints for each level or "floor" renderered--// 60 | Level[] lvls; 61 | 62 | public Camera(int width, int height, int texWid, Rectangle[] slices, Level[] levels) 63 | { 64 | w = width; 65 | h = height; 66 | texWidth = texWid; 67 | s = slices; 68 | lvls = levels; 69 | 70 | //--init cam pre calc array--// 71 | camX = new double[w]; 72 | preCalcCamX(); 73 | 74 | map = new Map(); 75 | worldMap = map.getGrid(); 76 | upMap = map.getGridUp(); 77 | midMap = map.getGridMid(); 78 | 79 | raycast();//do an initial raycast 80 | } 81 | 82 | public void update() 83 | { 84 | //--do raycast--// 85 | raycast(); 86 | 87 | //=========================// 88 | //=====take user input=====// 89 | //=========================// 90 | 91 | KeyboardState state = Keyboard.GetState(); 92 | 93 | bool lArrowKeyDown = state.IsKeyDown(Keys.Left) || state.IsKeyDown(Keys.A); 94 | 95 | if (lArrowKeyDown) 96 | { 97 | rotate(rotSpeed); 98 | } 99 | 100 | bool rArrowKeyDown = state.IsKeyDown(Keys.Right) || state.IsKeyDown(Keys.D); 101 | 102 | if (rArrowKeyDown) 103 | { 104 | rotate(-rotSpeed); 105 | } 106 | 107 | bool uArrowKeyDown = state.IsKeyDown(Keys.Up) || state.IsKeyDown(Keys.W); 108 | 109 | if (uArrowKeyDown) 110 | { 111 | move(moveSpeed); 112 | } 113 | 114 | bool dArrowKeyDown = state.IsKeyDown(Keys.Down) || state.IsKeyDown(Keys.S); 115 | 116 | if (dArrowKeyDown) 117 | { 118 | move(-moveSpeed); 119 | } 120 | 121 | //=========================// 122 | //=====user input end======// 123 | //=========================// 124 | } 125 | 126 | public void raycast() 127 | { 128 | for (int x = 0; x < w; x++) 129 | { 130 | for (int i = 0; i < lvls.Length; i++) 131 | { 132 | int[,] map; 133 | if (i == 0) map = worldMap; 134 | else if (i == 1) map = midMap; 135 | else map = upMap;//if above lvl2 just keep extending up 136 | castLevel(x, map, lvls[i].cts, lvls[i].sv, lvls[i].st, i); 137 | } 138 | } 139 | 140 | } 141 | 142 | /** 143 | * credit : Raycast loop and setting up of vectors for matrix calculations, I just updated it to use modern rendering methods. 144 | * courtesy - http://lodev.org/cgtutor/raycasting.html 145 | */ 146 | public void castLevel(int x, int[,] grid, Rectangle[] _cts, Rectangle[] _sv, Color[] _st, int levelNum) 147 | { 148 | //calculate ray position and direction 149 | double cameraX = camX[x];//x-coordinate in camera space 150 | double rayDirX = dir.X + plane.X * cameraX; 151 | double rayDirY = dir.Y + plane.Y * cameraX; 152 | 153 | //--rays start at camera position--// 154 | double rayPosX = pos.X; 155 | double rayPosY = pos.Y; 156 | 157 | //which box of the map we're in 158 | int mapX = (int)rayPosX; 159 | int mapY = (int)rayPosY; 160 | 161 | //length of ray from current position to next x or y-side 162 | double sideDistX; 163 | double sideDistY; 164 | 165 | //length of ray from one x or y-side to next x or y-side 166 | double deltaDistX = Math.Sqrt(1 + (rayDirY * rayDirY) / (rayDirX * rayDirX)); 167 | double deltaDistY = Math.Sqrt(1 + (rayDirX * rayDirX) / (rayDirY * rayDirY)); 168 | double perpWallDist; 169 | 170 | //what direction to step in x or y-direction (either +1 or -1) 171 | int stepX; 172 | int stepY; 173 | 174 | int hit = 0; //was there a wall hit? 175 | int side = -1; //was a NS or a EW wall hit? 176 | 177 | //calculate step and initial sideDist 178 | if (rayDirX < 0) 179 | { 180 | stepX = -1; 181 | sideDistX = (rayPosX - mapX) * deltaDistX; 182 | } 183 | else 184 | { 185 | stepX = 1; 186 | sideDistX = (mapX + 1.0 - rayPosX) * deltaDistX; 187 | } 188 | if (rayDirY < 0) 189 | { 190 | stepY = -1; 191 | sideDistY = (rayPosY - mapY) * deltaDistY; 192 | } 193 | else 194 | { 195 | stepY = 1; 196 | sideDistY = (mapY + 1.0 - rayPosY) * deltaDistY; 197 | } 198 | //perform DDA 199 | while (hit == 0) 200 | { 201 | //jump to next map square, OR in x-direction, OR in y-direction 202 | if (sideDistX < sideDistY) 203 | { 204 | sideDistX += deltaDistX; 205 | mapX += stepX; 206 | side = 0; 207 | } 208 | else 209 | { 210 | sideDistY += deltaDistY; 211 | mapY += stepY; 212 | side = 1; 213 | } 214 | //Check if ray has hit a wall 215 | if (mapX < 24 && mapY < 24 && mapX > 0 && mapY > 0) 216 | { 217 | if (grid[mapX, mapY] > 0) hit = 1; 218 | } 219 | else 220 | { 221 | //hit grid boundary 222 | hit = 2; 223 | 224 | //prevent out of range errors, needs to be improved 225 | if (mapX < 0) mapX = 0; 226 | else if (mapX > 23) mapX = 23; 227 | if (mapY < 0) mapY = 0; 228 | else if (mapY > 23) mapY = 23; 229 | } 230 | } 231 | 232 | //Calculate distance of perpendicular ray (oblique distance will give fisheye effect!) 233 | if (side == 0) perpWallDist = (mapX - rayPosX + (1 - stepX) / 2) / rayDirX; 234 | else perpWallDist = (mapY - rayPosY + (1 - stepY) / 2) / rayDirY; 235 | 236 | //Calculate height of line to draw on screen 237 | int lineHeight = (int)(h / perpWallDist); 238 | 239 | //calculate lowest and highest pixel to fill in current stripe 240 | int drawStart = (-lineHeight / 2 + h / 2); 241 | //int drawEnd = (lineHeight / 2 + h / 2); 242 | 243 | //texturing calculations 244 | int texNum = grid[mapX, mapY] - 1; //1 subtracted from it so that texture 0 can be used 245 | if (texNum < 0) texNum = 0; //why? 246 | lvls[levelNum].currTexNum[x] = texNum; 247 | 248 | //calculate value of wallX 249 | double wallX; //where exactly the wall was hit 250 | if (side == 0) wallX = rayPosY + perpWallDist * rayDirY; 251 | else wallX = rayPosX + perpWallDist * rayDirX; 252 | wallX -= Math.Floor(wallX); 253 | 254 | //x coordinate on the texture 255 | int texX = (int)(wallX * texWidth); 256 | if (side == 0 && rayDirX > 0) texX = texWidth - texX - 1; 257 | if (side == 1 && rayDirY < 0) texX = texWidth - texX - 1; 258 | 259 | //--some supid hacks to make the houses render correctly--// 260 | if (side == 0) 261 | { 262 | if (texNum == 3) 263 | lvls[levelNum].currTexNum[x]++; 264 | else if (texNum == 4) 265 | lvls[levelNum].currTexNum[x]--; 266 | 267 | if (texNum == 1) 268 | lvls[levelNum].currTexNum[x] = 4; 269 | else if (texNum == 2) 270 | lvls[levelNum].currTexNum[x] = 3; 271 | } 272 | 273 | //--set current texture slice to be slice x--// 274 | _cts[x] = s[texX]; 275 | 276 | //--set height of slice--// 277 | _sv[x].Height = lineHeight; 278 | 279 | //--set draw start of slice--// 280 | _sv[x].Y = drawStart - lineHeight * levelNum; 281 | 282 | //--due to modern way of drawing using quads this should be down here to ovoid glitches at the edges--// 283 | if (drawStart < 0) drawStart = 0; 284 | // if (drawEnd >= h) drawEnd = h - 1; 285 | 286 | //--add a bit of tint to differentiate between walls of a corner--// 287 | _st[x] = Color.White; 288 | if (side == 1) 289 | { 290 | int wallDiff = 12; 291 | _st[x].R -= (byte)wallDiff; 292 | _st[x].G -= (byte)wallDiff; 293 | _st[x].B -= (byte)wallDiff; 294 | } 295 | //--simulates torch light, as if player was carrying a radial light--// 296 | float lightFalloff = -100; //decrease value to make torch dimmer 297 | 298 | //--sun brightness, illuminates whole level--// 299 | float sunLight = 300;//global illuminaion 300 | 301 | //--distance based dimming of light--// 302 | float shadowDepth = (float)Math.Sqrt(perpWallDist) * lightFalloff; 303 | _st[x].R = (byte)MathHelper.Clamp(_st[x].R + shadowDepth + sunLight, 0, 255); 304 | _st[x].G = (byte)MathHelper.Clamp(_st[x].G + shadowDepth + sunLight, 0, 255); 305 | _st[x].B = (byte)MathHelper.Clamp(_st[x].B + shadowDepth + sunLight, 0, 255); 306 | 307 | } 308 | 309 | /// 310 | /// Moves camera by move speed 311 | /// 312 | /// Move speed 313 | public void move(double mSpeed) 314 | { 315 | if (worldMap[(int)(pos.X + dir.X * mSpeed * 12), (int)pos.Y] > 0 == false) pos.X += (float)(dir.X * mSpeed); 316 | if (worldMap[(int)pos.X, (int)(pos.Y + dir.Y * mSpeed * 12)] > 0 == false) pos.Y += (float)(dir.Y * mSpeed); 317 | } 318 | 319 | /// 320 | /// Rotates camera by rotate speed 321 | /// 322 | /// Rotate speed 323 | public void rotate(double rSpeed) 324 | { 325 | //both camera direction and camera plane must be rotated 326 | double oldDirX = dir.X; 327 | dir.X = (float)(dir.X * Math.Cos(rSpeed) - dir.Y * Math.Sin(rSpeed)); 328 | dir.Y = (float)(oldDirX * Math.Sin(rSpeed) + dir.Y * Math.Cos(rSpeed)); 329 | double oldPlaneX = plane.X; 330 | plane.X = (float)(plane.X * Math.Cos(rSpeed) - plane.Y * Math.Sin(rSpeed)); 331 | plane.Y = (float)(oldPlaneX * Math.Sin(rSpeed) + plane.Y * Math.Cos(rSpeed)); 332 | } 333 | 334 | /// 335 | /// precalculates camera x coordinate 336 | /// 337 | public static void preCalcCamX() 338 | { 339 | for (int x = 0; x < w; x++) 340 | camX[x] = 2 * x / (double)w - 1; //x-coordinate in camera space 341 | } 342 | } 343 | } 344 | --------------------------------------------------------------------------------