Corona SDK游戏开发实例(二):物理效果与互动操作

译文
移动开发 Android iOS 移动应用 游戏开发
在本系列指导教程中,我们共同来学习如何创建一款平衡球类游戏。这款游戏的目标是保持小球平衡、避开各种障碍物并最终到达终点。简单的小游戏,咱们马上进入正题!

[[90110]]教程说明

  • 技术工具: Corona SDK
  • 执行难度: 普通
  • 操作时间: 30 到60分钟

书接上文

在本系列文章的前编中,我们了解了平衡球小游戏的基本概念并创建出基础用户界面。在后编中,我们将共同完成基础物理效果创建、游戏互动性编写等工作,并最终制作出能够给用户带来乐趣的应用成品。

步骤二十九: 添加物理效果

为游戏中的各个图形元素分配物理属性,要注意静态元素是不能移动的。另外还要检查玩家操控的小球与陷阱洞的半径,这些元素必须声明使用圆形物理属性而不能用一般的方形,这样会提高物理碰撞效果、提高游戏性。

  1. -- Add Physics to GFX  
  2.  
  3. physics.addBody(left, 'static'
  4. physics.addBody(right, 'static'
  5. physics.addBody(top, 'static'
  6. physics.addBody(bottom, 'static')  
  7.  
  8. physics.addBody(b1, 'static'
  9. physics.addBody(b2, 'static'
  10. physics.addBody(b3, 'static'
  11. physics.addBody(b4, 'static')  
  12.  
  13. physics.addBody(h1, 'static', {radius = 15}) 
  14. physics.addBody(h2, 'static', {radius = 15}) 
  15. physics.addBody(h3, 'static', {radius = 15}) 
  16. physics.addBody(h4, 'static', {radius = 15}) 
  17. physics.addBody(h5, 'static', {radius = 15}) 
  18.   
  19. physics.addBody(player, {radius = 14}) 
  20. physics.addBody(goal, 'static', {radius = 15}) 

步骤三十: 将陷阱小洞设置为感应器

由于作为陷阱的小洞本身不会产生物理碰撞效果,因此我们只要为其设置接触感应器即可。

  1. -- Set Holes as Sensors      
  2.  
  3.     h1.isSensor = true 
  4.     h2.isSensor = true 
  5.     h3.isSensor = true 
  6.     h4.isSensor = true 
  7.     h5.isSensor = true      
  8.  
  9.     --gameListeners('add'
  10. end 

步骤三十一: 代码审查

以下列出的是本教程所提到全部代码纲要,大家可以从宏观角度对作品进行核查,确定所有要素都已经包含在程序成品当中:

  1. -- Teeter like Game 
  2.  
  3. -- Developed by Carlos Yanez 
  4.  
  5.   
  6.  
  7. -- Hide Status Bar 
  8.  
  9.   
  10.  
  11. display.setStatusBar(display.HiddenStatusBar) 
  12.  
  13.   
  14.  
  15. -- Physics 
  16.  
  17.   
  18.  
  19. local physics = require('physics'
  20.  
  21. physics.start() 
  22.  
  23. physics.setGravity(0, 0) 
  24.  
  25.   
  26.  
  27. -- Graphics 
  28.  
  29.   
  30.  
  31. -- [Background] 
  32.  
  33.   
  34.  
  35. local bg = display.newImage('bg.png'
  36.  
  37.   
  38.  
  39. -- [Title View] 
  40.  
  41.   
  42.  
  43. local titleBg 
  44.  
  45. local playBtn 
  46.  
  47. local creditsBtn 
  48.  
  49. local titleView 
  50.  
  51.   
  52.  
  53. -- [Credits] 
  54.  
  55.   
  56.  
  57. local creditsView 
  58.  
  59.   
  60.  
  61. -- [Player] 
  62.  
  63.   
  64.  
  65. local player 
  66.  
  67.   
  68.  
  69. -- [Bars Table] 
  70.  
  71.   
  72.  
  73. local bars = {} 
  74.  
  75.   
  76.  
  77. -- [Holes Table] 
  78.  
  79.   
  80.  
  81. local holes = {} 
  82.  
  83.   
  84.  
  85. -- [Goal] 
  86.  
  87.   
  88.  
  89. local goal 
  90.  
  91.   
  92.  
  93. -- Sounds 
  94.  
  95.   
  96.  
  97. local bell = audio.loadSound('bell.caf'
  98.  
  99. local buzz = audio.loadSound('buzz.caf'
  100.  
  101.   
  102.  
  103. -- Functions 
  104.  
  105.   
  106.  
  107. local Main = {} 
  108.  
  109. local startButtonListeners = {} 
  110.  
  111. local showCredits = {} 
  112.  
  113. local hideCredits = {} 
  114.  
  115. local showGameView = {} 
  116.  
  117. local gameListeners = {} 
  118.  
  119. local movePlayer = {} 
  120.  
  121. local onCollision = {} 
  122.  
  123. local alert = {} 
  124.  
  125. local dragPaddle = {} 
  126.  
  127.   
  128.  
  129. -- Main Function 
  130.  
  131.   
  132.  
  133. function Main() 
  134.  
  135.     titleBg = display.newImage('titleBg.png'
  136.  
  137.     playBtn = display.newImage('playBtn.png', display.contentCenterX - 35.5, display.contentCenterY + 10) 
  138.  
  139.     creditsBtn = display.newImage('creditsBtn.png', display.contentCenterX - 50.5, display.contentCenterY + 65) 
  140.  
  141.     titleView = display.newGroup(titleBg, playBtn, creditsBtn) 
  142.  
  143.       
  144.  
  145.     startButtonListeners('add'
  146.  
  147. end 
  148.  
  149.   
  150.  
  151. function startButtonListeners(action) 
  152.  
  153.     if(action == 'add') then 
  154.  
  155.         playBtn:addEventListener('tap', showGameView) 
  156.  
  157.         creditsBtn:addEventListener('tap', showCredits) 
  158.  
  159.     else 
  160.  
  161.         playBtn:removeEventListener('tap', showGameView) 
  162.  
  163.         creditsBtn:removeEventListener('tap', showCredits) 
  164.  
  165.     end 
  166.  
  167. end 
  168.  
  169.   
  170.  
  171. function showCredits:tap(e) 
  172.  
  173.     playBtn.isVisible = false 
  174.  
  175.     creditsBtn.isVisible = false 
  176.  
  177.     creditsView = display.newImage('credits.png', 0, display.contentHeight+40) 
  178.  
  179.     transition.to(creditsView, {time = 300, y = display.contentHeight-20, onComplete = function() creditsView:addEventListener('tap', hideCredits) end}) 
  180.  
  181. end 
  182.  
  183.   
  184.  
  185. function hideCredits:tap(e) 
  186.  
  187.     playBtn.isVisible = true 
  188.  
  189.     creditsBtn.isVisible = true 
  190.  
  191.     transition.to(creditsView, {time = 300, y = display.contentHeight+creditsView.height, onComplete = function() creditsView:removeEventListener('tap', hideCredits) display.remove(creditsView) creditsView = nil end}) 
  192.  
  193. end 
  194.  
  195.   
  196.  
  197. function showGameView:tap(e) 
  198.  
  199.     transition.to(titleView, {time = 300, x = -titleView.height, onComplete = function() startButtonListeners('rmv') display.remove(titleView) titleView = nil end}) 
  200.  
  201.       
  202.  
  203.     -- [Add GFX] 
  204.  
  205.       
  206.  
  207.     -- Goal 
  208.  
  209.       
  210.  
  211.     goal = display.newImage('goal.png'
  212.  
  213.     goal.x = 439 
  214.  
  215.     goal.y = 31 
  216.  
  217.     goal.name = 'g' 
  218.  
  219.       
  220.  
  221.     -- Walls 
  222.  
  223.       
  224.  
  225.     local left = display.newLine(-1, 0, -1, display.contentHeight) 
  226.  
  227.     local right = display.newLine(display.contentWidth+1, 0, display.contentWidth+1, display.contentHeight) 
  228.  
  229.     local top = display.newLine(0, -3, display.contentWidth, -3) 
  230.  
  231.     local bottom = display.newLine(0, display.contentHeight, display.contentWidth, display.contentHeight) 
  232.  
  233.       
  234.  
  235.     -- Bars 
  236.  
  237.       
  238.  
  239.     local b1 = display.newImage('bar.png', 92, 67) 
  240.  
  241.     local b2 = display.newImage('bar.png', 192, -2) 
  242.  
  243.     local b3 = display.newImage('bar.png', 287, 67) 
  244.  
  245.     local b4 = display.newImage('bar.png', 387, -2) 
  246.  
  247.       
  248.  
  249.     -- Holes 
  250.  
  251.       
  252.  
  253.     local h1 = display.newImage('hole.png', 62, 76) 
  254.  
  255.     local h2 = display.newImage('hole.png', 124, 284) 
  256.  
  257.     local h3 = display.newImage('hole.png', 223, 224) 
  258.  
  259.     local h4 = display.newImage('hole.png', 356, 114) 
  260.  
  261.     local h5 = display.newImage('hole.png', 380, 256) 
  262.  
  263.       
  264.  
  265.     h1.name = 'h' 
  266.  
  267.     h2.name = 'h' 
  268.  
  269.     h3.name = 'h' 
  270.  
  271.     h4.name = 'h' 
  272.  
  273.     h5.name = 'h' 
  274.  
  275.       
  276.  
  277.     -- Player 
  278.  
  279.       
  280.  
  281.     player = display.newImage('player.png'
  282.  
  283.     player.x = 49 
  284.  
  285.     player.y = 288 
  286.  
  287.     player:setReferencePoint(display.CenterReferencePoint) 
  288.  
  289.       
  290.  
  291.     -- Add Physics to GFX 
  292.  
  293.       
  294.  
  295.     physics.addBody(left, 'static'
  296.  
  297.     physics.addBody(right, 'static'
  298.  
  299.     physics.addBody(top, 'static'
  300.  
  301.     physics.addBody(bottom, 'static'
  302.  
  303.       
  304.  
  305.     physics.addBody(b1, 'static'
  306.  
  307.     physics.addBody(b2, 'static'
  308.  
  309.     physics.addBody(b3, 'static'
  310.  
  311.     physics.addBody(b4, 'static'
  312.  
  313.       
  314.  
  315.     physics.addBody(h1, 'static', {radius = 15}) 
  316.  
  317.     physics.addBody(h2, 'static', {radius = 15}) 
  318.  
  319.     physics.addBody(h3, 'static', {radius = 15}) 
  320.  
  321.     physics.addBody(h4, 'static', {radius = 15}) 
  322.  
  323.     physics.addBody(h5, 'static', {radius = 15}) 
  324.  
  325.       
  326.  
  327.     physics.addBody(player, {radius = 14}) 
  328.  
  329.     physics.addBody(goal, 'static', {radius = 15}) 
  330.  
  331.       
  332.  
  333.     -- Set Holes as Sensors 
  334.  
  335.       
  336.  
  337.     h1.isSensor = true 
  338.  
  339.     h2.isSensor = true 
  340.  
  341.     h3.isSensor = true 
  342.  
  343.     h4.isSensor = true 
  344.  
  345.     h5.isSensor = true 
  346.  
  347.       
  348.  
  349.     gameListeners('add'
  350.  
  351. end 

步骤三十二: 游戏监听器

下列代码的作用是为应用程序添加重力加速及物理碰撞监听器。代码还能通过递交参数来移除这些效果。

  1. function gameListeners(action) 
  2.  
  3.     if(action == 'add') then 
  4.  
  5.         Runtime:addEventListener('accelerometer', movePlayer) 
  6.  
  7.         player:addEventListener('collision', onCollision) 
  8.  
  9.         player:addEventListener('touch', dragPaddle) 
  10.  
  11.     else 
  12.  
  13.         Runtime:removeEventListener('accelerometer', movePlayer) 
  14.  
  15.         player:removeEventListener('collision', onCollision) 
  16.  
  17.         player:removeEventListener('touch', dragPaddle) 
  18.  
  19.     end 
  20.  
  21. end 

步骤三十三: 移动小球

以下函数用来捕捉物理加速值,并根据结果给小球的X及Y属性赋值。

  1. function movePlayer:accelerometer(e) 
  2.  
  3.     player.x = player.x + (e.yGravity*-15) 
  4.  
  5.     player.y = player.y + (e.xGravity*-15) 
  6.  
  7. end 

步骤三十四: 物理碰撞

当小球与其它对象发生碰撞时,其名称会与触碰对象相比照。根据对象类型的不同(陷阱小洞及目的地),游戏会给出不同的提示信息。

  1. function onCollision(e) 
  2.  
  3.     if(e.other.name == 'h') then 
  4.  
  5.         alert() 
  6.  
  7.     elseif(e.other.name == 'g') then 
  8.  
  9.         alert('win'
  10.  
  11.     end 
  12.  
  13. end 

步骤三十五: 提示信息

提示信息被触发时,游戏中的所有监听器都会被移除,并在播放音效的同时显示正确的文本内容。

  1. function alert(action) 
  2.  
  3.     local alert 
  4.  
  5.       
  6.  
  7.     gameListeners('rmv'
  8.  
  9.       
  10.  
  11.     if(action == 'win') then 
  12.  
  13.         alert = display.newImage('complete.png'
  14.  
  15.         alert.x = display.contentCenterX 
  16.  
  17.         alert.y = display.contentCenterY 
  18.  
  19.         transition.from(alert, {time = 300, xScale = 0.3, yScale = 0.3}) 
  20.  
  21.         audio.play(bell) 
  22.  
  23.     else 
  24.  
  25.         alert = display.newImage('gameOver.png'
  26.  
  27.         alert.x = display.contentCenterX 
  28.  
  29.         alert.y = display.contentCenterY 
  30.  
  31.         transition.from(alert, {time = 300, xScale = 0.3, yScale = 0.3}) 
  32.  
  33.         audio.play(buzz) 
  34.  
  35.     end 
  36.  
  37. end 

步骤三十六: 模拟移动

这一步纯属建议,大家可以将下列代表添加进来,借以在模拟环境下拖动小球,观察移动方式是否与预期相符。

  1. function dragPaddle(e) 
  2.  
  3.     if(e.phase == 'began') then 
  4.  
  5.         lastY = e.y - player.y 
  6.  
  7.         lastX = e.x - player.x 
  8.  
  9.     elseif(e.phase == 'moved') then 
  10.  
  11.         player.y = e.y - lastY 
  12.  
  13.         player.x = e.x- lastX 
  14.  
  15.     end 
  16.  
  17. end 

步骤三十七: 调用Main函数

为了在应用启动时进行初始化,我们需要调用Main函数。上述代码编写完成之后,我们只需编辑以下内容即可实现初始化需求:

  1. Main() 

步骤三十八: 载入界面

[[90111]]

当我们启动指南针应用时,iOS系统会逐项载入基本数据,这时Default.png文件将作为背景图案显示在主屏幕当中。将这张图片保存到我们的项目资源文件夹中,这样它就会被自动添加到Corona的编译器中。

步骤三十九: 图标

[[90110]]

现在大家的做图功力就该派上用场了,快为自己的应用打造一款美观又令人印象深刻的图标吧。在非视网膜屏的iPhone设备上,图标文件的尺寸应为57x57像素,而视网膜屏则需要114x114像素,另外我们还需要为iTunes软件商店打造一个512x512的大版图形。我建议大家先以512x512像素为基准设计,然后再缩小成其它两种尺寸。

大家没必要在图标制作方面过分投入精力,制作圆角或者添加半透明特效完全是种花蛇添足——因为iTunes与iPhone会自动为你实现这些效果。

步骤四十: 在模拟环境下进行测试

是时候进行最终测试了。打开Corona模拟器,选择我们的项目文件夹并点击“打开”。如果一切都依照预期效果顺利运行,那么我们就可以着手做***一项工作了。

步骤四十一: 创建

在Corona模拟器中,点选文件选项下的创建项并选择目标设备平台。在对话框中输入项目数据并点击创建按钮。等上几秒,我们的应用作品就大功告成啦!接下来大家可以在设备上进行实机测试,或者直接将应用发布到软件商店中。

总结

后期测试总是越多越好,当我们对自己的应用作品详加打磨后,发行用户版吧——这也许会成为辉煌成功的***步!

希望这篇指南文章能够帮助大家在移动开发的道路上越走越好,感谢朋友们的支持!

 

原文链接:

http://mobile.tutsplus.com/tutorials/corona/corona-sdk-create-a-teeter-like-game-physics-and-interaction/

责任编辑:佚名 来源: 51CTO.com
相关推荐

2012-08-09 08:49:30

CoronaCorona SDKCorona SDK游

2012-12-13 13:27:29

Corona SDK

2012-12-13 09:20:55

Corona 2.0Corona SDK下

2013-04-27 16:14:33

Corona

2012-12-13 10:55:25

CoronaCorona SDK

2011-07-08 14:04:40

LuaCorona

2013-08-01 14:03:49

JavaScript

2012-03-06 08:47:40

Corona

2012-07-12 17:10:40

顽石互动吴刚迭代开发

2013-05-20 15:42:22

2011-04-25 14:45:38

2011-07-27 17:07:06

iPhone 游戏 Cocos2d

2009-06-05 09:24:53

struts标签jsp

2011-07-22 18:20:04

IOS View 动画

2011-12-31 21:28:33

2012-08-07 09:20:48

CoronaCorona SDKCorona SDK指

2020-12-28 06:29:31

Bash互动游戏Linux

2011-07-11 09:58:52

2013-05-21 11:26:49

Android游戏开发Sensor感应
点赞
收藏

51CTO技术栈公众号