fantomEngine - A 2D game framework

Monkey Programming Forums/User Modules/fantomEngine - A 2D game framework

MikeHart(Posted 2012) [#1]
Hi folks,

for the book that I wrote last year, I had to create a 2D game framework, which is called fantomEngine.

Now that the book is published, I guess more and more questions will arise and I think it is good to have a topic for the engine itself. Feel free to ask away and I will do my best to answer them.

If you wonder where to get this framework, it is located at google code here:

http://code.google.com/p/fantomengine

Cheers
Michael


Why0Why(Posted 2012) [#2]
Michael,

Vishal at Packt was kind enough to provide me with a review copy of the book. I will have a review up on my new blog by the end of May. It looks good, I am looking forward to really digging in to it.


MikeHart(Posted 2012) [#3]
Cool, let me know when you have the review published.


fsoft(Posted 2012) [#4]
Hi Michael,

just downloaded the book from my Safari Books Online :-)
I'll read it this evening!

Good job!


MikeHart(Posted 2012) [#5]
Thanks Fabio!


Orusaka(Posted 2012) [#6]
Okay, so I just got Monkey, and I also got this book to go along with it. I was initially very impressed by the fantomEngine, however, some problems have presented themselves.

Specifically, it runs really slowly with large numbers of objects. I decided to port a BreakOut clone I wrote in C++ with Allegro as my first Monkey project. Now, this implementation of mine represents the blocks as an two-dimensional array of potentially 25 rows x 50 cols of blocks, so patterns of blocks may be freely created. Now, this would create 25x50 (or 1250) block objects. Monkey and fantomEngine has no problem creating and rendering these 1250 objects. If I place them in a layer with no collision detection, there is not hit to the FPS. However, the second I place collision detection on them, the game runs at about 1 frame per second. However, the collision detection actually needed is very simple, and should not be all that taxing, certainly not as taxing as this. The original game ran at several thousand FPS when not capped, and in Monkey with fantomEngine, 1 FPS.

That said, if you're not doing 1000 objects on screen, then it seems really great.

Also, it's really annoying that CreateBox()'s X and Y positions relate to the center instead of top-left.


MikeHart(Posted 2012) [#7]
Well, being critic is ok. To bad I don't know where you have the faulty logic in your code but hey, whatever floats your boat. Ramble on all you like. And instead of being annoyed, you simply could have asked politely if I could add this feature you are missing. So maybe you should look into a different module/framework where you are much more happy with.

I don't say that fantomEngine is the best thing since sliced bread and I am open all ears for suggestions, but you should think about your way of communication first.

Anyway, I have some free time so I will try to recreate a scenario like you have described because I am curious. Heck you even say how you check for collision. Your own code, or you are using the methods of fE?


Orusaka(Posted 2012) [#8]
Hey, I'm sorry if I can off harsh. That really wasn't my intention. I can see how it might have come off that way, and I apologize. I was frustrated my implementation wasn't working out, and I shouldn't have taken it out on you. I actually like fantomEngine a lot, it simply does not seem to run well with tons of objects checking for collision detection.

The relevant code here would be:
format_code('
Method CreateBlocks:Void()
Local blockXOrigin:Float = 70
Local blockYOrigin:Float = 20
Local x:Float = blockXOrigin
Local y:Float = blockYOrigin

For Local rows:Int = 1 To 25
x = blockXOrigin
For Local cols:Int = 1 To 50
Local block:ftObject = eng.CreateBox(5.0,5.0,x+10,y+10)
block.SetLayer(layerGame)
block.SetColGroup(grpBlock)
block.SetColWith(grpBall, True)
x += 10
Next
y += 10
Next
End
')
Please excuse the literal constants here, that's just the nature of trying to get things up and running quickly for previous code. The ball is a circle made with CreateCircle(). Now, I know it's collision detection that's slowing everything to a halt, however, I don't know why.

As for how I do the collision detection, I set behavior in Method OnObjectCollision:Int(obj:ftObject, obj2:ftObject), and the code works, it just grinds to a halt, the second I place those objects into the gameLayer. A very noticeable drop in FPS can be seen by just setting the object into the gameLayer without assigning a collision group with SetColGroup(). When a group is set, however, it gives me 1 FPS. On my Galxy Nexus one frame every two or three seconds.

Quite frankly, nothing would thrill me more than the fault being my own.

edit: Cleaned up the logic, so I could share the entire source. Here you go, a minimum functional implementation of BreakOut:

format_code('
Strict

#rem
Script: baseScript.monkey
Description: Base Script fantomEngine
Author: ...
#end

Import fantomEngine
Global g:game


'***************************************
Class game Extends App
Field eng:engine
Field isSuspended:Bool = False

Field ball:ftObject
Field paddle:ftObject

Field layerBackGround:ftLayer
Field layerGame:ftLayer
Field layerTitle:ftLayer

'------------------------------------------
Const grpPaddle:Int = 1
Const grpBall:Int = 2
Const grpBlock:Int = 3

'------------------------------------------
Method CreatePaddle:Void()
paddle = eng.CreateBox(90.0,15.0,270+(90.0/2.0),400.0-(15.0/2.0))
paddle.SetLayer(layerGame)
paddle.SetColGroup(grpPaddle)
paddle.SetColWith(grpBall, True)
End
'------------------------------------------
Method CreateBall:Void()
ball = eng.CreateCircle(5.0,320.0,350.0)
ball.SetLayer(layerGame)
ball.SetColGroup(grpBall)
ball.SetColWith(grpPaddle, True)
ball.SetSpeedY(3)
ball.SetSpeedX(1)
End
'------------------------------------------
Method CreateLayers:Void()
layerBackGround = eng.CreateLayer()
layerGame = eng.CreateLayer()
layerTitle = eng.CreateLayer()
End
'------------------------------------------
Method CreateBackGround:Void()
Local box:ftObject = eng.CreateBox(640,480,640/2,480/2)
box.SetLayer(layerBackGround)
box.SetColor(0,0,100)
End
'------------------------------------------
Method CreateBlocks:Void()
Local blockXOrigin:Float = 70
Local blockYOrigin:Float = 20
Local x:Float = blockXOrigin
Local y:Float = blockYOrigin

For Local rows:Int = 1 To 25
x = blockXOrigin
For Local cols:Int = 1 To 50
Local block:ftObject = eng.CreateBox(10.0,10.0,x+10,y+10)
block.SetLayer(layerGame)
block.SetColGroup(grpBlock)
block.SetColWith(grpBall, True)
x += 10
Next
y += 10
Next
End
'------------------------------------------
Method OnCreate:Int()
SetUpdateRate(60)
eng = New engine
eng.SetCanvasSize(640,480)
CreateLayers()
CreateBackGround()
CreatePaddle()
CreateBall()
CreateBlocks()
Return 0
End
'------------------------------------------
Method OnUpdate:Int()
Local d:Float = Float(eng.CalcDeltaTime())/60.0
If isSuspended = False Then
eng.Update(Float(d))
eng.CollisionCheck(layerGame)
Endif
Return 0
End
'------------------------------------------
Method OnRender:Int()
Cls
eng.Render()
Return 0
End
'------------------------------------------
Method OnResume:Int()
isSuspended = False
SetUpdateRate(60)
Return 0
End
'------------------------------------------
Method OnSuspend:Int()
isSuspended = True
SetUpdateRate(5)
Return 0
End
End

'***************************************
Class engine Extends ftEngine
'------------------------------------------
Method OnObjectCollision:Int(obj:ftObject, obj2:ftObject)
If obj2.GetColGroup() = g.grpPaddle Then
obj.SetSpeedY(-obj.GetSpeedY())
Endif
If obj.GetColGroup() = g.grpBlock Then
obj.Remove()
obj2.SetSpeedY(-obj2.GetSpeedY())
Endif
Return 0
End
'------------------------------------------
Method OnObjectTimer:Int(timerId:Int, obj:ftObject)
Return 0
End
'------------------------------------------
Method OnObjectTouch:Int(obj:ftObject, touchId:Int)
Return 0
End
'------------------------------------------
Method OnObjectTransition:Int(transId:Int, obj:ftObject)
Return 0
End
'------------------------------------------
Method OnObjectUpdate:Int(obj:ftObject)
Select obj
Case g.ball
If(obj.yPos < obj.GetHeight()/2) Then
obj.SetSpeedY(-obj.GetSpeedY())
Endif
If(obj.yPos > (480 - obj.GetHeight()/2)) Then
obj.Remove()
Endif
If(obj.xPos < obj.GetWidth()/2) Then
obj.SetSpeedX(-obj.GetSpeedX())
Endif
If(obj.xPos > (640 - obj.GetWidth()/2)) Then
obj.SetSpeedX(-obj.GetSpeedX())
End
Case g.paddle
Local ac:Float = g.eng.GetAccelX()
If ac = 0 Then
g.paddle.SetSpeedX(0)
End
If ac = -1.0 Then
g.paddle.SetSpeedX(-10)
Endif
If ac = 1.0 Then
g.paddle.SetSpeedX(10)
Endif
If(obj.xPos < obj.GetWidth()/2) Then
obj.xPos = (obj.GetWidth()/2)
Endif
If(obj.xPos > (640 - obj.GetWidth()/2)) Then
obj.xPos = (640 - obj.GetWidth()/2)
Endif
End
Return 0
End
'------------------------------------------
Method OnLayerUpdate:Int(layer:ftLayer)
Return 0
End
End

'***************************************
Function Main:Int()
g = New game
Return 0
End

')


AdamRedwoods(Posted 2012) [#9]
collisions can be computationally expensive and all programmers need at some point to figure out their strategy to make it work faster.

some strategies would be to:
- only exposed bricks are activated for collision testing
- create a large parent 'invisible' object that encompasses a set of bricks, that each holds their own collision group. these groups are only checked when something touches the large parent object.
- use monkey's MAP feature to use a 'bounds' class to test for collisions (more advanced)
- divide the screen up in sections that are each their own collision group. only check when the ball is in that area

the catch-all strategy would be to use a space partitioning tree, like the kd-tree used in minib3d.


MikeHart(Posted 2012) [#10]
Hi Orusaka,

no problem. Thanks for posting the code. It actually looks good. After my own tests I can confirm that the problem with the current fantomEngine is that it will do a lot of collision checks. In your example 1252x1251 each check. That is a lot, right?

I have modified fantomEngine so it will only check objects, if they have the colWith parameter set.

Btw. In fE you don't need to have both objects set via a SetColWith command. Just the one you want an event be triggered for. You only need to set the collision group for both objects.

The best would be to let the paddle collide with the ball and the ball with the bricks. That would make 1 check for the paddle and 1250 checks for the ball.
Or have the ball collide with the paddle and the bricks.

Before I will update fE, you should do the collision check like this:

format_code('
eng.CollisionCheck(ball)
')

This way if will only check the ball, if it collides with the bricks or the paddle and won't iterate through all the other objects too.


Orusaka(Posted 2012) [#11]
Thanks for the suggestions. Those small changes brought the speed up to nearly playable on a few of the targets. What I wound up doing, though, was taking fantomEngine out of the loop on the blocks, and just writing my own simple collision detection routine. Since the blocks are perfect squares, you can pretty much treat them as circles and just do circle on circle collision detection. So, I did that, and now there is not a hint of slowdown.


richicon(Posted 2012) [#12]
@MikeHart - Any further plans for the engine? I notice it hasn't been updated since the book release (which I just got today from Amazon - very useful book).

Also - does fantomEngine support output from any of the Map editors out there; such as Tiled or DAME?


Neuro(Posted 2012) [#13]
From what i've heard from him, he currently is working on updates and fixes to the fantomEngine. Not sure what his status on it is yet.

does fantomEngine support output from any of the Map editors out there; such as Tiled or DAME?

Nope, not right now. He did mentioned looking into that for future updates. For now, I use Tiled with Diddy. Currently I'm working on a really limited tiled editor for us in the fantomEngine.


richicon(Posted 2012) [#14]
Thanks Neuro :)

So for Tiled/Diddy - can you use this in conjunction with Fantom or can you only really use the one module at a time?


Neuro(Posted 2012) [#15]
I actually am using fantomEngine in conjunction with Diddy's low level routines. Haven't actually used Diddy's Tiled stuff with fantom yet as i'm trying to keep them separated since Diddy has this screen class thingy which kinda collides with fantom's renderings. Thats not to say that it can't work, you just may get odd results :).


Tri|Ga|De(Posted 2012) [#16]
Would it be possible to make some swipe functions in fantomEngine?
And a TexturePacker loader would be very nice!

Other than than that I really like your fantomEngine.
I'm using it for my latest game, your book got me started.


MikeHart(Posted 2012) [#17]
Thank you for your nice comments.

I will think about your suggestions.


Tri|Ga|De(Posted 2012) [#18]
I also made some threads on your fantomEngine forum.


MikeHart(Posted 2012) [#19]
Thanks for mentioning the forum. I wasn't visiting them for while due to personal problems. Will go there asap.


Neuro(Posted 2012) [#20]
Would it be possible to make some swipe functions in fantomEngine?

fantom does have some built in touch functionality, but ended writing my own touch module instead. Actually i did started working on some swipe functionality with it also.

I'm using it for my latest game, your book got me started.

Just to note, my Tevada Trigger game was also built using fantomEngine and is an evolution of the "Comet Crusher" game from the book. The DNA is still in there though :).


MikeHart(Posted 2012) [#21]
@Neuro: cool I have to check your game soon.


Neuro(Posted 2012) [#22]
Is fantomEngine using raycasting for collision?


MikeHart(Posted 2012) [#23]
@Neuro, no it doesn't.


MikeHart(Posted 2012) [#24]
Status update: I was forced to stop coding on all my stuff because I needed to get some private issues solved and could not concentrate on my projects durign that time. These are solved now and I will restart the development of fantomEngine over the weekend.


MikeHart(Posted 2012) [#25]
I just have finished uploading version 1.43 of fantomEngine to google code. If your suggestion didn't make it into this version, it will mostlikely appear soon in the next one.


Tri|Ga|De(Posted 2012) [#26]
Nice!

I'm looking forward to this!


Snader(Posted 2012) [#27]
Thank you! Is there somehow any possibility for the use of images loaded from a webserver? I want to create a game that will expand in time, based upon the actions the players made.


Neuro(Posted 2012) [#28]
Glad to hear you still doing more on this :)! Now if you can only get that tilemap system integrated in there and it'll be caught up to the other frameworks here :).


MikeHart(Posted 2012) [#29]
@Neuro: I hear ya :-) Could you provide a test map?

@Snader: You mean downloading images into the data directory?


MikeHart(Posted 2012) [#30]
Folks, what do you need regarding documentation/samples/tutorials?


Snader(Posted 2012) [#31]
@MikeHart: Not really downloading it in the data dir but instead of using an image from the data directory, load it from the web into memory and use it like any other image.


MikeHart(Posted 2012) [#32]
@Snader: Sorry, I have no knowledge about how to do this. And it sounds like it would need a modification of mojo.


Tri|Ga|De(Posted 2012) [#33]
I get an error with the new engine.

Error: Identifier 'IsPause' not found.

In this line: If isPause = True Then


Tri|Ga|De(Posted 2012) [#34]
I found out myself.

IsPause should be IsPaused

And there was an error in this line
startTime += difftime should be startTime += diffTime


c.k.(Posted 2012) [#35]
Snader, you could download an image from the web and save it to the target filesystem, then load it normally.


Neuro(Posted 2012) [#36]
I think he actually wants to store the images on the webserver "cloud" so that it can be accessed from there instead of having to load it locally.


MikeHart(Posted 2012) [#37]
@TriGaDe: Yip, found these errors too. Sorry. Will be fixed in the next version (this week) plus I mentioned it on google code too.


Snader(Posted 2012) [#38]
@C.k.: Neuro is right, that's what I want. For now I am using a program to convert (small) images to a simple imageformat made by myself. Basically it is an textfile with some packing to make it smaller. Monkey now reads the file from the web using mnet and then decodes it to draw it in the game. It is not a fast action game, so for this it suits fine.

It would be fine though to read an PNG image from the web and use it like normal images in the active gamesession.


MikeHart(Posted 2012) [#39]
@snader:

It would be fine though to read an PNG image from the web and use it like normal images in the active gamesession.


For this we would need either the ability to save the image and then use LoadImage, or you do it with MNET, create an empty image, render the downloaded image in the backbuffer, read the pixels with ReadPxiel and then via image.WritePixel modify the created one with the content you have just read. As Mark seems to have a FileModule almost running, the first option sounds doable soon. The only problem here are the platforms that won't allow file saveing like HTML5.


MikeHart(Posted 2012) [#40]
Next update is scheduled for Sept 30th, 11 pm CET. The two biggest additions are TexturePacker support and tile maps (Tiled). Any suggestions for tile maps? What methods would you need?


Tri|Ga|De(Posted 2012) [#41]
Is swipe going to be in the next update to?


MikeHart(Posted 2012) [#42]
Maybe, I will try it. Wife is out of town for the weekend and I might have enough time for it.


Tri|Ga|De(Posted 2012) [#43]
Animating tiles perhaps!
Collision if you have not implemented it yet.


MikeHart(Posted 2012) [#44]
I am working on the collision atm.


Tri|Ga|De(Posted 2012) [#45]
Do you have a release time?


MikeHart(Posted 2012) [#46]
Wanted to release it yesterday. But because of household work and family business I didn't find enough time for it. So I target the coming weekend. Maybe earlier.


MikeHart(Posted 2012) [#47]
Version 1.44 was uploaded a few minutes ago. Support for TexturePacker textures, Tiled tilemaps and some other goodies like more auto scale options for SetCanvasSize were added.

Check out the sample scripts that were added too.

Next stop Box2D integration, waypoint/path finding and gesture detection.


Snader(Posted 2012) [#48]
Thank you mike!


Tri|Ga|De(Posted 2012) [#49]
Thanks! Mike you the mann.


vmakar85(Posted 2012) [#50]
MikeHart - path finding - it will be the most interesting to me, as a whole did a great job! Thank you so much for this!


Tri|Ga|De(Posted 2012) [#51]
I can't compile the TileMap example in V1.66 in GLFW

format_code('
TRANS FAILED: TRANS Failed to execute 'xcodebuild -configuration Release', return code=16640
')


MikeHart(Posted 2012) [#52]
Looks like a problem with Trans calling Xcode. Will check tommorow if I get the same problem. I have compiled the example in HTML5/Android just fine.


MikeHart(Posted 2012) [#53]
Ok, Seesm that XCode 4.2 is not compatible with Monkey anymore. At least not from the build process. You get this error with all the monkey projects from the bananas folder too.


Tri|Ga|De(Posted 2012) [#54]
But it compiles okay for iOS just not GLFW


MikeHart(Posted 2012) [#55]
I get this error with IOS. And there is a problem with GLFW and Xcode 4.2 too in release mode. Not in debug mode. I added to a bug report recently and got told so. You need to upgrade XCode most likely or fix it they way people suggesting there. It has nothing to do with fantomEngine. At least I believe that. :-)


Tri|Ga|De(Posted 2012) [#56]
I get this error in both release and debug mode when trying to compile it to GLFW.
And not only with your tilemap example but with all my programs.

I hope Mark will fix this very soon as I always like to test my programs in GLFW.


MikeHart(Posted 2012) [#57]
I have uploaded version 1.45 now. It supports swipe gesture detection with an automatic callback event. Added also the new SwipeDetection sample script.


MikeHart(Posted 2012) [#58]
A question to the people who use the fantomEngine. I would like to switch the documentation to a more maintainable way. Here I prefer a Open Office document which I could export to a PDF file. Would you be ok with that?


c.k.(Posted 2012) [#59]
A user-editable wiki would be most maintainable... :-)

Personally, I don't like PDF docs. HTML is much more navigable and easy to use.


MikeHart(Posted 2012) [#60]
The problems with Wiki and these things are... you spend to much time to format content. Someone ask me if I could add samples for each command on the wiki. Yes it would be nice, but when I see how much I have to do to format the stuff there, I don't like it. HTML in general would be doable. I have a tool called HelpnDoc which can export HTML files.


Tri|Ga|De(Posted 2012) [#61]
I was the one asking for example for each command and I don't mind if it in PDF.


c.k.(Posted 2012) [#62]
The point of a wiki is that you don't have to do all the work yourself. Imagine your users posting examples, clarifications, etc...

That's the point of a wiki! Time savings and input from many experts...


MikeHart(Posted 2012) [#63]
Can the google code wiki be used like that?


DarkyCrystal(Posted 2012) [#64]
Hi :)

Just a question, in the book you told about a program to make bitmap font and to use with your engine. But this software is only for mac...

Is there a software for PC that is be able to generate bitmap font compatible with your engine ?

Thank you in advance :)


MikeHart(Posted 2012) [#65]
Yes, look at Hiero:

http://slick.cokeandcode.com/demos/hiero.jnlp

If I remember correctly, you have to rename the .fnt file to .txt and flip the bitmap file as it is upside down.


DarkyCrystal(Posted 2012) [#66]
Thank you :) I will try :)

Just a thing : What do you mean with "flip the bitmap file as it is upside down" ?

sorry my english is poor ^^

Thank you in advance :)


MikeHart(Posted 2012) [#67]
You have to load it into an editor and flip it so up is down and down is up.


MikeHart(Posted 2012) [#68]
About the wiki, if anyone wants to help documenting it, then please let me know your gmail adress and I can add you to it.


DarkyCrystal(Posted 2012) [#69]
oki do a vertical flip if I understand :) I will try and I will say to you if it works :) thank you :)


Tri|Ga|De(Posted 2012) [#70]
I'll help you with the wiki Mike.
My mail is jenscit (at) gmail.com
I don't know all the commands yes, but I have use some of them.
I'll help you with what I can.


MikeHart(Posted 2012) [#71]
Thanks, that is great. I added you as a commiter.


MikeHart(Posted 2012) [#72]
I have documented the first example here:

http://code.google.com/p/fantomengine/wiki/ActivateSwipe

Here is the wiki code for this command.
format_code('
#summary Documentation for CreateLayer.

= Syntax =

[ftLayer] = ftEngine.CreateLayer()

= Parent class =

[ftEngine]

= Parameters =

|| Parameter || Type || Description ||
|| none || - || - ||

=Return value=

|| Type || Description ||
|| [ftLayer] || The layer that was created ||

= Description =

To create a new layer, use CreateLayer.

= Example =

{{{
Local myEngine:ftEngine = New ftEngine
Local myLayer:ftLayer = myEngine.CreateLayer()
}}}

')

If you agree with the format, then you can go ahead and start adding docs for more commands. Just click on the questin mark next to a command you want to document. Thanks again for your help.


Tri|Ga|De(Posted 2012) [#73]
I'll do that


DarkyCrystal(Posted 2012) [#74]
The hero software for bitmap font doesn't work with me :

"
<jnlp spec="1.0+" codebase="http://slick.cokeandcode.com/demos" href="hiero.jnlp">
<information>
<title>Slick2D Hiero Bitmap Font Generator</title>
<vendor>Slick 2D</vendor>
<homepage href="http://slick.cokeandcode.com"/>
<description>Slick2D Hiero Bitmap Font Generator</description>
<description kind="short">Slick2D Hiero Bitmap Font Generator</description>
<icon href="icon.gif"/>
</information>
<security>
<all-permissions/>
</security>
<resources>
<j2se href="http://java.sun.com/products/autodl/j2se" version="1.4+" max-heap-size="512m"/>
<jar href="hiero.jar"/>
<jar href="slick.jar"/>
<jar href="lwjgl.jar"/>
</resources>
<resources os="Windows">
<j2se href="http://java.sun.com/products/autodl/j2se" version="1.4+" max-heap-size="128m"/>
<nativelib href="natives-win32.jar"/>
</resources>
<resources os="Linux">
<j2se href="http://java.sun.com/products/autodl/j2se" version="1.4+" max-heap-size="128m"/>
<nativelib href="natives-linux.jar"/>
</resources>
<resources os="Mac">
<j2se href="http://java.sun.com/products/autodl/j2se" version="1.4+" max-heap-size="128m"/>
<nativelib href="natives-mac.jar"/>
</resources>
<application-desc main-class="org.newdawn.slick.tools.hiero.Hiero"/>
</jnlp>"

I try to reinstall java and some things but that doesn't work. I am on Windows 8...So I don't know. Is here an other soft that could be compatible with your framework for PC ?


MikeHart(Posted 2012) [#75]
Not that I know of.


DarkyCrystal(Posted 2012) [#76]
However, this framework is very usefull :)


Tri|Ga|De(Posted 2012) [#77]
I use GlyphDesigner with the fantomEngine.


MikeHart(Posted 2012) [#78]
If you find a different font tool which you like to support for, please raise your voice.


DarkyCrystal(Posted 2012) [#79]
This tool works great : http://www.warriorsofthecucumber.com/applications/bitmapfontcreator/ I used it with AGK ;) May be it should be possible to make something compatible with :)


MikeHart(Posted 2012) [#80]
I will look into it.


DarkyCrystal(Posted 2012) [#81]
Nice ! thank's :)


christianstrang(Posted 2012) [#82]
nevermind, got it working :)


DarkyCrystal(Posted 2012) [#83]
Hello, I have a question about the ftObject gestion.

How do we play with ftObject and list ? Here's a example :

I create an ftObject for the bullets of my player. I have something like this :

format_code('myBullet = eng.CreateImage......')

After, I have two solution to have the movement :

1. If I assign a SetSpeedX() variable, all work , without problem.

But

2. If I want to create the movement myself, adjusting the coordinate manually with the X and Y variable, I have a problem : The engine stop updating the last object and updating only the new one.

I think the solution will be to create a list of that objects. But I don't know how to deal with this framework.

Any idea ?

Thank you in advance :)

Sorry for my english (again lol).


MikeHart(Posted 2012) [#84]
The OnObjectUpdate method of the engine is a perfect place to do it there. It will be called when you call the update method of the engine. I will create a small example today and post it here for you.


MikeHart(Posted 2012) [#85]
Ok, here you go:

[monkeycode]
Strict

#Rem
Script: ObjectMovement.monkey
Description: Sample script that shows how to control your objects at runtime
Author: Michael Hartlef
Version: 1.0
#End

Import fantomEngine
Global g:game


'***************************************
Class game Extends App
' Create a field to store the instance of the engine class, which is an instance
' of the ftEngine class itself
Field eng:engine

' Create a field to store the canon object so we can handle it directly
Field canon:ftObject

' Create two fields that store the width and height of the canvas
Field cw:Float
Field ch:Float

'------------------------------------------
' The SpawnShot method will create a new shot. It sets its ID , positions it
' infront of the canon and set its speed and heading reagrding the angle of the
' canon.
Method SpawnShot:Int()
' Determine the current angle of the canon
Local curAngle:Float = canon.GetAngle()

' Determine the vector that is 50 pixels away infront of the canon
Local pos:Float[] = canon.GetVector(50,curAngle)

' Create a shot in the middle of the screen
Local shot:ftObject = eng.CreateCircle(5,pos[0], pos[1])

' Set the speed and the angle of the shot
shot.SetSpeed(10, curAngle)

' Set its ID to 222 so we can detect it during the OnObjectUdpate event
shot.SetID(222)
Return 0
End
'------------------------------------------
Method OnCreate:Int()
' Set the update rate of Mojo's OnUpdate events to 60 FPS
SetUpdateRate(60)

' Create an instance of the fantomEngine, which was created via the engine class
eng = New engine

' Determine and store the width and height of the canvas
cw = eng.GetCanvasWidth()
ch = eng.GetCanvasHeight()

' Create the canon in the middle of the screen
canon = eng.CreateBox(20,60, cw/2, ch/2 )

' Set the ID of the canon so it won't be detected as a shot later
canon.SetID(111)
Return 0
End
'------------------------------------------
Method OnUpdate:Int()
' Determine the delta time and the update factor for the engine
Local d:Float = Float(eng.CalcDeltaTime())/60.0

' Update all objects of the engine
eng.Update(Float(d))

' If the LEFT key was pressed, turn the canon by 2 degrees left
If KeyDown(KEY_LEFT) Then canon.SetAngle(-2,True)

' If the RIGHT key was pressed, turn the canon by 2 degrees right
If KeyDown(KEY_RIGHT) Then canon.SetAngle(2,True)

' If the SPACE key was pressed, spwan a new shot
If KeyHit(KEY_SPACE) Then SpawnShot()

Return 0
End
'------------------------------------------
Method OnRender:Int()
' Clear the screen
Cls
' Render all visible objects of the engine
eng.Render()
Return 0
End
End

'***************************************
Class engine Extends ftEngine
Method OnObjectUpdate:Int(obj:ftObject)
' Determine if the object is a shot
If obj.GetID() = 222 Then

' If the shot, reaches the top or bottom, set its speed to zero
If obj.GetPosY() < 40 Or obj.GetPosY() > (g.ch-40) Then obj.SetSpeed(0)

' If the shot reaches the left or right border, remove the object
If obj.GetPosX() < 40 Or obj.GetPosX() > (g.cw-40) Then obj.Remove()

Endif
Return 0
End
End

'***************************************
Function Main:Int()
g = New game
Return 0
End

[/monkeycode]


DarkyCrystal(Posted 2012) [#86]
Thank's but you didn't understand my problem :)

If you use SetSpeed, you don't have any problem. When we use your frameworks commands, all work fine.

What I want is to update my object by myself with a calculation. In this way in the update method for object I can say something like that :

myobject.SetPos(myobject.GetPosX(), myobject.GetPosY() + multiplier)

But if I do this, and if more than one bullet are fired, the engine stop all the bullet (they don't move anymore) and update only the last created.

That's why I asked this question because with your commands, all update are fine, but with "manual commands", it seems the last object created, overwrite others.

I don't know if your understand :p

In you example, if you replace the SetSpeed command by something I wrote under, you should have the problem.


MikeHart(Posted 2012) [#87]
I understood you and thought by showing you where you can manipulate your object inside the engine, that you can see yourself. :-)))

Don't use Setspeed in Spawn then, but use

obj.SetPos(obj.GetPosX(), obj.GetPosY() + multiplier)

or something you think you can position your object inside the OnObjectUpdate method. I thought it was obviously that you can do ANY handling there, I just used some different commands.

If you don't want to do it there, store the objects you have created inside a list and handle them by itterating through that list.


MikeHart(Posted 2012) [#88]
If they there is a weird behaviour, then you handle it faulty. Show the code that is not working.


DarkyCrystal(Posted 2012) [#89]
I always use the OnObjectUpdate Method. But if I do what I want, that doesn't work... That works only for the last bullet object created.

but if I use at the same place, SetSpeed instead, that works...

I have a method "SpawnFire" in this method I created a bullet with something like :

myobjectfire = eng.CreateImage....blablabla

I assign it a layer, a position at start.

Now, in the OnObjectUpdate Method I write

format_code('
if obj = g.myobjectfire

obj.SetPos(obj.GetPosX(), obj.GetPosY() + multiplier)

EndIf
')

That works but only with the last bullet fired. If I shoot 4 times, the first will update until the second is created. When I shoot a second time , the first bullet stops, and only the second is updated, and so on...

But if I use SetSpeed instead, in the method, I don't have any problem...


MikeHart(Posted 2012) [#90]
Here is another version, showing how to use a list for your objects and handle it manually. ftEngine.Update is still called so you see that nothing is overwritten.

[monkeycode]
Strict

#Rem
Script: ObjectMovement2.monkey
Description: Sample script that shows how to control your objects at runtime
Author: Michael Hartlef
Version: 1.0
#End

Import fantomEngine
Global g:game


'***************************************
Class game Extends App
' Create a field to store the instance of the engine class, which is an instance
' of the ftEngine class itself
Field eng:engine

' Create a list to store the shots in
Field shotList := New List<ftObject>

' Create two fields that store the width and height of the canvas
Field cw:Float
Field ch:Float

'------------------------------------------
' The SpawnShot method will create a new shot. It sets its ID , positions it
' infront of the canon and set its speed and heading reagrding the angle of the
' canon.
Method SpawnShot:Int()
' Create a shot in the middle of the screen
Local shot:ftObject = eng.CreateCircle(5,cw/2, ch/2)

' Set the tag of a shot
shot.SetTag(Rnd(1,4))

' Set the speed and the angle of the shot
shotList.AddLast(shot)

Return 0
End
'------------------------------------------
Method OnCreate:Int()
' Set the update rate of Mojo's OnUpdate events to 60 FPS
SetUpdateRate(60)

' Create an instance of the fantomEngine, which was created via the engine class
eng = New engine

' Determine and store the width and height of the canvas
cw = eng.GetCanvasWidth()
ch = eng.GetCanvasHeight()

Return 0
End
'------------------------------------------
Method OnUpdate:Int()
' Determine the delta time and the update factor for the engine
Local d:Float = Float(eng.CalcDeltaTime())/60.0

' Update all shots depending on their tag value
For Local obj := Eachin shotList
If obj.GetTag() = 1 Then obj.SetPos(-2,0,True)
If obj.GetTag() = 2 Then obj.SetPos(2,0,True)
If obj.GetTag() = 3 Then obj.SetPos(0,-2,True)
If obj.GetTag() = 4 Then obj.SetPos(0,2,True)
Next

' Update all objects of the engine
eng.Update(d)

' If the SPACE key was pressed, spwan a new shot
If KeyHit(KEY_SPACE) Then SpawnShot()

Return 0
End
'------------------------------------------
Method OnRender:Int()
' Clear the screen
Cls

' Render all visible objects of the engine
eng.Render()

Return 0
End
End

'***************************************
Class engine Extends ftEngine
Method OnObjectUpdate:Int(obj:ftObject)

Return 0
End
End

'***************************************
Function Main:Int()
g = New game
Return 0
End

[/monkeycode]


MikeHart(Posted 2012) [#91]
In your code, you stored only the last bullet. That is why you only react on the last bullet. That is why I set an ID or TAG to an object. All bullets get the same ID. So ask for the ID and your problem should be solved.


MikeHart(Posted 2012) [#92]
Btw. your way of calculating the position makes no sence to me. Is this intentional?


DarkyCrystal(Posted 2012) [#93]
May be it's possible to move the content of the update method in the OnObjectUpdate() method ?

I wonder, I see you use the tag, but what about if we can't know how many object the player can shoot ? For example, I don't know if he will fire 4 times or 10 times.

to answer, that was a simple example, but yes it's intentional, I make some tests to update coordinate myself without use SetSpeed or something like this, just my own calculation.


MikeHart(Posted 2012) [#94]
You don't need to. I was just showing you how you could use a list outside OnObjectUpdate. OnObjectUpdate is called for every active object, internally it itterates through a list of objects already.
Inside the method you need to determine what kind of object it is, or you would modify any object there is.

Your problem was to find out if it is a bullet or not. You had used a field (g.myobjectfire). That can only store 1 bullet, the last one.

As you had checked inside OnObjectUpdate specifically for obj=g.myobjectfire, you will only update the latest bullet.

So, if you need do ANY handling of all bullets there is, give them a specific ID or Tag. It doesn't matter, as both are just integer values. You could even set and the ask for a specific collision group.

So if that object, that is been updated at this very moment, has this ID/TAG/whatever, then do something with it. This way it doesn't matter if you have 1, 10 or 1000 bullets running over the screen.


DarkyCrystal(Posted 2012) [#95]
I understand better, but I wonder how to assign a tag, be sure that there isn't an other bullet with the same.

And question : if we call eng.update() manually, we can do it several time in a program ? or only once in the custom update method ?


MikeHart(Posted 2012) [#96]
Use ftObject.SetTag(value:int) to change the Tag.

Do you need to handle each bullet differently?

Yes, you can use eng.Update as many times you want. If you give it a layer as a parameter, then only objects of that layer will be updated.

The next update of fantomEngine will give you the ability to store user data fields/methods inside the objects via an extra "data" object (class).


DarkyCrystal(Posted 2012) [#97]
No, in fact it doesn't matter for bullets, just want to store severals, but without regarding if there are 1, 2 or 100 bullets, so may be the setTag is not necessary ?

Sorry for my stupid questions ^^


MikeHart(Posted 2012) [#98]
There are no stupid questions. fantomEngine is very powerful but lacks documention. I am aware of this. Also I am very happy that you ask and not just go away.

Like I said, inside OnObjectUpdate, currently you need to identify what kind of object it is. Usually you have several types of objects. Bullets, enemies, whatever. And for sure you handle them differently. To seperate these objects from each other, you can group them via CollisionGroups, ID's or Tags. Choose what fits your style. Or you store the objects you want to handle in fields, arrays or lists and compare them to that. But itterating another list could become slow.

The next update will introduce a data object field inside the ftObject structure. There you can store another class. This class could have different fields and different methods. And these could be used during execution.


DarkyCrystal(Posted 2012) [#99]
oki thank you for your answer :)

An other question please. I see that we can use eng.createImage with a filename.

It's very cool when we have a single image (and not atlas). But if we want to create these at runtime, that consideraly slow down the process (because of file access).

The problem is that we have to use eng.CreateImage with the "atlas" style method instead.

Is there a way to store a sprite in the object like this but without the w/h parameter ?(because this is a single image, and I can't use the eng.CreateImage(filename) at runtime (it's too slow).

Other thing, it seems that the SetAlpha doesn't work with me.

On the update object method, if I write something like :

format_code(' obj.SetAlpha(0.5, True)')

or

format_code(' obj.SetAlpha(obj.GetAlpha() - 0.5) ')

the value seems to change at runtime (test with a print command), but on the screen there isn't any effect.



Thank's


MikeHart(Posted 2012) [#100]
Which platform do you have the problems with? I just tested it here on HTML5 and it works fine. Chrome V23 I used.


MikeHart(Posted 2012) [#101]
About the image thing, here is a variant of ftObject.CreateImage.
Please add this to your ftObject class.

format_code('
'------------------------------------------
Method CreateImage:ftObject(img:Image, xp:Float, yp:Float)
Local obj:ftObject = New ftObject
obj.engine = Self
obj.xPos = xp
obj.yPos = yp
obj.type = otImage
obj.img = img

obj.radius = (Max(obj.img.Height(), obj.img.Width())*1.42)/2.0
obj.w = obj.img.Width()
obj.h = obj.img.Height()

obj.rw = obj.w
obj.rh = obj.h

obj.SetLayer(Self.defaultLayer)
obj.SetActive(Self.defaultActive)
obj.SetVisible(Self.defaultVisible)
obj.collType = ctCircle
obj.internal_RotateSpriteCol(obj)
Return obj
End

')


MikeHart(Posted 2012) [#102]
Please continue to post here:

http://www.monkeycoder.co.nz/Community/posts.php?topic=3976#bottom


DarkyCrystal(Posted 2012) [#103]
Thank's for the routine.

Same here, html 5 and chrome. mmmh may be I do something wrong :p Do we have and additive blend with monkey and your framework ? :)

Ho question again :p (very sorry), for the collision. That works great, but I wonder, how to have more accurate collisions ? because when a player shoot a bullet, and the bullet collide with an object, we can see that the collision is "approximative". May be a method to improve this ?


MikeHart(Posted 2012) [#104]
I will answer your question here. Please continue there too:



http://www.monkeycoder.co.nz/Community/posts.php?topic=3976#bottom