Skip to content

Instantly share code, notes, and snippets.

@nabesi777
Created September 12, 2018 13:46
Show Gist options
  • Save nabesi777/3cd4892823902df560917818a55e59da to your computer and use it in GitHub Desktop.
Save nabesi777/3cd4892823902df560917818a55e59da to your computer and use it in GitHub Desktop.
C# 倉庫番
using System;
using System.Collections.Generic;
using UnityEngine;
public class Sokoban : MonoBehaviour
{
private enum TileType
{
NONE,
GROUND,
TARGET,
PLAYER,
BLOCK,
PLAYER_ON_TARGET,
BLOCK_ON_TARGET,
}
private enum DirectionType
{
UP,
RIGHT,
DOWN,
LEFT,
}
public TextAsset stageFile;
private int rows;
private int columns;
private TileType[,] tileList;
public float tileSize;
public Sprite groundSprite;
public Sprite targetSprite;
public Sprite playerSprite;
public Sprite blockSprite;
private GameObject player;
private Vector2 middleOffset;
private int blockCount;
private bool isClear;
private Dictionary<GameObject, Vector2Int> gameObjectPosTable = new Dictionary<GameObject, Vector2Int>();
private void Start()
{
LoadTileData();
CreateStage();
}
private void LoadTileData()
{
var lines = stageFile.text.Split
(
new[] { '\r', '\n' },
StringSplitOptions.RemoveEmptyEntries
);
var nums = lines[0].Split(new[] { ',' });
rows = lines.Length;
columns = nums.Length;
tileList = new TileType[columns, rows];
for (int y = 0; y < rows; y++)
{
var st = lines[y];
nums = st.Split(new[] { ',' });
for (int x = 0; x < columns; x++)
{
tileList[x, y] = (TileType)int.Parse(nums[x]);
}
}
}
private void CreateStage()
{
middleOffset.x = columns * tileSize * 0.5f - tileSize * 0.5f;
middleOffset.y = rows * tileSize * 0.5f - tileSize * 0.5f;
for (int y = 0; y < rows; y++)
{
for (int x = 0; x < columns; x++)
{
var val = tileList[x, y];
if (val == TileType.NONE) continue;
var name = "tile" + y + "_" + x;
var tile = new GameObject(name);
var sr = tile.AddComponent<SpriteRenderer>();
sr.sprite = groundSprite;
tile.transform.position = GetDisplayPosition(x, y);
if (val == TileType.TARGET)
{
var destination = new GameObject("destination");
sr = destination.AddComponent<SpriteRenderer>();
sr.sprite = targetSprite;
sr.sortingOrder = 1;
destination.transform.position = GetDisplayPosition(x, y);
}
if (val == TileType.PLAYER)
{
player = new GameObject("player");
sr = player.AddComponent<SpriteRenderer>();
sr.sprite = playerSprite;
sr.sortingOrder = 2;
player.transform.position = GetDisplayPosition(x, y);
gameObjectPosTable.Add(player, new Vector2Int(x, y));
}
else if (val == TileType.BLOCK)
{
blockCount++;
var block = new GameObject("block" + blockCount);
sr = block.AddComponent<SpriteRenderer>();
sr.sprite = blockSprite;
sr.sortingOrder = 2;
block.transform.position = GetDisplayPosition(x, y);
gameObjectPosTable.Add(block, new Vector2Int(x, y));
}
}
}
}
private Vector2 GetDisplayPosition(int x, int y)
{
return new Vector2
(
x * tileSize - middleOffset.x,
y * -tileSize + middleOffset.y
);
}
private GameObject GetGameObjectAtPosition(Vector2Int pos)
{
foreach (var pair in gameObjectPosTable)
{
if (pair.Value == pos)
{
return pair.Key;
}
}
return null;
}
private bool IsBlock(Vector2Int pos)
{
var cell = tileList[pos.x, pos.y];
return cell == TileType.BLOCK || cell == TileType.BLOCK_ON_TARGET;
}
private bool IsValidPosition(Vector2Int pos)
{
if (0 <= pos.x && pos.x < columns && 0 <= pos.y && pos.y < rows)
{
return tileList[pos.x, pos.y] != TileType.NONE;
}
return false;
}
private void Update()
{
if (isClear) return;
if (Input.GetKeyDown(KeyCode.UpArrow))
{
TryMovePlayer(DirectionType.UP);
}
if (Input.GetKeyDown(KeyCode.RightArrow))
{
TryMovePlayer(DirectionType.RIGHT);
}
if (Input.GetKeyDown(KeyCode.DownArrow))
{
TryMovePlayer(DirectionType.DOWN);
}
if (Input.GetKeyDown(KeyCode.LeftArrow))
{
TryMovePlayer(DirectionType.LEFT);
}
}
private void TryMovePlayer(DirectionType direction)
{
var currentPlayerPos = gameObjectPosTable[player];
var nextPlayerPos = GetNextPositionAlong(currentPlayerPos, direction);
if (!IsValidPosition(nextPlayerPos)) return;
if (IsBlock(nextPlayerPos))
{
var nextBlockPos = GetNextPositionAlong(nextPlayerPos, direction);
if (IsValidPosition(nextBlockPos) && !IsBlock(nextBlockPos))
{
var block = GetGameObjectAtPosition(nextPlayerPos);
UpdateGameObjectPosition(nextPlayerPos);
block.transform.position = GetDisplayPosition(nextBlockPos.x, nextBlockPos.y);
gameObjectPosTable[block] = nextBlockPos;
if (tileList[nextBlockPos.x, nextBlockPos.y] == TileType.GROUND)
{
tileList[nextBlockPos.x, nextBlockPos.y] = TileType.BLOCK;
}
else if (tileList[nextBlockPos.x, nextBlockPos.y] == TileType.TARGET)
{
tileList[nextBlockPos.x, nextBlockPos.y] = TileType.BLOCK_ON_TARGET;
}
UpdateGameObjectPosition(currentPlayerPos);
player.transform.position = GetDisplayPosition(nextPlayerPos.x, nextPlayerPos.y);
gameObjectPosTable[player] = nextPlayerPos;
if (tileList[nextPlayerPos.x, nextPlayerPos.y] == TileType.GROUND)
{
tileList[nextPlayerPos.x, nextPlayerPos.y] = TileType.PLAYER;
}
else if (tileList[nextPlayerPos.x, nextPlayerPos.y] == TileType.TARGET)
{
tileList[nextPlayerPos.x, nextPlayerPos.y] = TileType.PLAYER_ON_TARGET;
}
}
}
else
{
UpdateGameObjectPosition(currentPlayerPos);
player.transform.position = GetDisplayPosition(nextPlayerPos.x, nextPlayerPos.y);
gameObjectPosTable[player] = nextPlayerPos;
if (tileList[nextPlayerPos.x, nextPlayerPos.y] == TileType.GROUND)
{
tileList[nextPlayerPos.x, nextPlayerPos.y] = TileType.PLAYER;
}
else if (tileList[nextPlayerPos.x, nextPlayerPos.y] == TileType.TARGET)
{
tileList[nextPlayerPos.x, nextPlayerPos.y] = TileType.PLAYER_ON_TARGET;
}
}
CheckCompletion();
}
private Vector2Int GetNextPositionAlong(Vector2Int pos, DirectionType direction)
{
switch (direction)
{
case DirectionType.UP:
pos.y -= 1;
break;
case DirectionType.RIGHT:
pos.x += 1;
break;
case DirectionType.DOWN:
pos.y += 1;
break;
case DirectionType.LEFT:
pos.x -= 1;
break;
}
return pos;
}
private void UpdateGameObjectPosition(Vector2Int pos)
{
var cell = tileList[pos.x, pos.y];
if (cell == TileType.PLAYER || cell == TileType.BLOCK)
{
tileList[pos.x, pos.y] = TileType.GROUND;
}
else if (cell == TileType.PLAYER_ON_TARGET || cell == TileType.BLOCK_ON_TARGET)
{
tileList[pos.x, pos.y] = TileType.TARGET;
}
}
private void CheckCompletion()
{
int blockOnTargetCount = 0;
for (int y = 0; y < rows; y++)
{
for (int x = 0; x < columns; x++)
{
if(tileList[x,y]==TileType.BLOCK_ON_TARGET)
{
blockOnTargetCount++;
}
}
}
if(blockOnTargetCount==blockCount)
{
isClear = true;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment