常数
true等同于1.
false等同于 0.
pi等同于 3.1415...
实数函数
random(x)返回一个随机的实数,范围从 0 到 x 。数值总小于 x 。
choose(val1,val2,val3,...)随机返回其中一个参数。最多可以有16个参数。
abs(x)返回 x 的绝对值。
sign(x)返回 x 的符号(-1,0,或1)。
round(x)返回与 x 最接近的整数。
floor(x)返回比 x 小的最大整数。
ceil(x)返回比 x 大的最小整数。
frac(x)返回 x 的小数点以后的部分。
sqrt(x)返回 x 的开方。 x 不能是负数。
sqr(x)返回 x 的平方。
power(x,n)返回 x 的 n 次方。
exp(x)返回 x 的冥方指数 e 。
ln(x)返回 x 的自然对数。
log2(x)返回 x 的2的对数。
log10(x)返回 x 的10的对数。
logn(n,x)返回 x 的 n 的对数。
sin(x)返回 x 的正弦(x 单位为弧度)。
cos(x)返回 x 的余弦(x 单位为弧度)。
tan(x)返回 x 的正切(x 单位为弧度)。
arcsin(x)返回 x 的反正弦。
arccos(x)返回 x 的反余弦。
arctan(x)返回 x 的反正切。
arctan2(y,x)计算 arctan( y / x ) ,然后返回结果在正确象限内的角度值。
degtorad(x)转换角度到弧度。
radtodeg(x)转换弧度到角度。
min(val1,val2,val3,...)返回参数中的最小值。最高支持16个参数。必须全部是实数或全部是字符串。
max(val1,val2,val3,...)返回参数中的最大值。最高支持16个参数。必须全部是实数或全部是字符串。
mean(val1,val2,val3,...)返回所有参数的平均值。最高支持16个参数。必须全部是实数数值。
median(val1,val2,val3,...)返回参数的中间数(如果参数数目为偶数,则两个中间数中最小的那个作为返回值)。最高支持16个参数。必须全部是实数数值
point_distance(x1,y1,x2,y2)返回位置1(x1,y1)到位置2(x2,y2)的距离。
point_direction(x1,y1,x2,y2)返回从位置1(x1,y1)到位置2(x2,y2)的方向角度。lengthdir_x(len,dir)返回指定长度及方向的矢量线在 x 轴上的投影长度。
lengthdir_y(len,dir)返回指定长度及方向的矢量线在 y 轴上的投影长度。
is_real(x)返回 x 是否为真实数值(否则就是字符串)。
is_string(x)返回 x 是否是一个字符串(否则就是一个真实数值)。
字符串处理函数
chr(val)返回字符串中包含参数指定的 ASCII码字符的字符串。
ord(str)返回字符串中第一个字符的 ASCII 码。
real(str)将字符串转换为真实数值。字符串可包含负号,小数点甚至是指数部分。string(val)将真实数值转换为标准格式的字符串(整数时没有小数点位置,否则在小数点后留两位)。
string_format(val,tot,dec)将 val 以你自己的格式转换为字符串:tot 指定总的数字位置,dec 指定小数点后有几位数字。
string_length(str)返回字符串中字符的个数。
string_pos(substr,str)返回字符串 substr 在字符串 str 中的位置(0 代表完全不符)。
string_copy(str,index,count)返回字符串 str 的一部分,从 index 指定的位置开始,长度为 count 。
string_char_at(str,index)返回字符串 str 中索引为 index 的字符。
string_delete(str,index,count)返回删除了部分内容的字符串 str,从 index 开始,长度为 count 。
string_insert(substr,str,index)返回在位置 index 处添加子串 substr 后的字符串str。
string_replace(str,substr,newstr)返回字符串 str 的一份拷贝,为字符串中子串substr 第一次出现的地方开始被字符串 newstr 替换后的内容。
string_replace_all(str,substr,newstr)返回字符串 str 的一份拷贝,为字符串中子串 substr 所有出现的地方开始被字符串 newstr 替换后的内容。
string_count(substr,str)返回子串 substr 在字符串 str中出现的次数。
string_lower(str)返回小写格式的字符串 str。
string_upper(str)返回大写格式的字符串 str。
string_repeat(str,count)返回由 count 个字符串 str 组成的新字符串 str。
string_letters(str)返回只包含字母的字符串 str。
string_digits(str)返回只包含数字的字符串 str。
string_lettersdigits(str)返回包含字母和数字的字符串 str。
以下为处理系统粘贴板内容的相关函数。
clipboard_has_text()返回粘贴板中是否存在任何文本。
clipboard_get_text()返回当前粘贴板内文本内容。
clipboard_set_text(str)将字符串 str 送入粘贴板。
日期及时间处理
在Game Maker中有许多函数是专门处理日期和时间的。一个日期-时间格式是一组实数。整数部分代表日期,最早到12/30/1899。小数点后的部分代表一天之中的24小时。现有有以下函数 :
date_current_datetime()返回当前系统日期-时间。
date_current_date()返回当前系统日期(不包括时间)。
date_current_time()返回当前系统时间(不包括日期)。
date_create_datetime(year,month,day,hour,minute,second)建立一个指定的日期-时间数据。
date_create_date(year,month,day)建立一个指定的日期数据。
date_create_time(hour,minute,second)建立一个指定的时间数据。
date_valid_datetime(year,month,day,hour,minute,second)返回给定的日期-时间是否正确。
date_valid_date(year,month,day)返回给定的日期是否正确。
date_valid_time(hour,minute,second)返回给定的时间是否正确。
date_inc_year(date,amount)返回指定日期后 amount 年的新日期。amount 必须为整数date_inc_month(date,amount)返回指定日期后 amount 月的新日期。amount 必须为整数。
date_inc_week(date,amount)返回指定日期后 amount 星期的新日期。amount 必须为整数
date_inc_day(date,amount)返回指定日期后 amount 天的新日期。amount 必须为整数。date_inc_hour(date,amount)返回指定日期后 amount 小时的新日期。amount 必须为整数。
date_inc_minute(date,amount)返回指定日期后 amount 分钟的新日期。 amount 必须为整数。
date_inc_second(date,amount)返回指定日期后 amount 秒的新日期。amount 必须为整数。
date_get_year(date)返回 date 对应的年份。
date_get_month(date)返回 date 对应的月份。
date_get_week(date)返回 date 对应的星期。
date_get_day(date)返回 date 对应的天数。
date_get_hour(date)返回 date 对应的小时。
date_get_minute(date)返回 date 对应的分钟。
date_get_second(date)返回 date 对应的秒。
date_get_weekday(date)返回 date 对应一星期的哪一天。
date_get_day_of_year(date)返回 date 对应一年中的哪一天。
date_get_hour_of_year(date)返回 date 对应一年中的哪一小时。
date_get_minute_of_year(date)返回 date 对应一年中的哪一分钟。
date_get_second_of_year(date)返回 date 对应一年中的哪一秒。
date_year_span(date1,date2)返回两个日期 date1 和 date2 之间相隔多少年。此函数只报告年数片断。
date_month_span(date1,date2)返回两个日期 date1 和 date2 之间相隔多少月。此函数只报告月份片断。
date_week_span(date1,date2)返回两个日期 date1 和 date2 之间相隔多少星期。此函数只报告星期片断。
date_day_span(date1,date2)返回两个日期 date1 和 date2 之间相隔多少天。此函数只报告天数片断。
date_hour_span(date1,date2)返回两个日期 date1 和 date2 之间相隔多少小时。此函数只报告小时片断。
date_minute_span(date1,date2)返回两个日期 date1 和 date2 之间相隔多少分钟。此函数只报告分钟片断。
date_second_span(date1,date2)返回两个日期 date1 和 date2 之间相隔多少秒。此函数只报告秒数片断。
date_compare_datetime(date1,date2)比较两个日期时间的大小,返回-1,0,1,分别代表前者小于,等于,大于后者。
date_compare_date(date1,date2)比较两个日期的大小,返回-1,0,1,分别代表前者小于,等于,大于后者。
date_compare_time(date1,date2)比较两个时间的大小,返回-1,0,1,分别代表前者小于,等于,大于后者。
date_date_of(date)返回指定日期-时间数据的日期部分,时间部分设定成0。
date_time_of(date)返回指定日期-时间数据的时间部分,日期部分设定成0。
date_datetime_string(date)按照给定的数据,返回系统默认的字符串格式日期-时间。date_date_string(date)按照给定的数据,返回系统默认的字符串格式日期。
date_time_string(date)按照给定的数据,返回系统默认的字符串格式时间。
date_days_in_month(date)返回指定日期-时间所在月份的天数。
date_days_in_year(date)返回指定日期-时间所在年份的天数。
date_leap_year(date)返回指定日期-时间所在年份是否为闰年。
date_is_today(date)返回指定日期-时间是否为今天。
移动
很明显,游戏的一个重要方面就是对象实例的四处移动。每个实例拥有两个内建的变量 x 和y 用来指出实例的位置。(更精确的说,它们显示的位置是精灵原点摆放的位置。)( 0 ,0 )的位置在房间的最左上角。你可以通过改变实例 x 和 y 变量的值来改变实例的位置。你如果想要对象进行复杂运动,这是个可行的方法。把有关的代码放在对象的并行( step )事件里。
如果对象以固定方向及恒速移动,实现起来就很简单。每个对象实例都有一个水平速度( hspeed )和一个垂直速度( vspeed )。两个速度都是以像素每步( pixels per step )为单位。一个正的水平速度就是向右的运动,负的水平速度意味着向左的运动。正的垂直速度是向下,负的垂直速度是向上。所以你必须给这些变量初始化(比如在创建事件里)使对象实例有一个恒速。
自定义运动的方法和之前不同,使用了方向( direction )( 0-359 度),和速度( speed )(必须是非负数)。你可以设定并读取这些变量来自定义一个任意运动。(内部处理实际上是把值转换成 hspeed 和 vspeed 。)当然还有阻力( friction )和重力( gravity )和重力方向( gravity dirction )供你使用。最后要说的是函数 motion_add(dir,speed) 用来给现有对象增加速度。
完整来说,每个实例由以下变量和函数来处理它们的位置和运动 :
x对象的 x 坐标 .
y对象的 y 坐标 .
xprevious对象以前的 x 坐标 .
yprevious对象以前的 y 坐标 .
xstart对象在房间里的初始 x 坐标 .
ystart对象在房间里的初始 y 坐标 .
hspeed速度的水平部分,即水平速度 .
vspeed速度的垂直部分,即垂直速度 .
direction对象当前方向( 0-360 度,逆时针, 0 = 朝右) .
speed对象当前速度(像素每步) .
friction当前阻力(像素每步) .
gravity当前重力(像素每步) .
gravity_direction重力方向( 270 朝下) .
motion_set(dir,speed)以参数(方向,速度)设定运动 .
motion_add(dir,speed)以参数(方向,速度)对当前运动做改变 .
这儿有大量可利用的函数帮助你定义你的运动 :
place_free(x,y)返回实例在( x , y )位置是否与固体实例碰撞的值。这个函数用来在实际移动到新位置前检测。
place_empty(x,y)返回实例在( x , y )位置是否与任何东西碰撞的值。所以这个函数还把非固体实例加入计算范围。
place_meeting(x,y,obj)返回实例在( x , y )位置是否与对象( obj )碰撞的值。与 obj 对象的实例遇到时,函数返回真( true )。也可以用实例名做 obj 参数,实例名都意味着是对象的一个实例。
place_snapped(hsnap,vsnap)返回实例是否与网格对齐的值。 //hsnap 水平网格, vsnap 垂直网格
move_random(hsnap,vsnap)移动实例到一个随机空闲并且是网格的位置,和其对应的动作效果一样。
move_snap(hsnap,vsnap)将实例对齐网格,和其对应的动作效果一样。
move_wrap(hor,vert,margin)离开房间到另一边时卷动实例。参数 hor 为是否水平卷动( 1 或 0 )参数 vert 为是否垂直卷动( 1 或 0 )。参数 margin 为卷动前离原点多远时实例必须离开房间。等于围绕房间的一圈留白。这个函数在离开事件( outside event )中使用非常具有代表性。
move_towards_point(x,y,sp)以速度( sp )朝( x , y )位置移动实例。
move_bounce_solid(adv)遇到固体实例反弹,和其对应的动作效果一样。参数 adv ( 1 或0 )为是否使用高级反弹,高级反弹将倾斜面加入计算范围。
move_bounce_all(adv)遇到所有实例反弹,不单单对固体反弹。
move_contact_solid(dir,maxdist)朝某方向移动实例直到接触固体对象。如果在当前位置没有碰撞,实例在碰撞发生前将不停的移动。如果当前位置已经发生碰撞了,实例就不再移动。你可以指定移动的最大速(距离未定时可以使用负数) //dir 设定方向, maxdist 设定速度
move_contact_all(dir,maxdist)和上一个函数类似,不过这次接触到任何对象时都会停止,不单是固体对象。
move_outside_solid(dir,maxdist)朝某方向移动实例直到离开固体对象。如果在当前位
置没有碰撞,实例不移动。你可以指定移动的最大速(距离未定时可以使用负数) // 用于分开重叠的实例
move_outside_all(dir,maxdist)和上一个函数类似,不过这次是离开任何对象时都会停止,不单是固体对象。
distance_to_point(x,y)返回当前实例的碰撞盒离( x , y )的距离。
distance_to_object(obj)返回实例离最近的对象( obj )的距离。
position_empty(x,y)返回在( x , y )位置是否有任何实例的布尔值。
position_meeting(x,y,obj)返回( x , y )位置是否有实例 obj 的布尔值。参数 obj 可以是对象,实例名,或是其他关键字等等
路径
在 GameMaker 里你可以定义路径并且命令实例跟随路径。尽管你可以使用动作库,变量和函数可以使你更灵活的运用 :
path_start(path,speed,endaction,absolute)为当前实例开始一段路径。参数 path 是你想开始的路径名。参数 speed 是跟随路径的速度。负的 speed 意味着实例沿着路径往回移动。参数 edaction 是设定当实例到达路径的终点时发生的事件。有以下几个值可供使用 : 0: 停止路径
1: 从开始点继续(如果路径没有闭合,直接跳到开始点)
2: 从当前点继续
3: 反转路径,改变速度的符号
参数 absolute 应该是 true 或是 false ( 1 或 0 )。设为 true 时和路径是绝对的关系( absolute )。设为 false 时路径和实例的当前位置是相关的关系( relative )为了更精确地设定,如果 speed 是正的,当前位置就是路径的开始点,路径沿着当前位置而行。 speed 为负值时,当前位置就是路径的终点,路径沿着当前位置往后移动。
path_end()当前实例结束跟随路径。
path_index*当前实例跟随路径的索引。你不可以直接改变它,必须使用上面的函数。
path_position当前路径的位置。值为 0 时在路径的开始位置。值为 1 时在路径的结束位置。值必须在 0 到 1 之间。
path_positionprevious当前路径的前一个位置。可以使用碰撞事件( collision events )里的例子来设置在路径上位置使它回到前一个位置。
path_speed设置跟随路径的速度(像素每步)。负值时向后移动。
path_orientation路径处理时的方位(逆时针)设定。值 0 时为正常方向。
path_scale缩放路径。增加值使路径变大。 1 是默认值。
path_endaction路径结束时必须执行的行为。可以使用最上面的函数介绍的值。
运动设计
运动设计帮助你在避免与另一实例(比如:墙)碰撞的情况下将某实例从给定位置移动到另一位置。运动设计是一个有难度的项目。几乎不可能给出一些能够在任何情况下正常运作的普通函数。同时,计算碰撞运动非常耗费系统资源。所以使用这些函数时必须非常小心仔细。当你使用以下任一函数时请将这些建议记到心里。
Game Maker 提供了一些不同形式的运动计划。最简单的形式允许一个实例朝某特定目标方向步进,可能的话尽量走直线但是如果有要求的话可以取不同的方向。这些函数应当在实例的并行事件 (step event) 中使用。对应的运动计划动作库也是可用的 :
mp_linear_step(x,y,stepsize,checkall)这个函数作用为让实例朝指定位置( x , y )直线步进。每一步的大小由参数 stepsize 设置。如果实例已经到位,实例不再移动。如果参数 checkall 为 true ( 1 ),实例遇到任意对象的实例都不会停止。如果为 false ( 0 ),实例碰撞到另一固体实例时就会停止。注意这个函数遇到障碍时不会试着绕路。它只会简单的停止。函数返回值为是否到达目标位置。
mp_linear_step_object(x,y,stepsize,obj)除了参数 obj 实例为障碍,其他效果同上。参数 obj 可以是对象或是实例名。
mp_potential_step(x,y,stepsize,checkall)和先前的函数类似,这个函数也是让实例朝指定位置步进。不同处是这个函数会试着绕过障碍物。当实例快撞上某一固体实例(或任何实例, checkall 为 true 时)时,会改变运动方向来避开实例并且绕开它。这个方法不能保证有效,但是在大部分简单应用中会非常有效的让实例朝目标移动。函数返回值为是否到达目标位置。
mp_potential_step_object(x,y,stepsize,obj)除了参数 obj 实例为障碍物,其他效果同上。参数 obj 可以是对象或是实例名。
mp_potential_settings(maxrot,rotstep,ahead,onspot)先前的函数利用的一些参数可
以使用这个函数改变。以下方法都有全局性。首先试着朝目标直线移动。可以使用参数 ahead (默认值为 3 )设置前面有多少步。减少这个值意味着实例将在延后开始改变方向。增加这个值意味着提前开始改变方向。如果检测到将要碰撞,实例会开始朝向最佳方向,偏右或是偏左。根据参数 rotstep (默认值为 10 )的大小决定在多少步中改变朝向。减少 rotstep 的值会使得实例有更多移动的可能性但速度也会更慢。参数 maxrot 解释起来有一点难度。实例有一个当前方向。参数 maxrot (默认值为 30 )为在一步里面允许改变当前方向的最大值。所以说即使实例可以直线移动到目标,只要不超过改变方向的最大值,它就会这样执行。如果你把 maxrot 设得很大,实例就可以在每一步都改变很多方向。这样可以使它更简单的寻找一段短路径,但同时整个路径会变得非常丑陋(路线歪七歪八的…)。如果把值设得很小,路线就会很平滑但同时它可能会绕很远的路费很多时间(有时候甚至找不到到目标的路)。没有创建步时,实例的行为会建立在参数 onspot 上。如果 onspot 值为 true (或1 ,为默认值),实例会根据 maxrot 的大小在自己的位置上旋转。如果值为 false (或 0 )实例就不再移动。如果实例为车辆时,设为 false 比较好,但同时会减少寻路成功的机会。
请注意 potential 函数只能使用局部信息。所以它只能在局部信息足够确定正确的运动方向时寻路成功。举例来说,走出迷宫就找不到路了(大部分情况下)。
第二种类型函数为实例计算路径是否碰撞。一旦路径经过计算,你可以分配给实例让它朝目标移动。计算路径会花一些时间但接下来完成路径会非常快。当然只会在其间情况没有改变时才有效。举例来说,如果障碍物改变了,你可能需要重新计算路径。再次注意,这些函数可能不起作用
开始的两个函数使用了线形运动,潜在域方法照例是用在 step 函数里的。
mp_linear_path(path,xg,yg,stepsize,checkall)这个函数使用指定步大小计算实例从
当前位置到( xg , yg )的直线路径。使用步的方法和函数 mp_linear_step() 一样。指
定的路径必须已经存在并且会被新路径覆盖。(参考后面的章节怎样建立和销毁路径。)函数返回值为是否找到路径。函数在寻路失败前不会停止,开始和目标之间不存在直线路径为失败的情况。如果失败,路径仍然会被创建直到运行到实例到达封闭的位置。
mp_linear_path_object(path,xg,yg,stepsize,obj)除了参数 obj 实例为障碍物,其他效果同上。参数 obj 可以是对象或是实例名。
mp_potential_path(path,xg,yg,stepsize,factor,checkall)这个函数计算指定步大小
让实例绕过障碍从当前位置和方向到( xg , yg )的路线。函数使用了潜在域步骤,类似于函数 mp_potential_step() 当然参数可以用函数 mp_potential_settings() 来设置。指定的路径必须已经存在并且会被新路径覆盖。(参考后面的章节怎样建立和销毁路径。)函数返回值为是否找到路径。为了避免函数不停的计算下去,你需要给出一个大于 1 的参数factor 。如果找不到比开始和目标之间的距离更短的路径,函数就会停止并报错。参数factor 为 4 是正常够用的值了,但是如果想绕远点的话可能需要加大数值。如果失败,路径仍然会被创建并且在目标方向运行,但是到达不了目标
mp_potential_path_object(path,xg,yg,stepsize,factor,obj)除了参数 obj 实例为障碍物,其他效果同上。参数 obj 可以是对象或是实例名
另一些函数使用了更复杂的机构使用了一种基于网格的方法(有时候称它为 A* 算法)。寻路更容易成功(尽管还是有失败的可能)并且路线更短,缺点是需要很多操作。以下都是全局概念。首先我们在房间内放入一网格(相应的部分)。你可以选择精致的网格(较慢)或是粗糙的网格。接下来,我们要探测所有的相关对象与网格单元交叠的地方(不管是碰撞盒或是精确检测)并且对这些单元作禁止的标记。即使只是和障碍物部分交叠,单元会全部被标记为禁止通行。最后我们指定一个开始和一个目标位置(必须放在空白单元上),函数就会计算他们之间的最短路径(实际上是最接近最短路径)。路径会在中间空白的单元上行进。所以如果单元足够大到能在中心完全放下实例,函数就会成功。接下来你可以把这个路径给一个实例。
基于网格的方法十分强大(在很多专业游戏中使用)但是要求你仔细的考虑如何使用。你必须决定哪个区域以及单元大小比较合适。同样必须决定哪个对象必须避开并且决定精确检测是否必要。所有这些参数都强烈影响到寻路的效果。
特别需要注意,单元的大小十分重要。要记住单元必须要足够的大,大到能将移动的对象完全放入单元的中心。(注意对象原点的位置。同样要了解如果对象的原点不在它的中心,你就可以移动路径)另一方面,单元越小路径越容易存在。如果单元和障碍物之间的开口太大路径会闭合,因为所有的单元都和一个障碍物交叠。
基于网格方法的实际函数如下 :
mp_grid_create(left,top,hcells,vcells,cellwidth,cellheight)这个函数建立网格。返回一个索引用于其它函数调用。你可以在同一瞬间创建并维持多重网格结构。参数 left 和 top 指定网格左上角的位置。参数 hcells 和 vcells 设置水平和垂直单元的数量。参数 cellwidth 和 cellheight 是单元的大小。
mp_grid_destroy(id)销毁指定网格结构并释放空间。如果不再用到结构时记得调用这个函数。
mp_grid_clear_all(id)将网格中的所有单元都标记为空。
mp_grid_clear_cell(id,h,v)清除指定单元。单元 0 , 0 在最左上角。
mp_grid_clear_rectangle(id,left,top,right,bottom)清除和指定矩形交叉的所有的单元(在相应的房间里)。
mp_grid_add_cell(id,h,v)标记指定的单元为禁止通行。单元 0 , 0 在最左上角。
mp_grid_add_rectangle(id,left,top,right,bottom)标记和指定矩形交叉的所有的单元为禁止通行。
mp_grid_add_instances(id,obj,prec)标记所有与指定对象的实例交叉的单元为禁止通行。你可以通过参数 obj ,实例的 id 名来使用一个单独的实例。同样也可以使用关键字all 表示所以对象的所有实例。参数 prec 为是否使用精确检测(只有当实例使用的精灵打开精确检测时才有效)。
mp_grid_path(id,path,xstart,ystart,xgoal,ygoal,allowdiag)计算一条通过网格的路径。参数 path 必须指定一条已经存在的路径用来被电脑路径替代。参数 xstart 和 ystart 为路径的开始点, xgoal 和 ygoal 为目标点。参数 allowdiag 为是否允许使用斜角移动替代水平和垂直移动。函数返回值为是否寻路成功。(注意路径不受当前实例影响;是一条穿越网格的路径,不是某特殊实例的路径)
mp_grid_draw(id)这个函数将空的单元绘成绿色,禁止通行的单元绘成红色。这个函数运行起来很慢这是用来做 debug 工具。
碰撞检测
计划运动或是要决定具体行动时,察看实例是否与其它对象在确定的地点碰撞是一件十分重要的事。为此需要用到下面的程序。所有的这些函数有三个共有参数:参数 obj 是某对象,关键字all ,或是某实例的 id 名。参数 prec 是是否启用精确检测或是仅仅使用实例的碰撞盒。精确检测只有当实例的精灵设定了精确碰撞检测时才有效。参数 notme 可以设为true ( 1 ),使调用的实例不会被检测。所有的这些函数返回值为被碰撞实例的 id 名,如果没有碰撞就返回一个负值。
collision_point(x,y,obj,prec,notme)这个函数测试在( x , y )位置是否和实体对象 obj 有碰撞。
collision_rectangle(x1,y1,x2,y2,obj,prec,notme)这个函数测试指定对角的矩形(已填充)是否和实体对象 obj 有碰撞。举例来说,你可以使用这个函数测试某个区域里是否没有障碍物。
collision_circle(xc,yc,radius,obj,prec,notme)这个函数测试指定圆心( xc , yc )的圆(已填充)是否和实体对象 obj 有碰撞。举例来说,你可以使用这个函数测试某对象是否靠近某特点位置。
collision_ellipse(x1,y1,x2,y2,obj,prec,notme)这个函数测试指定对角的椭圆(已填充)是否和实体对象 obj 有碰撞。
collision_line(x1,y1,x2,y2,obj,prec,notme)这个函数测试线段( x1 , y1 )到
(x2,y2) 是否和实体对象 obj 有碰撞。这是个强大的函数。你可以这样使用这个函数,通过检测线段是否与他们之间的墙相交来测试某实例是否可以看到另一实例。
实例
游戏中,最基本的单位就是各种不同对象的实例。游戏进行时可以替换许多实例的外貌。同样你也可以通过创建新实例并摧毁实例达到替换的效果。除了先前讨论的运动相关变量和下面将要讨论的绘制相关变量,每个实例都有如下一些变量 :
object_index*对象的索引。这个变量不可以改变。
id*实例的统一标识符( >= 100000 )。(注意,定义房间时,鼠标指定的实例 id 名总会显示出来。)
mask_index遮照精灵的索引,用来碰撞检测。值为 -1 时效果和 sprite_index 一样。solid实例是否为固体。可以在游戏进行中改变。
persistent实例是否持久显示并且移动到另一房间时再现。某些时候经常需要把持久的效果关掉。(举例来说,要回到第一个房间的时候)
处理实例时有个问题。分辨单个的实例不是很容易。他们没有名字。只有某特点对象的某个实例时你可以使用对象名,否则需要实例的 id 名。实例有一个统一的标识符。你可以在with 语句中当做对象标识符使用。幸运的是有大量的变量及程序帮助你定位实例 id 名。
instance_count*房间中现存实例的数量。
instance_id[0..n-1]*特定实例的 id 名。这里的 n 为实例的编号。
注意,实例对实例 id 名的分配每一步都改变,所以你不能使用上一步的值。我来举个例子。设想你游戏中的每个单位都有特别有力量,你想找到最强壮的那个,可以使用以下代码 :
{
maxid = -1;
maxpower = 0;
for (i=0; i { iii = instance_id[i]; if (iii.object_index == unit) { if (iii.power > maxpower) {maxid = iii; maxpower = iii.power;} } } } 做完循环, maxid 就是那个最强的单位了。(循环时不要销毁实例,因为他们会自动从数组中移除) instance_find(obj,n)返回值为参数 obj 的第 (n+1) 个实例 id 名。参数 obj 可以是某对象或是关键字all 。如果不存在,返回特殊对象 noone 。注意,实例对实例 id 名的分配每一步都改变,所以你不能使用上一步的值。 instance_exists(obj)返回值为 obj 的实例是否存在。参数 obj 可以是某对象,实例 id 名或是关键字all 。 instance_number(obj)返回 obj 实例的编号。参数 obj 可以是某对象或是关键字all 。instance_position(x,y,obj)返回值为 obj 在( x , y )位置上实例的 id 名。同一位置有多个实例时,返回第一个实例。参数 obj 可以是某对象或是关键字all 。如果不存在,返回特殊对象 noone 。 instance_nearest(x,y,obj)返回值为最接近( x , y )位置的 obj 的实例 id 名。参 数 obj 可以是某对象或是关键字all 。 instance_furthest(x,y,obj)返回值为离( x , y )位置最远的 obj 的实例 id 名。参数 obj 可以是某对象或是关键字all 。 instance_place(x,y,obj)返回值为遇到当前( x , y )位置上实例的 obj 的实例 id 名。参数 obj 可以是某对象或是关键字all 。如果不存在,返回特殊对象 noone 。 下面的函数用于创建销毁实例。 instance_create(x,y,obj)在( x , y )位置创建 obj 的实例。函数返回新实例的 id 名。 instance_copy(performevent)创建当前实例的复制品。参数 performevent 为复制品的创建事件( creation event )是否必须执行。函数返回新复制品的 id 名。 instance_destroy()销毁当前实例。 instance_change(obj,perf)改变 obj 的实例。参数 perf 为是否执行销毁和创建事件( destroy and creation events )。 position_destroy(x,y)销毁所有包含( x , y )位置精灵的实例。 position_change(x,y,obj,perf)在( x , y )位置改变所有 obj 的实例。参数 perf 为是否执行销毁和创建事件( destroy and creation events )。 解散实例 当你创建大房间时,比如在平台游戏中,在一个小视野里,很多实例在视野的外面。这些实例仍然是激活状态并且会执行他们的事件。同样,计算碰撞检测时这些实例也会加入计算。这样会浪费大量的时间,通常也没有必要。(举例来说,视野外的实例移动一点都不重要。)为了解决这个问题,Game Maker 内含了一些函数来解散和激活实例。使用前你必须清楚地明白他们是怎样运作的。 解散实例时,它们会被判断为从游戏中移除。他们不再可见也不会执行任何事件。所以对大部分动作库和函数来说,它们不再存在。这样节省了大量的时间,但使用时要非常小心。举例来说,当你删除了某特别类型的所有实例,已解散实例没有被删除(因为它们不存在)。所以不要认为一串角色捡到的钥匙可以用来打开一个已解散的门。 最容易犯的错误是解除了一个激活的实例。为了避免下面的一些程序,要求你强调被调用的实例不会解除它本身 这儿有些可用的程序 : instance_deactivate_all(notme)解除房间内的所有实例。如果参数 notme 为 true ( 1 )正在调用的实例不会解除(通常是你想要的效果)。 instance_deactivate_object(obj)解除房间内的所有 obj 的实例。你也可以参数 obj 改为all 来使所有的实例解除或者指定实例 id 名解除一单个的实例。 instance_deactivate_region(left,top,width,height,inside,notme)解除指定区域内 的所有实例(那些碰撞盒部分在区域内的也算)。如果参数 inside 为 false ( 0 ),完全露在区域外的实例会被解除。如果参数 notme 为 true ( 1 )正在调用的实例不会解除(通常是你想要的效果)。 instance_activate_all()激活房间内的所有实例。 instance_activate_object(obj)激活房间内的所有 obj 的实例。你也可以参数 obj 改为all 来使所有的实例激活或者指定实例 id 名激活一单个的实例。 instance_activate_region(left,top,width,height,inside)激活指定区域内的所有实例。如果参数 inside 为 false ( 0 ),完全露在区域外的实例会被激活。 举例来说,视野外的实例都解除,视野内的实例全激活,你可以将下面的代码放到移动角色的并行事件中( step event ) r: { instance_activate_all(); instance_deactivate_region(view_xview[0],view_yview[0], view_wview[0],view_hview[0],false,true); } 特别注意,你可能需要让区域比视野稍微大一些。 定时 一个好的游戏要求精确的时间控制。幸运的是Game Maker 有许多时间方面的函数。使事物恒速( rate )发生。这个速度( rate )在定义房间的时候设置。你可以用全局变量room_speed 来改变它。举例来说,通过每一步对 room_speed 增加一个很小的量(比如0.001 ),你可以缓慢增加游戏的速度,使它难度更高。如果你的电脑很慢,游戏速度可能不能达到。可以使用变量 fps 来不断监测实际每秒的帧数。最后,一些高级定时使用时可以用变量 current_time ,电脑开始时的毫秒数。这儿是所有可用的变量(只有第一个可以改变) : room_speed当前房间的游戏速度(单位为步每秒)。 fps*实际每秒的帧数。 current_time*系统开始时经过的毫秒数。 current_year*当前年。 current_month*当前月。 current_day*当前日。 current_weekday*当前星期几( 1 为星期日,…,7 为星期六)。 current_hour*当前小时。 current_minute*当前分钟。 current_second*当前秒。 有时候你需要将游戏停止一小会儿。使用 sleep 函数。 sleep(numb)睡眠( numb )毫秒。 如你所知,每个实例有 12 个不同的定时器可以设置。使用下面的变量改变(或获取)不同定时器的值 : alarm[0..11]指定定时器的值。(注意只有在对象的定时器事件包含动作时,定时器才会更新!) 复杂的时间问题可以使用时间轴资源。每个实例都有一个时间轴资源关联。下面的函数是处理时间轴的 : timeline_index实例关联时间轴的索引。可以设定为一个特定的时间线然后使用它。设为-1 时停止使用时间轴。 timeline_position当前时间轴位置。可以改变它的值来跳过部分内容或是重复部分内容。timeline_speed一般来说,时间轴上的位置每步都增加1。可以改变为不同的值。你可以用一个实数比如0.5。如果值比1大,同样的时间步内会发生更多的事件。他们会根据正确的命令允许,所以不会跳过任何动作。 房间 游戏是在房间中运行的。每个房间都有一个索引名。当前房间保存在变量 room 中。你不要将房间想象成连续的。所以不要增加或减少 room 变量的值。而应该使用下面的函数和变量。你可以使用下面一行典型的代码 : { if (room != room_last) { room_goto_next(); } else { game_end(); } } 下面变量和函数用来处理房间 . room当前房间的索引。不能通过改变就进入一个不同的房间,要用下面的函数。 room_first*游戏中第一个房间的索引。 room_last*游戏中最后一个房间的索引。 room_goto(numb)进入索引为 numb 的房间。 room_goto_previous()进入先前的房间。 room_goto_next()进入下一个房间。 room_restart()当前房间重新开始。 room_previous(numb)返回先前房间的索引 numb ( -1 为空),但是不能去那里。 room_next(numb)返回下一个房间的索引 numb 。 game_end()结束游戏。 game_restart()游戏重新开始。 调用下面的函数来改变房间或结束或重新开始游戏时,请认识到房间的改变不会立刻实现。当前的动作全部执行完才开始改变。所以剩下的脚本仍然会执行,同样的应用可能调用脚本。 房间有这些附加属性 : room_width*房间的宽度。(单位为像素) room_height*房间的高度。(单位为像素) room_caption显示在窗口的房间名。 room_persistent当前房间是否持久显示。 很多游戏要求玩家保存游戏以及读取游戏。 Game Maker 中 F5 保存游戏 F6 读取游戏。也可以用一行代码保存和读取游戏(注意,读取只在当前步的最后发生)。 game_save(string)保存游戏为文件名 string 。 game_load(string)读取文件名为 string 的游戏。 请认识到,只是最基本的游戏数据被保存。如果播放一段音乐,在音乐的精确位置是不能保存的。同样改变过的资源也不能保存。另外未保存的是数据结构内容,粒子,还有多人设置。 得分 很多游戏的另一个重要方面是得分,生命值,以及生命。Game Maker 保留得分为全局变量score ,生命为全局变量 lives 。生命值和生命同样如此。所有的实例如果生命大于 0 ,并且要小于等于 0 ,没有生命事件( no-more-lives event )就会执行。如果你不想在标题上显示得分和生命,设置 show_score 为 false 。同样也可以改变标题。更复杂的游戏最好自己显示得分。 score当前得分。 lives生命数量。 health当前生命值( 0-100 )。 show_score是否在窗口标题中显示得分。 show_lives是否在窗口标题中显示生命数量。 show_health是否在窗口标题中显示生命值。 caption_score用于得分的标题。 caption_lives用于生命数量的标题。 caption_health用于生命值得标题。 产生事件 如你所知,Game Maker 是完全事件驱动的。所有的动作都在事件中发生。有大量不同的事件。创建和销毁事件发生在实例创建或是销毁时。每一步中,系统首先运行闹钟事件。接下来运行键盘和鼠标事件,然后运行并行事件。再然后是碰撞事件,实例碰撞后设置到新的位置。最后绘制事件用来绘制实例(注意有多重视野时绘制事件在每步中调用多次)。你也可以通过代码对当前实例使用事件。下面是可用的函数 : event_perform(type,numb)当前实例执行指定类型事件的 numb 号码。有以下事件类型可以指定 : ev_create创建事件 ev_destroy销毁事件 ev_step并行事件 ev_alarm闹钟事件 ev_keyboard键盘事件 ev_mouse鼠标事件 ev_collision碰撞事件 ev_other其他事件 ev_draw绘制事件 ev_keypress键盘按下事件 ev_keyrelease键盘松开事件 有多个事件类型时,参数 numb 可以用来指定精确的事件。比如闹钟事件 numb 可以设范围0 到 11 。键盘事件可以使用参数 keycode 。鼠标事件可以使用下面的常量 : ev_left_button 左键 ev_right_button 右键 ev_middle_button 中键 ev_no_button 没有按键 ev_left_press 按下左键 ev_right_press 按下右键 ev_middle_press 按下中键 ev_left_release 放开左键 ev_right_release 放开右键 ev_middle_release 放开中键 ev_mouse_enter 移入鼠标 ev_mouse_leave 移开鼠标 ev_mouse_wheel_up 滚轮向上 ev_mouse_wheel_down 滚轮向下 ev_global_left_button 全局左键 ev_global_right_button 全局右键 ev_global_middle_button 全局中键 ev_global_left_press 全局按下左键 ev_global_right_press 全局按下右键 ev_global_middle_press 全局按下中键 ev_global_left_release 全局放开左键 ev_global_right_release 全局放开右键 ev_global_middle_release 全局放开中键 碰撞事件中要给出另一对象的索引。最后,其他事件中使用以下常量 : ev_outside 出房间 ev_boundary 边界 ev_game_start 游戏开始 ev_game_end 游戏结束 ev_room_start 房间开始 ev_room_end 房间结束 ev_no_more_lives 没有生命 ev_no_more_health 没有生命值 ev_animation_end 结束动画 ev_end_of_path 结束路径 ev_user0 自定义 0 ev_user1 自定义 1 ev_user2 自定义 2 ev_user3 自定义 3 ev_user4 自定义 4 ev_user5 自定义 5 ev_user6 自定义 6 ev_user7 自定义 7 ev_user8 自定义 8 ev_user9 自定义 9 ev_user10 自定义 10 ev_user11 自定义 11 ev_user12 自定义 12 ev_user13 自定义 13 ev_user14 自定义 14 ev_user15 自定义 15 并行事件中使用以下常量 : ev_step_normal正常步 ev_step_begin步开始 ev_step_end步结束 event_perform_object(obj,type,numb)这个函数和上面的函数相同除了这次可以指定事件给另一个对象。注意,在这些事件里的动作是当前实例的,不是给对象实例的。 event_user(numb)在其他事件( other events )中可以定义 16 个用户事件。只有当你调用这个函数是运行。参数 numb 必须在 0 到 15 的范围内。 event_inherited()执行继承事件。只有实例拥有父对象是才有效。 使用下面的只读变量可以获取当前事件执行的信息 : event_type*当前开始执行的事件类型。 event_number*当前开始执行的事件号码。 event_object*当前执行的事件的对象索引。 event_action* 当前执行的事件的动作索引。( 0 为事件中第一个执行的,依次类推)。复杂的变量和函数 这里有一些处理出错的变量和函数。 error_occurred显示是否有错误发生。 error_last用字符串显示最后出错的信息。 show_debug_message(str) Debug 模式中显示字符串 下面的函数用来监测是否确定变量的存在以及怎样设置变量及获取他们的值。所有这些函数的变量名都是用字符串传递。 variable_global_exists(name)返回值为名为参数 name (字符串)的全局变量是否存在。variable_local_exists(name)返回值为当前实例的名为参数 name (字符串)的局部变量是否存在。 variable_global_get(name)返回值为给出参数 name (字符串)的全局变量的值。variable_global_array_get(name,ind)返回值为给出参数 name (字符串)的全局数组的参数 ind 的索引值。 variable_global_array2_get(name,ind1,ind2)返回值为给出参数 name (字符串)的全局二维数组变量的参数 ind1 , ind2 的索引值。 variable_local_get(name)返回值为给出参数 name (字符串)的局部变量的值。variable_local_array_get(name,ind)返回值为给出参数 name (字符串)的局部数组的参数 ind 的索引值。 variable_local_array2_get(name,ind1,ind2)返回值为给出参数 name (字符串)的局部二维数组变量的参数 ind1 , ind2 的索引值。 variable_global_set(name,value)设置给出参数 name (字符串)的全局变量的值。variable_global_array_set(name,ind,value)设置给出参数 name (字符串)的全局数组的参数 ind 的索引值。 variable_global_array2_set(name,ind1,ind2,value)设置给出参数 name (字符串)的全局二维数组变量的参数 ind1 , ind2 的索引值。 variable_local_set(name,value)设置给出参数 name (字符串)的局部变量的值variable_local_array_set(name,ind,value)设置给出参数 name (字符串)的局部数组的参数 ind 的索引值。 variable_local_array2_set(name,ind1,ind2,value)设置给出参数 name (字符串)的局部二维数组变量的参数 ind1 , ind2 的索引值。 举例来说,你可以这样写 : { if variable_global_exists('ammunition') global.ammunition += 1 else global.ammunition = 0 } 你可以使用这些函数通过一种参数传递的方法给脚本传递变量,通过传递它们的字符名以及使用函数来改变它们 你可以使用下面的函数改变程序的优先级 : set_program_priority(priority)设置程序的优先级。可以指定 -3 到 +3 之间的值。值为 -3 时意味着程序只会在如下情况运行,电脑没有其他程序要处理时,或是所有其他的程序都空闲时。值为 -2 或 -1 时在正常线下,其他程序会有优先权。值为 0 时是正常的值。值为 +1 或 +2 为较高的优先级,可能会导致较高的速度和较平滑的游戏流程。但其他程序会得到很少的处理时间。值为 +3 时为实时模式。在实时模式中基本上所有的时间都分配到游戏当中去了。这样会导致电脑正在运行的其他应用程序发生严重的问题。当然键盘事件不 再被电脑记录下来。所以只有当你想要所有的处理时间时才使用这个函数。同样要注意最好使用前仔细的检查一下并且运行前保存游戏。 键盘 键盘互动中,存在以下几个变量和函数 : keyboard_lastkey最后一个按下的按键代码。请看后面的按键代码手册。你可以改变它,例如设定成0,如果你愿意的话。 keyboard_key当前按下的按键代码(看后面;如果是0则表示没有按键)。 keyboard_lastchar最后一个按下的字符(返回字符串格式)。 keyboard_string返回最后一批被按下的字符,最多1024个。字符串将只包含可打印字符。 有些时候将某个按键映射成另一个按键相当有用。例如,你可能想允许玩家同时使用方向键和数字小键盘。除了简单复制动作以外,你还可以通过映射小键盘到方向键来完成。或者你想搞一个控制选项让玩家自己去设置按键。那么以下几个函数就会相当有用 : keyboard_set_map(key1,key2)映射按键代码 key1 到 key2 。 keyboard_get_map(key)返回当前 key 的映射代码。 keyboard_unset_map()重置所有被映射的按键到原始状态。 要检查某个按键或鼠标键是否被按下,你可以使用如下函数。这在需要设置多重按键的时候会用到。 keyboard_check(key)返回指定的 key 是否正处于被按下的状态。 keyboard_check_pressed(key)返回指定的按键 key 是否在上一步之后被按下。 keyboard_check_released(key)返回指定的按键 key 是否在上一步之后被放开。keyboard_check_direct(key)直接通过硬件返回指定按键 key 是否被按下。结果取决于 程序专注的方向,它允许使用更多的按键检查。尤其是它可以检查 vk_lshift,vk_lcontrol, vk_lalt,vk_rshift,vk_rcontrol和vk_ralt这样的按键代码来检测左边或右边的shift,control或alt键被按下。 以下几个函数用来处理键盘的状态 : keyboard_get_numlock()返回 numlock 键是否打开。 keyboard_set_numlock(on)开关 numlock 键。 keyboard_key_press(key)模拟指定按键 key 的一次按键操作。 keyboard_key_release(key)模拟指定按键 key 的一次放开键的操作。 以下为一些存在的虚拟按键代码 : vk_nokey没有按键时的按键代码。 vk_anykey任意键被按下时的按键代码。 vk_left左方向键的按键代码。 vk_right右方向键的按键代码。 vk_up上方向键的按键代码。 vk_down下方向键的按键代码。 vk_enter回车键 vk_escape ESC键 vk_space空格键 vk_shift Shift键 vk_control Ctrl键 vk_alt Alt键 vk_backspace Backspace键 vk_tab Tab键 vk_home Home 键 vk_end end 键 vk_delete delete 键 vk_insert insert 键 vk_pageup pageup 键 vk_pagedown pagedown 键 vk_pause pause/break 键 vk_printscreen printscreen/sysrq 键 vk_f1 ... vk_f12功能键 F1 ~ F12 vk_numpad0 ... vk_numpad9数字小键盘数字键 vk_multiply数字小键盘乘号 vk_divide数字小键盘分号 vk_add数字小键盘加号 vk_subtract数字小键盘减号 vk_decimal数字小键盘小数点 至于字母键可以使用类似 ord('A') 这样的格式表示按键代码(要用大写字母)。数字键就用 ord('5') 这样的格式。以下是在 keyboard_check_direct 里要用到的按键代码 : vk_lshift左shift 键 vk_lcontrol左 control 键 vk_lalt左 alt 键 vk_rshift右 shift 键 vk_rcontrol右 control 键 vk_ralt右 alt 键 例如,假设你有一个对象可以通过方向键控制移动,你可以用如下代码实现步行事件 : { if (keyboard_check(vk_left)) x -= 4; if (keyboard_check(vk_right)) x += 4; if (keyboard_check(vk_up)) y -= 4; if (keyboard_check(vk_down)) y += 4; } 当然在动作库里直接拖放设定更方便一些 这里有一些额外的键盘处理函数。 keyboard_clear(key)清除按键 key 的状态。这意味着除非它被连发,否则不会产生任何按键代码事件。 io_clear()清除所有键盘及鼠标状态。 io_handle()操作用户 io,更新键盘及鼠标状态。 keyboard_wait()等待,直到用户按下键盘上的某个键。 鼠标 在鼠标处理中,存在以下几个变量和函数 : mouse_x*鼠标在房间内的横坐标。无法更改。 mouse_y*鼠标在房间内的纵坐标。无法更改。 mouse_button当前按下的鼠标键。可以有如下集中状态: mb_none,mb_any,mb_left, mb_right,以及 mb_middle。 mouse_lastbutton最后一次按下的鼠标键。 为了检查指定的鼠标键是否被按下,你可以使用如下几个函数。这些函数尤其在多个键按下时非常有用。 mouse_check_button(numb)返回某个鼠标键是否被按中(numb 为 mb_none, mb_left, mb_middle, or mb_right 中的一种)。 mouse_check_button_pressed(numb)返回某个鼠标键在上一次行动后是否被按下(numb 为 mb_none, mb_left, mb_middle, or mb_right 中的一种)。 mouse_check_button_released(numb)返回某个鼠标键在上一次行动后是否被放开(numb 为 mb_none, mb_left, mb_middle, or mb_right 中的一种)。 这里有一些额外的鼠标处理函数。 mouse_clear(button)清除鼠标按键 button 的状态,直到玩家将它放开并再次按下。 io_clear()清除所有键盘及鼠标状态。 io_handle()管理用户 io,更新键盘及鼠标状态。 mouse_wait()等待,直到用户按下某个鼠标键。 精灵和图像 每个对象都有一个相关联的精灵。精灵可以是一张图像或是一组连续的图像。对于对象的每个实例,程序都要在屏幕上绘制对应的图像,在实例的坐标(x,y)原点(这个点在精灵属性里定义)上。当存在多幅图像的时候,会重复循环显示各个图像,形成动画效果。这里有一批函数负责处理图像的绘制。他们可以用来改变效果。每个实例含有如下几个变量 : visible如果 visible 为真(1),则图像就被绘制出来,否则就不予绘制。不可见的实例仍然是活动的并可以触发碰撞事件;只是你看不到而已。将 visible 设置为假可以用在例如手柄对象中(将他们设置为非固态形式以避免碰撞事件)或者隐藏的机关等。 sprite_index实例的当前精灵索引编号。你可以更改它使实例更换另一个精灵。根据不同的值你可以设定显示你所指定的不同的精灵。更改精灵并不会更改当前可见的子图像索引编