首页 资讯中心 硬件周边 攻略中心 秘籍中心 在线动漫 CG壁纸  
专题栏目: PSP NDS GBA PS2 PS3 XBOX XBOX360 WII
PSP 游戏资料 | 玩家宝典
您的位置:游狐网 >> PSP >> 玩家宝典 >> 软件教程

菜鸟也能为PSP编程 - Lua Player 编程初级指南

[ 时间:2008-5-6 9:40:37 | 来源:电玩巴士 | 收藏本文 ] 【

12——碰撞演示

  本课我们讲解如何在 lua 中制作一些简单的碰撞。本方法使用盒式碰撞,没有达到像素级精度。因为这是你的第一次碰撞尝试,所以简单一点好。

  我们将要做的这个小演示将使用一个可移动的玩家角色。屏幕上还有三个实施了碰撞效果的方块。玩家将无法穿过这些方块。

  首先我们创建两个要用的色彩。一个用于玩家,一个用于我们的方块。

代码:

green=Color.new(0,255,0)
white = Color.new(255,255,255)

  接着创建玩家和方块要用的图像。先创建空的 32x32 的方块,然后用我们刚刚创建的颜色填充它们。

代码:

player = Image.createEmpty(32,32)
player:clear(white)
block = Image.createEmpty(32,32)
block:clear(green)

  现在我们需要创建一个数列来存放我们的玩家信息。本演示中就是简单的保存玩家的 x 和 y 坐标位置。

代码:

Player = { x = 30, y = 100 }

  接下来我们要定义两个变量,存储我们玩家图像的高和宽。这些值将用于我们的碰撞函数中。记住我们刚才是以 32x32 创建图像的,所以那就是我们要用的值。

代码:

playerHeight = 32
playerWidth = 32

  然后,为我们的三个方块也创建一个数列来存储信息。自然,我们要存储每个方块在屏幕上所处的 x,y 值,还有每个方块的宽度与高度。我们使用 width() 和 height() 命令来自动从我们刚才创建的方块图像中获取这些值。代码如下:

代码:

Block = {}
Block[1] = { x = 100, y = 80, height = block:height(), width = block:width() }
Block[2] = { x = 300, y = 30, height = block:height(), width = block:width() }
Block[3] = { x = 200, y = 58, height = block:height(), width = block:width() }

  现在让我们写一个函数让玩家动起来。每次循环都会调用这个函数以检查移动。如果你认真学了前面的课程,应该不难理解下面的代码:

代码:

function movePlayer()
pad = Controls.read()
if pad:left() then
Player.x = Player.x - 1
end
if pad:right() then
Player.x = Player.x + 1
end
if pad:up() then
Player.y = Player.y - 1
end
if pad:down() then
Player.y = Player.y + 1
end
end

  ...终于到好玩的地方了。该是时候创建一个函数来检查碰撞是否产生了。这个函数将使得我们能对游戏中任何一个对象检测碰撞,只要在循环中为该对象调用该函数。先看一下整个函数,然后我们来分析一下。

代码:

function collisionCheck(object)
if (Player.x + playerWidth > object.x) and (Player.x < object.x + object.width) and (Player.y + playerHeight > object.y) and (Player.y < object.y + object.height) then
Player.x = oldx
Player.y = oldy
end
end

  看一下第一行:function collisionCheck(object)

  这是创建一个名为 collisionCheck 的函数。注意括号里的词 object,简单的说这就是一个“替代”变量。当我们稍后实际使用这个函数时需要用我们想要测试碰撞的对象名替换这个词。再往下看你会发现 object 这个词出现了很多次。一旦该函数执行,所有的 object 都会被替换为我们测试的实际对象名。

  有没有觉得第二行很华丽?!

  这一行的 if 语句检测了好几个条件。请注意我把每一块条件都放进了括号里,这样如此长的代码会容易阅读一些。

  首先是检测是否 (Player.x + playerWidth > object.x)。一个图像的 x 值就是指该图像的左上角顶端的横坐标。碰撞的关键就是检测两个图像是否彼此有重叠,如果是则让他们停止重叠。那么为什么要在玩家的 x 值上再加上玩家的宽度呢?很简单,因为如果我们只检测玩家的 x 值,那么只有玩家图像的左上角顶端重叠了才会检测到碰撞。如果我们向右移动,而有一个方块挡在路上,我们需要碰撞在玩家图像的右侧边缘发生。玩家的 x 值加上其宽度就是该图像的右上角顶端的值。

  简单来说,我们要做的就是在图像周围创建一个要求碰撞的盒型区域。一旦移动该盒型区域即为发生碰撞。

  我画了几张图让你对这行代码有形象化的理解。蓝色方盒是个静止的方块,而那个绿色方盒就是玩家。黑线表明碰撞发生的地方。

  到目前为止我们只是检测了玩家的右侧是否越过了其他物体的 x 坐标。

  正如你看到的,现在我们的玩家处于碰撞区域中……但是我们还有更多的检测要做。下一个条件是 (Player.x < object.x + object.width)。
这个代码用于向左移动碰上物体图像右侧的时候。就是前一条件的反例而已。物体对象的 x 值加上它的宽度就是该物体的右侧。现在让我们看看前两个检查条件下的碰撞区域。

  目前为止我们仍然处于碰撞区域。在设定了前两个条件之后,必须在这两条黑线之间碰撞才会发生。

  下一个条件是 (Player.y + playerHeight > object.y)。

  这是用于向下移动的时候。玩家的 y 坐标加上玩家的高度就是玩家图像的底端。如果该值大于其他物体的 y 坐标,则碰撞发生。让我们看看三个条件下的碰撞区域。

  现在你会发现物体方块的上方已不再是碰撞区域,而玩家图像的底端必须大于物体方块图像的顶端才能使碰撞发生。

  最后一个检查条件是 (Player.y < object.y + object.height)。

  这部分代码用于检查向上移动。如果玩家的 y 坐标小于物体的底端(y 坐标加高度)则碰撞发生。这次我们使用“小于”是因为在屏幕上向上移动时 y 值是递减的。现在看看碰撞情况。

  现在物体方块的底部以下也不是碰撞区域了。唯一会发生碰撞的地方就是方块所占据的区域。通过 if 语句的四个条件我们将方块所占区域包围了起来。

  接着我们必须设定一旦进入该区域会发生什么,所以我们将玩家的 x 和 y 值设为 oldx 和 oldy。

  此时我们尚未定义 oldx 和 oldy 的值。这是我们在主循环中要做的第一件事。这些值在每次循环开始时会被玩家当前的 x 和 y 值设定。如果我们的函数判断玩家处于碰撞区域则将玩家的位置设回上一次的位置,也就是 oldx 和 oldy 存储的值。这样我们就永远无法走进物体方块中了。函数在此结束。希望我上述的详细解析能帮到你理解这个函数。

  最后就是我们的主循环。学到这你应该对下面的代码不难理解了。

代码:

while true do

-- store player's position at beginning of each loop
oldx = Player.x
oldy = Player.y
screen:clear()

movePlayer()

--check collision for each block
collisionCheck(Block[1])
collisionCheck(Block[2])
collisionCheck(Block[3])

--paste player to screen
screen:blit(Player.x,Player.y,player)

--paste all 3 blocks to screen
for a = 1,3 do
screen:blit(Block[a].x,Block[a].y,block)
end

screen.waitVblankStart()
screen.flip()
end