suck it unity collab
This commit is contained in:
parent
2630db1920
commit
dad44ef0cf
456 changed files with 1861 additions and 128 deletions
8
Assets/RealCode/Animations.meta
Normal file
8
Assets/RealCode/Animations.meta
Normal file
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: a275a3205065727469603de8ce09ffba
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
20
Assets/RealCode/Animations/SimpleAnimationLoop.cs
Normal file
20
Assets/RealCode/Animations/SimpleAnimationLoop.cs
Normal file
|
@ -0,0 +1,20 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class SimpleAnimationLoop : MonoBehaviour {
|
||||
|
||||
private new SpriteRenderer renderer;
|
||||
public Sprite[] sprites;
|
||||
public float frameTime = 0.75f;
|
||||
|
||||
private void Awake() {
|
||||
renderer = GetComponent<SpriteRenderer>();
|
||||
}
|
||||
|
||||
private void Update() {
|
||||
var frameindex = Mathf.FloorToInt(Time.time / frameTime);
|
||||
renderer.sprite = sprites[frameindex % sprites.Length];
|
||||
}
|
||||
|
||||
}
|
11
Assets/RealCode/Animations/SimpleAnimationLoop.cs.meta
Normal file
11
Assets/RealCode/Animations/SimpleAnimationLoop.cs.meta
Normal file
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 8ab68913b04318744b5be4144a001b08
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
26
Assets/RealCode/Animations/SimpleScrollLoop.cs
Normal file
26
Assets/RealCode/Animations/SimpleScrollLoop.cs
Normal file
|
@ -0,0 +1,26 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class SimpleScrollLoop : MonoBehaviour {
|
||||
|
||||
public float width = 8.75f;
|
||||
public float speed = 1f;
|
||||
private float value = 0f;
|
||||
|
||||
public Transform one, two;
|
||||
|
||||
private void Update() {
|
||||
if (speed > 0) {
|
||||
one.localPosition = new Vector3(value - width, 0f, 0f);
|
||||
two.localPosition = new Vector3(value, 0f, 0f);
|
||||
} else {
|
||||
one.localPosition = new Vector3(value + width, 0f, 0f);
|
||||
two.localPosition = new Vector3(value, 0f, 0f);
|
||||
}
|
||||
|
||||
|
||||
value += Time.deltaTime * speed;
|
||||
value %= width;
|
||||
}
|
||||
}
|
11
Assets/RealCode/Animations/SimpleScrollLoop.cs.meta
Normal file
11
Assets/RealCode/Animations/SimpleScrollLoop.cs.meta
Normal file
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 90fbb72b07a62ea448ce550144c094c6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
856
Assets/RealCode/GameBoard.cs
Normal file
856
Assets/RealCode/GameBoard.cs
Normal file
|
@ -0,0 +1,856 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
using System.Linq;
|
||||
using Hashtable = ExitGames.Client.Photon.Hashtable;
|
||||
|
||||
using BoardState = System.Collections.Generic.List<System.Collections.Generic.List<TileInfo>>;
|
||||
using ExitGames.Client.Photon;
|
||||
|
||||
using EntityNetwork;
|
||||
|
||||
public class GameBoard : EntityBase, IAutoSerialize, IAutoDeserialize {
|
||||
public const int COLUMN = 6, ROW = 12;
|
||||
|
||||
public GameBoardRender render;
|
||||
|
||||
[System.NonSerialized]
|
||||
public BoardState board;
|
||||
private BoardState lastSentBoard;
|
||||
|
||||
public bool active;
|
||||
|
||||
public enum DelayState { None, Collapse, Combo, Loss }
|
||||
public DelayState delayState = DelayState.None;
|
||||
|
||||
// TIL I need to always have an update timer or the dispatcher doesn't get created
|
||||
[NetVar('n',true,true,100)]
|
||||
public int NextDrop;
|
||||
[NetVar('c',true,true)]
|
||||
public int CurrentDrop;
|
||||
|
||||
public (TileInfo left, TileInfo right) currentPair {
|
||||
get => TileInfo.FromPairInt(CurrentDrop);
|
||||
set => CurrentDrop = TileInfo.ToPairInt(value);
|
||||
}
|
||||
public (TileInfo left, TileInfo right) nextPair {
|
||||
get => TileInfo.FromPairInt(NextDrop);
|
||||
set => NextDrop = TileInfo.ToPairInt(value);
|
||||
}
|
||||
|
||||
// Simple reference rotation
|
||||
public void SwapTiles() {
|
||||
var pair = currentPair;
|
||||
currentPair = nextPair;
|
||||
nextPair = pair;
|
||||
}
|
||||
|
||||
[Header("Settings")]
|
||||
// Tile timing
|
||||
private int TilesUntilActivator = 3;
|
||||
int nextActivator = -1;
|
||||
|
||||
public float nextRootX = -1, nextRootY = 12;
|
||||
|
||||
TileColor lastActivatorColor;
|
||||
public void ReplaceNextTile() {
|
||||
(TileInfo left, TileInfo right) pair = (TileInfo.CreateRandomBlockTile(), TileInfo.CreateRandomBlockTile());
|
||||
--nextActivator;
|
||||
if (nextActivator < 1) {
|
||||
nextActivator = TilesUntilActivator;
|
||||
var activator = TileInfo.CreateRandomActivatorTile();
|
||||
while (activator.color == lastActivatorColor)
|
||||
activator = TileInfo.CreateRandomActivatorTile();
|
||||
|
||||
lastActivatorColor = activator.color;
|
||||
|
||||
if (Random.value > 0.5f) {
|
||||
pair.left = activator;
|
||||
} else {
|
||||
pair.right = activator;
|
||||
}
|
||||
}
|
||||
|
||||
nextPair = pair;
|
||||
}
|
||||
|
||||
public float airCollapseTime = 1f;
|
||||
public float activationSpreadTime = 0.5f;
|
||||
public int dropHeight = 12; // Y value to drop from
|
||||
|
||||
[Header("Scoring")]
|
||||
[NetVar('C',true,true)]
|
||||
public int Combo; // Increments on successively chained combos
|
||||
[NetVar('S',true,true)]
|
||||
public int score = 0;
|
||||
|
||||
|
||||
#region GameLogic
|
||||
// Time without moving that the game will kill you if you have lethal trash
|
||||
public float AutoDeathTime = 10f;
|
||||
|
||||
public float timeInState = 0;
|
||||
public DelayState lastState = DelayState.None;
|
||||
void GameLogic() {
|
||||
if (delayState != lastState) {
|
||||
timeInState = 0;
|
||||
}
|
||||
lastState = delayState;
|
||||
|
||||
timeInState += Time.deltaTime;
|
||||
|
||||
// Handle player input always, but block dropping when in a state
|
||||
if (!AIEnabled)
|
||||
PlayerInput();
|
||||
|
||||
switch (delayState) {
|
||||
case DelayState.Collapse:
|
||||
if (timeInState > airCollapseTime) {
|
||||
board = Collapse(board); // Remove air
|
||||
board = ActivateOnce(board, out bool didActivate);
|
||||
if (didActivate) {
|
||||
delayState = DelayState.Combo;
|
||||
++Combo;
|
||||
} else {
|
||||
Combo = 0;
|
||||
|
||||
ApplyTrash();
|
||||
|
||||
delayState = DelayState.None;
|
||||
}
|
||||
}
|
||||
return;
|
||||
case DelayState.Combo:
|
||||
if (timeInState > activationSpreadTime) {
|
||||
board = ActivateOnce(board, out bool didActivate);
|
||||
if (didActivate) {
|
||||
timeInState = 0;
|
||||
return;
|
||||
} else {
|
||||
int scoreValue = CountActivations(board) * Combo;
|
||||
|
||||
// Score increments too slow, make it get bigger!
|
||||
score += scoreValue * scoreValue;
|
||||
SendTrash(scoreValue - 3);
|
||||
|
||||
// TODO - Trigger animation for attacking
|
||||
|
||||
GhostActivations(); // Cool FX!
|
||||
board = ClearActivation(board);
|
||||
//board = Collapse(board); // Turns out THIS is what breaks the cool collapse effects
|
||||
// Overriding this like a dirty fellow to let me add negative buffer time
|
||||
timeInState = -0.5f * airCollapseTime; // Take 1.5x longer to collapse from combo chain
|
||||
lastState = DelayState.Collapse;
|
||||
delayState = DelayState.Collapse;
|
||||
return;
|
||||
}
|
||||
}
|
||||
return;
|
||||
case DelayState.None:
|
||||
if (HighestStack(board) >= 13) {
|
||||
delayState = DelayState.Loss;
|
||||
|
||||
StartCoroutine(HandleLoss());
|
||||
// TODO - Do a bunch of networking silliness to end the game here
|
||||
}
|
||||
|
||||
// If the player isn't taking actions, trash won't appear, so make instakills kill through inaction
|
||||
if (timeInState > AutoDeathTime) {
|
||||
var incomingHeight = HighestStackWithTrash(board, incomingTrash);
|
||||
if (incomingHeight > ROW) {
|
||||
ApplyTrash();
|
||||
} else {
|
||||
timeInState = 0; // Reset the time in state before we check autodeath again
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Draw the big collapse of pieces after a few seconds
|
||||
IEnumerator HandleLoss() {
|
||||
// Wait three seconds before doing the crumble so they can watch in dismay
|
||||
// at the piles of trash that killed them
|
||||
yield return new WaitForSeconds(3f);
|
||||
// First, crumble the board to be really cool
|
||||
for(int x = 0; x < board.Count; ++x) {
|
||||
var col = board[x];
|
||||
for(int y = 0; y < col.Count; ++y) {
|
||||
render.Crumble(col[y], (x, y));
|
||||
}
|
||||
}
|
||||
|
||||
// Now, re-initialize the board, so those falling pieces are the last of our board
|
||||
board = BoardStateExtension.Initialize();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Input
|
||||
/// <summary>
|
||||
/// Awaiting control stick neutral for control inputs to return
|
||||
/// </summary>
|
||||
public bool awaitingNeutral;
|
||||
public static float inputThreshold = 0.3f;
|
||||
|
||||
public void PlayerInput() {
|
||||
float rightIntent = Input.GetAxisRaw("Horizontal");
|
||||
float upIntent = Input.GetAxisRaw("Rotate");
|
||||
|
||||
var max = Mathf.Max(Mathf.Abs(rightIntent), Mathf.Abs(upIntent));
|
||||
if (max > 0.3f) {
|
||||
if (!awaitingNeutral) {
|
||||
if (rightIntent > 0.2f) {
|
||||
dropColumn += 1;
|
||||
} else if (rightIntent < -0.2f) {
|
||||
dropColumn -= 1;
|
||||
}
|
||||
|
||||
if (upIntent > 0.2f) {
|
||||
playerRotation += 1;
|
||||
} else if (upIntent < -0.2f) {
|
||||
playerRotation -= 1;
|
||||
}
|
||||
|
||||
// Shitty wrapping
|
||||
if (playerRotation > 3)
|
||||
playerRotation = 0;
|
||||
if (playerRotation < 0)
|
||||
playerRotation = 3;
|
||||
|
||||
dropColumn = ClampRotatedPosition(playerRotation);
|
||||
dropHeight = playerRotation != 3 ? 12 : 13; // Shift the drop height based on rotation
|
||||
}
|
||||
awaitingNeutral = true;
|
||||
} else {
|
||||
awaitingNeutral = false;
|
||||
}
|
||||
|
||||
if (Input.GetButtonDown("Drop")) {
|
||||
if (delayState == DelayState.None) {
|
||||
board = Collapse(board);
|
||||
board = DropNow(board);
|
||||
}
|
||||
}
|
||||
|
||||
if (Input.GetButtonDown("Swap")) {
|
||||
SwapTiles();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public BoardState DropNow(BoardState bs) {
|
||||
bs = Place(bs, currentPair, playerRotation, dropColumn);
|
||||
//this[dropColumn, dropHeight] = TileInfo.CreateRandomBlockTile();
|
||||
bs = ReduceCountdowns(bs);
|
||||
bs = Collapse(bs);
|
||||
delayState = DelayState.Collapse;
|
||||
|
||||
SwapTiles();
|
||||
ReplaceNextTile();
|
||||
|
||||
return bs;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region placement
|
||||
[NetVar('p',true,true)]
|
||||
public int dropColumn;
|
||||
[NetVar('r', true, true)]
|
||||
public int playerRotation = 0;
|
||||
// Rotations (Coordinate is always on left)
|
||||
// 0 - L/R
|
||||
|
||||
// 1 - L
|
||||
// R
|
||||
|
||||
// 2 - R/L
|
||||
|
||||
// 3 - R
|
||||
// L
|
||||
|
||||
private ((int x, int y) left, (int x, int y) right) GetPlacePosition(BoardState bs, int placeRotation, int dropColumn){
|
||||
(int x, int y) left = (dropColumn, dropHeight), right = (dropColumn, dropHeight);
|
||||
switch(placeRotation){
|
||||
case 0:
|
||||
right.x += 1;
|
||||
break;
|
||||
case 1:
|
||||
right.y += 1;
|
||||
break;
|
||||
case 2:
|
||||
right.x -= 1;
|
||||
break;
|
||||
case 3:
|
||||
right.y -= 1;
|
||||
break;
|
||||
}
|
||||
return (left, right);
|
||||
}
|
||||
|
||||
public BoardState Place(BoardState bs,(TileInfo left, TileInfo right) pair, int placeRotation, int dropColumn) {
|
||||
//Debug.LogFormat("Placing tile frame {0}",Time.frameCount);
|
||||
(int x, int y) dropLeft = (dropColumn, dropHeight), dropRight = (dropColumn, dropHeight);
|
||||
switch(placeRotation) {
|
||||
case 0:
|
||||
dropRight.x += 1;
|
||||
break;
|
||||
case 1:
|
||||
dropRight.y += 1;
|
||||
break;
|
||||
case 2:
|
||||
dropRight.x -= 1;
|
||||
break;
|
||||
case 3:
|
||||
dropRight.y -= 1;
|
||||
break;
|
||||
}
|
||||
// Fix an issue with placing tiles in the wrong order not working right
|
||||
if (dropRight.y < dropLeft.y) {
|
||||
// Texel - Switch to modifying the passed board state, instead of the authority board state
|
||||
bs.SetTile(pair.right, dropRight.x, dropRight.y);
|
||||
bs.SetTile(pair.left, dropLeft.x, dropLeft.y);
|
||||
//this[dropRight.x, dropRight.y] = pair.right;
|
||||
//this[dropLeft.x, dropLeft.y] = pair.left;
|
||||
} else {
|
||||
bs.SetTile(pair.left, dropLeft.x, dropLeft.y);
|
||||
bs.SetTile(pair.right, dropRight.x, dropRight.y);
|
||||
|
||||
//this[dropLeft.x, dropLeft.y] = pair.left;
|
||||
//this[dropRight.x, dropRight.y] = pair.right;
|
||||
}
|
||||
|
||||
|
||||
return bs;
|
||||
}
|
||||
|
||||
public int ClampRotatedPosition(int sourceRotation) {
|
||||
switch(sourceRotation) {
|
||||
case 0:
|
||||
return Mathf.Clamp(dropColumn, 0, COLUMN-2);
|
||||
case 1:
|
||||
case 3:
|
||||
return Mathf.Clamp(dropColumn, 0, COLUMN-1);
|
||||
case 2:
|
||||
return Mathf.Clamp(dropColumn, 1, COLUMN-1);
|
||||
default:
|
||||
throw new System.IndexOutOfRangeException("Rotation is out of bounds you dolt");
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region network
|
||||
// Serialize/Deserialize network board state
|
||||
public override void Deserialize(Hashtable h) {
|
||||
base.Deserialize(h);
|
||||
//Debug.Log("Deserializing");
|
||||
|
||||
if (h.TryGetValue('b', out var val)) {
|
||||
board.FromHashtable((Hashtable)val);
|
||||
//Debug.Log(val.ToString());
|
||||
}
|
||||
}
|
||||
public override void Serialize(Hashtable h) {
|
||||
base.Serialize(h);
|
||||
//Debug.Log("Serializing");
|
||||
|
||||
h.Add('b', board.ToHashtable());
|
||||
lastSentBoard = board.Copy();
|
||||
stateDirty = false;
|
||||
}
|
||||
|
||||
// Would be a lot better if we could get a good hash off of the board, but the data is too regular we'd collide constantly
|
||||
void checkDirty() {
|
||||
if (lastSentBoard != null && !board.Matches(lastSentBoard)) {
|
||||
stateDirty = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region trash
|
||||
BoardState ReduceCountdowns(BoardState bs) {
|
||||
for(int i = 0; i < bs.Count; ++i) {
|
||||
var col = bs[i];
|
||||
for(int y = 0; y < col.Count; ++y) {
|
||||
var tile = col[y];
|
||||
if (tile.kind == TileKind.Trash){
|
||||
tile.counter--;
|
||||
if (tile.counter == 0){ // Revert tiles to blocks
|
||||
tile.kind = TileKind.Block;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return bs;
|
||||
}
|
||||
|
||||
// Funny how THIS one is super easy, but once trash is involved it's hard
|
||||
int HighestStack(BoardState bs) => bs.Max(t => t.Count);
|
||||
|
||||
/// <summary>
|
||||
/// Calculate the highest stack with trash.
|
||||
/// </summary>
|
||||
int HighestStackWithTrash(BoardState bs, int amount) {
|
||||
var stackHeights = new List<int>();
|
||||
for(int c = 0; c < bs.Count; ++c)
|
||||
stackHeights.Add(bs[c].Count);
|
||||
|
||||
var cursorHead = trashCursorHead;
|
||||
while (amount > 0) {
|
||||
--amount;
|
||||
stackHeights[cursorHead] += 1;
|
||||
|
||||
if (cursorHead >= COLUMN) {
|
||||
cursorHead = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return stackHeights.Max();
|
||||
}
|
||||
|
||||
public int incomingTrash = 0;
|
||||
|
||||
void SendTrash(int amount) {
|
||||
if (amount < 1) return;
|
||||
// Uncached find? Blasphamy! Also whatever fukkit
|
||||
var otherBoards = FindObjectsOfType<GameBoard>().Where(t => t != this);
|
||||
foreach (var other in otherBoards) {
|
||||
other.RaiseEvent('t', true, amount);
|
||||
}
|
||||
}
|
||||
|
||||
[NetEvent('t')]
|
||||
void AddTrashNetwork(int i) {
|
||||
incomingTrash += i;
|
||||
}
|
||||
|
||||
// Column to drop trash
|
||||
int trashCursorHead = 0;
|
||||
void ApplyTrash() {
|
||||
if (incomingTrash > 0) {
|
||||
delayState = DelayState.Collapse;
|
||||
timeInState = 0;
|
||||
}
|
||||
while (incomingTrash > 0) {
|
||||
--incomingTrash;
|
||||
|
||||
var trash = TileInfo.CreateRandomTrashTile();
|
||||
board[trashCursorHead].Add(trash);
|
||||
|
||||
trashCursorHead += 1;
|
||||
if (trashCursorHead >= COLUMN)
|
||||
trashCursorHead = 0;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region activation
|
||||
BoardState ClearActivation(BoardState bs) {
|
||||
foreach(var col in bs) {
|
||||
for(int y = 0; y < col.Count; ++y) {
|
||||
var tile = col[y];
|
||||
if (tile.kind.Equals(TileKind.Activiting)){
|
||||
TileInfo.SetAirTile(tile);
|
||||
}
|
||||
}
|
||||
}
|
||||
return bs;
|
||||
}
|
||||
|
||||
int CountActivations(BoardState bs) {
|
||||
int total = 0;
|
||||
foreach(var col in bs) {
|
||||
total += col.Count(t => t.kind.Equals(TileKind.Activiting));
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
void GhostActivations() {
|
||||
for(int x = 0; x < board.Count; ++x) {
|
||||
var col = board[x];
|
||||
for (int y = 0; y < col.Count; ++y) {
|
||||
var tile = col[y];
|
||||
if (tile.kind.Equals(TileKind.Activiting)) {
|
||||
render.Ghost(tile, (x, y));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BoardState ActivateColorOnce(BoardState bs,TileColor tc,out bool success) {
|
||||
success = false;
|
||||
for(int x = 0; x < bs.Count; ++x) {
|
||||
var col = bs[x];
|
||||
for (int y = 0; y < col.Count; ++y) {
|
||||
//var tile = this[x, y];
|
||||
var tile = bs.tile(x, y);
|
||||
if (tile.kind.Equals(TileKind.Activator) || tile.kind.Equals(TileKind.Activiting)) {
|
||||
// Check adjacency for tiles to activate, filtering for unactivated blocks or other activators of our color
|
||||
var neighbors = Neighbors(x, y,bs).Where(t => t.kind.Equals(TileKind.Block) || t.kind.Equals(TileKind.Activator)).Where(t => t.color.Equals(tile.color));
|
||||
foreach(var neighbor in neighbors) {
|
||||
success = true;
|
||||
tile.kind = TileKind.Activiting;
|
||||
neighbor.kind = TileKind.Activiting;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return bs;
|
||||
}
|
||||
|
||||
BoardState ActivateColorOnceSplit(BoardState bs, TileColor tc, out bool success) {
|
||||
success = false;
|
||||
var activable = new List<(int x, int y)>();
|
||||
for (int x = 0; x < bs.Count; ++x) {
|
||||
var col = bs[x];
|
||||
for(int y = 0; y < col.Count; ++y) {
|
||||
var tile = bs.tile(x, y);//this[x, y];
|
||||
if (tile.color != tc) continue;
|
||||
if (tile.kind.Equals(TileKind.Activator) || tile.kind.Equals(TileKind.Activiting))
|
||||
activable.Add((x, y));
|
||||
}
|
||||
}
|
||||
|
||||
foreach(var potential in activable) {
|
||||
var tile = bs.tile(potential.x, potential.y);//this[potential.x, potential.y];
|
||||
if (tile.kind.Equals(TileKind.Activator) || tile.kind.Equals(TileKind.Activiting)) {
|
||||
// Check adjacency for tiles to activate, filtering for unactivated blocks or other activators of our color
|
||||
var neighbors = Neighbors(potential.x, potential.y,bs).Where(t => t.kind.Equals(TileKind.Block) || t.kind.Equals(TileKind.Activator)).Where(t => t.color.Equals(tile.color));
|
||||
foreach (var neighbor in neighbors) {
|
||||
success = true;
|
||||
tile.kind = TileKind.Activiting;
|
||||
neighbor.kind = TileKind.Activiting;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return bs;
|
||||
}
|
||||
|
||||
BoardState ActivateColor(BoardState bs, TileColor tc) {
|
||||
bool didActivate;
|
||||
do {
|
||||
bs = ActivateColorOnce(bs, tc, out didActivate);
|
||||
} while (didActivate);
|
||||
|
||||
return bs;
|
||||
}
|
||||
|
||||
BoardState ActivateOnce(BoardState bs, out bool success) {
|
||||
var colors = (TileColor[])System.Enum.GetValues(typeof(TileColor));
|
||||
success = false;
|
||||
foreach(var tc in colors) {
|
||||
//bs = ActivateColorOnce(bs,tc, out bool colorSuccess);
|
||||
bs = ActivateColorOnceSplit(bs, tc, out bool colorSuccess);
|
||||
if (colorSuccess) success = true;
|
||||
}
|
||||
return bs;
|
||||
}
|
||||
|
||||
BoardState Activate(BoardState bs) {
|
||||
var colors = (TileColor[])System.Enum.GetValues(typeof(TileColor));
|
||||
foreach(var tc in colors) {
|
||||
bs = ActivateColor(bs, tc);
|
||||
}
|
||||
return bs;
|
||||
}
|
||||
#endregion
|
||||
|
||||
static BoardState Collapse(BoardState bs) {
|
||||
for(int i = 0; i < bs.Count; ++i) {
|
||||
bs[i] = Collapse(bs[i]);
|
||||
}
|
||||
return bs;
|
||||
}
|
||||
|
||||
static List<TileInfo> Collapse(List<TileInfo> ti) {
|
||||
return ti.Where(t => t.kind != TileKind.Air).ToList();
|
||||
}
|
||||
|
||||
bool stateDirty = false;
|
||||
|
||||
[Header("Network")]
|
||||
public float networkTick = 0.1f;
|
||||
private float nextNetworkTick;
|
||||
|
||||
public void Update() {
|
||||
if (!active) {
|
||||
render.RenderName();
|
||||
return;
|
||||
}
|
||||
|
||||
if (isMine) {
|
||||
//checkDirty();
|
||||
|
||||
GameLogic();
|
||||
|
||||
if (Time.time >= nextNetworkTick && NetworkManager.inRoom){
|
||||
UpdateNow();
|
||||
nextNetworkTick = Time.time + networkTick;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
render.Render(board);
|
||||
// HACK So uh, there's an issue with air tiles taking two renders to be removed right, so uh, two renders it is. - Texel
|
||||
// Seriously I can't believe this works this is dirty
|
||||
|
||||
// It does make it render twice as fast, I have idea
|
||||
render.Render(board);
|
||||
|
||||
render.SetComboLevel(Combo);
|
||||
render.SetScoreValue(score);
|
||||
|
||||
var pair = currentPair;
|
||||
var pairp = GetPlacePosition(board, playerRotation, dropColumn);
|
||||
render.RenderPlacement(pair.left, pair.right, pairp.left, pairp.right);
|
||||
|
||||
render.RenderName();
|
||||
}
|
||||
|
||||
public override void Awake() {
|
||||
base.Awake();
|
||||
|
||||
Register();
|
||||
}
|
||||
|
||||
public void Setup(){
|
||||
board = BoardStateExtension.Initialize();
|
||||
|
||||
// Build the list of possible placements the AI may use
|
||||
PossiblePlacements = GetAllPossibilities();
|
||||
|
||||
lastActivatorColor = TileInfo.CreateRandomActivatorTile().color;
|
||||
|
||||
nextActivator = TilesUntilActivator;
|
||||
delayState = DelayState.None;
|
||||
timeInState = 0;
|
||||
|
||||
ReplaceNextTile();
|
||||
SwapTiles();
|
||||
ReplaceNextTile();
|
||||
|
||||
if (isMine){
|
||||
foreach(var c in board){
|
||||
c.Add(TileInfo.CreateRandomBlockTile());
|
||||
c.Add(TileInfo.CreateRandomBlockTile());
|
||||
}
|
||||
}
|
||||
|
||||
active = true;
|
||||
}
|
||||
|
||||
|
||||
public IEnumerable<TileInfo> Neighbors(int x, int y, BoardState bs) {
|
||||
var self = bs.tile(x, y);
|
||||
var neighborsWithNull = new[] { bs.tile(x + 1, y), bs.tile(x - 1, y), bs.tile(x, y + 1), bs.tile(x, y - 1) };
|
||||
return neighborsWithNull.Where(t => t != null).Where(t => t != self);
|
||||
|
||||
/*var self = this[x, y];
|
||||
var neighborsWithNull = new[] { this[x + 1, y], this[x - 1, y], this[x, y + 1], this[x, y - 1] };
|
||||
return neighborsWithNull.Where(t => t != null).Where(t=>t!=self);*/
|
||||
}
|
||||
|
||||
public TileInfo this[int x, int y] {
|
||||
get {
|
||||
// Pass null on sides/top, or anywhere where x, y doesn't exist.
|
||||
if (x < 0 || x >= board.Count) return null;
|
||||
if (y < 0) return null;
|
||||
|
||||
var col = board[x];
|
||||
|
||||
if (y < col.Count) return col[y];
|
||||
return null;
|
||||
}
|
||||
set {
|
||||
var col = board[x];
|
||||
|
||||
// Set value or append to end
|
||||
if (y < col.Count) col[y] = value;
|
||||
else col.Add(value); // Added else. Otherwises, any set would have grown board -- Ebony
|
||||
}
|
||||
}
|
||||
|
||||
#region AI
|
||||
List<(int r, int c)> PossiblePlacements;
|
||||
|
||||
/// <summary>
|
||||
/// Given input board state, return the end result for number of tiles that would be sent in an attack
|
||||
/// This is destructive to the input board state
|
||||
/// </summary>
|
||||
int ProjectAttack(BoardState bs) {
|
||||
int total = 0;
|
||||
int comboLength = 0;
|
||||
|
||||
bool repeat = false;
|
||||
do {
|
||||
repeat = false;
|
||||
bs = Collapse(bs);
|
||||
bs = Activate(bs);
|
||||
var newActivations = CountActivations(bs);
|
||||
if (newActivations > 0) {
|
||||
comboLength += 1;
|
||||
repeat = true;
|
||||
|
||||
if (newActivations > 3) total += (newActivations - 3) * comboLength;
|
||||
bs = ClearActivation(bs);
|
||||
}
|
||||
} while (repeat);
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
// Generates actual subset of possible moves
|
||||
List<(int simRotation, int simCol)> GetAllPossibilities() {
|
||||
var Considerables = new List<(int r, int c)>();
|
||||
for(int col = 0; col < COLUMN; ++col) {
|
||||
Considerables.AddRange(new[] {
|
||||
(0,col), (1,col), (2,col), (3,col)
|
||||
});
|
||||
}
|
||||
|
||||
for(int i = 0; i < Considerables.Count; ++i) {
|
||||
Considerables[i] = ClampPossibility(Considerables[i]);
|
||||
}
|
||||
return Considerables.Distinct().ToList();
|
||||
}
|
||||
|
||||
(int r, int c) ClampPossibility((int r, int c) possibility) {
|
||||
int oldDrop = dropColumn;
|
||||
dropColumn = possibility.c;
|
||||
possibility.c = ClampRotatedPosition(possibility.r);
|
||||
dropColumn = oldDrop;
|
||||
|
||||
return possibility;
|
||||
}
|
||||
|
||||
float averageConnectedSize(BoardState bs) {
|
||||
int maxRed =0, maxGreen=0, maxBlue=0, maxYellow=0;
|
||||
for (int i = 0; i < bs.Count; ++i) {
|
||||
(int count, TileColor color) cluster = ExposedClusterSize(bs, i);
|
||||
switch(cluster.color) {
|
||||
case TileColor.Blue:
|
||||
maxBlue = Mathf.Max(maxBlue, cluster.count);
|
||||
break;
|
||||
case TileColor.Green:
|
||||
maxGreen = Mathf.Max(maxGreen, cluster.count);
|
||||
break;
|
||||
case TileColor.Red:
|
||||
maxRed = Mathf.Max(maxRed, cluster.count);
|
||||
break;
|
||||
case TileColor.Yellow:
|
||||
maxYellow = Mathf.Max(maxYellow, cluster.count);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (maxRed + maxGreen + maxBlue + maxYellow) * 0.25f;
|
||||
}
|
||||
|
||||
// Texel - I gave up writing this and made it use a board copy destructively
|
||||
(int count, TileColor color) ExposedClusterSize(BoardState bs, int col) {
|
||||
var bc = bs.Copy();
|
||||
//ReduceToBlocksOnly(bc);
|
||||
|
||||
int startX = col;
|
||||
int startY = bc[col].Count - 1;
|
||||
if (startY < 0) return (0, TileColor.Blue); // Oops can't eval an empty col
|
||||
|
||||
var tile = bc.tile(startX, startY);
|
||||
|
||||
tile.kind = TileKind.Activator;
|
||||
//ProjectAttack(bc);
|
||||
bc = Activate(bc);
|
||||
|
||||
return (CountActivations(bc),tile.color);
|
||||
}
|
||||
|
||||
void ReduceToBlocksOnly(BoardState bs) {
|
||||
for(int x = 0; x < bs.Count; ++x) {
|
||||
var col = bs[x];
|
||||
for(int y = 0; y < bs.Count; ++y) {
|
||||
var tile = col[y];
|
||||
if (tile.kind.Equals(TileKind.Air)) continue;
|
||||
tile.kind = TileKind.Block;
|
||||
tile.counter = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create an internal copy of the board, simulate the given rotation/col against it.
|
||||
/// </summary>
|
||||
(int score,float averageConnectedSize, int maxHeight) EvalPossibility(BoardState bs, (int r, int c) possibility) {
|
||||
var bc = bs.Copy();
|
||||
try {
|
||||
bc = Place(bc, currentPair, possibility.r, possibility.c);
|
||||
|
||||
// TODO - Highest connected size
|
||||
float connectness = averageConnectedSize(bc);
|
||||
int trashValue = ProjectAttack(bc); // Forward simulate the board to it's next stable position
|
||||
int tallest = HighestStack(bc);
|
||||
|
||||
return (trashValue, connectness, tallest);
|
||||
} catch (System.Exception e) {
|
||||
Debug.LogFormat("Possibility ({0}, {1}) has encountered an exception", possibility.r, possibility.c);
|
||||
throw (e);
|
||||
}
|
||||
}
|
||||
// Methodology -> Place pieces to fire the longest combo, then place pieces to minimize our tallest stack.
|
||||
(int r, int c) GetBestMove(BoardState bs) {
|
||||
return PossiblePlacements
|
||||
.Select(possiblity => (possiblity, EvalPossibility(bs, possiblity)))
|
||||
.OrderByDescending(t => t.Item2.score) // First priority, attacking
|
||||
.ThenByDescending(t => t.Item2.maxHeight < 10 ? 1 : 0) // Second priority, not offing ourselves
|
||||
.ThenByDescending(t => t.Item2.averageConnectedSize) // Third priority, maximize cluster sizes
|
||||
.ThenBy(t => t.Item2.maxHeight) // Fourth priority, keeping our height down
|
||||
.Select(t => t.possiblity).First();
|
||||
}
|
||||
|
||||
[ContextMenu("Startup AI")]
|
||||
public void StartAI() {
|
||||
AIEnabled = true;
|
||||
StartCoroutine(AIThink());
|
||||
}
|
||||
|
||||
public bool AIEnabled = false;
|
||||
public float AIMoveTime = 0.5f;
|
||||
IEnumerator AIThink() {
|
||||
int totalMoves = 0;
|
||||
while (delayState != DelayState.Loss) {
|
||||
if (!AIEnabled)
|
||||
yield return new WaitUntil(() => AIEnabled);
|
||||
var (r, c) = GetBestMove(board);
|
||||
Debug.LogFormat("AI: Column {0}, Rotation {1}", c, r);
|
||||
totalMoves += 1;
|
||||
|
||||
// First match rotation
|
||||
while (playerRotation != r) {
|
||||
yield return new WaitForSeconds(AIMoveTime);
|
||||
if (playerRotation < r) ++playerRotation;
|
||||
if (playerRotation > r) --playerRotation;
|
||||
|
||||
dropColumn = ClampRotatedPosition(playerRotation);
|
||||
}
|
||||
|
||||
// Then move to the right column
|
||||
while (dropColumn != c) {
|
||||
yield return new WaitForSeconds(AIMoveTime);
|
||||
if (dropColumn > c) --dropColumn;
|
||||
if (dropColumn < c) ++dropColumn;
|
||||
}
|
||||
|
||||
// Wait until we're allowed to drop a piece
|
||||
yield return new WaitUntil(() => delayState.Equals(DelayState.None));
|
||||
board = DropNow(board);
|
||||
// Now wait for it all to settle before repeating
|
||||
yield return new WaitUntil(() => delayState.Equals(DelayState.None));
|
||||
}
|
||||
|
||||
Debug.LogFormat("AI lost after {0} moves",totalMoves);
|
||||
}
|
||||
#endregion
|
||||
}
|
11
Assets/RealCode/GameBoard.cs.meta
Normal file
11
Assets/RealCode/GameBoard.cs.meta
Normal file
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 42cc6281a82f5aa4ca2b2458fb89c8ec
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
107
Assets/RealCode/GameBoardExtension.cs
Normal file
107
Assets/RealCode/GameBoardExtension.cs
Normal file
|
@ -0,0 +1,107 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
using Hashtable = ExitGames.Client.Photon.Hashtable;
|
||||
|
||||
using BoardState = System.Collections.Generic.List<System.Collections.Generic.List<TileInfo>>;
|
||||
using TileList = System.Collections.Generic.List<TileInfo>;
|
||||
|
||||
// TODO: Peel this into it's own file?
|
||||
public static class BoardStateExtension {
|
||||
|
||||
public static BoardState Initialize() {
|
||||
var bs = new BoardState();
|
||||
for(var i = 0; i < GameBoard.COLUMN; ++i){
|
||||
bs.Add(new TileList());
|
||||
}
|
||||
return bs;
|
||||
}
|
||||
|
||||
public static Hashtable ToHashtable(this BoardState bs) {
|
||||
var ht = new Hashtable();
|
||||
for (int i = 0; i < bs.Count; ++i) {
|
||||
var col = bs[i];
|
||||
// Store a short[] representation of each column
|
||||
ht.Add(i, col.Select(t => (short)t).ToArray());
|
||||
}
|
||||
return ht;
|
||||
}
|
||||
|
||||
// Did you know that having TileInfo be a class makes this super expensive and complicated?
|
||||
public static bool Matches(this BoardState bs, BoardState other) {
|
||||
if (bs.Count != other.Count) return false;
|
||||
for(int i = 0; i < bs.Count; ++i) {
|
||||
var subListMine = bs[i].Flatten();
|
||||
var subListTheirs = other[i].Flatten();
|
||||
if (!subListMine.SequenceEqual(subListTheirs)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static short[] Flatten(this List<TileInfo> tileList) {
|
||||
return tileList.Select(t => t.dat).ToArray();
|
||||
}
|
||||
|
||||
// Unpack and repack all tile infos
|
||||
public static BoardState Copy(this BoardState bs) {
|
||||
var copy = Initialize();
|
||||
for(int i=0; i < bs.Count; ++i) {
|
||||
copy[i] = bs[i].Select(t=>(TileInfo)t.dat).ToList();
|
||||
}
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
public static void FromHashtable(this BoardState bs, Hashtable ht) {
|
||||
// The user deserves garbage collection anyways. Don't optimize it unless it's a problem?
|
||||
for (int i = 0; i < bs.Count; ++i) {
|
||||
var arr = (short[])ht[i];
|
||||
bs[i] = arr.Select(t => (TileInfo)t).ToList();
|
||||
}
|
||||
}
|
||||
|
||||
public static int[] ToHashtable(this List<(int x, int y)> list) {
|
||||
var array = new int[list.Count * 2];
|
||||
for (var i = 0; i < list.Count; i++) {
|
||||
var v = list[i];
|
||||
array[i * 2] = v.x;
|
||||
array[i * 2 + 1] = v.y;
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
public static void SetTile(this BoardState board,TileInfo value, int x, int y) {
|
||||
try {
|
||||
var col = board[x];
|
||||
// Set value or append to end
|
||||
if (y < col.Count) col[y] = value;
|
||||
else col.Add(value); // Added else. Otherwises, any set would have grown board -- Ebony
|
||||
} catch (System.Exception e) {
|
||||
Debug.LogErrorFormat("Illegal placement on board at {0},{1}",x,y);
|
||||
throw e;
|
||||
}
|
||||
|
||||
}
|
||||
public static TileInfo tile(this BoardState board, int x, int y) {
|
||||
if (x < 0 || x >= board.Count) return null;
|
||||
if (y < 0) return null;
|
||||
|
||||
var col = board[x];
|
||||
|
||||
if (y < col.Count) return col[y];
|
||||
return null;
|
||||
}
|
||||
|
||||
public static List<(int x, int y)> FromHashtable(int[] array) {
|
||||
var list = new List<(int x, int y)>();
|
||||
for (var i = 0; i < array.Length; i += 2) {
|
||||
list.Add((array[i], array[i + 1]));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
}
|
11
Assets/RealCode/GameBoardExtension.cs.meta
Normal file
11
Assets/RealCode/GameBoardExtension.cs.meta
Normal file
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: dbcb4427abf614c4bb531322c18951f1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
43
Assets/RealCode/GameBoardInstance.cs
Normal file
43
Assets/RealCode/GameBoardInstance.cs
Normal file
|
@ -0,0 +1,43 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
public class GameBoardInstance : MonoBehaviour {
|
||||
|
||||
public static GameBoardInstance instance { get; private set; }
|
||||
|
||||
public GameBoard player1, player2;
|
||||
|
||||
public GameObject tilePrefab;
|
||||
public Sprite[] regular;
|
||||
public Sprite[] lit;
|
||||
public Sprite[] activators;
|
||||
|
||||
private void Awake() {
|
||||
instance = this;
|
||||
}
|
||||
|
||||
public void SetupGame(){
|
||||
if (NetworkManager.inRoom){
|
||||
var players = NetworkManager.net.CurrentRoom.Players.Values.OrderBy(p => p.ID);
|
||||
var p1 = players.ElementAt(0);
|
||||
var p2 = players.ElementAt(1);
|
||||
|
||||
player1.authorityID = p1.ID;
|
||||
player2.authorityID = p2.ID;
|
||||
|
||||
player1.Setup();
|
||||
player2.Setup();
|
||||
} else {
|
||||
player1.authorityID = -1;
|
||||
player2.authorityID = -1;
|
||||
|
||||
player1.Setup();
|
||||
player2.Setup();
|
||||
}
|
||||
|
||||
GameTransition.Instance.state = GameState.InGame;
|
||||
}
|
||||
|
||||
}
|
11
Assets/RealCode/GameBoardInstance.cs.meta
Normal file
11
Assets/RealCode/GameBoardInstance.cs.meta
Normal file
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 053420afbc44de04f81b8665dab22391
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: -50
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
262
Assets/RealCode/GameBoardRender.cs
Normal file
262
Assets/RealCode/GameBoardRender.cs
Normal file
|
@ -0,0 +1,262 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
using BoardState = System.Collections.Generic.List<System.Collections.Generic.List<TileInfo>>;
|
||||
using TileList = System.Collections.Generic.List<TileInfo>;
|
||||
|
||||
using UnityEngine.UI;
|
||||
using TMPro;
|
||||
|
||||
public class GameBoardRender : MonoBehaviour {
|
||||
// Auto assign so that I can copy stuff around like a shmuk - Texel
|
||||
private GameBoard board;
|
||||
|
||||
public TMPro.TextMeshPro ScoreText;
|
||||
public TMPro.TextMeshPro ComboText;
|
||||
public TextMeshPro NickNameText;
|
||||
|
||||
[Header("Positioning")]
|
||||
public Transform basePoint;
|
||||
public float width, height;
|
||||
|
||||
[Header("Extra")]
|
||||
public TileRender place1;
|
||||
public TileRender place2;
|
||||
public TileRender place3, place4; // Next tile display
|
||||
|
||||
// Dramatically slow falls in combo mode
|
||||
public float tileSpeed => board.Combo > 0 ? 15 : 20;
|
||||
|
||||
GameObject tilePrefab => GameBoardInstance.instance.tilePrefab;
|
||||
|
||||
void Start() {
|
||||
// Auto-assign off same object - Texel
|
||||
board = GetComponent<GameBoard>();
|
||||
}
|
||||
|
||||
|
||||
float comboTime = 0f;
|
||||
float comboDuration = 3f;
|
||||
public void SetComboLevel(int num) {
|
||||
if (!ComboText) return;
|
||||
if (num == 0) return;
|
||||
|
||||
comboTime = Time.time;
|
||||
if (num == 1)
|
||||
ComboText.text = "NICE";
|
||||
else
|
||||
ComboText.text = string.Format("{0}x COMBO", num);
|
||||
}
|
||||
|
||||
public void SetScoreValue(int value) {
|
||||
if (ScoreText) ScoreText.text = string.Format("{0:D6}", value);
|
||||
}
|
||||
|
||||
Transform corner;
|
||||
private void Awake() {
|
||||
var pos = basePoint.position;
|
||||
var rowOffset = basePoint.right * width;
|
||||
var columnOffset = basePoint.up * height;
|
||||
pos += rowOffset * 0.5f + columnOffset * 0.5f;
|
||||
for (var i = 0; i < GameBoard.COLUMN; ++i) {
|
||||
var t = new GameObject("column" + i.ToString()).transform;
|
||||
t.SetParent(basePoint);
|
||||
t.position = pos + rowOffset * i;
|
||||
t.localRotation = Quaternion.identity;
|
||||
t.localScale = Vector3.one;
|
||||
}
|
||||
|
||||
corner = new GameObject("corner").transform;
|
||||
corner.SetParent(basePoint.GetChild(0));
|
||||
corner.localPosition = Vector3.zero;
|
||||
corner.localRotation = Quaternion.identity;
|
||||
corner.localScale = Vector3.one;
|
||||
corner.SetParent(transform, true);
|
||||
|
||||
place1 = Instantiate(GameBoardInstance.instance.tilePrefab, corner).GetComponent<TileRender>();
|
||||
place2 = Instantiate(GameBoardInstance.instance.tilePrefab, corner).GetComponent<TileRender>();
|
||||
|
||||
place3 = Instantiate(GameBoardInstance.instance.tilePrefab, corner).GetComponent<TileRender>();
|
||||
place4 = Instantiate(GameBoardInstance.instance.tilePrefab, corner).GetComponent<TileRender>();
|
||||
|
||||
place1.transform.localPosition = Vector3.zero;
|
||||
place2.transform.localPosition = Vector3.zero;
|
||||
place3.transform.localPosition = Vector3.zero;
|
||||
place4.transform.localPosition = Vector3.zero;
|
||||
}
|
||||
|
||||
public void Render(BoardState state) {
|
||||
if (Time.time + comboDuration > comboTime) {
|
||||
if (ComboText) ComboText.text = "";
|
||||
}
|
||||
|
||||
// render
|
||||
for (var i = 0; i < state.Count; ++i) {
|
||||
var root = basePoint.GetChild(i);
|
||||
var t = state[i];
|
||||
RebuildStack(root, t);
|
||||
DrawStack(root, t);
|
||||
}
|
||||
}
|
||||
|
||||
public void RenderName(){
|
||||
if (NetworkManager.inRoom && board.authorityID != -1){
|
||||
var player = NetworkManager.net.CurrentRoom.GetPlayer(board.authorityID);
|
||||
NickNameText.text = player.NickName;
|
||||
}
|
||||
}
|
||||
|
||||
// Spawn a fading 'ghost' of a tile as an activator for the cool effect
|
||||
public void Ghost(TileInfo tile, (int x, int y) ghostPos) {
|
||||
//var tileGo = Instantiate<GameObject>(tilePrefab,corner);
|
||||
var tileGo = Instantiate(tilePrefab, corner);
|
||||
var tr = tileGo.GetComponent<TileRender>();
|
||||
tr.renderer.sortingOrder = 3; // Draw infront of the others!
|
||||
tileGo.transform.localPosition = new Vector3(ghostPos.x * width, ghostPos.y * height);
|
||||
//Debug.Log("Ghosting", tr.gameObject);
|
||||
//Debug.Break();
|
||||
StartCoroutine(HandleGhost(tr,tile.color));
|
||||
}
|
||||
|
||||
public void Crumble(TileInfo tile, (int x, int y) crumblePos) {
|
||||
// Copypastecopypastecopypast - Texel
|
||||
var tileGo = Instantiate(tilePrefab, corner);
|
||||
var tr = tileGo.GetComponent<TileRender>();
|
||||
tr.renderer.sortingOrder = 3; // Draw infront of the others!
|
||||
tileGo.transform.localPosition = new Vector3(crumblePos.x * width, crumblePos.y * height);
|
||||
|
||||
StartCoroutine(HandleCrumble(tr, tile.color, tile.kind));
|
||||
}
|
||||
|
||||
// Float up and fade out
|
||||
IEnumerator HandleGhost(TileRender tr, TileColor color) {
|
||||
float opacity = 1f;
|
||||
while (opacity > 0f) {
|
||||
opacity -= Time.deltaTime;
|
||||
// Move up about one unit over a second?
|
||||
tr.transform.localPosition += new Vector3(0, Time.deltaTime, 0);
|
||||
|
||||
tr.SetDisplay(color, TileKind.Activator);
|
||||
tr.renderer.color = new Color(1, 1, 1, opacity);
|
||||
yield return null;
|
||||
}
|
||||
Destroy(tr.gameObject);
|
||||
}
|
||||
|
||||
// Fall down and fade out
|
||||
IEnumerator HandleCrumble(TileRender tr, TileColor color, TileKind kind) {
|
||||
float opacity = 2f;
|
||||
float sideVel = Random.value - 0.5f;
|
||||
float fallSpeed = 0.9f + (Random.value * 0.3f);
|
||||
|
||||
while (opacity > 0f) {
|
||||
opacity -= Time.deltaTime;
|
||||
tr.transform.localPosition += new Vector3(sideVel * Time.deltaTime, fallSpeed * -Time.deltaTime, 0);
|
||||
|
||||
tr.SetDisplay(color, kind);
|
||||
tr.renderer.color = new Color(1, 1, 1, opacity);
|
||||
yield return null;
|
||||
}
|
||||
Destroy(tr.gameObject);
|
||||
}
|
||||
|
||||
public void RenderPlacement(TileInfo left, TileInfo right, (int x, int y) leftPosition, (int x, int y) rightPosition){
|
||||
place1.transform.localPosition = new Vector3(leftPosition.x * width, leftPosition.y * height);
|
||||
place2.transform.localPosition = new Vector3(rightPosition.x * width, rightPosition.y * height);
|
||||
|
||||
place3.transform.localPosition = new Vector3(board.nextRootX * width, board.nextRootY * height);
|
||||
place4.transform.localPosition = new Vector3(board.nextRootX * width, (board.nextRootY - 1f) * height);
|
||||
|
||||
var np = board.nextPair;
|
||||
place3.SetDisplay(np.left.color, np.left.kind);
|
||||
place4.SetDisplay(np.right.color, np.right.kind);
|
||||
|
||||
place1.SetDisplay(left, left.color, left.kind);
|
||||
place2.SetDisplay(right, right.color, right.kind);
|
||||
}
|
||||
|
||||
void RebuildStack(Transform root, TileList tiles){
|
||||
var spawnOffset = 0f;
|
||||
var maxHeight = height * (GameBoard.ROW + 1);
|
||||
|
||||
for(var i = 0; i < tiles.Count; ++i){
|
||||
var tile = tiles[i];
|
||||
var tilestate = tile.kind;
|
||||
var tileinstance = 0;
|
||||
|
||||
var ttransform = i < root.childCount ? root.GetChild(i) : null;
|
||||
var trender = ttransform != null ? ttransform.GetComponent<TileRender>() : null;
|
||||
|
||||
// new tiles, place them at the top
|
||||
if (ttransform == null){
|
||||
var t = Instantiate(tilePrefab, root).transform;
|
||||
t.localPosition = new Vector3(0f, Mathf.Max(maxHeight, spawnOffset));
|
||||
t.localRotation = Quaternion.identity;
|
||||
t.localScale = Vector3.one;
|
||||
|
||||
t.GetComponent<TileRender>().id = tileinstance;
|
||||
|
||||
spawnOffset = t.localPosition.y + height;
|
||||
}
|
||||
// not in sync, stop destroying
|
||||
else if (tileinstance != trender.id){
|
||||
ttransform.parent = null;
|
||||
Destroy(ttransform.gameObject);
|
||||
i--;
|
||||
}
|
||||
// in sync, continue
|
||||
else {
|
||||
spawnOffset = ttransform.localPosition.y + height;
|
||||
}
|
||||
}
|
||||
|
||||
// any excess tiles are removed
|
||||
while(tiles.Count < root.childCount){
|
||||
var child = root.GetChild(root.childCount - 1);
|
||||
child.parent = null;
|
||||
Destroy(child.gameObject);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static Dictionary<TileColor, Color> colorConversion = new Dictionary<TileColor, Color>(){
|
||||
{ TileColor.Blue, Color.blue },
|
||||
{ TileColor.Green, Color.green },
|
||||
{ TileColor.Red, Color.red },
|
||||
{ TileColor.Yellow, Color.yellow}
|
||||
};
|
||||
|
||||
void DrawStack(Transform root, TileList tiles){
|
||||
var dest = 0f;
|
||||
var speed = Time.deltaTime * tileSpeed;
|
||||
|
||||
for(var i = 0; i < tiles.Count; ++i){
|
||||
var tile = tiles[i];
|
||||
var tilekind = tile.kind;
|
||||
var tilecolor = tile.color;
|
||||
var ttransform = root.GetChild(i);
|
||||
var trender = ttransform.GetComponent<TileRender>();
|
||||
|
||||
if (tilekind != TileKind.Air){
|
||||
// pos
|
||||
var pos = ttransform.localPosition.y;
|
||||
ttransform.localPosition = new Vector3(0f, Mathf.MoveTowards(pos, dest, speed));
|
||||
dest += height;
|
||||
|
||||
// color
|
||||
ttransform.gameObject.SetActive(true);
|
||||
trender.SetDisplay(tile, tilecolor, tilekind);
|
||||
|
||||
// counter
|
||||
trender.SetCounter(tilekind == TileKind.Trash ? tile.counter.ToString() : "");
|
||||
} else {
|
||||
ttransform.gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
11
Assets/RealCode/GameBoardRender.cs.meta
Normal file
11
Assets/RealCode/GameBoardRender.cs.meta
Normal file
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: ab13054faa84a9f43a2e16c145543dc4
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
8
Assets/RealCode/Menu.meta
Normal file
8
Assets/RealCode/Menu.meta
Normal file
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 477f6606b6539ab458dd13dea7db24ee
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
8
Assets/RealCode/Menu/ButtonS.meta
Normal file
8
Assets/RealCode/Menu/ButtonS.meta
Normal file
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 587c73a8c0f8e3c498bb361e2da0b077
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
13
Assets/RealCode/Menu/ButtonS/ButtonConnectArcade.cs
Normal file
13
Assets/RealCode/Menu/ButtonS/ButtonConnectArcade.cs
Normal file
|
@ -0,0 +1,13 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class ButtonConnectArcade : ButtonOnClick {
|
||||
|
||||
public override void OnClick() {
|
||||
if (GameTransition.Instance.state == GameState.Menu) {
|
||||
GameBoardInstance.instance.SetupGame();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
11
Assets/RealCode/Menu/ButtonS/ButtonConnectArcade.cs.meta
Normal file
11
Assets/RealCode/Menu/ButtonS/ButtonConnectArcade.cs.meta
Normal file
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b180e388299c2f14dbe4cb73df1c4bfb
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
83
Assets/RealCode/Menu/ButtonS/ButtonConnectOnline.cs
Normal file
83
Assets/RealCode/Menu/ButtonS/ButtonConnectOnline.cs
Normal file
|
@ -0,0 +1,83 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using ExitGames.Client.Photon.LoadBalancing;
|
||||
|
||||
public class ButtonConnectOnline : ButtonOnClick {
|
||||
|
||||
public static string region;
|
||||
|
||||
public override void OnClick() {
|
||||
if (GameTransition.Instance.state == GameState.Menu) {
|
||||
GameTransition.Instance.state = GameState.ConnectionInProgress;
|
||||
GameTransition.Instance.inMultiplayer = true;
|
||||
StartCoroutine(ConnectToMultiplayerCoroutine());
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerator ConnectToMultiplayerCoroutine(){
|
||||
if (NetworkManager.net.ConnectToNameServer()){
|
||||
Debug.Log("Connecting to name server");
|
||||
} else {
|
||||
Debug.Log("Name Server connection failed");
|
||||
yield break;
|
||||
}
|
||||
|
||||
while (!NetworkManager.onNameServer || !NetworkManager.isReady) yield return null;
|
||||
Debug.Log("Connected to name server");
|
||||
|
||||
if (NetworkManager.net.OpGetRegions()){
|
||||
Debug.Log("Started region request");
|
||||
} else {
|
||||
Debug.Log("Failed region request");
|
||||
yield break;
|
||||
}
|
||||
|
||||
while (NetworkManager.net.AvailableRegions == null) yield return null;
|
||||
Debug.Log("Received region list");
|
||||
|
||||
// testing, quick load
|
||||
if (NetworkManager.instance.quickLoadTestingLobby){
|
||||
region = "usw";
|
||||
}
|
||||
// select best region
|
||||
else {
|
||||
region = null;
|
||||
while(region == null) yield return null;
|
||||
GameTransition.Instance.state = GameState.ConnectionInProgress;
|
||||
}
|
||||
|
||||
|
||||
if(NetworkManager.net.ConnectToRegionMaster(region)){
|
||||
Debug.LogFormat("Connecting to region master '{0}'", region);
|
||||
} else {
|
||||
Debug.LogFormat("Failed to connect to region master '{0}'", region);
|
||||
yield break;
|
||||
}
|
||||
|
||||
while (!NetworkManager.onMasterLobby) yield return null;
|
||||
Debug.Log("Connected to region master");
|
||||
Debug.Log("You can quick join now");
|
||||
|
||||
// testing, quick load
|
||||
if (NetworkManager.instance.quickLoadTestingLobby){
|
||||
var activeScene = "QUICKJOIN";
|
||||
|
||||
var ro = new RoomOptions();
|
||||
ro.IsVisible = false;
|
||||
ro.IsOpen = true;
|
||||
ro.MaxPlayers = NetworkManager.instance.expectedMaxPlayers;
|
||||
|
||||
NetworkManager.net.OpJoinOrCreateRoomWithProperties(activeScene, ro, null);
|
||||
|
||||
// connect to room
|
||||
while(!NetworkManager.inRoom) yield return null;
|
||||
|
||||
// wait for max players to auto start
|
||||
while(NetworkManager.net.CurrentRoom.PlayerCount != NetworkManager.instance.expectedMaxPlayers) yield return null;
|
||||
|
||||
GameBoardInstance.instance.SetupGame();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
11
Assets/RealCode/Menu/ButtonS/ButtonConnectOnline.cs.meta
Normal file
11
Assets/RealCode/Menu/ButtonS/ButtonConnectOnline.cs.meta
Normal file
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: f4e462570ffc55746b27123581212710
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
45
Assets/RealCode/Menu/ButtonS/ButtonCreateLobby.cs
Normal file
45
Assets/RealCode/Menu/ButtonS/ButtonCreateLobby.cs
Normal file
|
@ -0,0 +1,45 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
using ClientState = ExitGames.Client.Photon.LoadBalancing.ClientState;
|
||||
using RoomInfo = ExitGames.Client.Photon.LoadBalancing.RoomInfo;
|
||||
using RoomOptions = ExitGames.Client.Photon.LoadBalancing.RoomOptions;
|
||||
|
||||
public class ButtonCreateLobby : ButtonOnClick {
|
||||
|
||||
public override void OnClick() {
|
||||
if (GameTransition.Instance.state == GameState.Multiplayer){
|
||||
GameTransition.Instance.state = GameState.ConnectionInProgress;
|
||||
Debug.Log("Creating room");
|
||||
|
||||
var ro = new RoomOptions();
|
||||
ro.EmptyRoomTtl = 1000;
|
||||
ro.CleanupCacheOnLeave = true;
|
||||
ro.PlayerTtl = 500;
|
||||
ro.PublishUserId = false;
|
||||
ro.MaxPlayers = 2; // TODO: Expose this better
|
||||
|
||||
string roomCode = string.Empty;
|
||||
var roomList = NetworkManager.net.RoomInfoList.Keys.ToList();
|
||||
do {
|
||||
roomCode = string.Format("{0}{1}{2}{3}", RandomDigit(), RandomDigit(), RandomDigit(), RandomDigit());
|
||||
} while (roomList.Contains(roomCode));
|
||||
|
||||
LobbySetup.Instance.Setup();
|
||||
|
||||
var success = NetworkManager.net.OpCreateRoomWithProperties(roomCode, ro, ExitGames.Client.Photon.LoadBalancing.TypedLobby.Default);
|
||||
if (success) {
|
||||
Debug.Log("Room created");
|
||||
} else {
|
||||
Debug.Log("Failed to connect to room");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int RandomDigit() {
|
||||
return Random.Range(0, 10);
|
||||
}
|
||||
|
||||
}
|
11
Assets/RealCode/Menu/ButtonS/ButtonCreateLobby.cs.meta
Normal file
11
Assets/RealCode/Menu/ButtonS/ButtonCreateLobby.cs.meta
Normal file
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 8f61e54fc64c3ac49bf99ba0c36fb95e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
20
Assets/RealCode/Menu/ButtonS/ButtonDisconnect.cs
Normal file
20
Assets/RealCode/Menu/ButtonS/ButtonDisconnect.cs
Normal file
|
@ -0,0 +1,20 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
using ClientState = ExitGames.Client.Photon.LoadBalancing.ClientState;
|
||||
|
||||
public class ButtonDisconnect : ButtonOnClick {
|
||||
|
||||
public ClientState state => NetworkManager.net.State;
|
||||
public bool isDisconnected => state == ClientState.Disconnected || state == ClientState.PeerCreated;
|
||||
|
||||
public override void OnClick() {
|
||||
if (GameTransition.Instance.state == GameState.Multiplayer) {
|
||||
GameTransition.Instance.state = GameState.ConnectionInProgress;
|
||||
NetworkManager.net.Service();
|
||||
NetworkManager.net.Disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
11
Assets/RealCode/Menu/ButtonS/ButtonDisconnect.cs.meta
Normal file
11
Assets/RealCode/Menu/ButtonS/ButtonDisconnect.cs.meta
Normal file
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: bda166cb3696bbf44a36856632e823ae
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
27
Assets/RealCode/Menu/ButtonS/ButtonJoinLobby.cs
Normal file
27
Assets/RealCode/Menu/ButtonS/ButtonJoinLobby.cs
Normal file
|
@ -0,0 +1,27 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using TMPro;
|
||||
|
||||
public class ButtonJoinLobby : ButtonOnClick {
|
||||
|
||||
public TMP_InputField joinField;
|
||||
|
||||
public override void OnClick() {
|
||||
if (GameTransition.Instance.state == GameState.Multiplayer){
|
||||
GameTransition.Instance.state = GameState.ConnectionInProgress;
|
||||
|
||||
LobbySetup.Instance.Setup();
|
||||
|
||||
var roomCode = joinField.text;
|
||||
Debug.LogFormat("Joining room '{0}'", roomCode);
|
||||
if (NetworkManager.net.OpJoinRoomWithProperties(roomCode)) {
|
||||
Debug.Log("Room joined");
|
||||
} else {
|
||||
Debug.Log("Couldn't join room");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
11
Assets/RealCode/Menu/ButtonS/ButtonJoinLobby.cs.meta
Normal file
11
Assets/RealCode/Menu/ButtonS/ButtonJoinLobby.cs.meta
Normal file
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: dda82481bd0d3ab4c8e4d41c04475835
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
14
Assets/RealCode/Menu/ButtonS/ButtonLeaveLobby.cs
Normal file
14
Assets/RealCode/Menu/ButtonS/ButtonLeaveLobby.cs
Normal file
|
@ -0,0 +1,14 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class ButtonLeaveLobby : ButtonOnClick {
|
||||
|
||||
public override void OnClick() {
|
||||
if (GameTransition.Instance.state == GameState.Lobby) {
|
||||
GameTransition.Instance.state = GameState.ConnectionInProgress;
|
||||
NetworkManager.net.OpLeaveRoom();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
11
Assets/RealCode/Menu/ButtonS/ButtonLeaveLobby.cs.meta
Normal file
11
Assets/RealCode/Menu/ButtonS/ButtonLeaveLobby.cs.meta
Normal file
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 0be7eb25514620d47bc3fbeff009a735
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
7
Assets/RealCode/Menu/ButtonS/ButtonOnClick.cs
Normal file
7
Assets/RealCode/Menu/ButtonS/ButtonOnClick.cs
Normal file
|
@ -0,0 +1,7 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public abstract class ButtonOnClick : MonoBehaviour {
|
||||
public abstract void OnClick();
|
||||
}
|
11
Assets/RealCode/Menu/ButtonS/ButtonOnClick.cs.meta
Normal file
11
Assets/RealCode/Menu/ButtonS/ButtonOnClick.cs.meta
Normal file
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 117c2cfc8bc6dd342bc6836cef88ab81
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
12
Assets/RealCode/Menu/ButtonS/ButtonReadyUp.cs
Normal file
12
Assets/RealCode/Menu/ButtonS/ButtonReadyUp.cs
Normal file
|
@ -0,0 +1,12 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class ButtonReadyUp : ButtonOnClick {
|
||||
|
||||
public override void OnClick() {
|
||||
if (GameTransition.Instance.state == GameState.Lobby)
|
||||
PlayerProperties.lobbyStatus.SetLocal(!PlayerProperties.lobbyStatus.GetLocal());
|
||||
}
|
||||
|
||||
}
|
11
Assets/RealCode/Menu/ButtonS/ButtonReadyUp.cs.meta
Normal file
11
Assets/RealCode/Menu/ButtonS/ButtonReadyUp.cs.meta
Normal file
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 16215d74378700844ae416c1de7db07d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
13
Assets/RealCode/Menu/ButtonS/ButtonSelectRegionMaster.cs
Normal file
13
Assets/RealCode/Menu/ButtonS/ButtonSelectRegionMaster.cs
Normal file
|
@ -0,0 +1,13 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class ButtonSelectRegionMaster : ButtonOnClick {
|
||||
|
||||
public string region;
|
||||
|
||||
public override void OnClick() {
|
||||
ButtonConnectOnline.region = region;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c68f2d0c5c989ac40b86c84c3c241d71
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
22
Assets/RealCode/Menu/ButtonS/ButtonSwitchLanguages.cs
Normal file
22
Assets/RealCode/Menu/ButtonS/ButtonSwitchLanguages.cs
Normal file
|
@ -0,0 +1,22 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class ButtonSwitchLanguages : ButtonOnClick {
|
||||
|
||||
private void Awake() {
|
||||
Localization.SelectedLanguage = (LocalizationLanguage)PlayerPrefs.GetInt("lang", 0);
|
||||
}
|
||||
|
||||
public override void OnClick() {
|
||||
Localization.SelectedLanguage = Localization.SelectedLanguage == LocalizationLanguage.English ? LocalizationLanguage.Japanese : LocalizationLanguage.English;
|
||||
PlayerPrefs.SetInt("lang", (int)Localization.SelectedLanguage);
|
||||
Localization.RebuildKeyDictionary();
|
||||
|
||||
var injector = FindObjectsOfType<LocalizationButtonInjector>();
|
||||
foreach(var i in injector){
|
||||
i.UpdateText();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
11
Assets/RealCode/Menu/ButtonS/ButtonSwitchLanguages.cs.meta
Normal file
11
Assets/RealCode/Menu/ButtonS/ButtonSwitchLanguages.cs.meta
Normal file
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 8ecef12b4d0865c49920da1e92c82a87
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
66
Assets/RealCode/Menu/ButtonS/MainMenuButton.cs
Normal file
66
Assets/RealCode/Menu/ButtonS/MainMenuButton.cs
Normal file
|
@ -0,0 +1,66 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityEngine.EventSystems;
|
||||
|
||||
public class MainMenuButton : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler, ISelectHandler, IDeselectHandler, IPointerDownHandler, IPointerUpHandler {
|
||||
|
||||
[Header("References")]
|
||||
public Image targetGraphic;
|
||||
public RectTransform targetTransform;
|
||||
public bool pointerSelected;
|
||||
public bool keyboardSelected;
|
||||
public bool pressed;
|
||||
|
||||
[Header("Style")]
|
||||
public Color baseColor;
|
||||
public Color selectedColor;
|
||||
public float baseWidth;
|
||||
public float selectedWidth;
|
||||
public Color tintColor;
|
||||
|
||||
public void OnPointerEnter(PointerEventData eventData) {
|
||||
pointerSelected = true;
|
||||
}
|
||||
|
||||
public void OnPointerExit(PointerEventData eventData) {
|
||||
pointerSelected = false;
|
||||
}
|
||||
|
||||
public void OnSelect(BaseEventData eventData) {
|
||||
keyboardSelected = true;
|
||||
}
|
||||
|
||||
public void OnDeselect(BaseEventData eventData) {
|
||||
keyboardSelected = false;
|
||||
}
|
||||
|
||||
public void OnPointerDown(PointerEventData eventData) {
|
||||
pressed = true;
|
||||
}
|
||||
|
||||
public void OnPointerUp(PointerEventData eventData) {
|
||||
pressed = false;
|
||||
}
|
||||
|
||||
void Start(){
|
||||
var b = GetComponent<Button>();
|
||||
if (b){
|
||||
b.onClick.RemoveAllListeners();
|
||||
|
||||
var click = GetComponent<ButtonOnClick>();
|
||||
if (click)
|
||||
b.onClick.AddListener(click.OnClick);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Update is called once per frame
|
||||
void Update() {
|
||||
var selected = keyboardSelected || pointerSelected;
|
||||
targetGraphic.color = (selected ? selectedColor : baseColor) * (pressed ? tintColor : Color.white);
|
||||
targetTransform.sizeDelta = new Vector2(selected ? selectedWidth : baseWidth, targetTransform.sizeDelta.y);
|
||||
}
|
||||
|
||||
}
|
11
Assets/RealCode/Menu/ButtonS/MainMenuButton.cs.meta
Normal file
11
Assets/RealCode/Menu/ButtonS/MainMenuButton.cs.meta
Normal file
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: bcbd46c9872ea004ba60441124c200df
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
21
Assets/RealCode/Menu/ButtonS/NicknameField.cs
Normal file
21
Assets/RealCode/Menu/ButtonS/NicknameField.cs
Normal file
|
@ -0,0 +1,21 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using TMPro;
|
||||
|
||||
public class NicknameField : MonoBehaviour {
|
||||
|
||||
public TMP_InputField field;
|
||||
|
||||
private void Start() {
|
||||
field.text = PlayerProperties.GetPlayerNickname();
|
||||
}
|
||||
|
||||
private void Update() {
|
||||
var nn = field.text;
|
||||
if (PlayerProperties.localPlayer.NickName != nn){
|
||||
PlayerProperties.SetPlayerNickname(nn);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
11
Assets/RealCode/Menu/ButtonS/NicknameField.cs.meta
Normal file
11
Assets/RealCode/Menu/ButtonS/NicknameField.cs.meta
Normal file
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 666188a1504035c4f9f23134443092c7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
8971
Assets/RealCode/Menu/Canvas.prefab
Normal file
8971
Assets/RealCode/Menu/Canvas.prefab
Normal file
File diff suppressed because it is too large
Load diff
7
Assets/RealCode/Menu/Canvas.prefab.meta
Normal file
7
Assets/RealCode/Menu/Canvas.prefab.meta
Normal file
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: adba91609cb1e5448b76682be198fc9b
|
||||
PrefabImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
156
Assets/RealCode/Menu/GameTransition.cs
Normal file
156
Assets/RealCode/Menu/GameTransition.cs
Normal file
|
@ -0,0 +1,156 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
using System.Linq;
|
||||
|
||||
public enum GameState { Menu, SinglePlayer, Multiplayer, Lobby, SelectingRegion, ConnectionInProgress, InGame, Continue }
|
||||
|
||||
public class GameTransition : MonoBehaviour {
|
||||
|
||||
public static GameTransition Instance { get; private set; }
|
||||
|
||||
[SerializeField]
|
||||
private GameState _state;
|
||||
public GameState state {
|
||||
get => _state;
|
||||
set {
|
||||
if (_state == value) return;
|
||||
|
||||
_state = value;
|
||||
EventSystem.current.SetSelectedGameObject(null);
|
||||
var select = rDisplays.FirstOrDefault(d => d.states.Contains(value) && d.firstSelectedGameObject != null);
|
||||
if (select != null)
|
||||
EventSystem.current.SetSelectedGameObject(select.firstSelectedGameObject);
|
||||
}
|
||||
}
|
||||
|
||||
public bool inMultiplayer;
|
||||
|
||||
public float lerpSpeed = 10f;
|
||||
|
||||
[System.Serializable]
|
||||
private class RectTransformDisplay{
|
||||
public RectTransform target = null;
|
||||
public GameState[] states = new GameState[] { GameState.Menu };
|
||||
|
||||
[System.NonSerialized]
|
||||
public Vector2 basePosition = Vector2.zero;
|
||||
public Vector2 selectedPosition = Vector2.zero;
|
||||
public GameObject firstSelectedGameObject = null;
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
private class TransformDisplay : TransformDefault{
|
||||
public GameState[] states = new GameState[] { GameState.Menu };
|
||||
public int playerLoadedCount = 0;
|
||||
|
||||
public TransformDisplay(Transform t, Vector3 p, Vector3 r, Vector3 s) : base(t, p, r, s) { }
|
||||
}
|
||||
|
||||
private class TransformDefault{
|
||||
public Transform target = null;
|
||||
|
||||
public Vector3 position = Vector3.zero;
|
||||
public Vector3 rotation = Vector3.zero;
|
||||
public Vector3 scale = Vector3.one;
|
||||
|
||||
public TransformDefault(Transform t, Vector3 p, Vector3 r, Vector3 s){
|
||||
target = t;
|
||||
position = p;
|
||||
rotation = r;
|
||||
scale = s;
|
||||
}
|
||||
|
||||
public void Set(float lerp){
|
||||
target.localPosition = Vector3.Lerp(target.localPosition, position, lerp);
|
||||
target.localRotation = Quaternion.Slerp(target.localRotation, Quaternion.Euler(rotation), lerp);
|
||||
target.localScale = Vector3.Lerp(target.localScale, scale, lerp);
|
||||
}
|
||||
}
|
||||
|
||||
private TransformDefault[] tDefault;
|
||||
|
||||
[SerializeField]
|
||||
private RectTransformDisplay[] rDisplays = new RectTransformDisplay[0];
|
||||
|
||||
[SerializeField]
|
||||
private TransformDisplay[] tDisplays = new TransformDisplay[0];
|
||||
|
||||
public GameState[] selectedOrthoStates;
|
||||
public float selectedCameraOrthoSize = 3f;
|
||||
private float baseCameraOrthoSize;
|
||||
private Camera baseCamera;
|
||||
|
||||
private void Awake() {
|
||||
Instance = this;
|
||||
}
|
||||
|
||||
private void Start() {
|
||||
baseCamera = Camera.main;
|
||||
baseCameraOrthoSize = baseCamera.orthographicSize;
|
||||
|
||||
foreach(var r in rDisplays){
|
||||
r.basePosition = r.target.anchoredPosition;
|
||||
}
|
||||
|
||||
tDefault = tDisplays.Select(t => t.target).Distinct().Select(t => new TransformDefault(t, t.localPosition, t.localEulerAngles, t.localScale)).ToArray();
|
||||
}
|
||||
|
||||
private void Update() {
|
||||
|
||||
if (inMultiplayer){
|
||||
switch(NetworkManager.net.State){
|
||||
case ExitGames.Client.Photon.LoadBalancing.ClientState.Disconnected:
|
||||
case ExitGames.Client.Photon.LoadBalancing.ClientState.PeerCreated:
|
||||
state = GameState.Menu;
|
||||
inMultiplayer = false;
|
||||
break;
|
||||
case ExitGames.Client.Photon.LoadBalancing.ClientState.ConnectedToNameServer:
|
||||
state = GameState.SelectingRegion;
|
||||
break;
|
||||
case ExitGames.Client.Photon.LoadBalancing.ClientState.JoinedLobby:
|
||||
state = GameState.Multiplayer;
|
||||
break;
|
||||
case ExitGames.Client.Photon.LoadBalancing.ClientState.Joined:
|
||||
state = GameState.Lobby;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// transform
|
||||
var dist = Time.deltaTime * lerpSpeed;
|
||||
var playersLoaded = NetworkManager.inRoom ? NetworkManager.net.CurrentRoom.PlayerCount : 2;
|
||||
|
||||
foreach(var d in rDisplays){
|
||||
var selected = d.states.Contains(state);
|
||||
|
||||
var item = d.target;
|
||||
if (item){
|
||||
item.anchoredPosition = Vector3.Lerp(item.anchoredPosition, selected ? d.selectedPosition : d.basePosition, dist);
|
||||
}
|
||||
}
|
||||
|
||||
var set = new Dictionary<Transform, TransformDefault>();
|
||||
foreach(var t in tDefault)
|
||||
set.Add(t.target, t);
|
||||
|
||||
foreach(var d in tDisplays){
|
||||
var selected = d.states.Contains(state);
|
||||
|
||||
if (selected && d.playerLoadedCount <= playersLoaded){
|
||||
d.Set(dist);
|
||||
set.Remove(d.target);
|
||||
}
|
||||
}
|
||||
|
||||
foreach(var d in set){
|
||||
d.Value.Set(dist);
|
||||
}
|
||||
|
||||
baseCamera.orthographicSize = Mathf.Lerp(baseCamera.orthographicSize, selectedOrthoStates.Contains(state) ? selectedCameraOrthoSize : baseCameraOrthoSize, dist);
|
||||
|
||||
}
|
||||
}
|
11
Assets/RealCode/Menu/GameTransition.cs.meta
Normal file
11
Assets/RealCode/Menu/GameTransition.cs.meta
Normal file
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 31f8c272002349f4fa1738a050947564
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
77
Assets/RealCode/Menu/LobbySetup.cs
Normal file
77
Assets/RealCode/Menu/LobbySetup.cs
Normal file
|
@ -0,0 +1,77 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using TMPro;
|
||||
|
||||
public class LobbySetup : MonoBehaviour {
|
||||
|
||||
public static LobbySetup Instance { get; private set; }
|
||||
|
||||
public Transform readyCheck1, readyCheck2;
|
||||
public Image readyImage1, readyImage2;
|
||||
public TextMeshProUGUI readyStatus;
|
||||
|
||||
[Header("Messages")]
|
||||
public string waitingKey;
|
||||
|
||||
public int dotMax = 3;
|
||||
public float dotDuration = 1f;
|
||||
|
||||
|
||||
private void Awake() {
|
||||
Instance = this;
|
||||
}
|
||||
|
||||
public void Setup(){
|
||||
PlayerProperties.CreatePlayerHashtable();
|
||||
}
|
||||
|
||||
// Update is called once per frame
|
||||
void Update() {
|
||||
var delta = Time.deltaTime * 180f;
|
||||
|
||||
if (NetworkManager.inRoom && GameTransition.Instance.state == GameState.Lobby){
|
||||
// we setting player values by their id order
|
||||
|
||||
var players = NetworkManager.net.CurrentRoom.Players.Values.OrderBy(p => p.ID);
|
||||
var p1 = players.ElementAtOrDefault(0);
|
||||
var p2 = players.ElementAtOrDefault(1);
|
||||
|
||||
// displays
|
||||
if (p1 != null){
|
||||
if (p1.IsLocal){
|
||||
PlayerProperties.playerCharacter.SetLocal(0);
|
||||
GameBoardInstance.instance.player1.authorityID = p1.ID;
|
||||
}
|
||||
var pready = PlayerProperties.lobbyStatus.Get(p1);
|
||||
readyCheck1.localRotation = Quaternion.RotateTowards(readyCheck1.localRotation, pready ? Quaternion.identity : Quaternion.Euler(0f, 0f, 45f), delta);
|
||||
readyImage1.color = pready ? Color.green : Color.red;
|
||||
}
|
||||
|
||||
// displays
|
||||
if (p2 != null){
|
||||
readyCheck2.gameObject.SetActive(true);
|
||||
if (p2.IsLocal) {
|
||||
PlayerProperties.playerCharacter.SetLocal(1);
|
||||
GameBoardInstance.instance.player2.authorityID = p2.ID;
|
||||
}
|
||||
var pready = PlayerProperties.lobbyStatus.Get(p1);
|
||||
readyCheck2.localRotation = Quaternion.RotateTowards(readyCheck1.localRotation, pready ? Quaternion.identity : Quaternion.Euler(0f, 0f, 45f), delta);
|
||||
readyImage2.color = pready ? Color.green : Color.red;
|
||||
} else {
|
||||
GameBoardInstance.instance.player2.authorityID = -1;
|
||||
readyCheck2.gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
readyStatus.text = Localization.GetString(waitingKey) + new string('.', Mathf.RoundToInt(Time.time / dotDuration) % dotMax);
|
||||
|
||||
if (PlayerProperties.GetAllLobbyStatus()){
|
||||
GameBoardInstance.instance.SetupGame();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
11
Assets/RealCode/Menu/LobbySetup.cs.meta
Normal file
11
Assets/RealCode/Menu/LobbySetup.cs.meta
Normal file
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: dc6fbe0d7ac22c949ab3227d60cd4152
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
130
Assets/RealCode/TileInfo.cs
Normal file
130
Assets/RealCode/TileInfo.cs
Normal file
|
@ -0,0 +1,130 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// Represents tile
|
||||
/// </summary>
|
||||
///
|
||||
|
||||
// ee dc bb aa
|
||||
// aa = color
|
||||
// bb = state/kind
|
||||
// c = special
|
||||
// d = activating/animation
|
||||
// ee = trash value
|
||||
|
||||
public enum TileColor : byte {
|
||||
Blue = 0,
|
||||
Red = 1,
|
||||
Yellow = 2,
|
||||
Green = 3
|
||||
}
|
||||
|
||||
public enum TileKind : byte {
|
||||
Air = 0,
|
||||
Block = 4,
|
||||
Activator = 8,
|
||||
Special = 12,
|
||||
Activiting = 16,
|
||||
Trash = 20
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper data structure for determining anything about a tile.
|
||||
/// </summary>
|
||||
[System.Serializable] // I guess so we can serialize patterns
|
||||
public class TileInfo {
|
||||
static uint _instanceCounter;
|
||||
private static byte _instance {
|
||||
get {
|
||||
return (byte)(_instanceCounter++ & 0x7F);
|
||||
}
|
||||
}
|
||||
|
||||
public short dat;
|
||||
|
||||
public TileInfo(short b) => dat = b;
|
||||
|
||||
// Removing so that the counter one works better
|
||||
/*public TileInfo(TileKind tk, TileColor tc, byte tileValue ) {
|
||||
dat = (short)((byte)tk | (byte)tc | (tileValue << 8));
|
||||
}*/
|
||||
|
||||
public static int ToPairInt((TileInfo left, TileInfo right) pair) {
|
||||
return ((int)pair.left.dat << 16) | (int)pair.right.dat;
|
||||
}
|
||||
public static (TileInfo left, TileInfo right) FromPairInt(int i) {
|
||||
return ((TileInfo)(short)(i >> 16), (TileInfo)(short)(i & 0x00FF));
|
||||
}
|
||||
public TileInfo(TileKind tk, TileColor tc, byte counter) {
|
||||
dat = (short)((byte)tk | (byte)tc | (counter << 5) | (_instance << 8));
|
||||
}
|
||||
|
||||
public TileInfo(TileKind tk, TileColor tc) {
|
||||
dat = (short)((byte)tk | (byte)tc | (_instance << 8));
|
||||
}
|
||||
|
||||
|
||||
public void Deconstruct(out short b) => b = dat;
|
||||
|
||||
private static TileColor getRandomColor {
|
||||
get {
|
||||
return (TileColor)Random.Range(0, 4);
|
||||
}
|
||||
}
|
||||
|
||||
public static TileInfo CreateAirTile() {
|
||||
return new TileInfo(TileKind.Air, TileColor.Blue);
|
||||
}
|
||||
|
||||
public static TileInfo CreateRandomBlockTile() {
|
||||
return new TileInfo(TileKind.Block, getRandomColor);
|
||||
}
|
||||
|
||||
public static TileInfo CreateRandomActivatorTile() {
|
||||
return new TileInfo(TileKind.Activator, getRandomColor);
|
||||
}
|
||||
|
||||
public static TileInfo CreateSpecialTile() {
|
||||
return new TileInfo(TileKind.Special, TileColor.Blue);
|
||||
}
|
||||
|
||||
public static TileInfo CreateRandomTrashTile() {
|
||||
return new TileInfo(TileKind.Trash, getRandomColor, 5);
|
||||
}
|
||||
|
||||
public static void SetAirTile(TileInfo ti) {
|
||||
ti.kind = TileKind.Air;
|
||||
ti.color = TileColor.Blue;
|
||||
}
|
||||
|
||||
public TileColor color {
|
||||
get => (TileColor)(dat & 0x0003);
|
||||
set => dat = (short)((dat & 0xFFFC) | (byte)value);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public TileKind kind {
|
||||
get => (TileKind)(dat & 0x001C);
|
||||
set => dat = (short)((dat & 0xFFE3) + (byte)value);
|
||||
}
|
||||
|
||||
public byte counter {
|
||||
get => (byte)((dat & 0x00E0) >> 5);
|
||||
set => dat = (short)((dat & 0xFF1F) | (value << 5));
|
||||
}
|
||||
|
||||
public byte tileValue {
|
||||
get => (byte)(dat >> 8);
|
||||
}
|
||||
|
||||
public static implicit operator short(TileInfo ti) {
|
||||
return ti.dat;
|
||||
}
|
||||
|
||||
public static explicit operator TileInfo(short b) {
|
||||
return new TileInfo(b);
|
||||
}
|
||||
}
|
11
Assets/RealCode/TileInfo.cs.meta
Normal file
11
Assets/RealCode/TileInfo.cs.meta
Normal file
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 082f457280b46a3429eb39d386aad97f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
44
Assets/RealCode/TileRender.cs
Normal file
44
Assets/RealCode/TileRender.cs
Normal file
|
@ -0,0 +1,44 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using TMPro;
|
||||
|
||||
public class TileRender : MonoBehaviour {
|
||||
|
||||
public new SpriteRenderer renderer;
|
||||
public TextMeshPro textMesh;
|
||||
public int id;
|
||||
|
||||
public void SetDisplay(TileColor color, TileKind kind) {
|
||||
SetDisplay(null, color, kind);
|
||||
}
|
||||
|
||||
public void SetDisplay(TileInfo tile, TileColor color, TileKind kind){
|
||||
Sprite[] sprites;
|
||||
switch(kind){
|
||||
case TileKind.Block:
|
||||
case TileKind.Trash:
|
||||
sprites = GameBoardInstance.instance.regular;
|
||||
break;
|
||||
case TileKind.Activator:
|
||||
sprites = GameBoardInstance.instance.activators;
|
||||
break;
|
||||
case TileKind.Activiting:
|
||||
sprites = GameBoardInstance.instance.lit;
|
||||
break;
|
||||
default:
|
||||
sprites = null;
|
||||
Debug.LogErrorFormat(this.gameObject,"{0}, {1}, {2} not supported by tile display", tile.color, tile.kind, tile.counter);
|
||||
//Debug.LogFormat("TileInfo Instance {0}",TileInfo._instance);
|
||||
break;
|
||||
}
|
||||
|
||||
var s = sprites[(int)color];
|
||||
renderer.sprite = s;
|
||||
}
|
||||
|
||||
public void SetCounter(string text){
|
||||
textMesh.text = text;
|
||||
}
|
||||
|
||||
}
|
11
Assets/RealCode/TileRender.cs.meta
Normal file
11
Assets/RealCode/TileRender.cs.meta
Normal file
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 19e461da8572fd340b69475d29ae84f4
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Loading…
Add table
Add a link
Reference in a new issue