diff --git a/1mGame.sln b/1mGame.sln new file mode 100644 index 0000000..40a7411 --- /dev/null +++ b/1mGame.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.2.32526.322 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "1mGame", "1mGame.vcxproj", "{8E1FE2C8-6B0D-4DC7-AE36-026A1ED8D525}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {8E1FE2C8-6B0D-4DC7-AE36-026A1ED8D525}.Debug|x64.ActiveCfg = Debug|x64 + {8E1FE2C8-6B0D-4DC7-AE36-026A1ED8D525}.Debug|x64.Build.0 = Debug|x64 + {8E1FE2C8-6B0D-4DC7-AE36-026A1ED8D525}.Release|x64.ActiveCfg = Release|x64 + {8E1FE2C8-6B0D-4DC7-AE36-026A1ED8D525}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {B82BAF57-C01C-4194-9774-CCE0AE107D86} + EndGlobalSection +EndGlobal diff --git a/1mGame.vcxproj b/1mGame.vcxproj new file mode 100644 index 0000000..30df8b9 --- /dev/null +++ b/1mGame.vcxproj @@ -0,0 +1,98 @@ + + + + + Debug + x64 + + + Release + x64 + + + + 16.0 + Win32Proj + {8e1fe2c8-6b0d-4dc7-ae36-026a1ed8d525} + My1mGame + 10.0 + + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + + + + + + + + + + + + + $(SolutionDir)bin\ + + + $(SolutionDir)bin\ + + + + Level3 + true + WIN32_LEAN_AND_MEAN;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + stdcpp20 + + + Console + true + Imm32.lib;d2d1.lib;Windowscodecs.lib;%(AdditionalDependencies) + + + + + Level3 + true + true + true + WIN32_LEAN_AND_MEAN;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + stdcpp20 + + + Windows + true + true + true + Imm32.lib;d2d1.lib;Windowscodecs.lib;%(AdditionalDependencies) + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/1mGame.vcxproj.filters b/1mGame.vcxproj.filters new file mode 100644 index 0000000..2c7b4ff --- /dev/null +++ b/1mGame.vcxproj.filters @@ -0,0 +1,46 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + 源文件 + + + 源文件 + + + 源文件 + + + 源文件 + + + 源文件 + + + 源文件 + + + 源文件 + + + 源文件 + + + 源文件 + + + \ No newline at end of file diff --git a/GameObject.ixx b/GameObject.ixx new file mode 100644 index 0000000..ec5af53 --- /dev/null +++ b/GameObject.ixx @@ -0,0 +1,57 @@ +module; +#include +#include + +export module GameObject; + +import Graphics; +import Math; + +export struct Texture +{ + using BitMap = ::Microsoft::WRL::ComPtr; + + BitMap bitmap; + Vector2 size; + Rect rect; + + static Texture LoadFromFile(LPCWSTR uri) + { + Texture tex; + tex.bitmap = Graphics::LoadImageFromFile(uri); + auto s = tex.bitmap->GetPixelSize(); + tex.size = { (FLOAT)s.width, (FLOAT)s.height }; + tex.rect = { 0.f, 0.f, tex.size.x, tex.size.y }; + return tex; + } +}; + +export class GameObject +{ + +public: + + Texture imge; + Vector2 Posi; + Vector2 Anch; + Vector2 Size; + + GameObject() {} + + virtual void OnStartUp() = 0; + virtual void OnCleanUp() = 0; + virtual void OnUpdate(float delta) = 0; + virtual void OnLaterUpdate(float delta) = 0; + + void OnRender() + { + Rect dst = + { + Posi.x - Size.x * Anch.x, + Posi.y + Size.y * (1.f - Anch.y), + Posi.x + Size.x * (1.f - Anch.x), + Posi.y - Size.y * Anch.y, + }; + Graphics::DrawBitMap(imge.bitmap, dst, imge.rect); + } +}; \ No newline at end of file diff --git a/Graphics.cpp b/Graphics.cpp new file mode 100644 index 0000000..504667d --- /dev/null +++ b/Graphics.cpp @@ -0,0 +1,114 @@ +module; +#include +#include +#include +#include + +module Graphics; + +using namespace D2D1; +using namespace ::Microsoft::WRL; + +constexpr D2D1_RECT_F SteveRect{ 1678,2,1766,96 }; + +ComPtr Graphics::RT = nullptr; +ComPtr Graphics::wic_factory = nullptr; +Vector2 Graphics::RtSize{}; +//ComPtr Graphics::wic_factory = nullptr; + +void Graphics::Init(HWND hwnd) +{ + ComPtr Factory = nullptr; + auto hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, Factory.GetAddressOf()); + assert(hr == S_OK); + + RECT rc; + GetClientRect(hwnd, &rc); + + hr = Factory->CreateHwndRenderTarget( + RenderTargetProperties(), + HwndRenderTargetProperties(hwnd, SizeU(rc.right-rc.left, rc.bottom-rc.top)), + &RT + ); + assert(hr == S_OK); + + RtSize = { (FLOAT)(rc.right - rc.left), (FLOAT)(rc.bottom - rc.top) }; + + hr = CoCreateInstance( + CLSID_WICImagingFactory, + NULL, + CLSCTX_INPROC_SERVER, + IID_PPV_ARGS(&wic_factory) + ); + assert(hr == S_OK); + +} + +void Graphics::BeginDraw() +{ + RT->BeginDraw(); +} +void Graphics::Clear() +{ + RT->Clear({ .r = 0.96862745f, .g = 0.96862745f, .b = 0.96862745f, .a = 1.0f }); +} + +void Graphics::Present() +{ + RT->EndDraw(); +} + +void Graphics::Finalize() +{ + +} + +void Graphics::DrawBitMap(const ComPtr& bitmap, D2D_RECT_F dst, D2D_RECT_F src) +{ + if (!bitmap) return; + dst.top = RtSize.y - dst.top; + dst.bottom = RtSize.y - dst.bottom; + RT->DrawBitmap(bitmap.Get(), dst, 1.0f, D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR, src); +} + +ComPtr Graphics::LoadImageFromFile(LPCWSTR uri) +{ + ComPtr img = nullptr; + ComPtr decoder = nullptr; + ComPtr source = nullptr; + ComPtr converter = nullptr; + + auto hr = wic_factory->CreateDecoderFromFilename( + uri, + nullptr, + GENERIC_READ, + WICDecodeMetadataCacheOnLoad, + &decoder + ); + assert(hr == S_OK); + + hr = decoder->GetFrame(0, &source); + assert(hr == S_OK); + + hr = wic_factory->CreateFormatConverter(&converter); + assert(hr == S_OK); + + hr = converter->Initialize( + source.Get(), + GUID_WICPixelFormat32bppPBGRA, + WICBitmapDitherTypeNone, + NULL, + 0.f, + WICBitmapPaletteTypeMedianCut + ); + assert(hr == S_OK); + + hr = RT->CreateBitmapFromWicBitmap( + converter.Get(), + nullptr, + &img + ); + assert(hr == S_OK); + + return img; +} \ No newline at end of file diff --git a/Graphics.ixx b/Graphics.ixx new file mode 100644 index 0000000..41cc94d --- /dev/null +++ b/Graphics.ixx @@ -0,0 +1,29 @@ +module; +#include +#include +#include + +export module Graphics; + +import Math; + +export class Graphics +{ + template + using ComPtr = ::Microsoft::WRL::ComPtr; +public: + static void Init(HWND hwnd); + static void BeginDraw(); + static void Clear(); + static void Present(); + static void Finalize(); + + static void DrawBitMap(const ComPtr& bitmap, D2D_RECT_F dst, D2D_RECT_F src); + + static ComPtr LoadImageFromFile(LPCWSTR uri); +private: + static ComPtr wic_factory; + static ComPtr RT; + static Vector2 RtSize; +}; + diff --git a/Input.ixx b/Input.ixx new file mode 100644 index 0000000..1b3fc98 --- /dev/null +++ b/Input.ixx @@ -0,0 +1,20 @@ +module; + +export module Input; + +export class KeyBoard +{ + static bool KeyStatus[256]; + +public: + static void Update(char keycode, bool status) + { + KeyStatus[keycode] = status; + } + static bool GetKey(char keycode) + { + return KeyStatus[keycode]; + } +}; + +bool KeyBoard::KeyStatus[256]{}; \ No newline at end of file diff --git a/Math.ixx b/Math.ixx new file mode 100644 index 0000000..128afc4 --- /dev/null +++ b/Math.ixx @@ -0,0 +1,16 @@ +module; +#include + +export module Math; + +export +{ + struct Vector2 : D2D1_POINT_2F + { + + }; + struct Rect : D2D1_RECT_F + { + + }; +} \ No newline at end of file diff --git a/MegaEngine.cpp b/MegaEngine.cpp new file mode 100644 index 0000000..f5ef46e --- /dev/null +++ b/MegaEngine.cpp @@ -0,0 +1,183 @@ +module; +#include +#include +#include +#include +#include +#include + +module MegaEngine; + +import Input; + +using namespace std; +using namespace std::chrono; + +void Game::Run() +{ + StartUp(); + + while (PeekMsg() && !Done()) + { + Update(); + Render(); + LaterUpdate(); + } + + CleanUp(); +} + +void Game::StartUp() +{ + last = steady_clock::now(); + + CreateWnd(); + Graphics::Init(hwnd); + + steve.OnStartUp(); + +} + +void Game::Update() +{ + auto now = steady_clock::now(); + delta = duration_cast>(now - last).count(); + last = now; + steve.OnUpdate(delta); +} + +void Game::Render() +{ + Graphics::BeginDraw(); + Graphics::Clear(); + + steve.OnRender(); + + Graphics::Present(); +} + +void Game::LaterUpdate() +{ + steve.OnLaterUpdate(delta); +} + +void Game::CleanUp() +{ + steve.OnCleanUp(); + + Graphics::Finalize(); + + if (hwnd) DestroyWindow(hwnd); + + auto hInst = GetModuleHandleW(nullptr); + UnregisterClassW(L"1mGameWnd", hInst); +} + +void Game::CreateWnd() +{ + auto hInst = GetModuleHandleW(nullptr); + + WNDCLASSEXW wc = + { + sizeof(WNDCLASSEXW), + CS_CLASSDC, + WndProcSetUp, + 0, + 0, + hInst, + LoadIconW(nullptr, IDI_APPLICATION), + LoadCursorW(nullptr, IDC_ARROW), + CreateSolidBrush(0x808080), + nullptr, + wndClassName, + nullptr + }; + + wc.lpszClassName = L"1mGameWnd"; + + RegisterClassExW(&wc); + + auto wnd_style = WS_OVERLAPPEDWINDOW & ~WS_THICKFRAME;//WS_CAPTION | WS_SYSMENU; + + RECT client_rect{ 0, 0, wndWidth, wndHeight }; + AdjustWindowRectEx(&client_rect, wnd_style, FALSE, 0u); + + hwnd = CreateWindowExW + ( + 0L, + L"1mGameWnd", + L"1mGame", + wnd_style, + CW_USEDEFAULT, + CW_USEDEFAULT, + client_rect.right - client_rect.left, + client_rect.bottom - client_rect.top, + nullptr, nullptr, hInst, (LPVOID)this + ); + + ShowWindow(hwnd, SW_SHOW); + UpdateWindow(hwnd); +} + +bool Game::PeekMsg() +{ + MSG msg; + while (PeekMessageW(&msg, nullptr, 0, 0, PM_REMOVE)) + { + if (msg.message == WM_QUIT) return false; + DispatchMessageW(&msg); + } + return true; +} + +bool Game::Done() +{ + return done; +} + +LRESULT CALLBACK Game::WndProcSetUp(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + if (msg == WM_NCCREATE) + { + ImmDisableIME(GetCurrentThreadId()); + auto CreateData = reinterpret_cast(lParam); + auto wnd_ptr = reinterpret_cast(CreateData->lpCreateParams); + + SetWindowLongPtrW(hWnd, GWLP_WNDPROC, reinterpret_cast(&Game::WndProcThunk)); + SetWindowLongPtrW(hWnd, GWLP_USERDATA, reinterpret_cast(wnd_ptr)); + + return wnd_ptr->WndProc(hWnd, msg, wParam, lParam); + } + + return DefWindowProcW(hWnd, msg, wParam, lParam); +} + +LRESULT CALLBACK Game::WndProcThunk(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + auto wnd_ptr = reinterpret_cast(GetWindowLongPtrW(hWnd, GWLP_USERDATA)); + return wnd_ptr->WndProc(hWnd, msg, wParam, lParam); +} + +LRESULT Game::WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch (msg) + { + case WM_KEYDOWN: + KeyBoard::Update((char)wParam, true); + break; + case WM_KEYUP: + KeyBoard::Update((char)wParam, false); + break; + case WM_CLOSE: + done = true; + DestroyWindow(hwnd); + hwnd = nullptr; + break; + case WM_DESTROY: + PostQuitMessage(0); + break; + default: + return DefWindowProcW(hWnd, msg, wParam, lParam); + } + return 0; +} \ No newline at end of file diff --git a/MegaEngine.ixx b/MegaEngine.ixx new file mode 100644 index 0000000..56608b1 --- /dev/null +++ b/MegaEngine.ixx @@ -0,0 +1,50 @@ +module; +#include +#include +#include +#include + +export module MegaEngine; + +import Input; +import Graphics; +import GameObject; +import Steve; + +using namespace std; +using namespace std::chrono; + +export class Game +{ +public: + static constexpr LPCWSTR wndClassName = L"1mGameWnd"; + static constexpr LPCWSTR gameTitle = L"1mGame"; + static constexpr int wndHeight = 450; + static constexpr int wndWidth = 1050; + + void Run(); + +private: + Steve steve; + steady_clock::time_point last; + float delta; + + HWND hwnd = nullptr; + bool done = false; + + void StartUp(); + + void Update(); + void Render(); + void LaterUpdate(); + + void CleanUp(); + + void CreateWnd(); + bool PeekMsg(); + bool Done(); + + static LRESULT CALLBACK WndProcSetUp(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); + static LRESULT CALLBACK WndProcThunk(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); + LRESULT WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); +}; diff --git a/README.md b/README.md index 42ef24d..6be6965 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,3 @@ # MegaSteve -复刻Chrome的断网小游戏The Jumping Steve. \ No newline at end of file +复刻Chrome的断网小游戏 Steve: The Jumping Dinosaur. \ No newline at end of file diff --git a/Steve.ixx b/Steve.ixx new file mode 100644 index 0000000..158b3a3 --- /dev/null +++ b/Steve.ixx @@ -0,0 +1,81 @@ +module; +#include + +export module Steve; + +import GameObject; +import Input; + +export struct Steve : GameObject +{ + float a, v, h; + bool jumping = false; + + enum Status { Idle, Running, Jumping, Freefall, Crawling, Dead } status; + + virtual void OnStartUp() override + { + imge = Texture::LoadFromFile(L"steve.png"); + imge.rect = { 1678, 2, 1766, 96 }; + + Posi = { 94, 100 }; + Anch = { 0.5f,0 }; + Size = { 88, 94 }; + + a = v = h = 0.0f; + } + virtual void OnCleanUp() override + { + imge.bitmap = nullptr; + } + virtual void OnUpdate(float delta) override + { + switch (status) + { + case Steve::Idle: + if (KeyBoard::GetKey(VK_SPACE)) status = Running; + break; + case Steve::Running: + if (KeyBoard::GetKey(VK_SPACE)) + { + status = Jumping; + goto _jump_; + } + break; + case Steve::Jumping: + _jump_: + if ((h < 60 || KeyBoard::GetKey(VK_SPACE)) && h < 120.f) + { + v = 1000.f; + h += v * delta; + Posi.y = 100 + h; + } + else + { + status = Freefall; + } + break; + case Steve::Freefall: + a = -8000.f; + v += a * delta; + if (v < -1000) v = -1200; + h += v * delta; + Posi.y = 100 + h; + if (Posi.y <= 100) + { + status = Running; + Posi.y = 100; + } + break; + case Steve::Crawling: + break; + case Steve::Dead: + break; + default: + break; + } + } + virtual void OnLaterUpdate(float delta) override + { + } +}; \ No newline at end of file diff --git a/Steve.png b/Steve.png new file mode 100644 index 0000000..3a1e92e Binary files /dev/null and b/Steve.png differ diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..d71934a --- /dev/null +++ b/main.cpp @@ -0,0 +1,13 @@ +#include + +import MegaEngine; + +#ifdef NDEBUG +int WINAPI wWinMain(HINSTANCE, HINSTANCE, LPWSTR, int) +#else +int main() +#endif // NDBUG +{ + Game().Run(); + return 0; +} \ No newline at end of file