• Announcements

    • khawk

      Download the Game Design and Indie Game Marketing Freebook   07/19/17

      GameDev.net and CRC Press have teamed up to bring a free ebook of content curated from top titles published by CRC Press. The freebook, Practices of Game Design & Indie Game Marketing, includes chapters from The Art of Game Design: A Book of Lenses, A Practical Guide to Indie Game Marketing, and An Architectural Approach to Level Design. The GameDev.net FreeBook is relevant to game designers, developers, and those interested in learning more about the challenges in game development. We know game development can be a tough discipline and business, so we picked several chapters from CRC Press titles that we thought would be of interest to you, the GameDev.net audience, in your journey to design, develop, and market your next game. The free ebook is available through CRC Press by clicking here. The Curated Books The Art of Game Design: A Book of Lenses, Second Edition, by Jesse Schell Presents 100+ sets of questions, or different lenses, for viewing a game’s design, encompassing diverse fields such as psychology, architecture, music, film, software engineering, theme park design, mathematics, anthropology, and more. Written by one of the world's top game designers, this book describes the deepest and most fundamental principles of game design, demonstrating how tactics used in board, card, and athletic games also work in video games. It provides practical instruction on creating world-class games that will be played again and again. View it here. A Practical Guide to Indie Game Marketing, by Joel Dreskin Marketing is an essential but too frequently overlooked or minimized component of the release plan for indie games. A Practical Guide to Indie Game Marketing provides you with the tools needed to build visibility and sell your indie games. With special focus on those developers with small budgets and limited staff and resources, this book is packed with tangible recommendations and techniques that you can put to use immediately. As a seasoned professional of the indie game arena, author Joel Dreskin gives you insight into practical, real-world experiences of marketing numerous successful games and also provides stories of the failures. View it here. An Architectural Approach to Level Design This is one of the first books to integrate architectural and spatial design theory with the field of level design. The book presents architectural techniques and theories for level designers to use in their own work. It connects architecture and level design in different ways that address the practical elements of how designers construct space and the experiential elements of how and why humans interact with this space. Throughout the text, readers learn skills for spatial layout, evoking emotion through gamespaces, and creating better levels through architectural theory. View it here. Learn more and download the ebook by clicking here. Did you know? GameDev.net and CRC Press also recently teamed up to bring GDNet+ Members up to a 20% discount on all CRC Press books. Learn more about this and other benefits here.

Gaius Baltar

Members
  • Content count

    30
  • Joined

  • Last visited

Community Reputation

300 Neutral

About Gaius Baltar

  • Rank
    Member
  1. Okay, I just realized that I forgot to add the InputLayout to the immediateContext. That basically solved the issue.   After some edits to the code I finally get the output I was hoping for:  
  2. First off I'd like to point out that I'm an absolute beginner regarding 3D graphics programming and DirectX in general. So if you have any code optimization tips for me I'll accept them with open arms.   I've been learning my way about the DirectX API using SlimDX and the help of some useful resources like Frank D. Luna's book on programming with DirectX 11 and this site . (The book and site go very well together, especially for someone learning to use DirectX with C#).   Anyhow, I've recently finished chapter 6 of Luna's book and decided to try and make a personal DirectX framework of sorts for learning purposes, but now that I've got a sort of skeleton of the thing going, it throws weird errors at me occasionally or it just doesn't do what I want it to (display a cube in this case).   So, here it is:   Window.cs [spoiler] using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using SlimDX; using SlimDX.Windows; using System.Drawing; using System.Windows.Forms; using SlimDX.Direct3D11; using Device = SlimDX.Direct3D11.Device; using Debug = System.Diagnostics.Debug; using SlimDX.DXGI;   namespace MyFramework {     public delegate void Renderer();     public delegate void Updater(float dt);     public delegate void Disposer();     public class Window : RenderForm     {         public Event windowsEvent;           public Renderer OnRender;         public Updater OnUpdate;         public Disposer OnDispose;         public Timer timer;         private Device device;         private SwapChain swapChain;         private DeviceContext immediateContext;         private RenderTargetView renderTargetView;         private DepthStencilView depthStencilView;         private Texture2D depthStencilBuffer;         private Viewport viewport;         private Rectangle scissorRect;         private Shader shader;         private EffectMatrixVariable fxWVP;         private Matrix proj;           private RasterizerStateDescription rsd;         private RasterizerState rs;           private int msaa4XQuality;         private bool enableMsaa4X;         private float viewportX;         private float viewportY;         private float viewportWidth;         private float viewportHeight;           public bool ToggleMsaa4XEnabled         {             get { return enableMsaa4X; }             set { enableMsaa4X = value; }         }           public bool ToggleWireframe         {             get             {                 if (rsd.FillMode == FillMode.Wireframe)                     return true;                 else                     return false;             }             set             {                 if (value)                     rsd.FillMode = FillMode.Wireframe;                 else                     rsd.FillMode = FillMode.Solid;             }         }           public bool ToggleScissorMode         {             get { return rsd.IsScissorEnabled; }             set { rsd.IsScissorEnabled = value; }         }           public Device Device         {             get { return device; }         }           public void SetScissorRect(int x, int y, int width, int height)         {             scissorRect = new Rectangle(x, y, width, height);         }         public Window(string title, Size size, float vX = 0, float vY = 0, float vWidth = -1, float vHeight = -1)             : base(title)         {             this.Size = size;             this.Icon = null;             viewportX = vX;             viewportY = vY;             viewportWidth = vWidth >= 0 ? vWidth : size.Width;             viewportHeight = vHeight >= 0 ? vHeight : size.Height;               Init();         }           private void Init()         {             device = null;             swapChain = null;             immediateContext = null;             renderTargetView = null;             depthStencilView = null;             depthStencilBuffer = null;             rs = null;             shader = null;             fxWVP = null;               msaa4XQuality = 0;             enableMsaa4X = true;               scissorRect = new Rectangle();             windowsEvent = new Event();             timer = new Timer();             rsd = new RasterizerStateDescription();             viewport = new Viewport();               OnRender += () => { };             OnUpdate += (dt) => { };             OnDispose += () => { };               this.ResizeBegin += (sender, args) =>             {                 timer.Stop();             };             this.ResizeEnd += (sender, args) =>             {                 timer.Start();                 OnResize();             };             this.FormClosing += (sender, args) =>             {                 DisposeWindow();                 OnDispose();                 Environment.Exit(0);               };             this.Show();             this.Update();               InitD3D();         }           private void InitD3D()         {             try             {                 device = new Device(DriverType.Hardware, DeviceCreationFlags.None);             }             catch (Exception ex)             {                 MessageBox.Show("D3D11Device creation failed\n" + ex.Message + "\n" + ex.StackTrace, "Error");             }               Debug.Assert((msaa4XQuality = device.CheckMultisampleQualityLevels(Format.R8G8B8A8_UNorm, 4)) > 0);             try             {                 var description = new SwapChainDescription()                 {                     BufferCount = 1,                     Usage = Usage.RenderTargetOutput,                     OutputHandle = this.Handle,                     IsWindowed = true,                     ModeDescription = new ModeDescription(0, 0, new Rational(60, 1), Format.R8G8B8A8_UNorm),                     SampleDescription = enableMsaa4X ? new SampleDescription(4, msaa4XQuality - 1) : new SampleDescription(1, 0),                     Flags = SwapChainFlags.AllowModeSwitch,                     SwapEffect = SwapEffect.Discard                 };                 Device.CreateWithSwapChain(DriverType.Hardware, DeviceCreationFlags.None, description, out device, out swapChain);                 immediateContext = device.ImmediateContext;                   rsd = new RasterizerStateDescription()                 {                     FillMode = FillMode.Solid,                     CullMode = CullMode.Back,                     IsAntialiasedLineEnabled = true,                     IsFrontCounterclockwise = false,                     IsDepthClipEnabled = true,                     IsScissorEnabled = false                 };                 rs = RasterizerState.FromDescription(device, rsd);                   using (var factory = swapChain.GetParent<SlimDX.DXGI.Factory>())                     factory.SetWindowAssociation(this.Handle, WindowAssociationFlags.IgnoreAltEnter);                   this.KeyDown += (o, e) =>                 {                     if (e.Alt && e.KeyCode == Keys.Enter)                     {                         swapChain.IsFullScreen = !swapChain.IsFullScreen;                     }                 };             }             catch (Exception ex)             {                 MessageBox.Show(ex.Message + "\n" + ex.StackTrace, "Error");             }             OnResize();         }           public void InitShader(string filePath)         {             shader = new Shader(ref device, filePath);             fxWVP = shader.fx.GetVariableByName("worldViewProj").AsMatrix();         }         public void InitCustomShader(string filePath, string[] inputElements, Format[] iEFormats, int[] iEStrides)         {             shader = new Shader(ref device, filePath, inputElements, iEFormats, iEStrides);         }           private void DisposeWindow()         {             Util.ReleaseCom(ref renderTargetView);             Util.ReleaseCom(ref depthStencilView);             Util.ReleaseCom(ref depthStencilBuffer);             if (shader != null) shader.Dispose();             if (immediateContext != null) immediateContext.ClearState();             if (swapChain.IsFullScreen) swapChain.SetFullScreenState(false, null);             Util.ReleaseCom(ref swapChain);             Util.ReleaseCom(ref immediateContext);             Util.ReleaseCom(ref device);         }           private void OnResize()         {             Util.ReleaseCom(ref renderTargetView);             Util.ReleaseCom(ref depthStencilView);             Util.ReleaseCom(ref depthStencilBuffer);             swapChain.ResizeBuffers(1, this.Width, this.Height, Format.R8G8B8A8_UNorm, SwapChainFlags.None);             using (var resource = SlimDX.Direct3D11.Resource.FromSwapChain<Texture2D>(swapChain, 0))             {                 renderTargetView = new RenderTargetView(device, resource);             }             var depthStencilDesc = new Texture2DDescription()             {                 Width = this.Width,                 Height = this.Height,                 MipLevels = 1,                 ArraySize = 1,                 Format = Format.D24_UNorm_S8_UInt,                 SampleDescription = enableMsaa4X ? new SampleDescription(4, msaa4XQuality - 1) : new SampleDescription(1, 0),                 Usage = ResourceUsage.Default,                 BindFlags = BindFlags.DepthStencil,                 CpuAccessFlags = CpuAccessFlags.None,                 OptionFlags = ResourceOptionFlags.None             };             depthStencilBuffer = new Texture2D(device, depthStencilDesc);             depthStencilView = new DepthStencilView(device, depthStencilBuffer);             immediateContext.OutputMerger.SetTargets(depthStencilView, renderTargetView);             viewport = new Viewport(viewportX, viewportY, viewportWidth, viewportHeight, 0.0f, 1.0f);             immediateContext.Rasterizer.SetViewports(viewport);               proj = Matrix.PerspectiveFovLH(0.25f * (float)Math.PI, this.Width / this.Height, 0.01f, 500.0f);         }           public Viewport Viewport         {             get { return viewport; }             set             {                 viewportX = value.X;                 viewportY = value.Y;                 viewportWidth = value.Width;                 viewportHeight = value.Height;                 OnResize();             }         }           public void Run()         {             MessagePump.Run(() =>             {                 timer.Tick();                 OnRender();                 OnUpdate(timer.DeltaTime);             });         }           public void ClearScreen(Color4 clearColor)         {             immediateContext.ClearRenderTargetView(renderTargetView, clearColor);             immediateContext.ClearDepthStencilView(depthStencilView, DepthStencilClearFlags.Depth | DepthStencilClearFlags.Stencil, 1.0f, 0);             immediateContext.Rasterizer.State = rs;         }           public void SetPrimitiveTobology(PrimitiveTopology topology)         {             immediateContext.InputAssembler.PrimitiveTopology = topology;         }           public void SwapBuffers()         {             swapChain.Present(0, PresentFlags.None);         }           public void Draw<T>(ref T entity) where T : Entity3D         {             immediateContext.InputAssembler.SetVertexBuffers(0, new VertexBufferBinding(entity.vb, Vertex.stride, 0));             immediateContext.InputAssembler.SetIndexBuffer(entity.ib, Format.R32_UInt, 0);               if (shader != null)             {                 Vector3 pos = new Vector3(3, 3, 3);                 Vector3 target = new Vector3(0);                 Vector3 up = new Vector3(0, 1, 0);                 Matrix view = Matrix.LookAtLH(pos, target, up);                 fxWVP.SetMatrix(entity.shapeWorld * view * proj);                 for (int p = 0; p < shader.tech.Description.PassCount; p++)                 {                     shader.tech.GetPassByIndex(p).Apply(immediateContext);                     immediateContext.DrawIndexed(entity.indexCount, 0, 0);                 }             }             else             {                 immediateContext.DrawIndexed(entity.indexCount, 0, 0);             }         }           protected override void WndProc(ref Message m)         {             windowsEvent.SetType(m);             base.WndProc(ref m);         }     } }  [/spoiler]   Sahder.cs [spoiler] using SlimDX.D3DCompiler; using SlimDX.Direct3D11; using SlimDX.DXGI; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using Device = SlimDX.Direct3D11.Device;   namespace MyFramework {     class Shader     {         public InputLayout inputLayout;         public Effect fx;         public EffectTechnique tech;           public Shader(ref Device device, string filePath, string[] inputElements, Format[] iEformats, int[] iEStrides)         {             CompileShaders(ref device, filePath);             CreateInputLayout(ref device, inputElements, iEformats, iEStrides);         }           public Shader(ref Device device, string filePath)         {             CompileShaders(ref device, filePath);             string[] inputElements = new string[] { "POSITION", "COLOR" };             Format[] iEformats = new Format[] { Format.R32G32B32_Float, Format.R32G32B32A32_Float };             int[] iEStrides = new int[] { 12 };               CreateInputLayout(ref device, inputElements, iEformats, iEStrides);         }           private void CompileShaders(ref Device device, string filePath)         {             string errors = null;             ShaderBytecode compiledShader = null;             try             {                 compiledShader = ShaderBytecode.CompileFromFile(                 filePath,                 null,                 "fx_5_0",                 ShaderFlags.None,                 EffectFlags.None,                 null,                 null,                 out errors);                 fx = new Effect(device, compiledShader);             }             catch (Exception ex)             {                 if (!string.IsNullOrEmpty(errors))                 {                     MessageBox.Show(errors);                 }                 MessageBox.Show(ex.Message);                 return;             }             finally             {                 Util.ReleaseCom(ref compiledShader);             }             tech = fx.GetTechniqueByName("Tech");         }           private void CreateInputLayout(ref Device device, string[] inputElements, Format[] iEformats, int[] iEStrides)         {             InputElement[] vertexDesc = new InputElement[inputElements.Length];             for (int i = 0; i < vertexDesc.Length; i++)             {                 vertexDesc[i] = new InputElement(inputElements[i], 0, iEformats[i], i > 0 ? iEStrides[i - 1] : 0, 0, InputClassification.PerVertexData, 0);             }               var passDesc = tech.GetPassByIndex(0).Description;             inputLayout = new InputLayout(device, passDesc.Signature, vertexDesc);         }           public void Dispose()         {             Util.ReleaseCom(ref inputLayout);             Util.ReleaseCom(ref fx);         }     } }  [/spoiler]   Entity3D.cs [spoiler] using SlimDX; using SlimDX.Direct3D11; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Buffer = SlimDX.Direct3D11.Buffer;   namespace MyFramework {     public class Entity3D     {         public int vertexCount;         public int indexCount;         public Vertex[] vertices;         public uint[] indices;         public Matrix shapeWorld;         public Buffer vb;         public Buffer ib;                    public Entity3D()         {             vertexCount = 0;             indexCount = 0;             vertices = null;             indices = null;             vb = null;             ib = null;             shapeWorld = Matrix.Identity;         }           public virtual void Dispose()         {             Util.ReleaseCom(ref vb);             Util.ReleaseCom(ref ib);         }     } }[/spoiler]   Cube.cs [spoiler] using SlimDX; using SlimDX.Direct3D11; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Buffer = SlimDX.Direct3D11.Buffer;   namespace MyFramework {     public class Cube : Entity3D     {         public Cube(Device device, float width, float height, float depth, Color4 color)             : base()         {             float x = 0.5f * width;             float y = 0.5f * height;             float z = 0.5f * depth;               vertexCount = 8;             indexCount = 36;             vertices = new Vertex[] {                  new Vertex(-x,-y,-z, color), // 0                 new Vertex( x,-y,-z, color), // 1                 new Vertex( x, y,-z, color), // 2                 new Vertex(-x, y,-z, color), // 3                 new Vertex(-x,-y, z, color), // 4                 new Vertex( x,-y, z, color), // 5                 new Vertex( x, y, z, color), // 6                 new Vertex(-x, y, z, color), // 7             };             indices = new uint[] {                  0,3,2,                 0,2,1,                 2,6,1,                 6,5,1,                 6,7,5,                 7,4,5,                 7,3,4,                 3,0,4,                 7,6,3,                 3,6,2,                 0,1,4,                 1,5,4             };               BufferDescription vbd = new BufferDescription(Vertex.stride * vertexCount, ResourceUsage.Immutable, BindFlags.VertexBuffer, CpuAccessFlags.None, ResourceOptionFlags.None, 0);             vb = new Buffer(device, new DataStream(vertices, false, false), vbd);             BufferDescription ibd = new BufferDescription(sizeof(uint) * indexCount, ResourceUsage.Immutable, BindFlags.IndexBuffer, CpuAccessFlags.None, ResourceOptionFlags.None, 0);             ib = new Buffer(device, new DataStream(indices, false, false), ibd);         }     } }  [/spoiler]   Vertex.cs [spoiler] using SlimDX; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks;   namespace MyFramework {     public struct Vertex     {         public Vector3 position;         public Color4 color;         public const int stride = 28;           public Vertex(Vector3 pos, Color4 col)         {             position = pos;             color = col;         }         public Vertex(float x, float y, float z, Color4 col)         {             position = new Vector3(x, y, z);             color = col;         }     } }  [/spoiler]   Program.cs //Main entry point   [spoiler] using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using MyFramework; using System.Drawing; using SlimDX;   namespace FrameworkTester {     class Program     {         static void Main(string[] args)         {             SlimDX.Configuration.EnableObjectTracking = true;             Window window = new Window("Test", new Size(1280, 720));               window.InitShader("FX/shader.fx");               window.OnUpdate += (dt) => {                               };               Cube cube = new Cube(window.Device, 0.5f, 0.5f, 0.5f, Color.White);               window.OnRender += () => {                 window.ClearScreen(Color.CornflowerBlue);                 window.SetPrimitiveTobology(SlimDX.Direct3D11.PrimitiveTopology.TriangleList);                 window.Draw(ref cube);                 window.SwapBuffers();             };               window.OnDispose += () => {                 cube.Dispose();             };               window.Run();         }     } }  [/spoiler]   And lastly, my shader, "shader.fx" [spoiler] cbuffer wvpm{ float4x4 worldViewProj; };   struct VertexIn { float3 PosL : POSITION; float4 Color : COLOR; }; struct VertexOut { float4 PosH : SV_POSITION; float4 Color: COLOR; }; RasterizerState rsWireframe{  FillMode = Wireframe; CullMode = Back; FrontCounterClockwise = false; }; VertexOut VS(VertexIn vin){ VertexOut vout; vout.PosH = mul(float4(vin.PosL, 1.0f), worldViewProj); vout.Color = vin.Color; return vout; } float4 PS(VertexOut pin) :SV_Target{ return pin.Color; } technique11 Tech { pass P0{ SetVertexShader(CompileShader(vs_4_0, VS())); SetGeometryShader(NULL); SetPixelShader(CompileShader(ps_4_0, PS())); } }[/spoiler]   I'd like to leave you with a screenshot of what I get when I run Program.cs:   Also, please don't bash the hard-coded stuff too much, everything so far is mostly just placeholder code for me to get my bearings.
  3.   It appears, I was wrong, go with Nypyren's suggestion, in this case it would be the better solution overall.
  4. Disregard this post. 
  5. Disregard this post
  6. You're welcome! The thing is, I've never actually done anything in 3d so this is completely theoretical... would be logical though.   Also I would be interested to know how one would find the position where the line and triangle pass each other, I could probably figure it out for 2d but it seems more complex for 3d.If anyone knows, would be great to note into my reference book.
  7. I'm just guessing right now, so this might be wrong:   First check if the line ever passes the triangle, if yes, take the point where the line passes the triangle and make three more triangles with each of the points of the original triangle and the point like so:       If the area of the three triangles is equal to the area of the larger triangle, you have yourself an intersection. I actually had a quick glimpse at a youtube video talking about this kind of intersection, thought it might be worth sharing my two cents.   Edit: Here's the video:  https://www.youtube.com/watch?v=s5m391a5HFg
  8. I figured that, but I thought Visual Studio somehow did it differently. Suppose not.
  9. Oh, I missed the static part. Thanks for clarification.
  10. I'm using Visual Studio, as far as I can tell it only compiles the files that have been edited, and if I'm not mistaken, I believe that it doesn't compile files just because they were included by another. Or, I could be totally wrong about that... I never really considered the possibility of simply creating a data array to fill another array. Wouldn't it be expensive though to recreate the array every iteration of the loop?
  11.   So, I should make multiple headers? includes.h and constants.h?   But I also don't really see how "init.h" isn't scalable, is it because of the merging of includes and constants in a single file, or is there another reason?   Even with the "classname.cpp #includes classname.h" thing, wouldn't it still be the same? Because the classname.h still might depend on stuff from init.h. Or am I getting this wrong somehow?     Yeah, I try to spend the least amount of time on naming my variables, if I don't think of a name fast, it might get a bad name .     I know. After a while it got really confusing to try and find code I was looking for in that file, In my next project I'm going to have my entire GUI in a separate class, that should save me a few lines.        I was thinking of doing that, but then I didn't... I suppose it was too much work for me , especially because it was only used for the high scores.       Yeah, KulSeran told me the same thing just about. And my question to him still stands:  "[background=#fafbfc]...I believe sfml takes care of deallocating it's own allocated memory, so the destructor wouldn't really be necessary(?)[/size][/background]". Is it always necessary to implement all three? Because in the case of the button class, the destructor would be empty.      I remember someone posting on a previous thread of mine that I shouldn't keep the application running after an error has occured. Should I keep it running or not? I'm confused, but I suppose I could write the error to a error log file or something.     My attempt at trying to stay consistent with the sfml naming convention (mostly inspired by the sf::Vector<> class) , I suppose I failed.      That's a mistake, I think most of the time I just completely forget that I'm following any kind of naming convention and just name the damn thing whatever seems right at the time .       Huh, but how would I integrate the jump from 300 to 600? I can't think of a way.      Woops, I think the problem here is that I used to have a text class. When I got rid of that I tried to rewrite everything into the button class, I suppose I just missed a few things on the way.       I keep forgetting some of these built in methods to make life easier... I'll implement that.        I used a whole button class, because I thought there was a method to test if one class was equal to another, that failed, so I used the string value in the button, seems stupid now that I think about it.       That's what I did with the missiles, because I first had like five vectors just for the missiles in my Missile_Command class. But I didn't want to make a whole new class for the enemies, I suppose it slipped my mind that I could have easily used a structure to store both items...       Thanks for reading through my code, I appreciate the time that you took to do so. This review really gave me a further push in the right direction and I'll most likely use this as a reference for future projects.      vector.end() is 1) you could do (vector.end() - 1) as well.  The end iterator is one-past the end of the array, and does not point at a valid object. 2) It's all relative to the container.  Not all containers provide iterators that support (end() -1).  Vector happens to be a random-access iterator, so vector.begin() + x is just as fast as vector.end() - y.  So yes, you could base the second point off the end iterator.     Oh, I thought vector.end() was just the last item in the array.   You're right, in my case it wouldn't matter for the _trails particles, because they all have a one pixel area and are mostly white.  
  12. You can use OpenTK for C#, it might even be what 3ddreamer meant with "There is an OpenGL library for 3D but I don't remember what it is called".
  13.   Thanks for trying it out! Yeah, the console window is a little intrusive at times, but is required for score keeping in this case (also debugging). I suppose I just didn't want to write a class utilizing text objects to keep track of user input.     First of all, thanks for taking the time to read through my code! As to the underscore naming convention, could you suggest what I should use instead?   I'll make sure to do that. That's interesting, so far I've always written my classes: private > protected > public. I'll keep that in mind for my next project.   I never really got into reserving memory for vectors before... I'll have to look that up, but does it really make in impact on performance to reserve vector space?   Wow, that actually makes way more sense than my code, but wouldn't it be vector.end() and not vector.begin() + (vector.size() - 1)? Or is there some sort of difference?   You're right about the copy constructor, but I believe sfml takes care of deallocating it's own allocated memory, so the destructor wouldn't really be necessary(?) I could implement it anyway, just to stay consistent with the C++ law.   I thought you only had to do the const reference thing on parameters, but I suppose now that you mentioned it, it kind of does make sense to return a const reference as well.   Yeah, I keep telling myself that, because most of the time I end up expanding my if statements anyway, but I suppose in some cases it's just faster to not include the curly brackets. I think I'll eventually find an equilibrium between curly brackets and no curly brackets.   Woops.
  14. I recently finished programming a clone to the popular game Missile Command as part of the "getting started" article on gamedev.net. This project took me about two weeks to complete whilst working on it every now and then. The code contains over 1500 lines of C++ and SFML. This time I took a different design approach to my previous projects in order to simplify the code and make it more readable... hopefully.   Links to my other projects in this series: Breakout Snake Pong   Video of my Missile Command clone: http://youtu.be/2jqhiZ9QPks   Download: https://www.dropbox.com/s/07lq4wc5fsp1djb/Missile%20Command.zip (Please tell me if the game doesn't work)   Features: Crappy UI Highscores Explosions    Screenshots:           Files:       Last but not least: A huge chunk of code.   main.cpp #include "init.h" int main(){ Missile_Command game; game.run(); return 0; } init.h #pragma once // C++ #include <iostream> #include <string> #include <vector> #include <fstream> #include <sstream> // SFML #include <SFML/Graphics.hpp> #include <SFML/Audio.hpp> #include <SFML/Network.hpp> // Framework #include "SoundEffect.h" #include "Entity.h" #include "Button.h" #include "Math.h" #include "Collision_Detection.h" #include "Windows_Stuff.h" // Game #include "Missiles.h" #include "Missile_Command.h" // Globals const float SECOND = 1000; const float BLOCKSIZE = 20; const int GRIDSIZE_X = 50; const int GRIDSIZE_Y = 30; const int SCRW = (int)BLOCKSIZE * GRIDSIZE_X; const int SCRH = (int)BLOCKSIZE * GRIDSIZE_Y; const double INTERVAL = 16.6; // 1000 / INTERVAL = FPS -> ~60 const sf::Color CLEARCOLOR(sf::Color(0, 0, 0)); Missile_Command.h #pragma once struct Particle; enum class GameState{ Home, Settings, About, Highscores, Playing, Paused, GameOver, Win }; class Missile_Command{ sf::RenderWindow _window; sf::Event _event; GameState _gameState; sf::Clock _clock; sf::Font _font; sf::Text _aboutText; sf::Text _volumeText; sf::Text _volumeInfoText; sf::Text _scoreText; sf::Text _inGameInfoText; sf::Text _gameOverText; sf::Text _winText; sf::Text _highscoreNamesText; sf::Text _highscoreScoresText; sf::Text _ammunitionText; sf::Texture _bgTex; sf::Sprite _bgSprite1; sf::Sprite _bgSprite2; sf::Vector2f _wallSize; sf::Vector2f _windowCenter; sf::Vector2f _playerCenterLoc; sf::Vector2f _missileSize; std::vector<sf::Vector2f> _enemyVel; int _score; int _wave; int _ammunition; int _enemyCount; // wave limit int _enemiesSpawned; // amount of enemies spawned in this wave float _explosionExpandVel; float _explosionFadeVel; size_t _updates; double _skippedTime; double _secondSkipped; float _canonAngle; float _missileSpeed; float _enemySpeed; float _bgMoveVel; float _bgOriginMoveVel; float _floorHeight; float _playerSize; float _volume; std::string _playerName; std::vector<std::string> _highscores; sf::Color _playerColor; sf::Color _baseColor; sf::Color _buttonColor; sf::Color _buttonHoverColor; sf::Color _missileColor; sf::Color _baseExplodeColor; sf::Color _baseFadeColor; sf::Color _enemyExplodeColor; sf::Color _enemyFadeColor; sf::RectangleShape colBounds; Missiles _missiles; EntityR _canon; EntityR _bunkerBase; EntityC _bunkerTop; EntityC _playerFloor; std::vector<EntityR> _floor; std::vector<EntityC> _bases; std::vector<EntityC> _enemies; Particles _menuEffect; Particles _trails; // comet trails SoundEffect _shootSound; SoundEffect _explodeSound; SoundEffect _loseSound; SoundEffect _waveWinSound; std::vector<SoundEffect> _hoverSounds; ui::Button _quit; ui::Button _start; ui::Button _settings; ui::Button _about; ui::Button _highscoresBtn; ui::Button _back; ui::Button _continue; ui::Button _pauseQuit; ui::Button _home; ui::Button _volumeDown; ui::Button _volumeUp; ui::Button _lastHovered; // used to detect the button that was last hovered over void init(); void initFloor(); void initPlayer(); void initEnemy(); void initButtons(); void initText(); void initSounds(); void doEvents(); void reset(); // Load menus void loadHome(); void loadSettings(); void loadAbout(); void loadHighscores(); void loadPlaying(); void loadPaused(); void loadGameOver(); void loadWin(); void update(); void updateBG(); void updateMenuEffect(); void updateEnemies(); void render(); void renderHome(); void renderSettings(); void renderAbout(); void renderHighScores(); void renderPlaying(); void renderPause(); void renderGameOver(); void renderWin(); void renderMenuEffect(); void renderBG(); void doHover(ui::Button & button); void setVolume(); void spawnEnemy(); void removeEnemyAt(size_t index); void doCollisions(); void removeBaseAt(size_t index); void nextWave(); std::vector<std::string> split(std::string string, char splitParam); void getHighscores(); bool addHighscore(); void writeHighscores(); void sortHighscores(); public: Missile_Command(); ~Missile_Command(); void run(); }; Missile_Command.cpp (~800 Lines) #include "init.h" Missile_Command::Missile_Command(){ srand((size_t)time(0)); init(); } Missile_Command::~Missile_Command(){ // Destroy } void Missile_Command::init(){ _window.create(sf::VideoMode(SCRW, SCRH), "Missile Command"); _missileSize = sf::Vector2f(4, 4); _explosionExpandVel = 0.8f; _explosionFadeVel = 2.2f; _missileSpeed = 12.0f; _skippedTime = 0; _updates = 0; _secondSkipped = 0; _bgOriginMoveVel = 1.0f; _bgMoveVel = _bgOriginMoveVel; _enemySpeed = 1.0f; _volume = 30; _baseExplodeColor = sf::Color(0, 100, 255); _baseFadeColor = sf::Color(200, 50, 10); _enemyExplodeColor = sf::Color::Yellow; _enemyFadeColor = sf::Color::Magenta; _playerColor = sf::Color::White; _baseColor = sf::Color(56, 78, 90, 200); _buttonColor = sf::Color(255, 255, 255, 128); _buttonHoverColor = sf::Color((sf::Uint8)(_buttonColor.r / 1.5), (sf::Uint8)(_buttonColor.g / 1.5), (sf::Uint8)(_buttonColor.b / 1.5, 128)); _missileColor = sf::Color(255, 165, 0); _floorHeight = 50; _wallSize = sf::Vector2f(_floorHeight, _floorHeight * 2.0f); _playerSize = _floorHeight; _windowCenter = (sf::Vector2f)_window.getSize() / 2.0f; if (!_bgTex.loadFromFile("sprites/bg.png")) std::exit(-4); _bgSprite1.setTexture(_bgTex); _bgSprite2.setTexture(_bgTex); _bgSprite1.setPosition(0, 0); _bgSprite2.setPosition(_bgSprite1.getPosition().x - _bgTex.getSize().x, 0); initFloor(); initButtons(); initText(); initSounds(); initPlayer(); _playerCenterLoc = _bunkerTop.getPosition() + sf::Vector2f(_bunkerTop.getRadius(), _bunkerTop.getRadius()); reset(); _gameState = GameState::Home; // Temporary -> Home } void Missile_Command::initFloor(){ _floor.resize(3); _floor[0] = EntityR(sf::Vector2f((float)_window.getSize().x, _floorHeight), sf::Vector2f(0.0f, (float)_window.getSize().y - _floorHeight), _playerColor); // Main floor _floor[1] = EntityR(_wallSize, sf::Vector2f(0, _window.getSize().y - (_floorHeight + _wallSize.y)), _playerColor); // Left wall _floor[2] = EntityR(_wallSize, (sf::Vector2f)_window.getSize() - sf::Vector2f(_wallSize.x, _floorHeight + _wallSize.y), _playerColor); // Right wall _playerFloor = EntityC(_playerSize * 2.0f, 9, sf::Vector2f(_windowCenter.x - _playerSize * 2.0f, _window.getSize().y - _floorHeight * 2.0f), _playerColor); } void Missile_Command::initPlayer(){ _bunkerBase = EntityR(sf::Vector2f(_playerSize, _playerSize / 2.1f), sf::Vector2f(_windowCenter.x - _playerSize / 2.0f, _playerFloor.getPosition().y - _playerSize / 4.2f), _playerColor); _bunkerTop = EntityC(_playerSize / 2.0f, 40, sf::Vector2f(_windowCenter.x - _playerSize / 2.0f, _playerFloor.getPosition().y - _playerSize / 1.5f), _playerColor); _canon = EntityR(sf::Vector2f(_playerSize / 5.0f, _playerSize / 1.2f), sf::Vector2f(_windowCenter.x, _bunkerTop.getPosition().y + _bunkerTop.getRadius()), _playerColor); _canon.setOrigin(sf::Vector2f(_canon.getSize().x / 2.0f, _canon.getSize().y)); // Init bases _bases.resize(6); _bases[0] = EntityC(50, 10, sf::Vector2f(100, 520), _baseColor); _bases[1] = EntityC(50, 10, sf::Vector2f(200, 520), _baseColor); _bases[2] = EntityC(50, 10, sf::Vector2f(300, 520), _baseColor); _bases[3] = EntityC(50, 10, sf::Vector2f(600, 520), _baseColor); _bases[4] = EntityC(50, 10, sf::Vector2f(700, 520), _baseColor); _bases[5] = EntityC(50, 10, sf::Vector2f(800, 520), _baseColor); } void Missile_Command::initEnemy(){ _enemies.clear(); _enemyVel.clear(); } void Missile_Command::initButtons(){ _start = ui::Button("Start", 50, sf::Vector2f(15, 0), sf::Color::Black, _buttonColor, "fonts/segoeuil.ttf"); _settings = ui::Button("Settings", 50, sf::Vector2f(15, 80), sf::Color::Black, _buttonColor, "fonts/segoeuil.ttf"); _about = ui::Button("About", 50, sf::Vector2f(15, 160), sf::Color::Black, _buttonColor, "fonts/segoeuil.ttf"); _highscoresBtn = ui::Button("Highscores", 50, sf::Vector2f(15, 240), sf::Color::Black, _buttonColor, "fonts/segoeuil.ttf"); _quit = ui::Button("Quit", 50, sf::Vector2f(15, 320), sf::Color::Black, _buttonColor, "fonts/segoeuil.ttf"); _back = ui::Button("Back", 50, sf::Vector2f(15.0f, SCRH - 90.0f), sf::Color::Black, _buttonColor, "fonts/segoeuil.ttf"); _continue = ui::Button("Continue", 50, sf::Vector2f(400, 260), sf::Color::Black, _buttonColor, "fonts/segoeuil.ttf"); _pauseQuit = ui::Button("Home", 50, sf::Vector2f(250, 260), sf::Color::Black, _buttonColor, "fonts/segoeuil.ttf"); _volumeDown = ui::Button("<", 50, sf::Vector2f(15, 40), sf::Color::Black, _buttonColor, "fonts/segoeuil.ttf"); _volumeUp = ui::Button(">", 50, sf::Vector2f(130, 40), sf::Color::Black, _buttonColor, "fonts/segoeuil.ttf"); } void Missile_Command::initText(){ _font.loadFromFile("fonts/segoeuil.ttf"); _aboutText.setFont(_font); _volumeText.setFont(_font); _volumeInfoText.setFont(_font); _scoreText.setFont(_font); _inGameInfoText.setFont(_font); _gameOverText.setFont(_font); _winText.setFont(_font); _highscoreNamesText.setFont(_font); _highscoreScoresText.setFont(_font); _ammunitionText.setFont(_font); _aboutText.setString("Game is controlled solely through mouse input.\n\n Programming: Gaius Baltar\n Sound effects: Gaius Baltar"); _volumeText.setString(std::to_string(_volume)); _volumeText.setCharacterSize(50); _volumeText.setPosition(sf::Vector2f(65, 50)); _volumeInfoText.setString("Volume:"); _volumeInfoText.setCharacterSize(50); _volumeInfoText.setPosition(sf::Vector2f(15, 0)); _scoreText.setCharacterSize(50); _scoreText.setPosition(sf::Vector2f(250, 180)); _inGameInfoText.setCharacterSize(20); _gameOverText.setCharacterSize(50); _gameOverText.setPosition(sf::Vector2f(250, 100)); _gameOverText.setString("You lose..."); _winText.setCharacterSize(50); _winText.setPosition(sf::Vector2f(250, 100)); _winText.setString("You Win!"); _highscoreNamesText.setCharacterSize(30); _highscoreNamesText.setPosition(sf::Vector2f(50, 50)); _highscoreScoresText.setCharacterSize(30); _highscoreScoresText.setPosition(sf::Vector2f(500, 50)); _ammunitionText.setCharacterSize(50); _ammunitionText.setPosition(sf::Vector2f(475, 510)); _ammunitionText.setColor(sf::Color::Black); } void Missile_Command::initSounds(){ _shootSound = SoundEffect("sounds/shoot.wav", _volume); _explodeSound = SoundEffect("sounds/explode.wav", _volume); _loseSound = SoundEffect("sounds/lose.wav", _volume); _waveWinSound = SoundEffect("sounds/win.wav", _volume); _hoverSounds.resize(5); for (size_t i = 0; i < _hoverSounds.size(); i++){ _hoverSounds[i] = SoundEffect("sounds/hover" + std::to_string(i + 1) + ".wav", _volume); } } void Missile_Command::doEvents(){ while (_window.pollEvent(_event)){ if (_event.type == sf::Event::Closed){ _window.close(); } switch (_gameState){ case GameState::Home: if (_event.type == sf::Event::KeyPressed && _event.key.code == sf::Keyboard::Escape || _quit.isPressed(_event)){ _window.close(); } if (_start.isPressed(_event)) loadPlaying(); if (_settings.isPressed(_event)) loadSettings(); if (_about.isPressed(_event)) loadAbout(); if (_highscoresBtn.isPressed(_event)) loadHighscores(); if (_event.type == sf::Event::MouseMoved){ doHover(_quit); doHover(_start); doHover(_settings); doHover(_about); doHover(_highscoresBtn); } break; case GameState::Settings: if (_event.type == sf::Event::KeyPressed && _event.key.code == sf::Keyboard::Escape){ loadHome(); } if (_volumeDown.isPressed(_event) && _volume > 0){ _volume -= 1; _volumeText.setString(std::to_string((int)_volume)); setVolume(); } if (_volumeUp.isPressed(_event) && _volume < 100){ _volume += 1; _volumeText.setString(std::to_string((int)_volume)); setVolume(); } if (_back.isPressed(_event)) loadHome(); if (_event.type == sf::Event::MouseMoved){ doHover(_back); doHover(_volumeDown); doHover(_volumeUp); } break; case GameState::About: if (_event.type == sf::Event::KeyPressed && _event.key.code == sf::Keyboard::Escape){ loadHome(); } if (_back.isPressed(_event)) loadHome(); if (_event.type == sf::Event::MouseMoved){ doHover(_back); } break; case GameState::Highscores: if (_event.type == sf::Event::KeyPressed && _event.key.code == sf::Keyboard::Escape){ loadHome(); } if (_back.isPressed(_event)) loadHome(); if (_event.type == sf::Event::MouseMoved){ doHover(_back); } break; case GameState::Playing: if (_event.type == sf::Event::KeyPressed){ if (_event.key.code == sf::Keyboard::Space){ _missiles.explodeAtPosition(_playerFloor.getPosition() + sf::Vector2f(_playerFloor.getRadius(), _playerFloor.getRadius()), 0.5f, 7.0f, sf::Color(155, 115, 0), sf::Color(100, 0, 0)); } if (_event.key.code == sf::Keyboard::Escape) loadPaused(); } if (_event.type == sf::Event::MouseButtonPressed){ if (_event.mouseButton.button == sf::Mouse::Left && _ammunition > 0){ _shootSound.play(); _canonAngle = (float)mth::getAngleInRadians(_playerCenterLoc, (sf::Vector2f)sf::Mouse::getPosition(_window)); _missiles.fireMissile(mth::getVelocity(_canonAngle, _missileSpeed), (sf::Vector2f)sf::Mouse::getPosition(_window)); _ammunition--; } } break; case GameState::Paused: if (_event.type == sf::Event::KeyPressed && _event.key.code == sf::Keyboard::Escape){ loadPlaying(); } if (_continue.isPressed(_event)) loadPlaying(); if (_pauseQuit.isPressed(_event)) loadHome(); if (_event.type == sf::Event::MouseMoved){ doHover(_continue); doHover(_pauseQuit); } break; case GameState::GameOver: if (_event.type == sf::Event::KeyPressed && _event.key.code == sf::Keyboard::Escape){ loadHome(); } if (_pauseQuit.isPressed(_event)) loadHome(); if (_continue.isPressed(_event)){ reset(); loadPlaying(); } if (_event.type == sf::Event::MouseMoved){ doHover(_pauseQuit); doHover(_continue); } break; case GameState::Win: if (_event.type == sf::Event::KeyPressed && _event.key.code == sf::Keyboard::Escape){ loadPlaying(); } if (_pauseQuit.isPressed(_event)) loadHome(); if (_continue.isPressed(_event)){ loadPlaying(); } if (_event.type == sf::Event::MouseMoved){ doHover(_pauseQuit); doHover(_continue); } break; default: break; } } } void Missile_Command::reset(){ _wave = 0; nextWave(); _ammunition = 40; _score = 0; _missiles = Missiles(_missileSize, _playerCenterLoc, _missileColor, sf::Color::Red, _explosionExpandVel, _explosionFadeVel); initPlayer(); initEnemy(); _menuEffect.clear(); _trails.clear(); } void Missile_Command::loadHome(){ _gameState = GameState::Home; _bgMoveVel = _bgOriginMoveVel; reset(); } void Missile_Command::loadSettings(){ _gameState = GameState::Settings; _volumeText.setString(std::to_string((int)_volume)); _bgMoveVel = _bgOriginMoveVel; } void Missile_Command::loadAbout(){ _gameState = GameState::About; _bgMoveVel = _bgOriginMoveVel; } void Missile_Command::loadHighscores(){ _gameState = GameState::Highscores; _bgMoveVel = _bgOriginMoveVel; getHighscores(); sortHighscores(); std::string namesList; std::string scoresList; for (size_t i = 0; i < _highscores.size() - 1; i += 2){ namesList += std::to_string((i+2)/2) + ". " + _highscores[i] + "\n"; scoresList += _highscores[i + 1] + "\n"; } _highscoreNamesText.setString(namesList); _highscoreScoresText.setString(scoresList); } void Missile_Command::loadPlaying(){ _gameState = GameState::Playing; _menuEffect.clear(); _bgMoveVel = _bgOriginMoveVel / 3.0f; } void Missile_Command::loadPaused(){ _continue.setString("Continue"); _gameState = GameState::Paused; _bgMoveVel = _bgOriginMoveVel * 2.0f; } void Missile_Command::loadGameOver(){ _gameState = GameState::GameOver; _continue.setString("Restart"); _bgMoveVel = _bgOriginMoveVel * 2.0f; _enemies.clear(); _enemyVel.clear(); _missiles.clear(); _score += _ammunition * 10; _score += _bases.size() * 100; _scoreText.setString("Score: " + std::to_string(_score)); if (_playerName.size() <= 0){ std::cout << "\n\n\nPlease enter your name for the highscores list:\n\n\n"; std::getline(std::cin, _playerName); } addHighscore(); } void Missile_Command::loadWin(){ _gameState = GameState::Win; _continue.setString("Continue"); _bgMoveVel = _bgOriginMoveVel * 2.0f; _enemies.clear(); _enemyVel.clear(); _missiles.clear(); _score += _ammunition * 10; _score += _bases.size() * 100; _ammunition = 40; _scoreText.setString("Score: " + std::to_string(_score)); nextWave(); } void Missile_Command::update(){ switch (_gameState){ case GameState::Home: updateBG(); updateMenuEffect(); break; case GameState::Settings: updateBG(); updateMenuEffect(); break; case GameState::About: updateBG(); updateMenuEffect(); break; case GameState::Highscores: updateBG(); updateMenuEffect(); break; case GameState::Playing: updateBG(); _canon.setRotation(90 + (float)mth::getAngleInDegrees(_playerCenterLoc, (sf::Vector2f)sf::Mouse::getPosition(_window))); _inGameInfoText.setString("Score: " + std::to_string(_score) + " Wave: " + std::to_string(_wave) + " Enemies remaining: " + std::to_string(_enemyCount - _enemiesSpawned)); _ammunitionText.setString(std::to_string(_ammunition)); _missiles.update(_explodeSound); updateEnemies(); doCollisions(); if (rand() % 1000 <= _wave * 10 && _enemiesSpawned < _enemyCount){ spawnEnemy(); _enemiesSpawned++; } if (_bases.size() <= 0){ _loseSound.play(); loadGameOver(); } if (_enemies.size() <= 0 && _enemiesSpawned >= _enemyCount){ _waveWinSound.play(); loadWin(); } if (_wave > 10){ _waveWinSound.play(); loadGameOver(); loadHighscores(); } break; case GameState::Paused: _bgMoveVel = _bgOriginMoveVel * 2.0f; updateBG(); updateMenuEffect(); break; case GameState::GameOver: _bgMoveVel = _bgOriginMoveVel * 2.0f; updateBG(); updateMenuEffect(); break; case GameState::Win: _bgMoveVel = _bgOriginMoveVel * 2.0f; updateBG(); updateMenuEffect(); break; } } void Missile_Command::updateBG(){ _bgSprite1.setPosition(_bgSprite1.getPosition() + sf::Vector2f(_bgMoveVel, 0)); _bgSprite2.setPosition(_bgSprite2.getPosition() + sf::Vector2f(_bgMoveVel, 0)); if (_bgSprite1.getPosition().x > _window.getSize().x) _bgSprite1.setPosition(_bgSprite2.getPosition().x - _bgTex.getSize().x, 0); if (_bgSprite2.getPosition().x > _window.getSize().x) _bgSprite2.setPosition(_bgSprite1.getPosition().x - _bgTex.getSize().x, 0); } void Missile_Command::updateMenuEffect(){ if (rand() % 1000 <= 100){ _menuEffect.append(sf::Vector2f((float)(rand() % SCRW), (float)(rand() % SCRH)), 500, sf::Color(rand() % 256, rand() % 256, rand() % 256, 20)); } if (_menuEffect.particles.size() > 1000) _menuEffect.clear(); } void Missile_Command::updateEnemies(){ for (size_t i = 0; i < _enemies.size(); i++){ _enemies[i].setPosition(_enemies[i].getPosition() + _enemyVel[i]); if (rand() % 1000 < 200){ _trails.append(_enemies[i].getPosition() + sf::Vector2f((float)(rand() % 10), 0.0f), 500, sf::Color(200, rand() % 100 + 150, rand() % 100 + 150)); } } for (size_t i = 0; i < _trails.life.size(); i++){ _trails.life[i]--; if (_trails.life[i] <= 0){ _trails.removeAt(i); } } } void Missile_Command::render(){ _window.clear(CLEARCOLOR); switch (_gameState){ case GameState::Home: renderBG(); renderMenuEffect(); renderHome(); break; case GameState::Settings: renderBG(); renderMenuEffect(); renderSettings(); break; case GameState::About: renderBG(); renderMenuEffect(); renderAbout(); break; case GameState::Highscores: renderBG(); renderMenuEffect(); renderHighScores(); break; case GameState::Playing: renderBG(); _window.draw(colBounds); renderPlaying(); break; case GameState::Paused: renderBG(); renderMenuEffect(); renderPlaying(); renderPause(); break; case GameState::GameOver: renderBG(); renderMenuEffect(); renderPlaying(); renderGameOver(); break; case GameState::Win: renderBG(); renderMenuEffect(); renderPlaying(); renderWin(); break; } _window.display(); } void Missile_Command::renderHome(){ _window.draw(_start); _window.draw(_settings); _window.draw(_about); _window.draw(_highscoresBtn); _window.draw(_quit); } void Missile_Command::renderSettings(){ _window.draw(_back); _window.draw(_volumeDown); _window.draw(_volumeUp); _window.draw(_volumeText); _window.draw(_volumeInfoText); } void Missile_Command::renderAbout(){ _window.draw(_aboutText); _window.draw(_back); } void Missile_Command::renderHighScores(){ _window.draw(_back); _window.draw(_highscoreNamesText); _window.draw(_highscoreScoresText); } void Missile_Command::renderPlaying(){ for (auto item : _enemies) _window.draw(item); if (_trails.particles.size() > 0) _window.draw(&_trails.particles[0], _trails.particles.size(), sf::PrimitiveType::Points); _window.draw(_missiles); for (auto item : _bases) _window.draw(item); for (auto item : _floor) _window.draw(item); _window.draw(_bunkerBase); _window.draw(_bunkerTop); _window.draw(_canon); _window.draw(_playerFloor); _window.draw(_ammunitionText); _window.draw(_inGameInfoText); } void Missile_Command::renderPause(){ _window.draw(_continue); _window.draw(_pauseQuit); } void Missile_Command::renderGameOver(){ _window.draw(_pauseQuit); _window.draw(_gameOverText); _window.draw(_scoreText); } void Missile_Command::renderWin(){ _window.draw(_pauseQuit); _window.draw(_continue); _window.draw(_winText); _window.draw(_scoreText); } void Missile_Command::renderMenuEffect(){ if (_menuEffect.particles.size() > 0) _window.draw(&_menuEffect.particles[0], _menuEffect.particles.size(), sf::PrimitiveType::Triangles); } void Missile_Command::renderBG(){ _window.draw(_bgSprite1); _window.draw(_bgSprite2); } void Missile_Command::doHover(ui::Button & button){ if (button.isHovering(_event)){ if (_lastHovered.getString() != button.getString()){ button.setButtonFaceColor(_buttonHoverColor); _hoverSounds[rand() % _hoverSounds.size()].play(); _lastHovered.setString(button.getString()); } } else{ if (_lastHovered.getString() == button.getString()) _lastHovered.setString(" "); button.setButtonFaceColor(_buttonColor); } } void Missile_Command::setVolume(){ _shootSound.setVolume(_volume); _explodeSound.setVolume(_volume); _loseSound.setVolume(_volume); _waveWinSound.setVolume(_volume); for (int i = 0; i < _hoverSounds.size();i++) _hoverSounds[i].setVolume(_volume); } void Missile_Command::spawnEnemy(){ if (rand() % 2 == 0){ _enemies.push_back(EntityC(5, 5, sf::Vector2f((float)(rand() % 490), -10.0f), sf::Color::Red)); _enemyVel.push_back(sf::Vector2f(_enemySpeed / (rand() % 5 + 1), _enemySpeed)); } else{ _enemies.push_back(EntityC(5, 5, sf::Vector2f((float)(rand() % 490 + 500), -10.0f), sf::Color::Red)); _enemyVel.push_back(sf::Vector2f((_enemySpeed / (rand() % 5 + 1)) * -1, _enemySpeed)); } } void Missile_Command::removeEnemyAt(size_t index){ _enemies.erase(_enemies.begin() + index); _enemyVel.erase(_enemyVel.begin() + index); } void Missile_Command::doCollisions(){ // Missiles -> Enemies for (auto missile : _missiles.getExplosions()){ for (size_t i = 0; i < _enemies.size(); i++){ if (cd::doesIntersect(missile, _enemies[i])){ _explodeSound.play(); _missiles.explodeAtPosition(_enemies[i].getPosition() + sf::Vector2f(_enemies[i].getRadius(), _enemies[i].getRadius()), 1.05f, 0.3f, _enemyExplodeColor, _enemyFadeColor); _score += 10; removeEnemyAt(i); i--; } } } // Enemies -> Bases for (size_t i = 0; i < _enemies.size(); i++){ if (_enemies[i].getPosition().y > _window.getSize().y - 200){ for (size_t j = 0; j < _bases.size(); j++){ if (_enemies.size() > 0 && cd::doesIntersect(_enemies[i], _bases[j])){ _explodeSound.play(); _missiles.explodeAtPosition(_bases[j].getPosition() + sf::Vector2f(_bases[j].getRadius(), _bases[j].getRadius()), 1.5f, 3.0f, _baseExplodeColor, _baseFadeColor); removeBaseAt(j); removeEnemyAt(i); _score += 100 / (_bases.size() + 1); std::cout << "sup\n"; i = i - 1 > 0 ? i - 1 : i; break; } } } } // Enemies -> Floor for (size_t i = 0; i < _enemies.size(); i++){ if (_enemies[i].getPosition().y > _window.getSize().y - 200){ if (_enemies.size() > 0 && _enemies[i].getPosition().y > _window.getSize().y - 60){ _explodeSound.play(); _missiles.explodeAtPosition(_enemies[i].getPosition() + sf::Vector2f(_enemies[i].getRadius(), _enemies[i].getRadius()), 1.05f, 0.3f, _enemyExplodeColor, _enemyFadeColor); removeEnemyAt(i); _score -= 10; i = i - 1 > 0 ? i - 1 : i; continue; } else if (_enemies.size() > 0 && cd::doesIntersect(_enemies[i], _playerFloor)){ _explodeSound.play(); _missiles.explodeAtPosition(_enemies[i].getPosition() + sf::Vector2f(_enemies[i].getRadius(), _enemies[i].getRadius()), 1.05f, 0.3f, _enemyExplodeColor, _enemyFadeColor); removeEnemyAt(i); if (_ammunition >= 5) _ammunition -= 5; else _ammunition = 0; i = i - 1 > 0 ? i - 1 : i; continue; } } } } void Missile_Command::removeBaseAt(size_t index){ _bases.erase(_bases.begin() + index); } void Missile_Command::nextWave(){ _wave++; _enemyCount = (_wave * _wave) + (_wave * _wave) + 10; _enemySpeed = _wave / 10.0f + 0.5f; _enemiesSpawned = 0; } std::vector<std::string> Missile_Command::split(std::string string, char splitParam){ std::vector<std::string> splitString; int strBegin = 0; for (size_t i = 0; i < string.size(); i++){ if (string[i] == splitParam && i != 0){ splitString.push_back(string.substr(strBegin, i)); if (string.size() > i + 1) strBegin = i + 1; } if (string.size() <= i + 1){ splitString.push_back(string.substr(strBegin, i)); } } return splitString; } void Missile_Command::getHighscores(){ // read file into program _highscores.clear(); std::string line; std::ifstream inputStream("highscores.txt"); if (inputStream.is_open()){ while (std::getline(inputStream, line)){ std::vector<std::string> toIns{ split(line, '|') }; _highscores.insert(_highscores.end(), toIns.begin(), toIns.end()); } inputStream.close(); } for (size_t i = 0; i < _highscores.size() - 1; i+=2){ std::cout << _highscores[i] << " " << _highscores[i + 1] << "\n"; } } bool Missile_Command::addHighscore(){ bool isAdded; getHighscores(); // Add score _highscores.push_back(_playerName); _highscores.push_back(std::to_string(_score)); // Sort all scores sortHighscores(); if (atoi(_highscores[_highscores.size() - 1].c_str()) == _score) isAdded = false; else isAdded = true; // Remove lowest score if (_highscores.size() > 20){ _highscores.resize(_highscores.size() - 2); } // Write highscores to file writeHighscores(); return isAdded; } // write highscores into file void Missile_Command::writeHighscores(){ std::ofstream outputStream("highscores.txt"); if (outputStream.is_open()) { for (size_t i = 0; i < _highscores.size(); i += 2){ outputStream << _highscores[i] << '|' << _highscores[i + 1] << '\n'; } outputStream.close(); } } void Missile_Command::sortHighscores(){ // sort highscores int j; std::string tmp1; std::string tmp2; for (size_t i = 3; i < _highscores.size(); i += 2){ j = i; while (j > 1 && std::atoi(_highscores[j - 2].c_str()) < std::atoi(_highscores[j].c_str())) { tmp1 = _highscores[j]; tmp2 = _highscores[j - 1]; _highscores[j] = _highscores[j - 2]; _highscores[j - 1] = _highscores[j - 3]; _highscores[j - 3] = tmp2; _highscores[j - 2] = tmp1; j -= 2; } } } void Missile_Command::run(){ while (_window.isOpen()){ const double elapsedTime = _clock.getElapsedTime().asMicroseconds() / 1000.0; _skippedTime += elapsedTime; _secondSkipped += elapsedTime; _clock.restart(); while (_secondSkipped >= SECOND){ std::cout << _updates << " Updates at an average interval of " << _secondSkipped / _updates << "ms.\n"; _updates = 0; _secondSkipped -= SECOND; } while (_skippedTime >= INTERVAL){ _updates++; _skippedTime -= INTERVAL; doEvents(); update(); } render(); } } Entity.h #pragma once template<class T> class Entity : public T { public: //Constructors Entity(sf::Vector2f size, sf::Vector2f pos, sf::Color color) : T(size){ setPosition(pos); setFillColor(color); } Entity(float radius, size_t pointCount, sf::Vector2f pos, sf::Color color) : T(radius){ setPointCount(pointCount); setPosition(pos); setFillColor(color); } Entity(float width, float height, float x, float y) : T(sf::Vector2f(width, height)){ setPosition(x, y); } Entity() : T(){}; sf::Vector2i getGridPosition() const; void setGridPosition(size_t x, size_t y); void setOutline(float thickness, const sf::Color & color); }; // Definitions ---------------------------------------------------------------------------- Definitions enum class Side{ Top, Bottom, Left, Right }; struct Particles{ Particles(){} std::vector<sf::Vertex> particles; std::vector<float> life; void append(sf::Vector2f pos, float life, sf::Color color){ sf::Vertex vertex(pos, color); this->life.push_back(life); particles.push_back(vertex); } void append(sf::Vector2f pos){ sf::Vertex vertex(pos); this->life.push_back(100000.01f); particles.push_back(vertex); } void removeAt(size_t index){ life.erase(life.begin() + index); particles.erase(particles.begin() + index); } void clear(){ life.clear(); particles.clear(); } }; typedef Entity<sf::RectangleShape> EntityR; typedef Entity<sf::CircleShape> EntityC; template<class T> sf::Vector2i Entity<T>::getGridPosition() const{ return sf::Vector2i(getPosition() / BLOCKSIZE); } template<class T> void Entity<T>::setGridPosition(size_t x, size_t y){ setPosition(x * BLOCKSIZE, y * BLOCKSIZE); } template<class T> void Entity<T>::setOutline(float thickness, const sf::Color & color){ setOutlineThickness(thickness); setOutlineColor(color); } Entity.cpp #include "init.h" Button.h #pragma once namespace ui{ class Button : public sf::Drawable { EntityR buttonFace; sf::Font font; sf::Text text; public: Button(std::string text, size_t textSize, sf::Vector2f pos, sf::Color textColor, sf::Color buttonFaceColor, std::string font); Button& operator=(Button other){ font = other.font; text = other.text; buttonFace = other.buttonFace; text.setFont(font); return *this; } Button(){} std::string getString() const; EntityR getButtonFaceObj() const; sf::Vector2f getPosition() const; sf::Vector2f getButtonFaceSize() const; size_t getTextSize() const; sf::Color getTextColor() const; sf::Color getButtonFaceColor() const; void setString(std::string text); void setPosition(const sf::Vector2f & pos); void setTextSize(size_t textSize); void setTextColor(const sf::Color & color); void setButtonFaceColor(const sf::Color & color); bool isPressed(const sf::Event & event); bool isHovering(const sf::Event & event); virtual void draw(sf::RenderTarget & target, sf::RenderStates states) const; }; }   Button.cpp (Advice on how I could improve this class would be great) #include "init.h" ui::Button::Button(std::string text, size_t textSize, sf::Vector2f pos, sf::Color textColor, sf::Color buttonFaceColor, std::string font){ this->font.loadFromFile(font); this->text.setFont(this->font); setTextSize(textSize); setString(text); setPosition(pos); setTextColor(textColor); setButtonFaceColor(buttonFaceColor); } std::string ui::Button::getString() const{ return text.getString(); } EntityR ui::Button::getButtonFaceObj() const{ return buttonFace; } sf::Vector2f ui::Button::getPosition() const{ return buttonFace.getPosition(); } sf::Vector2f ui::Button::getButtonFaceSize() const{ return buttonFace.getSize(); } size_t ui::Button::getTextSize() const{ return text.getCharacterSize(); } sf::Color ui::Button::getTextColor() const{ return text.getColor(); } sf::Color ui::Button::getButtonFaceColor() const{ return buttonFace.getFillColor(); } void ui::Button::setString(std::string text){ this->text.setString(text); setTextSize(getTextSize()); } void ui::Button::setPosition(const sf::Vector2f & pos){ text.setPosition(pos + sf::Vector2f(10, 10)); float left = text.getGlobalBounds().left; float top = text.getGlobalBounds().top; buttonFace.setPosition(left - 10, top - 10); } void ui::Button::setTextSize(size_t textSize){ text.setCharacterSize(textSize); float left = text.getGlobalBounds().left; float top = text.getGlobalBounds().top; float width = text.getGlobalBounds().width; float height = text.getGlobalBounds().height; buttonFace.setSize(sf::Vector2f(width + 20, height + 20)); buttonFace.setPosition(left - 10, top - 10); } void ui::Button::setTextColor(const sf::Color & color){ text.setColor(color); } void ui::Button::setButtonFaceColor(const sf::Color & color){ buttonFace.setFillColor(color); } bool ui::Button::isPressed(const sf::Event & event){ if (event.type == sf::Event::MouseButtonPressed){ if (event.mouseButton.button == sf::Mouse::Button::Left){ sf::Vector2f mousePos((float)event.mouseButton.x, (float)event.mouseButton.y); if (cd::doesIntersect(mousePos, buttonFace)) return true; } } return false; } bool ui::Button::isHovering(const sf::Event & event){ sf::Vector2f mousePos((float)event.mouseMove.x, (float)event.mouseMove.y); if (cd::doesIntersect(mousePos, buttonFace)) return true; return false; } void ui::Button::draw(sf::RenderTarget & target, sf::RenderStates states) const{ target.draw(buttonFace); target.draw(text); } Missiles.h #pragma once class Missiles : public sf::Drawable { std::vector<sf::RectangleShape> missiles; std::vector<EntityC> explosions; std::vector<sf::Vector2f> missileVelocities; std::vector<sf::Vector2f> explodePositions; std::vector<float> expandVelocities; std::vector<float> fadeVelocities; std::vector<sf::Color> explodeColors; std::vector<sf::Color> fadeColors; sf::RectangleShape model; sf::Color standardFadeColor; float standardFadeVel; float standardExpandVel; public: Missiles(const sf::Vector2f & size, const sf::Vector2f & origin, const sf::Color & color, const sf::Color & fadeColor, float expandVelocity, float fadeVelocity); Missiles(){}; std::vector<EntityC> getExplosions() const{ return explosions; } void update(SoundEffect & sound); void clear(); void removeMissileAt(size_t index); void removeExplosionAt(size_t index); void explodeAtPosition(const sf::Vector2f & pos, float fadeVel, float expandVel, sf::Color color, sf::Color fadeColor); void fireMissile(const sf::Vector2f & velocity, const sf::Vector2f & explodePos); virtual void draw(sf::RenderTarget & target, sf::RenderStates states) const; }; Missiles.cpp #include "init.h" Missiles::Missiles(const sf::Vector2f & size, const sf::Vector2f & origin, const sf::Color & color, const sf::Color & fadeColor, float expandVelocity, float fadeVelocity){ model.setSize(size); model.setPosition(origin); model.setFillColor(color); standardFadeVel = fadeVelocity; standardExpandVel = expandVelocity; standardFadeColor = fadeColor; clear(); } void Missiles::update(SoundEffect & sound){ // Move missiles for (size_t i = 0; i < missiles.size(); i++){ missiles[i].move(missileVelocities[i]); } // Test for boundary intersections for (size_t i = 0; i < missiles.size(); i++){ if (cd::boundaryIntersect(missiles[i], EntityR((float)SCRW, (float)SCRH, 0, 0), Side::Top) || cd::boundaryIntersect(missiles[i], EntityR((float)SCRW, (float)SCRH, 0, 0), Side::Bottom) || cd::boundaryIntersect(missiles[i], EntityR((float)SCRW, (float)SCRH, 0, 0), Side::Left) || cd::boundaryIntersect(missiles[i], EntityR((float)SCRW, (float)SCRH, 0, 0), Side::Right)) { removeMissileAt(i); } } // Expand explosions and remove explosions that have completed their cycle for (size_t i = 0; i < explosions.size(); i++){ explosions[i].setRadius(explosions[i].getRadius() + expandVelocities[i]); explosions[i].setPosition(explosions[i].getPosition() - sf::Vector2f(expandVelocities[i], expandVelocities[i])); if (explodeColors[i].a >= fadeVelocities[i]){ explodeColors[i].a -= fadeVelocities[i]; if (explodeColors[i].r > fadeColors[i].r) explodeColors[i].r--; else if (explodeColors[i].r < fadeColors[i].r) explodeColors[i].r++; if (explodeColors[i].g > fadeColors[i].g) explodeColors[i].g--; else if (explodeColors[i].g < fadeColors[i].g) explodeColors[i].g++; if (explodeColors[i].b > fadeColors[i].b) explodeColors[i].b--; else if (explodeColors[i].b < fadeColors[i].b) explodeColors[i].b++; explosions[i].setFillColor(explodeColors[i]); } else{ removeExplosionAt(i); i = 0; } } // Test if a missile should explode bool willExplode = false; size_t index = 0; for (size_t i = 0; i < missiles.size(); i++){ sf::Vector2f missilePos = missiles[i].getPosition(); if (missileVelocities[i].x <= 0 && missileVelocities[i].y <= 0 && missilePos.x <= explodePositions[i].x && missilePos.y <= explodePositions[i].y || missileVelocities[i].x <= 0 && missileVelocities[i].y > 0 && missilePos.x <= explodePositions[i].x && missilePos.y > explodePositions[i].y || missileVelocities[i].x > 0 && missileVelocities[i].y <= 0 && missilePos.x > explodePositions[i].x && missilePos.y <= explodePositions[i].y || missileVelocities[i].x > 0 && missileVelocities[i].y > 0 && missilePos.x > explodePositions[i].x && missilePos.y > explodePositions[i].y){ willExplode = true; index = i; } if (willExplode) break; } if (willExplode){ sound.play(); fadeVelocities.push_back(standardFadeVel); fadeColors.push_back(standardFadeColor); expandVelocities.push_back(standardExpandVel); explodeColors.push_back(model.getFillColor()); explosions.push_back(EntityC(model.getSize().x/2.0f, 30, explodePositions[index], explodeColors[explodeColors.size() - 1])); removeMissileAt(index); } } void Missiles::clear(){ missiles.clear(); explosions.clear(); missileVelocities.clear(); explodePositions.clear(); expandVelocities.clear(); fadeVelocities.clear(); explodeColors.clear(); fadeColors.clear(); } void Missiles::removeMissileAt(size_t index){ missiles.erase(missiles.begin() + index); missileVelocities.erase(missileVelocities.begin() + index); explodePositions.erase(explodePositions.begin() + index); } void Missiles::removeExplosionAt(size_t index){ explosions.erase(explosions.begin() + index); explodeColors.erase(explodeColors.begin() + index); fadeVelocities.erase(fadeVelocities.begin() + index); fadeColors.erase(fadeColors.begin() + index); expandVelocities.erase(expandVelocities.begin() + index); } void Missiles::explodeAtPosition(const sf::Vector2f & pos, float fadeVel, float expandVel, sf::Color color, sf::Color fadeColor){ fadeVelocities.push_back(fadeVel); fadeColors.push_back(fadeColor); expandVelocities.push_back(expandVel); explodeColors.push_back(color); explosions.push_back(EntityC(model.getSize().x / 2.0f, 30, pos, explodeColors[explodeColors.size() - 1])); } void Missiles::fireMissile(const sf::Vector2f & velocity, const sf::Vector2f & explodePos){ explodePositions.push_back(explodePos); missileVelocities.push_back(velocity); missiles.push_back(model); } void Missiles::draw(sf::RenderTarget & target, sf::RenderStates states) const{ for (auto item : missiles){ target.draw(item); } for (auto item : explosions){ target.draw(item); } } Collision_Detection.h #pragma once enum class Side; namespace cd{ // A simple struct to make it easier to do stuff with lines struct Line; // A simple function to determine whether entity1 is within entity2 bool doesIntersect(EntityR entity1, EntityR entity2); bool doesIntersect(EntityC entity1, EntityR entity2); bool doesIntersect(EntityC entity1, EntityC entity2); bool doesIntersect(sf::Vector2f point, EntityR entity); // Test if an entity is outside the entity bounds bool boundaryIntersect(sf::RectangleShape entity, sf::RectangleShape bounds, Side side); bool boundaryIntersect(sf::CircleShape entity, sf::RectangleShape bounds, Side side); // Test for an intersection between two lines bool lineIntersect(Line line, sf::Vector2f pointMoving, float diam); // Test if two entities will intersect with the current velocity vel bool willIntercept(const EntityR & entityMoving, const EntityR & entityStatic, sf::Vector2f vel, Side side); } Collision_Detection.cpp #include "init.h" struct cd::Line{ Line(){} Line(sf::Vector2f pointA, sf::Vector2f pointB) : A(pointA), B(pointB){} sf::Vector2f A; sf::Vector2f B; }; bool cd::doesIntersect(EntityR entity1, EntityR entity2){ if (entity1.getPosition().x <= entity2.getPosition().x + entity2.getSize().x && entity1.getPosition().x + entity1.getSize().x >= entity2.getPosition().x && entity1.getPosition().y <= entity2.getPosition().y + entity2.getSize().y && entity1.getPosition().y + entity1.getSize().y >= entity2.getPosition().y) return true; return false; } bool cd::doesIntersect(EntityC entity1, EntityR entity2){ return false; } bool cd::doesIntersect(EntityC entity1, EntityC entity2){ sf::Vector2f origin1 = entity1.getPosition() + sf::Vector2f(entity1.getRadius(), entity1.getRadius()); sf::Vector2f origin2 = entity2.getPosition() + sf::Vector2f(entity2.getRadius(), entity2.getRadius()); float radius1 = entity1.getRadius(); float radius2 = entity2.getRadius(); if (sqrt((origin2.x - origin1.x) * (origin2.x - origin1.x) + (origin2.y - origin1.y) * (origin2.y - origin1.y)) < (radius1 + radius2)){ return true; } return false; } bool cd::doesIntersect(sf::Vector2f point, EntityR entity){ if (point.x >= entity.getPosition().x && point.x <= entity.getPosition().x + entity.getSize().x && point.y >= entity.getPosition().y && point.y <= entity.getPosition().y + entity.getSize().y) return true; return false; } bool cd::boundaryIntersect(sf::RectangleShape entity, sf::RectangleShape bounds, Side side){ if (side == Side::Top && entity.getPosition().y < bounds.getPosition().y) return true; else if (side == Side::Bottom && entity.getPosition().y + entity.getSize().y > bounds.getPosition().y + bounds.getSize().y) return true; else if (side == Side::Left && entity.getPosition().x < bounds.getPosition().x) return true; else if (side == Side::Right && entity.getPosition().x + entity.getSize().x > bounds.getPosition().x + bounds.getSize().x) return true; return false; } bool cd::boundaryIntersect(sf::CircleShape entity, sf::RectangleShape bounds, Side side){ if (side == Side::Top && entity.getPosition().y < bounds.getPosition().y) return true; else if (side == Side::Bottom && entity.getPosition().y + entity.getRadius() * 2.0f > bounds.getPosition().y + bounds.getSize().y) return true; else if (side == Side::Left && entity.getPosition().x < bounds.getPosition().x) return true; else if (side == Side::Right && entity.getPosition().x + entity.getRadius() * 2.0f > bounds.getPosition().x + bounds.getSize().x) return true; return false; } bool cd::lineIntersect(Line line, sf::Vector2f pointMoving, float diam){ if (line.A.x == line.B.x && pointMoving.x >= line.A.x - diam / 2.0f && pointMoving.x <= line.A.x + diam / 2.0f && pointMoving.y >= line.A.y && pointMoving.y <= line.B.y) return true; if (line.A.y == line.B.y && pointMoving.y >= line.A.y - diam / 2.0f && pointMoving.y <= line.A.y + diam / 2.0f && pointMoving.x >= line.A.x && pointMoving.x <= line.B.x) return true; return false; } bool cd::willIntercept(const EntityR & entityMoving, const EntityR & entityStatic, sf::Vector2f vel, Side side){ float m, b; sf::Vector2f emCenter(entityMoving.getPosition() + (entityMoving.getSize() / 2.0f)); m = ((emCenter.y + vel.y) - emCenter.y) / ((emCenter.x + vel.x) - emCenter.x); b = emCenter.y - m * emCenter.x; Line line; sf::Vector2f start(emCenter); sf::Vector2f end; if (side <= Side::Bottom){ line.A = entityStatic.getPosition() + sf::Vector2f(0, entityStatic.getSize().y * (int)side); line.B = entityStatic.getPosition() + sf::Vector2f(entityStatic.getSize().x, entityStatic.getSize().y * (int)side); end = sf::Vector2f((float)(int)((vel.y + emCenter.y - b) / m), vel.y + emCenter.y); if (side == Side::Top){ for (float y = 0; y <= vel.y; y += 0.1f){ if (lineIntersect(line, sf::Vector2f((float)(int)((y + emCenter.y - b) / m), y + emCenter.y), entityMoving.getSize().y)) return true; } } else if (side == Side::Bottom){ for (float y = 0; y >= vel.y; y -= 0.1f){ if (lineIntersect(line, sf::Vector2f((float)(int)((y + emCenter.y - b) / m), y + emCenter.y), entityMoving.getSize().y)) return true; } } } else if (side >= Side::Left){ int tmpSide = (int)side - (int)Side::Left; line.A = entityStatic.getPosition() + sf::Vector2f(entityStatic.getSize().x * tmpSide, 0); line.B = entityStatic.getPosition() + sf::Vector2f(entityStatic.getSize().x * tmpSide, entityStatic.getSize().y); end = sf::Vector2f(vel.x + emCenter.x, (float)(int)(m * (vel.x + emCenter.x) + b)); if (side == Side::Left){ for (float x = 0; x <= vel.x; x += 0.1f){ if (lineIntersect(line, sf::Vector2f(x + emCenter.x, (float)(int)(m * (x + emCenter.x) + b)), entityMoving.getSize().x)) return true; } } else if (side == Side::Right){ for (float x = 0; x >= vel.x; x -= 0.1f){ if (lineIntersect(line, sf::Vector2f(x + emCenter.x, (float)(int)(m * (x + emCenter.x) + b)), entityMoving.getSize().x)) return true; } } } return false; } Math.h #pragma once namespace mth{ // Basically pi const double PI = 3.14159265358979323846264338327950288419716939937510582097494459; // Get the angle between two vectors in degrees double getAngleInDegrees(const sf::Vector2f & entityStaticCenter, const sf::Vector2f & entityMovingCenter); // Get the angle between two vectors in radians double getAngleInRadians(const sf::Vector2f & entityStaticCenter, const sf::Vector2f & entityMovingCenter); // Calculate directional veloctiy, given radians and global velocity sf::Vector2f getVelocity(double radians, double vel); } Math.cpp #include "init.h" double mth::getAngleInDegrees(const sf::Vector2f & entityStaticCenter, const sf::Vector2f & entityMovingCenter){ double winkel = atan2((entityMovingCenter.y - (entityStaticCenter.y)), (entityMovingCenter.x - (entityStaticCenter.x))); winkel *= 180 / PI; return winkel; } double mth::getAngleInRadians(const sf::Vector2f & entityStaticCenter, const sf::Vector2f & entityMovingCenter){ return atan2f((entityMovingCenter.y - (entityStaticCenter.y)), (entityMovingCenter.x - (entityStaticCenter.x))); } sf::Vector2f mth::getVelocity(double radians, double vel){ return sf::Vector2f((float)cos(radians) * (float)vel, (float)sin(radians) * (float)vel); } SoundEffect.h #pragma once class SoundEffect { sf::SoundBuffer buffer; sf::Sound sound; public: SoundEffect(std::string filePath, float volume); SoundEffect(std::string filePath, sf::Sound sound); SoundEffect(){ } SoundEffect& operator=(SoundEffect other){ buffer = other.buffer; sound = other.sound; sound.setBuffer(buffer); return *this; } float getVolume() const; void setVolume(float volume); void play(); void pause(); void stop(); }; SoundEffect.cpp #include "init.h" SoundEffect::SoundEffect(std::string filePath, float volume){ if (!buffer.loadFromFile(filePath)) std::exit(-3); sound.setBuffer(buffer); sound.setVolume(volume); } SoundEffect::SoundEffect(std::string filePath, sf::Sound sound){ if (!buffer.loadFromFile(filePath)) std::exit(-3); this->sound = sound; this->sound.setBuffer(buffer); } float SoundEffect::getVolume() const{ return sound.getVolume(); } void SoundEffect::setVolume(float volume){ sound.setVolume(volume); } void SoundEffect::play(){ sound.play(); } void SoundEffect::pause(){ sound.pause(); } void SoundEffect::stop(){ sound.stop(); } Thank you for your time and for reading!
  15. Ok, I think I found the source of the problem. _quit = ui::Button("Quit", 32, sf::Vector2f(0, 200), sf::Color::Black, "segoeuil.ttf"); _start = ui::Button("Start", 32, sf::Vector2f(0, 300), sf::Color::Black, "segoeuil.ttf"); For some reason, re instantiating the Button objects and then drawing them gives me the out of range error. I found that if I immediately instantiated the Button objects the error wouldn't appear.   I made a minimal working example to demonstrate.   main.cpp: #include <SFML/Graphics.hpp> class Text : public sf::Drawable { sf::Font font; sf::Text text; public: Text(std::string string){ if (!font.loadFromFile("segoeuil.ttf")) // Nothing wrong with loading the font std::exit(-1); text = sf::Text(string, font, 30); } Text(){ } virtual void draw(sf::RenderTarget & target, sf::RenderStates states) const{ target.draw(text); } }; int main(){ sf::RenderWindow window(sf::VideoMode(800, 600), "Text test"); Text text("Text"); //Text text; -> same result // Error (on draw) -> Access Violation // Commenting this line out, solves the problem text = Text("Text"); while (window.isOpen()){ window.clear(); window.draw(text); window.display(); } return 0; } Edit: Solved! I was missing a = operator overload, because SFML stores it's fonts as pointers in it's text objects.   so this is what I added to make the above code work: Text& operator=(Text other){ font = other.font; text = other.text; text.setFont(font); return *this; }