Skip to content

Commit e058e35

Browse files
authored
Map abstraction (#161)
* Added MapConfig Struct * Reworked map systems to use configs * Added handling for new areas Important scenes' backgrounds change based on area. Added a transitional scene between areas MapConfigs set for each area Ability to generate new map for new area. Map in Cartographer to better show nearby map rooms. * Cleanup for merge * Standardized background changing Created AreaBasedBackground class
1 parent 74d7d64 commit e058e35

10 files changed

Lines changed: 224 additions & 40 deletions

File tree

Globals/FunkEngineNameSpace.cs

Lines changed: 79 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Collections.Generic;
23
using System.Linq;
34
using FunkEngine.Classes.MidiMaestro;
45
using Godot;
@@ -251,6 +252,13 @@ public enum Stages
251252
Quit,
252253
Map,
253254
Load,
255+
Continue,
256+
}
257+
258+
public enum Area
259+
{
260+
Forest = 0,
261+
City = 1,
254262
}
255263

256264
public enum Rarity
@@ -308,59 +316,111 @@ public void AddChild(int newIdx)
308316
}
309317
}
310318

319+
//TODO: Make odds for rooms based on y-level, e.g. elites only spawn on y > 3
320+
public struct MapConfig
321+
{
322+
public int Width { get; private set; }
323+
public int Height { get; private set; }
324+
public int Paths { get; private set; }
325+
326+
/// <summary>
327+
/// Rooms that exist at set levels, only one room can be set per y-level.
328+
/// </summary>
329+
public Dictionary<int, Stages> SetRooms { get; private set; } =
330+
new()
331+
{
332+
{ 0, Stages.Battle }, //The first, e.g. y = 0 room, should always be a battle.
333+
};
334+
335+
public const int NumStages = 2;
336+
337+
public static readonly Stages[] StagsToRoll = new[] { Stages.Battle, Stages.Chest };
338+
339+
/// <summary>
340+
/// The odds for each stage to appear in a non-set room position.
341+
/// </summary>
342+
public float[] StageOdds = new float[2];
343+
344+
public MapConfig(int width, int height, int paths, float[] odds)
345+
{
346+
Width = width;
347+
Height = height;
348+
Paths = paths;
349+
for (int i = 0; i < NumStages; i++)
350+
{
351+
StageOdds[i] = odds[i];
352+
}
353+
}
354+
355+
/// <summary>
356+
/// Adds a set room type to be generated guaranteed. Additional entries in the same y-level are ignored.
357+
/// </summary>
358+
/// <param name="height">The y-level of the rooms</param>
359+
/// <param name="roomType">The room type to be set.</param>
360+
public MapConfig AddSetRoom(int height, Stages roomType)
361+
{
362+
SetRooms.TryAdd(height, roomType);
363+
return this;
364+
}
365+
}
366+
311367
/**
312368
* <summary>Initializes the map with max <c>width</c>, max <c>height</c>, and with number of <c>paths</c>.</summary>
313369
*/
314-
public void InitMapGrid(int width, int height, int paths)
370+
public void InitMapGrid(MapConfig curConfig)
315371
{
316372
_curIdx = 0;
317-
_rooms = Array.Empty<Room>();
318-
_map = new int[width, height]; //x,y
373+
_rooms = [];
374+
_map = new int[curConfig.Width, curConfig.Height]; //x,y
319375

320-
int startX = (width / 2);
376+
int startX = (curConfig.Width / 2);
321377
_rooms = _rooms.Append(new Room(_curIdx, startX, 0)).ToArray();
322378
_rooms[0].SetType(Stages.Battle);
323379
_map[startX, 0] = _curIdx++;
324380

325-
for (int i = 0; i < paths; i++)
381+
for (int i = 0; i < curConfig.Paths; i++)
326382
{
327-
GeneratePath_r(startX, 0, width, height);
383+
GeneratePath_r(startX, 0, curConfig);
328384
}
329-
CreateCommonChildren(width, height);
330-
AddBossRoom(width, height);
385+
CreateCommonChildren(curConfig.Width, curConfig.Height);
386+
AddBossRoom(curConfig.Width, curConfig.Height);
331387
}
332388

333389
/**Start at x, y, assume prev room exists. Picks new x pos within +/- 1, attaches recursively*/
334-
private void GeneratePath_r(int x, int y, int width, int height)
390+
private void GeneratePath_r(int x, int y, MapConfig curConfig)
335391
{
336392
int nextX = StageProducer.GlobalRng.RandiRange(
337393
Math.Max(x - 1, 0),
338-
Math.Min(x + 1, width - 1)
394+
Math.Min(x + 1, curConfig.Width - 1)
339395
);
340396
if (_map[nextX, y + 1] == 0)
341397
{
342398
_rooms = _rooms.Append(new Room(_curIdx, nextX, y + 1)).ToArray();
343399
_map[nextX, y + 1] = _curIdx;
344400
_rooms[_map[x, y]].AddChild(_curIdx++);
345-
_rooms[^1].SetType(PickRoomType(x, y));
401+
_rooms[^1].SetType(PickRoomType(x, y, curConfig));
346402
}
347403
else
348404
{
349405
_rooms[_map[x, y]].AddChild(_map[nextX, y + 1]);
350406
}
351-
if (y < height - 2)
407+
if (y < curConfig.Height - 2)
352408
{
353-
GeneratePath_r(nextX, y + 1, width, height);
409+
GeneratePath_r(nextX, y + 1, curConfig);
354410
}
355411
}
356412

357-
private Stages PickRoomType(int x, int y)
413+
private Stages PickRoomType(int x, int y, MapConfig curConfig)
358414
{
359-
if (y % 3 == 0)
360-
return Stages.Chest;
361-
if (StageProducer.GlobalRng.Randf() < .08)
362-
return Stages.Chest;
363-
return Stages.Battle;
415+
//If the y has a set room return it.
416+
if (curConfig.SetRooms.TryGetValue(y, out Stages result))
417+
{
418+
return result;
419+
}
420+
421+
//Random roll for the room type.
422+
int idx = (int)StageProducer.GlobalRng.RandWeighted(curConfig.StageOdds);
423+
return MapConfig.StagsToRoll[idx];
364424
}
365425

366426
//Asserts that if there is a room at the same x, but y+1 they are connected

Globals/StageProducer.cs

Lines changed: 52 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,28 @@ public partial class StageProducer : Node
1313

1414
public static readonly RandomNumberGenerator GlobalRng = new();
1515

16-
public static Vector2I MapSize { get; } = new(7, 6); //For now, make width an odd number
17-
public static MapGrid Map { get; } = new();
16+
private static readonly MapGrid.MapConfig FirstMapConfig = new MapGrid.MapConfig(
17+
7,
18+
6,
19+
3,
20+
[10, 1]
21+
).AddSetRoom(3, Stages.Chest);
22+
23+
private static readonly MapGrid.MapConfig TestMapConfig = new MapGrid.MapConfig(
24+
10,
25+
10,
26+
5,
27+
[10, 2]
28+
)
29+
.AddSetRoom(3, Stages.Chest)
30+
.AddSetRoom(6, Stages.Chest);
31+
32+
private static readonly MapGrid.MapConfig[] MapConfigs = new[] { FirstMapConfig };
33+
34+
public static MapGrid Map { get; private set; } = new();
1835
private Stages _curStage = Stages.Title;
1936
public static int CurRoom { get; private set; }
37+
public static Area CurArea { get; private set; } = Area.Forest;
2038

2139
private Node _curScene;
2240
private Node _preloadStage;
@@ -53,12 +71,13 @@ private void InitFromCfg()
5371
private void GenerateMapConsistent()
5472
{
5573
GlobalRng.State = GlobalRng.Seed << 5 / 2; //Fudge seed state, to get consistent maps across new/loaded games
56-
Map.InitMapGrid(MapSize.X, MapSize.Y, 3);
74+
Map.InitMapGrid(MapConfigs[(int)CurArea]);
5775
}
5876

5977
private void StartNewGame()
6078
{
6179
GlobalRng.Randomize();
80+
CurArea = Area.Forest;
6281
GenerateMapConsistent();
6382

6483
PlayerStats = new PlayerStats();
@@ -112,10 +131,10 @@ public void TransitionFromRoom(int nextRoomIdx)
112131

113132
private Task _loadTask;
114133

115-
/**
116-
* <summary>To be used from Cartographer. Preloads the scene during transition animation.
117-
* This removes the occasionally noticeable load time for the scene change.</summary>
118-
*/
134+
/// <summary>
135+
/// To be used from Cartographer. Preloads the scene during transition animation. This removes the occasionally noticeable load time for the scene change.
136+
/// </summary>
137+
/// <param name="nextRoomIdx">Index of the next room in the map to get the stage from.</param>
119138
public void PreloadScene(int nextRoomIdx)
120139
{
121140
Stages nextStage = Map.GetRooms()[nextRoomIdx].Type;
@@ -174,6 +193,10 @@ public void TransitionStage(Stages nextStage, int nextRoomIdx = -1)
174193
case Stages.Quit:
175194
GetTree().Quit();
176195
return;
196+
case Stages.Continue:
197+
ProgressAreas();
198+
GetTree().ChangeSceneToFile("res://Scenes/Maps/InBetween.tscn");
199+
break;
177200
default:
178201
GD.PushError($"Error Scene Transition is {nextStage}");
179202
break;
@@ -227,4 +250,26 @@ public override void _Input(InputEvent @event)
227250
return;
228251
}
229252
}
253+
254+
#region Area Management
255+
256+
/// <summary>
257+
/// There should always be a mapconfig for each area. It's preferable to crash later if there isn't even a placeholder config.
258+
/// </summary>
259+
/// <returns>True if there is another area.</returns>
260+
public static bool IsMoreAreas()
261+
{
262+
return (int)CurArea + 1 < MapConfigs.Length;
263+
}
264+
265+
public void ProgressAreas()
266+
{
267+
CurArea += 1;
268+
269+
Map = new();
270+
GenerateMapConsistent();
271+
CurRoom = Map.GetRooms()[0].Idx;
272+
}
273+
274+
#endregion
230275
}

Globals/Translations/Translations.csv

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ CONTROLS_CHOOSE_BUTTON,Choose new button,选择输入按钮
2020
ESCAPE_MENU_RESUME,Resume,继续
2121
ESCAPE_MENU_QUIT,Quit,退出
2222
ESCAPE_MENU_TITLE,Quit to Title,返回标题
23+
INBETWEEN_CONTINUE,Continue,继续
2324
CHEST_ROOM_REWARDS,Reward Selection!,奖励!
2425
CHEST_ROOM_SKIP,Skip,跳过
2526
CHEST_ROOM_ACCEPT,Accept,接受
@@ -65,15 +66,15 @@ RELIC_COLORBOROS_TOOLTIP,"Taste the rainbow. Charges the freestyle bar every rif
6566
RELIC_CHIPS_NAME,"Chips",薯片
6667
RELIC_CHIPS_TOOLTIP,"Hitting a note deals a bit of damage.","击中音符会造成少量伤害。"
6768
RELIC_PAPERCUT_NAME,Paper Cut,纸割伤
68-
RELIC_PAPERCUT_TOOLTIP,"Deals damage each loop.","每轮造成伤害"
69+
RELIC_PAPERCUT_TOOLTIP,"Deals damage each riff.","每轮造成伤害"
6970
RELIC_ENERGYDRINK_NAME,Energy Drink,"能量饮料"
7071
RELIC_ENERGYDRINK_TOOLTIP,"Take a chance to cool down and sip an energy drink to increase your max energy bar.","碰碰运气,喝一口能量饮料来冷静下来并增加你的最大能量条。"
7172
RELIC_BANDAGE_NAME,Bandage,"绷带"
7273
RELIC_BANDAGE_TOOLTIP,"A clean strip of cloth. Use it after a fight to patch up and feel better.","一块干净的布条,战斗后使用来包扎并恢复一些健康。"
7374
RELIC_MEDKIT_NAME,Medkit,"急救包"
74-
RELIC_MEDKIT_TOOLTIP,"A small kit with medical supplies. Heals you a bit after each loop.","包含一些医疗用品的小包,每次循环后恢复少量生命。"
75+
RELIC_MEDKIT_TOOLTIP,"A small kit with medical supplies. Heals you a bit after each riff.","包含一些医疗用品的小包,每次循环后恢复少量生命。"
7576
RELIC_VINYLRECORD_NAME,Vinyl Record,"黑胶唱片"
76-
RELIC_VINYLRECORD_TOOLTIP,"Right round, right round. All loop effects trigger twice.","把我转起来,把我转起来。所有循环效果触发两次。"
77+
RELIC_VINYLRECORD_TOOLTIP,"Right round, right round. All riff effects trigger twice.","把我转起来,把我转起来。所有循环效果触发两次。"
7778
INVENTORY_TAB_NOTES,Notes,乐谱
7879
INVENTORY_TAB_RELICS,Relics,遗物
7980
OPTIONS_VOLUME_LABEL,Master Volume,最终音量设置

Scenes/AreaBasedBackground.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
using System;
2+
using FunkEngine;
3+
using Godot;
4+
5+
public partial class AreaBasedBackground : TextureRect
6+
{
7+
public override void _Ready()
8+
{
9+
Texture = StageProducer.CurArea switch
10+
{
11+
Area.Forest => GD.Load<Texture2D>("res://SharedAssets/BackGround_Full.png"),
12+
Area.City => GD.Load<Texture2D>("res://icon.svg"),
13+
_ => null,
14+
};
15+
}
16+
}

Scenes/AreaBasedBackground.cs.uid

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
uid://cp6t6haqyef7o

Scenes/BattleDirector/BattleScene.tscn

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1-
[gd_scene load_steps=11 format=3 uid="uid://b0mrgr7h0ty1y"]
1+
[gd_scene load_steps=12 format=3 uid="uid://b0mrgr7h0ty1y"]
22

33
[ext_resource type="Script" uid="uid://bttu0wmy2fp64" path="res://Scenes/BattleDirector/Scripts/BattleDirector.cs" id="1_jmdo1"]
44
[ext_resource type="Script" uid="uid://pl57giqyhckb" path="res://Scenes/UI/Scripts/MenuModule.cs" id="2_ka0ws"]
55
[ext_resource type="Script" uid="uid://tg14hkh1n7iv" path="res://Scenes/BattleDirector/Scripts/Conductor.cs" id="3_elcaj"]
66
[ext_resource type="PackedScene" uid="uid://duhiilcv4tat3" path="res://Scenes/BattleDirector/NotePlacementBar.tscn" id="4_qk7om"]
77
[ext_resource type="PackedScene" uid="uid://dfevfib11kou1" path="res://Scenes/ChartViewport/ChartViewport.tscn" id="5_r2xh0"]
88
[ext_resource type="Texture2D" uid="uid://qhwve7fik4do" path="res://SharedAssets/BackGround_Full.png" id="6_0jtpx"]
9+
[ext_resource type="Script" uid="uid://cp6t6haqyef7o" path="res://Scenes/AreaBasedBackground.cs" id="7_6k2qj"]
910
[ext_resource type="Texture2D" uid="uid://dbjotl0v1ymia" path="res://SharedAssets/BattleFrame1.png" id="7_klvil"]
1011
[ext_resource type="Theme" uid="uid://d37e3tpsbxwak" path="res://Scenes/UI/Assets/GeneralTheme.tres" id="8_62qim"]
1112

@@ -18,9 +19,10 @@ gradient = SubResource("Gradient_8uy3a")
1819
fill_from = Vector2(1, 0)
1920
fill_to = Vector2(0.738532, 1)
2021

21-
[node name="ProtoBattleDirector" type="Node2D" node_paths=PackedStringArray("PuppetMarkers", "CD", "CM", "NPB", "Audio", "_focusedButton")]
22+
[node name="ProtoBattleDirector" type="Node2D" node_paths=PackedStringArray("BackgroundRect", "PuppetMarkers", "CD", "CM", "NPB", "Audio", "_focusedButton")]
2223
process_mode = 1
2324
script = ExtResource("1_jmdo1")
25+
BackgroundRect = NodePath("BackGround")
2426
PuppetMarkers = [NodePath("PlayerMarker"), NodePath("Enemy1Marker"), NodePath("Enemy2Marker"), NodePath("Enemy3Marker")]
2527
CD = NodePath("Conductor")
2628
CM = NodePath("SubViewport")
@@ -73,6 +75,7 @@ z_index = -1
7375
offset_right = 640.0
7476
offset_bottom = 178.0
7577
texture = ExtResource("6_0jtpx")
78+
script = ExtResource("7_6k2qj")
7679

7780
[node name="BattleFrame" type="TextureRect" parent="."]
7881
z_index = 1

Scenes/ChestScene/ChestScene.tscn

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
[gd_scene load_steps=10 format=3 uid="uid://c4vmb783d3v03"]
1+
[gd_scene load_steps=11 format=3 uid="uid://c4vmb783d3v03"]
22

33
[ext_resource type="Script" uid="uid://cetn71kolbrmg" path="res://Scenes/ChestScene/ChestScene.cs" id="1_ardd2"]
44
[ext_resource type="AudioStream" uid="uid://be5ial13ynf3o" path="res://Audio/Song1.ogg" id="2_x78jo"]
55
[ext_resource type="Script" uid="uid://pl57giqyhckb" path="res://Scenes/UI/Scripts/MenuModule.cs" id="3_5uvci"]
6+
[ext_resource type="Script" uid="uid://cp6t6haqyef7o" path="res://Scenes/AreaBasedBackground.cs" id="5_u0wcg"]
67
[ext_resource type="Shader" uid="uid://dp36iuuy414k1" path="res://SharedAssets/StarryNight.gdshader" id="5_whthd"]
78
[ext_resource type="Texture2D" uid="uid://qhwve7fik4do" path="res://SharedAssets/BackGround_Full.png" id="6_37nar"]
89
[ext_resource type="Texture2D" uid="uid://d0ywqw1j1k71v" path="res://Scenes/ChestScene/Assets/Chest.png" id="6_58hf4"]
@@ -16,11 +17,12 @@ shader_parameter/bg_bottom_color = Vector4(0.028, 0.008, 0.184, 0)
1617
shader_parameter/gradient_ratio = 1.0
1718
shader_parameter/time_scale = 1.0
1819

19-
[node name="ChestScene" type="Node2D" node_paths=PackedStringArray("ChestButton", "PlayerMarker")]
20+
[node name="ChestScene" type="Node2D" node_paths=PackedStringArray("ChestButton", "PlayerMarker", "BackgroundRect")]
2021
process_mode = 1
2122
script = ExtResource("1_ardd2")
2223
ChestButton = NodePath("CenterContainer/VBoxContainer/ChestButton")
2324
PlayerMarker = NodePath("PlayerMarker")
25+
BackgroundRect = NodePath("BackGround")
2426

2527
[node name="AudioStreamPlayer" type="AudioStreamPlayer" parent="."]
2628
stream = ExtResource("2_x78jo")
@@ -38,6 +40,7 @@ z_index = -1
3840
offset_right = 640.0
3941
offset_bottom = 178.0
4042
texture = ExtResource("6_37nar")
43+
script = ExtResource("5_u0wcg")
4144

4245
[node name="BattleFrame" type="TextureRect" parent="."]
4346
z_index = 1

0 commit comments

Comments
 (0)