基于C#.NET对战卡牌游戏-《混战》游戏开发

点我查看《混战》源码

目录

第1章 任务描述

第二章 总体设计

第三章 详细设计

 第四章 介面设计

第5章 代码设计

第六章 总结

第七章 参考文献


摘  要

Microsoft给开发人员一个选择-一专门用于. NET、具有新起点的语言,即Visual C# .NET。Microsoft 在正式场合把C#描述成一种简单、现代、面向对象、类型非常安全、派生于C和C++的编程语言。大多独立的评论员对其说法是“继承于C、C++和Java”。这种描述在技术上是非常精准的,但没有涉及到该种语言的真正优点。从语法上看,C#非常类同于C++和Java, 许多关键字都是相同的,C#也使用类似于C++和Java的块状结构,并用括号( {} )来标识代码块,用分号分隔各行语句。对C#代码的第一个印象是它非常类似于C++或Java代码。但在这些表面级的类似性后面,C#学习起来要比C++轻松得多,但比Java难一些。 其设计与现代开发工具的可适应性要比其他语言更高,它同时具有Visual Basic 的易用性、高性能以及C++的低级内存访问性。

在游戏开发领域,C#已经逐渐变成了使用人数最多的语言。不仅是Unity,还有一些新兴的游戏引擎也采用了C#语言(比如godot引擎)。

在游戏行业从业多年的开发者,大都掌握多门开发语言,可以对比评测。总体来看,C#在游戏开发领域口碑非常不错,具体在学习上手、招聘人才、编程规范、运行性能方面都做的十分平衡,没有明显的缺陷。

除游戏前端,C#和.net技术在游戏后端(游戏服务器)也获得了越来越广泛的应用,以前C#在linux上运行有一些问题,现在有了.net core,问题基本解决。

现在市面上大部分游戏都能盈利,相对比影视来讲,影视开发周期长,上线后能不能盈利还不好说。 现在是市场经济,都追求能快熟盈利的产品无论你在哪里,只要有手机,电脑,iPad,估计您都能看到玩游戏的人,VR虚拟游戏体验也非常受大众喜爱,特别是90后,00后,对游戏的接受喜爱程度都很高

这已经足以支撑游戏产业的蓬勃发展,所以,游戏在未来将会越来越火,这一行的薪资待遇自然是非常不错的。

关键词:c#;游戏;.net技术

1 任务描述

在Visual Studio平台下基于C# 利用Form.NET编程独立游戏,塔防卡牌游戏《混战》,并完成以下的总体目标:

  1. 体现出面向对象思想的三大特性:封装,继承,多态。
  2. 自主设计,体现出卡牌,对战,角色扮演的游戏要素。
  3. 在游戏中加载基本的图片和音效资源,实现基础打击反馈。
  4. 至少有一个开始界面和游戏界面。
  5. 利用拖动和手动编程俩种方法来生成和显示控件。
  6. 利用属性事件填写和自定义委托俩种方法来完成事件绑定。
  7. 游戏完成后,录制视频,进行简单的游戏介绍和编程思想解释。

第二章 总体设计

2.1 框架结构

表2.1 框架结构

平台

Window10

软件

Visual Studio 2019

编程语言

C#

编程框架

WinForm.NET窗体应用程序

2.2 目录结构

图2.1目录结构图

2.3 下载资源

2.3.1 图片资源

图2.2 图片资源

2.3.2 音效资源

图2.3 音效资源

第三章 详细设计

列出了主要类和主要方法名,以及类和方法的用途,方法体内容省略,进行大概理解整体框架结构。主要有Manager类,People类,role类组,Player类和俩个辅助类MCI类和PanelEnhanced类。

3.1 Manager类

用于统筹管理,进行显示和数据管理,对整个系统进行整合,关联所有类

class Manager
    {
        Form cform = new Form();
        public int mouse_int = 0;//鼠标编号
        public static List<People> roles = new List<People>();//角色图签,只是可读
        public Player I_Player = new Player(1);//自己玩家
        public Player E_Player = new Player(2);//敌人玩家
        public List<People> road1 = new List<People>();//1路自己
        public List<People> eroad1 = new List<People>();//1路敌人
        public List<People> road2 = new List<People>();//2路自己
        public List<People> eroad2 = new List<People>();//2路敌人
        public List<People> road3 = new List<People>();//3路自己
        public List<People> eroad3 = new List<People>();//3路敌人

        int E_MaxValue = 0;
        Button PB = new Button();//头像框
        Button I_HPB = new Button();//血条框
        Button E_HPB = new Button();//敌人血条框
        
       public Manager(){...}//初始化-无参构造函数
   public void Ini_Eintlist(){...}//敌人卡牌集初始化
   public void AddRoles(){...}//图签初始化
   public  void GenerateRole(int sum,int team,int road){...}//生成角色,sun编号,team队伍,road生成道路
        public void addform(Form _cform){...}//绑定当前窗口 初始化窗口控件位置 卡牌框组样式既位置
public void Move_or_Atk(){...}//检测移动攻击

//以下私有成员函数,用于简化前面公有函数所提取
private void random(int[] a,int n){...}//不重复随机整数数组生成,用于初始化敌人卡牌图签
private void change_mouse(object sender,EventArgs e){...}//点击角色卡牌,鼠标数值变化
        private void Place_people(Object sender,EventArgs e){...}//放置角色卡牌
private void cards_down(){...} //点击其他地方 卡牌下移
        private void Addroad(People p, int road){...}//把某人加到某路
private void Fram_rate(){...}//帧率:敌我血条变化 金币显示 敌人AI出兵 敌我增长钱
private void one_MA(List<People> road1, List<People> eroad1){...}//一路检测移动攻击
private void ATK_one(List<People> road1, List<People> eroad1){...}
private void check_state(List<People> road1){...}//状态检测
private void check_die(){...} //检测死亡和兵走到路尽头扣血
      }

3.3 Player类

玩家类,继承People,用于判断游戏输赢,拥有自己卡牌组和金币

 class Player:People
    {
        public int[] intList= new int[6];//自己的卡牌号码组
        public int gold=13;//玩家金币
        public int gold_getspeed=10;//玩家得到金币速度
        public int gold_time = 0;//满百得1
        public int grade=1;//玩家等级

    public Player(){...}//无参构造,初始化玩家血量
    public Player(int _team) : this(){...}//生成有位置,有队伍的图片,且调用无参构造
    public void addgold()//自动增长金币

 //以下为无用的空函数,为了满足抽象类People重写
        public override void atk_sound(){}
        public override void PassiveSkill(List<People> road1, List<People> eroad1, People ep){}
        public override void Skill(List<People> road1, List<People> eroad1, People ep)
        public override void skill_sound(){}
        public override void Skill_time_change(){}
}

3.4 role类组举例

卡牌角色类,继承People,游戏中基本单位,拥有各自的特征(生命,攻击,移速,攻速,图片,技能等等....)可实现扩展,用其中之一类SwordMan剑士类作为举例:

图3.1  role类组包含的角色类

【举例】SwordMan类:

class SwordMan : People
    {   public SwordMan()//角色初始化
        {
            NAME = "剑士";//名称
             num = 1;//编号
            VALUE = 14;//购买价格
            MHP = 100;//最大血量
             HP = 100;//血量
            ATK = 10;//攻击力
            DEF = 10;//防御力 减伤百分比=防御力/(防御力+X)
            ATK_mothod = 1;//攻击方法
            ATK_range = 10;//攻击范围
            ATK_speed = 10;//攻击速度
            SPEED = 10;//移动速度
            PBox.Image = System.Drawing.Image.FromFile(@"..//..//Resources//剑.png");
            //队伍team
            //显示框PBox
            //当前位置_P
        }
public SwordMan(int _team):this(){...}//生成有位置,有队伍的图片,调用无参构造
public override void Skill_time_change(){...}//损失血量增加技能释放概率
public override void Skill(List<People> road1,List<People> eroad1,People ep){...}//主动技能 激励:攻速加快
public override void PassiveSkill(List<People> road1, List<People> eroad1, People ep){}//被动技能:无
public override void atk_sound(){...}//攻击音效
public override void skill_sound(){...}//技能音效
}

3.5 MCI类

自带的音乐播放函数System.Meida.SoundPlayer(),会造成播放阻塞,不能同时播放俩首音乐。为了使得游戏音效重叠播放需要自定义音乐播放类.用线程来解决在播放的时候指定wait时产生线程阻塞,从而导致界面假死的现象。

public class MCI
        {
            [DllImport("winmm.dll")]
            private static extern long mciSendString(
                string command,      //MCI命令字符串
                string returnString, //存放反馈信息的缓冲区
                int returnSize,      //缓冲区的长度
                IntPtr hwndCallback  //回调窗口的句柄,一般为NULL
                );     
           private Thread thread;
  private void PlayWait(string file){...}// 按指定次数播放
private void PlayRepeat(string file){...}  // 循环播放
 public void Play(string file, int times){...}//播放音频文件
 public void Exit(){...}// 结束播放的线程
}

3.6自定义控件PanelEnhanced类

由于背景图的存在,当角色移动时,由于窗口频繁刷新会产生角色白光闪烁,为解决这一问题,需要自定义Panel控件重写里面的函数,来放置背景,利用双缓冲区解决问题

class PanelEnhanced : Panel
    {
protected override void OnPaintBackground(PaintEventArgs e){...}// 重载基类的背景擦除函数, 解决窗口刷新,放大,图像闪烁
protected override void OnPaint(PaintEventArgs e){...}// 使用双缓冲 背景重绘移动到此
}

 第四章 介面设计

为适应游戏的可扩展性,只有少部分不动的控件利用拖动和属性修改器进行生成控件,但为了随着游戏的随机性和角色图签的扩展性,是通过代码来根据数据自动生成界面。

4.1 开始界面

图4.1 开始界面

其中只有“请选择六名角色卡牌”是拖动Label控件完成,其他都是代码书写样式并显示,下面展示样式及其按钮事件代码

 public partial class Start : Form
    {
        int selectCount = 0;
        public static int[] intlist=new int[6];
        public Start()
        {
            InitializeComponent();

        }

        private void Start_Load(object sender, EventArgs e)
        {  
 int x = this.Width;//获得屏幕宽度
// 卡牌样式
            for (int i = 0; i < Manager.roles.Count; i++)
            {
                 Button B_I_role = new Button();
                B_I_role.Size = new Size(150,150);
                this.Controls.Add(B_I_role);
                B_I_role.Location = new Point(i*160%(Width-150), (i*160/(Width-150))*160+100);
                B_I_role.Name = "button" + Convert.ToString(i);
                B_I_role.Text = Convert.ToString(i + 1)+Manager.roles[i].NAME;
                B_I_role.TextAlign = ContentAlignment.TopCenter;
                B_I_role.Image = Manager.roles[i].PBox.Image;
                B_I_role.Click += new EventHandler(select);//绑定按钮事件
                B_I_role.Tag ="0";
            }
            //开始按钮及其样式
            Button Run = new Button();
            Run.Size = new Size(300, 50);
            this.Controls.Add(Run);
            Run.Location = new Point(600,700);
            Run.Text = "开始";
            Run.TextAlign = ContentAlignment.MiddleCenter;
            Run.Click += new EventHandler(run);//绑定按钮事件
            Run.Tag = "0";
        }
//开始按钮点击事件
        private void select(object sender, EventArgs e)
        {
            Button button = (Button)sender;//获取调用事件的主体
            for (int i = 0; i < Manager.roles.Count; i++)
            {
                if (button.Name == "button" + Convert.ToString(i))//找到所点击的按钮
                {  
                  if ((string)button.Tag == "0"&&selectCount<6) 
                    { button.Tag ="1";
                        selectCount++; 
                        button.BackColor = Color.Red;
                        for (int j = 0; j < 6; j++)
                        {if (intlist[j] == 0)
                            { intlist[j]= i+1;
                                break;
                            }                      
                        }
                        break; 
                    };
                  if ((string)button.Tag == "1") 
                    { button.Tag ="0"; 
                        selectCount--; 
                        button.BackColor = Color.White;
                        for (int j = 0; j < 6; j++)
                        {
                            if (intlist[j] == i+1)
                            {
                                intlist[j] =0;
                                break;
                            }
                        }
                        break; };
                }
            }
        }
        private void run(object sender,EventArgs e)
        {   //检测选满后创建新窗口
            Button b = (Button)sender;
            for(int i=0;i<6; i++)
            {
                if (intlist[i] != 0)
                { }
                else 
                { b.Text = "未满6名角色无法开始游戏"; return; }
            }
            Form1 form1 = new Form1(intlist);
            form1.ShowDialog();
            this.Close();
        }
    }

4.2 游戏界面

图4.2 游戏界面

本页面全通过手动代码完成,通过Manager类根据数据进行自动显示,然后在窗体的Load函数中调用该函数完成页面初始化,只挑选出有关此游戏页面样式的代码进行展示:

class Manager
{
 ......
//绑定当前窗口 初始化窗口控件 卡牌框组样式既位置
        public void addform(Form _cform)
        {   
            cform = _cform;
           
            cform.Text = "《混战》";
            cform.MouseDown += new MouseEventHandler(Place_people);//给窗体添加点击事件
            /*      AI_first();//AI初始化*/
            //初始化窗口控件
            //敌人金币初始化(难度)
            E_Player.gold += 5;
            E_Player.gold_getspeed +=1;
            //头像界面
           
            PB.Size = new Size(130, 130);
            I_HPB.Size = new Size(970, 20);
            E_HPB.Size = new Size(970, 20);
            cform.Controls.Add(PB);
            cform.Controls.Add(I_HPB);
            cform.Controls.Add(E_HPB);
            PB.Location = new Point(260, 515);
            I_HPB.Location = new Point(260, 480);
            E_HPB.Location = new Point(260, 460);

            PB.Name = "头像";
            PB.BackColor =Color.White;
            I_HPB.BackColor = Color.Green;
            E_HPB.BackColor = Color.Red;
            PB.Enabled = false;
            I_HPB.Enabled = false;
            E_HPB.Enabled = false;
            PB.TextAlign =ContentAlignment.BottomCenter;
            
            for (int i = 0; i < 6; i++)
            {//卡牌组样式既位置
                Button B_I_role = new Button();
                B_I_role.Size = new Size(130, 130);
                cform.Controls.Add(B_I_role);
                B_I_role.Location = new Point(400+i*140,515);
                B_I_role.Name = "button"+Convert.ToString(i + 1);
                B_I_role.Text =Convert.ToString(i+1);
                for (int j=0; j < roles.Count; j++)
                { if (I_Player.intList[i] == roles[j].num)
                    {
                        B_I_role.Text +=roles[j].NAME;
                        B_I_role.Text += "\n";
                        B_I_role.Text +="价格:"+ roles[j].VALUE+"金币";
                        break;
                    }
                }
                B_I_role.TextAlign = ContentAlignment.TopLeft;
                B_I_role.Image = roles[I_Player.intList[i]-1].PBox.Image;
                B_I_role.Click += new EventHandler(change_mouse);//绑定自定义按钮事件
            }
     }
.....
}

第5章 代码设计

此部分主要用来介绍一些主要功能代码,详细到方法体内容。

5.1 焦点点击屏幕放置功能

public void addform(Form _cform)
        {
......  
 cform.MouseDown += new MouseEventHandler(Place_people);//给窗体添加点击事件
......
}
private void Place_people(Object sender,EventArgs e)//放置角色卡牌
        {  
            if (mouse_int > 0&&I_Player.gold>= roles[mouse_int - 1].VALUE)
            {
                I_Player.gold -= roles[mouse_int-1].VALUE;
                Point MouP = cform.PointToClient(Control.MousePosition);//焦点点击
                if (MouP.Y > 85 && MouP.Y <= 115 + People.SIDE)//焦点点击在第一路
                {
                    GenerateRole(mouse_int,1,1);
                }
                else if (MouP.Y > 115 + People.SIDE && MouP.Y <= 145 + 2 * People.SIDE)//第二路
                {
                    GenerateRole(mouse_int, 1, 2);

                }
                else if (MouP.Y > 145 + 2 * People.SIDE && MouP.Y <= 175 + 3 * People.SIDE)//第三路
                {
                    GenerateRole(mouse_int, 1, 3);
                }
                else
                {
                    //点击其他地方 卡牌下移
                    cards_down();
                    I_Player.gold += roles[mouse_int - 1].VALUE;
                    mouse_int = 0;
                }
            }
        }
  public  void GenerateRole(int sum,int team,int road)//生成角色,sun编号,team队伍,road生成道路
        {
                People p;
                switch (sum)//编号
                {
                case 0: return;
                case 1:  p = new SwordMan(team); p.addform(cform); Addroad(p, road); break;
                case 2:  p = new StoneMan(team); p.addform(cform); Addroad(p, road); break;
                case 3: p = new vampire(team); p.addform(cform); Addroad(p, road); break;
                case 4: p = new FireMage(team); p.addform(cform); Addroad(p, road); break;
                case 5: p = new Archer(team); p.addform(cform); Addroad(p, road); break;
                case 6: p = new Dog(team); p.addform(cform); Addroad(p, road); break;
                case 7: p = new Minister(team); p.addform(cform); Addroad(p, road); break;
                case 8: p = new ThornBeast(team); p.addform(cform); Addroad(p, road); break;
                case 9: p = new Orcs(team); p.addform(cform); Addroad(p, road); break;
                case 10: p = new SKeleton(team); p.addform(cform); Addroad(p, road); break;          
                case 11: p = new SKeletonMage(team); p.addform(cform); Addroad(p, road); break;
                case 12: p = new Boom(team); p.addform(cform); Addroad(p, road); break;
                case 13: p = new Shrem(team); p.addform(cform); Addroad(p, road); break;
            }
        }
  private void Addroad(People p, int road)//把某人加到某路
        {        
            switch (road)
            {
                case 1:
                    if (p.team == 1)
                    { road1.Add(p);
                        p.road1 = road1;
                        p.eroad1 = eroad1;
                        p._P = new Point(People.SIDE, 100);
                    }
                    else
                    { eroad1.Add(p);
                        p.road1 = eroad1;
                        p.eroad1 = road1;
                        p._P = new Point(1552-People.SIDE*2, 100);
                    } break;
                case 2:
                    if (p.team == 1)
                    { road2.Add(p);
                        p.road1 = road2;
                        p.eroad1 = eroad2;
                        p._P = new Point(People.SIDE, 100 + (People.SIDE + 30));
                    }
                    else
                    { eroad2.Add(p);
                        p.road1 = eroad2;
                        p.eroad1 = road2;
                        p._P = new Point(1552 - People.SIDE * 2, 100 + (People.SIDE + 30));
                    } break;
                case 3:
                    if (p.team == 1)
                    { road3.Add(p);
                        p.road1 = road3;
                        p.eroad1 = eroad3;
                        p._P = new Point(People.SIDE, 100 + (People.SIDE + 30) * 2);
                    }
                    else
                    {   eroad3.Add(p);
                        p.road1 = eroad3;
                        p.eroad1 = road3;
                        p._P = new Point(1552 - People.SIDE * 2, 100 + (People.SIDE + 30) * 2);
                    } break;

            }
            //显示
            p.PBox.Location = p._P;
            p.HpBox.Location = p._P;


            cform.Controls.Add(p.HpBox);
            cform.Controls.Add(p.PBox);

         
        }

5.2 随机化敌人卡牌功能

 public void Ini_Eintlist()//敌人卡牌集初始化
        {   
            //敌人初始化 
            Array.Clear(E_Player.intList, 0, E_Player.intList.Length);
            random(E_Player.intList, 6);
            E_MaxValue = roles[E_Player.intList[0] - 1].VALUE; //敌人最大价格
            foreach (int sum in E_Player.intList)
            {
                if (roles[sum - 1].VALUE > E_MaxValue)
                {
                    E_MaxValue = roles[sum - 1].VALUE;
                }

            }
        }
  //不重复随机整数数组生成,用于初始化敌人卡牌图签
        private void random(int[] a,int n)
        {
            long tick = DateTime.Now.Ticks;
            Random ran = new Random((int)(tick & 0xffffffffL) | (int)(tick >> 32));

           
            for (int i = 0; i < n; i++)
            {
                a[i] = ran.Next(1, roles.Count+1);
            }
            Boolean bol = true;
            while (bol)
            {
                Array.Sort(a);
                int num = 0;
                for (int i = 0; i < 5; i++)
                {
                    if (a[i] != a[i + 1])
                    {
                        num++;
                    }
                    else
                    {
                        a[i + 1] = ran.Next(1, roles.Count+1);
                    }
                    if (num == 5)
                    {
                        bol = false;

                    }
                }
            }

        }

5.3 卡牌移动与攻击功能

  class Manager
{
.....
        public void Move_or_Atk()//检测移动攻击
        {   // 帧率变化

            Fram_rate();
            //检测移动攻击
            one_MA(road1, eroad1);
            one_MA(road2, eroad2);
            one_MA(road3, eroad3);

            check_die();//检测死亡
        }
 private void one_MA(List<People> road1, List<People> eroad1)//一路检测移动攻击
        {   
            //状态检测
            check_state(road1);
            check_state(eroad1);
            //如果两边都有人

            if (road1.Count != 0 && eroad1.Count != 0)
            {   //攻击或移动
                ATK_one(road1, eroad1);
                ATK_one(eroad1, road1);        //交换检测

            }
            else
            {//如果只有一边有人
                foreach (People p1 in road1)
                { p1.Move(); };
                foreach (People p2 in eroad1)
                { p2.Move(); };
            }
        }

        //攻击或移动
        private void ATK_one(List<People> road1, List<People> eroad1)
        {
            try//避免空集暂停程序
            {
                foreach (People p1 in road1)
                {
                    bool IsMove = true;
                    bool IsAtk = true;
                    foreach (People p2 in eroad1)
                    {
                        int range = Math.Abs(p2._P.X - p1._P.X);
                        IsAtk = ((p1.ATK_range + People.SIDE) >= range);

                        if (IsAtk)
                        {
                            p1.Atk(p2);
                            if (p1.ATK_mothod == 1) break;//单体攻击找到后退出循环
                            IsMove = false; //(解决后方问题?会移动后方,由于判断移动了)
                        }
                    }
                    if (IsAtk == false && IsMove == true)
                    {
                        p1.Move();
                    }
                }
            }
            catch { };
        }
.....
}
 abstract class People
{
......
   public  void Move()//公共方法-移动
        {
            //移动上下跳动
        _P.Y = (int)(_P.Y - SPEED * Math.Cos(time++)+0.45); 

            //移动
            switch (team)
             {    
                  case 1: _P.X += (int)(SPEED / 1.2 + 1); break;
                  case 2: _P.X -= (int)(SPEED / 1.2 + 1); break;
             }
            PBox.Location = _P;
            HpBox.Location = _P;
            HpBox.BringToFront();  
        }
        public virtual void Atk(People p)//虚方法-攻击/特殊的重写
        {
            Skill_time_change();//技能概率变化
            //技能随机释放
            int a = 1+Convert.ToInt32(Guid.NewGuid().GetHashCode() % 100);
            int random=0;
            if (a < 0) random = a + 100;
            else { random = 100; }
            this.ATK_time += this.ATK_speed;//攻速满一百一次攻击
             if (this.ATK_time >= 100)
           {
                    this.ATK_time -= 100;
                if (random >= Skill_time)
                {
                    p.PassiveSkill(eroad1, road1, this);//被动技能
                    atk_sound();//攻击音效
                    p.HP -= (int)(this.ATK * (1 - (p.DEF / (p.DEF + 30))));
                }
                else { Skill(road1, eroad1, p); }
            }
        }
public abstract void Skill_time_change();//多态方法-技能概率变换
        public abstract void Skill(List<People> road1,List<People> eroad1,People ep);//多态方法-技能
        public abstract void PassiveSkill(List<People> road1, List<People> eroad1, People ep);//多态方法-被动技能
        public abstract void atk_sound();//攻击音效
        public abstract void skill_sound();//技能音效
}

5.4动态化频率显示功能

 private void Fram_rate()
        {  //敌我血条变化
            I_HPB.Size =new Size(970*I_Player.HP/2000,20);
            E_HPB.Size = new Size(970 * E_Player.HP / 2000, 20);
            //金币显示
            PB.Text ="生命:"+I_Player.HP+"\n"+ "金币:" + I_Player.gold;
            //敌人AI出兵
            if (E_MaxValue <= E_Player.gold)
            {
                int MaxX = 0;
                int road = 2;
                foreach (People p1 in road1)
                {
                    if (p1._P.X > MaxX)
                    {
                        MaxX = p1._P.X; road = 1;
                    }

                }
                foreach (People p1 in road2)
                {
                    if (p1._P.X > MaxX)
                    {
                        MaxX = p1._P.X; road = 2;
                    }

                }
                foreach (People p1 in road3)
                {
                    if (p1._P.X > MaxX)
                    {
                        MaxX = p1._P.X; road = 3;
                    }

                }
                int r2 =100* (MaxX-People.SIDE) /( 1552 - People.SIDE);
                int r3 = (UInt16)DateTime.Now.Ticks % 101;
                int r = (UInt16)DateTime.Now.Ticks % 6;
                if (roles[E_Player.intList[r]-1].VALUE <= E_Player.gold)
                {
                    if (r3 <= r2 + 30)
                    { GenerateRole(E_Player.intList[r], 2, road); }
                    else
                    {
                        int road2 = 1 + r3 % 3;
                        GenerateRole(E_Player.intList[r], 2, road2);
                    }
                    E_Player.gold -= roles[E_Player.intList[r]-1].VALUE;
                }
            }
            //敌我增长钱
            I_Player.addgold();
            E_Player.addgold();
            for (int i = 0; i < 6; i++)
            {
                Control[] c = cform.Controls.Find("button" + Convert.ToString(i + 1), false);
                if (roles[I_Player.intList[i]-1].VALUE > I_Player.gold)
                    c[0].BackColor = Color.Red;
                else { c[0].BackColor = Color.White; }

            }

        }

第六章 总结

刚开始作为游戏编程小白的我,听别人建议,这一学期专门学习了c#来进行编程,为了使得游戏好玩,我零零散散学了许多东西,例如像素画,音效合成,打击反馈等等。刚开始是这个c#WinForm窗口提起了我的兴趣(作为一个被控制台文字毒害的我,终于发现了一个可视化程序编程宝藏),于是我马不停蹄的俩周学完了c#基础,然后因为拥有c++编程的原因,以及做过几个小系统,立马完成了我的第一款自己做的《飞机大战》小游戏,但是这个游戏的编程思想纯粹是顺序编程,没有体现面向对象,于是在接下来的一周时间,我好好计划了一下项目,既不能太大让我束手无策,也不能太小没有可玩性。于是《混战》便诞生了,刚开始的版本非常简陋,只有几个角色,而且也有许多BUG,可能一天查BUG到最后才发现不小心写错了单词。但我还是坚持下来了,总的来说,编程是最重要的,但是查找各种图片音效资源,以及手动画了一张像素背景画却也花费了我的大量时间,所以说游戏编程并不容易。

虽然说这个版本还有许多遗憾没有完成,像开始界面的设置按钮(调音量,调背景,调上传头像),关卡界面(增强可玩性),存档功能(IO流记录的比较多,不想搞了),以及比较难搞的攻击和移动动画等都是一些遗憾,但就此结束吧!

最主要原因,还是这个WinForm的框架编游戏太困难了,不仅出现背景闪烁(加入新控件,已解决),音频互相阻塞(加入新类,已解决),,帧移动不流畅(未解决),用过的垃圾不能手动回收(未解决,死亡的人物占内存,没有垃圾池机制)等等许多毛病,而且需要手动编写碰撞箱,基础表格,以及运行起来缓慢,让我放弃了WinForm窗体应用程序框架。

幸运的是,在我学习过程中,我了解了Unity软件,它对3D游戏编程最为方便也可进行2D游戏编程,且内置了许多功能,方便一众独立游戏编程,我已经大概了解了软件使用基本过程,准备在假期期间继续对C#的深入学习和Unity的熟练掌握。

第七章 参考文献

  1. 知乎,皮皮关,《c#目前在游戏领域应用》
  2. CSDN,kucoffee12,《解决C#Winform应用程序中窗体背景闪烁问题》
  3. CSDN,Zhy,《调用API函数mciSendString播放音频文件》

  • 7
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ζั͡ ั͡雾 ั͡狼 ั͡✾

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值