1
Fork 0
mirror of https://github.com/Steffo99/better-tee.git synced 2024-11-27 17:14:18 +00:00
This commit is contained in:
Steffo 2019-09-19 12:28:02 +02:00
parent 8bd953ddfa
commit 40a7c5c6f8
81 changed files with 1333 additions and 1040 deletions

View file

@ -1,88 +0,0 @@
using System;
using UnityEngine;
using UnityEngine.EventSystems;
public abstract class ActController : MonoBehaviour
{
[Header("Settings")]
public ActSettings settings = null;
protected ActPhase phase = ActPhase.NONE;
[Header("Results")]
public ActResults results = null;
[Header("Objects")]
public Canvas canvas = null;
public EventSystem eventSystem = null;
[Serializable]
public class InvalidPhaseException : Exception {
public readonly ActPhase currentPhase;
public InvalidPhaseException(ActPhase currentPhase) {
this.currentPhase = currentPhase;
}
};
[Serializable]
public class MissingSettingsException : Exception {};
public ActPhase Phase { get; }
/// <summary>
/// Call this to initialize the Act (GameObjects, ActSettings, etc). All interactable components should be disabled in this phase.
/// </summary>
public virtual void ActInit() {
phase = ActPhase.INIT;
canvas = GameObject.FindGameObjectWithTag("Canvas")?.GetComponent<Canvas>();
eventSystem = GameObject.FindGameObjectWithTag("EventSystem")?.GetComponent<EventSystem>();
if(settings == null) {
throw new MissingSettingsException();
}
}
/// <summary>
/// Call this to enable all interactable components in the Act. It should be called when the player is ready to play.
/// </summary>
public virtual void ActStart() {
if(Phase != ActPhase.INIT) throw new InvalidPhaseException(phase);
phase = ActPhase.START;
}
/// <summary>
/// Call this to disable once again all interactable components in the Act. It should be called when the Act is finished (time ran out, player reached submission limit, etc).
/// </summary>
public virtual void ActEnd() {
if(Phase != ActPhase.START) throw new InvalidPhaseException(phase);
phase = ActPhase.END;
}
/// <summary>
/// Call this to cleanup all GameObjects created during the Init phase.
/// </summary>
public virtual void ActCleanup() {
if(Phase != ActPhase.END) {
Debug.LogWarningFormat("ActCleanup() was called during {0}", Phase);
}
phase = ActPhase.CLEANUP;
}
protected virtual void Awake() {
}
protected virtual void Start() {
}
protected virtual void Update() {
}
protected virtual void OnDestroy() {
ActCleanup();
}
}

View file

@ -1,6 +1,7 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: c059168d0dc57204b9d45701d0fc25a0 guid: c1b50fe5123a21e44ac5f1d6f24daef2
TextScriptImporter: folderAsset: yes
DefaultImporter:
externalObjects: {} externalObjects: {}
userData: userData:
assetBundleName: assetBundleName:

View file

@ -0,0 +1,22 @@
using System;
[Serializable]
public class ConnectedPlayerData {
public string name;
public int id;
}
public class ConnectedPlayer {
public string name;
public int id;
public ConnectedPlayerData Data {
get {
return new ConnectedPlayerData {
name = this.name,
id = this.id
};
}
}
}

View file

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using UnityEngine;
[Serializable]
public class DrawingSettings : ActSettings {
public Color startingColor = Color.white;
public Color[] palette = null;
public float timeLimit = 99f;
public string actName = "Untitled";
public string actDescription = "This Act is missing a description.";
public string destinationPool = "default";
}

View file

@ -1,3 +1,6 @@
using System;
[Serializable]
public enum GamePhase { public enum GamePhase {
UNINTIALIZED, UNINTIALIZED,
LOBBY, LOBBY,

View file

@ -1,5 +1,4 @@
using System; using System;
using System.Collections.Generic;
[Serializable] [Serializable]

View file

@ -0,0 +1,65 @@
using Mirror;
namespace BetterTee.NetMsg
{
namespace Server
{
namespace Error {
public class InvalidPassword : MessageBase {}
public class GameAlreadyStarted : MessageBase {}
}
public class LobbyStatusChange : MessageBase {
public ConnectedPlayerData[] players;
public ConnectedViewerData[] viewers;
}
public class LobbyEnd : MessageBase
{
public ConnectedPlayerData[] players;
}
public class ActInit : MessageBase
{
public ActSettings settings;
}
public class ActStart : MessageBase {}
public class ActEnd : MessageBase {}
public class GameEnd : MessageBase
{
public ConnectedPlayerData[] leaderboard;
}
}
namespace Client
{
public class PlayerJoin : MessageBase
{
public string playerName;
public string gamePassword;
}
public class ActResults : MessageBase
{
public ActResults results;
}
}
namespace Viewer
{
public class ViewerLink : MessageBase
{
public string viewerName;
public string gamePassword;
}
public class Settings : MessageBase
{
public GameSettings settings;
}
}
}

View file

@ -1,5 +1,4 @@
using System; using System;
using System.Collections.Generic;
[Serializable] [Serializable]

View file

@ -0,0 +1,10 @@
using System;
[Serializable]
public class TypingSettings : ActSettings {
public float timeLimit = 99f;
public string actName = "Untitled";
public string actDescription = "This Act is missing a description.";
public string destinationPool = "default";
}

View file

@ -1,12 +0,0 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DrawTool : MonoBehaviour
{
protected DrawableFrame frame;
protected virtual void Start() {
frame = GetComponent<DrawableFrame>();
}
}

View file

@ -1,75 +0,0 @@
using UnityEngine;
public class DrawableFrame : MonoBehaviour
{
[Header("Configuration")]
public Vector2Int resolution;
public Color startingColor = Color.white;
[Header("State")]
public bool interactable = false;
public bool hasChanged = false;
[Header("References")]
protected Texture2D texture = null;
protected Sprite sprite = null;
protected SpriteRenderer spriteRenderer;
public Rect Bounds {
get {
return new Rect(transform.position.x - (transform.localScale.x / 2),
transform.position.y - (transform.localScale.y / 2),
transform.localScale.x,
transform.localScale.y);
}
}
protected void Start()
{
texture = new Texture2D(resolution.x, resolution.y);
if(resolution.x <= 128 || resolution.y <= 128) {
texture.filterMode = FilterMode.Point;
}
else {
texture.filterMode = FilterMode.Trilinear;
}
Color[] colors = texture.GetPixels();
for(int i = 0; i < colors.Length; i++) {
colors[i] = startingColor;
}
texture.SetPixels(colors);
texture.Apply();
spriteRenderer = GetComponent<SpriteRenderer>();
sprite = Sprite.Create(texture, new Rect(0, 0, resolution.x, resolution.y), new Vector2(0.5f, 0.5f), resolution.x);
spriteRenderer.sprite = sprite;
}
public Color[] GetPixels() {
return texture.GetPixels();
}
public void SetPixels(Color[] colors) {
if(interactable) {
texture.SetPixels(colors);
hasChanged = true;
}
}
public byte[] ToPNG() {
return texture.EncodeToPNG();
}
protected void Update() {
if(hasChanged) {
texture.Apply();
}
}
protected void OnDrawGizmos()
{
Gizmos.DrawWireCube(transform.position, transform.localScale);
}
}

View file

@ -1,106 +0,0 @@
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class DrawingController : ActController
{
[Header("Prefabs")]
public GameObject drawableFramePrefab;
public GameObject paletteButtonPrefab;
public GameObject radiusSliderPrefab;
public GameObject actNamePrefab;
public GameObject actDescriptionPrefab;
public GameObject actTimerPrefab;
[Header("Objects")]
protected PencilTool pencil;
protected DrawableFrame drawableFrame;
protected List<PaletteButton> paletteButtons;
protected RadiusSlider radiusSlider;
protected Text actName;
protected Text actDescription;
protected Timer actTimer;
public override void ActInit() {
base.ActInit();
//Load settings
DrawingSettings drawingSettings = settings as DrawingSettings;
//Create drawable frame
drawableFrame = Instantiate(drawableFramePrefab, transform).GetComponent<DrawableFrame>();
drawableFrame.startingColor = drawingSettings.startingColor;
//Init PencilTool
pencil = drawableFrame.GetComponent<PencilTool>();
try {
pencil.selectedColor = drawingSettings.palette[0];
} catch(ArgumentOutOfRangeException) {
pencil.selectedColor = drawingSettings.startingColor;
}
//Init PaletteButtons
paletteButtons = new List<PaletteButton>();
for(int i = 0; i < drawingSettings.palette.Length; i++) {
PaletteButton button = Instantiate(paletteButtonPrefab, canvas.transform).GetComponent<PaletteButton>();
RectTransform btnTransform = button.GetComponent<RectTransform>();
Image btnImage = button.GetComponent<Image>();
button.pencil = pencil;
btnImage.color = drawingSettings.palette[i];
btnTransform.anchoredPosition = new Vector2(-420 + i * 110, 150);
paletteButtons.Add(button);
}
//Init RadiusSlider
radiusSlider = Instantiate(radiusSliderPrefab, canvas.transform).GetComponent<RadiusSlider>();
radiusSlider.pencil = pencil;
//Init actName Text
actName = Instantiate(actNamePrefab, canvas.transform).GetComponent<Text>();
actName.text = drawingSettings.actName;
//Init actDescription Text
actDescription = Instantiate(actDescriptionPrefab, canvas.transform).GetComponent<Text>();
actDescription.text = drawingSettings.actDescription;
//Init actTimer
actTimer = Instantiate(actTimerPrefab, canvas.transform).GetComponent<Timer>();
actTimer.TimerSet(drawingSettings.timeLimit);
}
public override void ActStart() {
base.ActStart();
//Unlock frame
drawableFrame.interactable = false;
//Start timer
actTimer.OnTimeOut += new Action(ActEnd);
actTimer.TimerStart();
}
public override void ActEnd() {
base.ActEnd();
//Lock frame
drawableFrame.interactable = true;
//Generate results
results = new DrawingResults(drawableFrame.ToPNG());
}
public override void ActCleanup() {
base.ActCleanup();
Destroy(drawableFrame.gameObject);
foreach(PaletteButton button in paletteButtons) {
Destroy(button.gameObject);
}
Destroy(radiusSlider.gameObject);
Destroy(actName.gameObject);
Destroy(actDescription.gameObject);
Destroy(actTimer.gameObject);
}
}

View file

@ -1,24 +0,0 @@
using System;
using System.Collections.Generic;
using UnityEngine;
[Serializable]
public class DrawingSettings : ActSettings {
public Color startingColor = Color.white;
public Color[] palette = null;
public float timeLimit = 99f;
public string actName = "Untitled";
public string actDescription = "This Act is missing a description.";
public string destinationPool = "default";
public DrawingSettings(Color startingColor, Color[] palette, float timeLimit, string actName, string actDescription, string destinationPool) {
this.type = "Drawing";
this.startingColor = startingColor;
this.palette = palette;
this.timeLimit = timeLimit;
this.actName = actName;
this.actDescription = actDescription;
this.destinationPool = destinationPool;
}
}

View file

@ -1,70 +0,0 @@
using Mirror;
namespace NetMessage
{
namespace Error
{
public class InvalidPassword : MessageBase {}
}
namespace Connect
{
public class PlayerJoin : MessageBase
{
public string playerName;
public string gamePassword;
}
public class PlayerJoinSuccessful : MessageBase
{
public Player player;
}
public class ViewerLink : MessageBase
{
public string gamePassword;
}
public class ViewerLinkSuccessful : MessageBase
{
public Viewer viewer;
}
}
namespace Game
{
public class Settings : MessageBase
{
public GameSettings settings;
}
public class Start : MessageBase
{
public Player[] players;
}
public class End : MessageBase
{
public Player[] leaderboard;
}
}
namespace Act
{
public class Init : MessageBase
{
public ActSettings settings;
}
public class Start : MessageBase {}
public class Results : MessageBase
{
public ActResults results;
}
public class End : MessageBase {}
}
}

View file

@ -1,21 +0,0 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class PaletteButton : MonoBehaviour
{
public PencilTool pencil;
protected Image image;
protected void Start()
{
image = GetComponent<Image>();
}
public void OnClick()
{
pencil.selectedColor = image.color;
}
}

View file

@ -1,152 +0,0 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PencilTool : DrawTool
{
public Color selectedColor = Color.black;
public float size = 1f;
protected Color[] colors;
private Vector2Int? previousPixel;
private Vector2Int? pixel;
protected Vector2Int? GetPixelAtScreenPosition(Vector2 screenPosition) {
Vector2 worldPoint = Camera.main.ScreenToWorldPoint(screenPosition);
if(frame.Bounds.Contains(worldPoint)) {
Vector2 normalized = Rect.PointToNormalized(frame.Bounds, worldPoint);
Vector2Int result = new Vector2Int(Mathf.FloorToInt(normalized.x * frame.resolution.x), Mathf.FloorToInt(normalized.y * frame.resolution.y));
return result;
}
return null;
}
protected override void Start() {
base.Start();
colors = frame.GetPixels();
Input.simulateMouseWithTouches = false;
}
protected void Update() {
bool hasChanged = false;
// Touch
foreach(Touch t in Input.touches) {
pixel = GetPixelAtScreenPosition(t.position);
previousPixel = GetPixelAtScreenPosition(t.position - t.deltaPosition);
if(pixel.HasValue) {
if(previousPixel.HasValue) {
DrawBresenhamsThickLine(pixel.Value, previousPixel.Value, size, selectedColor);
}
else {
DrawFilledCircle(pixel.Value, size, selectedColor);
}
}
hasChanged = true;
}
// Mouse
previousPixel = pixel;
if(Input.GetMouseButton(0)) {
pixel = GetPixelAtScreenPosition(Input.mousePosition);
if(pixel.HasValue) {
if(previousPixel.HasValue) {
DrawBresenhamsThickLine(previousPixel.Value, pixel.Value, size, selectedColor);
}
else {
DrawFilledCircle(pixel.Value, size, selectedColor);
}
}
hasChanged = true;
}
else {
pixel = null;
}
if(hasChanged) {
frame.SetPixels(colors);
}
}
protected void DrawPixel(int x, int y, Color color) {
if(x < 0 || x >= frame.resolution.x || y < 0 || y >= frame.resolution.y) return;
colors[x + y*frame.resolution.x] = color;
}
protected void DrawCircleEightPoints(Vector2Int center, int x_radius, int y_radius, Color color) {
DrawPixel(center.x+x_radius, center.y+y_radius, color);
DrawPixel(center.x-x_radius, center.y+y_radius, color);
DrawPixel(center.x+x_radius, center.y-y_radius, color);
DrawPixel(center.x-x_radius, center.y-y_radius, color);
DrawPixel(center.x+y_radius, center.y+x_radius, color);
DrawPixel(center.x-y_radius, center.y+x_radius, color);
DrawPixel(center.x+y_radius, center.y-x_radius, color);
DrawPixel(center.x-y_radius, center.y-x_radius, color);
}
// No idea on how does it work
// https://www.geeksforgeeks.org/bresenhams-circle-drawing-algorithm/
protected void DrawBresenhamEmptyCircle(Vector2Int center, int radius, Color color) {
int x = 0;
int y = radius;
int d = 3 - 2 * radius;
DrawCircleEightPoints(center, x, y, color);
while(y >= x) {
x++;
if(d > 0) {
y--;
d = d + 4 * (x - y) + 10;
}
else {
d = d + 4 * x + 6;
}
DrawCircleEightPoints(center, x, y, color);
}
}
protected void DrawFilledCircle(Vector2Int center, float radius, Color color) {
int x_start = Mathf.CeilToInt((float)center.x - radius);
int x_end = Mathf.CeilToInt((float)center.x + radius);
int y_start = Mathf.CeilToInt((float)center.y - radius);
int y_end = Mathf.CeilToInt((float)center.y + radius);
for(int x = x_start; x < x_end; x++) {
for(int y = y_start; y < y_end; y++) {
if(Vector2Int.Distance(new Vector2Int(x, y), center) < radius) {
DrawPixel(x, y, color);
}
}
}
}
// http://www.roguebasin.com/index.php?title=Bresenham%27s_Line_Algorithm
protected void DrawBresenhamsThickLine(Vector2Int start, Vector2Int end, float radius, Color color) {
int start_x = start.x, start_y = start.y, end_x = end.x, end_y = end.y;
bool steep = Mathf.Abs(end_y - start_y) > Mathf.Abs(end_x - start_x);
if (steep) {
Utils.Swap<int>(ref start_x, ref start_y);
Utils.Swap<int>(ref end_x, ref end_y);
}
if (start_x > end_x) {
Utils.Swap<int>(ref start_x, ref end_x);
Utils.Swap<int>(ref start_y, ref end_y);
}
int dX = (end_x - start_x), dY = Mathf.Abs(end_y - start_y), err = (dX / 2), ystep = (start_y < end_y ? 1 : -1), y = start_y;
for (int x = start_x; x <= end_x; ++x)
{
if(steep) {
DrawFilledCircle(new Vector2Int(y, x), radius, color);
}
else {
DrawFilledCircle(new Vector2Int(x, y), radius, color);
}
err = err - dY;
if (err < 0) { y += ystep; err += dX; }
}
}
protected void Apply() {
}
}

View file

@ -1,7 +0,0 @@
using System;
[Serializable]
public struct Player {
public string name;
public int id;
}

8
Assets/Code/Player.meta Normal file
View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 38dcaa329b85fc447b2976e3c6d8fcd9
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,93 @@
using System;
using UnityEngine;
using UnityEngine.EventSystems;
namespace BetterTee.Player
{
public abstract class ActController : MonoBehaviour
{
[Header("Settings")]
public ActSettings settings = null;
protected ActPhase phase = ActPhase.NONE;
[Header("Results")]
public ActResults results = null;
[Header("Objects")]
public Canvas canvas = null;
public EventSystem eventSystem = null;
[Serializable]
public class InvalidPhaseException : Exception {
public readonly ActPhase currentPhase;
public InvalidPhaseException(ActPhase currentPhase) {
this.currentPhase = currentPhase;
}
};
[Serializable]
public class MissingSettingsException : Exception {};
public ActPhase Phase { get; }
/// <summary>
/// Call this to initialize the Act (GameObjects, ActSettings, etc). All interactable components should be disabled in this phase.
/// </summary>
public virtual void ActInit() {
phase = ActPhase.INIT;
canvas = GameObject.FindGameObjectWithTag("Canvas")?.GetComponent<Canvas>();
eventSystem = GameObject.FindGameObjectWithTag("EventSystem")?.GetComponent<EventSystem>();
if(settings == null) {
throw new MissingSettingsException();
}
}
/// <summary>
/// Call this to enable all interactable components in the Act. It should be called when the player is ready to play.
/// </summary>
public virtual void ActStart() {
if(Phase != ActPhase.INIT) throw new InvalidPhaseException(phase);
phase = ActPhase.START;
}
/// <summary>
/// Call this to disable once again all interactable components in the Act. It should be called when the Act is finished (time ran out, player reached submission limit, etc).
/// </summary>
public virtual void ActEnd() {
if(Phase != ActPhase.START) throw new InvalidPhaseException(phase);
phase = ActPhase.END;
}
/// <summary>
/// Call this to cleanup all GameObjects created during the Init phase.
/// </summary>
public virtual void ActCleanup() {
if(Phase != ActPhase.END) {
Debug.LogWarningFormat("ActCleanup() was called during {0}", Phase);
}
phase = ActPhase.CLEANUP;
}
protected virtual void Awake() {
}
protected virtual void Start() {
}
protected virtual void Update() {
}
protected virtual void OnDestroy() {
ActCleanup();
}
}
}

View file

@ -1,5 +1,5 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: 1b7c9976c1c705342bf5b92905a0533e guid: 0f4726b47423bf742bfc526e428363d8
MonoImporter: MonoImporter:
externalObjects: {} externalObjects: {}
serializedVersion: 2 serializedVersion: 2

View file

@ -0,0 +1,16 @@
using UnityEngine;
namespace BetterTee.Player
{
public class DrawTool : MonoBehaviour
{
protected DrawableFrame frame;
protected virtual void Start() {
frame = GetComponent<DrawableFrame>();
}
}
}

View file

@ -0,0 +1,80 @@
using UnityEngine;
namespace BetterTee.Player
{
public class DrawableFrame : MonoBehaviour
{
[Header("Configuration")]
public Vector2Int resolution;
public Color startingColor = Color.white;
[Header("State")]
public bool interactable = false;
public bool hasChanged = false;
[Header("References")]
protected Texture2D texture = null;
protected Sprite sprite = null;
protected SpriteRenderer spriteRenderer;
public Rect Bounds {
get {
return new Rect(transform.position.x - (transform.localScale.x / 2),
transform.position.y - (transform.localScale.y / 2),
transform.localScale.x,
transform.localScale.y);
}
}
protected void Start()
{
texture = new Texture2D(resolution.x, resolution.y);
if(resolution.x <= 128 || resolution.y <= 128) {
texture.filterMode = FilterMode.Point;
}
else {
texture.filterMode = FilterMode.Trilinear;
}
Color[] colors = texture.GetPixels();
for(int i = 0; i < colors.Length; i++) {
colors[i] = startingColor;
}
texture.SetPixels(colors);
texture.Apply();
spriteRenderer = GetComponent<SpriteRenderer>();
sprite = Sprite.Create(texture, new Rect(0, 0, resolution.x, resolution.y), new Vector2(0.5f, 0.5f), resolution.x);
spriteRenderer.sprite = sprite;
}
public Color[] GetPixels() {
return texture.GetPixels();
}
public void SetPixels(Color[] colors) {
if(interactable) {
texture.SetPixels(colors);
hasChanged = true;
}
}
public byte[] ToPNG() {
return texture.EncodeToPNG();
}
protected void Update() {
if(hasChanged) {
texture.Apply();
}
}
protected void OnDrawGizmos()
{
Gizmos.DrawWireCube(transform.position, transform.localScale);
}
}
}

View file

@ -0,0 +1,111 @@
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
namespace BetterTee.Player
{
public class DrawingController : ActController
{
[Header("Prefabs")]
public GameObject drawableFramePrefab;
public GameObject paletteButtonPrefab;
public GameObject radiusSliderPrefab;
public GameObject actNamePrefab;
public GameObject actDescriptionPrefab;
public GameObject actTimerPrefab;
[Header("Objects")]
protected PencilTool pencil;
protected DrawableFrame drawableFrame;
protected List<PaletteButton> paletteButtons;
protected RadiusSlider radiusSlider;
protected Text actName;
protected Text actDescription;
protected Timer actTimer;
public override void ActInit() {
base.ActInit();
//Load settings
DrawingSettings drawingSettings = settings as DrawingSettings;
//Create drawable frame
drawableFrame = Instantiate(drawableFramePrefab, transform).GetComponent<DrawableFrame>();
drawableFrame.startingColor = drawingSettings.startingColor;
//Init PencilTool
pencil = drawableFrame.GetComponent<PencilTool>();
try {
pencil.selectedColor = drawingSettings.palette[0];
} catch(ArgumentOutOfRangeException) {
pencil.selectedColor = drawingSettings.startingColor;
}
//Init PaletteButtons
paletteButtons = new List<PaletteButton>();
for(int i = 0; i < drawingSettings.palette.Length; i++) {
PaletteButton button = Instantiate(paletteButtonPrefab, canvas.transform).GetComponent<PaletteButton>();
RectTransform btnTransform = button.GetComponent<RectTransform>();
Image btnImage = button.GetComponent<Image>();
button.pencil = pencil;
btnImage.color = drawingSettings.palette[i];
btnTransform.anchoredPosition = new Vector2(-420 + i * 110, 150);
paletteButtons.Add(button);
}
//Init RadiusSlider
radiusSlider = Instantiate(radiusSliderPrefab, canvas.transform).GetComponent<RadiusSlider>();
radiusSlider.pencil = pencil;
//Init actName Text
actName = Instantiate(actNamePrefab, canvas.transform).GetComponent<Text>();
actName.text = drawingSettings.actName;
//Init actDescription Text
actDescription = Instantiate(actDescriptionPrefab, canvas.transform).GetComponent<Text>();
actDescription.text = drawingSettings.actDescription;
//Init actTimer
actTimer = Instantiate(actTimerPrefab, canvas.transform).GetComponent<Timer>();
actTimer.TimerSet(drawingSettings.timeLimit);
}
public override void ActStart() {
base.ActStart();
//Unlock frame
drawableFrame.interactable = false;
//Start timer
actTimer.OnTimeOut += new Action(ActEnd);
actTimer.TimerStart();
}
public override void ActEnd() {
base.ActEnd();
//Lock frame
drawableFrame.interactable = true;
//Generate results
results = new DrawingResults(drawableFrame.ToPNG());
}
public override void ActCleanup() {
base.ActCleanup();
Destroy(drawableFrame.gameObject);
foreach(PaletteButton button in paletteButtons) {
Destroy(button.gameObject);
}
Destroy(radiusSlider.gameObject);
Destroy(actName.gameObject);
Destroy(actDescription.gameObject);
Destroy(actTimer.gameObject);
}
}
}

View file

@ -0,0 +1,25 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
namespace BetterTee.Player {
public class PaletteButton : MonoBehaviour
{
public PencilTool pencil;
protected Image image;
protected void Start()
{
image = GetComponent<Image>();
}
public void OnClick()
{
pencil.selectedColor = image.color;
}
}
}

View file

@ -0,0 +1,158 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace BetterTee.Player
{
public class PencilTool : DrawTool
{
public Color selectedColor = Color.black;
public float size = 1f;
protected Color[] colors;
private Vector2Int? previousPixel;
private Vector2Int? pixel;
protected Vector2Int? GetPixelAtScreenPosition(Vector2 screenPosition) {
Vector2 worldPoint = Camera.main.ScreenToWorldPoint(screenPosition);
if(frame.Bounds.Contains(worldPoint)) {
Vector2 normalized = Rect.PointToNormalized(frame.Bounds, worldPoint);
Vector2Int result = new Vector2Int(Mathf.FloorToInt(normalized.x * frame.resolution.x), Mathf.FloorToInt(normalized.y * frame.resolution.y));
return result;
}
return null;
}
protected override void Start() {
base.Start();
colors = frame.GetPixels();
Input.simulateMouseWithTouches = false;
}
protected void Update() {
bool hasChanged = false;
// Touch
foreach(Touch t in Input.touches) {
pixel = GetPixelAtScreenPosition(t.position);
previousPixel = GetPixelAtScreenPosition(t.position - t.deltaPosition);
if(pixel.HasValue) {
if(previousPixel.HasValue) {
DrawBresenhamsThickLine(pixel.Value, previousPixel.Value, size, selectedColor);
}
else {
DrawFilledCircle(pixel.Value, size, selectedColor);
}
}
hasChanged = true;
}
// Mouse
previousPixel = pixel;
if(Input.GetMouseButton(0)) {
pixel = GetPixelAtScreenPosition(Input.mousePosition);
if(pixel.HasValue) {
if(previousPixel.HasValue) {
DrawBresenhamsThickLine(previousPixel.Value, pixel.Value, size, selectedColor);
}
else {
DrawFilledCircle(pixel.Value, size, selectedColor);
}
}
hasChanged = true;
}
else {
pixel = null;
}
if(hasChanged) {
frame.SetPixels(colors);
}
}
protected void DrawPixel(int x, int y, Color color) {
if(x < 0 || x >= frame.resolution.x || y < 0 || y >= frame.resolution.y) return;
colors[x + y*frame.resolution.x] = color;
}
protected void DrawCircleEightPoints(Vector2Int center, int x_radius, int y_radius, Color color) {
DrawPixel(center.x+x_radius, center.y+y_radius, color);
DrawPixel(center.x-x_radius, center.y+y_radius, color);
DrawPixel(center.x+x_radius, center.y-y_radius, color);
DrawPixel(center.x-x_radius, center.y-y_radius, color);
DrawPixel(center.x+y_radius, center.y+x_radius, color);
DrawPixel(center.x-y_radius, center.y+x_radius, color);
DrawPixel(center.x+y_radius, center.y-x_radius, color);
DrawPixel(center.x-y_radius, center.y-x_radius, color);
}
// No idea on how does it work
// https://www.geeksforgeeks.org/bresenhams-circle-drawing-algorithm/
protected void DrawBresenhamEmptyCircle(Vector2Int center, int radius, Color color) {
int x = 0;
int y = radius;
int d = 3 - 2 * radius;
DrawCircleEightPoints(center, x, y, color);
while(y >= x) {
x++;
if(d > 0) {
y--;
d = d + 4 * (x - y) + 10;
}
else {
d = d + 4 * x + 6;
}
DrawCircleEightPoints(center, x, y, color);
}
}
protected void DrawFilledCircle(Vector2Int center, float radius, Color color) {
int x_start = Mathf.CeilToInt((float)center.x - radius);
int x_end = Mathf.CeilToInt((float)center.x + radius);
int y_start = Mathf.CeilToInt((float)center.y - radius);
int y_end = Mathf.CeilToInt((float)center.y + radius);
for(int x = x_start; x < x_end; x++) {
for(int y = y_start; y < y_end; y++) {
if(Vector2Int.Distance(new Vector2Int(x, y), center) < radius) {
DrawPixel(x, y, color);
}
}
}
}
// http://www.roguebasin.com/index.php?title=Bresenham%27s_Line_Algorithm
protected void DrawBresenhamsThickLine(Vector2Int start, Vector2Int end, float radius, Color color) {
int start_x = start.x, start_y = start.y, end_x = end.x, end_y = end.y;
bool steep = Mathf.Abs(end_y - start_y) > Mathf.Abs(end_x - start_x);
if (steep) {
Utils.Swap<int>(ref start_x, ref start_y);
Utils.Swap<int>(ref end_x, ref end_y);
}
if (start_x > end_x) {
Utils.Swap<int>(ref start_x, ref end_x);
Utils.Swap<int>(ref start_y, ref end_y);
}
int dX = (end_x - start_x), dY = Mathf.Abs(end_y - start_y), err = (dX / 2), ystep = (start_y < end_y ? 1 : -1), y = start_y;
for (int x = start_x; x <= end_x; ++x)
{
if(steep) {
DrawFilledCircle(new Vector2Int(y, x), radius, color);
}
else {
DrawFilledCircle(new Vector2Int(x, y), radius, color);
}
err = err - dY;
if (err < 0) { y += ystep; err += dX; }
}
}
protected void Apply() {
}
}
}

View file

@ -0,0 +1,99 @@
using System;
using UnityEngine;
using Mirror;
using BetterTee;
namespace BetterTee.Player
{
public class PlayerMainController : MonoBehaviour
{
[Header("WIP")]
public string address = "127.0.0.1";
public string playerName = "Steffo";
public string gamePassword = "ASDF";
void Start() {
ConnectToServer(address, playerName);
}
[Header("Objects")]
public ActController currentAct = null;
[Header("Prefabs")]
public GameObject drawingControllerPrefab;
public GameObject typingControllerPrefab;
[Serializable]
public class InvalidActTypeException : Exception {
public readonly string actType;
public InvalidActTypeException(string actType) {
this.actType = actType;
}
};
public void LoadAct(ActSettings settings) {
if(settings.type == "Drawing") {
currentAct = Instantiate(drawingControllerPrefab, transform).GetComponent<DrawingController>();
}
else if (settings.type == "Typing") {
currentAct = Instantiate(typingControllerPrefab, transform).GetComponent<TypingController>();
}
else throw new InvalidActTypeException(settings.type);
currentAct.settings = settings;
}
public void ConnectToServer(string address, string playerName) {
LogFilter.Debug = true;
Transport.activeTransport = GetComponent<TelepathyTransport>();
NetworkClient.RegisterHandler<ConnectMessage>(OnConnect);
NetworkClient.RegisterHandler<NetMsg.Server.PlayerJoined>(OnPlayerJoinSuccessful);
NetworkClient.RegisterHandler<NetMsg.Server.LobbyEnd>(OnLobbyEnd);
NetworkClient.RegisterHandler<NetMsg.Server.GameEnd>(OnGameEnd);
NetworkClient.RegisterHandler<NetMsg.Server.ActInit>(OnActInit);
NetworkClient.RegisterHandler<NetMsg.Server.ActStart>(OnActStart);
NetworkClient.RegisterHandler<NetMsg.Server.ActEnd>(OnActEnd);
NetworkClient.Connect(address);
}
#region Network Events
protected void OnConnect(NetworkConnection connection, ConnectMessage message) {
Debug.Log("Sending NetMessage.Connect.PlayerJoin");
connection.Send<NetMsg.Client.PlayerJoin>(new NetMsg.Client.PlayerJoin {
playerName = playerName,
gamePassword = gamePassword
});
}
protected void OnPlayerJoinSuccessful(NetworkConnection connection, NetMsg.Server.PlayerJoined message) {
}
protected void OnLobbyEnd(NetworkConnection connection, NetMsg.Server.LobbyEnd message) {}
protected void OnGameEnd(NetworkConnection connection, NetMsg.Server.GameEnd message) {}
protected void OnActInit(NetworkConnection connection, NetMsg.Server.ActInit message) {
LoadAct(message.settings);
currentAct.ActInit();
}
protected void OnActStart(NetworkConnection connection, NetMsg.Server.ActStart message) {
currentAct.ActStart();
}
protected void OnActEnd(NetworkConnection connection, NetMsg.Server.ActEnd message) {
currentAct.ActEnd();
//SEND RESULTS HERE
//test this
Destroy(currentAct);
}
#endregion
}
}

View file

@ -0,0 +1,22 @@
using UnityEngine;
using UnityEngine.UI;
namespace BetterTee.Player {
public class RadiusSlider : MonoBehaviour
{
public PencilTool pencil;
protected Slider slider;
protected void Start() {
slider = GetComponent<Slider>();
}
public void OnValueChange()
{
pencil.size = slider.value;
}
}
}

View file

@ -0,0 +1,27 @@
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
namespace BetterTee.Player
{
public class Submit : MonoBehaviour
{
public InputField inputField;
public TypingController typingController;
protected EventSystem eventSystem;
protected void Start() {
eventSystem = GameObject.FindGameObjectWithTag("EventSystem").GetComponent<EventSystem>();
}
public void OnClick() {
typingController.Submit(inputField.text);
inputField.text = "";
eventSystem.SetSelectedGameObject(inputField.gameObject);
}
}
}

View file

@ -0,0 +1,56 @@
using System;
using UnityEngine;
namespace BetterTee.Player
{
public class Timer : MonoBehaviour
{
public float startingTime = 0f;
public float time = 0f;
private bool isTriggered = false;
private bool isRunning = false;
protected void Update() {
if(time >= 0f) {
if(isRunning) {
time -= Time.deltaTime;
}
}
else {
if(isTriggered) {
OnTimeOut();
time = 0f;
isTriggered = false;
isRunning = false;
}
}
}
public void TimerSet(float startingTime) {
isTriggered = true;
isRunning = false;
this.startingTime = startingTime;
time = startingTime;
}
public void TimerStart() {
isRunning = true;
}
public void TimerPause() {
isRunning = false;
}
public void TimerCancel() {
time = 0f;
isTriggered = false;
isRunning = false;
}
public event Action OnTimeOut;
}
}

View file

@ -0,0 +1,24 @@
using UnityEngine;
using UnityEngine.UI;
namespace BetterTee.Player
{
public class TimerToText : MonoBehaviour
{
protected Timer timer;
protected Text text;
protected void Start()
{
timer = GetComponent<Timer>();
text = GetComponent<Text>();
}
public void Update()
{
text.text = Mathf.CeilToInt(timer.time).ToString();
}
}
}

View file

@ -0,0 +1,109 @@
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
namespace BetterTee.Player {
public class TypingController : ActController
{
public List<String> submissions;
[Header("Prefabs")]
public GameObject actNamePrefab;
public GameObject actDescriptionPrefab;
public GameObject timerPrefab;
public GameObject submissionFieldPrefab;
public GameObject submitPrefab;
public GameObject submittedCountPrefab;
[Header("Objects")]
protected Text actName;
protected Text actDescription;
protected Timer actTimer;
protected InputField submissionField;
protected Submit submit;
protected Text submittedCount;
protected override void Start() {
base.Start();
submissions = new List<string>();
}
public override void ActInit() {
base.ActInit();
//Load settings
TypingSettings typingSettings = settings as TypingSettings;
//Init actName Text
actName = Instantiate(actNamePrefab, canvas.transform).GetComponent<Text>();
actName.text = typingSettings.actName;
//Init actDescription Text
actDescription = Instantiate(actDescriptionPrefab, canvas.transform).GetComponent<Text>();
actDescription.text = typingSettings.actDescription;
//Init actTimer
actTimer = Instantiate(timerPrefab, canvas.transform).GetComponent<Timer>();
actTimer.TimerSet(typingSettings.timeLimit);
//Init submissionInputField
submissionField = Instantiate(submissionFieldPrefab, canvas.transform).GetComponent<InputField>();
//Init submit Button
submit = Instantiate(submitPrefab, canvas.transform).GetComponent<Submit>();
submit.typingController = this;
submit.inputField = submissionField;
//Init submissionCount Text
submittedCount = Instantiate(submittedCountPrefab, canvas.transform).GetComponent<Text>();
submittedCount.text = "";
}
public override void ActStart() {
base.ActStart();
//Enable submissionField and submit Button
submissionField.interactable = true;
submit.GetComponent<Button>().interactable = true;
//Focus on submissionField
eventSystem.SetSelectedGameObject(submissionField.gameObject);
//Start timer
actTimer.OnTimeOut += new Action(ActEnd);
actTimer.TimerStart();
}
public override void ActEnd() {
base.ActEnd();
//Disable submissionField and submit Button
submissionField.interactable = false;
submit.GetComponent<Button>().interactable = false;
//Create results
results = new TypingResults(submissions.ToArray());
}
public override void ActCleanup() {
base.ActCleanup();
Destroy(actName.gameObject);
Destroy(actDescription.gameObject);
Destroy(actTimer.gameObject);
Destroy(submissionField.gameObject);
Destroy(submit.gameObject);
Destroy(submittedCount.gameObject);
}
public void Submit(string submission) {
if(submission != "") {
submissions.Add(submission);
submittedCount.text = String.Format("Submitted: {0}", submissions.Count);
}
}
}
}

View file

@ -1,92 +0,0 @@
using System;
using UnityEngine;
using Mirror;
public class PlayerMainController : MonoBehaviour
{
[Header("WIP")]
public string address = "127.0.0.1";
public string playerName = "Steffo";
public string gamePassword = "ASDF";
void Start() {
ConnectToServer(address, playerName);
}
[Header("Objects")]
public ActController currentAct = null;
[Header("Prefabs")]
public GameObject drawingControllerPrefab;
public GameObject typingControllerPrefab;
[Serializable]
public class InvalidActTypeException : Exception {
public readonly string actType;
public InvalidActTypeException(string actType) {
this.actType = actType;
}
};
public void LoadAct(ActSettings settings) {
if(settings.type == "Drawing") {
currentAct = Instantiate(drawingControllerPrefab, transform).GetComponent<DrawingController>();
}
else if (settings.type == "Typing") {
currentAct = Instantiate(typingControllerPrefab, transform).GetComponent<TypingController>();
}
else throw new InvalidActTypeException(settings.type);
currentAct.settings = settings;
}
public void ConnectToServer(string address, string playerName) {
LogFilter.Debug = true;
Transport.activeTransport = GetComponent<TelepathyTransport>();
NetworkClient.RegisterHandler<ConnectMessage>(OnConnect);
NetworkClient.RegisterHandler<NetMessage.Connect.PlayerJoinSuccessful>(OnPlayerJoinSuccessful);
NetworkClient.RegisterHandler<NetMessage.Game.Settings>(OnGameSettings);
NetworkClient.RegisterHandler<NetMessage.Game.Start>(OnGameStart);
NetworkClient.RegisterHandler<NetMessage.Game.End>(OnGameEnd);
NetworkClient.RegisterHandler<NetMessage.Act.Init>(OnActInit);
NetworkClient.RegisterHandler<NetMessage.Act.Start>(OnActStart);
NetworkClient.RegisterHandler<NetMessage.Act.End>(OnActEnd);
NetworkClient.Connect(address);
}
public void OnConnect(NetworkConnection connection, ConnectMessage message) {
Debug.Log("Sending NetMessage.Connect.PlayerJoin");
NetMessage.Connect.PlayerJoin playerJoin = new NetMessage.Connect.PlayerJoin {
playerName = playerName,
gamePassword = gamePassword
};
connection.Send<NetMessage.Connect.PlayerJoin>(playerJoin);
}
protected void OnPlayerJoinSuccessful(NetworkConnection connection, NetMessage.Connect.PlayerJoinSuccessful message) {}
protected void OnGameSettings(NetworkConnection connection, NetMessage.Game.Settings message) {}
protected void OnGameStart(NetworkConnection connection, NetMessage.Game.Start message) {}
protected void OnGameEnd(NetworkConnection connection, NetMessage.Game.End message) {}
protected void OnActInit(NetworkConnection connection, NetMessage.Act.Init message) {
LoadAct(message.settings);
currentAct.ActInit();
}
protected void OnActStart(NetworkConnection connection, NetMessage.Act.Start message) {
currentAct.ActStart();
}
protected void OnActEnd(NetworkConnection connection, NetMessage.Act.End message) {
currentAct.ActEnd();
//SEND RESULTS HERE
//test this
Destroy(currentAct);
}
}

View file

@ -1,20 +0,0 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class RadiusSlider : MonoBehaviour
{
public PencilTool pencil;
protected Slider slider;
protected void Start() {
slider = GetComponent<Slider>();
}
public void OnValueChange()
{
pencil.size = slider.value;
}
}

View file

@ -1,51 +0,0 @@
{
"type": "Drawing",
"actName": "Sample Drawing Act",
"actDescription": "This is a sample act that should be able to be loaded as a DrawingSettings instance.",
"timeLimit": 66.6,
"startingColor": {
"r": 1.0,
"g": 1.0,
"b": 1.0,
"a": 1.0
},
"palette": [
{
"r": 1.0,
"g": 0.0,
"b": 0.0,
"a": 1.0
},
{
"r": 1.0,
"g": 1.0,
"b": 0.0,
"a": 1.0
},
{
"r": 0.0,
"g": 1.0,
"b": 0.0,
"a": 1.0
},
{
"r": 0.0,
"g": 1.0,
"b": 1.0,
"a": 1.0
},
{
"r": 0.0,
"g": 0.0,
"b": 1.0,
"a": 1.0
},
{
"r": 1.0,
"g": 0.0,
"b": 1.0,
"a": 1.0
}
],
"destinationPool": "sample"
}

View file

@ -1,7 +0,0 @@
{
"type": "Typing",
"actName": "Sample Typing Act",
"actDescription": "This is a sample act that should be able to be loaded as a TypingSettings instance.",
"timeLimit": 66.6,
"destinationPool": "sample"
}

8
Assets/Code/Server.meta Normal file
View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 6653cdd1e604f58418506141bc2215a9
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,108 @@
using System;
using System.Collections.Generic;
using UnityEngine;
using Mirror;
namespace BetterTee.Server {
public class ServerMainController : MonoBehaviour
{
[Header("Status")]
public string password = null;
public List<ConnectedPlayerData> players;
public List<ConnectedViewerData> viewers;
public GamePhase phase = GamePhase.UNINTIALIZED;
[Header("Constants")]
public const int MAX_CONNECTIONS = 32;
protected void Start() {
StartServer();
}
protected void OnDestroy() {
if(NetworkServer.active) NetworkServer.Shutdown();
}
public void StartServer() {
LogFilter.Debug = true;
phase = GamePhase.LOBBY;
Transport.activeTransport = GetComponent<TelepathyTransport>();
#region Client Messages
NetworkServer.RegisterHandler<NetMsg.Client.PlayerJoin>(OnPlayerJoin);
NetworkServer.RegisterHandler<NetMsg.Client.ActResults>(OnActResults);
#endregion
#region Viewer Messages
NetworkServer.RegisterHandler<NetMsg.Viewer.ViewerLink>(OnViewerLink);
#endregion
#region Other Messages
NetworkServer.RegisterHandler<ConnectMessage>(OnConnect);
#endregion
NetworkServer.Listen(MAX_CONNECTIONS);
}
#region Network Events
protected void OnConnect(NetworkConnection connection, ConnectMessage message) {}
protected void OnPlayerJoin(NetworkConnection connection, NetMsg.Client.PlayerJoin message)
{
if(message.gamePassword != password) {
connection.Send<NetMsg.Server.Error.InvalidPassword>(new NetMsg.Server.Error.InvalidPassword());
connection.Disconnect();
return;
}
if(phase != GamePhase.LOBBY) {
connection.Send<NetMsg.Server.Error.GameAlreadyStarted>(new NetMsg.Server.Error.GameAlreadyStarted());
connection.Disconnect();
return;
}
ConnectedPlayerData newPlayer = new ConnectedPlayerData {
name = message.playerName,
id = players.Count
};
players.Add(newPlayer);
Debug.LogFormat("Player {0} joined the game", message.playerName);
connection.Send<NetMsg.Server.LobbyStatusChange>(new NetMsg.Server.LobbyStatusChange {
players = players.ToArray(),
viewers = viewers.ToArray()
});
}
protected void OnActResults(NetworkConnection connection, NetMsg.Client.ActResults message) {
//TODO
}
protected void OnViewerLink(NetworkConnection connection, NetMsg.Viewer.ViewerLink message)
{
if(message.gamePassword != password) {
connection.Send<NetMsg.Server.Error.InvalidPassword>(new NetMsg.Server.Error.InvalidPassword());
connection.Disconnect();
return;
}
ConnectedViewerData newViewer = new ConnectedViewerData {
id = viewers.Count
};
viewers.Add(newViewer);
Debug.LogFormat("Viewer {0} is now linked to the game", message.viewerName);
connection.Send<NetMsg.Server.LobbyStatusChange>(new NetMsg.Server.LobbyStatusChange {
players = players.ToArray(),
viewers = viewers.ToArray()
});
}
#endregion
}
}

View file

@ -1,79 +0,0 @@
using System;
using System.Collections.Generic;
using UnityEngine;
using Mirror;
public class ServerMainController : MonoBehaviour
{
[Header("Status")]
public string password = null;
public List<Player> players;
public List<Viewer> viewers;
public GamePhase phase = GamePhase.UNINTIALIZED;
[Header("Constants")]
public const int MAX_CONNECTIONS = 32;
protected void Start() {
StartServer();
}
protected void OnDestroy() {
if(NetworkServer.active) NetworkServer.Shutdown();
}
public void StartServer() {
LogFilter.Debug = true;
phase = GamePhase.LOBBY;
Transport.activeTransport = GetComponent<TelepathyTransport>();
NetworkServer.RegisterHandler<NetMessage.Connect.PlayerJoin>(OnPlayerJoin);
NetworkServer.RegisterHandler<NetMessage.Error.InvalidPassword>(OnInvalidPassword);
NetworkServer.RegisterHandler<NetMessage.Connect.ViewerLink>(OnViewerLink);
NetworkServer.RegisterHandler<NetMessage.Game.Settings>(OnGameSettings);
NetworkServer.RegisterHandler<NetMessage.Act.Results>(OnActResults);
NetworkServer.Listen(MAX_CONNECTIONS);
}
public void OnPlayerJoin(NetworkConnection connection, NetMessage.Connect.PlayerJoin message) {
Debug.LogFormat("Received NetMessage.Connect.PlayerJoin from {0}", message.playerName);
if(message.gamePassword != password) {
connection.Send<NetMessage.Error.InvalidPassword>(new NetMessage.Error.InvalidPassword());
connection.Disconnect();
return;
}
Player newPlayer = new Player {
name = message.playerName,
id = players.Count
};
players.Add(newPlayer);
NetMessage.Connect.PlayerJoinSuccessful reply = new NetMessage.Connect.PlayerJoinSuccessful {
player = newPlayer
};
connection.Send<NetMessage.Connect.PlayerJoinSuccessful>(reply);
}
public void OnInvalidPassword(NetworkConnection connection, NetMessage.Error.InvalidPassword message) {
Debug.LogError("Invalid gamePassword");
}
public void OnViewerLink(NetworkConnection connection, NetMessage.Connect.ViewerLink message) {
if(message.gamePassword != password) {
connection.Send<NetMessage.Error.InvalidPassword>(new NetMessage.Error.InvalidPassword());
return;
}
Viewer newViewer = new Viewer {
id = viewers.Count
};
viewers.Add(newViewer);
NetMessage.Connect.ViewerLinkSuccessful reply = new NetMessage.Connect.ViewerLinkSuccessful {
viewer = newViewer
};
connection.Send<NetMessage.Connect.ViewerLinkSuccessful>(reply);
}
public void OnGameSettings(NetworkConnection connection, NetMessage.Game.Settings message) {}
public void OnActResults(NetworkConnection connection, NetMessage.Act.Results message) {}
}

View file

@ -1,23 +0,0 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
public class Submit : MonoBehaviour
{
public InputField inputField;
public TypingController typingController;
protected EventSystem eventSystem;
protected void Start() {
eventSystem = GameObject.FindGameObjectWithTag("EventSystem").GetComponent<EventSystem>();
}
public void OnClick() {
typingController.Submit(inputField.text);
inputField.text = "";
eventSystem.SetSelectedGameObject(inputField.gameObject);
}
}

View file

@ -1,53 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class Timer : MonoBehaviour
{
public float startingTime = 0f;
public float time = 0f;
private bool isTriggered = false;
private bool isRunning = false;
protected void Update() {
if(time >= 0f) {
if(isRunning) {
time -= Time.deltaTime;
}
}
else {
if(isTriggered) {
OnTimeOut();
time = 0f;
isTriggered = false;
isRunning = false;
}
}
}
public void TimerSet(float startingTime) {
isTriggered = true;
isRunning = false;
this.startingTime = startingTime;
time = startingTime;
}
public void TimerStart() {
isRunning = true;
}
public void TimerPause() {
isRunning = false;
}
public void TimerCancel() {
time = 0f;
isTriggered = false;
isRunning = false;
}
public event Action OnTimeOut;
}

View file

@ -1,21 +0,0 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class TimerToText : MonoBehaviour
{
protected Timer timer;
protected Text text;
protected void Start()
{
timer = GetComponent<Timer>();
text = GetComponent<Text>();
}
public void Update()
{
text.text = Mathf.CeilToInt(timer.time).ToString();
}
}

View file

@ -1,107 +0,0 @@
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
public class TypingController : ActController
{
public List<String> submissions;
[Header("Prefabs")]
public GameObject actNamePrefab;
public GameObject actDescriptionPrefab;
public GameObject timerPrefab;
public GameObject submissionFieldPrefab;
public GameObject submitPrefab;
public GameObject submittedCountPrefab;
[Header("Objects")]
protected Text actName;
protected Text actDescription;
protected Timer actTimer;
protected InputField submissionField;
protected Submit submit;
protected Text submittedCount;
protected override void Start() {
base.Start();
submissions = new List<string>();
}
public override void ActInit() {
base.ActInit();
//Load settings
TypingSettings typingSettings = settings as TypingSettings;
//Init actName Text
actName = Instantiate(actNamePrefab, canvas.transform).GetComponent<Text>();
actName.text = typingSettings.actName;
//Init actDescription Text
actDescription = Instantiate(actDescriptionPrefab, canvas.transform).GetComponent<Text>();
actDescription.text = typingSettings.actDescription;
//Init actTimer
actTimer = Instantiate(timerPrefab, canvas.transform).GetComponent<Timer>();
actTimer.TimerSet(typingSettings.timeLimit);
//Init submissionInputField
submissionField = Instantiate(submissionFieldPrefab, canvas.transform).GetComponent<InputField>();
//Init submit Button
submit = Instantiate(submitPrefab, canvas.transform).GetComponent<Submit>();
submit.typingController = this;
submit.inputField = submissionField;
//Init submissionCount Text
submittedCount = Instantiate(submittedCountPrefab, canvas.transform).GetComponent<Text>();
submittedCount.text = "";
}
public override void ActStart() {
base.ActStart();
//Enable submissionField and submit Button
submissionField.interactable = true;
submit.GetComponent<Button>().interactable = true;
//Focus on submissionField
eventSystem.SetSelectedGameObject(submissionField.gameObject);
//Start timer
actTimer.OnTimeOut += new Action(ActEnd);
actTimer.TimerStart();
}
public override void ActEnd() {
base.ActEnd();
//Disable submissionField and submit Button
submissionField.interactable = false;
submit.GetComponent<Button>().interactable = false;
//Create results
results = new TypingResults(submissions.ToArray());
}
public override void ActCleanup() {
base.ActCleanup();
Destroy(actName.gameObject);
Destroy(actDescription.gameObject);
Destroy(actTimer.gameObject);
Destroy(submissionField.gameObject);
Destroy(submit.gameObject);
Destroy(submittedCount.gameObject);
}
public void Submit(string submission) {
if(submission != "") {
submissions.Add(submission);
submittedCount.text = String.Format("Submitted: {0}", submissions.Count);
}
}
}

View file

@ -1,18 +0,0 @@
using System;
[Serializable]
public class TypingSettings : ActSettings {
public float timeLimit = 99f;
public string actName = "Untitled";
public string actDescription = "This Act is missing a description.";
public string destinationPool = "default";
public TypingSettings(float timeLimit, string actName, string actDescription, string destinationPool) {
this.type = "Typing";
this.timeLimit = timeLimit;
this.actName = actName;
this.actDescription = actDescription;
this.destinationPool = destinationPool;
}
}

View file

@ -1,6 +0,0 @@
using System;
public class Viewer {
public int id;
}

8
Assets/Code/Viewer.meta Normal file
View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: a497e85620cc42944b8561c2059342ac
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,19 @@
using UnityEngine;
using UnityEngine.EventSystems;
namespace BetterTee.Viewer
{
public class ActController
{
[Header("Settings")]
public ActSettings settings = null;
protected ActPhase phase = ActPhase.NONE;
[Header("Objects")]
public Canvas canvas = null;
public EventSystem eventSystem = null;
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 46e22a25283addd4c8d9d9de963462ea
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,13 @@
using System;
using UnityEngine;
using Mirror;
namespace BetterTee.Viewer
{
public class ViewerMainController : MonoBehaviour
{
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7de9e5b69cd5a9c4796053227593c096
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

206
Assets/Scenes/Viewer.unity Normal file
View file

@ -0,0 +1,206 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!29 &1
OcclusionCullingSettings:
m_ObjectHideFlags: 0
serializedVersion: 2
m_OcclusionBakeSettings:
smallestOccluder: 5
smallestHole: 0.25
backfaceThreshold: 100
m_SceneGUID: 00000000000000000000000000000000
m_OcclusionCullingData: {fileID: 0}
--- !u!104 &2
RenderSettings:
m_ObjectHideFlags: 0
serializedVersion: 9
m_Fog: 0
m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1}
m_FogMode: 3
m_FogDensity: 0.01
m_LinearFogStart: 0
m_LinearFogEnd: 300
m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1}
m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1}
m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1}
m_AmbientIntensity: 1
m_AmbientMode: 3
m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1}
m_SkyboxMaterial: {fileID: 0}
m_HaloStrength: 0.5
m_FlareStrength: 1
m_FlareFadeSpeed: 3
m_HaloTexture: {fileID: 0}
m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0}
m_DefaultReflectionMode: 0
m_DefaultReflectionResolution: 128
m_ReflectionBounces: 1
m_ReflectionIntensity: 1
m_CustomReflection: {fileID: 0}
m_Sun: {fileID: 0}
m_IndirectSpecularColor: {r: 0, g: 0, b: 0, a: 1}
m_UseRadianceAmbientProbe: 0
--- !u!157 &3
LightmapSettings:
m_ObjectHideFlags: 0
serializedVersion: 11
m_GIWorkflowMode: 1
m_GISettings:
serializedVersion: 2
m_BounceScale: 1
m_IndirectOutputScale: 1
m_AlbedoBoost: 1
m_EnvironmentLightingMode: 0
m_EnableBakedLightmaps: 0
m_EnableRealtimeLightmaps: 0
m_LightmapEditorSettings:
serializedVersion: 12
m_Resolution: 2
m_BakeResolution: 40
m_AtlasSize: 1024
m_AO: 0
m_AOMaxDistance: 1
m_CompAOExponent: 1
m_CompAOExponentDirect: 0
m_ExtractAmbientOcclusion: 0
m_Padding: 2
m_LightmapParameters: {fileID: 0}
m_LightmapsBakeMode: 1
m_TextureCompression: 1
m_FinalGather: 0
m_FinalGatherFiltering: 1
m_FinalGatherRayCount: 256
m_ReflectionCompression: 2
m_MixedBakeMode: 2
m_BakeBackend: 1
m_PVRSampling: 1
m_PVRDirectSampleCount: 32
m_PVRSampleCount: 512
m_PVRBounces: 2
m_PVREnvironmentSampleCount: 256
m_PVREnvironmentReferencePointCount: 2048
m_PVRFilteringMode: 1
m_PVRDenoiserTypeDirect: 1
m_PVRDenoiserTypeIndirect: 1
m_PVRDenoiserTypeAO: 1
m_PVRFilterTypeDirect: 0
m_PVRFilterTypeIndirect: 0
m_PVRFilterTypeAO: 0
m_PVREnvironmentMIS: 1
m_PVRCulling: 1
m_PVRFilteringGaussRadiusDirect: 1
m_PVRFilteringGaussRadiusIndirect: 5
m_PVRFilteringGaussRadiusAO: 2
m_PVRFilteringAtrousPositionSigmaDirect: 0.5
m_PVRFilteringAtrousPositionSigmaIndirect: 2
m_PVRFilteringAtrousPositionSigmaAO: 1
m_ExportTrainingData: 0
m_TrainingDataDestination: TrainingData
m_LightProbeSampleCountMultiplier: 4
m_LightingDataAsset: {fileID: 0}
m_UseShadowmask: 1
--- !u!196 &4
NavMeshSettings:
serializedVersion: 2
m_ObjectHideFlags: 0
m_BuildSettings:
serializedVersion: 2
agentTypeID: 0
agentRadius: 0.5
agentHeight: 2
agentSlope: 45
agentClimb: 0.4
ledgeDropHeight: 0
maxJumpAcrossDistance: 0
minRegionArea: 2
manualCellSize: 0
cellSize: 0.16666667
manualTileSize: 0
tileSize: 256
accuratePlacement: 0
debug:
m_Flags: 0
m_NavMeshData: {fileID: 0}
--- !u!1 &1600768605
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1600768608}
- component: {fileID: 1600768607}
- component: {fileID: 1600768606}
m_Layer: 0
m_Name: Main Camera
m_TagString: MainCamera
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!81 &1600768606
AudioListener:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1600768605}
m_Enabled: 1
--- !u!20 &1600768607
Camera:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1600768605}
m_Enabled: 1
serializedVersion: 2
m_ClearFlags: 1
m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0}
m_projectionMatrixMode: 1
m_GateFitMode: 2
m_FOVAxisMode: 0
m_SensorSize: {x: 36, y: 24}
m_LensShift: {x: 0, y: 0}
m_FocalLength: 50
m_NormalizedViewPortRect:
serializedVersion: 2
x: 0
y: 0
width: 1
height: 1
near clip plane: 0.3
far clip plane: 1000
field of view: 60
orthographic: 1
orthographic size: 5
m_Depth: -1
m_CullingMask:
serializedVersion: 2
m_Bits: 4294967295
m_RenderingPath: -1
m_TargetTexture: {fileID: 0}
m_TargetDisplay: 0
m_TargetEye: 3
m_HDR: 1
m_AllowMSAA: 1
m_AllowDynamicResolution: 0
m_ForceIntoRT: 0
m_OcclusionCulling: 1
m_StereoConvergence: 10
m_StereoSeparation: 0.022
--- !u!4 &1600768608
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1600768605}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: -10}
m_LocalScale: {x: 1, y: 1, z: 1}
m_Children: []
m_Father: {fileID: 0}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}

View file

@ -1,6 +1,6 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: 546b7440efcb5644c8243bc3b3d2e743 guid: 73fa8e1d2e6de384a94ce9ff74269804
TextScriptImporter: DefaultImporter:
externalObjects: {} externalObjects: {}
userData: userData:
assetBundleName: assetBundleName: