diff --git a/README.md b/README.md
index 426ea597..56c073ce 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,23 @@
# Socket Demo
+# Running and playing instructions
+These are the step-by-step instructions for running and playing Assignment 3.
-This code is to be used as a basis for doing assignment 1 and for the tutorials we will do in class.
+1. Build the solution and launch a command window from SocketDemo\RoboCat\Bin\Debug
+2. Run the .exe in the command window with the following arguments. For the first instance of the game, enter a port number and the username of the player.
+Exe: SocketDemo.exe 8000 Harris
+3. For all other instances once the master peer is open, give it the full address of the master peer, followed by the username.
+Exe: SocketDemo.exe 127.0.0.1:8000 Scott
+4. Once all game instances are open, press the S KEY on the master peer instance to start the game.
+5. The game should now be started and you can take the following actions.
+
+LEFT CLICK: Will draw the base game object on both instances. Can be held down to draw more.
+
+RIGHT CLICK: Will delete all game objects at the clicked location
+
+ONE KEY: Will create a different game object at a random location. The locations will be synced
+
+TWO KEY: Will create a 3rd game object at your mouse location. Will then move to a new location every few seconds. (Note: I couldn't get the random working right so while the movement is synced, it's not exactly random.)
+
+SPACE KEY: Will pause all animations. (It's updated every frame, so if the button is held it will toggle quickly.)
+
+ESCAPE: Will quit and end the program. (Can be done even if not connected to other players)
diff --git a/RoboCat/Chapter3.vcxproj b/RoboCat/Chapter3.vcxproj
index 8c859a81..a78cb428 100644
--- a/RoboCat/Chapter3.vcxproj
+++ b/RoboCat/Chapter3.vcxproj
@@ -92,6 +92,12 @@
true
true
Bin\$(Configuration)\
+ true
+ true
+ true
+ true
+ true
+ true
true
@@ -127,8 +133,8 @@
WIN32;_DEBUG;DEBUG;PROFILE;_WINDOWS;_WIN32_WINNT=0x0600;%(PreprocessorDefinitions)
ProgramDatabase
EnableFastChecks
- ..\SDL\include;Inc;..\
- Use
+ ..\SDL\include;Inc;..\;Inc\GraphicsInc;Inc\DeanInc;Inc\BaseGameInc
+ NotUsing
RoboCatPCH.h
@@ -370,10 +376,36 @@
-
+
+
+
+
+
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -386,12 +418,35 @@
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -399,6 +454,7 @@
+
diff --git a/RoboCat/Inc/BaseGameInc/Game.h b/RoboCat/Inc/BaseGameInc/Game.h
new file mode 100644
index 00000000..e098f892
--- /dev/null
+++ b/RoboCat/Inc/BaseGameInc/Game.h
@@ -0,0 +1,98 @@
+#pragma once
+
+#include
+#include
+
+
+
+
+class System;
+class Unit;
+class GraphicsBuffer;
+class UnitManager;
+class MemoryManager;
+class GraphicsBufferManager;
+class NetworkManager;
+typedef std::string GBKey;
+class Game : public Trackable
+{
+public:
+
+ static Game* getInstance();
+ static void initInstance();
+ static void deleteInstance();
+
+ bool init(unsigned int width, unsigned int height, double targetTimePerFrame = 16.7);
+ void cleanup();
+
+ void doLoop();
+
+ System* getSystem() const { return mpSystem; };
+
+ double getTargetTimePerFrame() const { return mTargetTimePerFrame; };
+ GraphicsBufferManager* getGraphicsBufferManager() const { return mpGraphicsBufferManager; };
+ UnitManager* getUnitManager() const { return mpUnitManager; };
+ MemoryManager* getMemoryManager() const { return mpMemoryManager; };
+ NetworkManager* getNetworkManager() const { return mpNetworkManager; };
+ void startGame() { gameStarted = true; };
+
+ enum class ActionTypes
+ {
+ CreateUnit,
+ CreateUnitRand,
+ CreateUnitMove,
+ DestroyUnit,
+ ToggleAnimSingle,
+ ToggleAnimAll
+ };
+ enum class UnitTypes
+ {
+ BASE_UNIT,
+ RAND_DIR,
+ RAND_SPAWN
+ };
+ void HandleAction(ActionTypes, Vector2D, int);
+
+private:
+ static Game* mspInstance;
+
+ System* mpSystem=NULL;
+ UnitManager* mpUnitManager = NULL;
+ GraphicsBufferManager* mpGraphicsBufferManager = NULL;
+ MemoryManager* mpMemoryManager = NULL;
+
+ double mTargetTimePerFrame=0;
+ bool mIsInitted = false;
+ bool mShouldContinue = true;
+ bool gameStarted = false;
+ NetworkManager* mpNetworkManager = NULL;
+
+
+
+ //private constructor/destructor - don't want someone trying to delete the instance directly
+ Game();
+ ~Game();
+
+ //might as well invalidate copy constructor and assignment operator
+ Game(Game& game);
+ void operator=(const Game& game);
+
+ void getInput();
+ void update(double dt);
+ void render();
+
+ void loadBuffers();
+ void createUnit(const Vector2D& pos);
+ void createUnit(int seed);
+ void createUnit(const Vector2D& pos, int seed);
+
+
+};
+
+
+
+const GBKey WOODS("woods");
+const GBKey SMURFS("smurfs");
+const GBKey DEAN("dean");
+const GBKey NUMBERED("numbered");
+
diff --git a/RoboCat/Inc/BaseGameInc/GraphicsBufferManager.h b/RoboCat/Inc/BaseGameInc/GraphicsBufferManager.h
new file mode 100644
index 00000000..522b43bb
--- /dev/null
+++ b/RoboCat/Inc/BaseGameInc/GraphicsBufferManager.h
@@ -0,0 +1,33 @@
+#pragma once
+
+#include
+#include
+#include
+
+#include "Color.h"
+
+class GraphicsBuffer;
+
+typedef std::string GBKey;
+
+class GraphicsBufferManager :public Trackable
+{
+public:
+ GraphicsBufferManager();
+ ~GraphicsBufferManager();
+
+ void clear();
+
+ const GraphicsBuffer* createBuffer(const GBKey& key, const std::string& filename);
+ const GraphicsBuffer* createBuffer(const GBKey& key, unsigned int width, unsigned int height, Color color = Color());
+ const GraphicsBuffer* cloneBuffer(const GBKey& newKey, const GBKey& existingKey);//make a copy of existingKey's buffer and call it newKey
+ const GraphicsBuffer* getBuffer(const GBKey& key) const;
+ bool destroyBuffer(const GBKey& key);
+ bool destroyBuffer(GraphicsBuffer* pBuffer);
+
+ unsigned int getNumBuffersManaged() const { return mMap.size(); };
+ bool alreadyExists(const GBKey& key) const;
+
+private:
+ std::map mMap;
+};
diff --git a/RoboCat/Inc/BaseGameInc/MemoryManager.h b/RoboCat/Inc/BaseGameInc/MemoryManager.h
new file mode 100644
index 00000000..a61e6371
--- /dev/null
+++ b/RoboCat/Inc/BaseGameInc/MemoryManager.h
@@ -0,0 +1,49 @@
+#pragma once
+#include
+#include
+#include
+
+using namespace std;
+
+class MemoryManager : public Trackable {
+public:
+ MemoryManager();
+ ~MemoryManager();
+
+ //Initialization and cleanup functions
+ void init();
+ void cleanup();
+
+ //Function to reset the memory allocations
+ void reset();
+
+ //Allocates memory to appropriate memoryPool
+ Byte* allocate(unsigned int);
+
+ //Deallocates memory from appropriate memoryPool
+ void deallocate(Byte*);
+
+ //returns total allocated memory
+ unsigned int getTotalAllocated() { return mTotalAllocated; };
+
+ //returns total capacity
+ unsigned int getTotalCapacity() { return mTotalCapacity; };
+
+ //returns total waste
+ unsigned int getTotalWaste() { return mTotalWaste; };
+
+private:
+ MemoryPool* mpMemoryPoolSmall; //Pointer to small memory pool
+ MemoryPool* mpMemoryPoolMed; //Pointer to medium memory pool
+ MemoryPool* mpMemoryPoolLarge; //pointer to large memory pool
+
+ unsigned int mTotalCapacity;
+ unsigned int mTotalAllocated;
+
+ unsigned int mTotalWaste;
+
+ unsigned int mMaxCapacity;
+
+
+
+};
diff --git a/RoboCat/Inc/BaseGameInc/NetworkManager.h b/RoboCat/Inc/BaseGameInc/NetworkManager.h
new file mode 100644
index 00000000..a4ae0100
--- /dev/null
+++ b/RoboCat/Inc/BaseGameInc/NetworkManager.h
@@ -0,0 +1,261 @@
+#pragma once
+#include "Trackable.h"
+#include "RoboCatPCH.h"
+#include "Unit.h"
+#include "Game.h"
+class NetworkManager : public Trackable
+{
+public:
+
+ //sent when first trying to join
+ static const uint32_t kHelloCC = 'HELO';
+ //sent when accepted by master peer
+ static const uint32_t kWelcomeCC = 'WLCM';
+ //sent as a reply to HELO if it isn't the master peer
+ static const uint32_t kNotMasterPeerCC = 'NOMP';
+ //sent as a reply to HELO if the game can't be joined (either full or already started)
+ static const uint32_t kNotJoinableCC = 'NOJN';
+ //sent by new player to all non-master peers after being accepted
+ static const uint32_t kIntroCC = 'INTR';
+ //contains data for a particular turn
+ static const uint32_t kUpdateCC = 'UPDT';
+ //notifies peers that the game will be starting soon
+ static const uint32_t kStartCC = 'STRT';
+ static const int kMaxPacketsPerFrameCount = 10;
+
+ enum class NetworkManagerState
+ {
+ NMS_Unitialized,
+ NMS_Hello,
+ NMS_Lobby,
+ //everything above this should be the pre-game/lobby/connection
+ NMS_Starting,
+ NMS_Playing,
+ NMS_Delay,
+ };
+
+
+ //static bool StaticInitAsMasterPeer(uint16_t inPort, const string& inName);
+ //static bool StaticInitAsPeer(const SocketAddress& inMPAddress, const string& inName);
+
+ NetworkManager();
+ ~NetworkManager();
+
+ void cleanup();
+
+ void ProcessIncomingPackets();
+
+ void SendOutgoingPackets();
+
+private:
+ friend struct TransmissionData;
+
+ void UpdateSayingHello(bool inForce = false);
+ void SendHelloPacket();
+ void UpdateStarting();
+ void UpdateSendActionPacket();
+
+
+public:
+ void ProcessPacket(InputMemoryBitStream& inInputStream, const SocketAddress& inFromAddress);
+private:
+ void ProcessPacketsHello(InputMemoryBitStream& inInputStream, const SocketAddress& inFromAddress);
+ void HandleNotMPPacket(InputMemoryBitStream& inInputStream);
+ void HandleWelcomePacket(InputMemoryBitStream& inInputStream);
+ void ProcessPacketsLobby(InputMemoryBitStream& inInputStream, const SocketAddress& inFromAddress);
+ void HandleHelloPacket(InputMemoryBitStream& inInputStream, const SocketAddress& inFromAddress);
+ void HandleIntroPacket(InputMemoryBitStream& inInputStream, const SocketAddress& inFromAddress);
+ void HandleStartPacket(InputMemoryBitStream& inInputStream, const SocketAddress& inFromAddress);
+ void HandleUpdatePacket(InputMemoryBitStream& inInputStream, const SocketAddress& inFromAddress);
+ void ProcessPacketsPlaying(InputMemoryBitStream& inInputStream, const SocketAddress& inFromAddress);
+ void ProcessPacketsDelay(InputMemoryBitStream& inInputStream, const SocketAddress& inFromAddress);
+
+
+public:
+ void HandleConnectionReset(const SocketAddress& inFromAddress);
+
+ void SendPacket(const OutputMemoryBitStream& inOutputStream, const SocketAddress& inToAddress);
+
+ void TryStartGame();
+
+ const WeightedTimedMovingAverage& GetBytesReceivedPerSecond() const { return mBytesReceivedPerSecond; }
+ const WeightedTimedMovingAverage& GetBytesSentPerSecond() const { return mBytesSentPerSecond; }
+
+ void SetDropPacketChance(float inChance) { mDropPacketChance = inChance; }
+ float GetDropPacketChance() const { return mDropPacketChance; }
+ void SetSimulatedLatency(float inLatency) { mSimulatedLatency = inLatency; }
+ float GetSimulatedLatency() const { return mSimulatedLatency; }
+
+ bool IsMasterPeer() const { return mIsMasterPeer; }
+ float GetTimeToStart() const { return mTimeToStart; }
+
+ int GetPlayerCount() const { return mPlayerCount; }
+ uint32_t GetMyPlayerId() const { return mPlayerId; }
+
+ bool InitAsMasterPeer(uint16_t inPort, const string& inName);
+ bool InitAsPeer(const SocketAddress& inMPAddress, const string& inName);
+ bool InitSocket(uint16_t inPort);
+
+ NetworkManagerState GetState() { return mState; };
+
+ void addAction(Game::ActionTypes type, Vector2D pos, int seed);
+
+private:
+
+ class ReceivedPacket
+ {
+ public:
+ ReceivedPacket(float inReceivedTime, InputMemoryBitStream& inInputMemoryBitStream, const SocketAddress& inAddress);
+
+ const SocketAddress& GetFromAddress() const { return mFromAddress; }
+ float GetReceivedTime() const { return mReceivedTime; }
+ InputMemoryBitStream& GetPacketBuffer() { return mPacketBuffer; }
+
+ private:
+
+ float mReceivedTime;
+ InputMemoryBitStream mPacketBuffer;
+ SocketAddress mFromAddress;
+
+ };
+
+ struct ActionData
+ {
+ void Write(OutputMemoryBitStream& inOutputStream);
+ void Read(InputMemoryBitStream& inInputStream);
+ Game::ActionTypes type;
+ Vector2D postion;
+ int seed;
+ };
+
+
+
+
+
+
+ void UpdateBytesSentLastFrame();
+ void ReadIncomingPacketsIntoQueue();
+ void ProcessQueuedPackets();
+
+ void UpdateHighestPlayerId(uint32_t inId);
+ void EnterPlayingState();
+
+ void WritePendingAcks(OutputMemoryBitStream&);
+
+ void ProcessNewAcks(InputMemoryBitStream&);
+ void ProcessSequenceNum(int);
+
+ void WriteNextSequenceNum(OutputMemoryBitStream&);
+
+ //these should stay ordered!
+ typedef map< uint32_t, SocketAddress > IntToSocketAddrMap;
+ typedef map< uint32_t, string > IntToStrMap;
+
+ //Change to Unit pointer?
+ typedef map< uint32_t, Unit* > IntToGameObjectMap;
+ typedef unordered_map< SocketAddress, uint32_t > SocketAddrToIntMap;
+
+
+ queue< ReceivedPacket, list< ReceivedPacket > > mPacketQueue;
+
+ IntToGameObjectMap mNetworkIdToGameObjectMap;
+ IntToSocketAddrMap mPlayerToSocketMap;
+ SocketAddrToIntMap mSocketToPlayerMap;
+
+ IntToStrMap mPlayerNameMap;
+
+ UDPSocketPtr mSocket;
+ SocketAddress mMasterPeerAddr;
+
+
+ int mBytesSentThisFrame;
+ std::string mName;
+ WeightedTimedMovingAverage mBytesReceivedPerSecond;
+ WeightedTimedMovingAverage mBytesSentPerSecond;
+
+ float mDropPacketChance;
+ float mSimulatedLatency;
+
+ float mTimeOfLastHello;
+ float mTimeToStart;
+
+ int mPlayerCount;
+ //we track the highest player id seen in the event
+ //the master peer d/cs and we need a new master peer
+ //who can assign ids
+ uint32_t mHighestPlayerId;
+ uint32_t mNewNetworkId;
+ uint32_t mPlayerId;
+
+ bool mIsMasterPeer;
+
+ NetworkManagerState mState;
+
+ vector mActionVec;
+
+
+ int mNextOutgoingSequenceNumber;
+ int mDispatchedPacketCount;
+ int mNextExpectedSequenceNumber;
+
+ vector mPendingAcks;
+
+ struct TransmissionData : public Trackable
+ {
+ TransmissionData() {};
+ ~TransmissionData() {};
+ virtual void handleDeliveryFailure() { std::cout << sequenceID << " Packet dropped, resending" << std::endl; };
+ virtual void handleDeliverySuccess() {};
+ int sequenceID;
+ uint32_t mPacketType;
+ };
+
+ struct TransmissionDataUpdate : public TransmissionData
+ {
+ TransmissionDataUpdate(uint32_t id) {mPlayerID = id;};
+ void handleDeliveryFailure();
+ //virtual void handleDeliverySuccess();
+
+ vector mData;
+ uint32_t mPlayerID;
+ };
+
+ struct TransmissionDataHello : public TransmissionData
+ {
+ TransmissionDataHello(string name) { mName = name; };
+ void handleDeliveryFailure();
+ //virtual void handleDeliverySuccess();
+
+ string mName;
+ };
+
+ struct TransmissionDataWelcome : public TransmissionData
+ {
+ TransmissionDataWelcome() { };
+ void handleDeliveryFailure();
+ //virtual void handleDeliverySuccess();
+
+ uint32_t mHighestID;
+ uint32_t mID;
+ };
+
+ struct TransmissionDataIntro : public TransmissionData
+ {
+ TransmissionDataIntro(string name, int id) { mName = name; mID = id; };
+ void handleDeliveryFailure();
+ //virtual void handleDeliverySuccess();
+
+ uint32_t mID;
+ string mName;
+ };
+
+ struct TransmissionDataStart : public TransmissionData
+ {
+ TransmissionDataStart() {};
+ void handleDeliveryFailure();
+ //virtual void handleDeliverySuccess();
+ };
+
+ map mInFlightPackets;
+ void AddInFlightPacket(TransmissionData*, OutputMemoryBitStream&);
+};
\ No newline at end of file
diff --git a/RoboCat/Inc/BaseGameInc/Unit.h b/RoboCat/Inc/BaseGameInc/Unit.h
new file mode 100644
index 00000000..321f9318
--- /dev/null
+++ b/RoboCat/Inc/BaseGameInc/Unit.h
@@ -0,0 +1,93 @@
+#pragma once
+
+#include
+#include
+#include
+
+#include "Animation.h"
+
+class UnitManager;
+
+
+
+class Unit : public Trackable
+{
+ friend class UnitManager;
+public:
+
+ Unit(const Vector2D& position, const Animation& mainAnimation, const Animation& altAnimation);
+ Unit() { mMainAnimation = NULL; mAltAnimation = NULL; mpCurrentAnimation = nullptr; };
+ virtual ~Unit() {};
+
+ virtual void update(double dt);
+ virtual void draw();
+ virtual void setPosition(const Vector2D& newPos) { mPos = newPos; };
+ virtual void toggleAnimation();
+ void speedUpAnimation();
+ void slowDownAnimation();
+ virtual void setAnimationPauseState(bool shouldPause);
+ virtual void toggleAnimationPauseState();
+ virtual bool doesPointIntersect(const Vector2D& point) const;
+ virtual Vector2D getULPosition() const;
+ virtual Vector2D getCenterPosition() const { return mPos; };
+ virtual Vector2D getLRPosition() const;
+
+private:
+ Animation mMainAnimation;
+ Animation mAltAnimation;
+ Animation* mpCurrentAnimation;
+ Vector2D mPos;
+};
+
+class RandomSpawnedUnit : public Unit
+{
+public:
+ RandomSpawnedUnit(const Vector2D& position, const Animation& mainAnimation, const Animation& altAnimation, int seed);
+
+ virtual ~RandomSpawnedUnit() {};
+
+ virtual void update(double dt);
+ virtual void draw();
+ virtual void setPosition(const Vector2D& newPos) { mPos = newPos; };
+ virtual void toggleAnimation();
+ virtual bool doesPointIntersect(const Vector2D& point) const;
+ virtual Vector2D getULPosition() const;
+ virtual Vector2D getCenterPosition() const { return mPos; };
+ virtual Vector2D getLRPosition() const;
+ virtual void setAnimationPauseState(bool shouldPause);
+ virtual void toggleAnimationPauseState();
+
+private:
+ Animation mMainAnimation;
+ Animation mAltAnimation;
+ Animation* mpCurrentAnimation;
+ Vector2D mPos;
+ int mSeed;
+};
+
+class RandomPosUnit : public Unit
+{
+public:
+ RandomPosUnit(const Vector2D& position, const Animation& mainAnimation, const Animation& altAnimation, int seed);
+
+ virtual ~RandomPosUnit() {};
+
+ virtual void update(double dt);
+ virtual void draw();
+ virtual void setPosition(const Vector2D& newPos) { mPos = newPos; };
+ virtual void toggleAnimation();
+ virtual bool doesPointIntersect(const Vector2D& point) const;
+ virtual Vector2D getULPosition() const;
+ virtual Vector2D getCenterPosition() const { return mPos; };
+ virtual Vector2D getLRPosition() const;
+ virtual void setAnimationPauseState(bool shouldPause);
+ virtual void toggleAnimationPauseState();
+
+private:
+ Animation mMainAnimation;
+ Animation mAltAnimation;
+ Animation* mpCurrentAnimation;
+ Vector2D mPos;
+ int mSeed;
+ double timer = 3;
+};
diff --git a/RoboCat/Inc/BaseGameInc/UnitManager.h b/RoboCat/Inc/BaseGameInc/UnitManager.h
new file mode 100644
index 00000000..91cd11c7
--- /dev/null
+++ b/RoboCat/Inc/BaseGameInc/UnitManager.h
@@ -0,0 +1,40 @@
+#pragma once
+
+#include
+#include
+#include
+
+class Unit;
+class Animation;
+class Sprite;
+
+class UnitManager : public Trackable
+{
+public:
+ UnitManager();
+ ~UnitManager();
+
+ void clear();//remove and delete all units
+
+ void update(double dt);
+ void draw() const;
+
+ Unit* createUnit(const Vector2D& position, const Animation& mainAnimation, const Animation& altAnimation);
+ Unit* createUnit(const Vector2D& position, const Animation& mainAnimation, const Animation& altAnimation, int seed);
+ Unit* createUnit(const Animation& mainAnimation, const Animation& altAnimation, int seed);
+
+ void deleteAllUnitsAt2DPosition(const Vector2D& position);
+ bool deleteUnitAt2DPosition(const Vector2D& position);//return true if unit found and deleted - false otherwise
+ void deleteUnitAtIndex(unsigned int index);
+ void deleteUnit(Unit* pUnit);
+
+ Unit* getLastUnitCreated() const;
+ void setPauseStateForAllAnimations( bool isPaused );
+ void togglePauseStateForAllAnimations();
+
+ unsigned int getNumUnits() const { return mUnits.size(); };
+
+private:
+ std::vector mUnits;
+ uint32_t nextID;
+};
diff --git a/RoboCat/Inc/DeanInc/CircularQueue.h b/RoboCat/Inc/DeanInc/CircularQueue.h
new file mode 100644
index 00000000..5955cf0a
--- /dev/null
+++ b/RoboCat/Inc/DeanInc/CircularQueue.h
@@ -0,0 +1,70 @@
+#pragma once
+#include
+#include
+
+template < class T >
+class CircularQueue : public Trackable
+{
+public:
+ explicit CircularQueue(Uint32 size)
+ : mCapacity(size)
+ , mFront(0)
+ , mBack(0)
+ , mNumEntries(0)
+ {
+ mArray = new T[size];
+ }
+
+ ~CircularQueue()
+ {
+ delete[] mArray;
+ }
+
+ void reset()
+ {
+ mFront = 0;
+ mBack = 0;
+ mNumEntries = 0;
+ }
+
+ bool pushBack(const T& item)//return false if not successfully added (not enough space)
+ {
+ if (mNumEntries >= mCapacity)//no room left
+ return false;
+
+ mArray[mBack] = item;
+ mBack++;
+ mNumEntries++;
+
+ if (mBack >= mCapacity)
+ {
+ mBack = 0;
+ }
+
+ return true;
+ }
+
+ bool popFront(T& item)//returns false if queue is empty
+ {
+ if (mNumEntries == 0)//empty
+ return false;
+
+ item = mArray[mFront];
+ mFront++;
+ mNumEntries--;
+
+ if (mFront >= mCapacity)
+ {
+ mFront = 0;
+ }
+
+ return true;
+ }
+private:
+ T* mArray;
+ Uint32 mCapacity;
+ Uint32 mBack;
+ Uint32 mFront;
+ Uint32 mNumEntries;
+};
+
diff --git a/RoboCat/Inc/DeanInc/ConditionalCallback.h b/RoboCat/Inc/DeanInc/ConditionalCallback.h
new file mode 100644
index 00000000..f22a14cb
--- /dev/null
+++ b/RoboCat/Inc/DeanInc/ConditionalCallback.h
@@ -0,0 +1,45 @@
+#pragma once
+
+#pragma once
+
+#include
+
+/*template
+void callbackFunc(T var)
+{
+ F(var);
+}*/
+
+template
+class ConditionalCallback :public Trackable
+{
+public:
+ ConditionalCallback(bool(*condFunc)(), void(*func)(const T&), const T& val)
+ :mpCallbackFunc(func)
+ , mpConditionalFunc(condFunc)
+ , mValue(val)
+ {
+ };
+
+ bool update(double dtInMS)//returns true after calling callback, false otherwise
+ {
+ if (mpConditionalFunc())
+ {
+ call(mValue);
+ return true;
+ }
+ else
+ return false;
+ }
+
+private:
+ void(*mpCallbackFunc)(const &T) = nullptr;
+ bool(*mpConditionalFunc)() = nullptr;
+ T mValue;
+
+ void call(const T& var)
+ {
+ mpCallbackFunc(var);
+ };
+
+};
diff --git a/RoboCat/Inc/DeanInc/DataRepository.h b/RoboCat/Inc/DeanInc/DataRepository.h
new file mode 100644
index 00000000..cf5497f2
--- /dev/null
+++ b/RoboCat/Inc/DeanInc/DataRepository.h
@@ -0,0 +1,76 @@
+#pragma once
+#include
+
+#include
+#include
+#include
+#include
+
+const UINT MAX_STRING_VAL_SIZE = 128;
+
+union DataUnion
+{
+ int intVal;
+ float floatVal;
+ double doubleVal;
+ char stringVal[MAX_STRING_VAL_SIZE];
+ UINT uintVal;
+
+};
+
+enum DataType
+{
+ INT_VAL,
+ FLOAT_VAL,
+ DOUBLE_VAL,
+ STRING_VAL,
+ UINT_VAL
+};
+
+class DataEntry: public Trackable
+{
+public:
+ DataEntry( int val );
+ DataEntry( float val );
+ DataEntry( double val );
+ DataEntry( const std::string& val );
+ DataEntry( UINT val );
+ DataEntry() :mType(UINT_VAL) { mData.uintVal = 0; };
+
+ ~DataEntry(){};
+
+ inline int getIntVal() const { assert( mType == INT_VAL ); return mData.intVal; };
+ inline float getFloatVal() const { assert( mType == FLOAT_VAL ); return mData.floatVal; };
+ inline double getDoubleVal() const { assert( mType == DOUBLE_VAL ); return mData.doubleVal; };
+ inline std::string getStringVal() const { assert( mType == STRING_VAL ); return std::string(mData.stringVal); };
+ inline UINT getUIntVal() const { assert( mType == UINT_VAL ); return mData.uintVal; };
+private:
+ DataType mType;
+ DataUnion mData;
+
+};
+
+typedef int DataKey;
+
+class DataRepository : public Trackable
+{
+
+public:
+ DataRepository(){};
+ ~DataRepository(){};
+
+ void addEntry( const DataKey& key, int val );
+ void addEntry( const DataKey& key, float val );
+ void addEntry( const DataKey& key, double val );
+ void addEntry( const DataKey& key, const std::string& val );
+ void addEntry( const DataKey& key, UINT val );
+
+ const DataEntry& getEntry( const DataKey& key );
+
+ bool hasEntry(const DataKey& key);
+private:
+ std::unordered_map mMap;
+};
+
+
+
diff --git a/RoboCat/Inc/DeanInc/DeanLibDefines.h b/RoboCat/Inc/DeanInc/DeanLibDefines.h
new file mode 100644
index 00000000..2e235717
--- /dev/null
+++ b/RoboCat/Inc/DeanInc/DeanLibDefines.h
@@ -0,0 +1,4 @@
+#pragma once
+
+typedef unsigned char Byte;
+typedef unsigned int Uint32;
\ No newline at end of file
diff --git a/RoboCat/Inc/DeanInc/DeanLibUtilities.h b/RoboCat/Inc/DeanInc/DeanLibUtilities.h
new file mode 100644
index 00000000..a09ca5a4
--- /dev/null
+++ b/RoboCat/Inc/DeanInc/DeanLibUtilities.h
@@ -0,0 +1,9 @@
+#pragma once
+
+#include
+#include
+
+std::string peekString(std::istream& stream);
+int peekInt(std::istream& stream);
+
+
diff --git a/RoboCat/Inc/DeanInc/DeanMath.h b/RoboCat/Inc/DeanInc/DeanMath.h
new file mode 100644
index 00000000..6dbba171
--- /dev/null
+++ b/RoboCat/Inc/DeanInc/DeanMath.h
@@ -0,0 +1,15 @@
+#pragma once
+
+class Vector2D;
+
+const double PI = 3.14159265358979323846;
+const double DOUBLE_PI = PI*2;
+const double HALF_PI = PI / 2;
+const double QUARTER_PI = PI / 2;
+
+double mapToRangeMinusPiToPi(double val);
+
+double calcDotProduct(const Vector2D& vector1, const Vector2D& vector2);
+
+double lerp(double low, double high, double pct);
+int lerp(int low, int high, double pct);
diff --git a/RoboCat/Inc/DeanInc/MemoryPool.h b/RoboCat/Inc/DeanInc/MemoryPool.h
new file mode 100644
index 00000000..e97c8699
--- /dev/null
+++ b/RoboCat/Inc/DeanInc/MemoryPool.h
@@ -0,0 +1,33 @@
+#pragma once
+
+#include "DeanLibDefines.h"
+#include "CircularQueue.h"
+#include "Trackable.h"
+
+
+class MemoryPool: public Trackable
+{
+public:
+ MemoryPool(unsigned int maxNumObjects, unsigned int objectSize);
+ ~MemoryPool() { free(mMemory); delete mpFreeList; };
+
+ void reset();//doesn't reallocate memory but does reset free list and num allocated objects
+
+ Byte* allocateObject();
+ void freeObject(Byte* ptr);
+
+ inline Uint32 getMaxObjectSize(){ return mObjectSize; };
+ inline Uint32 getNumFreeObjects(){ return mMaxNumObjects - mNumAllocatedObjects; };
+
+ bool contains(Byte* ptr) const;
+
+private:
+ Byte* mMemory;
+ Byte* mHighestValidAddress;
+ Uint32 mMaxNumObjects;
+ Uint32 mNumAllocatedObjects;
+ Uint32 mObjectSize;
+ CircularQueue* mpFreeList;
+
+ void createFreeList();
+};
\ No newline at end of file
diff --git a/RoboCat/Inc/DeanInc/MemoryTracker.h b/RoboCat/Inc/DeanInc/MemoryTracker.h
new file mode 100644
index 00000000..4c3bac84
--- /dev/null
+++ b/RoboCat/Inc/DeanInc/MemoryTracker.h
@@ -0,0 +1,38 @@
+#pragma once
+
+#include
+#include
+
+
+class MemoryTracker
+{
+public:
+ static MemoryTracker* getInstance();
+
+ void addAllocation( void* ptr, size_t size );
+ void removeAllocation( void* ptr );
+
+ void reportAllocations( std::ostream& stream );
+
+private:
+ struct AllocationRecord
+ {
+ AllocationRecord(int theNum, size_t theSize) : num(theNum), size(theSize) {};
+ int num;
+ size_t size;
+ };
+
+
+ MemoryTracker();
+ ~MemoryTracker();
+
+ //copying not allowed
+ MemoryTracker( const MemoryTracker& );
+ MemoryTracker& operator=( const MemoryTracker& );
+
+ std::unordered_map mAllocations;
+
+ static int msAllocationNum;
+ static MemoryTracker* mspInstance;
+};
+
diff --git a/RoboCat/Inc/DeanInc/MultiDimensionalArray.h b/RoboCat/Inc/DeanInc/MultiDimensionalArray.h
new file mode 100644
index 00000000..040f1dde
--- /dev/null
+++ b/RoboCat/Inc/DeanInc/MultiDimensionalArray.h
@@ -0,0 +1,62 @@
+#pragma once
+
+#include "Trackable.h"
+
+template < class T >
+class MultiDimensionalArray :public Trackable
+{
+public:
+ explicit MultiDimensionalArray(unsigned int numRows, unsigned int numCols, const T& initialValue)
+ :mNumRows(numRows)
+ ,mNumCols(numCols)
+ {
+ mArray = new T[mNumRows*mNumCols];
+ for (unsigned int i = 0; i < mNumRows*mNumCols; i++)
+ {
+ mArray[i] = initialValue;
+ }
+
+ }
+
+ ~MultiDimensionalArray()
+ {
+ delete [] mArray;
+ }
+
+ T* get(unsigned int index)
+ {
+ if (index < mNumRows * mNumCols)
+ {
+ return &(mArray[index]);
+ }
+ else
+ return NULL;
+ }
+
+ T* get(unsigned int colNum, unsigned int rowNum)
+ {
+ return get(convertCoordsToIndex(colNum,rowNum));
+ }
+
+ void set(unsigned int index, const T& val) { *(get(index)) = val; }
+ void set(unsigned int colNum, unsigned int rowNum, const T& val) { *(get(colNum,rowNum)) = val; }
+
+ void convertIndexToCoords(unsigned int index, unsigned int& xOut, unsigned int& yOut)
+ {
+ xOut = index % mNumCols;
+ yOut = index / mNumCols;
+ }
+
+ unsigned int convertCoordsToIndex(const unsigned int& xIn, const unsigned int& yIn)
+ {
+ unsigned int index = yIn * mNumCols + xIn;
+ return index;
+ }
+
+private:
+ T* mArray;
+ unsigned int mNumRows;
+ unsigned int mNumCols;
+
+
+};
diff --git a/RoboCat/Inc/DeanInc/PerformanceTracker.h b/RoboCat/Inc/DeanInc/PerformanceTracker.h
new file mode 100644
index 00000000..bfb5dc41
--- /dev/null
+++ b/RoboCat/Inc/DeanInc/PerformanceTracker.h
@@ -0,0 +1,24 @@
+#pragma once
+
+#include "Timer.h"
+
+#include
+#include
+#include "Trackable.h"
+
+class PerformanceTracker: public Trackable
+{
+public:
+ PerformanceTracker();
+ ~PerformanceTracker();
+
+ void startTracking( const std::string& trackerName );
+ void stopTracking( const std::string& trackerName );
+ double getElapsedTime( const std::string& trackerName );
+ void removeTracker( const std::string& trackerName );
+ void clearTracker( const std::string& trackerName );
+
+private:
+ std::map mTimers;
+};
+
diff --git a/RoboCat/Inc/DeanInc/RayCaster.h b/RoboCat/Inc/DeanInc/RayCaster.h
new file mode 100644
index 00000000..d17e76d5
--- /dev/null
+++ b/RoboCat/Inc/DeanInc/RayCaster.h
@@ -0,0 +1,12 @@
+#pragma once
+
+#include "Trackable.h"
+#include "Vector2D.h"
+
+#include
+
+class RayCaster :public Trackable
+{
+public:
+ static std::vector getPoints(const Vector2D& start, const Vector2D& end, float interval);
+};
\ No newline at end of file
diff --git a/RoboCat/Inc/DeanInc/TimedCallback.h b/RoboCat/Inc/DeanInc/TimedCallback.h
new file mode 100644
index 00000000..1bf52447
--- /dev/null
+++ b/RoboCat/Inc/DeanInc/TimedCallback.h
@@ -0,0 +1,56 @@
+#pragma once
+
+#include
+
+//template
+//void callbackFunc(T var)
+//{
+// F(var);
+//}
+
+template
+class TimedCallback :public Trackable
+{
+public:
+ TimedCallback(double delayInMS, void(*func)(const T&), const T& val)
+ :mDelayInMS(delayInMS)
+ ,mTimeLeft(delayInMS)
+ ,mpCallbackFunc(func)
+ ,mValue(val)
+ {
+ };
+
+ bool update(double dtInMS)//returns true after calling callback, false otherwise
+ {
+ mTimeLeft -= dtInMS;
+ if (mTimeLeft <= 0.0)
+ {
+ call(mValue);
+ return true;
+ }
+ else
+ return false;
+ }
+
+ void reset(double delayInMS)
+ {
+ mDelayInMS = delayInMS;
+ mTimeLeft = delayInMS;
+ }
+
+ void setValue(const T& val)
+ {
+ mValue = val;
+ }
+private:
+ void(*mpCallbackFunc)(const T&) = nullptr;
+ double mDelayInMS = 0.0;
+ double mTimeLeft = 0.0;
+ T mValue;
+
+ void call(const T& var)
+ {
+ mpCallbackFunc(var);
+ };
+
+};
diff --git a/RoboCat/Inc/DeanInc/Timer.h b/RoboCat/Inc/DeanInc/Timer.h
new file mode 100644
index 00000000..5a4e2f53
--- /dev/null
+++ b/RoboCat/Inc/DeanInc/Timer.h
@@ -0,0 +1,40 @@
+#pragma once
+#include
+#include "Trackable.h"
+
+/* Timer - high accuracy timer - uses Large Integer to prevent rollover
+
+Dean Lawson
+Champlain College
+2011
+*/
+
+class Timer:public Trackable
+{
+public:
+ Timer();
+ ~Timer();
+
+ void start();
+ void stop();
+ double getElapsedTime() const;//returns how much time has elapsed since start
+ void sleepUntilElapsed( double ms );
+ void pause( bool shouldPause );
+ inline double getFactor() const { return mFactor; };
+ inline void multFactor( double mult ) { mLastFactor = mFactor; mFactor *= mult; };
+ inline void setFactor( double theFactor ) { mLastFactor = mFactor; mFactor = theFactor; };
+ inline void restoreLastFactor() { mFactor = mLastFactor; };
+
+private:
+ LARGE_INTEGER mStartTime;
+ LARGE_INTEGER mEndTime;
+ LARGE_INTEGER mTimerFrequency;
+ double mElapsedTime;
+ double mFactor;
+ double mLastFactor;
+ bool mPaused;
+
+ //helper function - uses current frequency for the Timer
+ double calcDifferenceInMS( LARGE_INTEGER from, LARGE_INTEGER to ) const;
+
+};
\ No newline at end of file
diff --git a/RoboCat/Inc/DeanInc/Trackable.h b/RoboCat/Inc/DeanInc/Trackable.h
new file mode 100644
index 00000000..ab7b4ba0
--- /dev/null
+++ b/RoboCat/Inc/DeanInc/Trackable.h
@@ -0,0 +1,23 @@
+#pragma once
+
+#include
+#include "RoboCatPCH.h"
+class Trackable
+{
+public:
+ Trackable() {}
+ void* operator new(std::size_t size);
+ void operator delete(void *ptr);
+ void* operator new[](std::size_t size);
+ void operator delete[](void *ptr);
+
+ //for use with placement new
+ void* operator new(std::size_t size, void* ptr) { UNREFERENCED_PARAMETER(size); return ptr; };
+ void operator delete(void* ptr, void* ptr2) { UNREFERENCED_PARAMETER(ptr); UNREFERENCED_PARAMETER(ptr2); };
+ void* operator new[](std::size_t size, void* ptr){ UNREFERENCED_PARAMETER(size); return ptr; };
+ void operator delete[](void *ptr, void* ptr2){UNREFERENCED_PARAMETER(ptr); UNREFERENCED_PARAMETER(ptr2); };
+
+ const std::string& getDebugSource() { static std::string junk; return junk; }
+
+private:
+};
diff --git a/RoboCat/Inc/DeanInc/Vector2D.h b/RoboCat/Inc/DeanInc/Vector2D.h
new file mode 100644
index 00000000..60342574
--- /dev/null
+++ b/RoboCat/Inc/DeanInc/Vector2D.h
@@ -0,0 +1,75 @@
+#pragma once
+
+/* Vector2D is a generally usable 2D vector. Most of the operator overloading code is patterned after the notes from
+ California Institue of Technology site: http://www.cs.caltech.edu/courses/cs11/material/cpp/donnie/cpp-ops.html .
+ Exact author unknown.
+ May be missing some important functions but this should be enough to do most things.
+
+ by Dean Lawson
+ Champlain College
+ 2011
+*/
+
+#include "Trackable.h"
+#include "DeanMath.h"
+#include
+#include
+
+
+class Vector2D :public Trackable
+{
+ friend std::ostream& operator<< (std::ostream& out, const Vector2D& vector);
+
+public:
+ explicit Vector2D(float x = 0.0f, float y = 0.0f);//constructor
+ explicit Vector2D(int x, int y);//constructor
+ Vector2D(const Vector2D& rhs);//copy constructor
+ ~Vector2D();//destructor
+
+ //math operators
+ Vector2D& operator += (const Vector2D& rhs);
+ Vector2D& operator -= (const Vector2D& rhs);
+ Vector2D& operator *= (float mult);
+ Vector2D& operator /= (float div);
+ Vector2D& operator = (const Vector2D& rhs);
+
+ bool operator == (const Vector2D& rhs)const;
+ bool operator != (const Vector2D& rhs)const;
+
+ Vector2D operator+(const Vector2D& other) const;
+ Vector2D operator-(const Vector2D& other) const;
+ Vector2D operator*(float mult) const;
+ Vector2D operator/(float div) const;
+
+ //getters and setters
+ inline float getX() const { return mX; };
+ inline float getY() const { return mY; };
+ inline void setX(float x) { mX = x; };
+ inline void setY(float y) { mY = y; };
+
+ //length functions
+ bool hasNonZeroLength() const;
+ float getLength() const;
+ float getLengthSquared() const;//more efficient than get length - use when comparing distances and actual distance is not needed
+
+ void normalize();//makes vector a unit vector (length of 1)
+ Vector2D getNormalizedVector() const;//returns a vector of length 1 but leaves the original vector unchanged
+ float dotProduct(const Vector2D& other) const;
+ Vector2D getRightVector() const;//right vector is a vector perpendicular and on the right side
+ double calcFacing() const;
+ static Vector2D getVectorInDirection(double direction);
+ static Vector2D getVectorInOppositeDirection(const Vector2D& vec);
+ static Vector2D getVectorInOppositeDirection(double direction);
+
+ static float getDistanceBetween(const Vector2D& vec1, const Vector2D& vec2);
+ static float getSquaredDistanceBetween(const Vector2D& vec1, const Vector2D& vec2);
+
+private:
+ float mX;
+ float mY;
+};
+
+std::ostream& operator<< (std::ostream& out, const Vector2D& vector);
+
+const Vector2D ZERO_VECTOR2D(0.0f, 0.0f);//useful when we need to return a pointer to a default vector from a function
+
diff --git a/RoboCat/Inc/GraphicsInc/Animation.h b/RoboCat/Inc/GraphicsInc/Animation.h
new file mode 100644
index 00000000..4dc8f9ba
--- /dev/null
+++ b/RoboCat/Inc/GraphicsInc/Animation.h
@@ -0,0 +1,44 @@
+#pragma once
+
+#include "Sprite.h"
+#include
+
+class GraphicsBuffer;
+
+class Animation
+{
+public:
+ Animation(float timePerFrame, bool isPaused = false, bool looping = true);
+ Animation(const GraphicsBuffer& buffer,
+ int spriteW,
+ int spriteH,
+ int numAcross,
+ int numDown,
+ float timePerFrame,
+ bool mIsPaused = false,
+ bool looping = true);
+
+ Animation();
+
+ ~Animation() {};
+
+ void addSprite(const Sprite& theSprite);
+ void setTimePerFrame(float newTimePerFrame);
+ float getTimePerFrame() const { return mTimePerFrame; };
+
+ void setPauseState(bool shouldPause) { mIsPaused = shouldPause; };
+ void togglePause() { mIsPaused = !mIsPaused; };
+
+ void synch(const Animation& otherAnimation);
+
+ const Sprite& getCurrentSprite() const;
+ void update(double dt);
+
+private:
+ std::vector mSprites;
+ int mCurrentSprite;
+ bool mLooping;
+ bool mIsPaused;
+ float mTimePerFrame;
+ float mTimeUntilNextFrame;
+};
diff --git a/RoboCat/Inc/GraphicsInc/Color.h b/RoboCat/Inc/GraphicsInc/Color.h
new file mode 100644
index 00000000..a7038ae3
--- /dev/null
+++ b/RoboCat/Inc/GraphicsInc/Color.h
@@ -0,0 +1,26 @@
+#pragma once
+
+#include
+
+#include
+
+class GraphicsSystem;
+
+class Color :public Trackable
+{
+ friend GraphicsSystem;
+public:
+ Color(int r=255, int g=255, int b=255, int a = 255);
+ Color(float r, float g, float b, float a = 1.0f);
+
+ int getR() const { return mR; };
+ int getG() const { return mG; };
+ int getB() const { return mB; };
+ int getA() const { return mA; };
+
+private:
+ int mR = 255;
+ int mG = 255;
+ int mB = 255;
+ int mA = 255;
+};
diff --git a/RoboCat/Inc/GraphicsInc/Font.h b/RoboCat/Inc/GraphicsInc/Font.h
new file mode 100644
index 00000000..5ee03126
--- /dev/null
+++ b/RoboCat/Inc/GraphicsInc/Font.h
@@ -0,0 +1,34 @@
+#pragma once
+
+#include
+#include
+#include
+
+#include
+
+#include
+
+class GraphicsSystem;
+
+class Font:public Trackable
+{
+ friend class GraphicsSystem;
+public:
+ enum Alignment
+ {
+ LEFT,
+ CENTER,
+ RIGHT
+ };
+
+ Font(const std::string& filename,int size);
+ ~Font();
+
+ int getSize() const { return mSize; };
+
+private:
+ ALLEGRO_FONT * mpFont;
+ int mSize;
+
+ ALLEGRO_FONT* getFont() const { return mpFont; };
+};
diff --git a/RoboCat/Inc/GraphicsInc/GraphicsBuffer.h b/RoboCat/Inc/GraphicsInc/GraphicsBuffer.h
new file mode 100644
index 00000000..14613297
--- /dev/null
+++ b/RoboCat/Inc/GraphicsInc/GraphicsBuffer.h
@@ -0,0 +1,38 @@
+#pragma once
+
+#include
+#include
+
+#include
+
+#include
+#include "Color.h"
+
+class GraphicsSystem;
+class GraphicsBufferManager;
+
+class GraphicsBuffer : public Trackable
+{
+ friend class GraphicsSystem;
+ friend class GraphicsBufferManager;
+public:
+
+ unsigned int getWidth() const { return al_get_bitmap_width(mpBitmap); };
+ unsigned int getHeight() const { return al_get_bitmap_height(mpBitmap); };
+
+private:
+ ALLEGRO_BITMAP* mpBitmap = NULL;
+ bool mOwnsBitmap = true;
+
+ GraphicsBuffer(ALLEGRO_DISPLAY* pDisplay);//to be called by GraphicsSystem only
+ ALLEGRO_BITMAP* getBitmap() const { return mpBitmap; };//to be called by GraphicsSystem only
+
+ GraphicsBuffer(const std::string& filename);//to be called by GraphicsBufferManager
+ GraphicsBuffer(unsigned int width, unsigned int height, Color color = Color());//to be called by GraphicsBufferManager
+ ~GraphicsBuffer();//to be called by GraphicsBufferManager
+ GraphicsBuffer* clone() const;//to be called by GraphicsBufferManager
+
+
+ GraphicsBuffer(GraphicsBuffer&);
+ GraphicsBuffer operator=(GraphicsBuffer&);//invalid
+};
diff --git a/RoboCat/Inc/GraphicsInc/GraphicsLib.h b/RoboCat/Inc/GraphicsInc/GraphicsLib.h
new file mode 100644
index 00000000..73edef45
--- /dev/null
+++ b/RoboCat/Inc/GraphicsInc/GraphicsLib.h
@@ -0,0 +1,3 @@
+#pragma once
+
+int initAllegro();
diff --git a/RoboCat/Inc/GraphicsInc/GraphicsSystem.h b/RoboCat/Inc/GraphicsInc/GraphicsSystem.h
new file mode 100644
index 00000000..a024875c
--- /dev/null
+++ b/RoboCat/Inc/GraphicsInc/GraphicsSystem.h
@@ -0,0 +1,53 @@
+#pragma once
+
+#include
+#include
+
+#include
+
+#include "Color.h"
+#include "Font.h"
+
+class GraphicsBuffer;
+class Sprite;
+class System;
+
+class GraphicsSystem :public Trackable
+{
+ friend class System;
+public:
+ unsigned int getDisplayWidth() const { return mWidth; };
+ unsigned int getDisplayHeight() const { return mHeight; };
+ GraphicsBuffer* getBackBuffer() const { return mpBackBuffer; };
+
+ void flip();
+
+ static void draw(const Vector2D& destLoc, const GraphicsBuffer& src, double scale = 1.0);
+ static void draw(GraphicsBuffer& dest, const Vector2D& loc, const GraphicsBuffer& src, double scale = 1.0);
+ static void draw(const Vector2D& destLoc, const Sprite& sprite, double scale = 1.0);
+ static void draw(GraphicsBuffer& dest, const Vector2D& destLoc, const Sprite& sprite, double scale = 1.0);
+ static void writeText(GraphicsBuffer& dest, const Vector2D& destLoc, const Font& font, const Color& color, const std::string& text, Font::Alignment align = Font::LEFT);
+ static void writeText(const Vector2D& destLoc, const Font& font, const Color& color, const std::string& text, Font::Alignment align = Font::LEFT);
+
+ static void setBufferToColor(GraphicsBuffer& buffer, const Color& color);
+ static void saveBufferToFile(const GraphicsBuffer& buffer, const std::string& filename);
+private:
+ ALLEGRO_DISPLAY* mDisplay = NULL;
+ GraphicsBuffer* mpBackBuffer = NULL;
+ bool mIsInitted = false;
+ unsigned int mWidth = 0;
+ unsigned int mHeight = 0;
+
+ GraphicsSystem();
+ ~GraphicsSystem();
+
+ bool init(unsigned int width, unsigned int height);
+ void cleanup();
+
+ bool initAddOns();
+ ALLEGRO_DISPLAY* getDisplay() const { return mDisplay; };
+ static ALLEGRO_COLOR getAllegroColorFromColor(const Color& color);
+ static int getAllegroFontAlignFlag(Font::Alignment align);
+
+
+};
diff --git a/RoboCat/Inc/GraphicsInc/Sprite.h b/RoboCat/Inc/GraphicsInc/Sprite.h
new file mode 100644
index 00000000..32424ac4
--- /dev/null
+++ b/RoboCat/Inc/GraphicsInc/Sprite.h
@@ -0,0 +1,24 @@
+#pragma once
+
+#include
+#include
+
+class GraphicsBuffer;
+
+class Sprite : public Trackable
+{
+public:
+ Sprite(const GraphicsBuffer* pBuffer, const Vector2D& srcLoc, int width, int height);
+ Sprite() {};
+
+ const GraphicsBuffer* getBuffer() const { return mpBuffer; };
+ const Vector2D& getSourceLoc() const { return mSrcLoc; };
+ int getWidth() const { return mWidth; };
+ int getHeight() const { return mHeight; };
+ Vector2D getCenterOffset() const { return Vector2D(mWidth / 2, mHeight / 2); };
+private:
+ const GraphicsBuffer* mpBuffer = NULL;
+ Vector2D mSrcLoc = ZERO_VECTOR2D;
+ int mWidth = 0;
+ int mHeight = 0;
+};
\ No newline at end of file
diff --git a/RoboCat/Inc/GraphicsInc/System.h b/RoboCat/Inc/GraphicsInc/System.h
new file mode 100644
index 00000000..ee878305
--- /dev/null
+++ b/RoboCat/Inc/GraphicsInc/System.h
@@ -0,0 +1,45 @@
+#pragma once
+
+#include
+#include
+
+#include
+
+class GraphicsSystem;
+
+class System :public Trackable
+{
+public:
+ enum MouseButton
+ {
+ LEFT,
+ RIGHT,
+ CENTER
+ };
+
+ enum Key
+ {
+ F_KEY = ALLEGRO_KEY_F,
+ S_KEY = ALLEGRO_KEY_S,
+ ENTER_KEY = ALLEGRO_KEY_ENTER,
+ SPACE_KEY = ALLEGRO_KEY_SPACE,
+ ESCAPE_KEY = ALLEGRO_KEY_ESCAPE,
+ ONE_KEY = ALLEGRO_KEY_1,
+ TWO_KEY = ALLEGRO_KEY_2
+ };
+
+ System();
+ virtual ~System();
+
+ bool init(unsigned int width, unsigned int height);
+ void cleanup();
+ GraphicsSystem* getGraphicsSystem() const { return mpGraphicsSystem; };
+
+ Vector2D getCurrentMousePos();
+ bool isMouseButtonPressed(System::MouseButton button);
+ bool isKeyPressed(System::Key theKey);
+private:
+ bool mIsInitted = false;
+ GraphicsSystem* mpGraphicsSystem = NULL;
+
+};
diff --git a/RoboCat/Inc/MemoryBitStream.h b/RoboCat/Inc/MemoryBitStream.h
index c2138925..6b047237 100644
--- a/RoboCat/Inc/MemoryBitStream.h
+++ b/RoboCat/Inc/MemoryBitStream.h
@@ -100,11 +100,13 @@ class InputMemoryBitStream
//allocate buffer of right size
int byteCount = ( mBitCapacity + 7 ) / 8;
mBuffer = static_cast< char* >( malloc( byteCount ) );
- //copy
- memcpy( mBuffer, inOther.mBuffer, byteCount );
+ //copy
+ memcpy(mBuffer, inOther.mBuffer, byteCount);
+
}
- ~InputMemoryBitStream() { if (mIsBufferOwner) { std::cout << "Freeing " << mBuffer << std::endl; free(mBuffer); }; }
+ ~InputMemoryBitStream() { if (mIsBufferOwner) { //std::cout << "Freeing " << mBuffer << std::endl;
+ free(mBuffer); }; }
const char* GetBufferPtr() const { return mBuffer; }
uint32_t GetRemainingBitCount() const { return mBitCapacity - mBitHead; }
diff --git a/RoboCat/Inc/RoboCatPCH.h b/RoboCat/Inc/RoboCatPCH.h
index fa2871f8..9b5f8d1f 100644
--- a/RoboCat/Inc/RoboCatPCH.h
+++ b/RoboCat/Inc/RoboCatPCH.h
@@ -1,4 +1,4 @@
-
+#pragma once
#include
diff --git a/RoboCat/Inc/RoboCatShared.h b/RoboCat/Inc/RoboCatShared.h
index d7eac1bc..7446f19f 100644
--- a/RoboCat/Inc/RoboCatShared.h
+++ b/RoboCat/Inc/RoboCatShared.h
@@ -1,3 +1,4 @@
+#pragma once
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#define NOMINMAX
@@ -35,6 +36,7 @@
#include "deque"
#include "unordered_set"
#include "cassert"
+#include "map"
using std::shared_ptr;
using std::unique_ptr;
@@ -45,21 +47,17 @@ using std::deque;
using std::unordered_map;
using std::string;
using std::unordered_set;
+using std::map;
class RoboCat;
class GameObject;
#include "RoboMath.h"
-#include "TransmissionData.h"
-#include "InFlightPacket.h"
-
#include "LinkingContext.h"
#include "ByteSwap.h"
#include "MemoryBitStream.h"
-#include "AckRange.h"
-#include "Timing.h"
#include "StringUtils.h"
#include "SocketAddress.h"
#include "SocketAddressFactory.h"
@@ -67,4 +65,5 @@ class GameObject;
#include "TCPSocket.h"
#include "SocketUtil.h"
#include "OutputWindow.h"
-#include "DeliveryNotificationManager.h"
+#include "Timing.h"
+#include "WeightedTimedMovingAverage.h"
diff --git a/RoboCat/Inc/RoboMath.h b/RoboCat/Inc/RoboMath.h
index 718080a9..42135f8e 100644
--- a/RoboCat/Inc/RoboMath.h
+++ b/RoboCat/Inc/RoboMath.h
@@ -4,53 +4,53 @@ class Vector3
float mX, mY, mZ;
- Vector3( float x, float y, float z ) :
- mX( x ),
- mY( y ),
- mZ( z )
+ Vector3(float x, float y, float z) :
+ mX(x),
+ mY(y),
+ mZ(z)
{}
Vector3() :
- mX( 0.0f ),
- mY( 0.0f ),
- mZ( 0.0f )
+ mX(0.0f),
+ mY(0.0f),
+ mZ(0.0f)
{}
- void Set( float x, float y, float z )
+ void Set(float x, float y, float z)
{
mX = x;
mY = y;
mZ = z;
}
- friend Vector3 operator+( const Vector3& inLeft, const Vector3& inRight )
+ friend Vector3 operator+(const Vector3& inLeft, const Vector3& inRight)
{
- return Vector3( inLeft.mX + inRight.mX, inLeft.mY + inRight.mY, inLeft.mZ + inRight.mZ );
+ return Vector3(inLeft.mX + inRight.mX, inLeft.mY + inRight.mY, inLeft.mZ + inRight.mZ);
}
- friend Vector3 operator-( const Vector3& inLeft, const Vector3& inRight )
+ friend Vector3 operator-(const Vector3& inLeft, const Vector3& inRight)
{
- return Vector3( inLeft.mX - inRight.mX, inLeft.mY - inRight.mY, inLeft.mZ - inRight.mZ );
+ return Vector3(inLeft.mX - inRight.mX, inLeft.mY - inRight.mY, inLeft.mZ - inRight.mZ);
}
// Component-wise multiplication
- friend Vector3 operator*( const Vector3& inLeft, const Vector3& inRight )
+ friend Vector3 operator*(const Vector3& inLeft, const Vector3& inRight)
{
- return Vector3( inLeft.mX * inRight.mX, inLeft.mY * inRight.mY, inLeft.mZ * inRight.mZ );
+ return Vector3(inLeft.mX * inRight.mX, inLeft.mY * inRight.mY, inLeft.mZ * inRight.mZ);
}
// Scalar multiply
- friend Vector3 operator*( float inScalar, const Vector3& inVec )
+ friend Vector3 operator*(float inScalar, const Vector3& inVec)
{
- return Vector3( inVec.mX * inScalar, inVec.mY * inScalar, inVec.mZ * inScalar );
+ return Vector3(inVec.mX * inScalar, inVec.mY * inScalar, inVec.mZ * inScalar);
}
- friend Vector3 operator*( const Vector3& inVec, float inScalar )
+ friend Vector3 operator*(const Vector3& inVec, float inScalar)
{
- return Vector3( inVec.mX * inScalar, inVec.mY * inScalar, inVec.mZ * inScalar );
+ return Vector3(inVec.mX * inScalar, inVec.mY * inScalar, inVec.mZ * inScalar);
}
- Vector3& operator*=( float inScalar )
+ Vector3& operator*=(float inScalar)
{
mX *= inScalar;
mY *= inScalar;
@@ -58,7 +58,7 @@ class Vector3
return *this;
}
- Vector3& operator+=( const Vector3& inRight )
+ Vector3& operator+=(const Vector3& inRight)
{
mX += inRight.mX;
mY += inRight.mY;
@@ -66,7 +66,7 @@ class Vector3
return *this;
}
- Vector3& operator-=( const Vector3& inRight )
+ Vector3& operator-=(const Vector3& inRight)
{
mX -= inRight.mX;
mY -= inRight.mY;
@@ -76,7 +76,7 @@ class Vector3
float Length()
{
- return sqrtf( mX * mX + mY * mY + mZ * mZ );
+ return sqrtf(mX * mX + mY * mY + mZ * mZ);
}
float LengthSq()
@@ -86,7 +86,7 @@ class Vector3
float Length2D()
{
- return sqrtf( mX * mX + mY * mY );
+ return sqrtf(mX * mX + mY * mY);
}
float LengthSq2D()
@@ -109,17 +109,17 @@ class Vector3
mY /= length;
}
- friend float Dot( const Vector3& inLeft, const Vector3& inRight )
+ friend float Dot(const Vector3& inLeft, const Vector3& inRight)
{
- return ( inLeft.mX * inRight.mX + inLeft.mY * inRight.mY + inLeft.mZ * inRight.mZ );
+ return (inLeft.mX * inRight.mX + inLeft.mY * inRight.mY + inLeft.mZ * inRight.mZ);
}
- friend float Dot2D( const Vector3& inLeft, const Vector3& inRight )
+ friend float Dot2D(const Vector3& inLeft, const Vector3& inRight)
{
- return ( inLeft.mX * inRight.mX + inLeft.mY * inRight.mY );
+ return (inLeft.mX * inRight.mX + inLeft.mY * inRight.mY);
}
- friend Vector3 Cross( const Vector3& inLeft, const Vector3& inRight )
+ friend Vector3 Cross(const Vector3& inLeft, const Vector3& inRight)
{
Vector3 temp;
temp.mX = inLeft.mY * inRight.mZ - inLeft.mZ * inRight.mY;
@@ -128,15 +128,18 @@ class Vector3
return temp;
}
- friend Vector3 Lerp( const Vector3& inA, const Vector3& inB, float t )
+ friend Vector3 Lerp(const Vector3& inA, const Vector3& inB, float t)
{
- return Vector3( inA + t * ( inB - inA ) );
+ return Vector3(inA + t * (inB - inA));
}
static const Vector3 Zero;
static const Vector3 UnitX;
static const Vector3 UnitY;
static const Vector3 UnitZ;
+ static const Vector3 NegUnitX;
+ static const Vector3 NegUnitY;
+ static const Vector3 NegUnitZ;
};
@@ -152,7 +155,7 @@ class Quaternion
template< int tValue, int tBits >
struct GetRequiredBitsHelper
{
- enum { Value = GetRequiredBitsHelper< ( tValue >> 1 ), tBits + 1 >::Value };
+ enum { Value = GetRequiredBitsHelper< (tValue >> 1), tBits + 1 >::Value };
};
template< int tBits >
@@ -170,16 +173,15 @@ struct GetRequiredBits
namespace RoboMath
{
const float PI = 3.1415926535f;
- float GetRandomFloat();
+ float GetRandomFloatNonGame();
+ float GetRandomFloat(float, float);
- Vector3 GetRandomVector( const Vector3& inMin, const Vector3& inMax );
-
- inline bool Is2DVectorEqual( const Vector3& inA, const Vector3& inB )
+ inline bool Is2DVectorEqual(const Vector3& inA, const Vector3& inB)
{
- return ( inA.mX == inB.mX && inA.mY == inB.mY );
+ return (inA.mX == inB.mX && inA.mY == inB.mY);
}
- inline float ToDegrees( float inRadians )
+ inline float ToDegrees(float inRadians)
{
return inRadians * 180.0f / PI;
}
@@ -187,13 +189,13 @@ namespace RoboMath
namespace Colors
{
- static const Vector3 Black( 0.0f, 0.0f, 0.0f );
- static const Vector3 White( 1.0f, 1.0f, 1.0f );
- static const Vector3 Red( 1.0f, 0.0f, 0.0f );
- static const Vector3 Green( 0.0f, 1.0f, 0.0f );
- static const Vector3 Blue( 0.0f, 0.0f, 1.0f );
- static const Vector3 LightYellow( 1.0f, 1.0f, 0.88f );
- static const Vector3 LightBlue( 0.68f, 0.85f, 0.9f );
- static const Vector3 LightPink( 1.0f, 0.71f, 0.76f );
- static const Vector3 LightGreen( 0.56f, 0.93f, 0.56f );
-}
+ static const Vector3 Black(0.0f, 0.0f, 0.0f);
+ static const Vector3 White(1.0f, 1.0f, 1.0f);
+ static const Vector3 Red(1.0f, 0.0f, 0.0f);
+ static const Vector3 Green(0.0f, 1.0f, 0.0f);
+ static const Vector3 Blue(0.0f, 0.0f, 1.0f);
+ static const Vector3 LightYellow(1.0f, 1.0f, 0.88f);
+ static const Vector3 LightBlue(0.68f, 0.85f, 0.9f);
+ static const Vector3 LightPink(1.0f, 0.71f, 0.76f);
+ static const Vector3 LightGreen(0.56f, 0.93f, 0.56f);
+}
\ No newline at end of file
diff --git a/RoboCat/Inc/SocketAddress.h b/RoboCat/Inc/SocketAddress.h
index 05bad2b8..e8736a65 100644
--- a/RoboCat/Inc/SocketAddress.h
+++ b/RoboCat/Inc/SocketAddress.h
@@ -1,16 +1,19 @@
+class InputMemoryBitStream;
+class OutputMemoryBitStream;
+
class SocketAddress
{
public:
- SocketAddress( uint32_t inAddress, uint16_t inPort )
+ SocketAddress(uint32_t inAddress, uint16_t inPort)
{
GetAsSockAddrIn()->sin_family = AF_INET;
- GetIP4Ref() = htonl( inAddress );
- GetAsSockAddrIn()->sin_port = htons( inPort );
+ GetIP4Ref() = htonl(inAddress);
+ GetAsSockAddrIn()->sin_port = htons(inPort);
}
- SocketAddress( const sockaddr& inSockAddr )
+ SocketAddress(const sockaddr& inSockAddr)
{
- memcpy( &mSockAddr, &inSockAddr, sizeof( sockaddr ) );
+ memcpy(&mSockAddr, &inSockAddr, sizeof(sockaddr));
}
SocketAddress()
@@ -20,22 +23,24 @@ class SocketAddress
GetAsSockAddrIn()->sin_port = 0;
}
- bool operator==( const SocketAddress& inOther ) const
+ bool operator==(const SocketAddress& inOther) const
{
- return ( mSockAddr.sa_family == AF_INET &&
- GetAsSockAddrIn()->sin_port == inOther.GetAsSockAddrIn()->sin_port ) &&
- ( GetIP4Ref() == inOther.GetIP4Ref() );
+ return (mSockAddr.sa_family == AF_INET &&
+ GetAsSockAddrIn()->sin_port == inOther.GetAsSockAddrIn()->sin_port) &&
+ (GetIP4Ref() == inOther.GetIP4Ref());
}
size_t GetHash() const
{
- return ( GetIP4Ref() ) |
- ( ( static_cast< uint32_t >( GetAsSockAddrIn()->sin_port ) ) << 13 ) |
+ return (GetIP4Ref()) |
+ ((static_cast(GetAsSockAddrIn()->sin_port)) << 13) |
mSockAddr.sa_family;
}
+ void Read(InputMemoryBitStream& inInputStream);
+ void Write(OutputMemoryBitStream& inOutputStream);
- uint32_t GetSize() const { return sizeof( sockaddr ); }
+ uint32_t GetSize() const { return sizeof(sockaddr); }
string ToString() const;
@@ -45,15 +50,15 @@ class SocketAddress
sockaddr mSockAddr;
#if _WIN32
- uint32_t& GetIP4Ref() { return *reinterpret_cast< uint32_t* >( &GetAsSockAddrIn()->sin_addr.S_un.S_addr ); }
- const uint32_t& GetIP4Ref() const { return *reinterpret_cast< const uint32_t* >( &GetAsSockAddrIn()->sin_addr.S_un.S_addr ); }
+ uint32_t& GetIP4Ref() { return *reinterpret_cast(&GetAsSockAddrIn()->sin_addr.S_un.S_addr); }
+ const uint32_t& GetIP4Ref() const { return *reinterpret_cast(&GetAsSockAddrIn()->sin_addr.S_un.S_addr); }
#else
- uint32_t& GetIP4Ref() { return GetAsSockAddrIn()->sin_addr.s_addr; }
- const uint32_t& GetIP4Ref() const { return GetAsSockAddrIn()->sin_addr.s_addr; }
+ uint32_t& GetIP4Ref() { return GetAsSockAddrIn()->sin_addr.s_addr; }
+ const uint32_t& GetIP4Ref() const { return GetAsSockAddrIn()->sin_addr.s_addr; }
#endif
- sockaddr_in* GetAsSockAddrIn() { return reinterpret_cast< sockaddr_in* >( &mSockAddr ); }
- const sockaddr_in* GetAsSockAddrIn() const { return reinterpret_cast< const sockaddr_in* >( &mSockAddr ); }
+ sockaddr_in* GetAsSockAddrIn() { return reinterpret_cast(&mSockAddr); }
+ const sockaddr_in* GetAsSockAddrIn() const { return reinterpret_cast(&mSockAddr); }
};
@@ -63,7 +68,7 @@ namespace std
{
template<> struct hash< SocketAddress >
{
- size_t operator()( const SocketAddress& inAddress ) const
+ size_t operator()(const SocketAddress& inAddress) const
{
return inAddress.GetHash();
}
diff --git a/RoboCat/Inc/StringUtils.h b/RoboCat/Inc/StringUtils.h
index b46b745d..e79ad328 100644
--- a/RoboCat/Inc/StringUtils.h
+++ b/RoboCat/Inc/StringUtils.h
@@ -1,11 +1,10 @@
namespace StringUtils
{
- string GetCommandLineArg( int inIndex );
+ string GetCommandLineArg(int inIndex);
- string Sprintf( const char* inFormat, ... );
+ string Sprintf(const char* inFormat, ...);
- void Log( const char* inFormat );
- void Log( const char* inFormat, ... );
+ void Log(const char* inFormat, ...);
}
#define LOG( ... ) StringUtils::Log( __VA_ARGS__ );
\ No newline at end of file
diff --git a/RoboCat/Inc/Timing.h b/RoboCat/Inc/Timing.h
index b5af28d8..629ce459 100644
--- a/RoboCat/Inc/Timing.h
+++ b/RoboCat/Inc/Timing.h
@@ -3,7 +3,7 @@ class Timing
public:
Timing();
-
+
void Update();
float GetDeltaTime() const { return mDeltaTime; }
@@ -12,13 +12,13 @@ class Timing
float GetTimef() const
{
- return static_cast< float >( GetTime() );
+ return static_cast(GetTime());
}
float GetFrameStartTime() const { return mFrameStartTimef; }
- static Timing sInstance;
+ static Timing sInstance;
private:
float mDeltaTime;
@@ -28,4 +28,4 @@ class Timing
float mFrameStartTimef;
double mPerfCountDuration;
-};
\ No newline at end of file
+};
diff --git a/RoboCat/Inc/WeightedTimedMovingAverage.h b/RoboCat/Inc/WeightedTimedMovingAverage.h
new file mode 100644
index 00000000..9e620f83
--- /dev/null
+++ b/RoboCat/Inc/WeightedTimedMovingAverage.h
@@ -0,0 +1,51 @@
+#pragma once
+class WeightedTimedMovingAverage
+{
+public:
+
+ WeightedTimedMovingAverage(float inDuration = 5.f) :
+ mDuration(inDuration),
+ mValue(0.f)
+ {
+ mTimeLastEntryMade = Timing::sInstance.GetTimef();
+ }
+
+ void UpdatePerSecond(float inValue)
+ {
+ float time = Timing::sInstance.GetTimef();
+ float timeSinceLastEntry = time - mTimeLastEntryMade;
+
+ float valueOverTime = inValue / timeSinceLastEntry;
+
+ //now update our value by whatever amount of the duration that was..
+ float fractionOfDuration = (timeSinceLastEntry / mDuration);
+ if (fractionOfDuration > 1.f) { fractionOfDuration = 1.f; }
+
+ mValue = mValue * (1.f - fractionOfDuration) + valueOverTime * fractionOfDuration;
+
+ mTimeLastEntryMade = time;
+ }
+
+ void Update(float inValue)
+ {
+ float time = Timing::sInstance.GetTimef();
+ float timeSinceLastEntry = time - mTimeLastEntryMade;
+
+ //now update our value by whatever amount of the duration that was..
+ float fractionOfDuration = (timeSinceLastEntry / mDuration);
+ if (fractionOfDuration > 1.f) { fractionOfDuration = 1.f; }
+
+ mValue = mValue * (1.f - fractionOfDuration) + inValue * fractionOfDuration;
+
+ mTimeLastEntryMade = time;
+ }
+
+ float GetValue() const { return mValue; }
+
+private:
+
+ float mTimeLastEntryMade;
+ float mValue;
+ float mDuration;
+
+};
\ No newline at end of file
diff --git a/RoboCat/Src/BaseGameSrc/Game.cpp b/RoboCat/Src/BaseGameSrc/Game.cpp
new file mode 100644
index 00000000..67943965
--- /dev/null
+++ b/RoboCat/Src/BaseGameSrc/Game.cpp
@@ -0,0 +1,343 @@
+#include "Game.h"
+#include "Unit.h"
+#include "UnitManager.h"
+#include "GraphicsBufferManager.h"
+#include "NetworkManager.h"
+#include "MemoryManager.h"
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+using namespace std;
+
+Game* Game::mspInstance = NULL;
+
+
+Game::Game()
+{
+ mpSystem = new System;
+}
+
+Game::~Game()
+{
+ cleanup();
+ delete mpSystem;
+}
+
+Game* Game::getInstance()
+{
+ assert(mspInstance != NULL);
+ return mspInstance;
+}
+
+void Game::initInstance()
+{
+ assert(mspInstance == NULL);
+ if (mspInstance == NULL)
+ {
+ mspInstance = new Game();
+ }
+}
+
+void Game::deleteInstance()
+{
+ assert(mspInstance != NULL);
+ delete mspInstance;
+ mspInstance = nullptr;
+}
+
+bool Game::init(unsigned int width, unsigned int height, double targetTimePerFrame /*= 16.7*/)
+{
+ if (mIsInitted)
+ {
+ cleanup();
+ }
+ srand(time(NULL));
+ SocketUtil::StaticInit();
+
+ string destination = StringUtils::GetCommandLineArg(1);
+ string name = StringUtils::GetCommandLineArg(2);
+ if (destination == "" || name == "")
+ {
+ destination = "8000";
+ name = "Harris";
+ // LOG("ERROR: Missing command line arguments.");
+ //return false;
+ }
+ mpNetworkManager = new NetworkManager;
+ //assume no colon implies this is just the port, which implies that this is the master peer
+ if (destination.find_first_of(':') == string::npos)
+ {
+ mpNetworkManager->InitAsMasterPeer(stoi(destination), name);
+ }
+ else
+ {
+ SocketAddressPtr targetAddress = SocketAddressFactory::CreateIPv4FromString(destination);
+ if (!targetAddress)
+ {
+ LOG("ERROR: Unable to create target address from destination.");
+ return false;
+ }
+ mpNetworkManager->InitAsPeer(*targetAddress, name);
+ }
+ mpSystem->init(width, height);
+ mTargetTimePerFrame = targetTimePerFrame;
+
+ mpMemoryManager = new MemoryManager;
+ mpMemoryManager->init();
+
+ mpGraphicsBufferManager = new GraphicsBufferManager;
+ mpUnitManager = new UnitManager;
+
+
+
+ loadBuffers();
+
+ mIsInitted = true;
+
+ return true;
+}
+
+void Game::cleanup()
+{
+ if (mIsInitted)
+ {
+
+
+ delete mpUnitManager;
+ delete mpGraphicsBufferManager;
+ delete mpMemoryManager;
+ delete mpNetworkManager;
+ mpSystem->cleanup();
+ }
+ SocketUtil::CleanUp();
+ mIsInitted = false;
+}
+
+void Game::doLoop()
+{
+ Timer timer;
+ PerformanceTracker tracker;
+
+ while (mShouldContinue)
+ {
+ tracker.clearTracker("loop");
+ tracker.startTracking("loop");
+ timer.start();
+
+ getInput();
+
+ if (mpNetworkManager->GetState() != NetworkManager::NetworkManagerState::NMS_Delay)
+ {
+
+ update(mTargetTimePerFrame);
+ mpNetworkManager->ProcessIncomingPackets();
+ mpNetworkManager->SendOutgoingPackets();
+ }
+ else
+ {
+ //only grab the incoming packets because if I'm in delay,
+ //the only way I'm getting out is if an incoming packet saves me
+ mpNetworkManager->ProcessIncomingPackets();
+ }
+
+
+ render();
+
+ timer.sleepUntilElapsed(mTargetTimePerFrame);
+ tracker.stopTracking("loop");
+ //cout << tracker.getElapsedTime("loop") << endl;
+
+ //cout << "Allocated memory: " << mpMemoryManager->getTotalAllocated() << endl;
+ //cout << "Current available memory: " << mpMemoryManager->getTotalCapacity() << endl;
+ }
+}
+
+void Game::getInput()
+{
+ if (mpSystem->isKeyPressed(System::ESCAPE_KEY))
+ {
+ mShouldContinue = false;
+ }
+ if (gameStarted)
+ {
+ if (mpSystem->isKeyPressed(System::ENTER_KEY))
+ {
+ Unit* pUnit = mpUnitManager->getLastUnitCreated();
+ if (pUnit)
+ {
+ pUnit->toggleAnimation();
+ mpNetworkManager->addAction(ActionTypes::ToggleAnimSingle, pUnit->getCenterPosition(),-1);
+ }
+ }
+ if (mpSystem->isKeyPressed(System::SPACE_KEY))
+ {
+ mpUnitManager->togglePauseStateForAllAnimations();
+ mpNetworkManager->addAction(ActionTypes::ToggleAnimAll, Vector2D(0, 0), -1);
+ }
+ if (mpSystem->isMouseButtonPressed(System::LEFT))
+ {
+ Vector2D mousePos = mpSystem->getCurrentMousePos();
+ createUnit(mousePos);
+ mpNetworkManager->addAction(ActionTypes::CreateUnit, mousePos, -1);
+ }
+ if (mpSystem->isMouseButtonPressed(System::RIGHT))
+ {
+ Vector2D mousePos = mpSystem->getCurrentMousePos();
+ mpUnitManager->deleteAllUnitsAt2DPosition(mousePos);
+ mpNetworkManager->addAction(ActionTypes::DestroyUnit, mousePos,-1);
+ }
+ if (mpSystem->isKeyPressed(System::ONE_KEY))
+ {
+ int seed = rand() % 99999999;
+ Vector2D mousePos = mpSystem->getCurrentMousePos();
+ createUnit(mousePos, seed);
+ mpNetworkManager->addAction(ActionTypes::CreateUnitMove, mousePos, seed);
+ }
+ if (mpSystem->isKeyPressed(System::TWO_KEY))
+ {
+ Vector2D mousePos = mpSystem->getCurrentMousePos();
+
+
+ int seed = rand() % 99999999;
+
+ createUnit(seed);
+ mpNetworkManager->addAction(ActionTypes::CreateUnitRand, mousePos, seed);
+ }
+ }
+ if (mpSystem->isKeyPressed(System::S_KEY) && !gameStarted && mpNetworkManager->IsMasterPeer())
+ {
+ mpNetworkManager->TryStartGame();
+ gameStarted = true;
+ }
+}
+
+void Game::update(double dt)
+{
+ mpUnitManager->update(dt);
+ Timing::sInstance.Update();
+}
+
+void Game::render()
+{
+ //draw background
+ GraphicsSystem::draw(ZERO_VECTOR2D, *(mpGraphicsBufferManager->getBuffer(WOODS)), 0.5f);
+
+ //draw units
+ mpUnitManager->draw();
+
+ mpSystem->getGraphicsSystem()->flip();
+}
+
+void Game::loadBuffers()
+{
+ const string ASSET_PATH = "..\\..\\..\\assets\\";
+ const string BACKGROUND_FILENAME = "woods.png";
+ const string SMURF_FILENAME = "smurf_sprites.png";
+ const string DEAN_FILENAME = "dean_sprites.png";
+ const string NUMBERED_FILENAME = "smurf_sprites_numbered.png";
+
+ mpGraphicsBufferManager->createBuffer(WOODS, ASSET_PATH + BACKGROUND_FILENAME);
+ mpGraphicsBufferManager->createBuffer(SMURFS, ASSET_PATH + SMURF_FILENAME);
+ mpGraphicsBufferManager->createBuffer(DEAN, ASSET_PATH + DEAN_FILENAME);
+ mpGraphicsBufferManager->createBuffer(NUMBERED, ASSET_PATH + NUMBERED_FILENAME);
+
+
+}
+
+const int PIXEL_WIDTH = 60;
+const int PIXEL_HEIGHT = 60;
+const int SPRITES_ACROSS = 4;
+const int SPRITES_DOWN = 4;
+const float TIME_PER_FRAME_MULTIPLE = 5;
+
+void Game::createUnit(const Vector2D& pos)
+{
+
+ float timePerFrame = (float)mTargetTimePerFrame * TIME_PER_FRAME_MULTIPLE;
+ const GraphicsBuffer* pSmurfs = mpGraphicsBufferManager->getBuffer(SMURFS);
+ assert(pSmurfs);
+ const GraphicsBuffer* pDean = mpGraphicsBufferManager->getBuffer(DEAN);
+ if (pSmurfs)
+ {
+ Animation smurfAnimation(*pSmurfs, PIXEL_WIDTH, PIXEL_HEIGHT, SPRITES_ACROSS, SPRITES_DOWN, timePerFrame);
+ Animation deanAnimation(*pDean, PIXEL_WIDTH, PIXEL_HEIGHT, SPRITES_ACROSS, SPRITES_DOWN, timePerFrame);
+
+ mpUnitManager->createUnit(pos, smurfAnimation, deanAnimation);
+ }
+}
+
+void Game::createUnit(int seed)
+{
+ float timePerFrame = (float)mTargetTimePerFrame * TIME_PER_FRAME_MULTIPLE;
+ const GraphicsBuffer* pSmurfs = mpGraphicsBufferManager->getBuffer(SMURFS);
+ assert(pSmurfs);
+ const GraphicsBuffer* pDean = mpGraphicsBufferManager->getBuffer(DEAN);
+ assert(pDean);
+ Animation smurfAnimation(*pSmurfs, PIXEL_WIDTH, PIXEL_HEIGHT, SPRITES_ACROSS, SPRITES_DOWN, timePerFrame);
+ Animation deanAnimation(*pDean, PIXEL_WIDTH, PIXEL_HEIGHT, SPRITES_ACROSS, SPRITES_DOWN, timePerFrame);
+
+
+
+ mpUnitManager->createUnit(deanAnimation, smurfAnimation, seed);
+}
+
+void Game::createUnit(const Vector2D& pos, int seed)
+{
+ float timePerFrame = (float)mTargetTimePerFrame * TIME_PER_FRAME_MULTIPLE;
+ const GraphicsBuffer* pNumbered = mpGraphicsBufferManager->getBuffer(NUMBERED);
+ assert(pNumbered);
+ const GraphicsBuffer* pDean = mpGraphicsBufferManager->getBuffer(DEAN);
+ assert(pDean);
+ Animation numberedAnimation(*pNumbered, PIXEL_WIDTH, PIXEL_HEIGHT, SPRITES_ACROSS, SPRITES_DOWN, timePerFrame);
+ Animation deanAnimation(*pDean, PIXEL_WIDTH, PIXEL_HEIGHT, SPRITES_ACROSS, SPRITES_DOWN, timePerFrame);
+
+ mpUnitManager->createUnit(pos, numberedAnimation, deanAnimation, seed);
+}
+
+void Game::HandleAction(ActionTypes type, Vector2D pos, int seed)
+{
+ switch (type)
+ {
+ case ActionTypes::ToggleAnimAll:
+ {
+ mpUnitManager->togglePauseStateForAllAnimations();
+ break;
+ }
+ case ActionTypes::ToggleAnimSingle:
+ {
+ Unit* pUnit = mpUnitManager->getLastUnitCreated();
+ if (pUnit)
+ {
+ pUnit->toggleAnimation();
+ }
+ break;
+ }
+ case ActionTypes::CreateUnit:
+ {
+ createUnit(pos);
+ break;
+ }
+ case ActionTypes::CreateUnitRand:
+ {
+ createUnit(seed);
+ break;
+ }
+ case ActionTypes::CreateUnitMove:
+ {
+ createUnit(pos, seed);
+ break;
+ }
+ case ActionTypes::DestroyUnit:
+ {
+ mpUnitManager->deleteAllUnitsAt2DPosition(pos);
+ break;
+ }
+ }
+}
diff --git a/RoboCat/Src/BaseGameSrc/GraphicsBufferManager.cpp b/RoboCat/Src/BaseGameSrc/GraphicsBufferManager.cpp
new file mode 100644
index 00000000..6281cbfa
--- /dev/null
+++ b/RoboCat/Src/BaseGameSrc/GraphicsBufferManager.cpp
@@ -0,0 +1,135 @@
+#include "GraphicsBufferManager.h"
+#include "GraphicsBuffer.h"
+
+#include "MemoryManager.h"
+
+#include "Game.h"
+
+using namespace std;
+
+GraphicsBufferManager::GraphicsBufferManager()
+{
+}
+
+GraphicsBufferManager::~GraphicsBufferManager()
+{
+ clear();
+}
+
+void GraphicsBufferManager::clear()
+{
+ map::iterator iter;
+ MemoryManager* pMemoryManager = Game::getInstance()->getMemoryManager();
+ for (iter = mMap.begin(); iter != mMap.end(); ++iter)
+ {
+ iter->second->~GraphicsBuffer();
+ pMemoryManager->deallocate((Byte*)iter->second);
+ }
+
+ mMap.clear();
+}
+
+const GraphicsBuffer* GraphicsBufferManager::createBuffer(const GBKey& key, const std::string& filename)
+{
+ GraphicsBuffer* pBuffer = NULL;
+ MemoryManager* pMemoryManager = Game::getInstance()->getMemoryManager();
+ Byte* ptr = pMemoryManager->allocate(sizeof(GraphicsBuffer));
+
+ if (!alreadyExists(key))
+ {
+ GraphicsBuffer* pBuffer = new(ptr)GraphicsBuffer(filename);
+ mMap[key] = pBuffer;
+ }
+
+ return pBuffer;
+}
+
+const GraphicsBuffer* GraphicsBufferManager::createBuffer(const GBKey& key, unsigned int width, unsigned int height, Color color /*= Color()*/)
+{
+ GraphicsBuffer* pBuffer = NULL;
+ MemoryManager* pMemoryManager = Game::getInstance()->getMemoryManager();
+ Byte* ptr = pMemoryManager->allocate(sizeof(GraphicsBuffer));
+
+ if (!alreadyExists(key))
+ {
+ GraphicsBuffer* pBuffer = new(ptr)GraphicsBuffer( width, height, color );
+ mMap[key] = pBuffer;
+ }
+
+ return pBuffer;
+}
+
+const GraphicsBuffer* GraphicsBufferManager::cloneBuffer(const GBKey& newKey, const GBKey& existingKey)
+{
+ GraphicsBuffer* pNewBuffer = NULL;
+ const GraphicsBuffer* pExistingBuffer = getBuffer(existingKey);
+
+
+
+ if (!alreadyExists(newKey) && pExistingBuffer != NULL)
+ {
+ pNewBuffer = pExistingBuffer->clone();
+ mMap[newKey] = pNewBuffer;
+ }
+
+ return pNewBuffer;
+}
+
+const GraphicsBuffer* GraphicsBufferManager::getBuffer(const GBKey& key) const
+{
+ map::const_iterator iter = mMap.find(key);
+
+ if (iter != mMap.end())
+ {
+ return iter->second;
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+bool GraphicsBufferManager::destroyBuffer(const GBKey& key)
+{
+ if (alreadyExists(key))
+ {
+ MemoryManager* pMemoryManager = Game::getInstance()->getMemoryManager();
+ const GraphicsBuffer* pBuffer = getBuffer(key);
+ pBuffer->~GraphicsBuffer();
+ pMemoryManager->deallocate((Byte*)pBuffer);
+ mMap.erase(key);
+ return true;
+ }
+
+ return false;
+}
+
+bool GraphicsBufferManager::destroyBuffer(GraphicsBuffer* pBuffer)
+{
+ map::const_iterator iter;
+ MemoryManager* pMemoryManager = Game::getInstance()->getMemoryManager();
+ for (iter = mMap.begin(); iter != mMap.end(); ++iter)
+ {
+ if (pBuffer == iter->second)
+ {
+ pBuffer->~GraphicsBuffer();
+ pMemoryManager->deallocate((Byte*)pBuffer);
+ mMap.erase(iter);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool GraphicsBufferManager::alreadyExists(const GBKey& key) const
+{
+ if (getBuffer(key) == NULL)
+ {
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+}
diff --git a/RoboCat/Src/BaseGameSrc/MemoryManager.cpp b/RoboCat/Src/BaseGameSrc/MemoryManager.cpp
new file mode 100644
index 00000000..08579191
--- /dev/null
+++ b/RoboCat/Src/BaseGameSrc/MemoryManager.cpp
@@ -0,0 +1,121 @@
+#include "MemoryManager.h"
+
+
+MemoryManager::MemoryManager()
+{
+
+}
+MemoryManager::~MemoryManager()
+{
+ cleanup();
+}
+
+//Initializing the memory manager
+void MemoryManager::init()
+{
+ mpMemoryPoolSmall = new MemoryPool(10000, 128);
+ mpMemoryPoolMed = new MemoryPool(10000, 1024); //creating the medium memory pool
+ mpMemoryPoolLarge = new MemoryPool(640, 1048576); //creating the large memory pool
+
+ //Caluclates the total maximum capacity availible using the max object size and total number of free objects from each pool
+ mTotalCapacity = (mpMemoryPoolSmall->getNumFreeObjects() * mpMemoryPoolSmall->getMaxObjectSize()) +
+ (mpMemoryPoolMed->getNumFreeObjects() * mpMemoryPoolMed->getMaxObjectSize()) +
+ (mpMemoryPoolLarge->getNumFreeObjects() * mpMemoryPoolLarge->getMaxObjectSize());
+
+ mTotalAllocated = 0;
+ mMaxCapacity = mTotalCapacity;
+ mTotalWaste = 0;
+}
+//cleans up and resets the memory manager
+void MemoryManager::cleanup()
+{
+
+ reset();
+
+ //deletes all the memory pools
+ delete(mpMemoryPoolSmall);
+ delete(mpMemoryPoolMed);
+ delete(mpMemoryPoolLarge);
+
+ mpMemoryPoolSmall = nullptr;
+ mpMemoryPoolMed = nullptr;
+ mpMemoryPoolLarge = nullptr;
+
+}
+
+//resets the data and frees all the space in the memory pools
+void MemoryManager::reset()
+{
+ //resets all the pools
+ mpMemoryPoolSmall->reset();
+ mpMemoryPoolMed->reset();
+ mpMemoryPoolLarge->reset();
+
+ //Calculates total free capacity when all pools are empty
+ mTotalCapacity = (mpMemoryPoolSmall->getNumFreeObjects() * mpMemoryPoolSmall->getMaxObjectSize()) +
+ (mpMemoryPoolMed->getNumFreeObjects() * mpMemoryPoolMed->getMaxObjectSize()) +
+ (mpMemoryPoolLarge->getNumFreeObjects() * mpMemoryPoolLarge->getMaxObjectSize());
+ mTotalAllocated = 0;
+ mMaxCapacity = mTotalCapacity;
+ mTotalWaste = 0;
+
+}
+
+//allocates an object for the passed in amount of memory
+Byte* MemoryManager::allocate(unsigned int memory)
+{
+ Byte* ptr = nullptr;
+ unsigned int size;
+
+ //If-else statements to determine which pool to use
+ if (memory <= mpMemoryPoolSmall->getMaxObjectSize())
+ {
+ size = mpMemoryPoolSmall->getMaxObjectSize(); //Sets size to the pool's max object size
+ ptr = mpMemoryPoolSmall->allocateObject(); //allocates the object and sets the pointer
+ mTotalAllocated += size; //updates the allocated data
+ mTotalWaste += size - memory; //updates the waste data
+
+ }
+ else if (memory <= mpMemoryPoolMed->getMaxObjectSize())
+ {
+ size = mpMemoryPoolMed->getMaxObjectSize(); //Sets size to the pool's max object size
+ ptr = mpMemoryPoolMed->allocateObject(); //allocates the object and sets the pointer
+ mTotalAllocated += size; //updates the allocated data
+ mTotalWaste += size - memory; //updates the waste data
+ }
+ else if (memory <= mpMemoryPoolLarge->getMaxObjectSize())
+ {
+ size = mpMemoryPoolLarge->getMaxObjectSize(); //Sets size to the pool's max object size
+ ptr = mpMemoryPoolLarge->allocateObject(); //allocates the object and sets the pointer
+ mTotalAllocated += size; //updates the allocated data
+ mTotalWaste += size - memory; //updates the waste data
+ }
+ mTotalCapacity = mMaxCapacity - mTotalAllocated; //updates the total free capacity data
+
+ return ptr;
+
+}
+
+//deallocates the passed in byte
+void MemoryManager::deallocate(Byte* byte)
+{
+ //if else statements checking to see which pool the byte is contained in
+ if (mpMemoryPoolSmall->contains(byte))
+ {
+ mpMemoryPoolSmall->freeObject(byte); //Frees the object at the passed in byte
+ mTotalAllocated -= mpMemoryPoolSmall->getMaxObjectSize(); //updates the total allocated data
+ }
+ else if (mpMemoryPoolMed->contains(byte))
+ {
+ mpMemoryPoolMed->freeObject(byte); //Frees the object at the passed in byte
+ mTotalAllocated -= mpMemoryPoolMed->getMaxObjectSize(); //updates the total allocated data
+ }
+ else if (mpMemoryPoolMed->contains(byte))
+ {
+ mpMemoryPoolLarge->freeObject(byte); //Frees the object at the passed in byte
+ mTotalAllocated -= mpMemoryPoolLarge->getMaxObjectSize(); //updates the total allocated data
+ }
+ mTotalCapacity = mMaxCapacity - mTotalAllocated; //updates the total capacity data
+}
+
+
diff --git a/RoboCat/Src/BaseGameSrc/NetworkManager.cpp b/RoboCat/Src/BaseGameSrc/NetworkManager.cpp
new file mode 100644
index 00000000..2a3c43ee
--- /dev/null
+++ b/RoboCat/Src/BaseGameSrc/NetworkManager.cpp
@@ -0,0 +1,907 @@
+#include "NetworkManager.h"
+#include
+namespace
+{
+ const float kTimeBetweenHellos = 1.f;
+ const float kStartDelay = 0.0f;
+ const int kSubTurnsPerTurn = 3;
+ const int kMaxPlayerCount = 4;
+}
+NetworkManager::NetworkManager() :
+ mBytesSentThisFrame(0),
+ mDropPacketChance(0.1f),
+ mSimulatedLatency(0.5f),
+ mBytesReceivedPerSecond(WeightedTimedMovingAverage(1.f)),
+ mBytesSentPerSecond(WeightedTimedMovingAverage(1.f)),
+ mPlayerId(0),
+ mNewNetworkId(1),
+ mIsMasterPeer(false),
+ mPlayerCount(0),
+ mHighestPlayerId(0),
+ mTimeOfLastHello(0.0f),
+ mTimeToStart(-1.0f),
+ mState(NetworkManagerState::NMS_Unitialized),
+ mNextOutgoingSequenceNumber(0),
+ mNextExpectedSequenceNumber(0),
+ mDispatchedPacketCount(0)
+{
+ mPendingAcks.clear();
+}
+
+NetworkManager::~NetworkManager()
+{
+ TransmissionData* temp;
+ int size = mInFlightPackets.size();
+ for (int i = 0; i < size; i++)
+ {
+ temp = mInFlightPackets.begin()->second;
+ mInFlightPackets.erase(mInFlightPackets.begin());
+ delete(temp);
+ temp = nullptr;
+ }
+}
+
+bool NetworkManager::InitAsMasterPeer(uint16_t inPort, const string& inName)
+{
+ if (!InitSocket(inPort))
+ {
+ return false;
+ }
+ //master peer at init means guaranteed first player id
+ mPlayerId = 1;
+ mHighestPlayerId = mPlayerId;
+ mIsMasterPeer = true;
+ mPlayerCount = 1;
+
+ //in lobby cause we don't need to ask the master peer (since we are the master peer)
+ mState = NetworkManagerState::NMS_Lobby;
+
+ //add myself to the player name map
+ mName = inName;
+ mPlayerNameMap.emplace(mPlayerId, mName);
+ std::cout << "Init as Master peer" << std::endl;
+ return true;
+}
+
+bool NetworkManager::InitAsPeer(const SocketAddress& inMPAddress, const string& inName)
+{
+ if (!InitSocket(0))
+ {
+ return false;
+ }
+
+ mMasterPeerAddr = inMPAddress;
+
+ //we're going to have to ask the master peer
+ mState = NetworkManagerState::NMS_Hello;
+
+ //set my name
+ mName = inName;
+ //don't know my player id, so can't add myself to the name map yet
+ std::cout << "Init as peer" << std::endl;
+ return true;
+}
+
+bool NetworkManager::InitSocket(uint16_t inPort)
+{
+ mSocket = SocketUtil::CreateUDPSocket(SocketAddressFamily::INET);
+ SocketAddress ownAddress(INADDR_ANY, inPort);
+ mSocket->Bind(ownAddress);
+ std::cout << "Initializing NetworkManager at port " << inPort << std::endl;
+
+
+ //did we bind okay?
+ if (mSocket == nullptr)
+ {
+ return false;
+ }
+
+ if (mSocket->SetNonBlockingMode(true) != NO_ERROR)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+void NetworkManager::ProcessIncomingPackets()
+{
+ ReadIncomingPacketsIntoQueue();
+
+ ProcessQueuedPackets();
+
+ UpdateBytesSentLastFrame();
+
+}
+
+void NetworkManager::SendOutgoingPackets()
+{
+ switch (mState)
+ {
+ case NetworkManagerState::NMS_Hello:
+ UpdateSayingHello();
+ break;
+ case NetworkManagerState::NMS_Starting:
+ //std::cout << "Starting" << std::endl;
+ UpdateStarting();
+ break;
+ case NetworkManagerState::NMS_Playing:
+ //std::cout << "Playing" << std::endl;
+ UpdateSendActionPacket();
+ break;
+ default:
+ break;
+ }
+}
+
+void NetworkManager::UpdateSayingHello(bool inForce)
+{
+ float time = Timing::sInstance.GetTimef();
+
+ if (inForce || time > mTimeOfLastHello + kTimeBetweenHellos)
+ {
+ SendHelloPacket();
+ mTimeOfLastHello = time;
+ }
+}
+
+void NetworkManager::SendHelloPacket()
+{
+ OutputMemoryBitStream helloPacket;
+
+ TransmissionDataHello* newData = new TransmissionDataHello(mName);
+ newData->mPacketType = kHelloCC;
+ AddInFlightPacket(newData, helloPacket);
+ helloPacket.Write(kHelloCC);
+ helloPacket.Write(mName);
+ std::cout << "Saying hello" << std::endl;
+
+ WritePendingAcks(helloPacket);
+
+ SendPacket(helloPacket, mMasterPeerAddr);
+}
+
+void NetworkManager::UpdateStarting()
+{
+ mTimeToStart -= Timing::sInstance.GetDeltaTime();
+ if (mTimeToStart <= 0.0f)
+ {
+ EnterPlayingState();
+ }
+}
+
+void NetworkManager::UpdateSendActionPacket()
+{
+ //we need to send a turn packet to all of our peers
+ OutputMemoryBitStream packet;
+
+
+ TransmissionDataUpdate* newData = new TransmissionDataUpdate(mPlayerId);
+ newData->mPacketType = kUpdateCC;
+ AddInFlightPacket(newData, packet);
+
+ //std::cout << newData->sequenceID << " Update" << std::endl;
+
+
+ packet.Write(kUpdateCC);
+ packet.Write(mPlayerId);
+ uint32_t size = mActionVec.size();
+ packet.Write(size);
+ //std::cout << "Num actions sent: " << size << std::endl;
+ if (size > 0)
+ {
+ for (uint32_t i = 0; i < size; i++)
+ {
+ mActionVec[i].Write(packet);
+ newData->mData.push_back(mActionVec[i]);
+ }
+ }
+
+ WritePendingAcks(packet);
+
+ for (auto& iter : mPlayerToSocketMap)
+ {
+ SendPacket(packet, iter.second);
+ }
+
+ mActionVec.clear();
+}
+
+void NetworkManager::ProcessPacket(InputMemoryBitStream& inInputStream, const SocketAddress& inFromAddress)
+{
+ int sequenceID;
+ inInputStream.Read(sequenceID);
+ ProcessSequenceNum(sequenceID);
+ //std::cout << "Recieved packet #" << sequenceID << std::endl;
+ switch (mState)
+ {
+ case NetworkManagerState::NMS_Hello:
+ ProcessPacketsHello(inInputStream, inFromAddress);
+ break;
+ case NetworkManagerState::NMS_Lobby:
+ ProcessPacketsLobby(inInputStream, inFromAddress);
+ break;
+ case NetworkManagerState::NMS_Playing:
+ ProcessPacketsPlaying(inInputStream, inFromAddress);
+ break;
+ case NetworkManagerState::NMS_Delay:
+ ProcessPacketsDelay(inInputStream, inFromAddress);
+ break;
+ default:
+ break;
+ }
+ ProcessNewAcks(inInputStream);
+}
+
+void NetworkManager::ProcessPacketsHello(InputMemoryBitStream& inInputStream, const SocketAddress& inFromAddress)
+{
+ UNREFERENCED_PARAMETER(inFromAddress);
+ //only time we're in hello state is when we are not the master peer and trying to join
+ uint32_t packetType;
+ inInputStream.Read(packetType);
+
+ switch (packetType)
+ {
+ case kNotMasterPeerCC:
+ HandleNotMPPacket(inInputStream);
+ break;
+ case kWelcomeCC:
+ std::cout << "Handling welcome" << std::endl;
+ HandleWelcomePacket(inInputStream);
+ break;
+ case kNotJoinableCC:
+ default:
+ //couldn't join or something crazy happened, goodbye cruel world
+ //LOG("Failed to join game, exiting...");
+ //Engine::sInstance->SetShouldKeepRunning(false);
+ break;
+ }
+}
+
+void NetworkManager::HandleNotMPPacket(InputMemoryBitStream& inInputStream)
+{
+ //this will have the correct master peer address
+ mMasterPeerAddr.Read(inInputStream);
+ //just force send this immediately
+ UpdateSayingHello(true);
+}
+
+void NetworkManager::HandleWelcomePacket(InputMemoryBitStream& inInputStream)
+{
+ //first is my player id
+ int playerId;
+ inInputStream.Read(playerId);
+ UpdateHighestPlayerId(playerId);
+ mPlayerId = playerId;
+
+ //add me to the name map
+ mPlayerNameMap.emplace(mPlayerId, mName);
+
+ //now the player id for the master peer
+ //add entries for the master peer
+ inInputStream.Read(playerId);
+ UpdateHighestPlayerId(playerId);
+ mPlayerToSocketMap.emplace(playerId, mMasterPeerAddr);
+ mSocketToPlayerMap.emplace(mMasterPeerAddr, playerId);
+
+ //now remaining players
+ inInputStream.Read(mPlayerCount);
+ SocketAddress socketAddr;
+ // there's actually count - 1 entries because the master peer won't have an entry for themselves
+ for (int i = 0; i < mPlayerCount - 1; ++i)
+ {
+ inInputStream.Read(playerId);
+ UpdateHighestPlayerId(playerId);
+
+ socketAddr.Read(inInputStream);
+
+ mPlayerToSocketMap.emplace(playerId, socketAddr);
+ mSocketToPlayerMap.emplace(socketAddr, playerId);
+ }
+
+ //now player names
+ std::string name;
+ for (int i = 0; i < mPlayerCount; ++i)
+ {
+ inInputStream.Read(playerId);
+ inInputStream.Read(name);
+ mPlayerNameMap.emplace(playerId, name);
+ }
+
+ //now add 1 to the player count cause I've joined
+ //(the master peer sends me the old list before adding me)
+ mPlayerCount++;
+
+ //now we need to send out an intro packet to every peer in the socket map
+ OutputMemoryBitStream outPacket;
+
+ TransmissionDataIntro* newData = new TransmissionDataIntro(mName, mPlayerId);
+ newData->mPacketType = kIntroCC;
+ AddInFlightPacket(newData, outPacket);
+ outPacket.Write(kIntroCC);
+ outPacket.Write(mPlayerId);
+ outPacket.Write(mName);
+
+
+ WritePendingAcks(outPacket);
+
+ for (auto& iter : mPlayerToSocketMap)
+ {
+ SendPacket(outPacket, iter.second);
+ }
+
+ //I've been welcomed, so I'm in the lobby now
+ mState = NetworkManagerState::NMS_Lobby;
+}
+
+void NetworkManager::ProcessPacketsLobby(InputMemoryBitStream& inInputStream, const SocketAddress& inFromAddress)
+{
+ //could be someone saying hello, an introduction, or a start packet
+ uint32_t packetType;
+ inInputStream.Read(packetType);
+
+ switch (packetType)
+ {
+ case kHelloCC:
+ HandleHelloPacket(inInputStream, inFromAddress);
+ break;
+ case kIntroCC:
+ HandleIntroPacket(inInputStream, inFromAddress);
+ break;
+ case kStartCC:
+ HandleStartPacket(inInputStream, inFromAddress);
+ break;
+ default:
+ LOG("Unexpected packet received in Lobby state. Ignoring.");
+ break;
+ }
+}
+
+void NetworkManager::HandleHelloPacket(InputMemoryBitStream& inInputStream, const SocketAddress& inFromAddress)
+{
+ //for now, if I already know of this player, throw away the packet
+ //this doesn't work if there's packet loss
+ if (mSocketToPlayerMap.find(inFromAddress) != mSocketToPlayerMap.end())
+ {
+ return;
+ }
+
+ if (mPlayerCount >= kMaxPlayerCount)
+ {
+ //sorry, can't join if full
+ OutputMemoryBitStream outPacket;
+ TransmissionData* newData = new TransmissionData;
+ AddInFlightPacket(newData, outPacket);
+ newData->mPacketType = kNotJoinableCC;
+ outPacket.Write(kNotJoinableCC);
+ WritePendingAcks(outPacket);
+ SendPacket(outPacket, inFromAddress);
+ return;
+ }
+
+ if (mIsMasterPeer)
+ {
+ //it'll only contain the new player's name
+ string name;
+ inInputStream.Read(name);
+ OutputMemoryBitStream outputStream;
+ TransmissionDataWelcome* newPacket = new TransmissionDataWelcome;
+ newPacket->mPacketType = kWelcomeCC;
+ AddInFlightPacket(newPacket, outputStream);
+
+ outputStream.Write(kWelcomeCC);
+ //we'll assign the next possible player id to this player
+ mHighestPlayerId++;
+ outputStream.Write(mHighestPlayerId);
+ newPacket->mHighestID = mHighestPlayerId;
+ //write our player id
+ outputStream.Write(mPlayerId);
+ newPacket->mID = mPlayerId;
+ outputStream.Write(mPlayerCount);
+ //now write the player to socket map
+ for (auto& iter : mPlayerToSocketMap)
+ {
+ outputStream.Write(iter.first);
+ iter.second.Write(outputStream);
+ }
+
+ //and the player names
+ for (auto& iter : mPlayerNameMap)
+ {
+ outputStream.Write(iter.first);
+ outputStream.Write(iter.second);
+ }
+ std::cout << "Sending welcome" << std::endl;
+ WritePendingAcks(outputStream);
+ SendPacket(outputStream, inFromAddress);
+
+ //increment the player count and add this player to maps
+ mPlayerCount++;
+ mPlayerToSocketMap.emplace(mHighestPlayerId, inFromAddress);
+ mSocketToPlayerMap.emplace(inFromAddress, mHighestPlayerId);
+ mPlayerNameMap.emplace(mHighestPlayerId, name);
+ }
+ else
+ {
+ string name;
+ inInputStream.Read(name);
+ //talk to the master peer, not me
+
+ TransmissionData* newData = new TransmissionData;
+
+ OutputMemoryBitStream outPacket;
+ AddInFlightPacket(newData, outPacket);
+ newData->mPacketType = kNotMasterPeerCC;
+ outPacket.Write(kNotMasterPeerCC);
+ mMasterPeerAddr.Write(outPacket);
+ WritePendingAcks(outPacket);
+ SendPacket(outPacket, inFromAddress);
+ }
+}
+
+void NetworkManager::HandleIntroPacket(InputMemoryBitStream& inInputStream, const SocketAddress& inFromAddress)
+{
+ //master peer can safely ignore the intro packet
+ if (!mIsMasterPeer)
+ {
+ std::cout << "handling intro" << std::endl;
+ //just contains player's id and name
+ int playerId;
+ string name;
+ inInputStream.Read(playerId);
+ inInputStream.Read(name);
+ UpdateHighestPlayerId(playerId);
+ mPlayerCount++;
+
+ //add the new player to our maps
+ mPlayerToSocketMap.emplace(playerId, inFromAddress);
+ mSocketToPlayerMap.emplace(inFromAddress, playerId);
+ mPlayerNameMap.emplace(playerId, name);
+ }
+ else //Masterpeer does need to read in the info in order for the acknowledgement to work
+ {
+ int playerId;
+ string name;
+ inInputStream.Read(playerId); //Just read them in, doesn't need to do anything else
+ inInputStream.Read(name);
+ }
+}
+
+void NetworkManager::HandleStartPacket(InputMemoryBitStream& inInputStream, const SocketAddress& inFromAddress)
+{
+ UNREFERENCED_PARAMETER(inInputStream);
+ //make sure this is the master peer, cause we don't want any funny business
+ if (inFromAddress == mMasterPeerAddr)
+ {
+ LOG("Got the orders to go!");
+ std::cout << "Handling start" << std::endl;
+ //for now, assume that we're one frame off, but ideally we would RTT to adjust
+ //the time to start, based on latency/jitter
+ mState = NetworkManagerState::NMS_Starting;
+ mTimeToStart = kStartDelay - Timing::sInstance.GetDeltaTime();
+
+ }
+}
+
+void NetworkManager::ProcessPacketsPlaying(InputMemoryBitStream& inInputStream, const SocketAddress& inFromAddress)
+{
+ uint32_t packetType;
+ inInputStream.Read(packetType);
+
+ switch (packetType)
+ {
+ case kUpdateCC:
+ HandleUpdatePacket(inInputStream, inFromAddress);
+ break;
+ default:
+ //ignore anything else
+ std::cout << "anything else" << std::endl;
+ break;
+ }
+}
+
+void NetworkManager::HandleUpdatePacket(InputMemoryBitStream& inInputStream, const SocketAddress& inFromAddress)
+{
+ if (mSocketToPlayerMap.find(inFromAddress) != mSocketToPlayerMap.end())
+ {
+ int expectedId = mSocketToPlayerMap[inFromAddress];
+
+ int playerId;
+ //inInputStream.Read(turnNum);
+ inInputStream.Read(playerId);
+
+ if (playerId != expectedId)
+ {
+ std::cout << "We received turn data for a different player Id...stop trying to cheat!" << std::endl;
+ return;
+ }
+ uint32_t size;
+ inInputStream.Read(size);
+ //std::cout << "Num actions read: " << size << std::endl;
+ if (size > 0)
+ {
+ for (int i = 0; i < size; i++)
+ {
+ ActionData data;
+ data.Read(inInputStream);
+ Game::getInstance()->HandleAction(data.type, data.postion, data.seed);
+
+ }
+ }
+
+
+
+ }
+}
+
+void NetworkManager::ProcessPacketsDelay(InputMemoryBitStream& inInputStream, const SocketAddress& inFromAddress)
+{
+ //the only packet we can even consider here is an input one, since we
+ //only can only enter delay after we've been playing
+ uint32_t packetType;
+ inInputStream.Read(packetType);
+
+ if (packetType == kUpdateCC)
+ {
+ HandleUpdatePacket(inInputStream, inFromAddress);
+ //if we're lucky, maybe this was the packet we were waiting on?
+ //TryAdvanceTurn();
+ }
+}
+
+void NetworkManager::HandleConnectionReset(const SocketAddress& inFromAddress)
+{
+ //remove this player from our maps
+ if (mSocketToPlayerMap.find(inFromAddress) != mSocketToPlayerMap.end())
+ {
+ uint32_t playerId = mSocketToPlayerMap[inFromAddress];
+ mSocketToPlayerMap.erase(inFromAddress);
+ mPlayerToSocketMap.erase(playerId);
+ mPlayerNameMap.erase(playerId);
+ //ScoreBoardManager::sInstance->RemoveEntry(playerId);
+
+ mPlayerCount--;
+
+ //if this was the master peer, pick the next player in the string map to be MP
+ if (inFromAddress == mMasterPeerAddr)
+ {
+ uint32_t newMPId = mPlayerNameMap.begin()->first;
+ if (newMPId == mPlayerId)
+ {
+ //I'm the new master peer, muahahahah
+ mIsMasterPeer = true;
+ }
+ else
+ {
+ mMasterPeerAddr = mPlayerToSocketMap[newMPId];
+ }
+ }
+
+ //if we were in delay, then let's see if we can continue now that this player DC'd?
+ if (mState == NetworkManagerState::NMS_Delay)
+ {
+ //TryAdvanceTurn();
+ }
+ }
+}
+
+void NetworkManager::ReadIncomingPacketsIntoQueue()
+{
+ //should we just keep a static one?
+ char packetMem[1500];
+ int packetSize = sizeof(packetMem);
+ InputMemoryBitStream inputStream(packetMem, packetSize * 8);
+ SocketAddress fromAddress;
+
+ //keep reading until we don't have anything to read ( or we hit a max number that we'll process per frame )
+ int receivedPackedCount = 0;
+ int totalReadByteCount = 0;
+
+ while (receivedPackedCount < kMaxPacketsPerFrameCount)
+ {
+ int readByteCount = mSocket->ReceiveFrom(packetMem, packetSize, fromAddress);
+ if (readByteCount == 0)
+ {
+ //nothing to read
+ break;
+ }
+ else if (readByteCount == -WSAECONNRESET)
+ {
+ //port closed on other end, so DC this person immediately
+ HandleConnectionReset(fromAddress);
+ }
+ else if (readByteCount > 0)
+ {
+ inputStream.ResetToCapacity(readByteCount);
+ ++receivedPackedCount;
+ totalReadByteCount += readByteCount;
+
+ //now, should we drop the packet?
+ if (RoboMath::GetRandomFloatNonGame() >= mDropPacketChance && mState >= NetworkManagerState::NMS_Playing)
+ {
+ //we made it
+ //shove the packet into the queue and we'll handle it as soon as we should...
+ //we'll pretend it wasn't received until simulated latency from now
+ float simulatedReceivedTime = Timing::sInstance.GetTimef() + mSimulatedLatency;
+
+ //Simulating Jitter
+ float simulatedJitter = RoboMath::GetRandomFloat(-0.5f,0.5f);
+ simulatedReceivedTime += simulatedJitter;
+
+ mPacketQueue.emplace(simulatedReceivedTime, inputStream, fromAddress);
+ }
+ else if (mState < NetworkManagerState::NMS_Playing) //Here so that it doesn't drop packets before the game has started
+ {
+ float simulatedReceivedTime = Timing::sInstance.GetTimef() + mSimulatedLatency;
+
+ mPacketQueue.emplace(simulatedReceivedTime, inputStream, fromAddress);
+ }
+ else
+ {
+ //LOG("Dropped packet!", 0);
+ //dropped!
+ }
+ }
+ else
+ {
+ //uhoh, error? exit or just keep going?
+ }
+ }
+
+ if (totalReadByteCount > 0)
+ {
+ mBytesReceivedPerSecond.UpdatePerSecond(static_cast(totalReadByteCount));
+ }
+}
+
+void NetworkManager::ProcessQueuedPackets()
+{
+ //look at the front packet...
+ while (!mPacketQueue.empty())
+ {
+ ReceivedPacket& nextPacket = mPacketQueue.front();
+ if (Timing::sInstance.GetTimef() > nextPacket.GetReceivedTime())
+ {
+ ProcessPacket(nextPacket.GetPacketBuffer(), nextPacket.GetFromAddress());
+ mPacketQueue.pop();
+ }
+ else
+ {
+ break;
+ }
+
+ }
+
+}
+
+void NetworkManager::UpdateHighestPlayerId(uint32_t inId)
+{
+ mHighestPlayerId = std::max(mHighestPlayerId, inId);
+}
+
+void NetworkManager::EnterPlayingState()
+{
+ mState = NetworkManagerState::NMS_Playing;
+ Game::getInstance()->startGame();
+}
+
+void NetworkManager::SendPacket(const OutputMemoryBitStream& inOutputStream, const SocketAddress& inToAddress)
+{
+ int sentByteCount = mSocket->SendTo(inOutputStream.GetBufferPtr(), inOutputStream.GetByteLength(), inToAddress);
+ if (sentByteCount > 0)
+ {
+ mBytesSentThisFrame += sentByteCount;
+ }
+}
+
+void NetworkManager::TryStartGame()
+{
+ if (mState < NetworkManagerState::NMS_Starting && IsMasterPeer())
+ {
+ LOG("Master peer starting the game!");
+ std::cout << "Sending start" << std::endl;
+ //let everyone know
+ OutputMemoryBitStream outPacket;
+ TransmissionDataStart* newData = new TransmissionDataStart;
+ newData->mPacketType = kStartCC;
+ AddInFlightPacket(newData, outPacket);
+
+ outPacket.Write(kStartCC);
+ WritePendingAcks(outPacket);
+ for (auto& iter : mPlayerToSocketMap)
+ {
+ SendPacket(outPacket, iter.second);
+ }
+
+ mTimeToStart = kStartDelay;
+ mState = NetworkManagerState::NMS_Starting;
+ }
+}
+
+void NetworkManager::UpdateBytesSentLastFrame()
+{
+ if (mBytesSentThisFrame > 0)
+ {
+ mBytesSentPerSecond.UpdatePerSecond(static_cast(mBytesSentThisFrame));
+
+ mBytesSentThisFrame = 0;
+ }
+
+}
+
+
+NetworkManager::ReceivedPacket::ReceivedPacket(float inReceivedTime, InputMemoryBitStream& ioInputMemoryBitStream, const SocketAddress& inFromAddress) :
+ mReceivedTime(inReceivedTime),
+ mFromAddress(inFromAddress),
+ mPacketBuffer(ioInputMemoryBitStream)
+{
+}
+
+void NetworkManager::addAction(Game::ActionTypes type, Vector2D pos, int seed)
+{
+ ActionData action;
+ action.type = type;
+ action.postion = pos;
+ action.seed = seed;
+ mActionVec.push_back(action);
+}
+
+void NetworkManager::ActionData::Write(OutputMemoryBitStream& inOutputStream)
+{
+ inOutputStream.Write(type);
+ inOutputStream.Write(postion.getX());
+ inOutputStream.Write(postion.getY());
+ if (type == Game::ActionTypes::CreateUnitRand || type == Game::ActionTypes::CreateUnitMove)
+ {
+ inOutputStream.Write(seed);
+ }
+}
+
+void NetworkManager::ActionData::Read(InputMemoryBitStream& inInputStream)
+{
+ float x, y;
+ inInputStream.Read(type);
+ inInputStream.Read(x);
+ inInputStream.Read(y);
+ postion = Vector2D(x, y);
+ if (type == Game::ActionTypes::CreateUnitRand || type == Game::ActionTypes::CreateUnitMove)
+ {
+ inInputStream.Read(seed);
+ }
+}
+
+void NetworkManager::AddInFlightPacket(TransmissionData* data, OutputMemoryBitStream& output)
+{
+ int sequenceNumber = mNextOutgoingSequenceNumber;
+ output.Write(sequenceNumber);
+ //std::cout << "Sending packet #" << sequenceNumber << " " <sequenceID = sequenceNumber;
+
+ mInFlightPackets.emplace(sequenceNumber, data);
+ mNextOutgoingSequenceNumber++;
+}
+
+void NetworkManager::WritePendingAcks(OutputMemoryBitStream& output)
+{
+ uint32_t size = mPendingAcks.size();
+ output.Write(size);
+ //std::cout << "Num of acks " << size << std::endl;
+ if (size > 0)
+ {
+ for (int i = 0; i < size; i++)
+ {
+ output.Write(mPendingAcks[i]);
+ //std::cout << mPendingAcks[i] << std::endl;
+ }
+ }
+ mPendingAcks.clear();
+}
+
+void NetworkManager::ProcessNewAcks(InputMemoryBitStream& input)
+{
+ TransmissionData* temp;
+ uint32_t Acks;
+ input.Read(Acks);
+ //std::cout << "Acks: " << Acks << std::endl;
+ if (Acks > 0)
+ {
+ for (int i = 0; i < Acks; i++)
+ {
+ int sequenceNum;
+ input.Read(sequenceNum);
+ int size = mInFlightPackets.size();
+ map::iterator itr = mInFlightPackets.begin();
+ for (int j = 0; j < size; j++)
+ {
+ if (itr->first < sequenceNum)
+ {
+ //std::cout << itr->first << " < " << sequenceNum << std::endl;
+ temp = itr->second;
+ temp->handleDeliveryFailure();
+ mInFlightPackets.erase(itr);
+ itr = mInFlightPackets.begin();
+ delete(temp);
+ temp = nullptr;
+ }
+ else if (itr->first == sequenceNum)
+ {
+ temp = itr->second;
+ //std::cout << sequenceNum << " Packet delivered" << std::endl;
+ temp->handleDeliverySuccess();
+ mInFlightPackets.erase(itr);
+ itr = mInFlightPackets.begin();
+ delete(temp);
+ temp = nullptr;
+ }
+ else if (itr->first > sequenceNum)
+ {
+ //std::cout << sequenceNum << " No news" << std::endl;
+ break;
+ }
+ }
+ }
+ }
+}
+
+void NetworkManager::ProcessSequenceNum(int sequenceNum)
+{
+ if (sequenceNum == mNextExpectedSequenceNumber)
+ {
+ //std::cout << sequenceNum << " equals " << mNextExpectedSequenceNumber << std::endl;
+ mNextExpectedSequenceNumber = sequenceNum + 1;
+ mPendingAcks.push_back(sequenceNum);
+ }
+ else if (sequenceNum > mNextExpectedSequenceNumber)
+ {
+ //std::cout << sequenceNum << " greater than " << mNextExpectedSequenceNumber << std::endl;
+ mNextExpectedSequenceNumber = sequenceNum + 1;
+
+ mPendingAcks.push_back(sequenceNum);
+
+ }
+ else
+ {
+ //std::cout << sequenceNum << " less than " << mNextExpectedSequenceNumber << std::endl;
+ return;
+ }
+
+}
+
+
+
+void NetworkManager::TransmissionDataUpdate::handleDeliveryFailure()
+{
+ if (mData.size() > 0)
+ {
+ std::cout << sequenceID << " Action packet dropped, resending" << std::endl;
+ NetworkManager* pNetManager = Game::getInstance()->getNetworkManager();
+ for (int i = 0; i < mData.size(); i++)
+ {
+ pNetManager->mActionVec.push_back(mData[i]);
+ }
+ mData.clear();
+ }
+}
+
+void NetworkManager::TransmissionDataHello::handleDeliveryFailure()
+{
+ std::cout << sequenceID << " hello packet dropped" << std::endl;
+}
+
+void NetworkManager::TransmissionDataIntro::handleDeliveryFailure()
+{
+ std::cout << sequenceID << " intro packet dropped, resending" << std::endl;
+}
+
+void NetworkManager::TransmissionDataWelcome::handleDeliveryFailure()
+{
+ std::cout << sequenceID << " welcome packet dropped, resending" << std::endl;
+}
+void NetworkManager::TransmissionDataStart::handleDeliveryFailure()
+{
+ std::cout << sequenceID << " start packet dropped, resending" << std::endl;
+ NetworkManager* pNetManager = Game::getInstance()->getNetworkManager();
+ pNetManager->TryStartGame();
+}
\ No newline at end of file
diff --git a/RoboCat/Src/BaseGameSrc/Unit.cpp b/RoboCat/Src/BaseGameSrc/Unit.cpp
new file mode 100644
index 00000000..872321f7
--- /dev/null
+++ b/RoboCat/Src/BaseGameSrc/Unit.cpp
@@ -0,0 +1,324 @@
+#include "Unit.h"
+#include "Game.h"
+#include
+#include
+#include
+
+Unit::Unit(const Vector2D& position, const Animation& mainAnimation, const Animation& altAnimation)
+ :mPos(position)
+ ,mMainAnimation(mainAnimation)
+ ,mAltAnimation(altAnimation)
+ ,mpCurrentAnimation(NULL)
+{
+ mpCurrentAnimation = &mMainAnimation;
+}
+
+void Unit::update(double dt)
+{
+ mpCurrentAnimation->update(dt);
+}
+
+void Unit::draw()
+{
+ const Sprite& currSprite = mpCurrentAnimation->getCurrentSprite();
+ Vector2D offset = currSprite.getCenterOffset();
+ Vector2D centerPos = mPos - offset;
+
+ Game::getInstance()->getSystem()->getGraphicsSystem()->draw(centerPos, currSprite);
+}
+
+void Unit::toggleAnimation()
+{
+ Animation* pOldAnimation = mpCurrentAnimation;
+ if (mpCurrentAnimation == &mMainAnimation)
+ {
+ mpCurrentAnimation = &mAltAnimation;
+ }
+ else
+ {
+ mpCurrentAnimation = &mMainAnimation;
+ }
+
+ mpCurrentAnimation->synch(*pOldAnimation);
+
+}
+
+void Unit::speedUpAnimation()
+{
+ float currentTiming = mpCurrentAnimation->getTimePerFrame();
+ float gameTimePerFrame = (float)Game::getInstance()->getTargetTimePerFrame();
+ currentTiming -= gameTimePerFrame;
+ if (currentTiming < gameTimePerFrame)
+ {
+ currentTiming = gameTimePerFrame;
+ }
+
+ mpCurrentAnimation->setTimePerFrame(currentTiming);
+}
+
+int MAX_MULTIPLE = 50;
+
+void Unit::slowDownAnimation()
+{
+ float currentTiming = mpCurrentAnimation->getTimePerFrame();
+ float gameTimePerFrame = (float)Game::getInstance()->getTargetTimePerFrame();
+ currentTiming += gameTimePerFrame;
+ if (currentTiming > gameTimePerFrame*MAX_MULTIPLE)
+ {
+ currentTiming = gameTimePerFrame*MAX_MULTIPLE;
+ }
+
+ mpCurrentAnimation->setTimePerFrame(currentTiming);
+}
+
+void Unit::setAnimationPauseState(bool shouldPause)
+{
+ mpCurrentAnimation->setPauseState(shouldPause);
+}
+
+void Unit::toggleAnimationPauseState()
+{
+ mpCurrentAnimation->togglePause();
+}
+
+bool Unit::doesPointIntersect(const Vector2D& point) const
+{
+ Vector2D ul = getULPosition();
+ Vector2D lr = getLRPosition();
+
+ if (point.getX() < ul.getX())
+ {
+ return false;
+ }
+ else if (point.getY() < ul.getY())
+ {
+ return false;
+ }
+
+ else if (point.getX() > lr.getX())
+ {
+ return false;
+ }
+ else if (point.getY() > lr.getY())
+ {
+ return false;
+ }
+
+ return true;
+}
+
+Vector2D Unit::getULPosition() const
+{
+ Vector2D center = getCenterPosition();
+ const Sprite& currSprite = mpCurrentAnimation->getCurrentSprite();
+ return center - Vector2D(currSprite.getWidth() / 2.0f, currSprite.getHeight() / 2.0f);
+}
+
+Vector2D Unit::getLRPosition() const
+{
+ Vector2D center = getCenterPosition();
+ const Sprite& currSprite = mpCurrentAnimation->getCurrentSprite();
+ return center + Vector2D(currSprite.getWidth() / 2.0f, currSprite.getHeight() / 2.0f);
+}
+
+RandomSpawnedUnit::RandomSpawnedUnit(const Vector2D& position, const Animation& mainAnimation, const Animation& altAnimation, int seed)
+ :mPos(position)
+ , mMainAnimation(mainAnimation)
+ , mAltAnimation(altAnimation)
+ , mpCurrentAnimation(NULL)
+ , mSeed(seed)
+{
+ mpCurrentAnimation = &mMainAnimation;
+}
+
+void RandomSpawnedUnit::update(double dt)
+{
+
+ mpCurrentAnimation->update(dt);
+
+}
+
+void RandomSpawnedUnit::draw()
+{
+
+ const Sprite& currSprite = mpCurrentAnimation->getCurrentSprite();
+ Vector2D offset = currSprite.getCenterOffset();
+ Vector2D centerPos = mPos - offset;
+
+ Game::getInstance()->getSystem()->getGraphicsSystem()->draw(centerPos, currSprite);
+
+}
+
+bool RandomSpawnedUnit::doesPointIntersect(const Vector2D& point) const
+{
+ Vector2D ul = getULPosition();
+ Vector2D lr = getLRPosition();
+
+ if (point.getX() < ul.getX())
+ {
+ return false;
+ }
+ else if (point.getY() < ul.getY())
+ {
+ return false;
+ }
+
+ else if (point.getX() > lr.getX())
+ {
+ return false;
+ }
+ else if (point.getY() > lr.getY())
+ {
+ return false;
+ }
+
+ return true;
+}
+
+void RandomSpawnedUnit::toggleAnimation()
+{
+ Animation* pOldAnimation = mpCurrentAnimation;
+ if (mpCurrentAnimation == &mMainAnimation)
+ {
+ mpCurrentAnimation = &mAltAnimation;
+ }
+ else
+ {
+ mpCurrentAnimation = &mMainAnimation;
+ }
+
+ mpCurrentAnimation->synch(*pOldAnimation);
+
+}
+
+Vector2D RandomSpawnedUnit::getULPosition() const
+{
+ Vector2D center = getCenterPosition();
+ const Sprite& currSprite = mpCurrentAnimation->getCurrentSprite();
+ return center - Vector2D(currSprite.getWidth() / 2.0f, currSprite.getHeight() / 2.0f);
+}
+
+Vector2D RandomSpawnedUnit::getLRPosition() const
+{
+ Vector2D center = getCenterPosition();
+ const Sprite& currSprite = mpCurrentAnimation->getCurrentSprite();
+ return center + Vector2D(currSprite.getWidth() / 2.0f, currSprite.getHeight() / 2.0f);
+}
+
+void RandomSpawnedUnit::setAnimationPauseState(bool shouldPause)
+{
+ mpCurrentAnimation->setPauseState(shouldPause);
+}
+
+void RandomSpawnedUnit::toggleAnimationPauseState()
+{
+ mpCurrentAnimation->togglePause();
+}
+
+RandomPosUnit::RandomPosUnit(const Vector2D& position, const Animation& mainAnimation, const Animation& altAnimation, int seed)
+ :mPos(position)
+ , mMainAnimation(mainAnimation)
+ , mAltAnimation(altAnimation)
+ , mpCurrentAnimation(NULL)
+ , mSeed(seed)
+ , timer(1200)
+{
+ mpCurrentAnimation = &mMainAnimation;
+}
+
+void RandomPosUnit::update(double dt)
+{
+
+ timer -= dt;
+
+ if (timer <= 0)
+ {
+ srand(mSeed);
+ int randX = rand() % 800;
+ int randY = rand() % 600;
+ Vector2D newPos(randX, randY);
+ setPosition(newPos);
+ timer = 1200;
+ mSeed += 1; //I couldn't figure out randomization in time. I know the constant srand-ing is not ideal
+ }
+
+ mpCurrentAnimation->update(dt);
+
+}
+
+void RandomPosUnit::draw()
+{
+
+ const Sprite& currSprite = mpCurrentAnimation->getCurrentSprite();
+ Vector2D offset = currSprite.getCenterOffset();
+ Vector2D centerPos = mPos - offset;
+
+ Game::getInstance()->getSystem()->getGraphicsSystem()->draw(centerPos, currSprite);
+
+}
+
+bool RandomPosUnit::doesPointIntersect(const Vector2D& point) const
+{
+ Vector2D ul = getULPosition();
+ Vector2D lr = getLRPosition();
+
+ if (point.getX() < ul.getX())
+ {
+ return false;
+ }
+ else if (point.getY() < ul.getY())
+ {
+ return false;
+ }
+
+ else if (point.getX() > lr.getX())
+ {
+ return false;
+ }
+ else if (point.getY() > lr.getY())
+ {
+ return false;
+ }
+
+ return true;
+}
+
+void RandomPosUnit::toggleAnimation()
+{
+ Animation* pOldAnimation = mpCurrentAnimation;
+ if (mpCurrentAnimation == &mMainAnimation)
+ {
+ mpCurrentAnimation = &mAltAnimation;
+ }
+ else
+ {
+ mpCurrentAnimation = &mMainAnimation;
+ }
+
+ mpCurrentAnimation->synch(*pOldAnimation);
+
+}
+
+Vector2D RandomPosUnit::getULPosition() const
+{
+ Vector2D center = getCenterPosition();
+ const Sprite& currSprite = mpCurrentAnimation->getCurrentSprite();
+ return center - Vector2D(currSprite.getWidth() / 2.0f, currSprite.getHeight() / 2.0f);
+}
+
+Vector2D RandomPosUnit::getLRPosition() const
+{
+ Vector2D center = getCenterPosition();
+ const Sprite& currSprite = mpCurrentAnimation->getCurrentSprite();
+ return center + Vector2D(currSprite.getWidth() / 2.0f, currSprite.getHeight() / 2.0f);
+}
+
+void RandomPosUnit::setAnimationPauseState(bool shouldPause)
+{
+ mpCurrentAnimation->setPauseState(shouldPause);
+}
+
+void RandomPosUnit::toggleAnimationPauseState()
+{
+ mpCurrentAnimation->togglePause();
+}
\ No newline at end of file
diff --git a/RoboCat/Src/BaseGameSrc/UnitManager.cpp b/RoboCat/Src/BaseGameSrc/UnitManager.cpp
new file mode 100644
index 00000000..515ae3aa
--- /dev/null
+++ b/RoboCat/Src/BaseGameSrc/UnitManager.cpp
@@ -0,0 +1,178 @@
+#include "UnitManager.h"
+#include "Unit.h"
+#include "Game.h"
+
+#include
+
+#include
+#include "MemoryManager.h"
+
+using namespace std;
+
+UnitManager::UnitManager()
+{
+ nextID = 0;
+}
+
+UnitManager::~UnitManager()
+{
+ clear();
+}
+
+void UnitManager::clear()
+{
+ /*vector::iterator iter;
+
+ for (iter = mUnits.begin(); iter != mUnits.end(); ++iter)
+ {
+ }*/
+ MemoryManager* pMemoryManager = Game::getInstance()->getMemoryManager();
+ for (auto iter : mUnits)
+ {
+
+ iter->~Unit();
+ pMemoryManager->deallocate((Byte*)iter);
+ }
+
+ mUnits.clear();
+}
+
+void UnitManager::update(double dt)
+{
+ for (unsigned int i = 0; i < mUnits.size(); i++)
+ {
+ mUnits[i]->update(dt);
+ }
+}
+
+void UnitManager::draw() const
+{
+ vector::const_iterator iter;
+ for (iter = mUnits.begin(); iter != mUnits.end(); ++iter)
+ {
+ (*iter)->draw();
+ }
+}
+
+Unit* UnitManager::createUnit(const Vector2D& position, const Animation& mainAnimation, const Animation& altAnimation)
+{
+ MemoryManager* pMemoryManager = Game::getInstance()->getMemoryManager();
+
+ Byte* ptr = pMemoryManager->allocate(sizeof(Unit));
+
+ Unit* pUnit = new(ptr)Unit(position, mainAnimation, altAnimation);//placement new create the unit.
+
+
+
+ mUnits.push_back(pUnit);//put the unit into the vector
+ nextID += 1;
+ return pUnit;//return the newly created Unit (for convenience)
+}
+
+Unit* UnitManager::createUnit(const Vector2D& position, const Animation& mainAnimation, const Animation& altAnimation, int seed)
+{
+ MemoryManager* pMemoryManager = Game::getInstance()->getMemoryManager();
+
+ Byte* ptr = pMemoryManager->allocate(sizeof(RandomPosUnit));
+
+ Unit* pUnit = new(ptr)RandomPosUnit(position, mainAnimation, altAnimation, seed);//placement new create the unit.
+
+
+
+ mUnits.push_back(pUnit);//put the unit into the vector
+ nextID += 1;
+ return pUnit;//return the newly created Unit (for convenience)
+}
+
+Unit* UnitManager::createUnit(const Animation& mainAnimation, const Animation& altAnimation, int seed)
+{
+ MemoryManager* pMemoryManager = Game::getInstance()->getMemoryManager();
+
+ Byte* ptr = pMemoryManager->allocate(sizeof(RandomSpawnedUnit));
+ srand(seed);
+ int randX = rand() % 800;
+ int randY = rand() % 600;
+ Vector2D position(randX, randY);
+ Unit* pUnit = new(ptr)RandomSpawnedUnit(position, mainAnimation, altAnimation, seed);//placement new create the unit.
+ assert(pUnit);
+
+ mUnits.push_back(pUnit);//put the unit into the vector
+ nextID += 1;
+;
+ return pUnit;//return the newly created Unit (for convenience)
+}
+
+void UnitManager::deleteAllUnitsAt2DPosition(const Vector2D& position)
+{
+ while (deleteUnitAt2DPosition(position));
+}
+
+bool UnitManager::deleteUnitAt2DPosition(const Vector2D& position)
+{
+ for (unsigned int i = 0; i < mUnits.size(); i++)
+ {
+ if (mUnits[i]->doesPointIntersect(position))
+ {
+ deleteUnitAtIndex(i);//only delete one unit
+ return true;
+ }
+ }
+ return false;
+}
+
+void UnitManager::deleteUnitAtIndex(unsigned int index)
+{
+ assert(index >= 0 && index < mUnits.size());
+ MemoryManager* pMemoryManager = Game::getInstance()->getMemoryManager();
+ if (index >= 0 && index < mUnits.size())
+ {
+ mUnits[index]->~Unit();
+ pMemoryManager->deallocate((Byte*)mUnits[index]);
+ mUnits.erase(mUnits.begin() + index);
+
+
+ }
+
+}
+
+void UnitManager::deleteUnit(Unit* pUnit)
+{
+ vector::iterator iter;
+ MemoryManager* pMemoryManager = Game::getInstance()->getMemoryManager();
+ for (iter = mUnits.begin(); iter != mUnits.end(); ++iter)
+ {
+ if (*iter == pUnit)
+ {
+ pUnit->~Unit(); //Placement new destructor call. Need to do it.
+ pMemoryManager->deallocate((Byte*)pUnit);
+ mUnits.erase(iter);
+ break;
+ }
+ }
+}
+
+Unit* UnitManager::getLastUnitCreated() const
+{
+ if (mUnits.size() > 0)
+ {
+ return mUnits[mUnits.size() - 1];
+ }
+ else
+ return NULL;
+}
+
+void UnitManager::setPauseStateForAllAnimations(bool isPaused)
+{
+ for (unsigned int i = 0; i < mUnits.size(); i++)
+ {
+ mUnits[i]->setAnimationPauseState(isPaused);
+ }
+}
+
+void UnitManager::togglePauseStateForAllAnimations()
+{
+ for (unsigned int i = 0; i < mUnits.size(); i++)
+ {
+ mUnits[i]->toggleAnimationPauseState();
+ }
+}
diff --git a/RoboCat/Src/BaseGameSrc/main.cpp b/RoboCat/Src/BaseGameSrc/main.cpp
new file mode 100644
index 00000000..04234d91
--- /dev/null
+++ b/RoboCat/Src/BaseGameSrc/main.cpp
@@ -0,0 +1,43 @@
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "Game.h"
+#include "RoboCatPCH.h"
+using namespace std;
+
+int main(int argc, const char** argv)
+{
+ UNREFERENCED_PARAMETER(argc);
+ UNREFERENCED_PARAMETER(argv);
+
+ const unsigned int WIDTH = 800;
+ const unsigned int HEIGHT = 600;
+ //SocketUtil::StaticInit();
+ Game::initInstance();
+ Game* pGame = Game::getInstance();
+
+ pGame->init(WIDTH, HEIGHT);
+ pGame->doLoop();
+ pGame->cleanup();
+
+ Game::deleteInstance();
+ //SocketUtil::CleanUp();
+ MemoryTracker::getInstance()->reportAllocations(cout);
+ system("pause");
+
+ return 0;
+
+}
\ No newline at end of file
diff --git a/RoboCat/Src/DeanSrc/CircularQueue.cpp b/RoboCat/Src/DeanSrc/CircularQueue.cpp
new file mode 100644
index 00000000..184644b5
--- /dev/null
+++ b/RoboCat/Src/DeanSrc/CircularQueue.cpp
@@ -0,0 +1,7 @@
+#include "CircularQueue.h"
+
+
+
+
+
+
diff --git a/RoboCat/Src/DeanSrc/DataRepository.cpp b/RoboCat/Src/DeanSrc/DataRepository.cpp
new file mode 100644
index 00000000..54717cf5
--- /dev/null
+++ b/RoboCat/Src/DeanSrc/DataRepository.cpp
@@ -0,0 +1,88 @@
+#include "DataRepository.h"
+#include
+
+DataEntry::DataEntry( int val )
+ :mType(INT_VAL)
+{
+ mData.intVal = val;
+}
+
+DataEntry::DataEntry( float val )
+ :mType(FLOAT_VAL)
+{
+ mData.floatVal = val;
+}
+
+DataEntry::DataEntry( double val )
+ :mType(DOUBLE_VAL)
+{
+ mData.doubleVal = val;
+}
+
+DataEntry::DataEntry( const std::string& val )
+ :mType(STRING_VAL)
+{
+ assert( val.size() + 1 < MAX_STRING_VAL_SIZE );
+ strcpy_s( mData.stringVal, val.c_str() );
+}
+
+DataEntry::DataEntry( UINT val )
+ :mType(UINT_VAL)
+{
+ mData.uintVal = val;
+}
+
+void DataRepository::addEntry( const DataKey& key, int val )
+{
+ DataEntry entry( val );
+ mMap[key] = entry;
+}
+
+void DataRepository::addEntry( const DataKey& key, float val )
+{
+ DataEntry entry( val );
+ mMap[key] = entry;
+}
+
+void DataRepository::addEntry( const DataKey& key, double val )
+{
+ DataEntry entry( val );
+ mMap[key] = entry;
+}
+
+void DataRepository::addEntry( const DataKey& key, const std::string& val )
+{
+ DataEntry entry( val );
+ mMap[key] = entry;
+}
+
+void DataRepository::addEntry( const DataKey& key, UINT val )
+{
+ DataEntry entry( val );
+ mMap[key] = entry;
+}
+
+const DataEntry& DataRepository::getEntry( const DataKey& key )
+{
+ static DataEntry nullEntry(0);
+
+ auto iter = mMap.find( key );
+ if( iter != mMap.end() )
+ {
+ return iter->second;
+ }
+ else
+ {
+ return nullEntry;
+ }
+}
+
+bool DataRepository::hasEntry(const DataKey& key)
+{
+ auto iter = mMap.find(key);
+ if (iter != mMap.end())
+ return true;
+ else
+ return false;
+}
+
diff --git a/RoboCat/Src/DeanSrc/DeanLibUtilities.cpp b/RoboCat/Src/DeanSrc/DeanLibUtilities.cpp
new file mode 100644
index 00000000..e9051ab8
--- /dev/null
+++ b/RoboCat/Src/DeanSrc/DeanLibUtilities.cpp
@@ -0,0 +1,37 @@
+#include "DeanLibUtilities.h"
+#include
+
+using namespace std;
+
+string peekString(istream& stream)
+{
+ if (!stream.good() || stream.eof())
+ {
+ return "";
+ }
+
+ int charCnt = 0;
+ auto currPos = stream.tellg();
+
+ string theString;
+
+ getline(stream, theString);
+
+ stringstream sStream(theString);
+
+ string extractedString;
+ sStream >> extractedString;
+
+ stream.seekg(currPos);
+ return extractedString;
+}
+
+int peekInt(std::istream& stream)
+{
+ string extractedString = peekString(stream);
+ int theInt = 0;
+ stringstream sStream(extractedString);
+ sStream >> theInt;
+ return theInt;
+}
+
diff --git a/RoboCat/Src/DeanSrc/DeanMath.cpp b/RoboCat/Src/DeanSrc/DeanMath.cpp
new file mode 100644
index 00000000..49bb986b
--- /dev/null
+++ b/RoboCat/Src/DeanSrc/DeanMath.cpp
@@ -0,0 +1,42 @@
+#include "DeanMath.h"
+#include "Vector2D.h"
+
+double calcDotProduct(const Vector2D& vector1, const Vector2D& vector2)
+{
+ return vector1.dotProduct(vector2);
+}
+
+double mapToRangeMinusPiToPi(double val)
+{
+ while (val < -PI)
+ {
+ val += DOUBLE_PI;
+ }
+
+ while (val > PI)
+ {
+ val -= DOUBLE_PI;
+ }
+ return val;
+}
+
+double lerp(double low, double high, double pct)
+{
+ if (pct > 1.0)
+ pct = 1.0;
+ else if (pct < 0.0)
+ pct = 0.0;
+
+ return low + pct * (high - low);
+}
+
+int lerp(int low, int high, double pct)
+{
+ if (pct > 1.0)
+ pct = 1.0;
+ else if (pct < 0.0)
+ pct = 0.0;
+
+ return low + (int)((float)pct * (high - low));
+}
+
diff --git a/RoboCat/Src/DeanSrc/MemoryPool.cpp b/RoboCat/Src/DeanSrc/MemoryPool.cpp
new file mode 100644
index 00000000..5570f533
--- /dev/null
+++ b/RoboCat/Src/DeanSrc/MemoryPool.cpp
@@ -0,0 +1,126 @@
+#include "MemoryPool.h"
+#include
+#include
+#include
+
+using namespace std;
+
+//got this algorithm from: http://www.exploringbinary.com/ten-ways-to-check-if-an-integer-is-a-power-of-two-in-c/
+int isPowerOfTwo(unsigned int x)
+{
+ return ((x != 0) && !(x & (x - 1)));
+}
+
+unsigned int getClosestPowerOf2LargerThan(unsigned int num)
+{
+ static Uint32 powersOf2[32];
+ static bool arrayInitted = false;
+
+ //init an array containing all the powers of 2
+ //(as it is static this should only run the first time this function is called)
+ if (!arrayInitted)
+ {
+ for (Uint32 i = 0; i < 32; i++)
+ {
+ powersOf2[i] = 1 << i;
+ }
+ }
+
+ //find the 1st power of 2 which is bigger than or equal to num
+ for (Uint32 i = 0; i < 32; i++)
+ {
+ if ( powersOf2[i] >= num )
+ return powersOf2[i];
+ }
+
+ //failsafe
+ return 0;
+
+}
+
+MemoryPool::MemoryPool(Uint32 maxNumObjects, Uint32 objectSize)
+{
+ //make objectSize a power of 2 - used for padding
+ objectSize = getClosestPowerOf2LargerThan(objectSize);
+ if (objectSize < 4)
+ {
+ objectSize = 4;
+ }
+
+ //allocate the memory
+ mMemory = (Byte*)malloc(objectSize * maxNumObjects);
+
+ //set member variables
+ mMaxNumObjects = maxNumObjects;
+ mNumAllocatedObjects = 0;
+ mObjectSize = objectSize;
+ mHighestValidAddress = mMemory + ((maxNumObjects - 1) * objectSize);
+
+ //allocate the free list
+ mpFreeList = new CircularQueue(mMaxNumObjects);
+
+ //create the free list
+ createFreeList();
+}
+
+void MemoryPool::reset()
+{
+ //clear the free list
+ mpFreeList->reset();
+ //create the free list again
+ createFreeList();
+ //reset count of allocated objects
+ mNumAllocatedObjects = 0;
+}
+
+Byte* MemoryPool::allocateObject()
+{
+ if (mNumAllocatedObjects >= mMaxNumObjects)
+ {
+ return NULL;
+ }
+
+ mNumAllocatedObjects++;
+ Byte* ptr;
+ bool success = mpFreeList->popFront(ptr);
+ if (success)
+ {
+ return ptr;
+ }
+ else
+ {
+ assert(false);
+ return NULL;
+ }
+}
+
+void MemoryPool::freeObject(Byte* ptr)
+{
+ //make sure that the address passed in is actually one managed by this pool
+ if (contains(ptr))
+ {
+ //add address back to free list
+ mpFreeList->pushBack(ptr);
+
+ mNumAllocatedObjects--;
+ }
+ else
+ {
+ cout << "ERROR: object freed from a pool that doesn't manage it\n";
+ assert(ptr >= mMemory && ptr <= mHighestValidAddress);
+ }
+}
+
+bool MemoryPool::contains(Byte* ptr) const
+{
+ return (ptr >= mMemory && ptr <= mHighestValidAddress);
+}
+
+void MemoryPool::createFreeList()
+{
+ for (Uint32 i = 0; ipushBack(mMemory + (i * mObjectSize));
+ }
+
+}
diff --git a/RoboCat/Src/DeanSrc/MemoryTracker.cpp b/RoboCat/Src/DeanSrc/MemoryTracker.cpp
new file mode 100644
index 00000000..690a1ded
--- /dev/null
+++ b/RoboCat/Src/DeanSrc/MemoryTracker.cpp
@@ -0,0 +1,70 @@
+#include
+#include
+#include "MemoryTracker.h"
+#include "Trackable.h"
+
+using namespace std;
+
+int MemoryTracker::msAllocationNum = 0;
+MemoryTracker* MemoryTracker::mspInstance = NULL;
+
+MemoryTracker* MemoryTracker::getInstance()
+{
+ if (mspInstance == NULL)
+ {
+ mspInstance = new MemoryTracker;
+ }
+ return mspInstance;
+}
+
+MemoryTracker::MemoryTracker()
+{
+}
+
+MemoryTracker::~MemoryTracker()
+{
+ cout << "MemoryTracker being deleted: final allocations follow:\n";
+ reportAllocations( cout );
+}
+
+void MemoryTracker::addAllocation( void* ptr, size_t size )
+{
+ //make sure it's not already in the map
+ unordered_map::iterator iter = mAllocations.find( ptr );
+ if( iter != mAllocations.end() )
+ {
+ //already exists - problem!
+ }
+ else
+ {
+ AllocationRecord theRec( msAllocationNum, size );
+ pair thePair(ptr,theRec);
+ mAllocations.insert( thePair );
+ msAllocationNum++;
+ }
+}
+
+void MemoryTracker::removeAllocation( void* ptr )
+{
+ //find it in the map!
+ unordered_map::iterator iter = mAllocations.find( ptr );
+ if( iter == mAllocations.end() )
+ {
+ //problem!!!!
+ }
+ else
+ {
+ mAllocations.erase( iter );
+ }
+}
+
+void MemoryTracker::reportAllocations( std::ostream& stream )
+{
+ stream << "Current memory allocations:\n";
+
+ unordered_map::iterator iter;
+ for( iter = mAllocations.begin(); iter != mAllocations.end(); ++iter )
+ {
+ stream << "address:" << iter->first << " size:" << iter->second.size << " num:" << iter->second.num << endl;
+ }
+}
diff --git a/RoboCat/Src/DeanSrc/PerformanceTracker.cpp b/RoboCat/Src/DeanSrc/PerformanceTracker.cpp
new file mode 100644
index 00000000..6817bfbe
--- /dev/null
+++ b/RoboCat/Src/DeanSrc/PerformanceTracker.cpp
@@ -0,0 +1,81 @@
+#include "PerformanceTracker.h"
+
+using namespace std;
+
+PerformanceTracker::PerformanceTracker()
+{
+}
+
+PerformanceTracker::~PerformanceTracker()
+{
+ map::iterator iter;
+ for( iter = mTimers.begin(); iter != mTimers.end(); ++iter )
+ {
+ delete iter->second;
+ }
+}
+
+void PerformanceTracker::startTracking( const string& trackerName )
+{
+ Timer* pTimer = NULL;
+
+ //find if tracker already exists
+ map::iterator iter = mTimers.find( trackerName );
+ if( iter != mTimers.end() )
+ {
+ pTimer = iter->second;
+ }
+ else
+ {
+ pTimer = new Timer();
+ pTimer->start();
+ mTimers[trackerName] = pTimer;
+ }
+
+ pTimer->pause(false);
+}
+
+void PerformanceTracker::stopTracking( const string& trackerName )
+{
+ //make sure timer already exists
+ map::iterator iter = mTimers.find( trackerName );
+ if( iter != mTimers.end() )
+ {
+ iter->second->pause(true);
+ }
+
+}
+
+double PerformanceTracker::getElapsedTime( const string& trackerName )
+{
+ //make sure timer already exists
+ map::iterator iter = mTimers.find( trackerName );
+ if( iter != mTimers.end() )
+ {
+ return iter->second->getElapsedTime();
+ }
+ else
+ return 0.0;
+}
+
+void PerformanceTracker::removeTracker( const std::string& trackerName )
+{
+ //find the existing timer
+ map::iterator iter = mTimers.find( trackerName );
+ if( iter != mTimers.end() )
+ {
+ delete iter->second;
+ mTimers.erase( iter );
+ }
+
+}
+
+void PerformanceTracker::clearTracker( const std::string& trackerName )
+{
+ //find if tracker already exists
+ map::iterator iter = mTimers.find( trackerName );
+ if( iter != mTimers.end() )
+ {
+ iter->second->start();
+ }
+}
\ No newline at end of file
diff --git a/RoboCat/Src/DeanSrc/RayCaster.cpp b/RoboCat/Src/DeanSrc/RayCaster.cpp
new file mode 100644
index 00000000..108576bc
--- /dev/null
+++ b/RoboCat/Src/DeanSrc/RayCaster.cpp
@@ -0,0 +1,18 @@
+#include "RayCaster.h"
+
+std::vector RayCaster::getPoints(const Vector2D& start, const Vector2D& end, float interval)
+{
+ std::vector thePoints;
+
+ Vector2D diff = end - start;
+ Vector2D normalizedDiff = diff;
+ normalizedDiff.normalize();
+
+ int numIterations = (int)(diff.getLength() / interval)-1;
+ for (int i = 1; i < numIterations; i++)
+ {
+ Vector2D point = (normalizedDiff * interval * (float)i) + start;
+ thePoints.push_back(point);
+ }
+ return thePoints;
+}
diff --git a/RoboCat/Src/DeanSrc/Timer.cpp b/RoboCat/Src/DeanSrc/Timer.cpp
new file mode 100644
index 00000000..f74610c4
--- /dev/null
+++ b/RoboCat/Src/DeanSrc/Timer.cpp
@@ -0,0 +1,90 @@
+#include "Timer.h"
+
+Timer::Timer()
+:mElapsedTime(0.0)
+,mPaused(true)
+,mFactor(1.0)
+,mLastFactor(1.0)
+{
+ QueryPerformanceFrequency( &mTimerFrequency );
+ mStartTime.QuadPart = 0;
+ mEndTime.QuadPart = 0;
+}
+
+Timer::~Timer()
+{
+}
+
+void Timer::start()
+{
+ QueryPerformanceCounter( &mStartTime );
+
+ //reset end time as well
+ mEndTime.QuadPart = 0;
+
+ mElapsedTime = 0.0;
+
+ pause( false );//unpause
+}
+
+void Timer::stop()
+{
+ QueryPerformanceCounter( &mEndTime );
+ mElapsedTime = calcDifferenceInMS( mStartTime, mEndTime );
+}
+
+void Timer::pause( bool shouldPause )
+{
+ if( shouldPause && !mPaused )//want to pause and we are not currently paused
+ {
+ mPaused = true;
+ QueryPerformanceCounter( &mEndTime );
+ mElapsedTime += calcDifferenceInMS( mStartTime, mEndTime );
+ }
+ else if( !shouldPause && mPaused )//want to unpause and we are paused
+ {
+ mPaused = false;
+ QueryPerformanceCounter( &mStartTime );
+ }
+}
+
+double Timer::getElapsedTime() const
+{
+ //if we have an end time then the timer isn't running and we can just return the elapsed time
+ if( mEndTime.QuadPart != 0 )
+ {
+ return mElapsedTime;
+ }
+ else //otherwise we need to get the current time, do the math and return that
+ {
+ LARGE_INTEGER currentTime;
+ QueryPerformanceCounter( ¤tTime );
+ return calcDifferenceInMS( mStartTime, currentTime );
+ }
+}
+
+void Timer::sleepUntilElapsed( double ms )
+{
+ LARGE_INTEGER currentTime, lastTime;
+ QueryPerformanceCounter( ¤tTime );
+ double timeToSleep = ms - calcDifferenceInMS( mStartTime, currentTime );
+
+ while( timeToSleep > 0.0 )
+ {
+ lastTime = currentTime;
+ QueryPerformanceCounter( ¤tTime );
+ double timeElapsed = calcDifferenceInMS( lastTime, currentTime );
+ timeToSleep -= timeElapsed;
+ if( timeToSleep > 10.0 )//if we are going to be in this loop for a long time -
+ { //Sleep to relinquish back to Windows
+ Sleep(10);
+ }
+ }
+}
+
+double Timer::calcDifferenceInMS( LARGE_INTEGER from, LARGE_INTEGER to ) const
+{
+ double difference = (double)(to.QuadPart - from.QuadPart) / (double)mTimerFrequency.QuadPart;
+ difference *= mFactor;
+ return difference * 1000;
+}
diff --git a/RoboCat/Src/DeanSrc/Trackable.cpp b/RoboCat/Src/DeanSrc/Trackable.cpp
new file mode 100644
index 00000000..d1bb7e9b
--- /dev/null
+++ b/RoboCat/Src/DeanSrc/Trackable.cpp
@@ -0,0 +1,28 @@
+#include "Trackable.h"
+#include "MemoryTracker.h"
+
+void* Trackable::operator new( std::size_t size )
+{
+ void* ptr = malloc(size);
+ MemoryTracker::getInstance()->addAllocation( ptr, size );
+ return ptr;
+}
+
+void Trackable::operator delete( void *ptr )
+{
+ MemoryTracker::getInstance()->removeAllocation(ptr);
+ free(ptr);
+}
+
+void* Trackable::operator new[]( std::size_t size )
+{
+ void* ptr = malloc(size);
+ MemoryTracker::getInstance()->addAllocation( ptr, size );
+ return ptr;
+}
+
+void Trackable::operator delete[]( void *ptr )
+{
+ MemoryTracker::getInstance()->removeAllocation(ptr);
+ free(ptr);
+}
\ No newline at end of file
diff --git a/RoboCat/Src/DeanSrc/Vector2D.cpp b/RoboCat/Src/DeanSrc/Vector2D.cpp
new file mode 100644
index 00000000..22cc13fa
--- /dev/null
+++ b/RoboCat/Src/DeanSrc/Vector2D.cpp
@@ -0,0 +1,201 @@
+#include "Vector2D.h"
+#include
+#include
+#include
+#include "DeanMath.h"
+
+Vector2D::Vector2D(float x, float y)
+ :mX(x)
+ , mY(y)
+{
+}
+
+Vector2D::Vector2D(const Vector2D& rhs)
+ : mX(rhs.mX)
+ , mY(rhs.mY)
+{
+}
+
+Vector2D::Vector2D(int x, int y)
+ : mX((float)x)
+ , mY((float)y)
+{
+}
+
+Vector2D::~Vector2D()
+{
+}
+
+Vector2D& Vector2D::operator += (const Vector2D& rhs)
+{
+ mX += rhs.mX;
+ mY += rhs.mY;
+ return *this;
+}
+
+Vector2D& Vector2D::operator -= (const Vector2D& rhs)
+{
+ mX -= rhs.mX;
+ mY -= rhs.mY;
+ return *this;
+}
+
+Vector2D& Vector2D::operator = (const Vector2D& rhs)
+{
+ mX = rhs.mX;
+ mY = rhs.mY;
+ return *this;
+}
+
+Vector2D& Vector2D::operator *= (float mult)
+{
+ mX *= mult;
+ mY *= mult;
+ return *this;
+}
+
+Vector2D& Vector2D::operator /= (float div)
+{
+ mX /= div;
+ mY /= div;
+ return *this;
+}
+
+Vector2D Vector2D::operator+(const Vector2D& other) const
+{
+ Vector2D result = *this;
+ result += other;
+ return result;
+}
+
+Vector2D Vector2D::operator-(const Vector2D& other) const
+{
+ Vector2D result = *this;
+ result -= other;
+ return result;
+}
+
+Vector2D Vector2D::operator*(float mult) const
+{
+ Vector2D result = *this;
+ result.mX *= mult;
+ result.mY *= mult;
+
+ return result;
+}
+
+Vector2D Vector2D::operator/(float div) const
+{
+ Vector2D result = *this;
+ result.mX /= div;
+ result.mY /= div;
+
+ return result;
+}
+
+bool Vector2D::operator==(const Vector2D& rhs) const
+{
+ if ((getX() == rhs.getX()) && (getY() == rhs.getY()))
+ return true;
+ else return false;
+}
+
+bool Vector2D::operator!=(const Vector2D& rhs) const
+{
+ if ((getX() == rhs.getX()) && (getY() == rhs.getY()))
+ return false;
+ else return true;
+}
+
+bool Vector2D::hasNonZeroLength() const
+{
+ if (mX != 0.0f || mY != 0.0f)
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+float Vector2D::getLength() const
+{
+ float lengthSquared = getLengthSquared();
+ return sqrt(lengthSquared);
+}
+
+float Vector2D::getLengthSquared() const
+{
+ float lengthSquared = (mX * mX) + (mY * mY);
+ return lengthSquared;
+}
+
+void Vector2D::normalize()
+{
+ float invLength = 1.0f / (getLength() + FLT_MIN);
+ mX *= invLength;
+ mY *= invLength;
+}
+
+Vector2D Vector2D::getNormalizedVector() const
+{
+ Vector2D newVector(*this);
+ newVector.normalize();
+ return newVector;
+}
+
+float Vector2D::dotProduct(const Vector2D& other) const
+{
+ return mX * other.mX + mY * other.mY;
+}
+
+Vector2D Vector2D::getRightVector() const
+{
+ return Vector2D(-mY, mX);
+}
+
+double Vector2D::calcFacing() const
+{
+ return atan2(mY, mX);
+ //return atan2(mX, -mY);
+}
+
+Vector2D Vector2D::getVectorInDirection(double direction)
+{
+ Vector2D temp((float)cos(direction), (float)sin(direction));
+ //std::cout << temp << " " << direction << std::endl;
+ return temp;
+ //return Vector2D((float)cos(direction), (float)sin(direction));
+}
+
+Vector2D Vector2D::getVectorInOppositeDirection(const Vector2D& vec)
+{
+ return Vector2D(-vec.getX(), -vec.getY());
+}
+
+Vector2D Vector2D::getVectorInOppositeDirection(double direction)
+{
+ return getVectorInOppositeDirection(getVectorInDirection(direction));
+}
+
+float Vector2D::getDistanceBetween(const Vector2D& vec1, const Vector2D& vec2)
+{
+ Vector2D temp(vec1 - vec2);
+ return temp.getLength();
+}
+
+float Vector2D::getSquaredDistanceBetween(const Vector2D& vec1, const Vector2D& vec2)
+{
+ Vector2D temp(vec1 - vec2);
+ return temp.getLengthSquared();
+}
+
+std::ostream& operator<<(std::ostream& out, const Vector2D& vector)
+{
+ out << "(" << vector.getX() << "," << vector.getY() << ")";
+ return out;
+}
+
+
+
diff --git a/RoboCat/Src/GraphicsSrc/Animation.cpp b/RoboCat/Src/GraphicsSrc/Animation.cpp
new file mode 100644
index 00000000..c4fc7a5e
--- /dev/null
+++ b/RoboCat/Src/GraphicsSrc/Animation.cpp
@@ -0,0 +1,88 @@
+#include "Animation.h"
+#include
+#include
+
+
+Animation::Animation(float timePerFrame, bool isPaused /*= false*/, bool looping /*= true*/)
+ :mCurrentSprite(0)
+ ,mLooping(looping)
+ ,mIsPaused(isPaused)
+ ,mTimePerFrame(timePerFrame)
+ ,mTimeUntilNextFrame(timePerFrame)
+{
+}
+
+Animation::Animation(const GraphicsBuffer& buffer, int spriteW, int spriteH, int numAcross, int numDown, float timePerFrame, bool isPaused /*= false*/, bool looping /*= true*/)
+ :Animation(timePerFrame, isPaused, looping)
+{
+ for (int y = 0; y < numDown; y++)
+ {
+ for (int x = 0; x < numAcross; x++)
+ {
+ Sprite sprite(&buffer, Vector2D((int)(x*spriteW), (int)(y*spriteH)), spriteW, spriteH);
+ mSprites.push_back(sprite);
+ }
+ }
+}
+
+Animation::Animation()
+{
+
+}
+
+void Animation::addSprite(const Sprite& theSprite)
+{
+ mSprites.push_back(theSprite);
+}
+
+void Animation::setTimePerFrame(float newTimePerFrame)
+{
+ mTimePerFrame = newTimePerFrame;
+ if (mTimeUntilNextFrame > mTimePerFrame)
+ {
+ mTimeUntilNextFrame = mTimePerFrame;
+ }
+ //std::cout << mTimePerFrame << std::endl;
+}
+
+//in order to be synched animations must have the same number of frames
+void Animation::synch(const Animation& otherAnimation)
+{
+ if (mSprites.size() == otherAnimation.mSprites.size())
+ {
+ mCurrentSprite = otherAnimation.mCurrentSprite;
+ mTimePerFrame = otherAnimation.mTimePerFrame;
+ mTimeUntilNextFrame = otherAnimation.mTimeUntilNextFrame;
+ mIsPaused = otherAnimation.mIsPaused;
+ }
+}
+
+const Sprite& Animation::getCurrentSprite() const
+{
+ assert(mCurrentSprite < (int)mSprites.size());
+ return mSprites[mCurrentSprite];
+}
+
+void Animation::update(double dt)
+{
+ if (mIsPaused)//paused - nothing to do
+ {
+ return;//do nothing
+ }
+
+ //non-looping animation at the end?
+ if (!mLooping && mCurrentSprite == mSprites.size() - 1)
+ {
+ return;//do nothing
+ }
+
+ mTimeUntilNextFrame -= (float)dt;
+
+ if (mTimeUntilNextFrame <= 0.0f)
+ {
+ mCurrentSprite++;
+ mCurrentSprite %= mSprites.size();//makes it loop
+ mTimeUntilNextFrame = mTimePerFrame;
+ }
+}
+
diff --git a/RoboCat/Src/GraphicsSrc/Color.cpp b/RoboCat/Src/GraphicsSrc/Color.cpp
new file mode 100644
index 00000000..875ff81f
--- /dev/null
+++ b/RoboCat/Src/GraphicsSrc/Color.cpp
@@ -0,0 +1,19 @@
+#include "Color.h"
+
+Color::Color(int r, int g, int b, int a /*= 255*/)
+ :mR(r)
+ ,mG(g)
+ ,mB(b)
+ ,mA(a)
+{
+}
+
+Color::Color(float r, float g, float b, float a /*= 1.0f*/)
+ :mR(r*255)
+ ,mG(g*255)
+ ,mB(b*255)
+ ,mA(a*255)
+{
+}
+
+
diff --git a/RoboCat/Src/GraphicsSrc/Font.cpp b/RoboCat/Src/GraphicsSrc/Font.cpp
new file mode 100644
index 00000000..3e0fca93
--- /dev/null
+++ b/RoboCat/Src/GraphicsSrc/Font.cpp
@@ -0,0 +1,17 @@
+#include "Font.h"
+#include "Font.h"
+#include
+
+using namespace std;
+
+Font::Font(const std::string& filename, int size)
+ :mSize(size)
+{
+ mpFont = al_load_font(filename.c_str(), size, 0);
+ assert(mpFont);
+}
+
+Font::~Font()
+{
+ al_destroy_font(mpFont);
+}
diff --git a/RoboCat/Src/GraphicsSrc/GraphicsBuffer.cpp b/RoboCat/Src/GraphicsSrc/GraphicsBuffer.cpp
new file mode 100644
index 00000000..8a27d332
--- /dev/null
+++ b/RoboCat/Src/GraphicsSrc/GraphicsBuffer.cpp
@@ -0,0 +1,40 @@
+#include "GraphicsBuffer.h"
+#include "GraphicsSystem.h"
+#include "Color.h"
+
+GraphicsBuffer::GraphicsBuffer(ALLEGRO_DISPLAY* pDisplay)
+ :mOwnsBitmap(false)
+{
+ mpBitmap = al_get_backbuffer(pDisplay);
+}
+
+GraphicsBuffer::GraphicsBuffer(const std::string& filename)
+ :mOwnsBitmap(true)
+{
+ mpBitmap = al_load_bitmap(filename.c_str());
+ assert(mpBitmap != NULL);
+}
+
+GraphicsBuffer::GraphicsBuffer(unsigned int width, unsigned int height, Color color)
+ :mOwnsBitmap(true)
+{
+ mpBitmap = al_create_bitmap(width, height);
+ GraphicsSystem::setBufferToColor(*this,color);
+ assert(mpBitmap != NULL);
+}
+
+GraphicsBuffer::~GraphicsBuffer()
+{
+ if (mOwnsBitmap)
+ {
+ al_destroy_bitmap(mpBitmap);
+ }
+}
+
+GraphicsBuffer * GraphicsBuffer::clone() const
+{
+ GraphicsBuffer* pNewBuffer = new GraphicsBuffer(getWidth(), getHeight());
+ GraphicsSystem::draw(*pNewBuffer, ZERO_VECTOR2D, *this);
+ return pNewBuffer;
+}
+
diff --git a/RoboCat/Src/GraphicsSrc/GraphicsLib.cpp b/RoboCat/Src/GraphicsSrc/GraphicsLib.cpp
new file mode 100644
index 00000000..ffcafa4c
--- /dev/null
+++ b/RoboCat/Src/GraphicsSrc/GraphicsLib.cpp
@@ -0,0 +1,157 @@
+#include "GraphicsLib.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+using namespace std;
+
+int initAllegro()
+{
+ PerformanceTracker* pPerformanceTracker = new PerformanceTracker;
+
+ const string INIT_TRACKER_NAME = "init";
+ const string DRAW_TRACKER_NAME = "draw";
+ const string WAIT_TRACKER_NAME = "wait";
+
+
+ pPerformanceTracker->startTracking(INIT_TRACKER_NAME);
+
+ if (!al_init())
+ {
+ cout << "error initting Allegro\n";
+ return 1;
+ }
+ if (!al_init_image_addon())
+ {
+ cout << "error - Image Add-on not initted\n";
+ return 1;
+ }
+ if (!al_init_font_addon())
+ {
+ cout << "error - Font Add-on not initted\n";
+ return 1;
+ }
+ if (!al_init_ttf_addon())
+ {
+ cout << "error - TTF Add-on not initted\n";
+ return 1;
+ }
+ if (!al_init_primitives_addon())
+ {
+ cout << "error - primitives Add-on not initted\n";
+ return 1;
+ }
+ if (!al_install_audio())
+ {
+ cout << "error - Audio Add-on not initted\n";
+ //return 1;
+ }
+ if (!al_init_acodec_addon())
+ {
+ cout << "error - Audio Codec Add-on not initted\n";
+ //return 1;
+ }
+ if (!al_reserve_samples(1))
+ {
+ cout << "error - samples not reserved\n";
+ //return 1;
+ }
+
+ const int DISP_WIDTH = 800;
+ const int DISP_HEIGHT = 600;
+
+ const string ASSET_PATH = "..\\..\\shared\\assets\\";
+ const string BACKGROUND_FILENAME = "axamer-lizum.png";
+ const string QUIMBY_FILENAME = "mayor_quimby.png";
+ const string FONT_FILENAME = "cour.ttf";
+ const int FONT_SIZE = 24;
+ const string SAMPLE_FILENAME = "clapping.wav";
+ const double SLEEP_TIME = 5.0;
+
+ ALLEGRO_DISPLAY* display = al_create_display(DISP_WIDTH, DISP_HEIGHT);
+ assert(display);
+
+ ALLEGRO_BITMAP* bitmap = al_load_bitmap((ASSET_PATH + BACKGROUND_FILENAME).c_str());
+ assert(bitmap);
+ ALLEGRO_BITMAP* quimby = al_load_bitmap((ASSET_PATH + QUIMBY_FILENAME).c_str());
+ assert(quimby);
+
+ ALLEGRO_FONT* font = al_create_builtin_font();
+ assert(font);
+
+ ALLEGRO_FONT *cour_font = al_load_ttf_font((ASSET_PATH + FONT_FILENAME).c_str(), FONT_SIZE, 0);
+ assert(cour_font);
+
+ const ALLEGRO_COLOR WHITE = al_map_rgb(255, 255, 255);
+ const ALLEGRO_COLOR BLACK = al_map_rgb(0, 0, 0);
+ const ALLEGRO_COLOR BLACK_TRANSPARENT = al_map_rgba(0, 0, 0, 200);
+ const ALLEGRO_COLOR PURPLE = al_map_rgb(128, 64, 212);
+
+ ALLEGRO_SAMPLE* sample = al_load_sample((ASSET_PATH + SAMPLE_FILENAME).c_str());
+ assert(sample);
+
+ al_play_sample(sample, 1.0f, ALLEGRO_AUDIO_PAN_NONE, 1.0f, ALLEGRO_PLAYMODE_LOOP, nullptr);
+
+ pPerformanceTracker->stopTracking(INIT_TRACKER_NAME);
+
+ pPerformanceTracker->startTracking(DRAW_TRACKER_NAME);
+
+ al_clear_to_color(WHITE);
+
+ al_draw_bitmap(bitmap, 0, 0, 0);
+
+ const int CIRCLE_RADIUS = 150;
+ const int LOC1_X = 400;
+ const int LOC1_Y = 300;
+
+ al_draw_filled_circle(LOC1_X, LOC1_Y, CIRCLE_RADIUS, BLACK);
+ al_draw_text(cour_font, WHITE, LOC1_X, LOC1_Y, ALLEGRO_ALIGN_CENTER, "Welcome to Allegro!");
+
+ const int LOC2_X = 200;
+ const int LOC2_Y = 500;
+ al_draw_filled_circle(LOC2_X, LOC2_Y, CIRCLE_RADIUS, BLACK_TRANSPARENT);
+ al_draw_text(cour_font, PURPLE, LOC2_X, LOC2_Y, ALLEGRO_ALIGN_CENTER, "Welcome to Allegro!");
+
+ const int LOC3_X = 500;
+ const int LOC3_Y = 400;
+ int sourceWidth = al_get_bitmap_width(quimby);
+ int sourceHeight = al_get_bitmap_height(quimby);
+ const float SCALE_FACTOR = 0.75f;
+ al_draw_scaled_bitmap(quimby, 0, 0, sourceWidth, sourceHeight, LOC3_X, LOC3_Y, sourceWidth*SCALE_FACTOR, sourceHeight*SCALE_FACTOR, 0);
+
+ al_flip_display();
+
+ pPerformanceTracker->stopTracking(DRAW_TRACKER_NAME);
+
+ pPerformanceTracker->startTracking(WAIT_TRACKER_NAME);
+
+ al_rest(SLEEP_TIME);
+
+ pPerformanceTracker->stopTracking(WAIT_TRACKER_NAME);
+
+ al_destroy_sample(sample);
+ al_destroy_font(font);
+ al_destroy_display(display);
+
+ //report elapsed times
+ cout << endl << "Time to Init:" << pPerformanceTracker->getElapsedTime(INIT_TRACKER_NAME) << " ms" << endl;
+ cout << endl << "Time to Draw:" << pPerformanceTracker->getElapsedTime(DRAW_TRACKER_NAME) << " ms" << endl;
+ cout << endl << "Time spent waiting:" << pPerformanceTracker->getElapsedTime(WAIT_TRACKER_NAME) << " ms" << endl;
+
+ MemoryTracker::getInstance()->reportAllocations(cout);
+
+ return 0;
+}
\ No newline at end of file
diff --git a/RoboCat/Src/GraphicsSrc/GraphicsSystem.cpp b/RoboCat/Src/GraphicsSrc/GraphicsSystem.cpp
new file mode 100644
index 00000000..23c10cda
--- /dev/null
+++ b/RoboCat/Src/GraphicsSrc/GraphicsSystem.cpp
@@ -0,0 +1,232 @@
+#include "GraphicsSystem.h"
+#include "GraphicsBuffer.h"
+#include "Sprite.h"
+#include "Color.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+using namespace std;
+
+
+GraphicsSystem::GraphicsSystem()
+ :mDisplay(NULL)
+ ,mIsInitted(false)
+{
+}
+
+GraphicsSystem::~GraphicsSystem()
+{
+ cleanup();
+}
+
+bool GraphicsSystem::init(unsigned int width, unsigned int height)
+{
+ //possible enhancement - if width and height is different than current initted display - cleanup and re-init with new size
+ if (!mIsInitted)
+ {
+ if (!initAddOns())
+ {
+ cout << "error initting Allegro Add-Ons\n";
+ return false;
+ }
+ mDisplay = al_create_display(width, height);
+ mWidth = al_get_display_width(mDisplay);
+ mHeight = al_get_display_height(mDisplay);
+ mpBackBuffer = new GraphicsBuffer(mDisplay);
+ mIsInitted = true;
+ }
+ return true;
+}
+
+void GraphicsSystem::cleanup()
+{
+ if (mIsInitted)
+ {
+ delete mpBackBuffer;
+ mpBackBuffer = NULL;
+
+ al_uninstall_audio();
+ al_shutdown_primitives_addon();
+ al_shutdown_ttf_addon();
+ al_shutdown_font_addon();
+ al_shutdown_image_addon();
+ al_destroy_display(mDisplay);
+ mIsInitted = false;
+ mDisplay = NULL;
+ }
+}
+
+bool GraphicsSystem::initAddOns()
+{
+ if (!al_init_image_addon())
+ {
+ cout << "error - Image Add-on not initted\n";
+ return false;
+ }
+ if (!al_init_font_addon())
+ {
+ cout << "error - Font Add-on not initted\n";
+ return false;
+ }
+ if (!al_init_ttf_addon())
+ {
+ cout << "error - TTF Add-on not initted\n";
+ return false;
+ }
+ if (!al_init_primitives_addon())
+ {
+ cout << "error - primitives Add-on not initted\n";
+ return false;
+ }
+ if (!al_install_keyboard())
+ {
+ cout << "error - keyboard not installed\n";
+ return false;
+ }
+ if (!al_install_mouse())
+ {
+ cout << "error - mouse not installed\n";
+ return false;
+ }
+
+ if (!al_install_audio())
+ {
+ cout << "Warning!!! - Audio Add-on not initted\n";
+ }
+ else if (!al_init_acodec_addon())
+ {
+ cout << "Warning!!! - Audio Codec Add-on not initted\n";
+ }
+ else if (!al_reserve_samples(1))
+ {
+ cout << "Warning!!! - samples not reserved\n";
+ }
+
+
+ return true;
+}
+
+void GraphicsSystem::flip()
+{
+ assert(mIsInitted);
+ al_flip_display();
+}
+
+void GraphicsSystem::draw(const Vector2D& destLoc, const GraphicsBuffer& src, double scale /*= 1.0*/)
+{
+ ALLEGRO_BITMAP* pTarget = al_get_target_bitmap();
+ assert(pTarget != src.getBitmap());
+
+ if (pTarget != src.getBitmap())
+ {
+ int srcW = src.getWidth();
+ int srcH = src.getHeight();
+
+ al_draw_scaled_bitmap(src.getBitmap(), 0.0f, 0.0f, srcW, srcH, destLoc.getX(), destLoc.getY(), srcW*scale, srcH*scale, 0);
+ }
+}
+
+void GraphicsSystem::draw(GraphicsBuffer& dest, const Vector2D& loc, const GraphicsBuffer& src, double scale /*= 1.0*/)
+{
+ assert(dest.getBitmap() != src.getBitmap());
+ if (dest.getBitmap() != src.getBitmap())
+ {
+ ALLEGRO_BITMAP* pOldTarget = al_get_target_bitmap();
+ al_set_target_bitmap(dest.getBitmap());
+ draw(loc, src, scale);
+ al_set_target_bitmap(pOldTarget);
+ }
+}
+
+void GraphicsSystem::draw(const Vector2D& destLoc, const Sprite& sprite, double scale /*= 1.0*/)
+{
+ ALLEGRO_BITMAP* pTarget = al_get_target_bitmap();
+ const GraphicsBuffer* pSrc = sprite.getBuffer();
+ assert(pTarget != sprite.getBuffer()->getBitmap());
+
+ if (pTarget != sprite.getBuffer()->getBitmap())
+ {
+ int srcW = sprite.getWidth();
+ int srcH = sprite.getHeight();
+
+ al_draw_scaled_bitmap(pSrc->getBitmap(), sprite.getSourceLoc().getX(), sprite.getSourceLoc().getY(), srcW, srcH, destLoc.getX(), destLoc.getY(), srcW*scale, srcH*scale, 0);
+ }
+
+}
+
+void GraphicsSystem::draw(GraphicsBuffer& dest, const Vector2D& destLoc, const Sprite& sprite, double scale /*= 1.0*/)
+{
+ ALLEGRO_BITMAP* pOldTarget = al_get_target_bitmap();
+ al_set_target_bitmap(dest.getBitmap());
+ draw(destLoc, sprite, scale);
+ al_set_target_bitmap(pOldTarget);
+}
+
+void GraphicsSystem::writeText(const Vector2D& destLoc, const Font& font, const Color& color, const std::string& text, Font::Alignment align /*= Font::LEFT*/)
+{
+ al_draw_text(
+ font.getFont(),
+ getAllegroColorFromColor(color),
+ destLoc.getX(),
+ destLoc.getY(),
+ getAllegroFontAlignFlag(align),
+ text.c_str());
+}
+
+void GraphicsSystem::writeText(GraphicsBuffer& dest, const Vector2D& destLoc, const Font& font, const Color& color, const std::string& text, Font::Alignment align /*= Font::LEFT*/)
+{
+ ALLEGRO_BITMAP* pOldTarget = al_get_target_bitmap();
+ al_set_target_bitmap(dest.getBitmap());
+ writeText(destLoc, font, color, text, align);
+ al_set_target_bitmap(pOldTarget);
+
+}
+
+void GraphicsSystem::setBufferToColor(GraphicsBuffer& buffer, const Color& color)
+{
+ ALLEGRO_BITMAP* pOldTarget = al_get_target_bitmap();
+ al_set_target_bitmap(buffer.getBitmap());
+ al_clear_to_color(getAllegroColorFromColor(color));
+ al_set_target_bitmap(pOldTarget);
+}
+
+void GraphicsSystem::saveBufferToFile(const GraphicsBuffer& buffer, const std::string& filename)
+{
+ bool success = al_save_bitmap(filename.c_str(), buffer.getBitmap());
+ assert(success);
+}
+
+ALLEGRO_COLOR GraphicsSystem::getAllegroColorFromColor(const Color& color)
+{
+ return al_map_rgba(color.mR, color.mG, color.mB, color.mA);
+}
+
+int GraphicsSystem::getAllegroFontAlignFlag(Font::Alignment align)
+{
+ int flag;
+
+ switch (align)
+ {
+ case Font::LEFT:
+ flag = ALLEGRO_ALIGN_LEFT;
+ break;
+ case Font::CENTER:
+ flag = ALLEGRO_ALIGN_CENTER;
+ break;
+ case Font::RIGHT:
+ flag = ALLEGRO_ALIGN_RIGHT;
+ break;
+ default:
+ flag = ALLEGRO_ALIGN_LEFT;
+ }
+
+ return flag;
+}
diff --git a/RoboCat/Src/GraphicsSrc/Sprite.cpp b/RoboCat/Src/GraphicsSrc/Sprite.cpp
new file mode 100644
index 00000000..5fa6e23d
--- /dev/null
+++ b/RoboCat/Src/GraphicsSrc/Sprite.cpp
@@ -0,0 +1,10 @@
+#include "Sprite.h"
+
+Sprite::Sprite(const GraphicsBuffer* pBuffer, const Vector2D& srcLoc, int width, int height)
+ :mpBuffer(pBuffer)
+ ,mSrcLoc(srcLoc)
+ ,mWidth(width)
+ ,mHeight(height)
+{
+}
+
diff --git a/RoboCat/Src/GraphicsSrc/System.cpp b/RoboCat/Src/GraphicsSrc/System.cpp
new file mode 100644
index 00000000..34b306ae
--- /dev/null
+++ b/RoboCat/Src/GraphicsSrc/System.cpp
@@ -0,0 +1,115 @@
+#include "System.h"
+#include "GraphicsSystem.h"
+
+#include
+
+using namespace std;
+
+System::System()
+{
+ mpGraphicsSystem = new GraphicsSystem;
+}
+
+System::~System()
+{
+ cleanup();
+ delete mpGraphicsSystem;
+}
+
+bool System::init(unsigned int width, unsigned int height)
+{
+ if (!mIsInitted)
+ {
+ if (!al_init())
+ {
+ cout << "error initting Allegro\n";
+ return false;
+ }
+ else
+ {
+ bool ret = mpGraphicsSystem->init(width, height);
+ if (!ret)
+ {
+ cout << "error initting GraphicsSystem\n";
+ return false;
+ }
+ }
+ mIsInitted = true;
+ }
+ return true;
+}
+
+void System::cleanup()
+{
+ if (mIsInitted)
+ {
+ mpGraphicsSystem->cleanup();
+ mIsInitted = false;
+ }
+}
+
+Vector2D System::getCurrentMousePos()
+{
+ ALLEGRO_MOUSE_STATE state;
+
+ al_get_mouse_state(&state);
+
+ return Vector2D(state.x, state.y);
+}
+
+bool System::isMouseButtonPressed(System::MouseButton button)
+{
+ ALLEGRO_MOUSE_STATE state;
+
+ al_get_mouse_state(&state);
+
+ if (button == LEFT)
+ {
+ if (state.buttons & 1)
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ else if (button == RIGHT)
+ {
+ if (state.buttons & 2)
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ else if (button == CENTER)
+ {
+ if (state.buttons & 4)
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ return false;
+}
+
+bool System::isKeyPressed(Key theKey)
+{
+ ALLEGRO_KEYBOARD_STATE state;
+ al_get_keyboard_state(&state);
+
+ if (al_key_down(&state, theKey))
+ {
+ return true;
+ }
+
+ return false;
+}
+
diff --git a/RoboCat/Src/Main.cpp b/RoboCat/Src/Main.cpp
deleted file mode 100644
index 3b0ac9de..00000000
--- a/RoboCat/Src/Main.cpp
+++ /dev/null
@@ -1,25 +0,0 @@
-
-#include "RoboCatPCH.h"
-
-#if _WIN32
-
-
-int main(int argc, const char** argv)
-{
- UNREFERENCED_PARAMETER(argc);
- UNREFERENCED_PARAMETER(argv);
-#else
-const char** __argv;
-int __argc;
-int main(int argc, const char** argv)
-{
- __argc = argc;
- __argv = argv;
-#endif
-
- SocketUtil::StaticInit();
-
- SocketUtil::CleanUp();
-
- return 0;
-}
diff --git a/RoboCat/Src/RoboMath.cpp b/RoboCat/Src/RoboMath.cpp
new file mode 100644
index 00000000..6cbaaa9a
--- /dev/null
+++ b/RoboCat/Src/RoboMath.cpp
@@ -0,0 +1,28 @@
+
+#include "RoboCatPCH.h"
+
+#include
+
+const Vector3 Vector3::Zero(0.0f, 0.0f, 0.0f);
+const Vector3 Vector3::UnitX(1.0f, 0.0f, 0.0f);
+const Vector3 Vector3::UnitY(0.0f, 1.0f, 0.0f);
+const Vector3 Vector3::UnitZ(0.0f, 0.0f, 1.0f);
+const Vector3 Vector3::NegUnitX(-1.0f, 0.0f, 0.0f);
+const Vector3 Vector3::NegUnitY(0.0f, -1.0f, 0.0f);
+const Vector3 Vector3::NegUnitZ(0.0f, 0.0f, -1.0f);
+
+float RoboMath::GetRandomFloatNonGame()
+{
+ static std::random_device rd;
+ static std::mt19937 gen(rd());
+ static std::uniform_real_distribution< float > dis(0.f, 1.f);
+ return dis(gen);
+}
+
+float RoboMath::GetRandomFloat(float min, float max)
+{
+ static std::random_device rd;
+ static std::mt19937 gen(rd());
+ static std::uniform_real_distribution< float > dis(min, max);
+ return dis(gen);
+}
\ No newline at end of file
diff --git a/RoboCat/Src/SocketAddress.cpp b/RoboCat/Src/SocketAddress.cpp
index c387c9e0..3a570c6f 100644
--- a/RoboCat/Src/SocketAddress.cpp
+++ b/RoboCat/Src/SocketAddress.cpp
@@ -1,18 +1,32 @@
#include "RoboCatPCH.h"
+//TODO: check these, I have no idea if this is the best way to do it...
+//(definitely doesn't work from cross-platform standpoint)
+void SocketAddress::Read(InputMemoryBitStream& inInputStream)
+{
+ //read the address and port
+ inInputStream.Read(GetIP4Ref());
+ inInputStream.Read(GetAsSockAddrIn()->sin_port);
+}
+
+void SocketAddress::Write(OutputMemoryBitStream& inOutputStream)
+{
+ //write the address and port
+ inOutputStream.Write(GetIP4Ref());
+ inOutputStream.Write(GetAsSockAddrIn()->sin_port);
+}
string SocketAddress::ToString() const
{
#if _WIN32
const sockaddr_in* s = GetAsSockAddrIn();
- char destinationBuffer[ 128 ];
- InetNtop( s->sin_family, const_cast< in_addr* >( &s->sin_addr ), destinationBuffer, sizeof( destinationBuffer ) );
- return StringUtils::Sprintf( "%s:%d",
- destinationBuffer,
- ntohs( s->sin_port ) );
+ char destinationBuffer[128];
+ InetNtop(s->sin_family, const_cast(&s->sin_addr), destinationBuffer, sizeof(destinationBuffer));
+ return StringUtils::Sprintf("%s:%d",
+ destinationBuffer,
+ ntohs(s->sin_port));
#else
//not implement on mac for now...
- return string( "not implemented on mac for now" );
+ return string("not implemented on mac for now");
#endif
-}
-
+}
\ No newline at end of file
diff --git a/RoboCat/Src/SocketMain.cpp b/RoboCat/Src/SocketMain.cpp
new file mode 100644
index 00000000..6245d9fc
--- /dev/null
+++ b/RoboCat/Src/SocketMain.cpp
@@ -0,0 +1,63 @@
+
+#include "RoboCatPCH.h"
+#include
+#if _WIN32
+
+
+int main1(int argc, const char** argv)
+{
+ UNREFERENCED_PARAMETER(argc);
+ UNREFERENCED_PARAMETER(argv);
+#else
+const char** __argv;
+int __argc;
+int main(int argc, const char** argv)
+{
+ __argc = argc;
+ __argv = argv;
+#endif
+
+ SocketUtil::StaticInit();
+
+
+ UDPSocketPtr cliSock = SocketUtil::CreateUDPSocket(SocketAddressFamily::INET);
+ UDPSocketPtr srvSock = SocketUtil::CreateUDPSocket(SocketAddressFamily::INET);
+
+
+
+ SocketAddressPtr cliAddr = SocketAddressFactory::CreateIPv4FromString("127.0.0.1:9000");
+ SocketAddressPtr srvAddr = SocketAddressFactory::CreateIPv4FromString("127.0.0.1:9001");
+ cliSock->Bind(*cliAddr);
+ srvSock->Bind(*srvAddr);
+
+
+
+
+ std::string msg("Hello server!");
+ int bytesSent = cliSock->SendTo(msg.c_str(), msg.length(), *srvAddr);
+ if (bytesSent <= 0)
+ {
+ SocketUtil::ReportError("Client SendTo");
+ }
+ std::cout << "Sent " << bytesSent << " bytes\n";
+
+ std::thread srvThread([&srvSock]() {
+ char buffer[4096];
+ SocketAddress fromAddr;
+ int nBytesReceived = srvSock->ReceiveFrom(buffer, 4096, fromAddr);
+
+ if (nBytesReceived <= 0)
+ {
+ SocketUtil::ReportError("Server receivedFrom");
+ return;
+ }
+ std::string msg(buffer, nBytesReceived);
+ std::cout << "Received message from " << fromAddr.ToString() << ": " << msg << std::endl;
+ });
+
+
+ srvThread.join();
+ SocketUtil::CleanUp();
+
+ return 0;
+}
diff --git a/RoboCat/Src/StringUtils.cpp b/RoboCat/Src/StringUtils.cpp
index 65918d12..3809567f 100644
--- a/RoboCat/Src/StringUtils.cpp
+++ b/RoboCat/Src/StringUtils.cpp
@@ -3,37 +3,37 @@
#if !_WIN32
extern const char** __argv;
extern int __argc;
-void OutputDebugString( const char* inString )
+void OutputDebugString(const char* inString)
{
- printf( "%s", inString );
+ printf("%s", inString);
}
#endif
-string StringUtils::GetCommandLineArg( int inIndex )
+string StringUtils::GetCommandLineArg(int inIndex)
{
- if( inIndex < __argc )
+ if (inIndex < __argc)
{
- return string( __argv[ inIndex ] );
+ return string(__argv[inIndex]);
}
-
+
return string();
}
-string StringUtils::Sprintf( const char* inFormat, ... )
+string StringUtils::Sprintf(const char* inFormat, ...)
{
//not thread safe...
- static char temp[ 4096 ];
-
+ static char temp[4096];
+
va_list args;
- va_start (args, inFormat );
-
+ va_start(args, inFormat);
+
#if _WIN32
- _vsnprintf_s( temp, 4096, 4096, inFormat, args );
+ _vsnprintf_s(temp, 4096, 4096, inFormat, args);
#else
vsnprintf(temp, 4096, inFormat, args);
#endif
- return string( temp );
+ return string(temp);
}
// void StringUtils::Log( const char* inFormat )
@@ -42,22 +42,19 @@ string StringUtils::Sprintf( const char* inFormat, ... )
// OutputDebugString( "\n" );
// }
-void StringUtils::Log( const char* inFormat, ... )
+void StringUtils::Log(const char* inFormat, ...)
{
//not thread safe...
- static char temp[ 4096 ];
-
+ static char temp[4096];
+
va_list args;
- va_start (args, inFormat );
-
+ va_start(args, inFormat);
+
#if _WIN32
- _vsnprintf_s( temp, 4096, 4096, inFormat, args );
+ _vsnprintf_s(temp, 4096, 4096, inFormat, args);
#else
vsnprintf(temp, 4096, inFormat, args);
#endif
- printf(temp);
- printf("\n");
- //OutputDebugString( temp );
- //OutputDebugString( "\n" );
-}
-
+ OutputDebugString(temp);
+ OutputDebugString("\n");
+}
\ No newline at end of file
diff --git a/RoboCat/Src/Timing.cpp b/RoboCat/Src/Timing.cpp
index 9a8be86c..176a30d1 100644
--- a/RoboCat/Src/Timing.cpp
+++ b/RoboCat/Src/Timing.cpp
@@ -1,9 +1,9 @@
#include "RoboCatPCH.h"
-
+float kDesiredFrameTime = 0.03333333f;
#if !_WIN32
- #include
- using namespace std::chrono;
+#include
+using namespace std::chrono;
#endif
Timing Timing::sInstance;
@@ -21,10 +21,10 @@ Timing::Timing()
{
#if _WIN32
LARGE_INTEGER perfFreq;
- QueryPerformanceFrequency( &perfFreq );
+ QueryPerformanceFrequency(&perfFreq);
mPerfCountDuration = 1.0 / perfFreq.QuadPart;
- QueryPerformanceCounter( &sStartTime );
+ QueryPerformanceCounter(&sStartTime);
mLastFrameStartTime = GetTime();
#else
@@ -37,10 +37,23 @@ void Timing::Update()
double currentTime = GetTime();
- mDeltaTime = ( float ) ( currentTime - mLastFrameStartTime );
-
+ mDeltaTime = (float)(currentTime - mLastFrameStartTime);
+
+ //frame lock at 30fps
+ while (mDeltaTime < kDesiredFrameTime)
+ {
+ currentTime = GetTime();
+
+ mDeltaTime = (float)(currentTime - mLastFrameStartTime);
+ }
+
+ //set the delta time to the desired frame time, to try to account
+ //for potential slight fluctuations that may occur when exiting the loop
+ //this also will handle the frame time not going crazy if spammed with events
+ mDeltaTime = kDesiredFrameTime;
+
mLastFrameStartTime = currentTime;
- mFrameStartTimef = static_cast< float > ( mLastFrameStartTime );
+ mFrameStartTimef = static_cast (mLastFrameStartTime);
}
@@ -48,15 +61,15 @@ double Timing::GetTime() const
{
#if _WIN32
LARGE_INTEGER curTime, timeSinceStart;
- QueryPerformanceCounter( &curTime );
+ QueryPerformanceCounter(&curTime);
timeSinceStart.QuadPart = curTime.QuadPart - sStartTime.QuadPart;
return timeSinceStart.QuadPart * mPerfCountDuration;
#else
auto now = high_resolution_clock::now();
- auto ms = duration_cast< milliseconds >( now - sStartTime ).count();
+ auto ms = duration_cast(now - sStartTime).count();
//a little uncool to then convert into a double just to go back, but oh well.
- return static_cast< double >( ms ) / 1000;
+ return static_cast(ms) / 1000;
#endif
}
\ No newline at end of file
diff --git a/SocketDemo.sln b/SocketDemo.sln
index d4b486ba..932ffda6 100644
--- a/SocketDemo.sln
+++ b/SocketDemo.sln
@@ -1,9 +1,9 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 2013
-VisualStudioVersion = 12.0.31101.0
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.32126.315
MinimumVisualStudioVersion = 10.0.40219.1
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Chapter3", "RoboCat\Chapter3.vcxproj", "{B3B75176-8D81-4E7B-A5D0-C2E5423844D3}"
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SocketDemo", "RoboCat\Chapter3.vcxproj", "{B3B75176-8D81-4E7B-A5D0-C2E5423844D3}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -31,4 +31,7 @@ Global
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {D9E435D9-D4D6-4F86-89F2-1326F358A3B8}
+ EndGlobalSection
EndGlobal
diff --git a/assets/Mayor_Quimby.png b/assets/Mayor_Quimby.png
new file mode 100644
index 00000000..dc96c61e
Binary files /dev/null and b/assets/Mayor_Quimby.png differ
diff --git a/assets/Woods.png b/assets/Woods.png
new file mode 100644
index 00000000..8cf6c786
Binary files /dev/null and b/assets/Woods.png differ
diff --git a/assets/axamer-lizum.png b/assets/axamer-lizum.png
new file mode 100644
index 00000000..47a000bb
Binary files /dev/null and b/assets/axamer-lizum.png differ
diff --git a/assets/clapping.wav b/assets/clapping.wav
new file mode 100644
index 00000000..84c2031f
Binary files /dev/null and b/assets/clapping.wav differ
diff --git a/assets/cour.ttf b/assets/cour.ttf
new file mode 100644
index 00000000..2c99e08c
Binary files /dev/null and b/assets/cour.ttf differ
diff --git a/assets/dean_sprites.png b/assets/dean_sprites.png
new file mode 100644
index 00000000..45850b65
Binary files /dev/null and b/assets/dean_sprites.png differ
diff --git a/assets/imp.png b/assets/imp.png
new file mode 100644
index 00000000..4dbbfa79
Binary files /dev/null and b/assets/imp.png differ
diff --git a/assets/smurf_sprites.png b/assets/smurf_sprites.png
new file mode 100644
index 00000000..ba64e4c7
Binary files /dev/null and b/assets/smurf_sprites.png differ
diff --git a/assets/smurf_sprites_numbered.png b/assets/smurf_sprites_numbered.png
new file mode 100644
index 00000000..353d6f89
Binary files /dev/null and b/assets/smurf_sprites_numbered.png differ
diff --git a/assets/sprites.png b/assets/sprites.png
new file mode 100644
index 00000000..f1fe1d97
Binary files /dev/null and b/assets/sprites.png differ
diff --git a/assets/steps.png b/assets/steps.png
new file mode 100644
index 00000000..3f93af58
Binary files /dev/null and b/assets/steps.png differ