Archive

Posts Tagged ‘programming’

Collision detection without physics.

December 14th, 2011 4 comments

A frequent question that comes up in the Corona SDK forums is how to detect when two images on a screen hit each other. This is known as a “Collision”. The ability to determine when two things have bumped into each other is called “Collision Detection”.

Within Corona SDK, being that its an event driven system, we like the idea that we can have the system tell us when things hit each other and we just have to write the code to handle the interaction of the two. This is a coo concept and it works, but . . .

It requires using the Physics engine to do so.

Corona SDK uses a wonderful 2D Box model for physics and that model supports this event driven model and it works well. But if you’re game does not need physics and many apps don’t, like a card game where you move a card to a stack, its kind of silly and wasteful to include the overhead of the physics engine. You don’t need all of those angular momentum floating point mathematics going on for your game.

So how do I detect collisions? I don’t see any API calls to do that?

We really can’t use an event driven model like the physics engine, but there is a very simple method (well there are two) that use other features of Corona SDK, in particular using an “enterFrame” event on the Runtime listener.

Basically we have to write the code that the physics engine is doing for us and it’s not all that complex.

In my personal model, I typically have a table/array of all of my on screen objects and then I have my player’s avatar object.

1
2
3
4
5
6
local objects = {}
for i=1, 20, do
objects[i] = spawnEnemy() -- spawnEnemy creates on display objects and returns it.
end
local player = display.newImageRect("avatar.png", 64, 64) -- create me.

At this point we have a table of enemies in the “objects” table and my player object.

For the Runtime enterFrame event, you need a function to process the collision detection.

1
2
3
4
5
6
7
local function testCollisions
for i=1, #objects do
if hasCollided(objects[i], player) then
-- do what you need to do if they hit each other
end
end
end

So we simply iterate over the list of objects and see if any have hit the player object using a function called hasCollided.

This is a function that you also have to write.

There are two main methods for doing this, one is based on rectangles overlapping each other. The other involves circle testing.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
-- rectangle based
local function hasCollided(obj1, obj2)
if obj1 == nil then
return false
end
if obj2 == nil then
return false
end
local left = obj1.contentBounds.xMin <= obj2.contentBounds.xMin and obj1.contentBounds.xMax >= obj2.contentBounds.xMin
local right = obj1.contentBounds.xMin >= obj2.contentBounds.xMin and obj1.contentBounds.xMin <= obj2.contentBounds.xMax
local up = obj1.contentBounds.yMin <= obj2.contentBounds.yMin and obj1.contentBounds.yMax >= obj2.contentBounds.yMin
local down = obj1.contentBounds.yMin >= obj2.contentBounds.yMin and obj1.contentBounds.yMin <= obj2.contentBounds.yMax
return (left or right) and (up or down)
end
-- circle based
local function hasCollidedCircle(obj1, obj2)
if obj1 == nil then
return false
end
if obj2 == nil then
return false
end
local sqrt = math.sqrt
local dx = obj1.x - obj2.x;
local dy = obj1.y - obj2.y;
local distance = sqrt(dx*dx + dy*dy);
local objectSize = (obj2.contentWidth/2) + (obj1.contentWidth/2)
if distance < objectSize then
return true
end
return false
end

Depending on the shape of your player and objects, you may find that circles work better or rectangles work better. In my game Omniblaster I used both methods depending on the objects. My space ship has rounded shields and my rocks were basically round, and my enemies were basically round, so using the hasCollidedCircle made more sense to use.

When I say rounded, the images have transparency that when using rectangles would cause the objects to hit before they looked like it.

Yet, when I fired my phasers or torpedoes, those graphics fit nicely into rectangles, so using the rectangle hasCollided method was a better choice.

One gotcha that you need to be aware of is that if your processing takes too long, (longer than 1/30th of a second or 1/60th depending on frame rate) then your collision detection will fire again before you finish, so I usually change my collision handler to something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
local isCheckingCollisions = false
local function testCollisions
    if isCheckingCollisions then
   return true
    end
    isCheckingCollisions = true
for i=1, #objects do
if hasCollided(objects[i], player) then
-- do what you need to do if they hit each other
end
end
isCheckingCollisions = false
return true
end

This should be a lighter weight collision detection system than the overhead of the physics engine. Though you don’t get filters, being able to define polygon shapes unless you roll you’re own!

Happy coding!

Implementing a Health Status Bar in Corona SDK

May 30th, 2011 No comments

Implementing a Health Status Bar in Corona SDK

Many games need a way to show the players how well they are doing. It could be a simple counter to show the number of lives left or a bar that decreases and increases as a players energy goes up and down.

There are as many different ways to do this as there are games but lets look at a couple of different ways.

The simplest may be simply using text to display the health status:

1
2
3
4
5
local lives = 5
local livesLabel = display.newText("Lives: ", 10, 30, native.systemFont, 16)
local livesValue = display.newText(string.format("%d", lives), livesLabel.contentWidth+20,30,native.systemFontBold, 16)
livesLabel:setTextColor(225,225,225)
livesValue:setTextColor(255,255,255)

Then later in your code when a player looses a life (or gains one back) simply change the text value of “livesValue” and Corona will magically update the value for you:

1
2
3
4
if lives &gt; 0 then
lives = lives - 1
end
livesValue.text = string.format("%d", lives)

Of course you might want to drop a graphic behind the text, set the colors accordingly, and possibly drop a duplicate text string underneath offset by a pixel to give a little stroke/shadow to the text.

But our players expect more from games and a simple text display won’t be accepted as high quality. Traditional arcade games have shown your lives as small versions of your player’s graphic. If your game involves a ship, perhaps you see a display of 5 little ships to show your life count.

With a display of say 5 small rockets, you will need one image and you will replicate it several times.

1
2
3
4
5
6
7
8
9
local lifeIcons = {}
local lives = 5
local maxLives = 5
local i
for i = 1, maxLives do
lifeIcons[i] = display.newImage("lifeicon.png")
lifeIcons[i].x = 10 + (lifeIcons[i].contentWidth * (i - 1))
lifeIcons[i].y = 30 -- start at 10,10
end

This will create a display of 5 little icons that shows your full life status. Later in your code when you need to change the display:

1
2
3
4
if lives &gt; 0 then
lifeIcons[lives].isVisible = false
lives = lives - 1
end

Later when you need to give a life back:

1
2
3
4
5
lives = lives + 1
if lives &gt; maxLives then
lives = maxLives
end
lifeIcons[lives].isVisible = true

But what if you want more of a bar-graph display. As long as you’re using discrete values, you can continue to use a similar method using different graphics for each value, in this example, there are 5 lives, so you can create 5 different graphics for each of the 5 life states.


Instead of using a loop to load in the same graphic, you would need to load in each of the separate five graphics in and position them all at the same location:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
local lifeIcons = {}
local lives = 5
local maxLives = 5
lifeBar[0] = display.newImage("lifeicon0.png")
lifeBar[1] = display.newImage("lifeicon1.png")
lifeBar[2] = display.newImage("lifeicon2.png")
lifeBar[3] = display.newImage("lifeicon3.png")
lifeBar[4] = display.newImage("lifeicon4.png")
lifeBar[5] = display.newImage("lifeicon5.png")
local i
for i = 1, maxLives do
lifeBar[i].x = 10
lifeBar[i].y = 30
lifeBar[i].isVisible = false
end
lifeBar[lives].isVisible = true

Then to change the graphic:

1
2
3
4
5
if lives &gt; 0 then
lifeBar[lives].isVisible = false
lives = lives - 1
lifeBar[lives].isVisible = true
end

This same concept can be done with MovieClips.

1
2
3
4
healthSprites = movieclip.newAnim{"lifeicon1.png", "lifeicon2.png", "lifeicon3.png", "lifeicon4.png", "lifeicon5.png", "lifeicon0.png"}
healthSprites.x = 50
healthSprites.y = 10
healthSprites:play{startFrame=1, endFrame=lives, loop=1, remove=false}

Then to show the current health level:
[/crayon]

lives = lives – 1
if lives < 0 then
lives = 0
end
if lives == 0 then
healthSprites:play{startGrame=6, endFrame=6, loop=1, remove=false}
else
healthSprites:play{startFrame=1, endFrame=lives, loop=1, remove=false}
end
[/crayon]

This gives you the benefit of a little animation as well. Unlike the example above, we load in the “No life left” graphic in frame 6, because movieclip starts at frame 1. We could have put frame 0 first, and just done a “lives + 1″ to get the right offset.

Hope this is helpful!

 

Tech Geek — Adventures in Objective C Land

April 2nd, 2009 1 comment

Thank you for your patience with all the Sports-Geek posts of late, but its a subject near and dear to my heart. To make up for it, lets go really geek and deal with computer programming.

I am a programmer. It’s what I do. It’s what I’m good at.

Now I’m old school and its really hard for old programmers to learn new tricks. As you age in this field, it becomes harder and harder to adapt to new concepts. I first observed this phenomena early in my career as I watched my boss, who grew up in the punch card / batch processing world have trouble adapting to a world of PCs and interactive systems. He was eventually promoted out of the way. I now see the same thing happening to me. Though I pursued moving from a Support Developer to a Product Trainer, I’m now in a similar position where I’m letting the young’en’s do the programming, letting the new technology pass me by.

I can clearly identify where my downfall began. Object Oriented Programming.

I learned programming in the days of procedural programming. That is we designed our programs using sub-routines and functions. These blocks of code performed specific functions. Data was kept separate for most parts and in things called structures. Life was easy.

A new model developed where code and data kind of merged into things called “objects”. So instead of having a string data type and having functions to get the length, find a chunk (substring), etc. as separate parts, you now have a string object and not only does it have the data for the string, it has the different methods of manipulating it. The object contains the length method or substring method. It was a different way of thinking.

Now I fully understand the idea behind object oriented programming. And I can work comfortably with objects in JavaScript, Perl, C++, though I feel I would be hard pressed to build a major project in an object oriented environment.

One of the big limitations for me is the terminology. There are so many new terms and this old brain doesn’t want to learn them. Which leads me to where I am today.

This week I had a chance to participate in an iPhone application discussion. I’ve had a Mac for almost two years, and beyond some web code, I’ve not written a single Apple app. Not a drop of Applescript. I had Xcode, the Apple Development environment loaded all most the entire time. But real life has kept me from getting down to learning this new environment.

So with this opportunity to mess with an iPhone app, I decided this was a good time to get in and wrap my hands around this and try to upgrade my skills a bit. This is where I hit a major brick wall:

Objective C

Now I can write in the programming language ‘C’ in my sleep, even though I’ve not had a serious project in it in years. ‘C’ is an old language that came out of Bell Labs in the late ’60′s as part of their Unix environment. It became the most dominate language throughout the mid ’80-s through early the 2000′s. Its cryptic. Its powerful. It produces great machine code.

With ‘C’ being so popular, many of the modern languages are derived from it. ‘C’ had a major short coming. Its a procedural language. It knows squat about objects. The Object oriented programming crowd had some languages to use, like Smalltalk.

With ‘C’ being so popular, there were several attempts to objectify it. This produced ‘C++’ which is ‘C’ with objects. Java, is a very ‘C’ like language but it was constructed with Object oriented programming in mind. As web browsers needed a scripting language, we got JavaScript, not that related to Java, but its more of a scriptable ‘C’ with objects. We got PHP for webside scripting which had objects rammed into it later in its life. Flash apps use a ‘C’ / JavaScript like language, ActionScript as its scripting language and is fully object oriented today.

Around the same time that C++ was being worked on, another group was creating Objective C which involved adding some key features from SmallTalk into C. Steve Jobs after he left Apple to Form NeXT, licensed Objective C as the native language for NeXT. Apple ended up acquiring NeXT which lead to the modern OS X operating system. Objective C is tightly embedded to anything Apple today.

I know ‘C’. I don’t know Smalltalk. Objective C is ‘C’ for most stuff, Smalltalk for the objects. So when I went to learn how to write an iPhone App, I was immediately thrown for a loop. What was this alien syntax? I thought my head was going to explode.

Now this project was part of a monthly development practice where everyone takes an idea and tries to produce something that day. It gives developers a chance to work on things that normally wouldn’t get a chance to work on; a chance to make proof-of-concept; etc.

As a product trainer, I would not normally participate in this practice, but we wanted to see if there was anything that could benefit us in the training department. So I took this opportunity to participate. I went and got the iPhone SDK and installed it and dove in.

The first thing any good programmer is going to do is build the traditional “Hello World” program. After about an hour of struggling with a tutorial to build “Hello World” and dealing with this strange syntax I was running around screaming:

“I long for the days of
10 PRINT “Hello World”
20 END”

No, this huge project was loading in all kinds of framework and was creating models, views, and controllers and passing messages. While the code I had to create wasn’t that much, it was quite a bit to see the words “Hello World” show up on the iPhone simulator.

I didn’t quite understand everything. There was a lot of new terminology: Bundles and Delegates to name a couple. Now I was feeling pretty good about things because I managed to get one of our website’s mobile sites loaded into a compiled iPhone app after an hour of modifying “Hello World” without a lot help. Then it tanked. My next task was to determine my current location from the GPS and find the nearest business unit to the phone and show it.

By the time I left, I was still having it crash trying to get it to connect to my webserver to request the location information. Most of the day was spent trying simply construct the URL by converting the Latitude and Longitude to a string. Hours. Oh, yea, the String object can’t be changed, you have to use a Mutable String if you want to change it. Why can’t I simply call sprintf() and be done. The simple task of appending two strings together is a pain in the rear.

Now to put this in perspective, I developed a simple web service that when passed your current location, it returns you the business name and website URL, written in PHP in about 30 minutes. For this simple service I didn’t need to make it database driven, just an array of values, but it was working, tested and debugged in a very short time.

Admittedly my biggest hurdle was the Smalltalk syntax. I’d eventually get delegates and views and such figured out. But the square bracket syntax and variable passing was really confusing to read.

Well today, I spent a few minutes, going back to square one were I was reading the Objective C beginner’s guide when I came across a passage.

Objective C supports “dotted” notation.

Dotted notation is probably the most common way, ‘C’ like languages deal with objects. Wanna work in Java? C++? JavaScript? They all use the standard “dotted” notation. That is:

object.instancevariable = value;

or

value = object.method(parameter);

instead of:

[object instancevariable:value]

or

value = [object instancevariable]

So what the frak are people doing using this non ‘C’ syntax in a ‘C’ language.

Alas, if I’m going to write Apple code, I’m going to have to conform since all examples are in square bracket syntax.

I have to admit after spending some time with the beginner’s guide today, the square bracket syntax isn’t that hard and I think if I spend some time with it, it will be a quite capable language. But that shouldn’t surprise any one who’s used a Mac with OS X.

Maybe this old dog can learn something new!