Jump to content
  • Advertisement

Gaius Baltar

Member
  • Content Count

    32
  • Joined

  • Last visited

Everything posted by Gaius Baltar

  1. I'm trying to change the data in a Texture2D with Map/Unmap and am running into an issue where the texture seems to only appear in the top 5th of the screen and the rest is just random pixels. (screenshot for clarification) Here's some code: uint32_t* m_colorBuffer; //buffer to fill the texture with random colors D3D11_SUBRESOURCE_DATA m_textureData; ID3D11Texture2D* m_texture; D3D11_MAPPED_SUBRESOURCE mappedResource; m_deviceContext->Map(m_texture, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); uint32_t rowSize = 256 * 4; BYTE* mappedData = reinterpret_cast<BYTE*>(mappedResource.pData); for (int i = 0; i < 256; i++) { memcpy(mappedData, &(m_colorBuffer[i*rowSize]), rowSize); mappedData += mappedResource.RowPitch; } m_deviceContext->Unmap(m_texture, 0); Can Someone please tell me what I'm doing wrong here? I'd be happy to supply more code if needed.
  2. Thanks... I knew it was gonna be something simple...
  3. Gaius Baltar

    Issue with personal DirectX Framework

    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:  
  4. 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.
  5. Gaius Baltar

    c# method question

      It appears, I was wrong, go with Nypyren's suggestion, in this case it would be the better solution overall.
  6. Gaius Baltar

    c# method question

    Disregard this post. 
  7. Gaius Baltar

    c# method question

    Disregard this post
  8. Gaius Baltar

    Line vs Triangle collision in 3D

    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.
  9. Gaius Baltar

    Line vs Triangle collision in 3D

    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: 
  10. 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:   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!
  11. Gaius Baltar

    Missile Command code review request

    I figured that, but I thought Visual Studio somehow did it differently. Suppose not.
  12. Gaius Baltar

    Missile Command code review request

    Oh, I missed the static part. Thanks for clarification.
  13. Gaius Baltar

    Missile Command code review request

    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?
  14. Gaius Baltar

    Missile Command code review request

      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(?)[/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.  
  15. Gaius Baltar

    3D Graphics with C#

    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".
  16. Gaius Baltar

    Missile Command code review request

      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.
  17. Gaius Baltar

    Drawing Text Access Violation using SFML

    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; }
  18. call stack:   > sfml-graphics-d-2.dll!std::_Tree<std::_Tmap_traits<unsigned int,sf::Font::Page,std::less<unsigned int>,std::allocator<std::pair<unsigned int const ,sf::Font::Page> >,0> >::_Lbound(const unsigned int & _Keyval) Line 2109 C++   sfml-graphics-d-2.dll!std::_Tree<std::_Tmap_traits<unsigned int,sf::Font::Page,std::less<unsigned int>,std::allocator<std::pair<unsigned int const ,sf::Font::Page> >,0> >::lower_bound(const unsigned int & _Keyval) Line 1575 C++   sfml-graphics-d-2.dll!std::map<unsigned int,sf::Font::Page,std::less<unsigned int>,std::allocator<std::pair<unsigned int const ,sf::Font::Page> > >::operator[](const unsigned int & _Keyval) Line 226 C++   sfml-graphics-d-2.dll!sf::Font::getGlyph(unsigned int codePoint, unsigned int characterSize, bool bold) Line 295 C++   sfml-graphics-d-2.dll!sf::Text::ensureGeometryUpdate() Line 269 C++   sfml-graphics-d-2.dll!sf::Text::getLocalBounds() Line 214 C++   Engine.exe!Text::getLocalBounds() Line 41 C++   Engine.exe!Button::setTextSize(unsigned int textSize) Line 56 C++   Engine.exe!Button::setString(std::basic_string<char,std::char_traits<char>,std::allocator<char> > text) Line 47 C++   Engine.exe!Button::Button(std::basic_string<char,std::char_traits<char>,std::allocator<char> > text, unsigned int textSize, sf::Vector2<float> pos, sf::Color textColor, sf::Color buttonFaceColor) Line 7 C++   Engine.exe!Missile_Command::initButtons() Line 56 C++   Engine.exe!Missile_Command::init() Line 29 C++   Engine.exe!Missile_Command::Missile_Command() Line 6 C++   Engine.exe!main() Line 4 C++   [External Code]   [Frames below may be incorrect and/or missing, no symbols loaded for kernel32.dll]   code:   void Text::draw(sf::RenderTarget & target, sf::RenderStates states) const{ target.draw(text); }   which was called by:   void Button::draw(sf::RenderTarget & target, sf::RenderStates states) const{ target.draw(buttonFace); target.draw(text); }   No pointers were used to my knowledge.     The exact error is as follows: Unhandled exception at 0x0F21F95C (sfml-graphics-d-2.dll) in Engine.exe: 0xC0000005: Access violation reading location 0x0000000D.   I've been trying to solve this for quite some time now. I think it has something to do with my sf::Text object not being properly initialized or something, but I couldn't find anything.     Here's the my Text class if anyone's interested:   [spoiler] #include "init.h"   Text::Text(sf::Vector2f pos, size_t size, sf::Color color, std::string text, std::string font){ setPosition(pos); setSize(size); setColor(color); setText(text); setFont(font); }   Text::Text(std::string font, std::string text){ setText(text); setFont(font); }   std::string Text::getString() const{ return text.getString(); }   sf::Text Text::getText() const{ return text; }   sf::Color Text::getColor() const{ return text.getColor(); }   int Text::getSize() const{ return text.getCharacterSize(); }   sf::Vector2f Text::getPosition() const{ return text.getPosition(); }   sf::Font Text::getFont() const{ return font; }   sf::FloatRect Text::getLocalBounds() const{ return text.getLocalBounds(); }   void Text::setText(std::string text){ if (text != "" && text != " ") this->text.setString(text); }   void Text::setColor(sf::Color color){ text.setColor(color); }   void Text::setSize(size_t size){ text.setCharacterSize(size); }   void Text::setPosition(sf::Vector2f pos){ text.setPosition(pos); }   void Text::setFont(std::string file){ if (!font.loadFromFile(file)){ std::exit(-1); } text.setFont(font); }   void Text::draw(sf::RenderTarget & target, sf::RenderStates states) const{ target.draw(text); } [/spoiler]   "text" and "font" are private class members.
  19. Gaius Baltar

    Beginner creating a game by myself

    Just use Unity or UDK
  20. Gaius Baltar

    Breakout code review request

        Oh, yeah, high scores. I wanted to do that, but I was missing the required menu system for my game. I'll probably just save the result to a file an be done with it. Thanks for clarifying.
  21. This is my third review request on this forum: Snake Pong   Game: Video     Files: https://www.dropbox.com/s/5er86wt8wpy30zi/Breakout.zip     Code:   main.cpp [spoiler] #include <iostream> #include "includes.h" void doEvents(sf::RenderWindow & window, Upgrades & ups, BallState * ballState, Bullets * bullets, Entity * pad, Entity * ball, SoundEffect & shootSound, float pad_ball_delta_x); int main(){ srand(time(0)); sf::RenderWindow window(sf::VideoMode(SCREEN_SIZE_X, SCREEN_SIZE_Y), "Breakout"); window.setVerticalSyncEnabled(true); Entity pad(PAD_SIZE, (sf::Vector2f)SCREEN_SIZE - sf::Vector2f(SCREEN_CENTER.x - PAD_CENTER.x, PAD_SIZE.y + 10), sf::Color::White); Entity ball(BALL_SIZE, sf::Vector2f(pad.getPosition().x + PAD_CENTER.x - BALL_CENTER.x, pad.getPosition().y - BALL_SIZE.y), sf::Color(200, 200, 200)); float volume = 50; SoundEffect powerupSpawnSound("sounds/powerspawn.wav", volume); SoundEffect powerupCatchSound("sounds/powercatch.wav", volume); SoundEffect blockHitSound("sounds/blockhit.wav", volume); SoundEffect explodeSound("sounds/explode.wav", volume); SoundEffect wallHitSound("sounds/wallhit.wav", volume); SoundEffect padHitSound("sounds/padhit.wav", volume); SoundEffect deathSound("sounds/death.wav", volume); SoundEffect shootSound("sounds/shoot.wav", volume); float global_veloctiy = ORIGIN_VELOCITY; float angle = 0; sf::Vector2f velocity(global_veloctiy, global_veloctiy * -1); Upgrades ups; BallState ballState = BallState::Stopped; Bullets bullets(sf::Vector2f(5, 15), sf::Color(255, 165, 0), MAX_VELOCITY * -1); float lives = LIVES; size_t score = 0; size_t blockScore = 100; size_t deathScore = 1000; size_t padScore = 200; size_t upgradeScore = 1000; size_t boundScore = 50; // Setting up the maps size_t curMap = 0; // Set first map size_t map_count = 11; std::vector<std::string> maps(map_count); for (size_t i = 0; i < map_count; i++) maps[i] = "maps/" + std::to_string(i + 1) + ".png"; Map map(BLOCK_SIZE, OUTLINE_THICK, maps[curMap]); //Fixed timestep stuff sf::Clock clock; double skippedTime = 0; int updates = 0; double secondSkipped = 0; while (window.isOpen()){ const double elapsedTime = clock.getElapsedTime().asMicroseconds() / 1000.0; skippedTime += elapsedTime; secondSkipped += elapsedTime; clock.restart(); while (skippedTime >= INTERVAL){ updates++; while (secondSkipped > SECOND){ system("cls"); std::cout << updates << "Updates, " << secondSkipped / updates << " Average interval\n\n"; std::cout << "Stats:\n"; std::cout << "Lives: " << lives << '\n'; std::cout << "Score: " << score << '\n'; std::cout << '\n'; std::cout << "Upgrades:\n"; std::cout << "shooting: " << ups.isActive(Shooting) << '\n'; std::cout << "transparent: " << ups.isActive(Transparent) << '\n'; std::cout << "large pad: " << ups.isActive(Large) << '\n'; std::cout << "small pad: " << ups.isActive(Small) << '\n'; std::cout << "ball explode: " << ups.isActive(Explode) << '\n'; std::cout << "sticky pad: " << ups.isActive(Sticky) << '\n'; std::cout << "Y vel: " << velocity.y << '\n'; std::cout << "X vel: " << velocity.x << '\n'; std::cout << '\n'; updates = 0; secondSkipped -= SECOND; } //Events doEvents(window, ups, &ballState, &bullets, &pad, &ball, shootSound, ball.getPosition().x - pad.getPosition().x); //Update bullets.move(); ups.move(); if (ballState == BallState::Moving){ ball.move(velocity); } Entity bounds((sf::Vector2f)window.getSize(), sf::Vector2f(0, 0)); if (mth::boundaryIntersect(ball, bounds, Side::Left)){ velocity.x *= NEG; ball.setPosition(bounds.getPosition().x, ball.getPosition().y); wallHitSound.play(); score += boundScore; } else if (mth::boundaryIntersect(ball, bounds, Side::Right)){ velocity.x *= NEG; ball.setPosition(bounds.getSize().x - ball.getSize().x, ball.getPosition().y); wallHitSound.play(); score += boundScore; } if (mth::boundaryIntersect(ball, bounds, Side::Top)){ velocity.y *= NEG; ball.setPosition(ball.getPosition().x, bounds.getPosition().y); wallHitSound.play(); score += boundScore; } if (mth::boundaryIntersect(ball, bounds, Side::Bottom)){ lives--; if (lives <= 0) window.close(); ups.clearActive(); angle = 0; global_veloctiy = ORIGIN_VELOCITY; ballState = BallState::Stopped; ball.setPosition(pad.getPosition().x + PAD_CENTER.x - BALL_CENTER.x, pad.getPosition().y - BALL_SIZE.y - 1); velocity = sf::Vector2f(global_veloctiy, global_veloctiy * -1); deathSound.play(); score += deathScore; } // Check for collisions between upgrades and pad std::vector<Entity> upgrade_entities = ups.getEntities(); for (size_t i = 0; i < upgrade_entities.size(); i++){ if (mth::doesIntersect(pad, upgrade_entities[i])){ ups.addUpgrade(i); ups.removeAt(i); std::cout << "sup"; ballState = BallState::Moving; powerupCatchSound.play(); score += upgradeScore; } } // Check for collisions between bullets and blocks bool hit = false; size_t loc_y; size_t loc_x; vect2dTile blocks = map.getMap(); std::vector<Entity> bullet_entities = bullets.get(); for (size_t z = 0; z < bullet_entities.size(); z++){ size_t x = bullet_entities[z].getGridPosition().x; for (size_t y = 0; y < blocks.size(); y++){ if (blocks[y][x].strength > 0 && mth::doesIntersect(blocks[y][x].entity, bullet_entities[z])){ if (!ups.isActive(Transparent)){ bullets.removeAt(z); } if (rand() % 1000 <= UP_CHANCE){ ups.spawn(blocks[y][x].entity, FALL_VELOCITY, GRAVITY); powerupSpawnSound.play(); } map.hitAt(y, x); if (ups.isActive(Explode)){ explodeSound.play(); map.hitAt(y + 1, x); map.hitAt(y - 1, x); map.hitAt(y, x + 1); map.hitAt(y, x - 1); score += blockScore * 4; } score += blockScore; blockHitSound.play(); hit = true; break; } } if (hit) break; } // Check for intersepts blocks = map.getMap(); hit = false; // Downwards movement intersepts if (velocity.y > 0 && !hit){ if (mth::willIntercept(ball, pad, velocity, Side::Top)){ if (ups.isActive(Sticky)){ ballState = BallState::Stopped; } global_veloctiy += VELOCITY_INC; if (global_veloctiy > MAX_VELOCITY) global_veloctiy = MAX_VELOCITY; angle = mth::getAngleInRadians(pad.getPosition() + sf::Vector2f(pad.getSize().x / 2.0f, 20), ball.getPosition() + ball.getSize() / 2.0f); velocity = mth::getVelocity(angle, global_veloctiy); score += padScore; padHitSound.play(); } else for (size_t i = 0; i < blocks.size(); i++){ for (size_t j = 0; j < blocks[i].size(); j++) if (blocks[i][j].strength > 0 && mth::willIntercept(ball, blocks[i][j].entity, velocity, Side::Top)){ if (!ups.isActive(Transparent)) velocity.y *= NEG; loc_y = i; loc_x = j; hit = true; break; } if (hit) break; } } // Upwards movement intersepts else if (velocity.y < 0 && !hit){ for (size_t i = 0; i < blocks.size(); i++){ for (size_t j = 0; j < blocks[i].size(); j++) if (blocks[i][j].strength > 0 && mth::willIntercept(ball, blocks[i][j].entity, velocity, Side::Bottom)){ if (!ups.isActive(Transparent)) velocity.y *= NEG; loc_y = i; loc_x = j; hit = true; break; } if (hit) break; } } // Right movement intersepts if (velocity.x > 0 && !hit){ if (mth::willIntercept(ball, pad, velocity, Side::Left)){ velocity *= NEG; padHitSound.play(); score += padScore * 2; } else for (size_t i = 0; i < blocks.size(); i++){ for (size_t j = 0; j < blocks[i].size(); j++) if (blocks[i][j].strength > 0 && mth::willIntercept(ball, blocks[i][j].entity, velocity, Side::Left)){ if (!ups.isActive(Transparent)) velocity.x *= NEG; loc_y = i; loc_x = j; hit = true; break; } if (hit) break; } } // Left movement intersepts else if (velocity.x < 0 && !hit){ if (mth::willIntercept(ball, pad, velocity, Side::Right)){ velocity *= NEG; padHitSound.play(); score += padScore * 2; } else for (size_t i = 0; i < blocks.size(); i++){ for (size_t j = 0; j < blocks[i].size(); j++) if (blocks[i][j].strength > 0 && mth::willIntercept(ball, blocks[i][j].entity, velocity, Side::Right)){ if (!ups.isActive(Transparent)) velocity.x *= NEG; loc_y = i; loc_x = j; hit = true; break; } if (hit) break; } } if (hit){ if (rand() % 1000 <= UP_CHANCE){ ups.spawn(blocks[loc_y][loc_x].entity, FALL_VELOCITY, GRAVITY); powerupSpawnSound.play(); } map.hitAt(loc_y, loc_x); if (ups.isActive(Explode)){ explodeSound.play(); map.hitAt(loc_y + 1, loc_x); map.hitAt(loc_y - 1, loc_x); map.hitAt(loc_y, loc_x + 1); map.hitAt(loc_y, loc_x - 1); } blockHitSound.play(); score += blockScore; } std::vector<Upgrd> active_ups = ups.getActiveUpgrades(); Upgrd LorS = None_upgrd; for (size_t i = 0; i < active_ups.size(); i++){ if (active_ups[i] == Large || active_ups[i] == Small) LorS = active_ups[i]; } if (LorS == Large){ pad.setSize(PAD_SIZE.x * 2.0f, PAD_SIZE_Y); } else if (LorS == Small){ pad.setSize(PAD_SIZE.x / 2.0f, PAD_SIZE_Y); } else if (LorS == None_upgrd){ pad.setSize(PAD_SIZE); } upgrade_entities = ups.getEntities(); for (size_t i = 0; i < upgrade_entities.size(); i++){ if (upgrade_entities[i].getPosition().y > window.getSize().y) ups.removeAt(i); } bullet_entities = bullets.get(); for (size_t i = 0; i < bullet_entities.size(); i++){ if (bullet_entities[i].getPosition().y < -100) bullets.removeAt(i); } if (map.isCleared()){ if (curMap < map_count - 1){ map.setMap(maps[++curMap]); global_veloctiy = ORIGIN_VELOCITY; velocity = sf::Vector2f(global_veloctiy, global_veloctiy * -1); ballState = BallState::Stopped; ball.setPosition(pad.getPosition().x + PAD_CENTER.x - BALL_CENTER.x, pad.getPosition().y - BALL_SIZE.y); ups.clearActive(); bullets.clear(); } else{ curMap = 0; } } // Subtract INTERVAL from skippedTime skippedTime -= INTERVAL; } // Render window.clear(sf::Color(20, 20, 20)); map.draw(window); ball.draw(window); ups.draw(window); pad.draw(window); bullets.draw(window); window.display(); } return 0; } void doEvents(sf::RenderWindow & window, Upgrades & ups, BallState * ballState, Bullets * bullets, Entity * pad, Entity * ball, SoundEffect & shootSound, float pad_ball_delta_x){ sf::Event event; while (window.pollEvent(event)){ if (event.type == sf::Event::Closed) window.close(); else if (event.type == sf::Event::KeyPressed){ sf::Keyboard k; if (event.key.code == k.Escape){ window.close(); } if (event.key.code == k.Space){ *ballState = BallState::Moving; } if (event.key.code == k.F1){ ups.addUpgrade(Sticky); } if (event.key.code == k.F2){ ups.addUpgrade(Shooting); } if (event.key.code == k.F3){ ups.addUpgrade(Explode); } if (event.key.code == k.F4){ ups.addUpgrade(Transparent); } if (event.key.code == k.F5){ ups.addUpgrade(Large); } if (event.key.code == k.F6){ ups.addUpgrade(Small); } } else if (event.type == sf::Event::MouseMoved){ pad->setPosition(event.mouseMove.x - pad->getSize().x / 2.0f, pad->getPosition().y); if (*ballState == BallState::Stopped){ ball->setPosition(pad->getPosition().x + pad_ball_delta_x, pad->getPosition().y - ball->getSize().y); } } else if (event.type == sf::Event::MouseButtonPressed){ if (event.mouseButton.button == sf::Mouse::Button::Left){ *ballState = BallState::Moving; if (ups.isActive(Shooting)){ bullets->spawn(pad->getPosition() + sf::Vector2f(pad->getSize().x / 2.0f, 0)); shootSound.play(); } } } } }  [/spoiler]   includes.h [spoiler] #pragma once #include <string> #include <vector> #include <SFML/Graphics.hpp> #include <SFML/Audio.hpp> #include "globals.h" #include "Entity.h" #include "SoundEffect.h" #include "Map.h" #include "Bullet.h" #include "Upgrade.h" #include "mth_namespace.h"  [/spoiler]   globals.h [spoiler] #pragma once #include <SFML/System/Vector2.hpp> struct Tile; const float BLOCK_SIZE_XY = 40.0f; const float BALL_SIZE_XY = 20.0f; const float PAD_SIZE_Y = 20.0f; const float PAD_SIZE_X = PAD_SIZE_Y * 5.0f; const float UP_SIZE_XY = 40.0f; const int GRID_SIZE_X = 20; const int GRID_SIZE_Y = 10; const int SCREEN_SIZE_X = (int)BLOCK_SIZE_XY * GRID_SIZE_X; const int SCREEN_SIZE_Y = (int)BLOCK_SIZE_XY * GRID_SIZE_Y + 200; const float FALL_VELOCITY = -2; const float GRAVITY = 0.04f; const float ORIGIN_VELOCITY = 2; const float VELOCITY_INC = 0.15f; const float MAX_VELOCITY = 8; const int LIVES = 3; const int INTERVAL = 10; const int SECOND = 1000; const int UP_CHANCE = 50; // in 1000 const float OUTLINE_THICK = -10.0f; const float NEG = -1.0f; const sf::Vector2i SCREEN_SIZE(SCREEN_SIZE_X, SCREEN_SIZE_Y); const sf::Vector2f BLOCK_SIZE(BLOCK_SIZE_XY, BLOCK_SIZE_XY); const sf::Vector2f BALL_SIZE(BALL_SIZE_XY, BALL_SIZE_XY); const sf::Vector2i GRID_SIZE(GRID_SIZE_X , GRID_SIZE_Y); const sf::Vector2f SCREEN_CENTER(SCREEN_SIZE / 2); const sf::Vector2f PAD_SIZE(PAD_SIZE_X, PAD_SIZE_Y); const sf::Vector2f BLOCK_CENTER(BLOCK_SIZE / 2.0f); const sf::Vector2f BALL_CENTER(BALL_SIZE / 2.0f); const sf::Vector2f PAD_CENTER( PAD_SIZE / 2.0f); typedef std::vector<std::vector<Tile>> vect2dTile; enum BallState{ Moving, Stopped }; enum class Movement{ Up, Down, Left, Right }; enum Side{ Top, Bottom, Left, Right }; enum Upgrd{ Shooting, Transparent, Large, Small, Explode, Sticky, LAST_upgrd, None_upgrd };  [/spoiler]   mth_namespace.h [spoiler] #pragma once #include <SFML/System/Vector2.hpp> #include <SFML/Graphics/RenderWindow.hpp> class Entity; enum Side; namespace mth{ // 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(Entity entity1, Entity entity2); // Test if an entity is outside the entity bounds bool boundaryIntersect(Entity entity, Entity 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 Entity & entityMoving, const Entity & entityStatic, sf::Vector2f vel, Side side); // Get the angle between two vectors in radians float getAngleInRadians(const sf::Vector2f & entityStaticCenter, const sf::Vector2f & entityMovingCenter); // Calculate directional veloctiy, given radians and global velocity sf::Vector2f getVelocity(float radians, float vel); }  [/spoiler]   mth_namespace.cpp [spoiler] #include "mth_namespace.h" #include "includes.h" #include <iostream> struct mth::Line{ Line(){} Line(sf::Vector2f pointA, sf::Vector2f pointB) : A(pointA), B(pointB){} sf::Vector2f A; sf::Vector2f B; }; bool mth::doesIntersect(Entity entity1, Entity 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 mth::boundaryIntersect(Entity entity, Entity 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 mth::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 mth::willIntercept(const Entity & entityMoving, const Entity & 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 <= Bottom){ line.A = entityStatic.getPosition() + sf::Vector2f(0, entityStatic.getSize().y * side); line.B = entityStatic.getPosition() + sf::Vector2f(entityStatic.getSize().x, entityStatic.getSize().y * side); end = sf::Vector2f((int)((vel.y + emCenter.y - b) / m), vel.y + emCenter.y); if (side == Top){ for (float y = 0; y <= vel.y; y += 0.1f){ if (lineIntersect(line, sf::Vector2f((int)((y + emCenter.y - b) / m), y + emCenter.y), entityMoving.getSize().y)) return true; } } else if (side == Bottom){ for (float y = 0; y >= vel.y; y -= 0.1f){ if (lineIntersect(line, sf::Vector2f((int)((y + emCenter.y - b) / m), y + emCenter.y), entityMoving.getSize().y)) return true; } } } else if (side >= Left){ int tmpSide = 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, (int)(m * (vel.x + emCenter.x) + b)); if (side == Left){ for (float x = 0; x <= vel.x; x += 0.1f){ if (lineIntersect(line, sf::Vector2f(x + emCenter.x, (int)(m * (x + emCenter.x) + b)), entityMoving.getSize().x)) return true; } } else if (side == Right){ for (float x = 0; x >= vel.x; x -= 0.1f){ if (lineIntersect(line, sf::Vector2f(x + emCenter.x, (int)(m * (x + emCenter.x) + b)), entityMoving.getSize().x)) return true; } } } return false; } float mth::getAngleInRadians(const sf::Vector2f & entityStaticCenter, const sf::Vector2f & entityMovingCenter){ return atan2f((entityMovingCenter.y - (entityStaticCenter.y)), (entityMovingCenter.x - (entityStaticCenter.x))); } sf::Vector2f mth::getVelocity(float radians, float vel){ return sf::Vector2f((float)cos(radians) * (float)vel, (float)sin(radians) * (float)vel); }  [/spoiler]   Entity.h [spoiler] #pragma once #include <SFML/Graphics/RectangleShape.hpp> #include <SFML/System/Vector2.hpp> #include <SFML/Graphics/Color.hpp> #include <SFML/Graphics/RenderWindow.hpp> class Entity { private: protected: sf::RectangleShape rect; public: Entity(sf::Vector2f size, sf::Vector2f pos, sf::Color color = sf::Color::White); Entity(){ } sf::Vector2f getPosition() const; sf::Vector2i getGridPosition() const; sf::Vector2f getSize() const; float getOutlineThickness() const; void draw(sf::RenderWindow & window); void move(const sf::Vector2f & dist); void setPosition(float x, float y); void setPosition(const sf::Vector2f & pos); void setGridPosition(size_t x, size_t y); void setSize(float x, float y); void setSize(const sf::Vector2f & size); void setColor(const sf::Color & color); void setOutline(float thickness, const sf::Color & color); void setOutlineThickness(float thickness); void setOutlineColor(const sf::Color & color); };  [/spoiler]   Entity.cpp [spoiler] #include "Entity.h" #include "includes.h" #include <iostream> Entity::Entity(sf::Vector2f size, sf::Vector2f pos, sf::Color color){ setSize(size); setPosition(pos); setColor(color); } sf::Vector2f Entity::getPosition() const{ return rect.getPosition(); } sf::Vector2i Entity::getGridPosition() const{ return sf::Vector2i(rect.getPosition().x / BLOCK_SIZE_XY, rect.getPosition().y / BLOCK_SIZE_XY); } sf::Vector2f Entity::getSize() const{ return rect.getSize(); } float Entity::getOutlineThickness() const{ return rect.getOutlineThickness(); } void Entity::draw(sf::RenderWindow & window){ window.draw(rect); } void Entity::move(const sf::Vector2f & dist){ rect.setPosition(rect.getPosition() + dist); } void Entity::setPosition(float x, float y){ rect.setPosition(x, y); } void Entity::setPosition(const sf::Vector2f & pos){ rect.setPosition(pos); } void Entity::setGridPosition(size_t x, size_t y){ setPosition(x * getSize().x, y * getSize().y); } void Entity::setSize(float x, float y){ rect.setSize(sf::Vector2f(x, y)); } void Entity::setSize(const sf::Vector2f & size){ rect.setSize(size); } void Entity::setColor(const sf::Color & color){ rect.setFillColor(color); } void Entity::setOutline(float thickness, const sf::Color & color){ rect.setOutlineThickness(thickness); rect.setOutlineColor(color); } void Entity::setOutlineThickness(float thickness){ rect.setOutlineThickness(thickness); } void Entity::setOutlineColor(const sf::Color & color){ rect.setOutlineColor(color); }  [/spoiler]   Map.h [spoiler] #pragma once #include "Entity.h" #include "globals.h" struct Tile{ Entity entity; char strength = 1; }; class Map { vect2dTile tileMap; sf::Image map; Entity model; public: Map(const sf::Vector2f & tileSize, float outlineThickness, std::string mapPath); vect2dTile getMap() const; bool isCleared() const; void setMap(std::string mapPath); void hitAt(size_t y, size_t x); void draw(sf::RenderWindow & window); };  [/spoiler]   Map.cpp [spoiler] #include "Map.h" #include "includes.h" Map::Map(const sf::Vector2f & tileSize, float outlineThickness, std::string mapPath){ model.setSize(tileSize); model.setOutlineThickness(outlineThickness); setMap(mapPath); } vect2dTile Map::getMap() const{ return tileMap; } bool Map::isCleared() const{ bool cleared = true; for (size_t y = 0; y < tileMap.size(); y++){ for (size_t x = 0; x < tileMap[y].size(); x++){ if (tileMap[y][x].strength > 0) cleared = false; } } return cleared; } void Map::setMap(std::string mapPath){ // Load map if (!map.loadFromFile(mapPath)) std::exit(-3); // Initialize tile map tileMap.resize(map.getSize().y); for (size_t i = 0; i < tileMap.size(); i++) tileMap[i].resize(map.getSize().x); // Set tile map for (size_t y = 0; y < tileMap.size(); y++){ for (size_t x = 0; x < tileMap[y].size(); x++){ if (map.getPixel(x, y) == sf::Color::Magenta) tileMap[y][x].strength = 0; else{ tileMap[y][x].strength = 1; sf::Color pixCol = map.getPixel(x, y); tileMap[y][x].entity.setSize(model.getSize()); tileMap[y][x].entity.setGridPosition(x, y); tileMap[y][x].entity.setColor(pixCol); tileMap[y][x].entity.setOutline(model.getOutlineThickness(), sf::Color(pixCol.r / 1.5f, pixCol.g / 1.5f, pixCol.b / 1.5f)); } } } } void Map::hitAt(size_t y, size_t x){ if (tileMap.size() > y && y >= 0 && tileMap[y].size() > x && x >= 0){ if (tileMap[y][x].strength <= 1) tileMap[y][x].strength = 0; else tileMap[y][x].strength--; } } void Map::draw(sf::RenderWindow & window){ for (size_t i = 0; i < tileMap.size(); i++) for (size_t j = 0; j < tileMap[i].size(); j++){ if (tileMap[i][j].strength > 0) tileMap[i][j].entity.draw(window); } }  [/spoiler]   Upgrade.h [spoiler] #pragma once #include <vector> #include <SFML/Graphics/RenderWindow.hpp> #include <SFML/System/Vector2.hpp> #include "globals.h" class Entity; class Upgrades { std::vector<Upgrd> active; std::vector<Entity> entity; std::vector<Upgrd> upgrd; std::vector<sf::Vector2f> velocity; float gravity; public: Upgrades(){ } std::vector<Upgrd> getActiveUpgrades() const; std::vector<Entity> getEntities() const; void spawn(const Entity & origin, float startYVel, float gravity); void move(); void removeAt(size_t item); void addUpgrade(Upgrd up); void addUpgrade(size_t upgrd_item); bool isActive(Upgrd up) const; void draw(sf::RenderWindow & window); void clearActive(); };  [/spoiler]   Upgrade.cpp [spoiler] #include "Upgrade.h" #include "includes.h" std::vector<Upgrd> Upgrades::getActiveUpgrades() const{ return active; } std::vector<Entity> Upgrades::getEntities() const{ return entity; } void Upgrades::spawn(const Entity & origin, float startYVel, float gravity){ entity.push_back(origin); Upgrd tmp = (Upgrd)(rand() % LAST_upgrd); upgrd.push_back(tmp); velocity.push_back(sf::Vector2f(-0.5f + rand() % 11 / 10.0f, startYVel)); this->gravity = gravity; } void Upgrades::move(){ for (size_t i = 0; i < entity.size(); i++){ entity[i].move(velocity[i]); if (velocity[i].y < MAX_VELOCITY) velocity[i].y += gravity; else velocity[i].y = MAX_VELOCITY; } } void Upgrades::removeAt(size_t item){ entity.erase(entity.begin() + item); upgrd.erase(upgrd.begin() + item); velocity.erase(velocity.begin() + item); } void Upgrades::addUpgrade(Upgrd up){ active.push_back(up); } void Upgrades::addUpgrade(size_t upgrd_item){ active.push_back(upgrd[upgrd_item]); } bool Upgrades::isActive(Upgrd up) const{ for (size_t i = 0; i < active.size(); i++){ if (active[i] == up) return true; } return false; } void Upgrades::draw(sf::RenderWindow & window){ for (size_t i = 0; i < entity.size(); i++){ entity[i].draw(window); } } void Upgrades::clearActive(){ active.clear(); }  [/spoiler]   Bullet.h [spoiler] #pragma once #include <vector> #include "Entity.h" #include <SFML/System/Vector2.hpp> namespace sf{ class Color; class RenderWindow; }; class Bullets { std::vector<Entity> bullets; Entity model; float yVel; public: Bullets(const sf::Vector2f & size, const sf::Color & color, float vel); std::vector<Entity> get() const; void draw(sf::RenderWindow & window); void move(); void clear(); void removeAt(size_t item); void spawn(const sf::Vector2f & origin); };  [/spoiler]   Bullet.cpp [spoiler] #include "Bullet.h" #include "includes.h" Bullets::Bullets(const sf::Vector2f & size, const sf::Color & color, float vel){ model.setSize(size); model.setColor(color); yVel = vel; } std::vector<Entity> Bullets::get() const{ return bullets; } void Bullets::draw(sf::RenderWindow & window){ for (size_t i = 0; i < bullets.size(); i++){ bullets[i].draw(window); } } void Bullets::move(){ for (size_t i = 0; i < bullets.size(); i++){ bullets[i].move(sf::Vector2f(0, yVel)); } } void Bullets::clear(){ bullets.clear(); } void Bullets::removeAt(size_t item){ bullets.erase(bullets.begin() + item); } void Bullets::spawn(const sf::Vector2f & origin){ model.setPosition(origin); bullets.push_back(model); }  [/spoiler]   SoundEffect.h [spoiler] #pragma once #include <SFML/Audio/SoundBuffer.hpp> #include <SFML/Audio/Sound.hpp> class SoundEffect { sf::SoundBuffer buffer; sf::Sound sound; public: SoundEffect(std::string filePath, float volume); SoundEffect(std::string filePath, sf::Sound sound); SoundEffect(){ } float getVolume() const; void setVolume(float volume); void play(); void pause(); void stop(); };  [/spoiler]   SoundEffect.cpp [spoiler] #include "SoundEffect.h" #include "includes.h" SoundEffect::SoundEffect(std::string filePath, float volume){ if (!buffer.loadFromFile(filePath)) std::exit(-2); sound.setBuffer(buffer); sound.setVolume(volume); } SoundEffect::SoundEffect(std::string filePath, sf::Sound sound){ if (!buffer.loadFromFile(filePath)) std::exit(-2); 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(); }  [/spoiler]
  22. Gaius Baltar

    Breakout code review request

    Hi.   They do disappear, The way it works is, when the ball hits a tile, the tile explodes, and all tiles immediately next to it are removed in a pattern like so: O = Hit tile - = Affected tile . = nothing .........------- ------- OOO ------- .........-------   There are sound effects , the video just didn't catch them for some reason. You're right about music I should get on that.   I was thinking about that, but then I remembered the DX-Ball 2 game with it's background feature, and I kind of disliked it. It made it hard for me to see the moving ball at times. I made the background dark gray in order to be able to have black tiles and because that shade of gray is rarely used.   I never thought about that, will get on it.   I don't understand, could you rephrase?   I never really got into that, gonna have to check it out first.   Thanks.
  23. Gaius Baltar

    Breakout code review request

      Thanks for the feedback, I read your blog post and it helped me a lot with understanding code design. I'm gonna try sticking to some of the things you said in there in my next project (Missile Command), I was thinking of taking a whole new design path to my code this time over by placing the entire game into a class system so that my main function isn't so cluttered and so that I don't need to pass so many parameters when I want do something as simple as poll events etc..
  24. Gaius Baltar

    Snake code review request

    I've recently finished programming a clone of the popular "Snake" game in C++ with SFML and Visual Studio 12 and I would like to know if there is anything about the code or it's structure that I could improve. This is the second post I've made on this forum, the first was a Pong review request. http://www.gamedev.net/topic/659149-basic-pong-code-review-request/   Game:       Files:     Code:   main.cpp   [spoiler] #include <iostream> #include <string> #include <vector> #include <SFML/Graphics.hpp> #include <SFML/Audio.hpp> #include "globals.h" #include "Snake.h" #include "Food.h" #include "SoundEffect.h" void doEvents(sf::RenderWindow & window, bool & up, bool & down, bool & left, bool & right, bool & pressed); void move(Snake & snake, bool up, bool down, bool left, bool right); bool intersect(const Snake & snake); bool intersect(const Snake & snake, const Food & food, size_t & i); bool borderIntersect(const Snake & snake, const sf::RenderWindow & window); int main(){ srand(time(0)); sf::RenderWindow window(sf::VideoMode(SCRSIZE, SCRSIZE), "Snake"); float volume = 50; SoundEffect moveSound("sounds/move.wav", volume); SoundEffect foodSound("sounds/food.wav", volume); SoundEffect extraSound("sounds/extra.wav", volume); SoundEffect deathSound("sounds/death.wav", volume); sf::Color foodColor(0, 123, 123); Snake snake(sf::Vector2f(SIZE, SIZE), sf::Vector2f(GRIDSIZE/2, GRIDSIZE/2), 3, sf::Color::White, OUTLINE); Food food(1, foodColor); Food extra(2, RAND_COL); food.spawn(snake, extra, foodColor); bool gameOver = false; bool up = true; bool down = false; bool left = false; bool right = false; bool pressed = false; int collectedItems = 0; int level = 1; int score = 0; int lives = LIVES; // Fixed time step loop setup sf::Clock clock; double skippedTime = 0; double secondsElapsed = 0; double interval = INTERVAL; int updates = 0; // Game loop while (window.isOpen()){ const double elapsedTime = clock.getElapsedTime().asMicroseconds() / 1000.0; skippedTime += elapsedTime; secondsElapsed += elapsedTime; extra.clock(elapsedTime); clock.restart(); pressed = false; if (snake.getLength() <= 20) interval = INTERVAL * 2; else if (snake.getLength() <= 40) interval = INTERVAL / 2.0; else if (snake.getLength() <= 60) interval = INTERVAL / 1.2; else if (snake.getLength() <= 80) interval = INTERVAL; while (skippedTime >= interval){ //Second timer updates++; while (secondsElapsed >= 1000){ //system("cls"); std::cout << updates << " Updates, " << secondsElapsed / updates << " Average Interval\n"; std::cout << "Score: " << score << '\n'; std::cout << "Level: " << level << '\n'; std::cout << "Lives: " << lives << '\n'; updates = 0; secondsElapsed -= 1000; } //Events doEvents(window, up, down, left, right, pressed); //Update size_t pos = 0; move(snake, up, down, left, right); if (interval < 300 && (updates == 3 || updates == 6 || updates == 9)) moveSound.play(); else if (interval >= 300) moveSound.play(); if (rand() % 1000 <= 5){ extra.spawn(snake, food, RAND_COL, interval * 40); } if (intersect(snake) || borderIntersect(snake, window)){ deathSound.play(); gameOver = true; } if (intersect(snake, food, pos)){ foodSound.play(); food.remove(); food.spawn(snake, extra, foodColor); collectedItems++; score += food.getPoints(); snake.grow(); } if (intersect(snake, extra, pos)){ extraSound.play(); extra.remove(pos); collectedItems++; score += extra.getPoints(); snake.grow(); } if (collectedItems >= 10){ level++; collectedItems = 0; extra.setPoints(level * level); food.setPoints(level); } if (gameOver){ lives--; if (lives < 0) window.close(); snake = Snake(sf::Vector2f(SIZE, SIZE), sf::Vector2f(GRIDSIZE / 2, GRIDSIZE / 2), 3, sf::Color::White, OUTLINE); food = Food(level, sf::Color(0, 123, 123)); food.spawn(snake, extra, foodColor); extra = Food(level*level, RAND_COL); interval = INTERVAL; collectedItems = 0; if (score >= 100) score -= score / 3; else score = 0; gameOver = false; up = true; down = false; left = false; right = false; } //Subtract time skippedTime -= interval; } // Render window.clear(); snake.draw(window); food.draw(window); extra.draw(window); window.display(); } return 0; } void doEvents(sf::RenderWindow & window, bool & up, bool & down, bool & left, bool & right, bool & pressed){ sf::Event event; while (window.pollEvent(event)){ if (event.type == sf::Event::Closed){ window.close(); } if (event.type == sf::Event::KeyPressed){ sf::Keyboard k; if (event.key.code == k.Escape){ window.close(); } if (event.key.code == k.Up && !down && !pressed){ up = true; down = false; left = false; right = false; pressed = true; } else if (event.key.code == k.Down && !up && !pressed){ up = false; down = true; left = false; right = false; pressed = true; } else if (event.key.code == k.Left && !right && !pressed){ up = false; down = false; left = true; right = false; pressed = true; } else if (event.key.code == k.Right && !left && !pressed){ up = false; down = false; left = false; right = true; pressed = true; } } } } void move(Snake & snake, bool up, bool down, bool left, bool right){ if (up){ snake.moveUp(); } else if (down){ snake.moveDown(); } else if (left){ snake.moveLeft(); } else if (right){ snake.moveRight(); } } bool intersect(const Snake & snake){ for (int i = 1; i < snake.getLength(); i++){ if (snake.getGridPos() == snake.getGridPos(i)){ return true; } } return false; } bool intersect(const Snake & snake, const Food & food, size_t & item){ for (int i = 0; i < food.getLength(); i++){ if (snake.getGridPos() == food.getGridPos(i)){ item = i; return true; } } return false; } bool borderIntersect(const Snake & snake, const sf::RenderWindow & window){ if (snake.getPos().x >= window.getSize().x) return true; if (snake.getPos().x < 0) return true; if (snake.getPos().y >= window.getSize().y) return true; if (snake.getPos().y < 0) return true; return false; } [/spoiler] Snake.h [spoiler] #pragma once #include "Entity.h" class Snake : public Entity { public: Snake(const sf::Vector2f & size = sf::Vector2f(SIZE, SIZE), const sf::Vector2f & gridPos = sf::Vector2f(GRIDSIZE / 2, GRIDSIZE / 2), size_t length = 3, const sf::Color & color = sf::Color::White, float outline = OUTLINE) : Entity(size, gridPos * SIZE, color, length){ setOutline(outline, sf::Color(color.r / 1.5f, color.g / 1.5f, color.b / 1.5f)); } // inline constructor void moveUp(); void moveDown(); void moveLeft(); void moveRight(); void setGridPos(const sf::Vector2f & gridPos); void grow(); }; [/spoiler] Snake.cpp [spoiler] #include "Entity.h" #include <SFML/Graphics.hpp> #include "globals.h" #include "Snake.h" void Snake::moveUp(){ for (int i = entity.size() - 1; i > 0; i--){ entity[i].setPosition(entity[i - 1].getPosition()); } entity[0].setPosition(entity[0].getPosition() - sf::Vector2f(0, getSize().y)); } void Snake::moveDown(){ for (int i = entity.size() - 1; i > 0; i--){ entity[i].setPosition(entity[i - 1].getPosition()); } entity[0].setPosition(entity[0].getPosition() + sf::Vector2f(0, getSize().y)); } void Snake::moveLeft(){ for (int i = entity.size() - 1; i > 0; i--){ entity[i].setPosition(entity[i - 1].getPosition()); } entity[0].setPosition(entity[0].getPosition() - sf::Vector2f(getSize().x, 0)); } void Snake::moveRight(){ for (int i = entity.size() - 1; i > 0; i--){ entity[i].setPosition(entity[i - 1].getPosition()); } entity[0].setPosition(entity[0].getPosition() + sf::Vector2f(getSize().x, 0)); } void Snake::grow(){ setLength(getLength() + 1); setSize(getSize()); setColor(getColor()); setOutline(getOutlineThickness(), getOutlineColor()); entity[entity.size() - 1].setPosition(entity[entity.size() - 2].getPosition()); } [/spoiler] Food.h [spoiler] #pragma once #include "Entity.h" class Snake; class Food: public Entity { std::vector<double> timer; int points; float outline; sf::Color fillColor; sf::Color outlineColor; sf::Vector2f size; public: Food(int points, const sf::Color & color = sf::Color(0,123,123), const sf::Vector2f & size = sf::Vector2f(SIZE, SIZE), float outline = OUTLINE) : Entity(size, color, 0){ this->outline = outline; this->size = size; fillColor = color; setColor(fillColor); outlineColor = sf::Color(color.r / 1.5f, color.g / 1.5f, color.b / 1.5f); this->points = points; setOutline(outline, outlineColor); } // inline constructor int getPoints(){ return points; } // inline definition void setPoints(int points){ this->points = points; } // inline definition void clock(double elapsed); void spawn(const Snake & snake, const Food & other, sf::Color color = sf::Color::White, double time = 10000); void remove(size_t i = 0); }; [/spoiler] Food.cpp [spoiler] #include "Food.h" #include "Snake.h" #include <iostream> void Food::clock(double elapsed){ for (size_t i = 0; i < timer.size(); i++){ timer[i] -= elapsed; if (timer[i] <= 0){ remove(i); i = 0; } } } void Food::spawn(const Snake & snake, const Food & other, sf::Color color, double time){ setLength(getLength() + 1); sf::Vector2f pos(rand() % GRIDSIZE, rand() % GRIDSIZE); int counter = 0; bool done = false; while (!done){ done = true; for (int i = 0; i < snake.getLength(); i++){ if (pos == snake.getGridPos(i)){ pos = sf::Vector2f(rand() % GRIDSIZE, rand() % GRIDSIZE); done = false; break; } } for (int i = 0; i < other.getLength(); i++){ if (pos == other.getGridPos(i)){ pos = sf::Vector2f(rand() % GRIDSIZE, rand() % GRIDSIZE); done = false; break; } } for (int i = 0; i < getLength() - 1; i++){ if (pos == getGridPos(i)){ pos = sf::Vector2f(rand() % GRIDSIZE, rand() % GRIDSIZE); done = false; break; } } counter++; if (getLength() >= GRIDSIZE * GRIDSIZE - snake.getLength()) break; else if (other.getLength() >= GRIDSIZE * GRIDSIZE - snake.getLength()) break; } if (done){ timer.resize(getLength()); timer[timer.size() - 1] = time; outlineColor = sf::Color(color.r / 1.5f, color.g / 1.5f, color.b / 1.5f); fillColor = color; setSize(size); setOutline(outline, outlineColor); entity[getLength() - 1].setFillColor(fillColor); entity[getLength() - 1].setOutlineColor(outlineColor); entity[getLength() - 1].setOutlineThickness(outline); entity[getLength() - 1].setPosition(sf::Vector2f(pos.x * size.x, pos.y * size.y)); } else{ setLength(getLength() - 1); } } void Food::remove(size_t i){ timer.erase(timer.begin() + i); entity.erase(entity.begin() + i); } [/spoiler] Entity.h [spoiler] #pragma once #include <SFML/Graphics.hpp> #include <vector> #include "globals.h" class Entity { sf::Uint8 r; sf::Uint8 g; sf::Uint8 b; sf::Uint8 a; void setRGBA(sf::Uint8 r, sf::Uint8 g, sf::Uint8 b, sf::Uint8 a){ this->r = r; this->g = g; this->b = b; this->a = a; } protected: std::vector<sf::RectangleShape> entity; public: Entity(const sf::Vector2f & size = sf::Vector2f(SIZE, SIZE), const sf::Color & color = sf::Color::White, size_t length = 1); Entity(const sf::Vector2f & size = sf::Vector2f(SIZE, SIZE), const sf::Vector2f & pos = sf::Vector2f(0, 0), const sf::Color & color = sf::Color::White, size_t length = 1); std::vector<sf::RectangleShape> get() const; sf::Vector2f getSize(size_t i = 0) const; sf::Vector2f getPos(size_t i = 0) const; sf::Vector2f getGridPos(size_t i = 0) const; sf::Color getColor(size_t i = 0) const; size_t getLength() const; float getOutlineThickness(size_t i = 0) const; sf::Color getOutlineColor(size_t i = 0) const; void draw(sf::RenderWindow & window) const; void set(const sf::Vector2f & size = sf::Vector2f(SIZE, SIZE), const sf::Color & color = sf::Color::White, size_t length = 1); void set(const sf::Vector2f & size = sf::Vector2f(SIZE, SIZE), const sf::Vector2f & pos = sf::Vector2f(0, 0), const sf::Color & color = sf::Color::White, size_t length = 1); void setSize(const sf::Vector2f & size = sf::Vector2f(SIZE, SIZE)); void setSize(float x = SIZE, float y = SIZE); void setPos(const sf::Vector2f & pos = sf::Vector2f(0, 0)); void setPos(float x, float y); void setPos(const Entity & entity, size_t i); void setColor(const sf::Color & color = sf::Color::White); void setColor(sf::Uint8 r = 255, sf::Uint8 g = 255, sf::Uint8 b = 255, sf::Uint8 a = 255); void setColor(sf::Uint8 r = 255, sf::Uint8 g = 255, sf::Uint8 b = 255); void setColorR(sf::Uint8 val = 255); void setColorG(sf::Uint8 val = 255); void setColorB(sf::Uint8 val = 255); void setColorA(sf::Uint8 val = 255); void setOutline(float thickness, const sf::Color & color); void setLength(size_t length); }; [/spoiler] Entity.cpp [spoiler] #include <SFML/Graphics.hpp> #include "globals.h" #include <vector> #include <iostream> #include "Entity.h" Entity::Entity(const sf::Vector2f & size, const sf::Color & color, size_t length){ set(size, color, length); } Entity::Entity(const sf::Vector2f & size, const sf::Vector2f & pos, const sf::Color & color, size_t length){ set(size, pos, color, length); } std::vector<sf::RectangleShape> Entity::get() const{ return entity; } sf::Vector2f Entity::getSize(size_t i) const{ return entity[i].getSize(); } sf::Vector2f Entity::getPos(size_t i) const{ return entity[i].getPosition(); } sf::Vector2f Entity::getGridPos(size_t i) const{ sf::Vector2f size = entity[i].getSize(); sf::Vector2f pos = entity[i].getPosition(); return sf::Vector2f(pos.x / size.x, pos.y / size.y); } sf::Color Entity::getColor(size_t i) const{ return entity[i].getFillColor(); } size_t Entity::getLength() const{ return entity.size(); } float Entity::getOutlineThickness(size_t i) const{ return entity[i].getOutlineThickness(); } sf::Color Entity::getOutlineColor(size_t i) const{ return entity[i].getOutlineColor(); } void Entity::draw(sf::RenderWindow & window) const{ for (auto item : entity) window.draw(item); } void Entity::set(const sf::Vector2f & size, const sf::Color & color, size_t length){ setLength(length); setSize(size); setColor(color); } void Entity::set(const sf::Vector2f & size, const sf::Vector2f & pos, const sf::Color & color, size_t length){ setLength(length); setSize(size); setPos(pos); setColor(color); } void Entity::setSize(const sf::Vector2f & size){ for (size_t i = 0; i < entity.size(); i++){ entity[i].setSize(size); } } void Entity::setSize(float x, float y){ for (size_t i = 0; i < entity.size(); i++){ entity[i].setSize(sf::Vector2f(x, y)); } } void Entity::setPos(const sf::Vector2f & pos){ entity[0].setPosition(pos); for (size_t i = 1; i < entity.size(); i++){ entity[i].setPosition(entity[i - 1].getPosition() + sf::Vector2f(0, getSize().y)); } } void Entity::setPos(float x, float y){ for (size_t i = 0; i < entity.size(); i++){ entity[i].setPosition(x, y); } } void Entity::setPos(const Entity & entity, size_t i){ for (size_t i = 0; i < this->entity.size(); i++){ this->entity[i].setPosition(entity.getPos(i)); } } void Entity::setColor(const sf::Color & color){ setColor(color.r, color.g, color.b, color.a); } void Entity::setColor(sf::Uint8 r, sf::Uint8 g, sf::Uint8 b, sf::Uint8 a){ setRGBA(r, g, b, a); for (size_t i = 0; i < entity.size(); i++){ entity[i].setFillColor(sf::Color(this->r, this->g, this->b, this->a)); } } void Entity::setColor(sf::Uint8 r, sf::Uint8 g, sf::Uint8 b){ setColor(r, g, b, a); } void Entity::setColorR(sf::Uint8 val){ setColor(val, g, b, a); } void Entity::setColorG(sf::Uint8 val){ setColor(r, val, b, a); } void Entity::setColorB(sf::Uint8 val){ setColor(r, g, val, a); } void Entity::setColorA(sf::Uint8 val){ setColor(r, g, b, val); } void Entity::setOutline(float thickness, const sf::Color & color){ for (size_t i = 0; i < this->entity.size(); i++){ entity[i].setOutlineThickness(thickness); entity[i].setOutlineColor(color); } } void Entity::setLength(size_t length){ entity.resize(length); } [/spoiler] SoundEffect.h [spoiler] #pragma once class SoundEffect { sf::SoundBuffer buffer; sf::Sound sound; std::string path; public: SoundEffect(){}; SoundEffect(std::string file, float volume); float getVolume() const; std::string getPath() const; sf::Sound getSound() const; sf::Sound::Status getStatus() const; void set(std::string file, float volume); void play(); void pause(); void stop(); void setVolume(float volume); void setPath(std::string path); }; [/spoiler] SoundEffect.cpp [spoiler] #include <SFML/Audio.hpp> #include "SoundEffect.h" SoundEffect::SoundEffect(std::string file, float volume){ set(file, volume); } float SoundEffect::getVolume() const{ return sound.getVolume(); } std::string SoundEffect::getPath() const{ return path; } sf::Sound SoundEffect::getSound() const{ return sound; } sf::Sound::Status SoundEffect::getStatus() const{ return sound.getStatus(); } void SoundEffect::set(std::string file, float volume){ setPath(file); setVolume(volume); } void SoundEffect::play(){ sound.play(); } void SoundEffect::pause(){ sound.pause(); } void SoundEffect::stop(){ sound.stop(); } void SoundEffect::setVolume(float volume){ sound.setVolume(volume); } void SoundEffect::setPath(std::string path){ if (!buffer.loadFromFile(path)) std::exit(-1); sound.setBuffer(buffer); } [/spoiler] globals.h [spoiler] #ifndef H_GLBLS #define H_GLBLS const float SIZE = 30; // Snake/Food width and height const int GRIDSIZE = 20; // Grid size x and y const int SCRSIZE = GRIDSIZE * (int)SIZE; // Screen width and height perfectly adjusted to the snake and grid size const std::string FONT = "segoeuil.ttf"; // Preffered font const float OUTLINE = -2; // Should be negativve value in order for outline to be inside snake body const int INTERVAL = 300; // Origin interval const int LIVES = 3; // Origin lives #define RAND_COL sf::Color(rand() % 256, rand() % 256, rand() % 256) #endif [/spoiler]
  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!