From 39acbac09eb5d96df06414d3aee5b9184e368aad Mon Sep 17 00:00:00 2001 From: tymmkang Date: Mon, 9 Mar 2026 00:09:20 +0900 Subject: [PATCH] =?UTF-8?q?=ED=83=91=EB=8B=A4=EC=9A=B4=20=EB=AF=B8?= =?UTF-8?q?=EB=8B=88=EB=A7=B5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/MainScene.cpp | 204 ++++++++++++++++++++++++++++++++++++++----- Source/MainScene.h | 7 ++ 2 files changed, 191 insertions(+), 20 deletions(-) diff --git a/Source/MainScene.cpp b/Source/MainScene.cpp index e9dab68..b507fe0 100644 --- a/Source/MainScene.cpp +++ b/Source/MainScene.cpp @@ -25,6 +25,13 @@ #include "MainScene.h" +#if defined(AX_ENABLE_3D_PHYSICS) +# include "physics3d/Physics3DWorld.h" +#endif +#if defined(AX_ENABLE_NAVMESH) +# include "navmesh/NavMesh.h" +#endif + using namespace ax; static int s_sceneID = 1000; @@ -68,7 +75,8 @@ bool MainScene::init() this->addChild(menu, 1); ///////////////////////////// - // 3. 3D Setup + // 3D Setup + const unsigned short cameraMask3D = (unsigned short)CameraFlag::USER1 | (unsigned short)CameraFlag::USER2; // Grid settings const int gridSize = 10; @@ -82,19 +90,19 @@ bool MainScene::init() Vec3 gridCenter(gridWidth / 2.0f, 0.0f, gridWidth / 2.0f); // Create a single cube at the center of the grid area - auto centerCube = MeshRenderer::create("cube.obj"); - if (centerCube) + _playerCube = MeshRenderer::create("cube.obj"); + if (_playerCube) { - centerCube->setPosition3D(gridCenter); - centerCube->setCameraMask((unsigned short)CameraFlag::USER1); - this->addChild(centerCube); + _playerCube->setPosition3D(gridCenter); + _playerCube->setCameraMask(cameraMask3D); + this->addChild(_playerCube); } // Add Lights // Directional Light: Like sunlight, creating shadows/depth Vec3 lightDir(-1.0f, -1.0f, -0.5f); auto dirLight = DirectionLight::create(lightDir, Color3B::WHITE); - dirLight->setCameraMask((unsigned short)CameraFlag::USER1); + dirLight->setCameraMask(cameraMask3D); this->addChild(dirLight); // Visual marker for the Directional Light source @@ -109,13 +117,13 @@ bool MainScene::init() lightMarker->setPosition3D(markerPos); lightMarker->setScale(0.5f); lightMarker->setColor(Color3B::YELLOW); - lightMarker->setCameraMask((unsigned short)CameraFlag::USER1); + lightMarker->setCameraMask(cameraMask3D); this->addChild(lightMarker); } // Ambient Light: To ensure dark sides are still somewhat visible auto ambLight = AmbientLight::create(Color3B(80, 80, 80)); - ambLight->setCameraMask((unsigned short)CameraFlag::USER1); + ambLight->setCameraMask(cameraMask3D); this->addChild(ambLight); // Add a Ground Plane @@ -132,14 +140,15 @@ bool MainScene::init() ground->setScaleY(0.25f); // Thickness set to 0.25 // Positioned so the top surface is at Y = -0.5 (cubes are at Y=0 with height 1) ground->setPosition3D(Vec3(gridCenter.x, -0.5f - 0.125f, gridCenter.z)); - ground->setCameraMask((unsigned short)CameraFlag::USER1); + ground->setCameraMask(cameraMask3D); ground->setColor(Color3B(100, 100, 100)); this->addChild(ground); } - // Setup Camera for Quarter View (Isometric-like) + // Setup Main Camera for Quarter View (Isometric-like) _camera3D = Camera::createPerspective(60.0f, visibleSize.width / visibleSize.height, 0.1f, 1000.0f); _camera3D->setCameraFlag(CameraFlag::USER1); + _camera3D->setDepth(1); // Initial camera position setup _targetPos = gridCenter; @@ -150,6 +159,36 @@ bool MainScene::init() this->addChild(_camera3D); + // Setup Mini-map Camera for Top-down View + float miniMapSize = 200.0f; + _miniMapCamera = Camera::createPerspective(60.0f, 1.0f, 0.1f, 1000.0f); + _miniMapCamera->setCameraFlag(CameraFlag::USER2); + _miniMapCamera->setDepth(2); + + _miniMapCamera->setPosition3D(gridCenter + Vec3(0, 30.0f, 0.01f)); // Offset slightly on Z to avoid gimbal lock with up vector + _miniMapCamera->lookAt(gridCenter, Vec3(0, 0, -1)); + this->addChild(_miniMapCamera); + + // Mini-map Border (UI) + auto miniMapBorder = DrawNode::create(); + if (miniMapBorder) + { + Vec2 pos(visibleSize.width - miniMapSize - 20, visibleSize.height - miniMapSize - 20); + + // Draw the border line + miniMapBorder->drawRect(pos, pos + Vec2(miniMapSize, miniMapSize), Color4F::WHITE); + // Add a semi-transparent dark background for the map area + miniMapBorder->drawSolidRect(pos, pos + Vec2(miniMapSize, miniMapSize), Color4F(0, 0, 0, 0.4f)); + + // This belongs to the UI (DEFAULT camera) + miniMapBorder->setCameraMask((unsigned short)CameraFlag::DEFAULT); + this->addChild(miniMapBorder, 10); + _miniMapBorder = miniMapBorder; + } + + // Ensure Default Camera (UI) has higher depth to be on top + this->getDefaultCamera()->setDepth(3); + // Mouse Listener _mouseListener = EventListenerMouse::create(); _mouseListener->onMouseMove = AX_CALLBACK_1(MainScene::onMouseMove, this); @@ -158,6 +197,12 @@ bool MainScene::init() _mouseListener->onMouseScroll = AX_CALLBACK_1(MainScene::onMouseScroll, this); _eventDispatcher->addEventListenerWithSceneGraphPriority(_mouseListener, this); + // Keyboard Listener + _keyboardListener = EventListenerKeyboard::create(); + _keyboardListener->onKeyPressed = AX_CALLBACK_2(MainScene::onKeyPressed, this); + _keyboardListener->onKeyReleased = AX_CALLBACK_2(MainScene::onKeyReleased, this); + _eventDispatcher->addEventListenerWithSceneGraphPriority(_keyboardListener, this); + // Disable the default 2D camera for these 3D objects by using CameraFlag::USER1 // The label and menu will use the default camera (CameraFlag::DEFAULT) @@ -174,6 +219,95 @@ bool MainScene::init() return true; } +// Helper to access protected member of Camera +namespace ax +{ +class CameraHacker : public Camera +{ +public: + static void setVisitingCamera(Camera* cam) { _visitingCamera = cam; } +}; +} + +void MainScene::render(Renderer* renderer, const Mat4& eyeTransform, const Mat4* eyeProjection) +{ + auto visibleSize = _director->getVisibleSize(); + const auto& transform = getNodeToParentTransform(); + + for (const auto& camera : getCameras()) + { + if (!camera->isVisible()) + continue; + + ax::CameraHacker::setVisitingCamera(camera); + + // Set Viewport for this camera + if (camera == _miniMapCamera) + { + float miniMapSize = 200.0f; + Camera::setDefaultViewport(Viewport().set( + (int)(visibleSize.width - miniMapSize - 20), + (int)(visibleSize.height - miniMapSize - 20), + (int)miniMapSize, + (int)miniMapSize)); + } + else + { + Camera::setDefaultViewport(Viewport().set(0, 0, (int)visibleSize.width, (int)visibleSize.height)); + } + + if (eyeProjection) + camera->setAdditionalProjection(*eyeProjection * camera->getProjectionMatrix().getInversed()); + + camera->setAdditionalTransform(eyeTransform.getInversed()); + _director->pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION); + _director->loadMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION, camera->getViewProjectionMatrix()); + + camera->apply(); + // clear background with max depth + camera->clearBackground(); + // visit the scene + visit(renderer, transform, 0); + +#if defined(AX_ENABLE_NAVMESH) + if (_navMesh && _navMeshDebugCamera == camera) + { + _navMesh->debugDraw(renderer); + } +#endif + + renderer->render(); + + _director->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION); + } + +#if defined(AX_ENABLE_3D_PHYSICS) + if (_physics3DWorld && _physics3DWorld->isDebugDrawEnabled()) + { + Camera* physics3dDebugCamera = _physics3dDebugCamera != nullptr ? _physics3dDebugCamera : this->getDefaultCamera(); + + if (eyeProjection) + physics3dDebugCamera->setAdditionalProjection(*eyeProjection * + physics3dDebugCamera->getProjectionMatrix().getInversed()); + + physics3dDebugCamera->setAdditionalTransform(eyeTransform.getInversed()); + _director->pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION); + _director->loadMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION, + physics3dDebugCamera->getViewProjectionMatrix()); + + physics3dDebugCamera->apply(); + physics3dDebugCamera->clearBackground(); + + _physics3DWorld->debugDraw(renderer); + renderer->render(); + + _director->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION); + } +#endif + + ax::CameraHacker::setVisitingCamera(nullptr); +} + void MainScene::onTouchesBegan(const std::vector& touches, ax::Event* event) { for (auto&& t : touches) @@ -272,12 +406,12 @@ void MainScene::updateCameraPosition() void MainScene::onKeyPressed(EventKeyboard::KeyCode code, Event* event) { - AXLOGD("Scene: #{} onKeyPressed, keycode: {}", _sceneID, static_cast(code)); + _keyStates[code] = true; } void MainScene::onKeyReleased(EventKeyboard::KeyCode code, Event* event) { - AXLOGD("onKeyReleased, keycode: {}", static_cast(code)); + _keyStates[code] = false; } void MainScene::update(float delta) @@ -292,13 +426,43 @@ void MainScene::update(float delta) case GameState::update: { - ///////////////////////////// - // Add your codes below...like.... - // - // UpdateJoyStick(); - // UpdatePlayer(); - // UpdatePhysics(); - // ... + // Movement logic for _playerCube + if (_playerCube) + { + float speed = 10.0f * delta; + Vec3 move(0, 0, 0); + + if (_keyStates[EventKeyboard::KeyCode::KEY_W] || _keyStates[EventKeyboard::KeyCode::KEY_UP_ARROW]) move.z -= 1.0f; + if (_keyStates[EventKeyboard::KeyCode::KEY_S] || _keyStates[EventKeyboard::KeyCode::KEY_DOWN_ARROW]) move.z += 1.0f; + if (_keyStates[EventKeyboard::KeyCode::KEY_A] || _keyStates[EventKeyboard::KeyCode::KEY_LEFT_ARROW]) move.x -= 1.0f; + if (_keyStates[EventKeyboard::KeyCode::KEY_D] || _keyStates[EventKeyboard::KeyCode::KEY_RIGHT_ARROW]) move.x += 1.0f; + + if (move != Vec3::ZERO) + { + move.normalize(); + Vec3 currentPos = _playerCube->getPosition3D(); + Vec3 newPos = currentPos + (move * speed); + + // Boundary check against ground + // gridCenter = (5.625, 0, 5.625) + // groundSize = 14.25 + // cube half-size = 0.5 + float halfGround = 14.25f / 2.0f; + float minX = 5.625f - halfGround + 0.5f; // -1.0 + float maxX = 5.625f + halfGround - 0.5f; // 12.25 + float minZ = 5.625f - halfGround + 0.5f; // -1.0 + float maxZ = 5.625f + halfGround - 0.5f; // 12.25 + + newPos.x = std::clamp(newPos.x, minX, maxX); + newPos.z = std::clamp(newPos.z, minZ, maxZ); + + _playerCube->setPosition3D(newPos); + + // Camera follows the player + _targetPos = newPos; + updateCameraPosition(); + } + } break; } diff --git a/Source/MainScene.h b/Source/MainScene.h index 5b5485e..21835af 100644 --- a/Source/MainScene.h +++ b/Source/MainScene.h @@ -42,6 +42,7 @@ class MainScene : public ax::Scene public: bool init() override; void update(float delta) override; + void render(ax::Renderer* renderer, const ax::Mat4& eyeTransform, const ax::Mat4* eyeProjection = nullptr) override; // touch void onTouchesBegan(const std::vector& touches, ax::Event* event); @@ -73,8 +74,14 @@ private: ax::EventListenerMouse* _mouseListener = nullptr; int _sceneID = 0; + // Game Objects + ax::MeshRenderer* _playerCube = nullptr; + ax::DrawNode* _miniMapBorder = nullptr; + std::map _keyStates; + // Camera Orbit State ax::Camera* _camera3D = nullptr; + ax::Camera* _miniMapCamera = nullptr; ax::Vec3 _targetPos = ax::Vec3::ZERO; float _pitch = 45.0f; // degrees float _yaw = 45.0f; // degrees