|
Director游戏——制作“宇宙入侵者”
所有游戏中最经典的游戏“宇宙入侵者”.已有成百上千种翻版,其中有些就是用D
i r e c t o r
制作的。下面的例子只是非常简单的一个游戏。图1 是正在玩游戏时的情景。
图1 在这个“入侵者”游戏里,入侵者是一些样子十分可笑的位图
这个入侵者游戏比前面几个游戏都复杂。它分为四个行为:一个用于入侵者的角色,一
个用于战舰,一个用于入侵者所发射的子弹,一个用于战舰所发射的子弹。
1 制作入侵者角色
游戏主要由入侵者的运动所控制,它们集体从舞台的一侧横向移到另一侧。当它们碰到
舞台某个侧边时,就向下掉,离舞台的底边更近一步。
控制这种运动只需要一个行为,再把这个行为赋予舞台上的每一个入侵者角色就可以了。
不过,还要使用g H i t Wa l l 和g H i t B o t t o m 两个全局变量。当至少一个角色碰到舞台的侧边或底边
时,相应的全局变量就被设为T R U E ,然后由帧剧本来处理这个情况。
该行为开始时,方向和速度都被设为2 ,表示入侵者每帧向右移动两个像素。它还记录角
色的演员编号。在演员表里,每个入侵者有两个演员,它们基本相同,只是脚的方向反过来,
给人以“进军”的感觉。入侵者行为在各帧交替使用这两个演员.。
global gHitWall, gHitBottom
property pDirection, pMemNum
on beginSprite me
-- start moving 2 pixels to right
pDirection = 2
pMemNum = sprite(me.spriteNum).memberNum
end
on exitFrame me
-- freeze if not on play frame
if the frameLabel <> "Play" then exit
if pDirection = 0 then
-- no direction, must have been hit
sprite(me.spriteNum).memberNum = 0 -- remove sprite
else
-- move
sprite(me.spriteNum).locH = sprite(me.spriteNum).locH + pDirection
-- hit a wall?
if pDirection > 0 and sprite(me.spriteNum).locH > 460 then
gHitWall = TRUE
else if pDirection < 0 and sprite(me.spriteNum).locH < 20 then
gHitWall = TRUE
end if
-- toggle to other member to create animation
if sprite(me.spriteNum).memberNum = pMemNum then
sprite(me.spriteNum).memberNum = pMemNum + 1
else
sprite(me.spriteNum).memberNum = pMemNum
end if
-- fire 1 out of 200 times
if random(200) = 1 then
sendSprite(sprite 55, #fire, sprite(me.spriteNum).loc)
end if
end if
end
on exitFrame 处理程序还以1 / 2 0 0 的机会引发入侵者发射子弹。它向角色5 5 —即入侵者的
子弹—发送一个# f i r e 消息。
如果哪个角色与舞台侧边的距离太近,on exitFrame 处理程序就把全局变量g H i t Wa l l 设为
T R U E 。图3 2 - 7 的例子里使用了2 4 个入侵者。只要有一个入侵者距离墙(舞台的侧边)太近,就
要把这个全局变量设置为T R U E 。如果真的变为T R U E 了,帧剧本就将处理它,即向所有角色
发送一个# c h a n g e D i r e c t i o n 消息。只有入侵者角色才使用这个消息。下面就是那个被调用的处
理程序。它把入侵者向下移动,也改变运动方向。它还检查是否有角色已经太靠下了。
on changeDirection me
-- got change direction message
-- move down
sprite(me.spriteNum).locV = sprite(me.spriteNum).locV + abs(pDirection)
-- hit bottom?
if sprite(me.spriteNum).locV > sprite(5).rect.top then gHitBottom =
TRUE
-- reverse direction
pDirection = -pDirection
end
可以发送给入侵者的另一个消息是# h i t 。这时,演员变为一个爆炸情景的位图。舞台被更
新,于是爆炸的情景立刻显示出来。然后,p D i r e c t i o n 属性被设为0 。这是为了让on exitFrame
处理器知道这个入侵者已经死了,并通过在下一帧把它的演员编号设为0 而删除这个角色。
on hit me
-- got the message I was hit
-- change to hit graphic
sprite(me.spriteNum).member = member("Invader Hit")
-- show me, since I will disappear next frame
updateStage
-- dead, so no direction
pDirection = 0
end
与入侵者行为相连的是入侵者的子弹的行为。这个行为将赋予角色5 5 至角色7 5 。如果想
让角色每次发射更多子弹,可以把它赋予更多的角色;如果想让入侵者少发射些子弹,可以
赋予较少的角色。
入侵者行为里有一个p M o d e 属性,它告诉行为现在是否射击。on fire 处理程序导致发射子
弹,或者当已经发射子弹时,把该消息传给下一个角色。on exitFrame 处理程序负责移动发射
出来的子弹,并检测它是否击中了什么目标,.或是落到了舞台的底部。
property pMode
on beginSprite me
pMode = #none
end
on fire me, loc
if pMode = #fire then
-- busy, send to next sprite
sendSprite(sprite(me.spriteNum+1),#fire,loc)
else
-- set loc, mode
sprite(me.spriteNum).loc = loc
pMode = #fire
end if
end
on exitFrame me
-- freeze unless on play frame
if the frameLabel <> "Play" then exit
if pMode = #fire then
-- move down
sprite(me.spriteNum).locV = sprite(me.spriteNum).locV + 8
if sprite(me.spriteNum).locV > 320 then
-- hit bottom
pMode = #none
else
-- hit gun?
didIHit(me)
end if
end if
end
on exitFrame 处理程序调用on didIHit ,以确定子弹是否击中了战舰。战舰(或枪)是角色5 。
on didIHit me
-- hit gun?
if sprite 5 intersects me.spriteNum then
-- gun explodes
sprite(5).member = member("Invader Hit")
updateStage
-- game over
go to frame "Done"
end if
end
2 创建战舰
现在入侵者和入侵者的子弹都可以活动了,下面的任务是让战舰活动。用左、右箭头键
让战舰左右移动是十分容易的。如果按空格键,则把# f i r e 消息发送给一组战舰子弹角色。
property pFiredLastFrame
on exitFrame me
if the frameLabel <> "Play" then exit
if keyPressed(123) then
-- left arrow
sprite(me.spriteNum).locH = sprite(me.spriteNum).locH - 5
end if
if keyPressed(124) then
-- right arrow
sprite(me.spriteNum).locH = sprite(me.spriteNum).locH + 5
end if
-- check spacebar, plus check to make sure did not fire last frame
if keyPressed(SPACE) and not pFiredLastFrame then
-- space, fire
sendSprite(sprite 6, #fire, sprite(me.spriteNum).loc)
pFiredLastFrame = TRUE
else
pFiredLastFrame = FALSE
end if
end
战舰行为使用了一个名为p F i r e d L a s t F r a m e 的属性,它可以阻止用户按住空格键不放,从
而发射连续的子弹流,导致入侵者的伤亡太重。相反,只能每隔一帧发射一颗子弹。要把发
射子弹的时间间隔拉得更长,可以用该属性计算从上一次发射子弹到现在已经过了多少帧,
并只让子弹每隔3 或4 帧才能发射一次。
战舰的子弹的行为与入侵者的子弹的行为十分相似。其区别在于战舰的子弹向上运动,
并检测是否击中了任何入侵者角色。
由于每当击中入侵者就要加分,需要使用全局变量g S c o r e 。当检测到击中时,就为用户
加分。
global gScore
property pMode
on beginSprite me
pMode = #none
end
on fire me, loc
-- got signaled to fire
if pMode = #fire then
-- busy, send to next sprite
sendSprite(sprite(me.spriteNum+1),#fire,loc)
else
-- fire
sprite(me.spriteNum).loc = loc
pMode = #fire
end if
end
on exitFrame me
-- freeze if not on play frame
if the frameLabel <> "Play" then exit
if pMode = #fire then
-- move bullet up
sprite(me.spriteNum).locV = sprite(me.spriteNum).locV - 16
if sprite(me.spriteNum).locV < 0 then
-- reached top of screen
pMode = #none
else
-- check for hit
didIHit(me)
end if
end if
end
on didIHit me
-- loop through invader sprites
repeat with i = 30 to 53
-- see if it hit
if sprite i intersects me.spriteNum then
-- send hit message
sendSprite(sprite i, #hit)
-- get rid of bullet
sprite(me.spriteNum).locV = -100
pMode = #none
-- add to score
gScore = gScore + 1
showScore
end if
end repeat
end
影片剧本只承担很少的任务,如在必要时重新设置用户的得分,并显示新的分数等。
global gScore
on startMovie
gScore = 0
showScore
go to frame "Play"
end
on showScore
member("Score").text = "Score: "&&gScore
end
3 创建帧剧本
最后,游戏还需要一个帧剧本。这个帧剧本比一般的帧剧本的任务要多一些。其任务之
一是当发现g H i t Wa l l 标志时,向所有角色发送# c h a n g e D i r e c t i o n 。当发现g H
i t B o t t o m 时,它就
让游戏结束。这些任务都是在on enterFrame 处理程序里完成的,它保证这些任务将在角色的
行为里的on exitFrame 处理程序之前执行。
global gHitWall, gHitBottom
on enterFrame me
if gHitWall then
-- an invader hit the wall
sendAllSprites(#changeDirection)
else if gHitBottom then
-- an invader hit the bottom
go to frame "Done"
end if
-- reset wall hit flag for this frame
gHitWall = FALSE
end
on exitFrame
go to the frame
end
以上就是游戏所需要的剧本。其中,战舰、子弹和入侵者的速度的数值还都可以改变。
可以根据需要,在屏幕上放置更多或更少的入侵者。也可以使用其他位图,但记住每个入侵
者由两个演员组成,这两个演员频繁替换,以造成活动的效果。
把C D - R O M 上的这个影片打开来,并试着改一改某些设置。可以把入侵者的阵形改变成
其他形状,也可以添加一些“盾牌”,方法是添加一些角色和“盾牌”行为。可以采取多种方
法改进这个游戏。
|