car.lua 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. local love = require("compat")
  2. NUM_CAR_IMAGES = 4
  3. local Car = {}
  4. Car.__index = Car
  5. local col_shadow = { 0, 0, 0, 100 }
  6. local shadowOffsetX = 5
  7. local shadowOffsetY = 5
  8. --[[Car.draw = function() .... end
  9. Car["draw"]
  10. t = {}
  11. Car[t] = 4
  12. c = Car:new(...)
  13. c:updqte( dt )
  14. Car.update( c, dt )
  15. function Car:update( dt )
  16. function Car.update( self, dt )]]
  17. Images = require "images"
  18. local headoffsetMax = 10
  19. function Car:new( x, y, color, angle, bodyType )
  20. local c = {}
  21. setmetatable( c, Car )
  22. c.x = x
  23. c.y = y
  24. c.r = angle or 0 -- rotation
  25. c.vX = 0
  26. c.vY = 0
  27. c.color = {
  28. color[1] or 0,
  29. color[2] or 0,
  30. color[3] or 0,
  31. 255}
  32. c.scale = 0.5
  33. if not DEDICATED then
  34. c.body = images["car.png"]
  35. bodyType = bodyType or 1
  36. c.detail = images["detail" .. bodyType .. ".png"]
  37. c.head = images["head" .. bodyType .. ".png"]
  38. end
  39. c.driveTime = nil
  40. c.driveTimePassed = 0
  41. c.targetX = x
  42. c.targetY = y
  43. c.startX = x
  44. c.startY = y
  45. c.route = {}
  46. c.routeIndex = 1
  47. c.closerToEnd = true
  48. c.round = 0
  49. c.headX = x
  50. c.headY = y
  51. return c
  52. end
  53. function Car:draw()
  54. love.graphics.setLineWidth( 5 )
  55. love.graphics.setColor(self.color)
  56. -- draw driven route
  57. if self.routeIndex > 2 then
  58. for i = self.routeIndex, 3, -1 do
  59. love.graphics.line(self.route[i-1][1], self.route[i-1][2],
  60. self.route[i-2][1], self.route[i-2][2])
  61. end
  62. end
  63. if self.routeIndex > 1 then
  64. love.graphics.setColor(self.color)
  65. love.graphics.line(self.route[self.routeIndex-1][1], self.route[self.routeIndex-1][2],
  66. self.x, self.y)
  67. end
  68. -- draw Car
  69. love.graphics.push()
  70. --love.graphics.scale(self.scale, self.scale)
  71. -- draw shadow:
  72. love.graphics.setColor(col_shadow)
  73. love.graphics.draw(self.body, self.x+shadowOffsetX, self.y+shadowOffsetY, self.r, 1, 1, self.body:getWidth()/2, self.body:getHeight()/2, 0, 0)
  74. -- draw body
  75. love.graphics.setColor(self.color)
  76. love.graphics.draw(self.body, self.x, self.y, self.r, 1, 1, self.body:getWidth()/2, self.body:getHeight()/2, 0, 0)
  77. love.graphics.setColor(255,255,255,255)
  78. -- draw decoration
  79. love.graphics.draw(self.detail, self.x, self.y, self.r, 1, 1, self.detail:getWidth()/2, self.detail:getHeight()/2, 0, 0)
  80. -- draw heads
  81. love.graphics.draw(self.head, self.headX, self.headY, self.r, 1, 1, self.head:getWidth()/2, self.head:getHeight()/2, 0, 0)
  82. love.graphics.pop()
  83. end
  84. function Car:drawOnUI( x, y, scale )
  85. scale = scale or 1
  86. love.graphics.setColor(self.color)
  87. -- draw Car
  88. love.graphics.push()
  89. love.graphics.translate( x, y )
  90. --love.graphics.scale(self.scale, self.scale)
  91. -- draw body
  92. love.graphics.setColor(self.color)
  93. love.graphics.draw(self.body, 0, 0, .5, scale, scale, self.body:getWidth()/2, self.body:getHeight()/2, 0, 0)
  94. love.graphics.setColor(255,255,255,255)
  95. -- draw decoration
  96. love.graphics.draw(self.detail, 0, 0, .5, scale, scale, self.detail:getWidth()/2, self.detail:getHeight()/2, 0, 0)
  97. -- draw heads
  98. love.graphics.draw(self.head, 0, 0, .5, scale, scale, self.head:getWidth()/2, self.head:getHeight()/2, 0, 0)
  99. love.graphics.pop()
  100. end
  101. function Car:drawInfo()
  102. local info = "Round: " .. self.round
  103. info = info .. "\nx: " .. self.targetX
  104. info = info .. "\ny: " .. self.targetY
  105. local w, numLines = love.graphics.getFont():getWrap( info, 70 )
  106. love.graphics.setColor( 0,0,0,128 )
  107. love.graphics.rectangle( "fill", self.x, self.y + 10, 80, 10 + numLines*love.graphics.getFont():getHeight() )
  108. love.graphics.setColor( self.color )
  109. love.graphics.printf( info, self.x + 5, self.y + 15, 70 )
  110. end
  111. function Car:drawTargetPoints()
  112. if not self.driveTime then -- Don't show while moving.
  113. -- draw targets to move
  114. love.graphics.setColor(self.color[1], self.color[2], self.color[3], self.color[4]/3)
  115. love.graphics.polygon("fill",
  116. self.x+self.vX -GRIDSIZE, self.y+self.vY-GRIDSIZE,
  117. self.x+self.vX-GRIDSIZE, self.y+self.vY+GRIDSIZE,
  118. self.x+self.vX+GRIDSIZE, self.y+self.vY+GRIDSIZE,
  119. self.x+self.vX+GRIDSIZE, self.y+self.vY-GRIDSIZE)
  120. love.graphics.setColor( self.color )
  121. for x = -1, 1 do
  122. for y = -1, 1 do
  123. love.graphics.circle( "fill",
  124. self.x + self.vX + GRIDSIZE*x,
  125. self.y + self.vY + GRIDSIZE*y,
  126. 10 )
  127. end
  128. end
  129. end
  130. if self.route[self.routeIndex-1] and self.routeIndex > 1 then
  131. love.graphics.setColor( self.color )
  132. love.graphics.circle( "fill",
  133. self.route[self.routeIndex-1][1],
  134. self.route[self.routeIndex-1][2], 20 )
  135. end
  136. -- If mouse is hovering over (or close to) a target point, draw the route to
  137. -- that target point:
  138. local gX, gY = map:screenToGrid( love.mouse.getPosition() )
  139. gX = math.floor( gX + 0.5 )
  140. gY = math.floor( gY + 0.5 )
  141. if self:isThisAValidTargetPos( gX, gY ) then
  142. self:drawMovementPrediction( gX, gY )
  143. end
  144. end
  145. function Car:drawMovementPrediction( x, y )
  146. -- NOTE: This would not have to be calculated every frame,
  147. -- but since it's only done for one car, it's fine:
  148. local oldX, oldY = self.x/GRIDSIZE, self.y/GRIDSIZE--map:getCarPos( self.id )
  149. -- Step along the path and check if there's a collision. If so, stop there.
  150. local p = {x = oldX, y = oldY }
  151. local diff = {x = x-oldX, y = y-oldY}
  152. local dist = utility.length( diff )
  153. diff = utility.normalize(diff)
  154. -- Step forward in steps of 0.5 length - this makes sure no small gaps are jumped!
  155. local crashed, crashSiteFound = false, false
  156. local movedDist = 0
  157. local crashSite = nil
  158. for l = 0.5, dist, 0.5 do
  159. p = {x = oldX + l*diff.x, y = oldY + l*diff.y }
  160. if not map:isPointOnRoad( p.x*GRIDSIZE, p.y*GRIDSIZE, 0 ) then
  161. crashSite = p
  162. crashed = true
  163. break
  164. end
  165. movedDist = l
  166. end
  167. -- Also check the end position!!
  168. if not crashed then
  169. -- I have managed to move the entire distance!
  170. movedDist = dist
  171. if not map:isPointOnRoad( x*GRIDSIZE, y*GRIDSIZE, 0 ) then
  172. crashSite = {x=x, y=y}
  173. crashed = true
  174. end
  175. end
  176. if crashed then
  177. love.graphics.setColor( 255,64,64,255 )
  178. love.graphics.line( x*GRIDSIZE, y*GRIDSIZE,
  179. self.x, self.y )
  180. -- Draw crash site:
  181. love.graphics.circle( "fill", crashSite.x*GRIDSIZE, crashSite.y*GRIDSIZE, 5 )
  182. else
  183. love.graphics.setColor( 64,255,64,255 )
  184. love.graphics.line( x*GRIDSIZE, y*GRIDSIZE,
  185. self.x, self.y )
  186. end
  187. end
  188. function Car:update( dt )
  189. if self.driveTime then
  190. self.driveTimePassed = self.driveTimePassed + dt
  191. if self.driveTimePassed < self.driveTime then
  192. local amount = self.driveTimePassed/self.driveTime
  193. self.x = self.startX + (self.targetX - self.startX) * amount
  194. self.y = self.startY + (self.targetY - self.startY) * amount
  195. dist = math.sqrt((self.headX - self.x)*(self.headX - self.x) + (self.headY - self.y)*(self.headY - self.y))
  196. if dist > headoffsetMax then
  197. self.headX = self.x
  198. self.headY = self.y
  199. end
  200. else
  201. self.x = self.targetX
  202. self.y = self.targetY
  203. self.headX = self.targetX
  204. self.headY = self.targetY
  205. self.driveTime = nil
  206. end
  207. end
  208. --print("headoffset:", headoffset)
  209. end
  210. function Car:MoveToPos( x, y, time )
  211. if (not self.driveTime) then
  212. self.route[self.routeIndex] = {self.x, self.y}
  213. self.routeIndex = self.routeIndex + 1
  214. if self.routeIndex > TRAIL_LENGTH then
  215. self.routeIndex = self.routeIndex - 1
  216. table.remove( self.route, 1 )
  217. end
  218. self.targetX = x
  219. self.targetY = y
  220. self.vX = x - self.x
  221. self.vY = y - self.y
  222. self.startX = self.x
  223. self.startY = self.y
  224. self.driveTime = time
  225. self.driveTimePassed = 0
  226. --rotate to Target
  227. self.r = math.atan2(self.y - self.targetY, self.x - self.targetX) - math.pi/2
  228. end
  229. end
  230. function Car:setPos( x, y )
  231. self.vX = x - self.x
  232. self.vY = y - self.y
  233. self.startX = self.x
  234. self.startY = self.y
  235. self.targetX = x
  236. self.targetY = y
  237. self.startX = self.x
  238. self.startY = self.y
  239. --rotate to Target
  240. self.r = math.atan2(self.y - self.targetY, self.x - self.targetX) - math.pi/2
  241. -- Directly set position:
  242. self.x = x
  243. self.y = y
  244. end
  245. function Car:getPos()
  246. return self.x, self.y
  247. end
  248. function Car:isThisAValidTargetPos( x, y )
  249. x = x*GRIDSIZE
  250. y = y*GRIDSIZE
  251. if (x == self.targetX + self.vX - GRIDSIZE or
  252. x == self.targetX + self.vX or
  253. x == self.targetX + self.vX + GRIDSIZE ) and
  254. (y == self.targetY + self.vY - GRIDSIZE or
  255. y == self.targetY + self.vY or
  256. y == self.targetY + self.vY + GRIDSIZE ) then
  257. return true
  258. end
  259. return false
  260. end
  261. return Car