pong.lua 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. local Rx = require 'rx'
  2. require 'rx-love'
  3. -- Map parameters
  4. local width = 800
  5. local height = 600
  6. local border = 10
  7. -- Player parameters
  8. local paddleWidth = 20
  9. local paddleHeight = 80
  10. local paddleSpeed = 500
  11. -- Ball parameters
  12. local ballSize = 20
  13. -- Maps keys to players and directions
  14. local keyMap = {
  15. w = {'player1', -1},
  16. s = {'player1', 1},
  17. up = {'player2', -1},
  18. down = {'player2', 1}
  19. }
  20. local state
  21. -- Declare initial state of game
  22. function love.load()
  23. state = {
  24. ball = {
  25. x = width / 2 - ballSize / 2,
  26. y = height / 2 - ballSize / 2,
  27. width = ballSize,
  28. height = ballSize,
  29. direction = 3 * math.pi / 4,
  30. speed = 400
  31. },
  32. player1 = {
  33. x = border,
  34. y = height / 2 - paddleHeight / 2,
  35. width = paddleWidth,
  36. height = paddleHeight
  37. },
  38. player2 = {
  39. x = width - (border + paddleWidth / 2),
  40. y = height / 2 - paddleHeight / 2,
  41. width = paddleWidth,
  42. height = paddleHeight
  43. }
  44. }
  45. end
  46. -- Helper functions
  47. local function identity(...) return ... end
  48. local function const(val) return function() return val end end
  49. local function dt() return love.update:getValue() end
  50. local function move(dt, player, direction)
  51. state[player].y = state[player].y + direction * paddleSpeed * dt
  52. end
  53. -- Respond to key presses to move players
  54. for _, key in pairs({'up', 'down', 'w', 's'}) do
  55. love.update
  56. :filter(function()
  57. return love.keyboard.isDown(key)
  58. end)
  59. :map(function(dt)
  60. return dt, unpack(keyMap[key])
  61. end)
  62. :subscribe(move)
  63. end
  64. -- Move ball
  65. love.update
  66. :skip(1)
  67. :subscribe(function(dt)
  68. state.ball.x = state.ball.x + math.cos(state.ball.direction) * state.ball.speed * dt
  69. state.ball.y = state.ball.y + math.sin(state.ball.direction) * state.ball.speed * dt
  70. end)
  71. -- Collision on top and bottom
  72. love.update
  73. :filter(function()
  74. return state.ball.y < 0 or state.ball.y > height - ballSize
  75. end)
  76. :subscribe(function()
  77. state.ball.direction = -state.ball.direction
  78. state.ball.y = math.max(state.ball.y, 0)
  79. state.ball.y = math.min(state.ball.y, height - ballSize)
  80. end)
  81. -- Paddle collision
  82. love.update
  83. :map(function()
  84. local left = state.ball.x - ballSize / 2 < state.player1.x + paddleWidth and
  85. state.ball.y + ballSize / 2 > state.player1.y and
  86. state.ball.y + ballSize / 2 < state.player1.y + paddleHeight
  87. local right = state.ball.x + ballSize / 2 > state.player2.x and
  88. state.ball.y + ballSize / 2 > state.player2.y and
  89. state.ball.y + ballSize / 2 < state.player2.y + paddleHeight
  90. return left and 'left' or (right and 'right' or nil)
  91. end)
  92. :compact()
  93. :subscribe(function(side)
  94. local x, y = math.cos(state.ball.direction), math.sin(state.ball.direction)
  95. x = -x
  96. state.ball.direction = math.atan2(y, x)
  97. if side == 'left' then
  98. state.ball.x = math.max(state.ball.x, state.player1.x + paddleWidth + ballSize / 2)
  99. elseif side == 'right' then state.ball.x = math.max(state.ball.x, state.player1.x + paddleWidth)
  100. state.ball.x = math.min(state.ball.x, state.player2.x - ballSize / 2)
  101. end
  102. state.ball.speed = state.ball.speed + 20
  103. end)
  104. -- Game over
  105. love.update
  106. :filter(function()
  107. return state.ball.x < 0 or state.ball.x + ballSize > width
  108. end)
  109. :subscribe(love.load)
  110. -- Draw state
  111. love.draw:subscribe(function()
  112. local g = love.graphics
  113. g.setColor(0, 0, 0)
  114. g.rectangle('fill', 0, 0, width, height)
  115. g.setColor(255, 255, 255)
  116. g.rectangle('fill', state.player1.x, state.player1.y, state.player1.width, state.player1.height)
  117. g.rectangle('fill', state.player2.x, state.player2.y, state.player2.width, state.player2.height)
  118. g.rectangle('fill', state.ball.x, state.ball.y, state.ball.width, state.ball.height)
  119. end)