티스토리 뷰
제작한 작품 목록
- 자잘한 게임 및 코드들(숫자 맞추기, 계산기 등등)
- 틱택토
- 스네이크 게임
- 블랙잭 [기본적인 룰(스플릿 제외) 만 적용]
틱택토
[URL: https://lsu0503.tistory.com/53]
Today I Learned - Day 6 [틱택토 제작하기]
금일은 C#의 기본 문법에 대해서 공부하였습니다. 얼마 전 문법 톺아보기로도 한번 접했기도 한 지라, 전체적으로 복습한다는 느낌에 추가로 스파게티 코드 예방을 위해 '쉽게 알아볼 수 있게끔
lsu0503.tistory.com
해당 게임은 예외적으로 TIL로 작성되어 있습니다.
스네이크 게임
코드 전문
using System;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Reflection;
namespace _3rdWeekHomwork
{
class Coordinate
{
public int x, y;
public Coordinate(int _x, int _y)
{
x = _x;
y = _y;
}
static public bool CompareCoordinate(Coordinate firstCoordinate, Coordinate secondCoordinate)
{
bool result = true;
if(!(firstCoordinate.x == secondCoordinate.x))
result = false;
if (!(firstCoordinate.y == secondCoordinate.y))
result = false;
return result;
}
}
class GameManager
{
private static GameManager instance;
Field field;
Snake snake;
Thread gameUpdater;
public GameManager()
{
field = new Field();
snake = new Snake(field.fieldSize / 2, field.fieldSize / 2, field);
}
public static GameManager Instance()
{
if (instance == null)
instance = new GameManager();
return instance;
}
public void GameStart()
{
gameUpdater = new Thread(() => GameUpdater());
gameUpdater.Start();
getInput();
}
public void GameUpdater()
{
while (true)
{
Thread.Sleep(200);
Update();
}
}
public void getInput()
{
ConsoleKeyInfo input;
while (true)
{
input = Console.ReadKey();
switch (input.Key)
{
case ConsoleKey.RightArrow:
snake.ChangeDirection(0);
break;
case ConsoleKey.UpArrow:
snake.ChangeDirection(1);
break;
case ConsoleKey.LeftArrow:
snake.ChangeDirection(2);
break;
case ConsoleKey.DownArrow:
snake.ChangeDirection(3);
break;
case ConsoleKey.Escape:
GameOver();
break;
}
}
}
void Update()
{
Console.SetCursorPosition(0, 0);
snake.Update();
UpdateDisplay();
}
void UpdateDisplay()
{
bool isExist;
Console.Clear();
for (int j = field.fieldSize; j >= -1; j--)
{
for (int i = -1; i <= field.fieldSize; i++)
{
isExist = false;
Coordinate temp = new Coordinate(i, j);
if(i == -1 || i == field.fieldSize || j == -1 || j == field.fieldSize)
{
Console.Write("■");
isExist = true;
}
for (int k = 0; k < field.foodList.Count; k++)
if (Coordinate.CompareCoordinate(temp, field.foodList[k]))
{
Console.Write("★");
isExist = true;
break;
}
if (Coordinate.CompareCoordinate(temp, snake.snakeHead) && !isExist)
{
switch (snake.direction)
{
case 1:
Console.Write("▲");
break;
case 2:
Console.Write("◀");
break;
case 3:
Console.Write("▼");
break;
default:
Console.Write("▶");
break;
}
isExist = true;
}
for (int k = 0; k < snake.snakeBody.Count; k++)
if (Coordinate.CompareCoordinate(temp, snake.snakeBody[k]))
{
Console.Write("●");
isExist = true;
break;
}
if (!isExist)
Console.Write(" ");
}
Console.WriteLine();
}
}
public void GameOver()
{
Console.WriteLine("Game Over");
Console.WriteLine($"Score: {snake.snakeBody.Count}\n");
Environment.Exit(0);
}
}
class Field
{
public int fieldSize = 25;
public List<Coordinate> foodList = new List<Coordinate>();
public Field()
{
foodList.Clear();
Coordinate temp = new Coordinate(new Random().Next(0, fieldSize), new Random().Next(0, fieldSize));
while(temp.x == fieldSize / 2 && temp.y == fieldSize / 2)
temp = new Coordinate(new Random().Next(0, fieldSize), new Random().Next(0, fieldSize));
CreateFood(temp.x, temp.y);
}
public bool CreateFood(int x, int y)
{
Coordinate temp = new Coordinate(x, y);
bool isExist = false;
for(int i = 0; i < foodList.Count; i++)
if(Coordinate.CompareCoordinate(temp, foodList[i]))
isExist = true;
if (!isExist)
{
foodList.Add(temp);
return true;
}
else
return false;
}
}
class Snake
{
Field field { get; set; }
public Coordinate snakeHead = new Coordinate(0, 0);
public List<Coordinate> snakeBody = new List<Coordinate>();
public int direction = 0;
int[] dx = { 1, 0, -1, 0 };
int[] dy = { 0, 1, 0, -1 };
public Snake(int x, int y, Field _field)
{
snakeHead = new Coordinate(x, y);
snakeBody.Clear();
field = _field;
}
public void ChangeDirection(int _direction)
{
if (MathF.Abs(direction - _direction) == 2 && snakeBody.Count > 0)
GameManager.Instance().GameOver();
else
direction = _direction;
}
public void Update()
{
bool isGameOver = false;
MoveSnake(dx[direction], dy[direction]);
if (CheckCollision())
isGameOver = true;
if(CheckFieldOver())
isGameOver = true;
if(isGameOver)
GameManager.Instance().GameOver();
}
public void MoveSnake(int distanceX, int distanceY)
{
snakeBody.Add(snakeHead);
snakeHead = new Coordinate(snakeHead.x + distanceX, snakeHead.y + distanceY);
bool isAte = false;
for(int i = 0; i < field.foodList.Count; i++)
if (Coordinate.CompareCoordinate(snakeHead, field.foodList[i]))
{
isAte = true;
field.foodList.RemoveAt(i);
Coordinate temp;
while (true)
{
while (true)
{
bool tempBool1 = false;
temp = new Coordinate(new Random().Next(0, field.fieldSize), new Random().Next(0, field.fieldSize));
for (int j = 0; j < snakeBody.Count; j++)
if (Coordinate.CompareCoordinate(temp, snakeBody[j]))
tempBool1 = true;
if (!tempBool1)
break;
}
bool tempBool2 = field.CreateFood(temp.x, temp.y);
if (tempBool2)
break;
}
break;
}
if (!isAte)
snakeBody.RemoveAt(0);
}
public bool CheckCollision()
{
for(int i = 0; i < snakeBody.Count; i++)
if(Coordinate.CompareCoordinate(snakeHead, snakeBody[i]))
return true;
return false;
}
public bool CheckFieldOver()
{
if (snakeHead.x < 0 || snakeHead.y < 0 || snakeHead.x > field.fieldSize || snakeHead.y > field.fieldSize)
return true;
else
return false;
}
}
internal class Program
{
static void Main(string[] args)
{
GameManager.Instance().GameStart();
}
}
}
결과물
※ 콘솔창에는 XBOX Game Bar를 통한 녹화 기능을 사용할 수 없어서 스크린 샷으로 대체합니다.


※ 실수로 반대 방향키를 눌러서 게임 오버 된 상황입니다 [스크린샷 찍다가 방향 잘못봤네요.]
블랙잭
코드 전문
using System;
namespace _3rdWeekHomwork2
{
struct Card
{
public int number;
public char suit;
public Card(int _number, char _suit)
{
number = _number;
suit = _suit;
}
}
class GameManager
{
private static GameManager instance;
public Deck deck;
public Board player;
public Board dealer;
public GameManager()
{
deck = new Deck(1);
player = new Board();
dealer = new Board();
}
public static GameManager Instance()
{
if (instance == null)
instance = new GameManager();
return instance;
}
public void StartGame()
{
player.DrawCard(deck.DrawCard());
dealer.DrawCard(deck.DrawCard());
player.DrawCard(deck.DrawCard());
dealer.DrawCard(deck.DrawCard());
Console.WriteLine("Dealer hand");
dealer.DisplayHand();
Console.WriteLine("Player hand");
player.DisplayHand();
CheckBoard();
}
public void DrawTurn(bool playerDraw)
{
bool dealerDraw = false;
if(playerDraw)
player.DrawCard(deck.DrawCard());
if(dealer.total < 17)
{
dealer.DrawCard(deck.DrawCard());
dealerDraw = true;
}
Console.WriteLine("Dealer hand");
dealer.DisplayHand();
Console.WriteLine("Player hand");
player.DisplayHand();
if (!playerDraw && !dealerDraw)
GameOver(true);
CheckBoard();
}
public void CheckBoard()
{
if (player.total == 21)
GameOver(true);
else if (dealer.total == 21)
GameOver(false);
else if (player.total > 21)
GameOver(false);
else if (dealer.total > 21)
GameOver(true);
}
public void GameOver(bool isPlayer)
{
if (isPlayer)
Console.WriteLine("\nYou Win!\n");
else
Console.WriteLine("\nYou Lose...\n");
Environment.Exit(0);
}
}
class Board
{
List<Card> handList = new List<Card>();
public int total;
public Board()
{
handList.Clear();
total = 0;
}
public void DrawCard(Card _card)
{
handList.Add(_card);
total += _card.number;
UpdateTotal();
}
public void UpdateTotal()
{
int AAmouint = 0;
total = 0;
for(int i = 0; i < handList.Count; i++)
{
if (handList[i].number == 1)
AAmouint++;
else if (handList[i].number > 10)
total += 10;
else
total += handList[i].number;
}
for(int i = 0; i < AAmouint; i++)
{
if (total + ((AAmouint - i) * 11) > 21)
total += 1;
else
total += 11;
}
}
public void DisplayHand()
{
Console.Write($"{handList[0].suit} {handList[0].number}");
for (int i = 1; i < handList.Count; i++)
{
if(handList[i].number == 1)
Console.Write($" | {handList[i].suit} A");
else if (handList[i].number == 11)
Console.Write($" | {handList[i].suit} J");
else if (handList[i].number == 12)
Console.Write($" | {handList[i].suit} Q");
else if (handList[i].number == 13)
Console.Write($" | {handList[i].suit} K");
else
Console.Write($" | {handList[i].suit} {handList[i].number}");
}
Console.WriteLine($"\ntotal: {total}\n");
}
}
class Deck
{
public List<Card> deckList = new List<Card>();
public Deck(int numDeck)
{
List<Card> tempDeck = new List<Card>();
for (int i = 0; i < numDeck; i++)
{
for(int j = 1; j <= 13; j++)
{
tempDeck.Add(new Card(j, '♤'));
tempDeck.Add(new Card(j, '◆'));
tempDeck.Add(new Card(j, '♥'));
tempDeck.Add(new Card(j, '♧'));
}
}
deckList = tempDeck.OrderBy(_ => new Random().Next()).ToList();
}
public Card DrawCard()
{
Card drawed = deckList[0];
deckList.RemoveAt(0);
return drawed;
}
}
internal class Program
{
static void Main(string[] args)
{
string playerInput = null;
GameManager.Instance().StartGame();
while (true)
{
Console.Write("Draw Card? (Y/N): ");
playerInput = Console.ReadLine();
if(playerInput != "Y" && playerInput != "N")
{
Console.WriteLine("Wrong Command!");
continue;
}
if (playerInput == "Y")
GameManager.Instance().DrawTurn(true);
else if(playerInput == "N")
GameManager.Instance().DrawTurn(false);
}
}
}
}
결과물
플레이어 버스트 패배

플레이어가 21에 더 가까워서 승리.
[딜러는 17 이상이라 드로우 불가 -> 양쪽 모두 드로우를 안했으므로 게임 종료]

정확히 21으로 플레이어 승리

마무리하며
Unity가 아닌 C# 기본 코딩 만으로 게임을 제작하는 감각이 신선했었습니다.
열심히 머리 굴려가면서 제작 다 했는데 알고 보니까 강의 자료에 과제 관련 정보가 있어서 허탈하기도 했지만...
아무래도 그래픽 관련해서도 제가 직접 코딩해야 하다 보니, 그 부분에서 조금 당황했던 감이 있습니다.
다만, 아무래도 콘솔창 자체적으로 한계가 있다 보니, 제작 자체는 수월하게 진행된 거 같습니다.
이제 금주의 과제인 TextRPG 제작이 남았는데, TextRPG의 기본 구성을 잘 몰라서 일단 자료 탐색 부터 해 봐야 할 거 같습니다. 충동적으로 만들었다가는 콘솔창에서 턴제 RPG를 하는 꼴이 될 거 같아서...;;
'스파르타 내일배움캠프 > Weekly I Learned' 카테고리의 다른 글
Weekly I Learned - 6th Week [팀 프로젝트 - 고전게임 재구성하기] (1) | 2024.10.22 |
---|---|
Weekly I Learned - 5th Week [커뮤니티 게임 만들기] (0) | 2024.10.14 |
Weekly I Learned - 4th Week [Text RPG 팀 프로젝트] (0) | 2024.10.05 |
Weekly I Learned - 3rd Week [개인 프로젝트 - TextRPG] (3) | 2024.09.28 |
Weekly I Learned - 1st Week [미니 프로젝트 완료] (1) | 2024.09.14 |