如何用c#实现,在while (true)循环中,按Esc键退出循环? 有一循环,如果人工不主动按Esc键,则一直执行循环。如何实现按Esc键退出循环?while (true){ ....... if (?)//如何写捕捉按下Esc键的代码 { break; }} 解决方案 » 免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货 如何编制RPG游戏(上)类型:转贴 | 来源:整理| 时间: 2006-04-26游戏玩得多了,可能每个人都曾会想过一个问题:要是自己也能制作出一套游戏那多好。究竟编游戏的吸引力在哪里呢?在很多地方,颇具微妙--你就真正控制了故事中剧情的发展、主角的命运,也许还有用自己主观感情去感染别人。这就好比写作,虽然并非人人都会去做,却人人想做,极富魅力。 那么,在业余条件下能否完成游戏的编制呢?答案是完全可以。 一套游戏,其中包含的内容很多,涉及了编程技巧的方方面面。本文力求从简便的角度出发介绍RPG类游戏的制作,只要你有一点C语言的基础,就可以按部就班编出一个游戏来,若对C没有一点概念,那么正好趁此机会学习一下C,体会体会当代最实用的编程语言。考虑到现在C及C++各种版本的普及情况,在此拟采用Turbo C 2.0为例,逐一介绍这方面的具体知识。 一 浅说: 在正式进入游戏编程前,我们先来谈谈有关屏幕管理的几个有趣的问题。计算机显示器的工作方式有两种:正文方式和图形方式,在每种显示方式下还可分为不同的显示模式。对于我们的GAME来说,她的处理对象主要是图形,所以我们需要采用后一种显示方式。 在Turbo C中initgraph是一个初始化图形系统的有用函数,它从磁盘装入一个图形驱动程序,且把系统置成图形方式。除了这种动态装入机制外,也可以将一个或几个图形驱动程序文件直接同可执行程序文件连接起来。游戏中通常采用的是640×480或320×200的分辨率。让我们来看看一个子程序: setupgraph() /* 图形初始化 */ { int driver=VGA,mode=VGAHI; /* VGA卡的VGAHI图形模式,640*480同显16色 */ initgraph(&driver,&mode,""); /* 使用空字符串 "" 表示设备驱动程序在当前目录中 */ } 这个程序装入的图形驱动程序文件为EGAVGA.BGI,在例程中我们也将采用这种640×480的模式进行编程。若想选用其他分辩率,只需改变driver和mode的值便可。 下面我们来谈谈有关调色板的应用。 对于VGA显示器,图形模式12H(640×480,16色)共设置了16个颜色寄存器,所以显示器上能同时最多显示16种颜色。系统初始化时,也将颜色寄存器予以初始化,若这种默认颜色值不满足要求的话,只需修改相应颜色寄存器的数据,就可实现从64种颜色中任意选取,使显示的图形更加美观。 setpalette(调色板号,颜色号)函数可将指定的颜色填入指定的调色板中,从而改变调色板上的默认颜色。例如: setpalette (1,4); 用该函数重新设置后,以后使用1号调色板时,则显示4号颜色红色。 【注】有效的颜色依赖于当前的图形驱动程序和当前的图形模式,该函数不可用于IBM-8514图形驱动程序,应使用setrgbpalette函数。 VGA的13H模式是320×200点阵的彩色图形模式,同显256色。在图形初始化完成后,我们就可以进入富有挑战的游戏编程了。 二 制作精灵:在RPG游戏中,有很多能根据不同规则和目的而在背景场地跑来跑去的小目标:象城镇里的居民,野地上的小动物,或者再加上几株会动的小树,当然了,还有最重要的主角--游戏中的英雄或淘气鬼。这些小角色我们通常称之为“精灵”。 这些精灵要在各自的场地上迅速移动,当它们在草地上跑动时,经过的地方要遮住背景,而当它们经过后,背景的草地又要迅速恢复回来,若是遇到房屋、小河、岩石,就要停下来。那么,这些是如何实现的呢? 在程序中实现精灵的移动,我们通常采用这样的方法:在屏幕上擦除精灵当前的位置,然后在下一个位置进行重显……依次循环,你就会感到精灵跑动起来。这个原理是很简单的,但重要的是:擦掉并重显的速度必须足够快,才能有活生生的效果。 构成图形的最基本要素是点,无论背景也好,精灵也好,都是由许许多多的点组成的,所以精灵的重显问题其实也就是擦点画点的问题。在屏幕上画点有两种方法,一种是使用ROM BIOS调用,另一种是直接写显示RAM。这两种方法比较而言,前一种是相当慢的,而后一种极快。正因为如此,我们不能通过ROM BIOS去画点,而必须采用直接写显示RAM的办法画点。精灵在背景画面上保持动态最好的办法是通过XOR(“逻辑异或”)运算,借助XOR操作,动态精灵在同一显示位置上连续进行两次XOR运算,使画面出现和消失,而不会导致背景画面的任何损坏,我们来看例程:void putpoint (int x,int y,int color) { union REGS r; color=color|128; /* 参数color 和 128相逻辑或,置位最高位 */ r.h.bh=0; r.h.ah=12; r.h.al=color; r.x.dx=y; r.x.cx=x; int86(0x10,&r,&r); } 这个画点程序采取直接写显示RAM的办法,在画每一个点时, 先让彩色值与值128进行逻辑“或”,使彩色值的位7为1,(这就告诉了函数不是以新彩色值替换原彩色值,而是与原彩色值进行逻辑“异或”)。所以这个点总是可见的. 因为它总是与周围其它点颜色不一样,而连续两次XOR运算又很容易使周围曾经被它占据的点恢复成被占据前的颜色。 在解决了画点问题后,只要把组成精灵的点归入一个集合,使这些点同时进行运动,那么,精灵的问题也就解决了。 精灵的造型设计是丰富多彩的, 你尽可以凭你的想象创造出要在游戏中出现的形态各异的人和其它各种角色。我们可以借助Animator pro来完成角色设计,如果精灵不是很复杂的话,我们甚至可以直接“点”出她们:打开Spt或Windows的画笔,我们在“逐点修改”的方格阵上点绘出精灵的造型,反复修改至满意,给精灵定个外框,在四角任取一个点作为参照坐标(X,Y),以(X,Y)为参数组成精灵集合man(int x,int y): void man(int x,int y) { putpoint(x+dx1,y+dy1,color); ...... putpoint(x+dxn,y+dyn,color); } 一般来说,精灵应比较小,以便加快重显速度,使移动看起来比较平滑。若精灵太大,移动起来就比较慢。在例程中,我们用一个9×12的框代替精灵: void man(int x,int y,int color) { int i; for (i=0;i<9;i++) {putpoint(x+i,y,color); putpoint(x+i,y+12,color);} for (i=0;i<12;i++) {putpoint(x,y+i,color); putpoint(x+9,y+i,color);} } [返回页首] 三 键盘控制: 在游戏中,主角的移动一般是由上、下、左、右键或HOME、END、PGUP、PGDN四键控制的,此处还有几个问题:若键入空格、回车等,计算机如何识别?在游戏的中文菜单中如何用上下键移动选择光条?这些都是在游戏编程中会碰到的典型问题。 在Turbo C中,我们用bioskey (int cs)函数来获取键盘字符。这个函数使用BIOS中断0x14完成各种键盘操作,参数cs确定实际的操作:cs=0,返回从键盘输入的下一键码;cs=1,测试输入键是否有效;cs=2,请求当前移位键(SHIFT)的状态。 bioskey(0)获得所击键的扩展的扫描码。扩展的扫描码分两部分,即扫描码和ASCⅡ码。当按键是一般ASCⅡ码时,如回车、空格、ESC键,从扩展扫描码的低字节中可以得到它的ASCⅡ码值;当按键是特殊键时,如上、下、END、HOME键,其ASCⅡ码部分为0,所以要将组成扩展扫描码的两部分分开: …… do {key.i=bioskey(0); if(key.ch[0]) {switch(tolower(key.ch[0])) {case ‘\‘: 程序一 /* 空格键 */ case ‘r‘: 程序二 /* 回车键 */ …… }} else {switch(key.ch[1]) {case 72: 程序三 /* 上键 */ case 80: 程序四 /* 下键 */ case 75: 程序五 /* 左键 */ case 77: 程序六 /* 右键 */ …… }} }while(tolower(key.ch[0]!=27); /* ESC键 */ …… key.ch[0]中为ASCⅡ码部分,key.ch[1]为扫描码部分。ESC键为ASCⅡ字符键,键值为27,所以上面程序最后一行表示当按键不是ESC时,就一直循环。而由于上、下、左、右键为特殊键,所以判别是否按了这些键用switch(key.ch[1])。 楼上给出的是用turbo c在dos下实现的方法。楼主要问的是用c#在winform应用中的实现方法。 只要知道Esc的扫描码与键值就可以实现了啊 ESC的ascii码是027。所以你只要捕获到键盘输入ESC的时候跳出就行了。 private bool boolLoop; while(!boolLoop){}然后处理键盘单击事件当是ESC的时候boolLoop=true即可 在循环中不断检测键盘按键是不是esc,具体监视键盘要用到dll,搜下吧 我估计需要添加对程序消息的过滤,如下:public class MessageFilter : IMessageFilter {int WM_KEYDOWN = 0x0100public bool PreFilterMessage(ref Message m) {if (m.Msg == WM_KEYDOWN) {MessageBox.Show("WM_LBUTTONDOWN is: " + m.Msg);return true;}return false;}}然后使用Application.AddMessageFilter方法,例如:private static MessageFilter msgFliter = new MessageFilter();在Main方法中注册消息筛选器:Application.AddMessageFilter(msgFliter);如果要取消注册,可以调用Application.RemoveMessageFilter方法 if (e.KeyCode == Keys.F1){//.................} if (e.KeyCode == Keys.Esc){//.................}//晕,刚发错了 设置一个开关变量private bool flag=true;private void method(){ while (flag) { ....... }}protected override bool ProcessDialogKey(Keys keyData){ if(keyData==Keys.Escape) { flag=false; return true; } return base.ProcessDialogKey (keyData);} 在事件中用e.keycode可实现,现在问的是在具体的一个方法中如何实现? Application.DoEvents 方法处理当前在消息队列中的所有 Windows 消息。[C#]public static void DoEvents();备注当运行 Windows 窗体时,它将创建新窗体,然后该窗体等待处理事件。该窗体在每次处理事件时,均将处理与该事件关联的所有代码。所有其他事件在队列中等待。在代码处理事件时,应用程序并不响应。例如,当将另一窗口拖到该窗口前面时,该窗口不重新绘制。如果在代码中调用 DoEvents,则您的应用程序可以处理其他事件。例如,如果您有向 ListBox 添加数据的窗体,并将 DoEvents 添加到代码中,那么当将另一窗口拖到您的窗体上时,该窗体将重新绘制。如果从代码中移除 DoEvents,那么在按钮的单击事件处理程序执行结束以前,您的窗体不会重新绘制。通常,您在循环中使用该方法来处理消息。警告 调用该方法可以在某消息引发事件时导致重新输入代码。 在循环代码中,如果不加Application.DoEvents,你的进程占据CPU,根本得不到键盘消息 在循环代码中,如果不加Application.DoEvents,你的进程占据CPU,根本得不到键盘消息 可以这样做using System;namespace ConsoleApplication2{ class Program { static void Main(string[] args) { bool a = false; ConsoleKeyInfo keyInfo; while (!a) { if (System.Console.KeyAvailable) { keyInfo = System.Console.ReadKey(true); if (keyInfo.KeyChar == 'a') a = true; } else System.Console.WriteLine("循环中"); } } }} Do me a favor... 请教,怎么在VS2005中添加使用empp.dll 短信组件? 关于连接数据库的 事务处理 C#3.0新增功能 C#插入sql server 2000记录出错 为什么输出结果不是1 C# winfrom程序如何读取文本文件中的指定内容 怎么在C#中实现类似VB里面withevents的功能 用DataReader给DropDownList赋值的问题 substring . 紧急 怎么能修改C#中继承窗体的页面? 【求助】DOTNET中如何建立基类的问题?
一 浅说: 在正式进入游戏编程前,我们先来谈谈有关屏幕管理的几个有趣的问题。计算机显示器的工作方式有两种:正文方式和图形方式,在每种显示方式下还可分为不同的显示模式。对于我们的GAME来说,她的处理对象主要是图形,所以我们需要采用后一种显示方式。 在Turbo C中initgraph是一个初始化图形系统的有用函数,它从磁盘装入一个图形驱动程序,且把系统置成图形方式。除了这种动态装入机制外,也可以将一个或几个图形驱动程序文件直接同可执行程序文件连接起来。游戏中通常采用的是640×480或320×200的分辨率。让我们来看看一个子程序: setupgraph() /* 图形初始化 */
{
int driver=VGA,mode=VGAHI;
/* VGA卡的VGAHI图形模式,640*480同显16色 */
initgraph(&driver,&mode,"");
/* 使用空字符串 "" 表示设备驱动程序在当前目录中 */
} 这个程序装入的图形驱动程序文件为EGAVGA.BGI,在例程中我们也将采用这种640×480的模式进行编程。若想选用其他分辩率,只需改变driver和mode的值便可。 下面我们来谈谈有关调色板的应用。 对于VGA显示器,图形模式12H(640×480,16色)共设置了16个颜色寄存器,所以显示器上能同时最多显示16种颜色。系统初始化时,也将颜色寄存器予以初始化,若这种默认颜色值不满足要求的话,只需修改相应颜色寄存器的数据,就可实现从64种颜色中任意选取,使显示的图形更加美观。 setpalette(调色板号,颜色号)函数可将指定的颜色填入指定的调色板中,从而改变调色板上的默认颜色。例如: setpalette (1,4); 用该函数重新设置后,以后使用1号调色板时,则显示4号颜色红色。 【注】有效的颜色依赖于当前的图形驱动程序和当前的图形模式,该函数不可用于IBM-8514图形驱动程序,应使用setrgbpalette函数。 VGA的13H模式是320×200点阵的彩色图形模式,同显256色。在图形初始化完成后,我们就可以进入富有挑战的游戏编程了。 二 制作精灵:在RPG游戏中,有很多能根据不同规则和目的而在背景场地跑来跑去的小目标:象城镇里的居民,野地上的小动物,或者再加上几株会动的小树,当然了,还有最重要的主角--游戏中的英雄或淘气鬼。这些小角色我们通常称之为“精灵”。 这些精灵要在各自的场地上迅速移动,当它们在草地上跑动时,经过的地方要遮住背景,而当它们经过后,背景的草地又要迅速恢复回来,若是遇到房屋、小河、岩石,就要停下来。那么,这些是如何实现的呢?
在程序中实现精灵的移动,我们通常采用这样的方法:在屏幕上擦除精灵当前的位置,然后在下一个位置进行重显……依次循环,你就会感到精灵跑动起来。这个原理是很简单的,但重要的是:擦掉并重显的速度必须足够快,才能有活生生的效果。 构成图形的最基本要素是点,无论背景也好,精灵也好,都是由许许多多的点组成的,所以精灵的重显问题其实也就是擦点画点的问题。在屏幕上画点有两种方法,一种是使用ROM BIOS调用,另一种是直接写显示RAM。这两种方法比较而言,前一种是相当慢的,而后一种极快。正因为如此,我们不能通过ROM BIOS去画点,而必须采用直接写显示RAM的办法画点。精灵在背景画面上保持动态最好的办法是通过XOR(“逻辑异或”)运算,借助XOR操作,动态精灵在同一显示位置上连续进行两次XOR运算,使画面出现和消失,而不会导致背景画面的任何损坏,我们来看例程:void putpoint (int x,int y,int color)
{
union REGS r;
color=color|128;
/* 参数color 和 128相逻辑或,置位最高位 */
r.h.bh=0;
r.h.ah=12;
r.h.al=color;
r.x.dx=y;
r.x.cx=x;
int86(0x10,&r,&r);
} 这个画点程序采取直接写显示RAM的办法,在画每一个点时, 先让彩色值与值128进行逻辑“或”,使彩色值的位7为1,(这就告诉了函数不是以新彩色值替换原彩色值,而是与原彩色值进行逻辑“异或”)。所以这个点总是可见的. 因为它总是与周围其它点颜色不一样,而连续两次XOR运算又很容易使周围曾经被它占据的点恢复成被占据前的颜色。 在解决了画点问题后,只要把组成精灵的点归入一个集合,使这些点同时进行运动,那么,精灵的问题也就解决了。 精灵的造型设计是丰富多彩的, 你尽可以凭你的想象创造出要在游戏中出现的形态各异的人和其它各种角色。我们可以借助Animator pro来完成角色设计,如果精灵不是很复杂的话,我们甚至可以直接“点”出她们:打开Spt或Windows的画笔,我们在“逐点修改”的方格阵上点绘出精灵的造型,反复修改至满意,给精灵定个外框,在四角任取一个点作为参照坐标(X,Y),以(X,Y)为参数组成精灵集合man(int x,int y): void man(int x,int y)
{
putpoint(x+dx1,y+dy1,color);
......
putpoint(x+dxn,y+dyn,color);
}
一般来说,精灵应比较小,以便加快重显速度,使移动看起来比较平滑。若精灵太大,移动起来就比较慢。在例程中,我们用一个9×12的框代替精灵:
void man(int x,int y,int color)
{
int i;
for (i=0;i<9;i++)
{putpoint(x+i,y,color);
putpoint(x+i,y+12,color);}
for (i=0;i<12;i++)
{putpoint(x,y+i,color);
putpoint(x+9,y+i,color);}
}
[返回页首] 三 键盘控制: 在游戏中,主角的移动一般是由上、下、左、右键或HOME、END、PGUP、PGDN四键控制的,此处还有几个问题:若键入空格、回车等,计算机如何识别?在游戏的中文菜单中如何用上下键移动选择光条?这些都是在游戏编程中会碰到的典型问题。 在Turbo C中,我们用bioskey (int cs)函数来获取键盘字符。这个函数使用BIOS中断0x14完成各种键盘操作,参数cs确定实际的操作:cs=0,返回从键盘输入的下一键码;cs=1,测试输入键是否有效;cs=2,请求当前移位键(SHIFT)的状态。 bioskey(0)获得所击键的扩展的扫描码。扩展的扫描码分两部分,即扫描码和ASCⅡ码。当按键是一般ASCⅡ码时,如回车、空格、ESC键,从扩展扫描码的低字节中可以得到它的ASCⅡ码值;当按键是特殊键时,如上、下、END、HOME键,其ASCⅡ码部分为0,所以要将组成扩展扫描码的两部分分开: ……
do
{key.i=bioskey(0);
if(key.ch[0])
{switch(tolower(key.ch[0]))
{case ‘\‘:
程序一 /* 空格键 */
case ‘r‘:
程序二 /* 回车键 */
……
}}
else
{switch(key.ch[1])
{case 72:
程序三 /* 上键 */
case 80:
程序四 /* 下键 */
case 75:
程序五 /* 左键 */
case 77:
程序六 /* 右键 */
……
}}
}while(tolower(key.ch[0]!=27); /* ESC键 */
……
key.ch[0]中为ASCⅡ码部分,key.ch[1]为扫描码部分。ESC键为ASCⅡ字符键,键值为27,所以上面程序最后一行表示当按键不是ESC时,就一直循环。而由于上、下、左、右键为特殊键,所以判别是否按了这些键用switch(key.ch[1])。
while(!boolLoop)
{
}然后处理键盘单击事件
当是ESC的时候
boolLoop=true即可
public class MessageFilter : IMessageFilter
{
int WM_KEYDOWN = 0x0100
public bool PreFilterMessage(ref Message m)
{
if (m.Msg == WM_KEYDOWN)
{
MessageBox.Show("WM_LBUTTONDOWN is: " + m.Msg);
return true;
}
return false;
}}然后使用Application.AddMessageFilter方法,例如:
private static MessageFilter msgFliter = new MessageFilter();
在Main方法中注册消息筛选器:
Application.AddMessageFilter(msgFliter);
如果要取消注册,可以调用Application.RemoveMessageFilter方法
{
//.................
}
{
//.................
}
//晕,刚发错了
{
while (flag)
{
.......
}
}protected override bool ProcessDialogKey(Keys keyData)
{
if(keyData==Keys.Escape)
{
flag=false;
return true;
}
return base.ProcessDialogKey (keyData);
}
[C#]
public static void DoEvents();
备注
当运行 Windows 窗体时,它将创建新窗体,然后该窗体等待处理事件。该窗体在每次处理事件时,均将处理与该事件关联的所有代码。所有其他事件在队列中等待。在代码处理事件时,应用程序并不响应。例如,当将另一窗口拖到该窗口前面时,该窗口不重新绘制。如果在代码中调用 DoEvents,则您的应用程序可以处理其他事件。例如,如果您有向 ListBox 添加数据的窗体,并将 DoEvents 添加到代码中,那么当将另一窗口拖到您的窗体上时,该窗体将重新绘制。如果从代码中移除 DoEvents,那么在按钮的单击事件处理程序执行结束以前,您的窗体不会重新绘制。通常,您在循环中使用该方法来处理消息。警告 调用该方法可以在某消息引发事件时导致重新输入代码。
using System;namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
bool a = false;
ConsoleKeyInfo keyInfo;
while (!a)
{
if (System.Console.KeyAvailable)
{
keyInfo = System.Console.ReadKey(true);
if (keyInfo.KeyChar == 'a')
a = true;
}
else
System.Console.WriteLine("循环中");
} }
}
}