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