Hlavní menu, synchronizace jmen hráčů. Client hru spustí až ve chvíli kdy dostane správný packet. Oprava bugu v se scalováním UIElementu
This commit is contained in:
parent
e6128dc9f5
commit
7656707177
19 changed files with 315 additions and 53 deletions
|
|
@ -5,11 +5,13 @@
|
|||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ADictionary_00602_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F5e56f40aa42e4fc4b94786ec57da7544d1a400_003F07_003F804b4506_003FDictionary_00602_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AEnumerable_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F419320464d0849fb89a7e518f7ff8bc978a00_003Fe8_003F1faf66e3_003FEnumerable_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AEventChannel_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F384e456bc26f45f5a6a6a20ae50c6e0dd1a400_003Ffb_003Fca10f160_003FEventChannel_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AGame_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fa69b121f85054691b2a8d28643003c23136600_003Fc7_003F517f8541_003FGame_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AINetSerializable_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F3d47105f47a240929625d0f531812b9e1c000_003F0f_003Fe2eeb2cd_003FINetSerializable_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AKeyValuePair_00602_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F384e456bc26f45f5a6a6a20ae50c6e0dd1a400_003Fe8_003F7272ae72_003FKeyValuePair_00602_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AList_00601_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F5e56f40aa42e4fc4b94786ec57da7544d1a400_003Fe4_003F9c3fcf71_003FList_00601_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ANetManager_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F3d47105f47a240929625d0f531812b9e1c000_003Fd6_003Fec041615_003FNetManager_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ANetSerializer_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F3d47105f47a240929625d0f531812b9e1c000_003Fcc_003F8a34584a_003FNetSerializer_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AThread_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F5e56f40aa42e4fc4b94786ec57da7544d1a400_003Fb3_003F92670209_003FThread_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AThrowHelper_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F5e56f40aa42e4fc4b94786ec57da7544d1a400_003Ffb_003Fa0fd6fc3_003FThrowHelper_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ATitleContainer_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fa69b121f85054691b2a8d28643003c23136600_003F62_003F374a72ad_003FTitleContainer_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AValueTuple_00602_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F5e56f40aa42e4fc4b94786ec57da7544d1a400_003F09_003F312b9770_003FValueTuple_00602_002Ecs/@EntryIndexedValue">ForceIncluded</s:String></wpf:ResourceDictionary>
|
||||
|
|
@ -2,6 +2,7 @@ using System;
|
|||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Threading;
|
||||
using FNAF_Clone.GUI;
|
||||
using FNAF_Clone.Map;
|
||||
using GlobalClassLib;
|
||||
|
|
@ -12,6 +13,20 @@ using PacketLib;
|
|||
namespace FNAF_Clone;
|
||||
|
||||
public class Client {
|
||||
public enum ConnectionState {
|
||||
IDLE,
|
||||
CONNECTING,
|
||||
CONNECTED,
|
||||
ACCEPTED,
|
||||
GAME_STARTING,
|
||||
GAME_IN_PROGRESS,
|
||||
SERVER_NOT_FOUND,
|
||||
SERVER_FULL,
|
||||
ERROR
|
||||
}
|
||||
|
||||
public static ConnectionState State { get; private set; } = ConnectionState.IDLE;
|
||||
|
||||
private static EventBasedNetListener listener = new();
|
||||
private static NetManager client;
|
||||
private static NetPeer server;
|
||||
|
|
@ -24,6 +39,7 @@ public class Client {
|
|||
public static ClientPlayer GetPlayer(int pid) => Player.state.pid == pid ? Player : Opponent;
|
||||
|
||||
public static void Connect(string endPoint, int port) {
|
||||
State = ConnectionState.CONNECTING;
|
||||
writer = new NetDataWriter();
|
||||
processor = new NetPacketProcessor();
|
||||
|
||||
|
|
@ -32,7 +48,11 @@ public class Client {
|
|||
processor.SubscribeReusable<JoinAcceptPacket>(OnJoinAccept);
|
||||
processor.SubscribeReusable<UpdatePlayerPacket>(OnPlayerUpdate);
|
||||
processor.SubscribeReusable<MapInitPacket>(OnMapInit);
|
||||
processor.SubscribeReusable<OpponentInitPacket>(packet => Opponent.state = packet.state);
|
||||
processor.SubscribeReusable<OpponentInitPacket>(packet => { // TODO: move this to a method
|
||||
Opponent.state = packet.state;
|
||||
Opponent.username = packet.username;
|
||||
State = ConnectionState.GAME_STARTING;
|
||||
});
|
||||
|
||||
client = new NetManager(listener){
|
||||
AutoRecycle = true
|
||||
|
|
@ -48,10 +68,11 @@ public class Client {
|
|||
listener.PeerConnectedEvent += peer => {
|
||||
Console.WriteLine("Connected to Server");
|
||||
server = peer;
|
||||
SendPacket(new JoinPacket {username = "Player1"}, DeliveryMethod.ReliableOrdered);
|
||||
State = ConnectionState.CONNECTED;
|
||||
SendPacket(new JoinPacket {username = Player.username == "" ? "Anonymous" : Player.username}, DeliveryMethod.ReliableOrdered);
|
||||
};
|
||||
|
||||
client.Connect(endPoint, port, ""); // TODO: figure out how keys work
|
||||
new Thread(() => client.Connect(endPoint, port, "")).Start(); // TODO: figure out how keys work
|
||||
}
|
||||
|
||||
public static void SendPacket<T>(T packet, DeliveryMethod deliveryMethod) where T : class, new() {
|
||||
|
|
@ -71,6 +92,7 @@ public class Client {
|
|||
|
||||
private static void OnJoinAccept(JoinAcceptPacket packet) {
|
||||
Console.WriteLine($"Accepted by server, pid: {packet.state.pid}");
|
||||
State = ConnectionState.ACCEPTED;
|
||||
Player.state = packet.state;
|
||||
}
|
||||
|
||||
|
|
@ -83,8 +105,7 @@ public class Client {
|
|||
TileConnectorProjection[] connectors = connectorsData.Select(c => new TileConnectorProjection(ClientMapManager.Get(c.id1), ClientMapManager.Get(c.id2), c.type)).ToArray();
|
||||
ClientMapManager.InitConnectors(connectors);
|
||||
|
||||
UIManager.InitUI();
|
||||
UIManager.SpawnDoors(connectors.Where(c => c.Type == ConnectorType.DOOR_REMOTE).ToArray());
|
||||
UIManager.SpawnMapElements(connectors.Where(c => c.Type == ConnectorType.DOOR_REMOTE).ToArray());
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ public class CommandManager {
|
|||
Array.ForEach(keybinds, tuple => InputManager.AddListener(tuple.label, tuple.key, () => tuple.action(), InputTiming.PRESS, allControlsHook));
|
||||
}
|
||||
|
||||
public static void AllowInput(bool state) {
|
||||
public static void AllowGameControls(bool state) {
|
||||
allControlsHook.Enabled = state;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ with.
|
|||
Size is a float value, measured in points. Modify this value to change
|
||||
the size of the font.
|
||||
-->
|
||||
<Size>20</Size>
|
||||
<Size>40</Size>
|
||||
|
||||
<!--
|
||||
Spacing is a float value, measured in pixels. Modify this value to change
|
||||
|
|
|
|||
|
|
@ -101,6 +101,11 @@ public class EventProcessor {
|
|||
if(Client.Player.state.pid == e.Args[0]) UIManager.ShowVictoryScreen();
|
||||
break;
|
||||
|
||||
case 12:
|
||||
Console.WriteLine($"E: Game started");
|
||||
UIManager.DisplayGameUI();
|
||||
UIManager.StartTimer();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
37
FNAF_Clone/GUI/LoadingUIElement.cs
Normal file
37
FNAF_Clone/GUI/LoadingUIElement.cs
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace FNAF_Clone.GUI;
|
||||
|
||||
public class LoadingUIElement : TextUIElement {
|
||||
private string expectedEndpoint;
|
||||
private Client.ConnectionState lastState = Client.ConnectionState.IDLE;
|
||||
|
||||
public LoadingUIElement(Point corner1, SpriteFont font, string expectedEndpoint, Alignment alignment = Alignment.CENTER, bool autoBounds = true) : base(corner1, font, alignment, autoBounds) {
|
||||
this.expectedEndpoint = expectedEndpoint;
|
||||
Active = true;
|
||||
// Color = Color.LightGray;
|
||||
}
|
||||
|
||||
public override void Update() {
|
||||
if(lastState == Client.State) return;
|
||||
lastState = Client.State;
|
||||
|
||||
switch (Client.State){
|
||||
case Client.ConnectionState.CONNECTING:
|
||||
Text = "Connecting to " + expectedEndpoint;
|
||||
break;
|
||||
case Client.ConnectionState.CONNECTED:
|
||||
Text = "Connected to " + expectedEndpoint;
|
||||
break;
|
||||
case Client.ConnectionState.ACCEPTED:
|
||||
Text = "Waiting for opponent...";
|
||||
break;
|
||||
case Client.ConnectionState.GAME_STARTING:
|
||||
Text = "Opponent: " + Client.Opponent.username;
|
||||
Color = Color.White;
|
||||
// ScaleMultiplier = 1.5f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
45
FNAF_Clone/GUI/MenuInputField.cs
Normal file
45
FNAF_Clone/GUI/MenuInputField.cs
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using MonoGameLibrary.Graphics;
|
||||
|
||||
namespace FNAF_Clone.GUI;
|
||||
|
||||
public class MenuInputField : UIElement {
|
||||
private TextUIElement labelElement;
|
||||
private TextBoxUIElement textBoxElement;
|
||||
|
||||
public MenuInputField(SpriteFont font, Point position, string label, string defaultValue = "") : base(position, position) {
|
||||
labelElement =
|
||||
new TextUIElement(position, font){Text = label, Color = Color.Gray};
|
||||
textBoxElement =
|
||||
new TextBoxUIElement(font,
|
||||
new(labelElement.Bounds.Item1.X + (int)labelElement.Measure().X, labelElement.Bounds.Item1.Y),
|
||||
new(640, labelElement.Bounds.Item2.Y + (int)labelElement.Measure().Y));
|
||||
textBoxElement.OnFocused = () => {
|
||||
textBoxElement.Color = Color.LightGreen;
|
||||
labelElement.Color = Color.DarkGreen;
|
||||
};
|
||||
textBoxElement.OnUnfocused = () => {
|
||||
textBoxElement.Color = Color.White;
|
||||
labelElement.Color = Color.Gray;
|
||||
};
|
||||
|
||||
Bounds = (labelElement.Bounds.Item1, textBoxElement.Bounds.Item2);
|
||||
Pressable = true;
|
||||
OnMousePress = textBoxElement.OnMousePress;
|
||||
textBoxElement.Text = defaultValue;
|
||||
}
|
||||
|
||||
public string Text => textBoxElement.Text;
|
||||
|
||||
public override void Draw(SpriteBatch spriteBatch) {
|
||||
labelElement.Draw(spriteBatch);
|
||||
textBoxElement.Draw(spriteBatch);
|
||||
}
|
||||
|
||||
public override void Update() {
|
||||
base.Update();
|
||||
labelElement.Update();
|
||||
textBoxElement.Update();
|
||||
}
|
||||
}
|
||||
|
|
@ -4,4 +4,6 @@ namespace FNAF_Clone.GUI;
|
|||
|
||||
public static class PointExtensions {
|
||||
public static Point MultiplyByScalar(this Point point, int scalar) => new(point.X * scalar, point.Y * scalar);
|
||||
public static Point MultiplyByScalar(this Point point, float scalar) => new((int)(point.X * scalar), (int)(point.Y * scalar));
|
||||
|
||||
}
|
||||
|
|
@ -27,9 +27,8 @@ public class Screen {
|
|||
if (CurrentScreen.temporary){
|
||||
Screens.Remove(CurrentScreen.Label);
|
||||
}
|
||||
else if (CurrentScreen != null){
|
||||
|
||||
CurrentScreen.Active = false;
|
||||
}
|
||||
CurrentScreen = Screens[id];
|
||||
CurrentScreen.Active = true;
|
||||
}
|
||||
|
|
@ -40,14 +39,20 @@ public class Screen {
|
|||
|
||||
public static void UpdateAll() {
|
||||
foreach (var screen in Screens.Values){
|
||||
// if (!screen.Active) continue;
|
||||
if (!screen.Active) continue;
|
||||
screen.Update();
|
||||
}
|
||||
}
|
||||
public static Screen Empty => new(""){temporary = true};
|
||||
|
||||
public static void SetOverlayScreen(string id) {
|
||||
if (OverlayScreen.temporary){
|
||||
Screens.Remove(OverlayScreen.Label);
|
||||
}
|
||||
|
||||
OverlayScreen.Active = false;
|
||||
OverlayScreen = Screens[id];
|
||||
OverlayScreen.Active = true;
|
||||
}
|
||||
|
||||
public static void DisableOverlay() {
|
||||
|
|
@ -80,8 +85,9 @@ public class Screen {
|
|||
public UIElement this[string id] => elements[id];
|
||||
public UIElement TryGetElement(string id) => elements.TryGetValue(id, out var val) ? val : null;
|
||||
|
||||
public void AddElement(string id, UIElement element) {
|
||||
public UIElement AddElement(string id, UIElement element) {
|
||||
elements.Add(id, element);
|
||||
return element;
|
||||
}
|
||||
|
||||
public void SetActive(bool active) {
|
||||
|
|
|
|||
42
FNAF_Clone/GUI/TextBoxUIElement.cs
Normal file
42
FNAF_Clone/GUI/TextBoxUIElement.cs
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
using System;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using MonoGameLibrary;
|
||||
using MonoGameLibrary.Graphics;
|
||||
using MonoGameLibrary.Input;
|
||||
|
||||
namespace FNAF_Clone.GUI;
|
||||
|
||||
public class TextBoxUIElement : TextUIElement {
|
||||
public bool Focused{ get; set; } = false;
|
||||
public Action OnFocused{ get; set; } = () => { };
|
||||
public Action OnUnfocused{ get; set; } = () => { };
|
||||
|
||||
public TextBoxUIElement(SpriteFont font, Point corner1, Point corner2) : base(corner1, corner2, font) {
|
||||
Core.Instance.Window.TextInput += TextInputHandler;
|
||||
InputManager.AddListener(InputManager.MouseButton.LEFT, () => {
|
||||
if (!IsWithinBounds(InputManager.MouseState.Position)){
|
||||
Focused = false;
|
||||
OnUnfocused();
|
||||
}
|
||||
},
|
||||
InputTiming.PRESS, new InputListenerHook(true));
|
||||
Pressable = true;
|
||||
|
||||
OnMousePress = () => {
|
||||
Focused = true;
|
||||
OnFocused();
|
||||
};
|
||||
}
|
||||
|
||||
public void TextInputHandler(object sender, TextInputEventArgs e) {
|
||||
if (!Focused) return;
|
||||
if (e.Character == '\b') {
|
||||
if (Text.Length > 0) Text = Text[..^1];
|
||||
return;
|
||||
}
|
||||
|
||||
if(Font.Characters.Contains(e.Character))
|
||||
Text += e.Character;
|
||||
}
|
||||
}
|
||||
|
|
@ -7,11 +7,28 @@ namespace FNAF_Clone.GUI;
|
|||
|
||||
public class TextUIElement : UIElement {
|
||||
public SpriteFont Font { get; set; }
|
||||
public string Text{ get; set; } = "";
|
||||
public Color Color{ get; set; } = Color.White;
|
||||
private Vector2 origin;
|
||||
public Alignment CurrentAlignment { get; set; }
|
||||
|
||||
public TextUIElement(Point corner1, SpriteFont font, Alignment alignment = Alignment.LEFT) : base(corner1, corner1) {
|
||||
public string Text{
|
||||
get;
|
||||
set{
|
||||
field = value;
|
||||
if(AutoBounds)
|
||||
Bounds = (Bounds.Item1, Bounds.Item1 + new Point((int)Measure().X, (int)Measure().Y));
|
||||
}
|
||||
} = "";
|
||||
|
||||
public Color Color{ get; set; } = Color.White;
|
||||
public bool AutoBounds{ get; protected set; } = false;
|
||||
private Vector2 origin;
|
||||
private const float UNIVERSAL_TEXT_SCALE_MULTIPLIER = 0.3f;
|
||||
|
||||
public TextUIElement(Point corner1, SpriteFont font, Alignment alignment = Alignment.LEFT, bool autoBounds = true) : base(corner1, corner1) {
|
||||
Font = font;
|
||||
AutoBounds = autoBounds;
|
||||
Align(alignment);
|
||||
}
|
||||
public TextUIElement(Point corner1, Point corner2, SpriteFont font, Alignment alignment = Alignment.LEFT) : base(corner1, corner2) {
|
||||
Font = font;
|
||||
Align(alignment);
|
||||
}
|
||||
|
|
@ -19,10 +36,11 @@ public class TextUIElement : UIElement {
|
|||
public override void Draw(SpriteBatch spriteBatch) {
|
||||
base.Draw(spriteBatch);
|
||||
align();
|
||||
spriteBatch.DrawString(Font, Text, screenSpaceBounds.Item1.ToVector2(), Color, 0, origin, ScaleMultiplier, SpriteEffects.None, 0);
|
||||
spriteBatch.DrawString(Font, Text, screenSpaceBounds.Item1.ToVector2(), Color, 0, origin, pixelScaleMultiplier * UNIVERSAL_TEXT_SCALE_MULTIPLIER, SpriteEffects.None, 0);
|
||||
}
|
||||
|
||||
public void Align(Alignment alignment) {
|
||||
CurrentAlignment = alignment;
|
||||
switch (alignment){
|
||||
case Alignment.LEFT:
|
||||
AlignLeft();
|
||||
|
|
@ -36,14 +54,23 @@ public class TextUIElement : UIElement {
|
|||
}
|
||||
}
|
||||
|
||||
protected override void UpdateBounds() {
|
||||
Point inSpaceOrigin = Bounds.Item1 + origin.ToPoint();
|
||||
_bounds = ((Bounds.Item1 - inSpaceOrigin).MultiplyByScalar(ScaleMultiplier) + inSpaceOrigin, (Bounds.Item2 - Bounds.Item1).MultiplyByScalar(ScaleMultiplier) + inSpaceOrigin);
|
||||
screenSpaceBounds = (Bounds.Item1.MultiplyByScalar(pixelScaleMultiplier), Bounds.Item2.MultiplyByScalar(pixelScaleMultiplier));
|
||||
Align(CurrentAlignment);
|
||||
}
|
||||
|
||||
public Vector2 Measure() => Font.MeasureString(Text) * UNIVERSAL_TEXT_SCALE_MULTIPLIER * ScaleMultiplier;
|
||||
|
||||
private void AlignLeft() {
|
||||
align = () => origin = Vector2.Zero;
|
||||
}
|
||||
private void AlignRight() {
|
||||
align = () => origin = Font.MeasureString(Text);
|
||||
align = () => origin = Font.MeasureString(Text) * ScaleMultiplier;
|
||||
}
|
||||
private void AlignCenter() {
|
||||
align = () => origin = Font.MeasureString(Text) / 2;
|
||||
align = () => origin = new(Font.MeasureString(Text).X * ScaleMultiplier / 2, 0);
|
||||
}
|
||||
|
||||
private Action align;
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ public class TimerUIElement : TextUIElement{
|
|||
private Stopwatch stopwatch = new();
|
||||
|
||||
|
||||
public TimerUIElement(Point corner1, SpriteFont font) : base(corner1, font) {
|
||||
public TimerUIElement(Point corner1, SpriteFont font) : base(corner1, corner1, font) {
|
||||
Text = "00:00.000";
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,10 +14,11 @@ public class UIElement {
|
|||
public bool Pressable { get; set; } = false;
|
||||
public bool Visible { get; set; } = true;
|
||||
|
||||
protected (Point, Point) _bounds;
|
||||
public (Point, Point) Bounds{
|
||||
get;
|
||||
private set { field = value; UpdateBounds(); }
|
||||
} // TODO: Change this to support non-rectangular hitboxes
|
||||
get => _bounds;
|
||||
protected set { _bounds = value; UpdateBounds(); }
|
||||
}
|
||||
|
||||
protected (Point, Point) screenSpaceBounds;
|
||||
public List<TextureRegion> Textures = new();
|
||||
|
|
@ -33,13 +34,14 @@ public class UIElement {
|
|||
LoadPixelScaleMultiplier();
|
||||
}
|
||||
}
|
||||
private int pixelScaleMultiplier = 1;
|
||||
protected int pixelScaleMultiplier = 1;
|
||||
private void LoadPixelScaleMultiplier() {
|
||||
pixelScaleMultiplier = (int)(UIManager.GlobalPixelMultiplier * _scaleMultiplier); // TODO: move GlobalPixelMultiplier somewhere where it would make sense
|
||||
UpdateBounds();
|
||||
}
|
||||
|
||||
private void UpdateBounds() {
|
||||
protected virtual void UpdateBounds() {
|
||||
_bounds = (Bounds.Item1, (Bounds.Item2 - Bounds.Item1).MultiplyByScalar(ScaleMultiplier) + Bounds.Item1);
|
||||
screenSpaceBounds = (Bounds.Item1.MultiplyByScalar(pixelScaleMultiplier), Bounds.Item2.MultiplyByScalar(pixelScaleMultiplier));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading;
|
||||
using FNAF_Clone.Map;
|
||||
using GlobalClassLib;
|
||||
using Microsoft.Xna.Framework;
|
||||
|
|
@ -20,6 +21,8 @@ public class UIManager {
|
|||
public const string OVERLAY = "overlay";
|
||||
public const string WIN = "win";
|
||||
public const string LOSE = "lose";
|
||||
public const string MENU = "menu";
|
||||
public const string LOADING = "loading";
|
||||
}
|
||||
|
||||
private static Screen officeScreen = new(ScreenTypes.OFFICE);
|
||||
|
|
@ -27,6 +30,8 @@ public class UIManager {
|
|||
private static Screen overlayScreen = new(ScreenTypes.OVERLAY);
|
||||
private static Screen winScreen = new(ScreenTypes.WIN);
|
||||
private static Screen loseScreen = new(ScreenTypes.LOSE);
|
||||
private static Screen menuScreen = new(ScreenTypes.MENU);
|
||||
private static Screen loadingScreen = new(ScreenTypes.LOADING);
|
||||
|
||||
private static TextureAtlas testAtlas;
|
||||
public static TextureAtlas OfficeAtlas{ get; private set; }
|
||||
|
|
@ -42,18 +47,20 @@ public class UIManager {
|
|||
|
||||
private static InputListenerHook monitorSwitchHook;
|
||||
|
||||
public static void InitUI() {
|
||||
GlobalPixelMultiplier = Core.graphicsDevice.Viewport.Height / 360;
|
||||
|
||||
testAtlas = TextureAtlas.FromFile(Core.content, "images/testBlocks-definition.xml"); // TODO: move this to its own method
|
||||
public static void LoadAssets() {
|
||||
testAtlas = TextureAtlas.FromFile(Core.content, "images/testBlocks-definition.xml");
|
||||
OfficeAtlas = TextureAtlas.FromFile(Core.content, "images/office-definition.xml");
|
||||
MonitorAtlas = TextureAtlas.FromFile(Core.content, "images/monitor-definition.xml");
|
||||
EnemyAtlas = TextureAtlas.FromFile(Core.content, "images/enemies-definition.xml");
|
||||
PixelMonoFont = Core.content.Load<SpriteFont>("ponderosa");
|
||||
}
|
||||
|
||||
Screen.AddScreens([officeScreen, monitorScreen, overlayScreen, winScreen, loseScreen]);
|
||||
Screen.SetScreen(ScreenTypes.OFFICE);
|
||||
Screen.SetOverlayScreen(ScreenTypes.OVERLAY);
|
||||
public static void InitUI() {
|
||||
GlobalPixelMultiplier = Core.graphicsDevice.Viewport.Height / 360;
|
||||
|
||||
Screen.AddScreens([officeScreen, monitorScreen, overlayScreen, winScreen, loseScreen, menuScreen, loadingScreen]);
|
||||
// Screen.SetScreen(ScreenTypes.OFFICE);
|
||||
// Screen.SetOverlayScreen(ScreenTypes.OVERLAY);
|
||||
|
||||
officeScreen.AddElement("office_left", new UIElement([OfficeAtlas[3], OfficeAtlas[0]], Point.Zero));
|
||||
officeScreen.AddElement("office_centre", new UIElement([OfficeAtlas[4], OfficeAtlas[1]], new Point(200, 0)));
|
||||
|
|
@ -69,6 +76,74 @@ public class UIManager {
|
|||
monitorScreen.AddElement("map-frame", new UIElement(MonitorAtlas[2], new Point(334, 135)));
|
||||
monitorScreen.AddElement("map", new UIElement(MonitorAtlas[3], new Point(334, 135)));
|
||||
|
||||
|
||||
timerElement = new(new(0, 0), PixelMonoFont);
|
||||
overlayScreen.AddElement("timer", timerElement);
|
||||
|
||||
winScreen.AddElement("win-text", new TextUIElement(new(320, 180), PixelMonoFont, TextUIElement.Alignment.CENTER){Text = "YOU WIN", Color = Color.Green});
|
||||
loseScreen.AddElement("lose-text", new TextUIElement(new(320, 180), PixelMonoFont, TextUIElement.Alignment.CENTER){Text = "YOU LOSE", Color = Color.Red});
|
||||
|
||||
// overlayScreen.AddElement("test", new TextBoxUIElement(PixelMonoFont, Point.Zero, new(200, 100)));
|
||||
|
||||
// Main menu
|
||||
// TextUIElement serverIpLabel = (TextUIElement) menuScreen.AddElement("server-ip-label", new TextUIElement(new (20, 20), PixelMonoFont){Text = "ENTER SERVER IP: ", Color = Color.Gray});
|
||||
// TextBoxUIElement serverIpTextBox = (TextBoxUIElement)menuScreen.AddElement("server-ip-textbox",
|
||||
// new TextBoxUIElement(PixelMonoFont,
|
||||
// new(serverIpLabel.Bounds.Item1.X + (int)serverIpLabel.Measure().X, serverIpLabel.Bounds.Item1.Y),
|
||||
// new(640, serverIpLabel.Bounds.Item2.Y + (int)serverIpLabel.Measure().Y)));
|
||||
// serverIpTextBox.OnFocused = () => {
|
||||
// serverIpTextBox.Color = Color.LightGreen;
|
||||
// serverIpLabel.Color = Color.DarkGreen;
|
||||
// };
|
||||
// serverIpTextBox.OnUnfocused = () => {
|
||||
// serverIpTextBox.Color = Color.White;
|
||||
// serverIpLabel.Color = Color.Gray;
|
||||
// };
|
||||
|
||||
|
||||
MenuInputField usernameField = (MenuInputField)menuScreen.AddElement("username-field", new MenuInputField(PixelMonoFont, new(20, 20), "USERNAME: "));
|
||||
MenuInputField field = (MenuInputField)menuScreen.AddElement("server-ip-field", new MenuInputField(PixelMonoFont, new(usernameField.Bounds.Item1.X, usernameField.Bounds.Item2.Y + 20), "SERVER IP: ", "127.0.0.1"));
|
||||
UIElement connectButton = menuScreen.AddElement("server-ip-submit", new TextUIElement(new Point(field.Bounds.Item1.X, field.Bounds.Item2.Y), PixelMonoFont)
|
||||
{
|
||||
Text = "CONNECT",
|
||||
Pressable = true,
|
||||
OnMousePress = () => {
|
||||
// string[] input = serverIpTextBox.Text.Split(":");
|
||||
// if(input.Length != 2 || !int.TryParse(input[0], out var port)) return;
|
||||
// Client.Connect(input[0], port);
|
||||
Client.Player.username = usernameField.Text;
|
||||
Client.Connect(field.Text, 9012);
|
||||
Screen.SetScreen(ScreenTypes.LOADING);
|
||||
}
|
||||
});
|
||||
menuScreen.AddElement("host-button",
|
||||
new TextUIElement(new(connectButton.Bounds.Item1.X, connectButton.Bounds.Item2.Y + 30), PixelMonoFont) {Text = "HOST"});
|
||||
|
||||
|
||||
loadingScreen.AddElement("loading-text", new LoadingUIElement(new(320, 180), PixelMonoFont, field.Text));
|
||||
|
||||
}
|
||||
|
||||
public static void DisplayMainMenu() {
|
||||
Screen.SetScreen(ScreenTypes.MENU);
|
||||
CommandManager.AllowGameControls(false);
|
||||
}
|
||||
|
||||
|
||||
public static void DisplayGameUI() {
|
||||
Screen.SetScreen(ScreenTypes.OFFICE);
|
||||
Screen.SetOverlayScreen(ScreenTypes.OVERLAY);
|
||||
|
||||
CommandManager.AllowGameControls(true);
|
||||
UpdateCameras([Client.Player.state.camera]); // in case there is an enemy on the default camera
|
||||
|
||||
}
|
||||
public static void StartTimer() {
|
||||
timerElement.Start();
|
||||
}
|
||||
|
||||
public static void SpawnMapElements(TileConnectorProjection[] doors) {
|
||||
|
||||
for (int i = 0; i < 5; i++){ // NOTE: this loop does y in reverse, y labels are inverted to match server
|
||||
for (int j = 0; j < 5; j++){
|
||||
int i1 = i;
|
||||
|
|
@ -87,17 +162,6 @@ public class UIManager {
|
|||
monitorScreen.AddElement("eye-player", new UIElement(MonitorAtlas[24], monitorScreen["room"+Client.Player.state.camera].Bounds.Item1));
|
||||
monitorScreen.AddElement("eye-opponent", new UIElement([MonitorAtlas[23], MonitorAtlas[22]], monitorScreen["room"+Client.Opponent.state.camera].Bounds.Item1));
|
||||
|
||||
timerElement = new(new(0, 0), PixelMonoFont);
|
||||
overlayScreen.AddElement("timer", timerElement);
|
||||
timerElement.Start();
|
||||
|
||||
winScreen.AddElement("win-text", new TextUIElement(new(320, 180), PixelMonoFont, TextUIElement.Alignment.CENTER){Text = "YOU WIN", Color = Color.Green});
|
||||
loseScreen.AddElement("lose-text", new TextUIElement(new(320, 180), PixelMonoFont, TextUIElement.Alignment.CENTER){Text = "YOU LOSE", Color = Color.Red});
|
||||
|
||||
UpdateCameras([Client.Player.state.camera]);
|
||||
}
|
||||
|
||||
public static void SpawnDoors(TileConnectorProjection[] doors) {
|
||||
foreach (var door in doors){
|
||||
if(door.Type != ConnectorType.DOOR_REMOTE) continue;
|
||||
|
||||
|
|
@ -214,13 +278,13 @@ public class UIManager {
|
|||
public static void ShowVictoryScreen() {
|
||||
Screen.SetScreen(ScreenTypes.WIN);
|
||||
Screen.DisableOverlay();
|
||||
CommandManager.AllowInput(false);
|
||||
CommandManager.AllowGameControls(false);
|
||||
}
|
||||
|
||||
public static void ShowDeathScreen() {
|
||||
Screen.SetScreen(ScreenTypes.LOSE);
|
||||
Screen.DisableOverlay();
|
||||
CommandManager.AllowInput(false);
|
||||
CommandManager.AllowGameControls(false);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -14,18 +14,21 @@ public class GameMain() : Core("fnafkooo", 1280, 720, false) {
|
|||
// private GraphicsDeviceManager _graphics;
|
||||
// private SpriteBatch _spriteBatch;
|
||||
|
||||
|
||||
protected override void Initialize() {
|
||||
Client.Connect("127.0.0.1", 9012);
|
||||
// Client.Connect("127.0.0.1", 9012);
|
||||
CommandManager.InitInputListeners();
|
||||
|
||||
// InputManager.AddListener(InputManager.MouseButton.LEFT, (() => Console.WriteLine("LMB pressed at: " + InputManager.MouseState.Position)), InputTiming.PRESS, new InputListenerHook(true));
|
||||
|
||||
base.Initialize();
|
||||
|
||||
// UIManager.InitUI();
|
||||
UIManager.InitUI();
|
||||
UIManager.DisplayMainMenu();
|
||||
}
|
||||
|
||||
protected override void LoadContent() {
|
||||
UIManager.LoadAssets();
|
||||
// spriteBatch = new SpriteBatch(GraphicsDevice);
|
||||
// font = Content.Load<SpriteFont>("font");
|
||||
}
|
||||
|
|
@ -40,6 +43,8 @@ public class GameMain() : Core("fnafkooo", 1280, 720, false) {
|
|||
InputManager.NextInputCycle();
|
||||
Screen.UpdateAll();
|
||||
|
||||
if(Client.State == Client.ConnectionState.IDLE) return;
|
||||
|
||||
Client.Update();
|
||||
base.Update(gameTime);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,11 +34,13 @@ public class GameLogic {
|
|||
Server.SendPacket(new MapInitPacket{Connectors = connectorsConverted, UpsideDown = false}, Server.P1.peer);
|
||||
Server.SendPacket(new MapInitPacket{Connectors = connectorsConverted, UpsideDown = true}, Server.P2.peer);
|
||||
|
||||
EnemyManager.AddEnemy(new LurkEnemy(10)).Spawn(MapManager.Get(12));
|
||||
EnemyManager.AddEnemy(new LurkEnemy(0)).Spawn(MapManager.Get(12));
|
||||
EnemyManager.AddEnemy(new NekoEnemy(0)).Spawn(MapManager.Get(2));
|
||||
EnemyManager.AddEnemy(new SpotEnemy(0)).Spawn(MapManager.Get(12));
|
||||
EnemyManager.AddEnemy(new SpotEnemy(10)).Spawn(MapManager.Get(12));
|
||||
|
||||
Thread.Sleep(3000);
|
||||
secondCycleTimer.Start();
|
||||
Server.SendUpdateToAll([GameEvent.GAME_START()]);
|
||||
}
|
||||
public static void Update() {
|
||||
if(secondCycleTimer.Check()) NSecondUpdate = true;
|
||||
|
|
|
|||
|
|
@ -123,8 +123,8 @@ public class Server {
|
|||
SendPacket(new JoinAcceptPacket { state = newPlayer.state }, peer);
|
||||
P2 = newPlayer;
|
||||
|
||||
SendPacket(new OpponentInitPacket{state = newPlayer.state}, P1.peer);
|
||||
SendPacket(new OpponentInitPacket{state = P1.state}, P2.peer);
|
||||
SendPacket(new OpponentInitPacket{state = newPlayer.state, username = newPlayer.username}, P1.peer);
|
||||
SendPacket(new OpponentInitPacket{state = P1.state, username = P1.username}, P2.peer);
|
||||
GameLogic.Init();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ public struct GameEvent : INetSerializable{
|
|||
public static GameEvent SPOT_SET_ACTIVE(int enemyId, bool state) => new(){ ID = 10, Args = [enemyId, state ? 1 : 0] };
|
||||
|
||||
public static GameEvent PLAYER_WIN(int pid) => new(){ID = 11, Args = [pid]};
|
||||
public static GameEvent GAME_START() => new(){ID = 12};
|
||||
|
||||
public int ID{ get; set; }
|
||||
public bool Hideable => ID < 0;
|
||||
|
|
|
|||
|
|
@ -2,4 +2,5 @@ namespace PacketLib;
|
|||
|
||||
public class OpponentInitPacket {
|
||||
public PlayerState state { get; set; }
|
||||
public string username { get; set; }
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue