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