I’ve made some good progress on my two-player face-to-face game for iPad build with the Corona SDK tentatively titled ‘Cosmic Crossfire’ – inspired by the classic 90s tabletop action game Crossfire. For this early prototype, I was also inspired by the clean, sharp look and feel of the vector graphics / Vectrex games of the early 80s.

In Cosmic Crossfire, two players sit at opposite ends of the iPad and ‘swipe’ to fire pellets at large geometric shapes in the middle of the screen, attempting to knock them into the other player’s ‘goal zone’. To calculate the direction of the pellets while maintaining a constant ‘total’ firing force, I took the distance from the point where the player lifted his/her finger and compared that to the point where they first began their ‘swipe’ gesture.

Unfortunately, as Corona does not yet support vector math or contain a built-in function for normalizing a force with a unit vector, I had to write a little snippet to recreate the functionality. Note the hacky workarounds for a coordinate system where Y-values are inverted.

-- (Note, this runs when a finger is 'lifted' from the screen) -- Hacky workaround to account for negative distance values and inverted y-coord system if (event.x - event.xStart < 0) then multX = -1; end if (event.x - event.xStart >= 0) then multX = 1; end if (event.y - event.yStart < 0) then multY = -1; end if (event.y - event.yStart >= 0) then multY = 1; end -- Get the absolute value of the distance between where the swipe ended and where it began magX = math.abs(event.x - event.xStart); magY = math.abs(event.y - event.yStart); -- print("magX is " .. magX); -- print("magY is " .. magY); -- Get the angle of the shot by taking the inverse tangent of the y 'distance' over the x 'distance' (TOA = Tangent: Opposite over Adjacent!) local angle = math.atan(magY/magX) local constantForce = 500; -- Normalize the force using cosine and sine and multiplying by the desired constant force. Also, multiply by multX and multY, my hacky 'direction' handlers. local xPower = math.cos(angle)*constantForce*multX local yPower = math.sin(angle)*constantForce*multY -- print("angle is... " .. angle); -- If the distance of y is zero (user taps rather than swipes), angle can return 'undefined' and crash the program. Only fire if the distance between y-values is not zero. (Note that '~=' in Lua is the equivalent of '!=' in other languages). if (magY ~= 0) then shootFrom(1,event.x, xPower, yPower, totalTime) end

Although I plan to add all sorts of complex shapes and odd alien bodies and physics behaviors, the only one I’ve implemented so far is the ‘OctoOrb’. Although I’ve heard from passers-by that he/she/it resembles everything from the michelin man to a piece of candy, I was really going for some sort of weird top-down jellyfish-like creature as inspired by the various octopus villains from the old Sega Alex Kidd games and the Legend of the Mystical Ninja and the like. The OctoOrb is a sphere connected to two smaller spheres via revolute joints which are in turn connected to two tiny orbs. The OctoOrb’s ‘pulse’ is a momentary force applied to the center sphere in a random direction.

octoOrb.myJointR = physics.newJoint( "pivot", octoOrb, rightOrb, xLoc + 50,550 ) octoOrb.myJointR.isLimitEnabled = true -- (boolean) octoOrb.myJointR:setRotationLimits( -60, 60 ) myJointRsm = physics.newJoint( "pivot", rightOrb, rightSmOrb, xLoc+100,550 ) myJointRsm.isLimitEnabled = true -- (boolean) myJointRsm:setRotationLimits( -60, 60 ) myJointL = physics.newJoint( "pivot", octoOrb, leftOrb, xLoc-50,550 ) myJointL.isLimitEnabled = true -- (boolean) myJointL:setRotationLimits( -60, 60 ) myJointLsm = physics.newJoint( "pivot", leftOrb, leftSmOrb, xLoc-100,550 ) myJointLsm.isLimitEnabled = true -- (boolean) myJointLsm:setRotationLimits( -60, 60 )

I had a whale of a time dealing with the logistics of getting the game on the device which unfortunately kept me from implementing my idea for an ‘attractor’ a small capsule that travels in a sine wave across the screen unless struck by a player’s pellet, in which case in begins to attract all the large bodies toward it (and, presumably, toward the opposing player’s goal). Oh well, see you at the next version – code available on GitHub.