Разработка игрового приложения
Обзор операционных систем. Разработка сцены игрового процесса. Настройка режима свободной игры в жанре лабиринт. Основные требования к игровому приложению. Выбор текстуры игрового персонажа. Разработка архитектуры и кода. Диаграммы классов обработки меню.
Рубрика | Программирование, компьютеры и кибернетика |
Вид | дипломная работа |
Язык | русский |
Дата добавления | 14.12.2019 |
Размер файла | 1,9 M |
Отправить свою хорошую работу в базу знаний просто. Используйте форму, расположенную ниже
Студенты, аспиранты, молодые ученые, использующие базу знаний в своей учебе и работе, будут вам очень благодарны.
private static readonly Single activationDistance;
public static Boolean Swiped { private set; get; }
public static Direction LastDirection { private set; get; }
static SwipeManager()
{
activationDistance = Mathf.Min(Screen.width, Screen.height) * 0.05f;
}
public static void Update(MazeSystem mazeSystem)
{
Swiped = false;
if (Input.touchCount == 1)
{
Touch touch = Input.GetTouch(0);
switch(touch.phase)
{
case TouchPhase.Began:
firstPosition = touch.position;
break;
case TouchPhase.Ended:
lastPosition = touch.position;
Vector3 delta = lastPosition - firstPosition;
if (delta.magnitude >= activationDistance)
{
Swiped = true;
Single angle = Mathf.Atan2(delta.y, delta.x) - mazeSystem.TilePrefab.transform.rotation.eulerAngles.z / 180.0f * Mathf.PI;
if (angle < -Mathf.PI)
{
angle += 2 * Mathf.PI;
}
LastDirection = null;
for (Int32 i = 0; i < mazeSystem.DirectionCount; i++)
{
Direction direction = mazeSystem.GetDirection(i);
Single relativeAngle = Mathf.Abs(angle - direction.Angle);
if (relativeAngle > Mathf.PI)
{
relativeAngle = Mathf.Abs(relativeAngle - 2 * Mathf.PI);
}
if (relativeAngle < mazeSystem.HalfDirectionSegment)
{
LastDirection = direction;
break;
}
}
}
break;
}
}
}
}
}
#endif
Move.cs
using System;
using UnityEngine;
namespace Maze.Animations.Players
{
public class Move : StateMachineBehaviour
{
public override void OnStateUpdate(Animator animator, AnimatorStateInfo stateInfo, Int32 layerIndex)
{
Single time = animator.GetFloat("InMoveNormalizedTime");
Single delta = Time.deltaTime / stateInfo.length;
if (animator.GetBool("Direct Order"))
{
time += delta;
if (time > 1.0f)
{
time -= (Int32)time;
}
}
else
{
time -= delta;
if (time < 0.0f)
{
time -= (Int32)time;
}
}
animator.SetFloat("InMoveNormalizedTime", time);
}
}
}
Win.cs
using System;
using UnityEngine;
using UnityEngine.SceneManagement;
namespace Maze.Animations.Players
{
public class Win : StateMachineBehaviour
{
public override void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, Int32 layerIndex)
{
if (Properties.IsFreePlay)
{
animator.GetComponentInParent<Reals.Maze>().Restart();
}
else
{
Properties.MenuState = Properties.IsFreePlay ? Menu.MenuStates.FreePlay : Menu.MenuStates.Campaign;
SceneManager.LoadScene("Menu", LoadSceneMode.Single);
}
}
}
}
Appearance.cs
using System;
using UnityEngine;
namespace Maze.Animations.Tiles
{
public class Appearance : Disappearance
{
protected override Boolean MakeVisible => true;
protected override Single StartValue => 0.0f;
protected override Single EndValue => 1.0f;
}
}
Disappearance.cs
using System;
using UnityEngine;
namespace Maze.Animations.Tiles
{
public class Disappearance : Visible
{
protected override Boolean MakeVisible => false;
protected virtual Single EndValue => 0.0f;
public override void OnStateUpdate(Animator animator, AnimatorStateInfo stateInfo, Int32 layerIndex)
{
SetOpacity(tile.Opacity);
}
public override void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, Int32 layerIndex)
{
SetOpacity(EndValue);
}
}
}
Invisible.cs
using System;
using UnityEngine;
namespace Maze.Animations.Tiles
{
public class Invisible : Visible
{
protected override Boolean MakeVisible => false;
protected override Single StartValue => 0.0f;
}
}
Visible.cs
using Maze.Helpers;
using Maze.Reals;
using System;
using System.Collections.Generic;
using UnityEngine;
namespace Maze.Animations.Tiles
{
public class Visible : StateMachineBehaviour
{
protected Tile tile;
protected List<SpriteRenderer> renderers;
protected virtual Boolean MakeVisible => true;
protected virtual Single StartValue => 1.0f;
public override void OnStateEnter(Animator animator, AnimatorStateInfo animatorStateInfo, Int32 layerIndex)
{
Initialize(animator);
SetOpacity(StartValue);
tile.Visible = MakeVisible;
}
protected void Initialize(Animator animator)
{
tile = animator.GetComponentInParent<Tile>();
renderers = TileHelper.GetRenderers(tile, MakeVisible);
}
protected void SetOpacity(Single opacity)
{
if (!tile.OpacityUpdated)
{
return;
}
foreach (SpriteRenderer renderer in renderers)
{
Color color = renderer.color;
color.a = opacity;
renderer.color = color;
}
}
}
}
Direction.cs
using System;
using UnityEngine;
namespace Maze.Commons
{
public class Direction
{
public readonly Int32 Id;
public readonly Vector3 Vector;
public readonly Single Angle;
public readonly Quaternion Quaternion;
private readonly Direction[] directions;
private Direction(Int32 id, Vector3 vector, Single angle, Quaternion quaternion, Direction[] directions)
{
Id = id;
Vector = vector;
Angle = angle;
Quaternion = quaternion;
this.directions = directions;
}
public static Direction[] CreateDirections(Int32 count)
{
Direction[] directions = new Direction[count];
for (Int32 i = 0; i < count; i++)
{
Single angle = Mathf.PI * 2 * i / count;
if (angle > Mathf.PI)
{
angle -= 2 * Mathf.PI;
}
directions[i] = new Direction(
i,
new Vector3(Mathf.Cos(angle), Mathf.Sin(angle)),
angle,
Quaternion.Euler(0.0f, 0.0f, 360.0f * i / count),
directions);
}
return directions;
}
public override Boolean Equals(System.Object obj)
{
return obj is Direction direction && Id == direction.Id;
}
public override Int32 GetHashCode()
{
return Id.GetHashCode();
}
public static Boolean operator ==(Direction left, Direction right)
{
if (left is null)
{
return right is null;
}
return left.Equals(right);
}
public static Boolean operator !=(Direction left, Direction right)
{
return !(left == right);
}
public Direction Next()
{
return directions[(Id + 1) % directions.Length];
}
public Direction Previous()
{
return directions[(Id - 1 + directions.Length) % directions.Length];
}
public Direction Opposite()
{
return directions[(Id + directions.Length / 2) % directions.Length];
}
}
}
MazeSystem.cs
using Maze.Reals;
using System;
using UnityEngine;
namespace Maze.Commons
{
public class MazeSystem : MonoBehaviour
{
// Количество направлений, в которых можно перемещаться из ячейки
public Int32 DirectionCount;
// Максимальное количество ячеек в углу ячейки
public Int32 WallEdgeTileCount { private set; get; }
public Single HalfDirectionSegment { private set; get; }
private Direction[] directions;
public Polygon Polygon { private set; get; }
public Tile TilePrefab;
public Wall WallPrefab;
public WallEdge WallEdgePrefab;
public KeyCode[] keys;
public void Initialize()
{
WallEdgeTileCount = 2 + 4 / (DirectionCount - 2);
Polygon = new Polygon(DirectionCount, 0.5f);
directions = Direction.CreateDirections(DirectionCount);
Single wallThikness = Polygon.DistanceBetweenCenters / 15.0f;
Single angle = Mathf.PI * (WallEdgeTileCount - 2) / WallEdgeTileCount;
Single distance = wallThikness / (2.0f * Mathf.Cos(angle / 2.0f));
Vector3 wallEdgeScale = WallEdgePrefab.transform.localScale;
wallEdgeScale.x = distance * 2.0f;
wallEdgeScale.y = distance * 2.0f;
WallEdgePrefab.transform.localScale = wallEdgeScale;
Vector3 wallScale = WallPrefab.transform.localScale;
wallScale.x = Polygon.DistanceBetweenCenters / 15.0f;
wallScale.y = Polygon.SideSize - 2.0f * distance * Mathf.Sin(angle / 2.0f);
WallPrefab.transform.localScale = wallScale;
HalfDirectionSegment = Mathf.PI / DirectionCount;
TilePrefab.Visible = Properties.IsHiddenMode;
}
public Direction GetDirection(Int32 index)
{
return directions[index];
}
public Direction GetInputDirection()
{
#if UNITY_ANDROID || UNITY_IOS
if (SwipeManager.Swiped)
{
return SwipeManager.LastDirection;
}
return null;
#else
for (Int32 i = 0; i < DirectionCount; i++)
{
if (Input.GetKey(keys[i]))
{
return GetDirection(i);
}
}
return null;
#endif
}
}
}
Polygon.cs
using System;
using UnityEngine;
namespace Maze.Commons
{
public class Polygon
{
// Количество сторон
public readonly Int32 SideCount;
// Величина одного угла вершины в градусах
public readonly Single AngleDeg;
// Величина одного угла вершины в радианах
public readonly Single AngleRad;
// Угол между двумя вершинами относительно центра
public readonly Single AngleBetweenTwoVertexFromCenterDeg;
// Расстояние между центрами двух полигонов
public readonly Single DistanceBetweenCenters;
// Размер стороны
public readonly Single SideSize;
// Расстояние от центра до вершины
public readonly Single DistangeFromCenterToVertex;
public Polygon(Int32 sideCount, Single distanceFromCenterToVertex)
{
SideCount = sideCount;
AngleDeg = 180.0f * (SideCount - 2) / SideCount;
AngleRad = Mathf.PI * (SideCount - 2) / SideCount;
AngleBetweenTwoVertexFromCenterDeg = 360.0f / SideCount;
DistangeFromCenterToVertex = distanceFromCenterToVertex;
DistanceBetweenCenters = 2.0f * Mathf.Sin(AngleRad / 2.0f) * DistangeFromCenterToVertex;
SideSize = 2.0f * Mathf.Cos(AngleRad / 2.0f) * DistangeFromCenterToVertex;
}
}
}
TileHelper.cs
using Maze.Commons;
using Maze.Reals;
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace Maze.Helpers
{
public static class TileHelper
{
public static void SetVisible(Tile tile, Boolean visible)
{
if (tile.Visible != visible)
{
tile.Animator.ResetTrigger(visible ? "Disappearance" : "Appearance");
tile.Animator.SetTrigger(visible ? "Appearance" : "Disappearance");
}
}
public static void InitVisible(Tile tile, Boolean visible)
{
tile.Animator.ResetTrigger(visible ? "Invisible" : "Visible");
tile.Animator.SetTrigger(visible ? "Visible" : "Invisible");
}
public static List<SpriteRenderer> GetRenderers(Tile tile, Boolean newVisible)
{
if (tile.Visible == newVisible)
{
return new List<SpriteRenderer>();
}
var renderers = new List<SpriteRenderer>();
renderers.AddRange(tile.GetComponentsInChildren<SpriteRenderer>());
foreach (var direction in tile.Walls.Keys)
{
if (!tile.NearTiles.ContainsKey(direction) || !tile.NearTiles[direction].Visible)
{
renderers.AddRange(tile.Walls[direction].GetComponentsInChildren<SpriteRenderer>());
}
}
foreach (var direction in tile.WallEdges.Keys)
{
if (GetAllTiles(direction, tile).Except(new [] { (direction, tile) }).All(tuple => !tuple.Item2.Visible))
{
renderers.AddRange(tile.WallEdges[direction].GetComponentsInChildren<SpriteRenderer>());
}
}
return renderers;
}
public static HashSet<(Direction, Tile)> GetAllTiles(Direction edgeDirection, Tile tile)
{
var set = new HashSet<(Direction, Tile)> { (edgeDirection, tile) };
AddRightsToSet(set, edgeDirection, tile);
AddLeftsToSet(set, edgeDirection, tile);
return set;
}
private static void AddRightsToSet(HashSet<(Direction, Tile)> set, Direction direction, Tile tile)
{
while (tile.NearTiles.ContainsKey(direction))
{
tile = tile.NearTiles[direction];
direction = direction.Opposite().Previous();
if (set.Contains((direction, tile)))
{
break;
}
set.Add((direction, tile));
}
}
private static void AddLeftsToSet(HashSet<(Direction, Tile)> set, Direction direction, Tile tile)
{
direction = direction.Next();
while (tile.NearTiles.ContainsKey(direction))
{
tile = tile.NearTiles[direction];
direction = direction.Opposite().Next();
if (set.Contains((direction.Previous(), tile)))
{
break;
}
set.Add((direction.Previous(), tile));
}
}
public static void MakeActionInDirections(Tile tile, Action<Tile> action)
{
action(tile);
foreach (Direction direction in tile.ConnectedTiles.Keys)
{
ContinueAction(tile, direction, action);
}
}
private static void ContinueAction(Tile tile, Direction direction, Action<Tile> action)
{
do
{
tile = tile.ConnectedTiles[direction];
action(tile);
}
while (tile.ConnectedTiles.ContainsKey(direction));
}
public static void ShowTile(Tile tile)
{
MakeActionInDirections(tile, t => SetVisible(t, true));
}
public static void ForceShowTile(Tile tile)
{
MakeActionInDirections(tile, t => InitVisible(t, true));
}
// TODO: write method HideTile()
}
}
CampaignInfo.cs
using System;
namespace Maze.IO
{
[Serializable]
public class CampaignInfo
{
public LevelInfo[] Campaign;
}
}
IOManager.cs
using UnityEngine;
namespace Maze.IO
{
public static class IOManager
{
public static CampaignInfo LoadLevels()
{
TextAsset textAsset = Resources.Load<TextAsset>("Campaign");
var levels = JsonUtility.FromJson<CampaignInfo>(textAsset.text);
return levels;
}
}
}
LevelInfo.cs
using System;
namespace Maze.IO
{
[Serializable]
public class LevelInfo
{
public String Type;
public Int32 Width;
public Int32 Height;
public Int32 Seed;
public Boolean HiddenMode;
}
}
LevelButton.cs
using System;
using UnityEngine;
using UnityEngine.UI;
namespace Maze.Menu
{
public class LevelButton : MonoBehaviour
{
public Text Text;
protected Int32 level;
public Int32 Level
{
get => level;
set
{
level = value;
Text.text = level.ToString();
}
}
}
}
MenuStates.cs
namespace Maze.Menu
{
public enum MenuStates
{
MainMenu,
FreePlay,
Campaign,
Default = MainMenu
}
}
SliderHandler.cs
using System;
using UnityEngine;
using UnityEngine.UI;
namespace Maze.Menu
{
public class SliderHandler : MonoBehaviour
{
public Slider slider;
public Text valueText;
public Int32 minValue;
public Int32 maxValue;
public Int32 step;
public Int32 value;
public void Start()
{
slider.minValue = minValue;
slider.maxValue = maxValue;
slider.value = value;
valueText.text = value.ToString();
}
public void OnValueChanged()
{
value = (Int32)Mathf.Round(slider.value);
value = (value - minValue) / step * step + minValue;
slider.value = value;
valueText.text = value.ToString();
}
}
}
CampaignHandler.cs
using Maze;
using Maze.Commons;
using Maze.IO;
using Maze.Menu;
using System;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
public class CampaignHandler : MenuHandler
{
public GameObject MainMenu;
public Transform LevelButtonsTransform;
public LevelButton LevelButtonPrefab;
public LevelButton[] levelButtons;
public void Start()
{
levelButtons = new LevelButton[15];
for (Int32 i = 0; i < 3; i++)
{
for (Int32 j = 0; j < 5; j++)
{
LevelButton levelButton = levelButtons[i * 5 + j] = Instantiate(LevelButtonPrefab, LevelButtonsTransform);
levelButton.Level = i * 5 + j + 1;
levelButton.transform.localPosition = new Vector3(-440 + 220 * j, 220 - 220 * i);
var clickedEvent = new Button.ButtonClickedEvent();
clickedEvent.AddListener(() => LevelOnClick(levelButton));
levelButton.GetComponent<Button>().onClick = clickedEvent;
}
}
}
public void Update()
{
if (Input.GetKeyDown(KeyCode.Escape))
{
Forward(MainMenu);
}
}
public void BackOnClick()
{
Forward(MainMenu);
}
public void LevelOnClick(LevelButton levelButton)
{
LevelInfo level = Properties.Campaign[levelButton.Level - 1];
Properties.IsHiddenMode = level.HiddenMode;
Properties.MazeWidth = level.Width;
Properties.MazeHeight = level.Height;
Properties.MazeSeed = level.Seed;
Properties.IsRectangularMazeSystem = level.Type == "R";
Properties.IsFreePlay = false;
SceneManager.LoadScene("GamePlay", LoadSceneMode.Single);
}
}
FreePlayHandler.cs
using Maze.Menu;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
namespace Maze
{
public class FreePlayHandler : MenuHandler
{
public GameObject MainMenu;
public SliderHandler widthHandler;
public SliderHandler heightHandler;
public Toggle hiddenModeToggle;
public Toggle rectangularToggle;
public void Update()
{
if (Input.GetKeyDown(KeyCode.Escape))
{
Forward(MainMenu);
}
}
public void PlayOnClick()
{
Properties.IsHiddenMode = hiddenModeToggle.isOn;
Properties.IsRectangularMazeSystem = rectangularToggle.isOn;
Properties.MazeWidth = widthHandler.value;
Properties.MazeHeight = heightHandler.value;
Properties.IsFreePlay = true;
SceneManager.LoadScene("GamePlay", LoadSceneMode.Single);
}
public void RectangularOnValueChanged(Text text)
{
text.text = rectangularToggle.isOn ? "Rectangular Maze" : "HexagonalMaze";
}
public void BackOnClick()
{
Forward(MainMenu);
}
}
}
MainMenuHandler.cs
using UnityEngine;
namespace Maze
{
public class MainMenuHandler : MenuHandler
{
public GameObject Campaign;
public GameObject FreePlay;
private void Start()
{
switch (Properties.MenuState)
{
case Menu.MenuStates.Campaign:
Forward(Campaign);
break;
case Menu.MenuStates.FreePlay:
Forward(FreePlay);
break;
}
Properties.MenuState = Menu.MenuStates.Default;
}
public void CampaignOnClick()
{
Forward(Campaign);
}
public void FreePlayOnClick()
{
Forward(FreePlay);
}
public void ExitOnClick()
{
Application.Quit();
}
}
}
MenuHandler.cs
using UnityEngine;
public abstract class MenuHandler : MonoBehaviour
{
protected void Forward(GameObject nextMenu)
{
gameObject.SetActive(false);
nextMenu.SetActive(true);
}
}
IMoveSystem.cs
using Maze.Commons;
using Maze.Reals;
using System.Collections.Generic;
namespace Maze.MoveSystems
{
public interface IMoveSystem
{
LinkedList<Tile> Move(Tile tile, Direction direction);
}
}
PathMoveSystem.cs
using Maze.Commons;
using Maze.Reals;
using System.Collections.Generic;
namespace Maze.MoveSystems
{
public class PathMoveSystem : IMoveSystem
{
public LinkedList<Tile> Move(Tile tile, Direction direction)
{
var tiles = new LinkedList<Tile>();
tiles.AddFirst(tile);
while(tile.ConnectedTiles.ContainsKey(direction))
{
tile = tile.ConnectedTiles[direction];
tiles.AddLast(tile);
if (tile.ConnectedTiles.Count != 2)
{
break;
}
foreach (Direction newDirection in tile.ConnectedTiles.Keys)
{
if (newDirection != direction.Opposite())
{
direction = newDirection;
break;
}
}
}
return tiles;
}
}
}
StepMoveSystem.cs
using Maze.Commons;
using Maze.Reals;
using System.Collections.Generic;
namespace Maze.MoveSystems
{
public class StepMoveSystem : IMoveSystem
{
public LinkedList<Tile> Move(Tile tile, Direction direction)
{
var positions = new LinkedList<Tile>();
positions.AddFirst(tile);
if (tile.ConnectedTiles.ContainsKey(direction))
{
positions.AddLast(tile.ConnectedTiles[direction]);
}
return positions;
}
}
}
Exit.cs
namespace Maze.Reals
{
public class Exit : TileContent
{
public override void Run(Maze maze)
{
maze.Player.Animator.SetTrigger("Win");
}
}
}
Maze.cs
using Maze.Commons;
using Maze.Helpers;
using Maze.MoveSystems;
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.SceneManagement;
namespace Maze.Reals
{
public class Maze : MonoBehaviour
{
public Player PlayerPrefab;
public Exit ExitPrefab;
public Player Player;
public Transform TilesTransform;
public Transform WallsTransform;
public Transform WallEdgesTransform;
public List<Tile> Tiles;
public List<Wall> Walls;
public List<WallEdge> WallEdges;
public MazeSystem RectangularMazeSystemPrefab;
public MazeSystem HexagonalMazeSystemPrefab;
public MazeSystem MazeSystem;
public Int32? Seed;
public void Start()
{
Seed = Properties.MazeSeed;
MazeSystem = Instantiate(Properties.IsRectangularMazeSystem ? RectangularMazeSystemPrefab : HexagonalMazeSystemPrefab, transform);
MazeSystem.Initialize();
CreateMaze();
}
public void Update()
{
#if UNITY_ANDROID || UNITY_IOS
SwipeManager.Update(MazeSystem);
#endif
if (Input.GetKeyDown(KeyCode.Escape))
{
Properties.MenuState = Properties.IsFreePlay ? Menu.MenuStates.FreePlay : Menu.MenuStates.Campaign;
SceneManager.LoadScene("Menu", LoadSceneMode.Single);
}
}
private void CreateMaze()
{
CreateField();
ConnectTiles();
CreateWalls();
CreateWallEdges();
ApplyHiddenMode();
CreatePlayer();
SetPlayerAndExitTiles();
}
public void Restart()
{
Destroy(Player.gameObject);
Destroy(MazeSystem);
foreach (Tile tile in Tiles)
{
Destroy(tile.gameObject);
}
foreach(Wall wall in Walls)
{
Destroy(wall.gameObject);
}
foreach(WallEdge wallEdge in WallEdges)
{
Destroy(wallEdge.gameObject);
}
CreateMaze();
}
private void CreateField()
{
Tiles = new List<Tile>();
if (MazeSystem.DirectionCount == 4)
{
CreateRectangularField();
}
else if (MazeSystem.DirectionCount == 6)
{
CreateHexagonalField();
}
}
private void CreateRectangularField()
{
Int32 width = Properties.MazeWidth;
Int32 height = Properties.MazeHeight;
Tile[,] tiles = new Tile[width, height];
for (Int32 i = 0; i < width; i++)
{
for (Int32 j = 0; j < height; j++)
{
tiles[i, j] = Instantiate(MazeSystem.TilePrefab, TilesTransform);
Tiles.Add(tiles[i, j]);
}
}
for (Int32 i = 0; i < width; i++)
{
for (Int32 j = 0; j < height; j++)
{
if (i > 0 && !tiles[i, j].NearTiles.ContainsKey(MazeSystem.GetDirection(2)))
{
MakeNear(2, tiles[i, j], tiles[i - 1, j]);
}
if (j > 0 && !tiles[i, j].NearTiles.ContainsKey(MazeSystem.GetDirection(1)))
{
MakeNear(1, tiles[i, j], tiles[i, j - 1]);
}
if (i < width - 1 && !tiles[i, j].NearTiles.ContainsKey(MazeSystem.GetDirection(0)))
{
MakeNear(0, tiles[i, j], tiles[i + 1, j]);
}
if (j < height - 1 && !tiles[i, j].NearTiles.ContainsKey(MazeSystem.GetDirection(3)))
{
MakeNear(3, tiles[i, j], tiles[i, j + 1]);
}
}
}
}
private void CreateHexagonalField()
{
Int32 width = Properties.MazeWidth;
Int32 height = Properties.MazeHeight;
Tile[,] tiles = new Tile[width, height];
for (Int32 i = 0; i < width; i++)
{
for (Int32 j = 0; j < height; j++)
{
tiles[i, j] = Instantiate(MazeSystem.TilePrefab, TilesTransform);
Tiles.Add(tiles[i, j]);
}
}
for (Int32 i = 0; i < width; i++)
{
for (Int32 j = 0; j < height; j++)
{
if (i > 0 && !tiles[i, j].NearTiles.ContainsKey(MazeSystem.GetDirection(3)))
{
MakeNear(3, tiles[i, j], tiles[i - 1, j]);
}
if (i < width - 1 && !tiles[i, j].NearTiles.ContainsKey(MazeSystem.GetDirection(0)))
{
MakeNear(0, tiles[i, j], tiles[i + 1, j]);
}
if (j % 2 == 0)
{
if (j > 0)
{
if (!tiles[i, j].NearTiles.ContainsKey(MazeSystem.GetDirection(2)))
{
MakeNear(2, tiles[i, j], tiles[i, j - 1]);
}
if (i < width - 1 && !tiles[i, j].NearTiles.ContainsKey(MazeSystem.GetDirection(1)))
{
MakeNear(1, tiles[i, j], tiles[i + 1, j - 1]);
}
}
if (j < height - 1)
{
if (!tiles[i, j].NearTiles.ContainsKey(MazeSystem.GetDirection(4)))
{
MakeNear(4, tiles[i, j], tiles[i, j + 1]);
}
if (i < width - 1 && !tiles[i, j].NearTiles.ContainsKey(MazeSystem.GetDirection(5)))
{
MakeNear(5, tiles[i, j], tiles[i + 1, j + 1]);
}
}
}
else
{
if (j > 0)
{
if (!tiles[i, j].NearTiles.ContainsKey(MazeSystem.GetDirection(1)))
{
MakeNear(1, tiles[i, j], tiles[i, j - 1]);
}
if (i > 0 && !tiles[i, j].NearTiles.ContainsKey(MazeSystem.GetDirection(2)))
{
MakeNear(2, tiles[i, j], tiles[i - 1, j - 1]);
}
}
if (j < height - 1)
{
if (!tiles[i, j].NearTiles.ContainsKey(MazeSystem.GetDirection(5)))
{
MakeNear(5, tiles[i, j], tiles[i, j + 1]);
}
if (i > 0 && !tiles[i, j].NearTiles.ContainsKey(MazeSystem.GetDirection(4)))
{
MakeNear(4, tiles[i, j], tiles[i - 1, j + 1]);
}
}
}
}
}
}
private void ConnectTiles()
{
var random = Seed is null ? new System.Random() : new System.Random(Seed.Value);
var activeTiles = new List<Tile> { Tiles[random.Next(Tiles.Count)] };
var createdTiles = new HashSet<Tile> { activeTiles[0] };
while (activeTiles.Count > 0)
{
Tile activeTile = activeTiles[random.Next(10) < 8 ? activeTiles.Count - 1 : random.Next(activeTiles.Count)];
var freeDirections = new List<Direction>();
foreach (Direction direction in activeTile.NearTiles.Keys)
{
Tile nearTileObject = activeTile.NearTiles[direction];
if (!createdTiles.Contains(nearTileObject))
{
freeDirections.Add(direction);
}
}
if (freeDirections.Count == 0)
{
activeTiles.Remove(activeTile);
continue;
}
Direction selectedDirection = freeDirections[random.Next(freeDirections.Count)];
Tile selectedTileObject = activeTile.NearTiles[selectedDirection];
createdTiles.Add(selectedTileObject);
activeTiles.Add(selectedTileObject);
MakeConnected(selectedDirection, activeTile, selectedTileObject);
}
}
private void MakeNear(Int32 index, Tile tile1, Tile tile2)
{
tile1.NearTiles[MazeSystem.GetDirection(index)] = tile2;
tile2.NearTiles[MazeSystem.GetDirection(index).Opposite()] = tile1;
tile2.transform.localPosition = tile1.transform.localPosition + tile1.transform.rotation * MazeSystem.GetDirection(index).Vector * MazeSystem.Polygon.DistanceBetweenCenters;
}
private void MakeConnected(Direction direction, Tile tile1, Tile tile2)
{
tile1.ConnectedTiles[direction] = tile2;
tile2.ConnectedTiles[direction.Opposite()] = tile1;
}
private void CreateWalls()
{
Walls = new List<Wall>();
foreach (Tile tile in Tiles)
{
for (Int32 i = 0; i < MazeSystem.DirectionCount; i++)
{
Direction direction = MazeSystem.GetDirection(i);
if (!tile.NearTiles.ContainsKey(direction))
{
Wall wall = Instantiate(MazeSystem.WallPrefab, WallsTransform);
wall.transform.localPosition = tile.transform.localPosition + tile.transform.rotation * direction.Vector * MazeSystem.Polygon.DistanceBetweenCenters / 2.0f;
wall.transform.rotation = Quaternion.Euler(0.0f, 0.0f, tile.transform.rotation.eulerAngles.z + direction.Quaternion.eulerAngles.z);
tile.Walls[direction] = wall;
Walls.Add(wall);
}
else if (!tile.ConnectedTiles.ContainsKey(direction) && !tile.Walls.ContainsKey(direction))
{
Wall wall = Instantiate(MazeSystem.WallPrefab, WallsTransform);
wall.transform.localPosition = tile.transform.localPosition + tile.transform.rotation * direction.Vector * MazeSystem.Polygon.DistanceBetweenCenters / 2.0f;
wall.transform.rotation = Quaternion.Euler(0.0f, 0.0f, tile.transform.rotation.eulerAngles.z + direction.Quaternion.eulerAngles.z);
tile.Walls[direction] = wall;
tile.NearTiles[direction].Walls[direction.Opposite()] = wall;
Walls.Add(wall);
}
}
}
}
private void CreateWallEdges()
{
WallEdges = new List<WallEdge>();
foreach(Tile tile in Tiles)
{
for (Int32 i = 0; i < MazeSystem.DirectionCount; i++)
{
Direction direction = MazeSystem.GetDirection(i);
if (tile.Walls.ContainsKey(direction))
{
Wall wall = tile.Walls[direction];
if (!tile.WallEdges.ContainsKey(direction))
{
WallEdge wallEdge = Instantiate(MazeSystem.WallEdgePrefab, WallEdgesTransform);
WallEdges.Add(wallEdge);
wallEdge.transform.rotation = Quaternion.Euler(0.0f, 0.0f, tile.transform.rotation.eulerAngles.z + direction.Quaternion.eulerAngles.z);
wallEdge.transform.localPosition = wall.transform.localPosition + Quaternion.Euler(0.0f, 0.0f, tile.transform.rotation.eulerAngles.z + 90.0f) * direction.Vector * MazeSystem.Polygon.SideSize / 2.0f;
SetWallEdgeForNearWalls(direction, tile, wallEdge);
}
if (!tile.WallEdges.ContainsKey(direction.Previous()))
{
WallEdge wallEdge = Instantiate(MazeSystem.WallEdgePrefab, WallEdgesTransform);
WallEdges.Add(wallEdge);
wallEdge.transform.rotation = Quaternion.Euler(0.0f, 0.0f, tile.transform.rotation.eulerAngles.z + direction.Previous().Quaternion.eulerAngles.z);
wallEdge.transform.localPosition = wall.transform.localPosition + Quaternion.Euler(0.0f, 0.0f, tile.transform.rotation.eulerAngles.z + 270.0f) * direction.Vector * MazeSystem.Polygon.SideSize / 2.0f;
SetWallEdgeForNearWalls(direction.Previous(), tile, wallEdge);
}
}
}
}
}
private void ApplyHiddenMode()
{
foreach (Tile tile in Tiles)
{
TileHelper.InitVisible(tile, !Properties.IsHiddenMode);
}
}
private void SetWallEdgeForNearWalls(Direction edgeDirection, Tile tile, WallEdge wallEdge)
{
foreach((Direction direction, Tile setTile) in TileHelper.GetAllTiles(edgeDirection, tile))
{
setTile.WallEdges[direction] = wallEdge;
}
}
private void SetPlayerAndExitTiles()
{
var endTiles = new HashSet<Tile>(Tiles.Where(tile => tile.ConnectedTiles.Count == 1));
var forkTiles = new HashSet<Tile>(Tiles.Where(tile => tile.ConnectedTiles.Count >= 3));
Int32 maxCount = 0;
Tile playerTile = Tiles[0];
Tile exitTile = Tiles[Tiles.Count - 1];
foreach (Tile endTile in endTiles)
{
var stack = new Stack<(Tile tile, Direction source, Int32 count)>();
stack.Push((endTile, (Direction)null, 0));
while (stack.Count > 0)
{
(Tile tile, Direction source, Int32 count) = stack.Pop();
if (tile.ConnectedTiles.Count == 1 && count > maxCount)
{
maxCount = count;
playerTile = endTile;
exitTile = tile;
}
foreach (Direction direction in tile.ConnectedTiles.Keys)
{
if (direction != source)
{
Tile pushTile = tile.ConnectedTiles[direction];
stack.Push((pushTile, direction.Opposite(), pushTile.ConnectedTiles.Count >= 3 ? count + 1 : count));
}
}
}
}
exitTile.Content = Instantiate(ExitPrefab, exitTile.transform);
Player.Tile = playerTile;
}
private void CreatePlayer()
{
Player = Instantiate(PlayerPrefab, transform);
Player.Maze = this;
if (Properties.IsStepMoveSystem)
{
Player.MoveSystem = new StepMoveSystem();
}
else
{
Player.MoveSystem = new PathMoveSystem();
}
}
}
}
Player.cs
using Maze.Commons;
using Maze.Helpers;
using Maze.MoveSystems;
using System.Collections.Generic;
using UnityEngine;
namespace Maze.Reals
{
public class Player : MonoBehaviour
{
private Tile tile;
public Maze Maze;
public IMoveSystem MoveSystem;
public MoveSequence MoveSequence;
public Animator Animator;
public Tile Tile
{
get => tile;
set
{
tile = value;
transform.localPosition = tile.transform.localPosition;
tile.RunAction(Maze);
}
}
public void Start()
{
if (Properties.IsHiddenMode)
{
TileHelper.ForceShowTile(Tile);
}
}
public void Update()
{
Direction direction = Maze.MazeSystem.GetInputDirection();
if (direction != null)
{
if (MoveSequence.IsFinished())
{
LinkedList<Tile> tiles = MoveSystem.Move(Tile, direction);
if (tiles.Count != 1)
{
MoveSequence.SetTiles(tiles);
}
}
}
}
}
}
Tile.cs
using Maze.Commons;
using Maze.Helpers;
using System;
using System.Collections.Generic;
using UnityEngine;
namespace Maze.Reals
{
public class Tile : MonoBehaviour
{
public readonly Dictionary<Direction, Tile> NearTiles = new Dictionary<Direction, Tile>();
public readonly Dictionary<Direction, Tile> ConnectedTiles = new Dictionary<Direction, Tile>();
public readonly Dictionary<Direction, Wall> Walls = new Dictionary<Direction, Wall>();
public readonly Dictionary<Direction, WallEdge> WallEdges = new Dictionary<Direction, WallEdge>();
public TileContent Content;
private Single prevOpacity = -1.0f;
public Single Opacity;
public Boolean OpacityUpdated { private set; get; }
public Boolean Visible;
public Animator Animator;
public void Update()
{
if (prevOpacity != Opacity)
{
OpacityUpdated = true;
prevOpacity = Opacity;
}
else
{
OpacityUpdated = false;
}
}
public void RunAction(Maze maze)
{
Content?.Run(maze);
if (Properties.IsHiddenMode)
{
TileHelper.ShowTile(this);
}
}
}
}
TileContent.cs
using UnityEngine;
namespace Maze.Reals
{
public abstract class TileContent : MonoBehaviour
{
public Tile Tile;
public abstract void Run(Maze maze);
}
}
Wall.cs
using UnityEngine;
namespace Maze.Reals
{
public class Wall : MonoBehaviour
{
}
}
WallEdge.cs
using UnityEngine;
namespace Maze.Reals
{
public class WallEdge : MonoBehaviour
{
}
}
campaign.json
{
"Campaign":
[
{
"Type": "R",
"Width": "5",
"Height": "5",
"Seed": "327120579",
"HiddenMode": "false"
},
{
"Type": "R",
"Width": "8",
"Height": "8",
"Seed": "689058995",
"HiddenMode": "false"
},
{
"Type": "R",
"Width": "11",
"Height": "11",
"Seed": "1638027807",
"HiddenMode": "false"
},
{
"Type": "R",
"Width": "14",
"Height": "14",
"Seed": "1212451611",
"HiddenMode": "false"
},
{
"Type": "H",
"Width": "10",
"Height": "10",
"Seed": "4648563",
"HiddenMode": "false"
},
{
"Type": "H",
"Width": "14",
"Height": "14",
"Seed": "1225465750",
"HiddenMode": "false"
},
{
"Type": "H",
"Width": "18",
"Height": "18",
"Seed": "791343374",
"HiddenMode": "false"
},
{
"Type": "R",
"Width": "10",
"Height": "10",
"Seed": "145830520",
"HiddenMode": "true"
},
{
"Type": "R",
"Width": "20",
"Height": "20",
"Seed": "1651845122",
"HiddenMode": "true"
},
{
"Type": "H",
"Width": "10",
"Height": "10",
"Seed": "1947139214",
"HiddenMode": "true"
},
{
"Type": "H",
"Width": "20",
"Height": "20",
"Seed": "577089526",
"HiddenMode": "true"
},
{
"Type": "R",
"Width": "50",
"Height": "50",
"Seed": "1390792027",
"HiddenMode": "false"
},
{
"Type": "H",
"Width": "50",
"Height": "50",
"Seed": "1238724014",
"HiddenMode": "false"
},
{
"Type": "R",
"Width": "50",
"Height": "50",
"Seed": "124233181",
"HiddenMode": "true"
},
{
"Type": "H",
"Width": "50",
"Height": "50",
"Seed": "291371660",
"HiddenMode": "true"
}
]
}
Размещено на Allbest.ru
...Подобные документы
Изучение существующих подходов к использованию компьютерных игр в образовательном процессе. Разработка и реализация проекта игрового обучающего приложения на мобильной платформе. Выбор платформы и средств реализации игрового обучающего приложения.
дипломная работа [3,4 M], добавлен 12.08.2017Анализ игровых жанров для мобильных устройств и целевой аудитории. Разработка концепции игрового приложения, основной механики, меню и интерфейса игры. Описание переменных скриптов. Реализация выбора цели и стрельбы. Настройка работоспособности игры.
дипломная работа [1,4 M], добавлен 19.01.2017Сбор и анализ сведений по предметной области по дисциплине "Астрономия" с целью разработки обучающего игрового приложения. Исследование алгоритмов и характеристик существующих программных систем аналогов. Разработка архитектуры программной системы.
курсовая работа [4,1 M], добавлен 27.11.2014Структура Android-приложений. Особенности игрового движка. Алгоритмизация и программирование. Список игровых состояний. Настройка, отладка и тестирование программы. Разработка руководства пользователя. Тестирование инсталляции и отображения элементов.
дипломная работа [4,5 M], добавлен 19.01.2017Преимущества операционной системы Android. Проектирование интерфейса приложений. Визуальные редакторы и средства кроссплатформенной разработки. Оптимизация игрового процесса, выбор фреймворка и библиотек. Классификация и характеристика игр по жанрам.
дипломная работа [2,6 M], добавлен 10.07.2017Написание игры "Lines" на языке Object Pascal в среде Delphi. Алгоритм работы программы. Описание метода генерации поля. Используемые константы и переменные. Форма приложения после старта игрового процесса. Основные элементы формы и обработки событий.
курсовая работа [225,0 K], добавлен 12.04.2012Разработка программного продукта, предназначенного для имитации физического взаимодействия между объектами на основе игрового симулятора. Проектирование программы "LonelySpaceRanger", код которой представлен на языке VisualС++. Разработка интерфейса.
дипломная работа [3,2 M], добавлен 30.11.2011Разработка игрового проекта на игровом движке Unity 3D в среде программирования MS Visual Studio 2017. Блок-схема алгоритма работы приема сообщений с сервера на клиенте с упрощенным описанием выполняемых команд. Реализация пользовательского интерфейса.
курсовая работа [1,5 M], добавлен 10.07.2017История создания компьютерных игр. Обзор современных игровых жанров. Выбор используемых инструментов. Руководство пользователя. Разработка игры в жанре 3D шутера от первого лица. Конструктор игр Game Maker. Создание уровня с несколькими регионами.
курсовая работа [961,8 K], добавлен 22.06.2015Обзор системного и прикладного программного обеспечения используемого в ООО "Игровые системы". Описание компьютерной сети предприятия. Разработка игрового продукта для планшетов Apple iPad. Реализация визуального интерфейса и алгоритма работы модуля.
отчет по практике [1,4 M], добавлен 18.01.2015Изучение существующих подходов к использованию компьютерных игр в образовательном процессе. Особенности использования мобильного обучения. Методика и этапы закрепления полученных ранее знаний с использованием игрового приложения на мобильной платформе.
дипломная работа [813,0 K], добавлен 27.10.2017Разработка компьютерных игр как зрелищная и наиболее сложная отрасль программирования. Рассмотрение основных особенностей конструирования классов CGame и Players, а также алгоритмов вычисления траектории полета снаряда. Анализ алгоритма PassivePlayer.
курсовая работа [5,1 M], добавлен 22.02.2013Знакомство с особенностями и этапами разработки приложения для платформы Android. Рассмотрение функций персонажа: бег, прыжок, взаимодействие с объектами. Анализ блок-схемы алгоритма генерации платформ. Способы настройки функционала рабочей области.
дипломная работа [3,4 M], добавлен 19.01.2017Анализ деятельности группы компаний "Инрэко ЛАН". Общая характеристика, основы проектирования и разработка операционной системы Android. Этапы разработки программного игрового приложения с использованием физики. Скриншоты, отображающие игровой процесс.
отчет по практике [2,7 M], добавлен 19.07.2012История судоку, правила игры и цель головоломки. Разработка диаграммы классов. Реализация программы в объектно-ориентированном стиле по принципам модульности, иерархичности, ограничения доступа. Алгоритм генерации случайного игрового поля судоку.
курсовая работа [315,9 K], добавлен 01.02.2013Разработка компьютерной игры "Эволюция" с помощью игрового движка Unit. Сравнение критериев игры-аналога и разрабатываемой игры. Разработка графического интерфейса пользователя. Настройки камеры в редакторе Unity. Структура файла сохранения игры.
дипломная работа [3,6 M], добавлен 11.02.2017Анализ целевой аудитории. Функциональные характеристики пользовательского приложения. Разработка алгоритмов и интерфейса программного продукта, функций рабочей области. Написание скриптов на языке C#. Тестирование программы методом чёрного ящика.
дипломная работа [1,5 M], добавлен 09.11.2016Многообразие мини-игр и возможности языка Visual basic 6.0 для их реализации. Понятие мини-игр и их классификация. Элементы управления мини-игры "Реверси". Разработка прикладной программы. Создание игрового интерфейса. Написание программного кода.
курсовая работа [1,5 M], добавлен 03.06.2014Рассмотрение игр, схожих по жанру и модели распространения с разрабатываемым приложением. Выбор среды разработки и сторонних библиотек. Проектирование интерфейса и подготовка графических материалов приложения. Особенности введения в игру микротрансакций.
дипломная работа [3,1 M], добавлен 18.11.2017Разработка клиент-серверного игрового приложения на примере игры в шашки для мобильных устройств на базе операционной системы Android. Обзор мобильных платформ. Экраны приложения и их взаимодействие. Графический интерфейс, руководство пользователя.
курсовая работа [2,6 M], добавлен 15.06.2013