Skip to content

Commit

Permalink
Door actor initialization changed from interface to function
Browse files Browse the repository at this point in the history
  • Loading branch information
shun126 committed Mar 23, 2023
1 parent 769f49c commit 220a3fc
Show file tree
Hide file tree
Showing 15 changed files with 449 additions and 297 deletions.
26 changes: 26 additions & 0 deletions Samples/SM_BasePillar.obj
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Exported from 3D Builder
mtllib Base.mtl

o Object.1
v -0.25 4.000000 -0.25
v -0.25 4.000000 0.25
v 0.25 4.000000 -0.25
v 0.25 4.000000 0.25
v -0.25 0.000000 -0.25
v -0.25 0.000000 0.25
v 0.25 0.000000 -0.25
v 0.25 0.000000 0.25

usemtl Green_0
f 1 2 3
f 3 2 4
f 2 6 4
f 4 6 8
f 4 8 3
f 3 8 7
f 2 5 6
f 2 1 5
f 1 3 5
f 5 3 7
f 5 7 8
f 5 8 6
10 changes: 5 additions & 5 deletions Source/DungeonGenerator/Private/Core/DrawLots.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,19 +36,19 @@ namespace dungeon
auto weight = pred(*i);
if (weight < 1)
weight = 1;
weights.emplace_back(weight, i);
totalWeight += weight;
const auto currentWeight = totalWeight + weight;
weights.emplace_back(currentWeight, i);
totalWeight = currentWeight;
}

// TODO: specify random numbers externally.
std::size_t rnd = random() % totalWeight;
const std::size_t rnd = random() % totalWeight;

for (const auto& weight : weights)
{
// cppcheck-suppress [useStlAlgorithm]
if (rnd < weight.mWeight)
return weight.mBody;

rnd -= weight.mWeight;
}

return last;
Expand Down
22 changes: 11 additions & 11 deletions Source/DungeonGenerator/Private/Core/Generator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1065,17 +1065,7 @@ namespace dungeon
continue;
generatedEdges.emplace(&aisle);

if (room != room0)
{
// TODO::判定関数を作成して下さい
if (room0->GetItem() == Room::Item::Empty &&
room0->GetParts() != Room::Parts::Unidentified &&
room0->GetParts() != Room::Parts::Start &&
room0->GetParts() != Room::Parts::Goal)
result.push_back(room0);
FindByRoute(result, generatedEdges, room0);
}
else
if (room == room0)
{
// TODO::判定関数を作成して下さい
if (room1->GetItem() == Room::Item::Empty &&
Expand All @@ -1085,6 +1075,16 @@ namespace dungeon
result.push_back(room1);
FindByRoute(result, generatedEdges, room1);
}
else
{
// TODO::判定関数を作成して下さい
if (room0->GetItem() == Room::Item::Empty &&
room0->GetParts() != Room::Parts::Unidentified &&
room0->GetParts() != Room::Parts::Start &&
room0->GetParts() != Room::Parts::Goal)
result.push_back(room0);
FindByRoute(result, generatedEdges, room0);
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ namespace dungeon
mStartPoint = FindStartPoint();

size_t startPointIndex = verteces.Find(mStartPoint);
// cppcheck-suppress [knownConditionTrueFalse]
// cppcheck-suppress [knownConditionTrueFalse, unmatchedSuppression]
if (startPointIndex != static_cast<size_t>(~0))
{
// スタートから各部屋の深さ(部屋の数)を設定
Expand Down
158 changes: 116 additions & 42 deletions Source/DungeonGenerator/Private/Core/MissionGraph/MissionGraph.cpp
Original file line number Diff line number Diff line change
@@ -1,13 +1,21 @@
/*
MissionGraph
Generate dungeon strategy information
ダンジョンの攻略情報を生成します
Algorithm for generating keys and doors
1. set a goal door in the passage connecting to the goal room
2. collect reachable aisle and rooms separated by doors
3. place a key (or goal key) somewhere in the reachable room
4. place a door somewhere in the reachable aisle
5. if more keys and doors can be placed, go back to 2.
鍵と扉の生成アルゴリズム
1. ゴール部屋に接続する通路にゴール鍵を設定する
2. 通路に到達可能な部屋のどこかにゴール鍵を置く(別ブランチは抽選の優先度を上げる)
3. ゴール部屋よりも浅い深度の通路に鍵を設定する
4. 通路に到達可能な部屋のどこかに鍵を置く(別ブランチは抽選の優先度を上げる)
5. 深度1より探索深度が不快なら3に戻る
1. ゴール部屋に接続する通路にゴール扉を設定する
2. 扉で仕切られた到達可能な部屋と通路を集める
3. 到達可能な部屋のどこかに鍵(またはゴール鍵)を置く
4. 到達可能な通路のどこかに扉を置く
5. さらに鍵と扉が置けるなら2へ戻る
敵配置の生成アルゴリズム
Expand All @@ -28,79 +36,149 @@ namespace dungeon
MissionGraph::MissionGraph(const std::shared_ptr<Generator>& generator, const std::shared_ptr<const Point>& goal) noexcept
: mGenerator(generator)
{
Generate(goal->GetOwnerRoom());
const auto room = goal->GetOwnerRoom();

// Choose an aisle close to the entrance
if (Aisle* aisle = SelectAisle(room))
{
// Locked. (to limit FindByRoute search scope)
aisle->SetUniqueLock(true);

const auto& room0 = aisle->GetPoint(0)->GetOwnerRoom();
const auto& room1 = aisle->GetPoint(1)->GetOwnerRoom();
const auto& connectingRoom = room == room0 ? room1 : room0;

// Gathering reachable rooms
std::vector<std::shared_ptr<Room>> keyRooms;
keyRooms = mGenerator->FindByRoute(connectingRoom);
if (keyRooms.size() > 0)
{
// TODO:DrawLots内で乱数を使っています
const uint8_t roomBranch = room->GetBranchId();
const auto keyRoom = DrawLots(keyRooms.begin(), keyRooms.end(), [roomBranch](const std::shared_ptr<const Room>& room)
{
uint32_t weight = room->GetDepthFromStart();
if (room->GetBranchId() - roomBranch)
weight *= 3;
if (room->GetParts() == Room::Parts::Hanare)
weight *= 3;
return weight;
}
);
if (keyRoom != keyRooms.end())
{
check((*keyRoom)->GetItem() == Room::Item::Empty);
(*keyRoom)->SetItem(Room::Item::UniqueKey);

Generate(connectingRoom);
}
else
{
// It did not decide on a room to put the key, so it will be unlocked
aisle->SetUniqueLock(false);
}
}
else
{
// It did not decide on a room to put the key, so it will be unlocked
aisle->SetUniqueLock(false);
}
}
}

/*
TODO:乱数を共通化して下さい
*/
void MissionGraph::Generate(const std::shared_ptr<const Room>& room, const uint8_t count) noexcept
void MissionGraph::Generate(const std::shared_ptr<const Room>& room) noexcept
{
#if 0
{
const FString path = FPaths::ProjectSavedDir() + TEXT("/dungeon_aisle.txt");
mGenerator->DumpAisle(TCHAR_TO_UTF8(*path));
}
#endif

// Choose an aisle close to the entrance
if (Aisle* aisle = SelectAisle(room))
{
if (count == 0)
aisle->SetUniqueLock(true);
else
aisle->SetLock(true);
// Locked. (to limit FindByRoute search scope)
aisle->SetLock(true);

const size_t halfRoomCount = mGenerator->GetRoomCount() / 2;
const uint8_t roomBranch = room->GetBranchId();
const uint8_t roomDepth = room->GetDepthFromStart();
const auto& room0 = aisle->GetPoint(0)->GetOwnerRoom();
const auto& room1 = aisle->GetPoint(1)->GetOwnerRoom();

// Gathering reachable rooms
std::vector<std::shared_ptr<Room>> keyRooms;
keyRooms = mGenerator->FindByRoute(room == room0 ? room1 : room0);
if (keyRooms.size() > 0)
{
#if 0
// TODO:DrawLots内で乱数を使っています
const auto keyRoom = DrawLots(keyRooms.begin(), keyRooms.end(), [halfRoomCount, roomBranch, roomDepth](const std::shared_ptr<const Room>& room)
const uint8_t roomBranch = room->GetBranchId();
const auto keyRoom = DrawLots(keyRooms.begin(), keyRooms.end(), [roomBranch](const std::shared_ptr<const Room>& room)
{
const auto deltaBranch = std::abs(roomBranch - room->GetBranchId());
const auto addition = room->GetParts() == Room::Parts::Hanare ? halfRoomCount : 0;
return deltaBranch + room->GetDepthFromStart() + addition;
const uint32_t deltaBranch = std::abs(roomBranch - room->GetBranchId());
const uint32_t depthFromStart = room->GetDepthFromStart();
uint32_t weight = deltaBranch + depthFromStart;
//if (room->GetParts() == Room::Parts::Hanare)
// weight *= 2;
return weight;
}
);
if (keyRoom != keyRooms.end())
{
// 鍵を置く部屋が決まった
// That's the room where I'm supposed to put the key.
check((*keyRoom)->GetItem() == Room::Item::Empty);
(*keyRoom)->SetItem(count == 0 ? Room::Item::UniqueKey : Room::Item::Key);
(*keyRoom)->SetItem(Room::Item::Key);
#if 0
Generate(*keyRoom);
#else
//const auto lockRoom = keyRooms[std::rand() % keyRooms.size()];
const auto lockRoom = DrawLots(keyRooms.begin(), keyRooms.end(), [](const std::shared_ptr<const Room>& room)
{
return room->GetDepthFromStart();
}
);
Generate(*lockRoom);
#endif
}
else
{
// 鍵を置く部屋が決まらなかった
if (count == 0)
aisle->SetUniqueLock(false);
else
aisle->SetLock(false);
// It did not decide on a room to put the key, so it will be unlocked
aisle->SetLock(false);
}
#else
// That's the room where I'm supposed to put the key.
{
// TODO:共通の乱数を使用してください
const auto keyRoom = keyRooms[std::rand() % keyRooms.size()];
check(keyRoom->GetItem() == Room::Item::Empty);
keyRoom->SetItem(Room::Item::Key);
}

// 次の鍵
if (roomDepth >= 3)
// TODO:DrawLots内で乱数を使っています
const auto lockRoom = DrawLots(keyRooms.begin(), keyRooms.end(), [](const std::shared_ptr<const Room>& room)
{
const uint32_t depthFromStart = room->GetDepthFromStart();
return depthFromStart * 10;
}
);
if (lockRoom != keyRooms.end())
{
const auto& depths = mGenerator->FindByDepth(roomDepth - 2);
const auto index = std::rand() % depths.size();
Generate(depths[index], count + 1);
Generate(*lockRoom);
}
#endif
}
else
{
if (count == 0)
aisle->SetUniqueLock(false);
else
aisle->SetLock(false);
// It did not decide on a room to put the key, so it will be unlocked
aisle->SetLock(false);
}
}
}

/*
Choose an aisle close to the entrance.
*/
Aisle* MissionGraph::SelectAisle(const std::shared_ptr<const Room>& room) const noexcept
{
const uint8_t roomDepth = room->GetDepthFromStart();
Expand All @@ -112,19 +190,15 @@ namespace dungeon
{
const auto& room0 = edge.GetPoint(0)->GetOwnerRoom();
const auto& room1 = edge.GetPoint(1)->GetOwnerRoom();
if (room0->GetDepthFromStart() <= roomDepth || room1->GetDepthFromStart() <= roomDepth)
if (room0->GetDepthFromStart() <= roomDepth && room1->GetDepthFromStart() <= roomDepth)
aisles.emplace_back(&edge);
}
return false;
}
);

// TODO:抽選してください
const size_t size = aisles.size();
return size > 0 ? aisles[0 % size] : nullptr;
}

Aisle* MissionGraph::SelectAisle(const std::shared_ptr<const Point>& point) const noexcept
{
return SelectAisle(point->GetOwnerRoom());
return size > 0 ? aisles[0] : nullptr;
}
}
30 changes: 17 additions & 13 deletions Source/DungeonGenerator/Private/Core/MissionGraph/MissionGraph.h
Original file line number Diff line number Diff line change
@@ -1,17 +1,13 @@
/*
MissionGraph
ダンジョンの攻略情報を生成します
Generate dungeon strategy information
鍵と扉の生成アルゴリズム
1. ゴール部屋に接続する通路にゴール鍵を設定する
2. 通路に到達可能な部屋のどこかにゴール鍵を置く(別ブランチは抽選の優先度を上げる)
3. ゴール部屋よりも浅い深度の通路に鍵を設定する
4. 通路に到達可能な部屋のどこかに鍵を置く(別ブランチは抽選の優先度を上げる)
5. 深度1より探索深度が不快なら3に戻る
敵配置の生成アルゴリズム
部屋の装飾アルゴリズム
Algorithm for generating keys and doors
1. set a goal door in the passage connecting to the goal room
2. collect reachable aisle and rooms separated by doors
3. place a key (or goal key) somewhere in the reachable room
4. place a door somewhere in the reachable aisle
5. if more keys and doors can be placed, go back to 2.
\author Shun Moriya
\copyright 2023- Shun Moriya
Expand All @@ -28,16 +24,24 @@ namespace dungeon
class Point;
class Room;

/*
Generate dungeon strategy information
*/
class MissionGraph
{
public:
// constructor
MissionGraph(const std::shared_ptr<Generator>& generator, const std::shared_ptr<const Point>& goal) noexcept;

// destructor
virtual ~MissionGraph() = default;

private:
void Generate(const std::shared_ptr<const Room>& room, const uint8_t count = 0) noexcept;
// generate mission graph
void Generate(const std::shared_ptr<const Room>& room) noexcept;

// choose an aisle close to the entrance.
Aisle* SelectAisle(const std::shared_ptr<const Room>& room) const noexcept;
Aisle* SelectAisle(const std::shared_ptr<const Point>& point) const noexcept;

private:
std::shared_ptr<Generator> mGenerator;
Expand Down
2 changes: 1 addition & 1 deletion Source/DungeonGenerator/Private/Core/PathFinder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ namespace dungeon
return false;

// 最もコストの低いノードを検索
std::unordered_map<uint64_t, OpenNode>::iterator result;
std::unordered_map<uint64_t, OpenNode>::iterator result = mOpen.begin();
uint32_t minimumCost = std::numeric_limits<uint32_t>::max();
for (std::unordered_map<uint64_t, OpenNode>::iterator i = mOpen.begin(); i != mOpen.end(); ++i)
{
Expand Down

0 comments on commit 220a3fc

Please sign in to comment.