[게임] 맞고 패 배열값 만들기 프로그램
C# 2016. 10. 8. 15:18 |맞고 게임서버에 테스트 할때 사용한 맞고패 인덱스 배열 만들기 프로그램 입니다.
혹시나 필요하신분이 있을까봐 올려 봅니다.
그래그앤 드롭으로 해당 위치로 가져다 놓으면 배열이 만들어 집니다.
맞고 게임서버에 테스트 할때 사용한 맞고패 인덱스 배열 만들기 프로그램 입니다.
혹시나 필요하신분이 있을까봐 올려 봅니다.
그래그앤 드롭으로 해당 위치로 가져다 놓으면 배열이 만들어 집니다.
C# 공부도 할겸
네임드 사다리 게임결과를 파싱하는 코드 입니다.
http://www.named.com/game/ladder/v2_index.php
처음에는 이 웹 주소를 사용해서 했지만
게임결과값이 내부 iframe로 들어가 있어서 바로 안되는걸로 확인됨
그래서 내부 iframe 의 값을 사용해서 게임 결과값을 파싱 하는 형태로 진행
간단하게 게임결과 파싱하는 코드이기 때문에 참고하실 분만 받으세요.
게임소스
--선언--
using System.Security.Cryptography;
--코드--
#region MD5 메소드
static string getMd5Hash(string input)
{
// Create a new instance of the MD5CryptoServiceProvider object.
MD5 md5Hasher = MD5.Create();
// Convert the input string to a byte array and compute the hash.
byte[] data = md5Hasher.ComputeHash(Encoding.Default.GetBytes(input));
// Create a new Stringbuilder to collect the bytes
// and create a string.
StringBuilder sBuilder = new StringBuilder();
// Loop through each byte of the hashed data
// and format each one as a hexadecimal string.
for (int i = 0; i < data.Length; i++)
{
sBuilder.Append(data[i].ToString("x2"));
}
// Return the hexadecimal string.
return sBuilder.ToString();
}
// Verify a hash against a string.
static bool verifyMd5Hash(string input, string hash)
{
// Hash the input.
string hashOfInput = getMd5Hash(input);
// Create a StringComparer an comare the hashes.
StringComparer comparer = StringComparer.OrdinalIgnoreCase;
if (0 == comparer.Compare(hashOfInput, hash))
{
return true;
}
else
{
return false;
}
}
#endregion
#region MD5 테스트 블록
private void button1_Click(object sender, EventArgs e)
{
// 암호화 문자열을 가져온다.
string convmd5 = getMd5Hash(textBox1.Text);
// 암호화된 내용을 출력한다.
textBox2.Text = convmd5;
}
private void button2_Click(object sender, EventArgs e)
{
// 해당 문자열을 가져와서 암호화된 내용과 비교 한다.
if (verifyMd5Hash(textBox3.Text, textBox2.Text) == true)
{
MessageBox.Show("맞습니다.");
}
else
{
MessageBox.Show("틀립니다.");
}
}
#endregion
WebBrowser를 사용해야 되는 부분이 생겨서
많이 자료를 보고 해봤지만 TopMost라는 특성 때문에 Winform, WPF 모두
원하는 효과를 낼수가 없더라구요.
그래서 여러가지 보고 테스트도 해봤지만.
어떤건 속도가 너무 느리더라구요.
아래 코드는 완전 해결한건 아니지만,
이것도 조금은 접근이 된거 같아요.
목표점은
- 스레드를 통한 백그라운드 처리를 통해서 다른 UI의 동작을 원할하게 처리
- 모자이크 처리로 화면에 출력함으로 해서 조금은 이펙트를 중점으로 한다.
아래의 코드는 일부 접근된 코드를 우선 올려 봅니다.
-- Code --
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Media;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
WebBrowser web = new WebBrowser();
public Form1()
{
InitializeComponent();
web.Width = 1000;
web.Height = 1000;
web.ScrollBarsEnabled = false;
web.ScriptErrorsSuppressed = true;
web.Navigate("http://dev.iamgsi.com/googlemap");
timer1.Start();
}
private void button1_Click(object sender, EventArgs e)
{
//while (web.ReadyState != WebBrowserReadyState.Complete)
// System.Windows.Forms.Application.DoEvents();
//System.Threading.Thread.Sleep(TimeSpan.FromSeconds(5));
int width = web.Document.Body.ScrollRectangle.Width;
int height = web.Document.Body.ScrollRectangle.Height;
web.Width = width;
web.Height = height;
System.Drawing.Bitmap bmp = new Bitmap(width, height);
web.DrawToBitmap(bmp, new System.Drawing.Rectangle(0, 0, width, height));
this.pictureBox1.Width = width;
this.pictureBox1.Height = height;
if (this.pictureBox1.Image != null)
{
this.pictureBox1.Image.Dispose();
}
this.pictureBox1.Image = null;
this.pictureBox1.Image = bmp;
}
private void button2_Click(object sender, EventArgs e)
{
web.Document.InvokeScript("MoveAddress", new object[] { "서울" });
}
private void button3_Click(object sender, EventArgs e)
{
web.Document.InvokeScript("MoveAddress", new object[] { "거창" });
}
private void button4_Click(object sender, EventArgs e)
{
web.Document.InvokeScript("MoveAddress", new object[] { "광주" });
}
private void timer1_Tick(object sender, EventArgs e)
{
if (web.ReadyState != WebBrowserReadyState.Complete)
return;
int width = web.Document.Body.ScrollRectangle.Width;
int height = web.Document.Body.ScrollRectangle.Height;
web.Width = width;
web.Height = height;
System.Drawing.Bitmap bmp = new Bitmap(width, height);
web.DrawToBitmap(bmp, new System.Drawing.Rectangle(0, 0, width, height));
this.pictureBox1.Width = width;
this.pictureBox1.Height = height;
if (this.pictureBox1.Image != null)
{
this.pictureBox1.Image.Dispose();
}
this.pictureBox1.Image = null;
this.pictureBox1.Image = bmp;
}
}
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void timer1_Tick(object sender, EventArgs e)
{
bool bFind = false;
// USB 상태 체크
DriveInfo [] diArray = DriveInfo.GetDrives();
foreach (DriveInfo di in diArray)
{
if (di.IsReady == true && di.DriveType == DriveType.Removable)
{
bFind = true;
break;
}
}
label1.Text = (bFind == true) ? "존재합니다." : "없습니다.";
}
private void button1_Click(object sender, EventArgs e)
{
timer1.Start();
}
}
public partial class ucPanel : UserControl
{
public ucPanel()
{
InitializeComponent();
//
backgroundWorker1.RunWorkerAsync();
}
static public Font ChangeFontSize2(Font font, float fontSize, GraphicsUnit unit)
{
if (font != null)
{
float currentSize = font.Size;
if (currentSize != fontSize)
{
font = new Font(font.Name, fontSize,
font.Style, unit,
font.GdiCharSet, font.GdiVerticalFont);
}
}
return font;
}
public delegate void OnAddNode(string title, int x, int y);
public void AddNode(string title, int x, int y)
{
if (this.InvokeRequired)
{
this.Invoke(new OnAddNode(this.AddNode), new object[] { title, x, y });
return;
}
// 객체 추가
Label lbl2 = new Label();
lbl2.AutoSize = true;
lbl2.Text = title;
lbl2.Font = ChangeFontSize2(lbl2.Font, lbl2.Font.Size * 2, GraphicsUnit.Pixel);
lbl2.Left = x;
lbl2.Top = y;
this.Controls.Add(lbl2);
ucNode ucn = new ucNode();
ucn.Left = x;
ucn.Top = y;
this.Controls.Add(ucn);
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
int breakCount = 0;
Random rand = new Random();
while (true)
{
//
this.Invoke(new OnAddNode(this.AddNode), new object[] { "test", rand.Next(10, 738), rand.Next(10, 460) });
System.Threading.Thread.Sleep(TimeSpan.FromSeconds(1));
//
breakCount++;
if (breakCount > 100)
{
break;
}
}
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
}
}
구글이라던지 이곳저곳 찾아 보면 상당히 많은 예제가 나오는거 같다.
GsiClip을 제작중에 DB에 이미지를 데이터로 추가 해야 하는 부분에
단위 테스트에 사용한 소스 코드임. (테스트 수행)
private void button1_Click(object sender, EventArgs e)
{
// 이미지를 DB로 저장한다.
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
ImageSave(openFileDialog1.FileName);
MessageBox.Show("저장완료");
}
}
private void button2_Click(object sender, EventArgs e)
{
// 이미지를 DB에서 로드한다.
dsImageTableAdapters.Test1TableAdapter adapter =
new ImageSaveDB.dsImageTableAdapters.Test1TableAdapter();
dsImage.Test1DataTable table =
new dsImage.Test1DataTable();
adapter.Fill(table);
if (table.Count > 0)
{
pictureBox1.Image = byteArrayToImage(table[0].Content2);
}
}
public Image byteArrayToImage(byte[] byteArrayIn)
{
MemoryStream ms = new MemoryStream(byteArrayIn);
Image returnImage = Image.FromStream(ms);
return returnImage;
}
byte[] ReadFile(string sPath)
{
byte[] data = null;
//
FileInfo fInfo = new FileInfo(sPath);
long numBytes = fInfo.Length;
//
FileStream fStream = new FileStream(sPath, FileMode.Open, FileAccess.Read);
//
BinaryReader br = new BinaryReader(fStream);
//
data = br.ReadBytes((int)numBytes);
return data;
}
private void ImageSave(string filename)
{
byte[] imageData = ReadFile(filename);
//
dsImageTableAdapters.Test1TableAdapter adapter =
new ImageSaveDB.dsImageTableAdapters.Test1TableAdapter();
adapter.Insert(imageData);
}
System.Object 오버라이딩
public class Pixel {저번주에 값, 참조 타입에 대해서 스터디를 했다.
한번더 복습의 경험이 된거 같다.
우선 여기서 적을 것은 참조 타입의 주소 참조를 통해서 일어나는
몇가지를 적을 생각이다.
string 의 경우 값을 여러개 대입하거나 += 연산자를 통해서
해당 값들을 추가 할때 참조타입이기 때문에 메모리 공간에 값이 추가 되면서
string의 변수가 참조를 하게 된다.
이때 값을 대입하거나, += 을 통해서 대입되는 값들은
새로운 메모리 공간을 또 요구 하게 된다. 즉, 나머지 이전의 참조 값들은
더이상 참조가 되지 않는 것 뿐이며, 그 값은 가비지 컬렉터를 통해서
지워지게 된다.
그렇다 보니 그 값은 지워지지 않은 상태에서 많은 메모리를 소비 하게 된다.
string은 대입을 한번만 하고 해당 정보를 가져다 쓸때만 사용하는 것이 좋다.
만약 여러번의 대입을 사용할 경우는 StringBuilder 을 쓰는게 좋다.
이건 메모리를 충분히 잡아 놓은 상태에서 해당 값들을 계속해서
추가 하더라도 string보다는 메모리 소비가 적게 된다.
C#을 사용하다 보면 포인터의 개념이 없기 때문에 클래스인 경우는 참조 형태로 처리가 되는거 같아요.
A 의 클래스를 a, b로 선언하고 a의 값을 b로 대입하게 되면 참조 형태가 되어서 a의 값을 바꾸게 되면
결국에 b의 값도 바뀌게 되는 경우가 있습니다.
물론 데이터형인 경우는 깊은 복사가 이루어 지지만 클래스인 경우는 일반 복사가 이루어 지는듯 합니다.
간혹 깊은 복사를 해야 할때가 오는데요..
ICloneable을 상속 받아서 처리 하면 아래와 같이 처리 하면 될듯하네요.
// 샘플 코드
class Cell : ICloneable
{
string var;
public string Var
{
get { return var; }
set { var = value; }
}
public Cell(string var)
{
this.Var = var;
}
public object Clone()
{
return new Cell(this.Var);
}
}
class Cells : List<Cell>, ICloneable
{
public Cells()
{
}
public object Clone()
{
Cells listCell = new Cells();
foreach (Cell c in this)
{
listCell.Add((Cell)c.Clone());
}
return listCell;
}
}
맨날 도구상자에 있는 컨트롤만 쓰고 있는 나로서는..
새로운 UI를 구상할때면.. 좀 난감해 지네요 ^^..
이번에는 ListBox를 확장해야할듯 해서
바로 위와 같이 하나의 아이템에 복합적인 데이터가 들어가있다고 가정을 하고 작업을 해야 됩니다.
이미지 정보와 해당 이름 또는 나이 저노하 번호 등등..
이걸 위해서는 DrawItem()을 따로 구현해 줘야 되네요.
// Set the DrawMode property to draw fixed sized items.
listBox1.DrawMode = DrawMode.OwnerDrawVariable;
// Draw the background of the ListBox control for each item.
e.DrawBackground();
// Create a new Brush and initialize to a Black colored brush by default.
Brush myBrush = Brushes.Black;
// Determine the color of the brush to draw each item based on the index of the item to draw.
switch (e.Index)
{
case 0:
myBrush = Brushes.Red;
break;
case 1:
myBrush = Brushes.Orange;
break;
case 2:
myBrush = Brushes.Purple;
break;
}
// 이 부분에서 해당 값을 가져 올때 TestTemplate의 값으로 형변환 한 후에 값을 접근가능..
TestTemplate tt = (TestTemplate)listBox1.Items[e.Index];
// Draw the current item text based on the current Font and the custom brush settings.
e.Graphics.DrawImage(new Bitmap(tt.path), e.Bounds);
e.Graphics.DrawString(tt.name, e.Font, myBrush,e.Bounds,StringFormat.GenericDefault);
// If the ListBox has focus, draw a focus rectangle around the selected item.
e.DrawFocusRectangle();
}
이때 이미지와 여러가지를 표현하기 위해서는 아래의 함수도 오버라이딩 해서 변경해줘야 하네요.
위의 내용을 토대로 샘플을 하나 만들어 볼까 합니다.
하지만 고려되어야 하는 사항은 이미지가 들어가기 때문에
많은 양의 데이터를 읽어 들일때 UI가 블락킹 되는 현상이 불현듯 보이네요..
백그라운드 쓰레드나 일반 쓰레드를 통해서 따로 돌려야 할듯 합니다.
그러면 조금더 나은 UI 및 컨트롤을 구현할 수 있을거 같습니다.
개봉박두~~~..
GraphicsPath path = new GraphicsPath();
path.AddArc(arcRect, 180, 90);
arcRect.X = rect.Right - diameter;
path.AddArc(arcRect, 270, 90);
arcRect.Y = rect.Bottom - diameter;
path.AddArc(arcRect, 0, 90);
arcRect.X = rect.Left;
path.AddArc(arcRect, 90, 90);
path.CloseFigure();
return path;
}
Panel 함수에서 드로잉 하는 코드 입니다.
Graphics g = e.Graphics;
g.SmoothingMode = SmoothingMode.HighQuality;
int width = panel.ClientRectangle.Width;
int height = panel.ClientRectangle.Height;
Rectangle rect = new Rectangle(0, 0, width-1, height-1);
using (GraphicsPath path = RoundPanel.GetRoundedRectPath(rect, 8))
{
using (Brush brush = new LinearGradientBrush(
new Rectangle(0, 0, panel.ClientRectangle.Width, panel.ClientRectangle.Height),
Color.FromArgb(panel.Opcity, 102, 102, 102),
Color.FromArgb(panel.Opcity, 0, 0, 0),
90.0f))
{
//graphics.FillRectangle(brush, 0, 0, this.ClientRectangle.Width, this.ClientRectangle.Height);
g.FillPath(brush, path);
}
//g.FillPath(Brushes.Yellow, path);
Pen pen = new Pen(Color.FromArgb(panel.Opcity, 255, 255, 255));
g.DrawPath(pen, path);
}
}
이걸 처리 하다 보면 화면을 전환 하거나 리프레쉬할때 플리커 현상이 생기기도 합니다.
이걸 해결하기 위해서 RoundPanel에 더블버퍼링 처리 코드를 추가 했습니다.
실행 파일 :
Panel에 두장의 이미지(Bitmap)를 추가한 후에
위의 이미지에 알파값을 추가해서 블랜딩 효과를 줘봤습니다.
코드는 아래와 같아요..
g.DrawImage(beforeLeftImage, new PointF(0, 0));
float[][] ptsArray =
{
new float[] { 1, 0, 0, 0, 0},
new float[] { 0, 1, 0, 0, 0},
new float[] { 0, 0, 1, 0, 0},
new float[] { 0, 0, 0, 0.7f, 0},
new float[] { 0, 0, 0, 0, 1}
};
ColorMatrix clrMatrix = new ColorMatrix(ptsArray);
ImageAttributes imageAtrr = new ImageAttributes();
imageAtrr.SetColorMatrix(clrMatrix,
ColorMatrixFlag.Default,
ColorAdjustType.Bitmap);
g.DrawImage(beforeXrayLeftIamge,
new Rectangle(50, 50, beforeXrayLeftIamge.Width, beforeXrayLeftIamge.Height),
0, 0, beforeXrayLeftIamge.Width, beforeXrayLeftIamge.Height,
GraphicsUnit.Pixel,
imageAtrr);
}