map.lua 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868
  1. local love = require("compat")
  2. local map = {
  3. triangles = {},
  4. Boundary = {},
  5. nullpunkt = {},
  6. cars = {},
  7. lastRoundCars = {},
  8. subjects = {},
  9. View = {},
  10. loaded = false,
  11. }
  12. local Camera = require "lib/hump.camera"
  13. local Car = require "car"
  14. local mapSubject = require "environment"
  15. local CamTargetX = 0
  16. local CamTargetY = 0
  17. local CamStartX = 0
  18. local CamStartY = 0
  19. local CamZoomTime = 0
  20. local CamSwingTime = 0
  21. local CamZoomTimePassed = 0
  22. local CamSwingTimePassed = 0
  23. local dx, dy, ZoomIs, mul, ZoomTarget, ZoomStart = 0, 0, 1, 1, 0.1, 0.1
  24. local cam = nil
  25. local CamAngle = 0
  26. local GridColorSmall = {255, 255, 160, 25}
  27. local GridColorBig = {255, 255, 160, 50}
  28. local GridSizeSmallStep = 100
  29. local GridSizeBigStep = 500
  30. -- different Subjects:
  31. local maxS_OnePivot = 200 -- trees, ...
  32. local maxS_QuadPivot = 20 -- houses, ...
  33. local SubjectListOnePivot = {"Baum1", "Baum2", "Baum3", "BaumKl1", "BaumKl2", "BaumKl3"}
  34. local SubjectListQuadPivot = {"Haus1", "Haus2", "Haus3", "Haus4", "HausLang1", "HausLang2", "Kidz1", "Brunnen", "laternenumzug", "Markt1", "Markt2", "Schafe", "See", "Feld", "Traktor"}
  35. local noShadows = {"Schafe", "See", "laternenumzug", "Markt1", "Markt2", "Kidz1", "Feld", "Traktor"}
  36. GRIDSIZE = GridSizeSmallStep
  37. local MapScale = 500
  38. -- Start position triangle:
  39. local tri1 = {0, -GRIDSIZE/2}
  40. local tri2 = {-GRIDSIZE/2, GRIDSIZE/2}
  41. local tri3 = {GRIDSIZE/2, GRIDSIZE/2}
  42. --wird einmalig bei Spielstart aufgerufen
  43. function map:load()
  44. map.View.x = 0
  45. map.View.y = 0
  46. cam = Camera(map.View.x, map.View.y)
  47. end
  48. local DEBUG_POINT_LIST = {}
  49. --wird zum laden neuer Maps öfters aufgerufen
  50. -- ACHTUNG: Bitte nur noch map:newFromString aufrufen!
  51. --[[function map:new( mapstring ) -- Parameterbeispiel: "testtrackstl.stl"
  52. -- Read full file and save it in mapstring:
  53. local mapstring
  54. if not DEDICATED then
  55. mapstring = love.filesystem.read( dateiname )
  56. else
  57. local f = io.open(dateiname, "r")
  58. if f then
  59. mapstring = f:read("*all")
  60. f:close()
  61. end
  62. end
  63. self:newFromString( mapstring )
  64. end]]
  65. function map:newFromString( mapstring )
  66. map.loaded = false
  67. if not mapstring or #mapstring == 0 then
  68. print("Trying to load map from empty string!")
  69. return
  70. end
  71. local success, msg = map:import(mapstring)
  72. if not success then
  73. print("Error loading map: ", msg)
  74. lobby:errorMsg( msg )
  75. map:reset()
  76. return
  77. else
  78. map:getBoundary()
  79. map:zoomOut()
  80. local cX = map.Boundary.minX + (map.Boundary.maxX - map.Boundary.minX)*0.5
  81. local cY = map.Boundary.minY + (map.Boundary.maxY - map.Boundary.minY)*0.5
  82. map:camSwingToPos( cX, cY, 5 )
  83. --[[if server and not map.msgSent then
  84. map.msgSent = true
  85. server:send( CMD.CHAT, WELCOME_MSG )
  86. end]]
  87. if not DEDICATED then
  88. math.randomseed( utility.numFromString( mapstring:sub(1, 100 ) ) )
  89. --ZoomTarget = 50/MapScale -- startzoom depends on MapScale
  90. -- create Environment
  91. -- plant Subjects with big Pivots
  92. for i = 1, maxS_QuadPivot, 1 do
  93. --search fitting positon
  94. local x = math.random(map.Boundary.minX, map.Boundary.maxX)
  95. local y = math.random(map.Boundary.minY, map.Boundary.maxY)
  96. -- check every pivot, ugly as shit but workes
  97. local onRoad = 0
  98. local pivotX = x + GridSizeBigStep
  99. local pivotY = y + GridSizeBigStep
  100. if map:isPointOnRoad(pivotX, pivotY, 0) == true then
  101. onRoad = onRoad + 1
  102. end
  103. local pivotX = x - GridSizeBigStep
  104. local pivotY = y + GridSizeBigStep
  105. if map:isPointOnRoad(pivotX, pivotY, 0) == true then
  106. onRoad = onRoad + 1
  107. end
  108. local pivotX = x + GridSizeBigStep
  109. local pivotY = y - GridSizeBigStep
  110. if map:isPointOnRoad(pivotX, pivotY, 0) == true then
  111. onRoad = onRoad + 1
  112. end
  113. local pivotX = x - GridSizeBigStep
  114. local pivotY = y - GridSizeBigStep
  115. if map:isPointOnRoad(pivotX, pivotY, 0) == true then
  116. onRoad = onRoad + 1
  117. end
  118. if onRoad == 0 then
  119. local nSubject = math.random(1, utility.tablelength(SubjectListQuadPivot))
  120. local s = mapSubject:new(SubjectListQuadPivot[nSubject], x, y) -- choose random subject
  121. for key, str in pairs(noShadows) do
  122. if str == SubjectListQuadPivot[nSubject] then
  123. s.castshadow = false
  124. --print(SubjectListQuadPivot[nSubject], "has no shadow")
  125. end
  126. end
  127. table.insert(map.subjects, s)
  128. --s.r = math.pi
  129. end
  130. end
  131. -- plant Subjects with one Pivot
  132. for i = 1, maxS_OnePivot, 1 do
  133. --search fitting positon
  134. local x = math.random(map.Boundary.minX, map.Boundary.maxX)
  135. local y = math.random(map.Boundary.minY, map.Boundary.maxY)
  136. while map:isPointOnRoad(x, y, 0) == true do
  137. x = math.random(map.Boundary.minX, map.Boundary.maxX)
  138. y = math.random(map.Boundary.minY, map.Boundary.maxY)
  139. end
  140. local nSubject = math.random(1, utility.tablelength(SubjectListOnePivot))
  141. local s = mapSubject:new(SubjectListOnePivot[nSubject], x, y) -- choose random subject
  142. table.insert(map.subjects, s)
  143. end
  144. end
  145. end
  146. end
  147. function map:update( dt )
  148. -- Make sure a map is loaded first!
  149. if not map.loaded then return end
  150. cam.rot = CamAngle
  151. --cam:zoomTo(ZoomTarget)
  152. if CamZoomTime then
  153. CamZoomTimePassed = CamZoomTimePassed + dt
  154. if CamZoomTimePassed < CamZoomTime then
  155. local amount = utility.interpolateCos(CamZoomTimePassed/CamZoomTime)
  156. ZoomIs = ZoomStart + (ZoomTarget - ZoomStart) * amount
  157. else
  158. --mul = ZoomTarget
  159. ZoomIs = ZoomTarget
  160. CamZoomTime = nil
  161. end
  162. cam:zoomTo(ZoomIs)
  163. --else
  164. --cam:zoom(mul)
  165. end
  166. if CamSwingTime then
  167. CamSwingTimePassed = CamSwingTimePassed + dt
  168. if CamSwingTimePassed < CamSwingTime then
  169. local amount = utility.interpolateCos(CamSwingTimePassed/CamSwingTime)
  170. CamX = CamStartX + (CamTargetX - CamStartX) * amount
  171. CamY = CamStartY + (CamTargetY - CamStartY) * amount
  172. else
  173. CamX = CamTargetX
  174. CamY = CamTargetY
  175. CamSwingTime = nil
  176. end
  177. cam:lookAt(CamX,CamY)
  178. else
  179. if not DEDICATED then
  180. if STATE == "Game" and not chat.active then
  181. local dx = ((love.keyboard.isDown('d') or love.keyboard.isDown('right')) and 1 or 0)
  182. - ((love.keyboard.isDown('a') or love.keyboard.isDown('left')) and 1 or 0)
  183. local dy = ((love.keyboard.isDown('s') or love.keyboard.isDown('down')) and 1 or 0)
  184. - ((love.keyboard.isDown('w') or love.keyboard.isDown('up')) and 1 or 0)
  185. dx = dx * (map.Boundary.maxX-map.Boundary.minX)/5 *dt --GridSizeSmallStep --*dt
  186. dy = dy * (map.Boundary.maxY-map.Boundary.minY)/5 *dt --GridSizeSmallStep --*dt
  187. cam:move(dx, dy)
  188. end
  189. end
  190. end
  191. --mul = 1
  192. for id, car in pairs(map.cars) do
  193. car:update(dt)
  194. --[[if self:isPointOnRoad( car.x, car.y, 0 ) then
  195. car.color = { 255, 128, 128, 255 }
  196. else
  197. car.color = blue
  198. end]]
  199. end
  200. end
  201. function map:draw()
  202. -- Make sure a map is loaded first!
  203. if not map.loaded then return end
  204. cam:attach()
  205. -- draw World
  206. -- draw ground
  207. love.graphics.setColor( 40, 40, 40, 255 )
  208. for key, triang in pairs(map.triangles) do
  209. love.graphics.polygon( 'fill',
  210. triang.vertices[1].x,
  211. triang.vertices[1].y,
  212. triang.vertices[2].x,
  213. triang.vertices[2].y,
  214. triang.vertices[3].x,
  215. triang.vertices[3].y
  216. )
  217. end
  218. if self.startLine then
  219. love.graphics.setLineWidth( 30 )
  220. love.graphics.setColor( 50, 50, 50, 100 )
  221. --[[love.graphics.polygon( "fill",
  222. self.startTriangle[1].x,
  223. self.startTriangle[1].y,
  224. self.startTriangle[2].x,
  225. self.startTriangle[2].y,
  226. self.startTriangle[3].x,
  227. self.startTriangle[3].y
  228. )]]
  229. love.graphics.setColor( 150, 150, 150, 100 )
  230. love.graphics.line( self.startLine.p1.x, self.startLine.p1.y,
  231. self.startLine.p2.x, self.startLine.p2.y )
  232. --love.graphics.circle( "fill", self.startProjPoint.x, self.startProjPoint.y, 5 )
  233. --[[love.graphics.setColor( 0, 255,0, 255 )
  234. love.graphics.circle( "fill", self.startPoint.x, self.startPoint.y, 5 )
  235. love.graphics.setColor( 255,0,0, 255)
  236. love.graphics.circle( "fill", self.endPoint.x, self.endPoint.y, 5 )]]
  237. love.graphics.setColor( 150, 150, 150, 25 )
  238. for k, pos in pairs( self.startPositions ) do
  239. love.graphics.polygon( "fill", pos.triangle )
  240. end
  241. end
  242. -- draw grid
  243. map:drawGrid()
  244. -- draw player
  245. for id, c in pairs(map.cars) do
  246. c:draw()
  247. end
  248. -- draw environment
  249. for id, s in ipairs(map.subjects) do
  250. s:draw()
  251. end
  252. cam:detach()
  253. end
  254. function map:addDebugPoint( x, y, col )
  255. table.insert( DEBUG_POINT_LIST, {x=x, y=y, color = col} )
  256. end
  257. function map:drawDebug()
  258. if client then
  259. cam:attach()
  260. love.graphics.setPointSize( 5 )
  261. for i, p in pairs( DEBUG_POINT_LIST ) do
  262. love.graphics.setColor( p.color )
  263. love.graphics.point( p.x, p.y )
  264. end
  265. cam:detach()
  266. end
  267. end
  268. function map:drawTargetPoints( id )
  269. cam:attach()
  270. local car = map.cars[id]
  271. if car then
  272. car:drawTargetPoints()
  273. end
  274. cam:detach()
  275. end
  276. function map:drawCarInfo()
  277. cam:attach()
  278. for k, c in pairs( map.cars ) do
  279. c:drawInfo()
  280. end
  281. cam:detach()
  282. end
  283. function map:drawGrid()
  284. love.graphics.setLineWidth(1)
  285. if cam.scale > 0.14 then
  286. for i = 0, map.Boundary.maxX+math.abs(map.Boundary.minX), GridSizeSmallStep do
  287. if i % GridSizeBigStep == 0 then
  288. love.graphics.setColor(GridColorBig)
  289. else
  290. love.graphics.setColor(GridColorSmall)
  291. end
  292. love.graphics.line(i+map.Boundary.minX, map.Boundary.minY, i+map.Boundary.minX, map.Boundary.maxY)
  293. end
  294. for i = 0, map.Boundary.maxY+math.abs(map.Boundary.minY), GridSizeSmallStep do
  295. if i % GridSizeBigStep == 0 then
  296. love.graphics.setColor(GridColorBig)
  297. else
  298. love.graphics.setColor(GridColorSmall)
  299. end
  300. love.graphics.line(map.Boundary.minX, i+map.Boundary.minY, map.Boundary.maxX, i+map.Boundary.minY)
  301. end
  302. else
  303. love.graphics.setColor(GridColorSmall)
  304. for i = 0, map.Boundary.maxX+math.abs(map.Boundary.minX), GridSizeBigStep do
  305. love.graphics.line(i+map.Boundary.minX, map.Boundary.minY, i+map.Boundary.minX, map.Boundary.maxY)
  306. end
  307. for i = 0, map.Boundary.maxY+math.abs(map.Boundary.minY), GridSizeBigStep do
  308. love.graphics.line(map.Boundary.minX, i+map.Boundary.minY, map.Boundary.maxX, i+map.Boundary.minY)
  309. end
  310. end
  311. end
  312. function map:reset()
  313. map:removeAllCars()
  314. map.Boundary = { minX = math.huge,
  315. minY = math.huge,
  316. maxX = -math.huge,
  317. maxY = -math.huge,
  318. }
  319. map.subjects = {}
  320. map.triangles = {}
  321. map.startLine = nil
  322. map.startPositions = {}
  323. map.driveAngle = 0
  324. map:camSwingAbort()
  325. map.loaded = false
  326. end
  327. function map:import( mapstring )
  328. map:reset()
  329. local vertices = {}
  330. local positions = {"x", "y", "z"}
  331. local counterT = 1 -- Counter für Triangle
  332. local counterV = 1 -- Counter für Vertices
  333. local startpos, endpos
  334. --for line in love.filesystem.lines(Dateiname) do
  335. for line in string.gmatch( mapstring, "(.-)\r?\n" ) do
  336. if(string.find(line,"vertex") ~= nil) then
  337. vertices[counterV] = {}
  338. -- separiere Koordinaten mit Hilfe der Leerzeichen
  339. -- Aufbau in stl: "vertex 2.954973 2.911713 1.000000"
  340. -- -> "vertex[leer](-)[8xNum][leer](-)[8xNum][leer](-)[8xNum]"
  341. local x,y,z = string.match( line, "vertex (-?%d*.?%d*) (-?%d*.?%d*) (-?%d*.?%d*)" )
  342. vertices[counterV].x = tonumber(x) * MapScale
  343. vertices[counterV].y = tonumber(y) * MapScale
  344. vertices[counterV].z = tonumber(z) * MapScale
  345. --[[
  346. for key, value in ipairs(positions) do
  347. startpos = string.find(line," ")
  348. line = string.sub(line, startpos+1)
  349. startpos = 0
  350. endpos = string.find(line," ")
  351. vertices[counterV][value] = tonumber(string.sub(line, startpos, endpos)) * MapScale
  352. end]]
  353. --print("Vertex No",counterV, vertices[counterV].x, vertices[counterV].y, vertices[counterV].z)
  354. -- jeder dritte Vertex ergibt ein Dreieck
  355. if counterV%3 == 0 then
  356. -- Round the vertices on the z axis:
  357. vertices[counterV].z = math.floor( vertices[counterV].z/MapScale + 0.5 )*MapScale
  358. vertices[counterV-1].z = math.floor( vertices[counterV-1].z/MapScale + 0.5 )*MapScale
  359. vertices[counterV-2].z = math.floor( vertices[counterV-2].z/MapScale + 0.5 )*MapScale
  360. -- flip y coordinate:
  361. vertices[counterV].y = -vertices[counterV].y
  362. vertices[counterV-1].y = -vertices[counterV-1].y
  363. vertices[counterV-2].y = -vertices[counterV-2].y
  364. -- Vertices on layer z = 0 are part of the base mesh:
  365. if vertices[counterV].z == 0 and vertices[counterV-1].z == 0 and
  366. vertices[counterV-2].z == 0 then
  367. local newTriangle = {
  368. vertices[counterV-2],
  369. vertices[counterV-1],
  370. vertices[counterV]
  371. }
  372. local area = utility.triangleArea( newTriangle )
  373. --print("Area", area)
  374. if area > 0 then
  375. counterT = counterT + 1
  376. map.triangles[counterT] = {}
  377. map.triangles[counterT].vertices = newTriangle
  378. end
  379. elseif vertices[counterV].z == MapScale and vertices[counterV-1].z == MapScale and
  380. vertices[counterV-2].z == MapScale then
  381. -- Vertices on layer z = 1 are on the higher layer...
  382. elseif vertices[counterV].z == MapScale*2 and vertices[counterV-1].z == MapScale*2 and
  383. vertices[counterV-2].z == MapScale*2 then
  384. if not map.startLine then
  385. local d1 = utility.dist( vertices[counterV], vertices[counterV-1] )
  386. local d2 = utility.dist( vertices[counterV-1], vertices[counterV-2] )
  387. local d3 = utility.dist( vertices[counterV-2], vertices[counterV] )
  388. local p1, p2, p3
  389. -- Look for the longest distance - that's the starting line!
  390. if d1 > d2 and d1 > d3 then
  391. p1 = vertices[counterV]
  392. p2 = vertices[counterV-1]
  393. p3 = vertices[counterV-2]
  394. elseif d2 > d1 and d2 > d3 then
  395. p1 = vertices[counterV-1]
  396. p2 = vertices[counterV-2]
  397. p3 = vertices[counterV]
  398. else
  399. p1 = vertices[counterV-2]
  400. p2 = vertices[counterV]
  401. p3 = vertices[counterV-1]
  402. end
  403. -- This is the line the players need to cross in order to win
  404. map.startLine = { p1 = p1, p2 = p2 }
  405. map.startTriangle = { p1, p2, p3 }
  406. if whichSideOfLine( p1,p2, p3 ) == 0 then
  407. map.startLine = nil
  408. return false, "Start line is not a proper triangle."
  409. end
  410. map.startProjPoint = projectPointOntoLine( p1,p2, p3 )
  411. local diff = {
  412. x = p3.x - map.startProjPoint.x,
  413. y = p3.y - map.startProjPoint.y
  414. }
  415. map.startPoint = p3
  416. map.endPoint = {
  417. x = p3.x - 2*diff.x,
  418. y = p3.y - 2*diff.y
  419. }
  420. local driveDir = {
  421. x = map.startPoint.x - map.startProjPoint.x,
  422. y = map.startPoint.y - map.startProjPoint.y
  423. }
  424. map.driveAngle = math.atan2( driveDir.x, -driveDir.y )
  425. end
  426. elseif vertices[counterV].z == MapScale*3 and vertices[counterV-1].z == MapScale*3 and
  427. vertices[counterV-2].z == MapScale*3 then
  428. local x = math.floor(vertices[counterV].x/GRIDSIZE + 0.5)*GRIDSIZE
  429. local y = math.floor(vertices[counterV].y/GRIDSIZE + 0.5)*GRIDSIZE
  430. local found = false
  431. for k, s in pairs( map.startPositions ) do
  432. if s.x == x and s.y == y then
  433. found = true
  434. print("\tDuplicate start pos! Removing.", x, y)
  435. break
  436. end
  437. end
  438. if not found then
  439. table.insert( map.startPositions, {x = x, y = y} )
  440. end
  441. end
  442. end
  443. counterV = counterV + 1
  444. end
  445. end
  446. -- Consider the map as "loaded" if the list of triangles is not empty
  447. if #map.triangles < 1 then
  448. return false, "Number of triangles is 0. Make sure to save the map file as ASCII stl."
  449. end
  450. if not map.startLine then
  451. return false, "No start line found."
  452. end
  453. if server then
  454. if #map.startPositions < MAX_PLAYERS then
  455. return false, "Map only has " .. #map.startPositions .. " start positions, but you allow up to " .. MAX_PLAYERS .. " players. Change MAX_PLAYERS in config.txt."
  456. end
  457. -- Sort the start positions by how close they are to the start line:
  458. -- (only needed on server)
  459. table.sort( map.startPositions, sortStartPositions )
  460. end
  461. -- Create small triangles which represent the start positions:
  462. for k, pos in ipairs( map.startPositions ) do
  463. local x1, y1 = utility.rotatePoint( tri1[1], tri1[2], map.driveAngle)
  464. local x2, y2 = utility.rotatePoint( tri2[1], tri2[2], map.driveAngle)
  465. local x3, y3 = utility.rotatePoint( tri3[1], tri3[2], map.driveAngle)
  466. pos.triangle = {
  467. x1+pos.x, y1+pos.y,
  468. x2+pos.x, y2+pos.y,
  469. x3+pos.x, y3+pos.y }
  470. end
  471. map.loaded = true
  472. return true
  473. end
  474. -- Sort the start positions: the closer they are to the start line, the earlier they should come.
  475. function sortStartPositions( a, b )
  476. if a and b then
  477. if utility.dist( a, map.startProjPoint ) < utility.dist( b, map.startProjPoint ) then
  478. return true
  479. else
  480. return false
  481. end
  482. else
  483. return false
  484. end
  485. end
  486. -- Check if the given coordinates are on the road:
  487. function map:isPointOnRoad( x, y, z )
  488. local p = {x=x,y=y}
  489. for k, tr in pairs( self.triangles ) do
  490. -- if the point is in any of the triangles, then it's considered to be on the road:
  491. if utility.pointInTriangle( p, tr.vertices[1], tr.vertices[2], tr.vertices[3] ) then
  492. return true
  493. end
  494. end
  495. return false
  496. end
  497. function map:camZoom(zoom, time)
  498. if (not CamZoomTime) then
  499. ZoomTarget = zoom
  500. ZoomStart = cam.scale
  501. CamZoomTime = time
  502. CamZoomTimePassed = 0
  503. end
  504. end
  505. function map:camSwingToPos(x, y, time) --, zoom, time)
  506. if (not CamSwingTime) then
  507. CamTargetX = x
  508. CamTargetY = y
  509. CamStartX, CamStartY = cam:pos()
  510. CamSwingTime = time
  511. --ZoomTarget = zoom or ZoomIs -- zoom = nil or false -> ZoomIs
  512. --ZoomStart = ZoomIs
  513. --if zoom == nil then
  514. -- CamZoomTime = 0
  515. --else
  516. -- CamZoomTime = time
  517. --end
  518. --CamZoomTimePassed = 0
  519. CamSwingTimePassed = 0
  520. end
  521. end
  522. function map:camSwingAbort()
  523. CamSwingTime = nil
  524. CamZoomTime = nil
  525. end
  526. function map:updatecam(dt)
  527. end
  528. function map:getBoundary() -- liefert maximale und minimale x und y Koordinaten
  529. map.Boundary.minX = math.huge
  530. map.Boundary.minY = math.huge
  531. map.Boundary.maxX = -math.huge
  532. map.Boundary.maxY = -math.huge
  533. for key, value in pairs(map.triangles) do
  534. for i = 1, 3, 1 do
  535. map.Boundary.minX = math.min(map.triangles[key].vertices[i].x, map.Boundary.minX)
  536. map.Boundary.minY = math.min(map.triangles[key].vertices[i].y, map.Boundary.minY)
  537. map.Boundary.maxX = math.max(map.triangles[key].vertices[i].x, map.Boundary.maxX)
  538. map.Boundary.maxY = math.max(map.triangles[key].vertices[i].y, map.Boundary.maxY)
  539. end
  540. end
  541. map.nullpunkt = {
  542. x = map.Boundary.minX - 3*GridSizeBigStep,
  543. y = map.Boundary.minY - 3*GridSizeBigStep,
  544. }
  545. --local mapSizePixelX = math.abs(nullpunkt.x) + map.Boundary.maxX + 3*GridSizeBigStep
  546. --local mapSizePixelY = math.abs(nullpunkt.y) + map.Boundary.maxY + 3*GridSizeBigStep
  547. --local mapSizeGridX = mapSizePixelX / GridSizeSmallStep
  548. --local mapSizeGridY = mapSizePixelY / GridSizeSmallStep
  549. --print("mapSizePixelX:", mapSizePixelX, "mapSizePixelY:", mapSizePixelY)
  550. --print("mapSizeGridX:", mapSizeGridX, "mapSizeGridY:", mapSizeGridY)
  551. --for i = 1, mapSizeGridX, 1 do
  552. -- map.grid[i] = {}
  553. -- for j = 1, mapSizeGridY, 1 do
  554. -- map.grid[i][j] = {pxlX = i*GridSizeSmallStep, pxlY = j*GridSizeSmallStep}
  555. -- end
  556. --end
  557. --utility.printTable(map.grid)
  558. --print("Bound.: ", math.abs(map.Boundary.minX)+map.Boundary.maxX)
  559. --print("gerundet: ", (math.abs(map.Boundary.minX)+map.Boundary.maxX)%GridSizeSmallStep)
  560. map.Boundary.minX = map.Boundary.minX - map.Boundary.minX % GridSizeBigStep - 3*GridSizeBigStep
  561. map.Boundary.minY = map.Boundary.minY - map.Boundary.minY % GridSizeBigStep - 3*GridSizeBigStep
  562. map.Boundary.maxX = map.Boundary.maxX + 4*GridSizeBigStep
  563. map.Boundary.maxX = map.Boundary.maxX - map.Boundary.maxX % GridSizeBigStep
  564. map.Boundary.maxY = map.Boundary.maxY + 4*GridSizeBigStep
  565. map.Boundary.maxY = map.Boundary.maxY - map.Boundary.maxY % GridSizeBigStep
  566. end
  567. function map:keypressed( key )
  568. --if key == "p" then
  569. --print(map.grid[x][y].pxlX, map.grid[x][y].pxlY)
  570. --map:setCarPos(1, map.grid[x][y].pxlX, map.grid[x][y].pxlY)
  571. -- local x = -math.random(0,5)
  572. -- local y = math.random(0,5)
  573. -- map:setCarPos(1, x, y)
  574. --end
  575. if key == "+" then
  576. CamZoomTime = nil
  577. cam:zoom( 0.9 )
  578. if cam.scale < 0.01 then
  579. cam.scale = 0.01
  580. end
  581. --ZoomTarget = math.min(ZoomTarget + 0.1, 1)
  582. --map:camZoom(ZoomTarget, 1)
  583. --ZoomTarget = ZoomTarget + 0.01
  584. end
  585. if key == "-" then
  586. CamZoomTime = nil
  587. cam:zoom( 1.1 )
  588. if cam.scale > 1.5 then
  589. cam.scale = 1.5
  590. end
  591. --ZoomTarget = math.max(ZoomTarget - 0.1, 0.1)
  592. --map:camZoom(ZoomTarget, 1)
  593. --ZoomTarget = ZoomTarget - 0.01
  594. end
  595. end
  596. function map:mousepressed( x, y, button )
  597. if button == "wd" then
  598. CamZoomTime = nil
  599. cam:zoom( 0.9 )
  600. if cam.scale < 0.01 then
  601. cam.scale = 0.01
  602. end
  603. --ZoomTarget = math.min(ZoomTarget + 0.1, 1)
  604. --map:camZoom(ZoomTarget, 1)
  605. --ZoomTarget = ZoomTarget + 0.01
  606. end
  607. if button == "wu" then
  608. CamZoomTime = nil
  609. cam:zoom( 1.1 )
  610. if cam.scale > 1.5 then
  611. cam.scale = 1.5
  612. end
  613. --ZoomTarget = math.max(ZoomTarget - 0.1, 0.1)
  614. --map:camZoom(ZoomTarget, 1)
  615. --ZoomTarget = ZoomTarget - 0.01
  616. end
  617. end
  618. function map:TransCoordPtG(pos)
  619. pos = pos / GRIDSIZE
  620. return pos
  621. end
  622. function map:TransCoordGtP(pos)
  623. pos = pos * GRIDSIZE
  624. return pos
  625. end
  626. function map:setCarPos(id, posX, posY) --car-id as number, pos as Gridpos
  627. posX = map:TransCoordGtP(posX)
  628. posY = map:TransCoordGtP(posY)
  629. map.cars[id]:MoveToPos(posX, posY, 1)
  630. if client and client:getID() == id then
  631. map:camSwingToPos(posX, posY, 1)
  632. end
  633. map:checkRoundTransition( id )
  634. end
  635. function map:setCarPosDirectly(id, posX, posY) --car-id as number, pos as Gridpos
  636. posX = map:TransCoordGtP(posX)
  637. posY = map:TransCoordGtP(posY)
  638. map.cars[id]:setPos(posX, posY)
  639. map:checkRoundTransition( id )
  640. end
  641. function map:getCarPos(id)
  642. if map.cars[id] then
  643. local x = map.cars[id].x/GRIDSIZE
  644. local y = map.cars[id].y/GRIDSIZE
  645. return x, y
  646. else
  647. return nil,nil
  648. end
  649. end
  650. function map:hasCar(id)
  651. return (map.cars[id] ~= nil or map.lastRoundCars[id] ~= nil)
  652. end
  653. function map:getCar(id)
  654. if map.cars[id] then
  655. return map.cars[id]
  656. else
  657. return map.lastRoundCars[id]
  658. end
  659. end
  660. function map:getGridPos(GridNx,GridNy)
  661. local x = GridNx * GRIDSIZE
  662. local y = GridNy * GRIDSIZE
  663. return x, y
  664. end
  665. function map:showCarTargets(id, show)
  666. --if show == true
  667. --local positions = {}
  668. --map.cars[id].x = map.cars[id].x + map.cars[id].vx
  669. --map.cars[id].y = map.cars[id].y + map.cars[id].vy
  670. --map.cars[id].targetX
  671. --end
  672. end
  673. -- Check if a car has moved into a new round:
  674. function map:checkRoundTransition( id )
  675. local car = map.cars[id]
  676. local p = { x = car.targetX, y = car.targetY }
  677. local pStart = { x = car.startX, y = car.startY }
  678. local drivenLine = { p1=pStart, p2=p }
  679. local intersects = utility.segSegIntersection( map.startLine, drivenLine )
  680. local distToEnd = utility.dist( p, map.endPoint )
  681. local distToStart = utility.dist( p, map.startPoint )
  682. if car.closerToEnd then
  683. if distToStart < distToEnd then
  684. car.closerToEnd = false
  685. if intersects then
  686. car.round = car.round + 1
  687. end
  688. end
  689. else
  690. if distToEnd < distToStart then
  691. car.closerToEnd = true
  692. if intersects then
  693. car.round = car.round - 1
  694. end
  695. end
  696. end
  697. end
  698. function map:newCar( id, x, y, color )
  699. local users = network:getUsers()
  700. local bodyType = 1
  701. if users then
  702. if users[id] then
  703. bodyType = users[id].customData.body
  704. end
  705. end
  706. map.cars[id] = Car:new( x, y, color, map.driveAngle, bodyType )
  707. end
  708. function map:removeAllCars()
  709. map.lastRoundCars = map.cars
  710. map.cars = {}
  711. end
  712. -- Turn screen coordinates into world (pixel) coordinates:
  713. function map:screenToWorld( x, y )
  714. local wX, wY = cam:worldCoords( x, y )
  715. return wX, wY
  716. end
  717. -- Turn screen coordinates into grid coordinates:
  718. function map:screenToGrid( x, y )
  719. local wX, wY = cam:worldCoords( x, y )
  720. return self:TransCoordPtG(wX), self:TransCoordPtG(wY)
  721. end
  722. function map:isThisAValidTargetPos( id, x, y )
  723. local car = map.cars[id]
  724. if car then
  725. return car:isThisAValidTargetPos( x, y )
  726. end
  727. return false
  728. end
  729. function map:setCarNextMovement( id, x, y )
  730. end
  731. function map:resetCarNextMovement( id )
  732. end
  733. function map:getCarRound( id )
  734. local car = map.cars[id]
  735. if car then
  736. return car.round or -1
  737. end
  738. return -2
  739. end
  740. function map:getCarCenterVel( id )
  741. local car = map.cars[id]
  742. if car then
  743. return (car.x + car.vX)/GRIDSIZE, (car.y + car.vY)/GRIDSIZE
  744. end
  745. end
  746. function map:getCarSpeed()
  747. local car = map.cars[id]
  748. if car then
  749. return math.squrt( car.vX*car.vX + car.vY*var.vY )
  750. else
  751. return 0
  752. end
  753. end
  754. function map:zoomOut()
  755. if map.loaded then
  756. local max = math.max( math.abs(map.Boundary.maxX - map.Boundary.minX),
  757. math.abs(map.Boundary.maxY - map.Boundary.minY ))
  758. max = math.max( max, 1000 )
  759. map:camZoom( 700/max, 4.5 )
  760. end
  761. end
  762. function map:setName( name )
  763. self.name = name
  764. end
  765. function map:getName()
  766. return self.name or "Unknown"
  767. end
  768. return map