fantomEngine - A 2D game framework
Monkey Forums/User Modules/fantomEngine - A 2D game framework
| ||
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 |
| ||
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. |
| ||
Cool, let me know when you have the review published. |
| ||
Hi Michael, just downloaded the book from my Safari Books Online :-) I'll read it this evening! Good job! |
| ||
Thanks Fabio! |
| ||
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. |
| ||
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? |
| ||
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: 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: 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 |
| ||
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. |
| ||
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: 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. |
| ||
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. |
| ||
@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? |
| ||
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. |
| ||
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? |
| ||
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 :). |
| ||
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. |
| ||
Thank you for your nice comments. I will think about your suggestions. |
| ||
I also made some threads on your fantomEngine forum. |
| ||
Thanks for mentioning the forum. I wasn't visiting them for while due to personal problems. Will go there asap. |
| ||
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 :). |
| ||
@Neuro: cool I have to check your game soon. |
| ||
Is fantomEngine using raycasting for collision? |
| ||
@Neuro, no it doesn't. |
| ||
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. |
| ||
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. |
| ||
Nice! I'm looking forward to this! |
| ||
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. |
| ||
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 :). |
| ||
@Neuro: I hear ya :-) Could you provide a test map? @Snader: You mean downloading images into the data directory? |
| ||
Folks, what do you need regarding documentation/samples/tutorials? |
| ||
@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. |
| ||
@Snader: Sorry, I have no knowledge about how to do this. And it sounds like it would need a modification of mojo. |
| ||
I get an error with the new engine. Error: Identifier 'IsPause' not found. In this line: If isPause = True Then |
| ||
I found out myself. IsPause should be IsPaused And there was an error in this line startTime += difftime should be startTime += diffTime |
| ||
Snader, you could download an image from the web and save it to the target filesystem, then load it normally. |
| ||
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. |
| ||
@TriGaDe: Yip, found these errors too. Sorry. Will be fixed in the next version (this week) plus I mentioned it on google code too. |
| ||
@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. |
| ||
@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. |
| ||
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? |
| ||
Is swipe going to be in the next update to? |
| ||
Maybe, I will try it. Wife is out of town for the weekend and I might have enough time for it. |
| ||
Animating tiles perhaps! Collision if you have not implemented it yet. |
| ||
I am working on the collision atm. |
| ||
Do you have a release time? |
| ||
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. |
| ||
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. |
| ||
Thank you mike! |
| ||
Thanks! Mike you the mann. |
| ||
MikeHart - path finding - it will be the most interesting to me, as a whole did a great job! Thank you so much for this! |
| ||
I can't compile the TileMap example in V1.66 in GLFWTRANS FAILED: TRANS Failed to execute 'xcodebuild -configuration Release', return code=16640 |
| ||
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. |
| ||
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. |
| ||
But it compiles okay for iOS just not GLFW |
| ||
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. :-) |
| ||
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. |
| ||
I have uploaded version 1.45 now. It supports swipe gesture detection with an automatic callback event. Added also the new SwipeDetection sample script. |
| ||
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? |
| ||
A user-editable wiki would be most maintainable... :-) Personally, I don't like PDF docs. HTML is much more navigable and easy to use. |
| ||
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. |
| ||
I was the one asking for example for each command and I don't mind if it in PDF. |
| ||
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... |
| ||
Can the google code wiki be used like that? |
| ||
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 :) |
| ||
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. |
| ||
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 :) |
| ||
You have to load it into an editor and flip it so up is down and down is up. |
| ||
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. |
| ||
oki do a vertical flip if I understand :) I will try and I will say to you if it works :) thank you :) |
| ||
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. |
| ||
Thanks, that is great. I added you as a commiter. |
| ||
I have documented the first example here: http://code.google.com/p/fantomengine/wiki/ActivateSwipe Here is the wiki code for this command. #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. |
| ||
I'll do that |
| ||
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 ? |
| ||
Not that I know of. |
| ||
However, this framework is very usefull :) |
| ||
I use GlyphDesigner with the fantomEngine. |
| ||
If you find a different font tool which you like to support for, please raise your voice. |
| ||
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 :) |
| ||
I will look into it. |
| ||
Nice ! thank's :) |
| ||
nevermind, got it working :) |
| ||
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 : 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). |
| ||
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. |
| ||
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] |
| ||
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. |
| ||
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. |
| ||
If they there is a weird behaviour, then you handle it faulty. Show the code that is not working. |
| ||
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 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... |
| ||
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] |
| ||
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. |
| ||
Btw. your way of calculating the position makes no sence to me. Is this intentional? |
| ||
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. |
| ||
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. |
| ||
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 ? |
| ||
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). |
| ||
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 ^^ |
| ||
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. |
| ||
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 : obj.SetAlpha(0.5, True) or 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 |
| ||
Which platform do you have the problems with? I just tested it here on HTML5 and it works fine. Chrome V23 I used. |
| ||
About the image thing, here is a variant of ftObject.CreateImage. Please add this to your ftObject class. '------------------------------------------ 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 |
| ||
Please continue to post here: http://www.monkeycoder.co.nz/Community/posts.php?topic=3976#bottom |
| ||
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 ? |
| ||
I will answer your question here. Please continue there too: http://www.monkeycoder.co.nz/Community/posts.php?topic=3976#bottom |