fantomEngine - A 2D game framework - part 2

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

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

I have uploaded version 1.46b of fantomEngine. Get it here:

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

Cheers
Michael


MikeHart(Posted 2012) [#2]
A nice new feature of fantomEngine is now that you can store a user data object inside an ftObject. Create your class where you store this info and extra methods and then retrieve it when you need it. Here is an example:

[monkeycode]
Strict

#Rem
Script: UserObjectData.monkey
Description: Sample script that shows how To store any data inside an Object And use it at runtime
Author: Michael Hartlef
Version: 1.0
#End

Import fantomEngine
Global g:game


'***************************************
' This class will store some user defined data fields for our shot objects.
' Here it is the x/y speed factors for each bullet
Class shotData
Field xSpeed:Float
Field ySpeed:Float
End


'***************************************
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])

' Create a new shotData object
Local userData := New shotData

' store the speed values in the data object
userData.xSpeed = (pos[0] - cw/2) / 10
userData.ySpeed = (pos[1] - ch/2) / 10

' Set the data object of the shot object
'shot.SetDataObj(Object(userData))
shot.SetDataObj(userData)

' Set its ID to 222 so we can detect it during the OnObjectUpdate 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(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

' Get the data object, which holds the speed factors for the shot.
Local ud:shotData = shotData(obj.GetDataObj())

'Set the position relatively via the speed factors
obj.SetPos(ud.xSpeed, ud.ySpeed, True)
Endif
Return 0
End
End

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

[/monkeycode]


MikeHart(Posted 2012) [#3]

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 ?




Can you please post a simple example where your alpha changing doesn't work? fantomEngine just uses Mojo's SetAlpha (0.0-1.0) statement. Nothing magical. At the moment, fantomEngine doesn't store the mojo blend mode, but I can add that if you need it.

fantomEngine supports 3 collision types. Circle, BoundedBox and RotatedBox. I plan on adding polygon and pixel perfect collision, but that is still far ahead in my schedule. You can do two things now:

1) play with the sizes of the collision hulls via ftObject.SetRadius. that works also for box type collision checkings.

2) Create "collision" zone objects as a child of your visible object. Check for collisions only on these zone objects and not your visible object.


DarkyCrystal(Posted 2012) [#4]
Thank's for your reply.

For blend, I think it's a must have, especially for particles and explosions created at runtime, add blend give a very good effect for that ;)

For the alpha, I think it is because my object is a very small size, I used SetSize before, that's why I didn't see anything, I think, but I will make a test and if I have the problem I will post the code here :)


MikeHart(Posted 2012) [#5]
Ok, I will put "handling blendmode per object" on the roadmap.


DarkyCrystal(Posted 2012) [#6]
new update is fantastic ^^


MikeHart(Posted 2012) [#7]
And here we go again. Version 1.47 of fantomEngine is available. New important feature are the ability to copy an existing object and setting the blendmode of an object. Also multiline text is now supported. Also it fixed a lot of syntax errors which I found now using reflection for copying the object.


vmakar85(Posted 2012) [#8]
Hi Mike, added blending and transparency for the clouds in the game from the book "dog fight", it came out pretty cool ..


MikeHart(Posted 2012) [#9]
Thanks for letting me know.


MikeHart(Posted 2012) [#10]
Ok, the next version will have a box2D integration of fantomEngine Objects. Please suggest things you would like to see.


vmakar85(Posted 2012) [#11]
one side platform =)


Kauffy(Posted 2012) [#12]
Hi, Mike--

Have enjoyed working my way through your book so far-- it's been a great series of exercises to get back into the mindset.

I know you mentioned a lack of documentation-- and I know Diddy has this issue also-- is there a way using Monkey's documentation feature to generate some quick documentation for fantomEngine? Or do you have some quick docs?

I would just like to know what all the functions are and a little on how to use them where they haven't been covered by example in the book.

Thanks!


MikeHart(Posted 2012) [#13]
Which methods for all classes exist are displayed in the wiki, they are all listed there.

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

Sadly only a few have a documentation. I know I said I would add more docs but as you all know, time, life and things like that get in the way. I wish there would be some kind of system in Monkey, that could build docs from the sources, like we had that with BlitzMax. But I know don't of any with Monkey.

Feel free to join my forum and ask away there so we don't splatter this forum here.


Amon(Posted 2012) [#14]
I keep getting this error and can't proceed with my game. I'm using monkey 66 and fantomEngine 1.47 with JungleIDE!

format_code('
Monkey Runtime Error : TypeError: Error #1009

C:/Apps/Coding/MonkeyPro66/modules/fantomEngine/cftEngine.monkey<571>

')

It points also to this line in my code:
format_code('
map1 = eng.CreateTileMap("maps/map1.json", 64, 64)
')

Compiling to glfw shows up the following error!

format_code('
Monkey Runtime Error: Type Error: Cannot call method 'm_Frames' of null.
')


MikeHart(Posted 2012) [#15]
Did it work with fantomEngine 1.46? Does it work in HTML5? Does the example TileMap.monkey work for you?

It complains that it can't read the Frames count of the image from your tile map. Means basically that it didn't load the image for it. If you didn't got this error in 1.46, I would appreciate it if you could provide the map file and the images for it.


Tri|Ga|De(Posted 2012) [#16]
@Amon

Do you have your image in the data folder with your json file.
I also using the TileMap function and its working fine for me.
But I'm not on the newest fantomEngine, think I'm on 1.46

@MikeHart
B.t.w. When I have finished my latest game I'll take some time to update the fantomEngine Wiki.


MikeHart(Posted 2012) [#17]
Ok, I think I know whta is the problem. You have the map inside a sub folder in your data folder.

Here is a quick fix. Please backup your cftEngine.monkey file first:

Find Method CreateTileMap:ftObject(fname:string, startX:Float, startY:Float )
Change its top like this:

format_code('
Method CreateTileMap:ftObject(fname:string, startX:Float, startY:Float )
Local obj:ftObject = New ftObject
Local imgH:Int
Local imgW:int
Local tlH:Int
Local tlW:Int
'>>>>>>>>> Add this>>>>>>>>>>>>>>>>>>
Local path:String =""
If fname.Find("/") > -1 Then
Local pl:= fname.Split("/")
For Local pi:= 0 To (pl.Length()-2)
path = path + pl[pi]+"/"
Next
Endif
'<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
')

Then search for

obj.img = LoadImage(dataTileSet.GetItem("image")


and exchange this

format_code('
'>>>>>>>>>>>>>> Change this >>>>>>>>>>>>>>>>
'obj.img = LoadImage(dataTileSet.GetItem("image"), tlW, tlH, (imgH/tlH)*(imgW/tlW), Image.MidHandle)
obj.img = LoadImage(path + dataTileSet.GetItem("image"), tlW, tlH, (imgH/tlH)*(imgW/tlW), Image.MidHandle)
'<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

')


MikeHart(Posted 2012) [#18]
@TriGaDe: No problem, I understand and can relate to not having time for this :-)


Amon(Posted 2012) [#19]
Hi! Thanks for the advice. Yes the json file and the image were in the data folder but in their own folder called maps.

When moving them to the root of the data folder it all seems to work fine now.

[edit] Ahh! you found a fix! :) Thank you Mike, I will implement that now and let you know if the fix works.


Amon(Posted 2012) [#20]
Hi! It worked but not this bit.

format_code('
obj.img = Self.LoadImage(dataTileSet.GetItem("image")
')

That line in my 1.47 version doesn't have 'Self' before LoadImage. I did modify the line to just add ' path + ' and it is working now i.e. loading maps from subdirectories in the data folder.


MikeHart(Posted 2012) [#21]
Right, I forgot that I had added an image management inside FE so images don't get loaded twice. Sorry for the confusion.


Kauffy(Posted 2012) [#22]
@MikeHart--

I guess Monkey doesn't have a built-in doc system, but Jungle IDE does.
If a declaration (class/method/function?)is preceded by a comment (either line or block) beginning with the keyword "summary:" (without quotes, then it will autobuild the documentation).


Kauffy(Posted 2012) [#23]
I never worked with Blitz, but having seen its documentation a bit, this does look to generate something very similar.

'Summary: Basic Game class where all the magic happens.
Class Game Extends DiddyApp
.
.
.

That will get compiled into documentation.


MikeHart(Posted 2012) [#24]
i am a OSX user so Jungle is out of question for me. i will concentrate on the wiki right now. does that doc thing work in the free version of jungle too?


ziggy(Posted 2012) [#25]
@MikeHart: Yes it does work on the free version. I would help if anyone wants to write a standalone monkey version of this tool so it can be used from commandline into a Mac or windows computer.


MikeHart(Posted 2012) [#26]
Hi ziggy, Kauffy had mentioned what is needed to build docs for jungle inside the sources. But doesn't seem to be all. Can you provide a small sample on how things can be formatted? And where do I have to make comments inside the sources?


ziggy(Posted 2012) [#27]
Of course, you can see some small brief documentation here:
http://www.jungleide.com/docs/Creatingdocumentationformodule.html

And you can see the fontmachine module is fully documented (download here: http://www.jungleide.com/fontmachine/fontmachine-12-07-19-A.zip )

this is a small sample:

format_codebox('#rem
header:This module contains the DrawingPoint class.
This class is a simple X and Y vector.
#end


'summary: This class represents a simple X and Y vector
Class DrawingPoint
'summary: This field contains the X location of this point.
Field x:Float
'summary: This field contains the Y location of this point.
Field y:Float
'summary: This method returns a string with a representation of the vector contents.
Method DebugString:String() ; Return "(" + x + ", " + y + ")" ; End
End


#rem
footer:This FontMachine library is released under the MIT license:
Copyright (c) 2011 Manel Ibáñez

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

#end')

When you generate a HTML output for your documentation, notice that documentation will be generated "on cascade" that is, if a class does not have a summary, it won't be documented when you generate a HTML version of the documentation.

If you generate a HTML version of your documentation, your module users will get the appropiate documentation displayed when they press F1 on any of your module defined "keywords".

Header and footer are optional.


MikeHart(Posted 2012) [#28]
Ziggy, thanks for the info.


Kauffy(Posted 2012) [#29]
Yes, this documentation thing is FANTASTIC! I'm using it religiously within my own code and then I pop open my own docs while working on the code, just to keep everything straight.


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

as Kauffy needed some fixes I have uploaded a preview of Version 1.48 which includes the fixes and also all the new stuff.

Waypoints and Box2D are in no way settled. If you want to use what is there, then it might be a subject of change. Mainly in how much it will be integrated into the ftEngine class and which event handler methods are called and in which class they are. Plus both classes need more methods. But you can see where it goes.

Btw. for the Box2D stuff, you need this module:

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

Cheers
Michael


Amon(Posted 2012) [#31]
Good Stuff, Thanks!


MikeHart(Posted 2012) [#32]
@ziggy: Your documentation output is really nice. I like how it is displayed. Makes me think that an autogenerated documentation from source code is really the best way to do it.


ziggy(Posted 2012) [#33]
@MikeHart: Thanks for the feedback! I use it all the time when I work with more people and also on my modules.


Kauffy(Posted 2012) [#34]
@MikeHart--

Just saw this post! Thanks for the updates. I will download now.

I also have a question about removing an object from its parent.

I am using the SetParent feature to have one of my tanks pick up an object and then tow the object behind it, but when the tank is destroyed, I want to leave the object behind.

It looks like I can do this "by hand", by clearing the childNode node and setting the Parent object to Null, but it does not behave as expected-- instead, it seems like the child object disappears when the parent does, even though I have "disconnected them" first.

Does this make sense? (gob is always an ftObject contained by my objects)

format_code('
Method Drop:Void()
If Self.towedItem <> Null Then
Local droppedBooty:Booty = Self.towedItem
Self.towedItem = Null
droppedBooty.gob.parentNode.Remove()
droppedBooty.gob.parentObj = Null
Booty.AddToLoose(droppedBooty)
droppedBooty.gob.SetVisible(True)
droppedBooty.gob.SetActive(True)
'Print "Dropped Booty at " + droppedBooty.gob.GetPosX() + "," + droppedBooty.gob.GetPosY()
droppedBooty.gob.SetLayer(layGame)

End If

End Method
')


MikeHart(Posted 2012) [#35]
You are right, there is no method for this atm.

I will enhance the SetParent method so you can use NULL here too:

[monkeycode]
Method SetParent:Void(newParent:ftObject)
If Self.parentObj <> Null Then
'Self.parentObj.childObjList.Remove(Self)
Self.parentNode.Remove() '1.2.1
Endif
If newParent <> Null Then
Self.parentNode = newParent.childObjList.AddLast(Self)
Else
Self.parentNode = Null
Endif
Self.parentObj = newParent
End
[/monkeycode]

So, to remove a child from its parent, just do
[monkeycode]child.SetParent(Null)[/monkeycode]


Kauffy(Posted 2012) [#36]
I am using basically that code right now, though, and the child object disappears at the time I "unhook" it. Does that make sense?

I will try it with your exact code in ftE.


MikeHart(Posted 2012) [#37]
Well, then you don't have it correctly connected into a layer or something you did with your customization. If it disappears, that means it was GCed.

I have tested the method with a small example and when you press P you can disconnect the child from the parent without a problem and it is still visible.

[monkeycode]Strict

#rem
Script: ParentChild.monkey
Description: Sample script to show how to use parent/child relationships.
Author: Michael Hartlef
Version: 1.0
#End

' Import the fantomEngine framework which imports mojo itself
Import fantomEngine

' The g variable holds an instance to the game class
Global g:game


'***************************************
' The game class controls the app
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 field that hold the parent
Field parent:ftObject = Null

'------------------------------------------
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

' Create the parent
parent = eng.CreateCircle(20,200,200)

' Create the child and set its parent
Local child := eng.CreateBox(10,20,100,100)
child.SetParent(parent)

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
Local child:ftObject = Null

' If the parent has children, get teh first child
If parent.GetChildCount()>0 Then
child = parent.GetChild(1)
Endif

' Set the parents position accordingly to the mouse coordinates
parent.SetPos(eng.GetTouchX(), eng.GetTouchY())

' If there is a child, chekc for the P-Key and disconnect it from the parent
If child <> Null Then
If KeyHit(KEY_P) Then
If child.GetParent()<>Null Then
child.SetParent(Null)
Endif
Endif
Endif

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

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

'***************************************
' The engine class extends the ftEngine class to override the On... methods
Class engine Extends ftEngine
'...
End

'***************************************
Function Main:Int()
' Create an instance of the game class and store it inside the global var 'g'
g = New game

Return 0
End

[/monkeycode]


Kauffy(Posted 2012) [#38]
Truly above-and-beyond.. and you were correct.

I had a leftover .Remove() that was called above any of the code, so the parent and children were getting removed before the disconnection.

Is there a place for feature requests OR can the source be committed to if I make what I think to be a useful change?

For example, you can add permanent spin to an object, so similarly, I'd like to add pulse (where it continuously cycles its size).

I could see a lot of effects that could be added this way.


Kauffy(Posted 2012) [#39]
By the way, the negative speed code works as expected now-- my tank no-longer bounces when going in reverse EXCEPT if it's also turning. That is, if I am reversing and attempting to turn, it bounces just like it did when just reversing the speed.

Is this an issue with speedAngle?


MikeHart(Posted 2012) [#40]
Could be. Thinking about it now, that is why it made no sence to have negative speed. Speed was always positive, just the direction needed to be changed. Well, I will look into it when I find time.

Without some test code it will be difficult to reproduce anyway.


MikeHart(Posted 2012) [#41]
About the request. You can use my forum, or the issues board on google code.


Kauffy(Posted 2012) [#42]
I agree that speed is always positive on its own, but given a specific facing, you are either moving in the direction you are facing, or moving away from it.

To me, the heading is the angle you are moving along while facing is the angle you are pointed toward.

You could be faced toward a given angle and either be moving toward it or moving away from it.

For example, if I am moving toward New York (my facing is New York), I could either be moving at +5 miles per hour (each hour, I am 5 miles closer) or I could move at -5 miles per hour (each hour, I am 5 miles further).

This model makes sense to me when playing with vehicles just because it keeps the driving simple-- I can either add speed or subtract speed, ignore heading, and then just deal with the facing. It behaves predictably.


MikeHart(Posted 2012) [#43]
You are right. I guess i have to rework the angle part.


Kauffy(Posted 2012) [#44]
Another question-- this one relating to time!

Is the timescale on which ftEngine runs fixed to the Millisecs() clock, or is it scalable?

It would APPEAR that when you call it with the delta time, the default baseScript uses the Millsecs() delta, but you could substitute any number for that (presumably another clock, for example).

HOWEVER, I see a few places where Millsecs() is used to assign a value to a variable called "time" within the engine.

I am now working on my next project, and it became clear that I needed a way to manage time that could be both scaled and paused, but if I based my game-world events on Millsecs() alone, I would be in trouble. The situation is also the same under isSuspended-- the engine Update is not called, but doesn't time still march on?

So I wrote a kgClock class that lets me define a clock in terms of its relationship to Millisecs and then I just call Updates periodically, which check Millisecs() and then scale the value both according to the base scale and the current play scale, meaning I can define a clock as being 1000:1 (1 unit on my clock is 1,000) millisecs and THEN I can adjust the speed with which time passes (1.0, .5, 2.5, etc.).

Unfortunately, if the rendering part underneath doesn't like that, then I have a lot of work to do. :)

I could certainly test it, though I thought it might be simpler to ask whether you had designed the engine with this in mind or not, rather than test each object and each case, etc.

Thanks, as always!


MikeHart(Posted 2012) [#45]
You are right. Where it comes to timers, the engine is fixed on milliseconds. The update speed is variable. And you are right that the enigne doesn't handle the suspend state correctly in these timer controlled events. Consider this a bug, I have to fix this.


Kauffy(Posted 2012) [#46]
Hmm. I guess there's a decision for me to make. :)

The clock class I wrote hasn't been tested but wasn't that complicated. It allows for pausing, and then as long as all events are keyed to this other clock, it should behave according to this timescale.

I have started assembling a little bit of a framework that includes ftEngine and Diddy-- then I add in functions and classes that either extend or wrap the stuff beneath to make it easier for me to use. It's called Kauffy Grounds (that's the kg).

format_codebox('
#REM
Summary:
A collection of classes and functions for working with time and timescales.

For example, when game time is not analogous to real-time (you want to use time units other than millisecs, or you want to stop time advancing when you pause)
or you want to be able to alter time scale.
#END

Import kauffygrounds

Class kgClock
Private
Field time:Int
Field baseScale:Float 'Summary: Ratio of Millisecs to kgUnits. A value of 1000 here means 1 kgUnit passes per second.
Field playScale:Float 'Summary: Ratio of passage of time to 'normal' as defined above.
Field lastUpdated:Int 'Summary: Time in Millisecs the kgClock was last updated.
Field lastPaused:Int 'Summary: Time in Millisecs the kgClock was paused.
Field isPaused:Bool 'Summary: Is kgClock time paused from advancing?

Public
Method New(newTime:Int = 0, newScale:Int = 100, startPaused:Bool = False) 'Default to a fresh clock, and default to tenths of a second.
Self.time = newTime
Self.baseScale = newScale
Self.playScale = 1.0
If startPaused = True Then
Self.lastPaused = Millisecs
Self.isPaused = True
Else
Self.isPaused = False
End If
Self.lastUpdated = Millisecs
End Method

Method Update:Void()
If Self.isPaused = True Then Return
Self.time = Self.time + ( ( (Millisecs - Self.lastUpdated) / Self.baseScale) * Self.playScale)
Return
End Method

Method Pause:Void()
If Self.isPaused = True Then Return
Self.Update() 'One last call to Update to make sure we captured everything.
Self.isPaused = True
End Method

Method Unpause:Void()
If Self.isPaused = False Then Return
Self.isPaused = False
End Method

Method TogglePause:Void()
If Self.isPaused = True Then
Self.Unpause()
Else
Self.Pause()
End If
End Method

Method IsPaused:Bool()
Return Self.isPaused
End Method

Method PlayScale:Void(newPlayScale:Float) Property
If newPlayScale = 0 Then Return
Self.playScale = newPlayScale
End Method

Method PlayScale:Float() Property
Return Self.playScale
End Method
End Class
')


MikeHart(Posted 2013) [#47]
Ok, next version will support pausing updating of objects, timers and transitions with a single call to ftEngine.SetPause(True).


ondesic(Posted 2013) [#48]
Mike,

When you copy an object, does it just point to the original image (saving memory), or does it use memory to create real copy of the original image?


Kauffy(Posted 2013) [#49]
@ondesic:

The image used should be recycled, if I understand how the LoadImage works-- so yes, it saves memory. In fact, I think even if you Load an image multiple times, it is only loaded once.

@Mike:

What about changing timescale? That's important-- for both fast-forward and slow-mo.


MikeHart(Posted 2013) [#50]
What do you mean by changing time scale regarding timers and transitions. Do you mean that a timer that should fire in 3 seconds should fire earlier or later because you change the time scale?


MikeHart(Posted 2013) [#51]
Yes, according to Mark, it will be using the same image. The new version of fantomEngine even has an image managment that makes sure that an image is used really just once.


Kauffy(Posted 2013) [#52]
Yes, Mike-- I mean changing the timescale for everything, so that everything happens faster or slower according to the timescale.

So you would have the rendering engine work off of an independent clock, as opposed to the Millisecs clock and each time the engine is called, it is called with the independent clock time, rather than real Millisecs.

If everything (movement, transitions, animations, etc.) are keyed to that clock, then the clock not advancing should logically freeze movement. And the clock advancing faster or slower should logically speed up or slow down movement.

If we set up an alternate clock to treat milliseconds as millseconds (base scale of 1:1), then in your example, you'd set a timer to fire in 3000 Alternate Clock Millisecs (ACM). If you pause the clock, the timer doesn't advance (Millisecs() will keep moving, but we're not keyed to it)-- so the timer won't fire until a total of 3000 unpaused ACM have elapsed.

In the same way, if the timescale were set to 2x, 3000 ACM would elapse in 1500 Millisecs().

And, if the timescale were set to .5x, 3000 ACM would elapse in 6000 Millisecs().

If you can imagine everything keyed to the ACM-time, then all animation, all movement, all timers, all transitions, etc., etc., etc. should behave in-kind.

Please, correct me if I'm wrong.

I was just giving this a lot of thought because I have ideas for things that will require "real" pause and would likely benefit from adjustable timescale. Think of the fast-forward button in a tower defense game, or the gameplay workflow of spacebar-pause -> issue orders -> spacebar-unpause, or even just the eyecandy effect of going slow-mo/super slow-mo during a particularly complex and gratifying series of explosions.


ondesic(Posted 2013) [#53]
Mike,

I am not fond of the MidHandle flag that CreateImage, CreateAnimImage and CreateTileMap have. I rarely calculate from the center. I have manually changed this in your engine, but there are so many places to change that it is daunting to redo this with every update. There is one overload for CreateImage that you have implimented that allows the user to decide where the handle will be. Could you please include this in the other methods mentioned above? THANKS!

ps. I sent you an email with some bug fixes in it. Just wondering if you got it. From Ondesic


MikeHart(Posted 2013) [#54]
@ondesic: Yes, I can got it. I will see what I can do.

@Kauffy: I will see how I can add a time scale to the engine. Will require some rewriting of the timer and transition mechanism.

To all, please be aware that if a request breaks the compatibilty with my book, then I can't add it. I always have to keep in mind, that a change should not break anything regarding the book.


Kauffy(Posted 2013) [#55]
@Mike: That would be great.

For book-compatibility purposes, you could add a link at code.google.com/p/fantomengine that clearly identifies the book-intended version, though, I agree, as long as the original calls in the in-book source still behave as normal, functionality could be extended around them.

I just did a quick look for all of the occurrences of Millisecs() in all of FTEngine's source files (including Box2D and the JSON stuff).

It appears only in cftEngine-- and it would seem, just cursorily, that just some of those calls to Millisecs could be replaced with calls to the alternate clock-- though my clock, as currently designed, would only work if the clock being used were set to Millisecs. (One of the calls is for calculating FPS, so that should remain Millisecs(), too).

It also appears in cftSwipe, but I would imagine it should remain Millisecs() in that location.

And since I'm making it sound so incredibly simple, I'll just go ahead and try it. :)

Pushing ftEngine into source control nowwww....

[EDIT]

Okay, made the changes to the engine-- I added the clock object to the engine itself, added the calls to the clock Update to the engine's Update calls at the top, and then replaced the appropriate calls to Millisecs() to calls to the clock.GetTime(), and tested it with my tank game.

I actually had a lot more work to do in my own code than I did in ftEngine where my AI is heavily time-based.

It's uncanny how much it works like expected. I mapped a P)ause, then .5x, 1x, 2x speed to keys and I can alter the speed on the fly.

I had to make a lot of modifications to my AI that did stuff based on the elapse of time and the only "problems" I've noticed is that my AI behaves differently at 2x speed than it does at 1x speed and some activities still continue even when the game is paused, but I think that is because some of my code wasn't tied to clock, and I still make all my calls, even when things are paused.

Additionally, the ftEngine itself doesn't have a state of "pause", I guess, so some things still continue-- like I notice some of my objects continue to rotate for a moment after a pause is called and then there is a bunch of debug drawing that is still happening. Or that may actually be that I am manually setting the object angles incrementally and the Engine itself has no choice but to render them-- I think that's actually what's going on. :)

Still, a hugely promising first step! I think this gives me enough to work with!

[EDIT #2]
I get the difference in behavior now-- it is definitely how my code is written and not the engine. My object rotation (vehicle turns) are not done in-Engine (as I thought) and are not scaled to delta time or anything-- they get called regardless of the pause state of the engine and its my code that actually does the turning, regardless of the clock.

Which means the engine clock implementation deserves more testing, certainly, but that it sounds like this works.

Now I just have to figure out what I have to do in my code in this next project to make it work as expected.

[EDIT #3]
I modified my clock class to set the current PlayScale to 0 when paused, then added the PlayScale as a factor in calculating acceleration/deceleration/turn left/turn right and now all the turning/moving behaves as expected, regardless of the speed.


MikeHart(Posted 2013) [#56]
I think i will create its own GetTime method which will be scalable and also that you can overwrite easily with you own implementation. This way i don't need to modify timers and transitions, just exchange the Millisecs calls.


Kauffy(Posted 2013) [#57]
Yes. It became clear to me that for my clock class, I have to at least have one clock that is in Millisecs anyway just to support pause and timescaling with things that rely on Millisecs.

But adding other clocks that measure in different units will allow game-world time keeping on whatever scale is appropriate. I'm looking at that now.

And even more ambitious, you could assign different clocks to different groups of objects (or layers). Like a powerup that slows down enemies..


MikeHart(Posted 2013) [#58]
Uploaded version 1.48 final just a few minutes ago. Biggest changes are time scaling, Jungle-IDE style documentation, shipping with premade HTML docs.

If you still have issues/bugs with it, please let me know if I forgot something.


Neuro(Posted 2013) [#59]
Haven't checked out the newest updates to fantom for a few months now, but wow...looks great Mike! Gonna have to play catch up now..


MikeHart(Posted 2013) [#60]
Thanks Neuro, next update will hopefully include final path/waypoint management including A* pathfinding. After that it will be finalizing Box2D integration. Also I wanna convert the game editor I had created for Gideros one time to output stuff for fantomEngine.


Kauffy(Posted 2013) [#61]
DISREGARD THIS WHOLE POST :)

Hey, Mike--

Something I've noticed is that ftEngine seems to completely ignore an ftObject's scale settings when returning Height and Width. This makes sense when scaling the matrix or world-drawing settings, but at the object level, it seems more expected that the ftObject would report its size including factoring in its own scaling.

For example, if I create a text object that winds up with a raw size of 200x30, but then I set the scale X to .50, when I query its size, it should return 100x30.

I ran into this in my last project, too, where I was using art objects from different sets, but then just adding appropriate scale to them at the time they were instantiated to make them look right. ftEngine, though, still seemed to relate to them at the size the underlying image is.

I'm running into this now where I'm creating a bunch of text buttons, but I'm scaling the resulting text object-- unfortunately, for my layout code, the height/width reported for the object doesn't reflect its actual scaled size, but the size it was originally, meaning I'm having to fudge a lot to get the text to layout out automatically.

I am going to insert a "fix" for this into my copy of ftEngine and see if that improves things without breaking anything else.

[EDIT]

Just checked the code and it does include the scale as a factor-- so now I'm confused as to why it doesn't seem to be reporting expected values. I will look at it further.


Kauffy(Posted 2013) [#62]
NOW I figured it out. Nothing needs to be done with this.


MikeHart(Posted 2013) [#63]
Hi Kauffy,

I am glad you figured it out.

Michael


Tri|Ga|De(Posted 2013) [#64]
Mike?

Do you have some other Box2D examples besides the one that comes with your engine?


MikeHart(Posted 2013) [#65]
no, and the code is mostly about to change and still lacks a lot of functionality.


MikeHart(Posted 2013) [#66]
btw. jugglesoccerball uses box2d too.


Tri|Ga|De(Posted 2013) [#67]
Thanks I'll look at that juggle example.


RobB(Posted 2013) [#68]
[Never mind, thanks. It was simple, and I should have figured it out before. I just needed to use "ftObject" instead of "Image" and "engine.CreateImage()" instead of "LoadImage()".]
Mike,

In the bananas examples that come with Monkey, gerryq has an example called picpuzzle.monkey. I would like to load images as ftObjects into an image array as he does: [monkeycode]Field pictures:Image[] ' a set of 480x480 images (padded to power of two is best, some devices want that)

Field picture:Image ' the current image[/monkeycode]

Then he loads all the images numerically into an array like this:
[monkeycode]
' Load all images with names pic000.jpg, pic001.jpg etc.
Local pictureList:List< Image > = New List< Image >
For Local count:Int = 0 Until 1000
Const ZERO:Int = 48
Local chars:Int[] = New Int[ 3 ]
Local val:Int = count
chars[ 2 ] = ZERO + val Mod 10
val /= 10
chars[ 1 ] = ZERO + val Mod 10
val /= 10
chars[ 0 ] = ZERO + val Mod 10
Local name:String = "pic" + String.FromChars( chars ) + ".jpg"
Local pic:Image = LoadImage( name )
If pic <> Null
pictureList.AddLast( pic )
Else
Exit
End
Next
pictures = pictureList.ToArray()
If pictures.Length() < 1
Error( "No pictures found!" )
End

picture = pictures[ 0 ]
[/monkeycode]

I would like to set up a similar array, but with the images in an array as ftObjects, so I can manipulate each image with Fantom Engine. But I can't figure out how to make an image array that contains the images as ftObjects. If this can be done, would you be so kind as to modify the above code to show me how to do it with images as ftObjects?

Thanks.


RobB(Posted 2013) [#69]
[deleted]


MikeHart(Posted 2013) [#70]
Hi Rob,

I am fighting the flu atm and so once I am back in shape and my brain works right, I will look into this.

Michael


RobB(Posted 2013) [#71]
Never mind, Mike. All I needed to do was change "Image" to "ftObject" and use your engine.CreateImage() instead of LoadImage() . Hope you're feeling better.


MikeHart(Posted 2013) [#72]
Glad you got it working. I was busy with payed artwork the last days so i had no time to look into this. Sorry.


MikeHart(Posted 2013) [#73]
For future development news about fE, please visit its google code space. For support, post there under issues or at the support forum I have build up long time ago.


MikeHart(Posted 2013) [#74]
Working on some tutorials atm. What kind of woukd you like to see?


Isrex(Posted 2013) [#75]
It would be awesome to have a simple platform tutorial.
Thanks Mike!


MikeHart(Posted 2013) [#76]
You mean how to create a platformer game?


Isrex(Posted 2013) [#77]
Yes,please, that would be great!


armornick(Posted 2013) [#78]
I'd also like to see some tutorials for a complete game. While your current examples are quite helpful, it doesn't really show how to make a game with multiple screens or more complex object behavior using your engine.


MikeHart(Posted 2013) [#79]
Please define "more complex object behaviour".


armornick(Posted 2013) [#80]
For example, jumping behavior requires a mix of gravity (downward speed), the jump itself (upward speed) and stopping ascend/descend when the ground or ceiling is hit.

I have some ideas on how to implement this using fantom but maybe it'd be useful to see how you, as the creator of the engine, would do it.

As a side-question, am I correct in understanding that you could have multiple engines in the same game? (for multiple game states, for example)


MikeHart(Posted 2013) [#81]
Using multiply engines... mmmh, never heard about it. Strange but could be done for sure. Personally I create layers for each section. A menu layer, a highscore list layer, etc etc. But yes, you could do that.

A game engine, a menu engine. you just need to make sure that you will update and render them when needed.

Thanks for the suggestions about the behaviour. I will write something about it when the time comes. The platformer example is a good topic for the tutorial series. :-)


armornick(Posted 2013) [#82]
Oh, that's interesting to hear. I suppose there isn't a simple way to make one layer active and disable all others? In any case, a tutorial featuring an explanation on how to do multiple game states using your engine would be very much appreciated.


MikeHart(Posted 2013) [#83]
I my series over the next weeks I will show you how to do this.


Isrex(Posted 2013) [#84]
Awesome, thanks Mike!!


ordigdug(Posted 2013) [#85]
:)


MikeHart(Posted 2013) [#86]
If you didn't see it, part 2 was published.

And I will use the suggestion to create a platformer as a sample game along the road. But first I wanna cover the basics of fE.


ordigdug(Posted 2013) [#87]
Thanks Mike.


MikeHart(Posted 2013) [#88]
Version 1.49 released. A* path finding, transition tweening and other little bits and pieces. http://www.whiteskygames.com/?p=372


Tri|Ga|De(Posted 2013) [#89]
Nice one Mike.


vmakar85(Posted 2013) [#90]
MikeHart greate job ! a* that's what I needed. many tnx


DarkyCrystal(Posted 2013) [#91]
Hello, just have a simply question because, there is some times I don't follow here, I read changes log but about Bitmap Font, I remember that there was a project for FE to be able to use other bitmap font editor than hiero. is there anyone today that I can use with FE, but other than hiero that have some problems with 64 bits java edition ?

Thank in advance, and sorry for my aprox english ^^


MikeHart(Posted 2013) [#92]
I think Angelcode's bitmap font editor is usable on windows:

http://www.angelcode.com/products/bmfont/


Landon(Posted 2013) [#93]
I didn;t see whether it was a possibility or not, but in Tiled i can make a polyline in an objects layer. is there anyway to pull a way point from that data? in JSON it looks like this

format_code('
"height":100,
"name":"Object Layer 1",
"objects":[
{
"height":189,
"name":"dtfthdh",
"properties":
{

},
"type":"",
"visible":false,
"width":137,
"x":745,
"y":85
},
{
"height":0,
"name":"dhdhdh",
"polyline":[
{
"x":0,
"y":0
},
{
"x":-36,
"y":124
},
{
"x":144,
"y":254
},
{
"x":11,
"y":331
},
{
"x":-116,
"y":299
},
{
"x":-313,
"y":322
},
{
"x":-529,
"y":218
},
{
"x":-1,
"y":5
},
{
"x":-1,
"y":-2
},
{
"x":3,
"y":-2
}],
"properties":
{

},
"type":"",
"visible":true,
"width":0,
"x":966,
"y":85
}],
"opacity":1,
"type":"objectgroup",
"visible":true,
"width":100,
"x":0,
"y":0
}],
')

Each node i the polyline could be a waypoint. i noticed i can grab the object layer but i didn't see where i can retrieve that data to create a waypoint myself.


MikeHart(Posted 2013) [#94]
right now you can nly try to parse that file yourself. But i think it would be a great addition. Please provide me a sample file and I will see that you ge that ability in fE.


MikeHart(Posted 2013) [#95]
Btw. I relocated all fantomEngine/Monkey related blogging, tutorials, etc. to this domain:

http://www.fantomgl.com/

Why? Because I want to keep my development tools related stuff separate from the games I develop.

For version 1, google code will still be main place to download any new version. I might switch that too in the near future.

Cheers
Michael


MikeHart(Posted 2013) [#96]
Okey!!!

fantomEngine Version 1.50 released. This time with official Box2D integration and some other small goodies. the size increased as I am shipping the documentation tools with it also in executable form. When you let the patcher tool running, you can get F1 help from within TED now!


Landon(Posted 2013) [#97]
It's not elegant yet.. but i wrote a small parser that pulls the polyline data from a tiled map and converts it to a waypoint.





format_code('
Import fantomEngine

Class mapobjs

Field ojtype:Int
Field pathobj:= New List<ftPath>
Field zone:= New List<ftObject>


Method Parsemap(filename:String,eng:ftEngine)
Local path:String =""


If filename.Find("/") > -1 Then
Local pl:= filename.Split("/")
For Local pi:= 0 To (pl.Length()-2)
path = path + pl[pi]+"/"
Next
Endif

Local fileData:String = LoadString(filename)
Local jsonData:JSONDataItem = JSONData.ReadJSON(fileData)
Local jsonObject:JSONObject = JSONObject(jsonData)


Local layerObjects:JSONArray = JSONArray(jsonObject.GetItem("layers"))
Local tc:Int = 0

For Local layer:JSONDataItem = Eachin layerObjects
Local layerData:JSONObject = JSONObject(layer)

Local mapobjs:JSONArray = JSONArray(layerData.GetItem("objects"))
If mapobjs = Null Then Continue
For Local mobj:JSONDataItem = Eachin mapobjs
Local mapobjects:JSONObject = JSONObject(mobj)
Local plines:JSONArray = JSONArray(mapobjects.GetItem("polyline"))
If plines <> Null


Local path:ftPath = eng.CreatePath(JSONInteger(mapobjects.GetItem("x")),JSONInteger(mapobjects.GetItem("y")))
For Local pl:JSONDataItem = Eachin plines
Local polyl:JSONObject = JSONObject(pl)
path.AddWP( JSONInteger(polyl.GetItem("x")),JSONInteger(polyl.GetItem("y")), True)
Print "Path node: x: "+polyl.GetItem("x")+" y: "+polyl.GetItem("y")
Next
Local mk:ftMarker
mk = path.CreateMarker()
'debug path

mk.ConnectObj(eng.CreateImage("CarSprite.png",0,0))
mk.SetMoveMode(path.mmCircle)
Self.pathobj.AddLast(path)
Else

Local x:int = JSONInteger(mapobjects.GetItem("x"))
Local y:int = JSONInteger(mapobjects.GetItem("y"))
Local w:int = JSONInteger(mapobjects.GetItem("width"))
Local h:Int = JSONInteger(mapobjects.GetItem("height"))
Local mzone:ftObject = eng.CreateZoneBox(w, h, x, y)
Self.zone.AddLast(mzone)
Endif

next

Next




End
End

')


RobB(Posted 2013) [#98]
Our iPad app made with Fantom Engine is coming along great. Thanks, Mike!


MikeHart(Posted 2013) [#99]
Hey RobB, that is great to hear. What kind of game is it?

Landon, I was going to add this next. But thanks for the code piece. If it is Ok with you, I would like to integrate it somehow into fantomEngine.


muddy_shoes(Posted 2013) [#100]
Just a quick comment on the JSON lib use in lines like:

format_code('
Local x:int = JSONInteger(mapobjects.GetItem("x"))
')

When retrieving primitive types you don't have to cast the JSONDataItem reference. The unboxing operations are declared on the JSONDataItem so you can just do:

format_code('
Local x:int = mapobjects.GetItem("x")
')

Casting is only necessary when you're dealing with JSONObject or JSONArray types.


MikeHart(Posted 2013) [#101]
Thanks for the info.


Landon(Posted 2013) [#102]
Ah cool i'll keep that in mind.

@Mike, ya man go for it. i did have to make a slight change in the tilemap loading portion of the cftEgnine

format_code('
Local mapTiles:JSONArray = JSONArray(layerData.GetItem("data"))
If mapTiles <> Null then <------ added condition
')

The engine crashes if it runs into an object unless you tell it to skip this part if it's not maptiles


cool thing is i got a working tower defense game using the FE, using polylines for enemy paths and boxes for zones i can use the data to tell the engine where i can and cannot place towers.

here is the current incarnation of the TD game




MikeHart(Posted 2013) [#103]
Cool man, I like it! I will use your code and make it a little more generic. thanks for the contribution.


Landon(Posted 2013) [#104]
now with lightning and ooze towers mwhahaha




MikeHart(Posted 2013) [#105]
How do you create the lightning?


Landon(Posted 2013) [#106]
i used some old code from blitzmax that was on the code archives.


http://www.blitzbasic.com/codearcs/codearcs.php?code=485


MikeHart(Posted 2013) [#107]
What I ment was, is the lighting some kind of ftObject or did you draw them differently?


Landon(Posted 2013) [#108]
oh i drew them differently, i plan on extending an ftObject for it, but i was lazy at the time. Right now the lightning overlaps the UI.. lol


Why0Why(Posted 2013) [#109]
I have a question. I have the book and the most recent version of fantom. I would like to see some sample code that displays a simple png file that is assigned to an ftObject on the screen. I am trying to do some simple tests and I keep getting null objects no matter how I do it. I have tried assigning using eng.createimage, using both an atlas and solo. I have tried creating a new object and using the img field and assigning via the loadimage command. I am sure it is something very simple.

Thanks in advance.


MikeHart(Posted 2013) [#110]
Ok, gimme a few minutes. Just loading an image, right?


MikeHart(Posted 2013) [#111]
If want to see how to load from a TexturePacker sprite sheet, then have a look at the sample in examples/SpriteSheets_TileMaps/TexturePacker/TexturePacker.monkey.

For a single image, look at this code (Line 35):

format_codebox('Strict

#rem
Script: LoadImage.monkey
'Description: Same script that shows how to load and a single image
Author: Michael Hartlef
Version: 1.0
#End

' Import the fantomEngine framework which imports mojo itself
Import fantomEngine

' The _g variable holds an instance to the cGame class
Global _g:cGame

'***************************************
' The cGame class controls the app
Class cGame Extends App
' Create a field to store the instance of the cEngine class, which is an instance
' of the ftEngine class itself
Field fE:cEngine

'Create a field for your object
Field myObject:ftObject

'------------------------------------------
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 cEngine class
fE = New cEngine

' Now load the single image
myObject = fE.CreateImage("cratesmall.png", 320, 240)

Return 0
End
'------------------------------------------
Method OnUpdate:Int()
If KeyHit( KEY_CLOSE ) Then fE.ExitApp()
' Determine the delta time and the update factor for the engine
Local timeDelta:Float = Float(fE.CalcDeltaTime())/60.0

' Update all objects of the engine
If fE.GetPause() = False Then
fE.Update(timeDelta)
Endif
Return 0
End
'------------------------------------------
Method OnRender:Int()
' Check if the engine is not paused
If fE.GetPause() = False Then
' Clear the screen
Cls

' Render all visible objects of the engine
fE.Render()
Endif
Return 0
End
End

'***************************************
' The cEngine class extends the ftEngine class to override the On... methods
Class cEngine Extends ftEngine
'------------------------------------------
Method OnObjectUpdate:Int(obj:ftObject)
' This method is called when an object finishes its update. You can deactivate the event via ftObject.ActivateUpdateEvent.
obj.SetAngle(1,True)
Return 0
End
End

'***************************************
Function Main:Int()
' Create an instance of the cGame class and store it inside the global var 'g'
_g = New cGame

Return 0
End
')


MikeHart(Posted 2013) [#112]
Actually you would not need the myObject field in this example. When you create an object via ftEngine.Create... it stores it automatically in the active default layer.


Why0Why(Posted 2013) [#113]
Thanks! Exactly what I was looking for.


CalebDev(Posted 2013) [#114]
I've been messing around with the box2D integration and I can't seem to figure out how to align an image with a polygon shape. After creating an fEObject and a box2D:Polygon object I connect them together, but the center of the fEObject is aligned with the upper left corner of the physics object and I can't figure out how to line them up together without messing up rotation. The Method I'm using is below. Any help would be greatly appreciated!
[monkeycode] Method SpawnShape:Void(amount:Int)
Local shape:ftObject
Local poly:b2Body
Local verts:Float[] = [32.0,0.0, 96.0,0.0, 128.0,56.0, 96.0,112.0, 32.0,112.0, 0.0,56.0]
For Local i:Int = 1 To amount
shape = fE.CreateImage("hexIShapeBlue_128.png",128, 128)
shape.SetHandle(0.5,0.5)
poly = box2D.CreatePolygon(verts,Rnd(128.0,cw-128.0),128.0,2)
box2D.ConnectBody(shape,poly)
shape.SetID(polygonID)
box2D.SetDensity(shape, 1.3)
box2D.SetFriction(shape, 0.3)
box2D.SetRestitution(shape, 0.2)
box2D.SetFixedRotation(shape,false)
Next
End[/monkeycode]


MikeHart(Posted 2013) [#115]
Your image will have coordinates in the negative area, so you need to set up the poly accordingly. For an example, a square with 32 height and with would be like

format_code('Local verts:Float[] = [-16.0,-16.0, 16.0,-16.0, 16.0,16.0, -16.0,16.0]
')

The center is always at 0.0. Not sure if that fits too when you set the handle of the object but with a center in the middle it goes like that.


CalebDev(Posted 2013) [#116]
You are a gentleman and a scolar. Thank you kind sir!


CalebDev(Posted 2013) [#117]
Is there a way to connect more than one box2D physics body to a single fantomEngine object? When I try to do this, only the last physics body connected stays with the fEobject while the other one reacts independently.


MikeHart(Posted 2013) [#118]
At the moment not, you would need to run your own solution for this. Use a data object, then in ftEngine.OnObjectUpdate, update the object accordingly.

But why do you want to add more then one body?


CalebDev(Posted 2013) [#119]
One example is if you wanted to make a pencil and have it react realisticlly. If you could attach mutliple physics bodies to a single object then you could have the pencil shaft have no bounce to it and the eraser on the end could be really bouncy. That way when the pencil falls, if it lands on the eraser end it would bounce, otherwise it would just hit the ground and stop.

I'm actually porting a game I started making with Corona SDK to Monkey. In Corona you can add as many polygon physics bodies to a single object as you want. If it wasn't for fantomEngine I wouldn't be able to do much with Monkey at all, let alone port another project over. So thank you Mike for making Monkey accessible even to a novice programmer such as myself.


MikeHart(Posted 2013) [#120]
Ok, that makes sense. But how would you update the pencils position and angle? Right now the ftObject takes the position and angle from its b2body.


MikeHart(Posted 2013) [#121]
Actually, itsn't that doable with different fixtures for one body?


CalebDev(Posted 2013) [#122]
I'm not very familiar with box2D but it looks like you are correct, although I have no idea how to do it at the moment. I'm trying to figure out how to properly define multiple fixtures for the same body.


MikeHart(Posted 2013) [#123]
I think it goes similar like this:

format_code('Local v:b2Vec2[numberofvertices]
Local shape :b2PolygonShape= New b2PolygonShape()
shape.SetAsArray(v, numberofvertices)
Local def :b2FixtureDef = New b2FixtureDef()
def.shape = shape
def.density = dens
def.friction = fric
def.restitution = res

body.CreateFixture(def)
')

The ftBox2D.CreatePloygon method uses this approach do load PhysicsEditor compatible files which have bodies with more then one fixture defined.


RobB(Posted 2013) [#124]
MikeHart,

The sound on our iOs app works fine in FireFox and Chrome using .ogg files. However, when we translate it to Xcode it does not work on the simulator or the iPad 2. We tried .mp3, .aiff, .mp4a with no success. Any ideas what the problem might be?

Update: Mike, I realized I did not let you know what version of Monkey or fE I am using. Then I also realized that my son, whose iMac we use to compile our xCode, does not have the same versions running that I do. We have had no problem previously, but some of the sound commands in fE may be more recent than his version. So, don't spend a lot of time on my question until we've updated both our systems to the same versions. Thanks, Rob


MikeHart(Posted 2013) [#125]
Hi Robb,

I didn't change much reagrding the sound system, only that you are able to set the general volumes now.

Michael


RobB(Posted 2013) [#126]
Michael,

That one command turned out to be the problem. My son had a fE version installed below 1.49, so it apparently didn't recognize SetVolume(). We commented out the SetVolume() command, and it worked fine. Things are looking good for us. The basic program is all in order. Just need to get instruction screens, etc. and then start figuring out how to submit everything to the app store, enable in-app purchases, and all the technicalities. It will be a free app with an upgrade purchase available.

It's a child's game where you switch head, body, and feet among different fantasy monsters. Free version will have about six monsters with 216 different combinations. Upgrade will provide 9 more monsters for a total of 15. This gives 3375 possible combinations.

My son is a good artist and has spent a year or so developing these fantasy creatures. They have blinking eyes, parallax background that responds to tilt, and different sounds depending on the combination.

I think you'll be pleased with what we were able to do with Monkey and fE despite my unprofessional programming skills.


MikeHart(Posted 2013) [#127]
Sounds great Rob, can't wait to see some screenshots.


CalebDev(Posted 2013) [#128]
In case anyone is interested, I created a method that allows you to add additional shapes to a polygon physics body with fE. Just add it to cftBox2D.monkey inside the fantomEngine module. To use it, create a polygon b2Body like you normally would with fE and then send the b2Body and an array of vertices representing the shape you want attached to it.

[monkeycode]'----***********************************----
'- Description: Adds a polygon shape to an existing polygon physics body -'

Method CreateFixture:b2Body(body:b2Body, vec:Float[] )
Local shape:b2PolygonShape = New b2PolygonShape()
Local xp:Float
Local yp:float
Local v:b2Vec2[vec.Length()/2]
For Local vl:Float = 1.0 To vec.Length()/2
v[vl-1] = New b2Vec2
Next
For Local i:Float = 1.0 To vec.Length() Step 2
xp = vec[i-1]/m_physScale
yp = vec[i]/m_physScale
v[(i-1)/2].x = xp
v[(i-1)/2].y = yp
Next
shape.SetAsArray(v, vec.Length()/2)
body.CreateFixture2(shape)
Return body
End
'----***********************************----[/monkeycode]

MikeHart,
Thanks for your help figuring this out!


MikeHart(Posted 2013) [#129]
Thanks CalebDev, I have used this code to add this method to the cftBox2D file:

format_codebox(' Method AddPolygon:Void(tmpObj:ftObject, vec:Float[] )
Local body:b2Body = b2Body(tmpObj.box2DBody)
If body = Null Then Error("ftBox2D.AddPolygon - body = NULL")
Local shape:b2PolygonShape = New b2PolygonShape()
Local xp:Float
Local yp:float
Local v:b2Vec2[vec.Length()/2]
For Local vl:Float = 1.0 To vec.Length()/2
v[vl-1] = New b2Vec2
Next
For Local i:Float = 1.0 To vec.Length() Step 2
xp = vec[i-1]/m_physScale
yp = vec[i]/m_physScale
v[(i-1)/2].x = xp
v[(i-1)/2].y = yp
Next
shape.SetAsArray(v, vec.Length()/2)
body.CreateFixture2(shape)
End

')


RobB(Posted 2013) [#130]
Hi, Michael,

We would like to have two separate sounds follow one right after the other, but they are not all the same length; so timing is not a good method of handling them. Is there a way to know exactly when the first sound ends so we will know exactly when to play the second sound which follows? The second sound will then play immediately after the first sound ends.

Thanks.


MikeHart(Posted 2013) [#131]
Mojo's ChannelState command will return if a channel is active or not. When fE plays a ftSound, it will store the channel inside its channel field.
Technically I could implement a callback method but then I would add another update loop to the whole update process. Not sure if this would be a good addition to the engine.


RobB(Posted 2013) [#132]
Thanks for that help Michael. I'll check out the ChannelState command.


MikeHart(Posted 2013) [#133]
The sounds you want to play, are they always played in the same order?
If yes, then why don't you mix them together and play the mixed sound instead?


RobB(Posted 2013) [#134]
Thanks for the idea, but they vary with the creature combination that is up. But I got everything working great with the use of the ChannelState function you suggested.


ordigdug(Posted 2013) [#135]
Mike, I wrote the following code along with an example.
Adds: CreatePoint, CreateOval, CreateLine, CreatePoly, and also CreateStickMan. I hope you will add to official distribution.


Add code to "cftObject.monkey" in appropriate place

format_codebox('

Class ftObject:
'**---------------------------------------------------------------------------------------------------------------------------------------**
Field x2:Float = 0.0 'Render -- case ftEngine.otLine
Field y2:Float = 0.0 'Render -- case ftEngine.otLine
Field verts:Float[] = [0.0,0.0, 0.0,0.0, 0.0,0.0] 'Render -- case ftEngine.otPoly (Polygon requires minimum of 3 x,y pairs)
'**---------------------------------------------------------------------------------------------------------------------------------------**

Method Render:
'**------------------------------------------------------------------------------------------------------------------------------------------------------**

Case ftEngine.otPoint
DrawPoint xPos - w * (Self.handleX) + xoff, yPos - h * (Self.handleY) + yoff
Case ftEngine.otStickMan
PushMatrix
Translate ((xPos+xoff), (yPos+yoff))
Rotate 360.0-angle
Scale (Self.scaleX, Self.scaleY)
DrawCircle (-w*(Self.handleX))+4, (-h*(Self.handleY))+4, 4 ' o Head
DrawLine (-w*(Self.handleX))+4, (-h*(Self.handleY))+6, (-w*(Self.handleX))+4, (-h*(Self.handleY))+25 ' | Body
DrawLine (-w*(Self.handleX))+4, (-h*(Self.handleY))+14, (-w*(Self.handleX))+8, (-h*(Self.handleY))+18 ' \ Arm
DrawLine (-w*(Self.handleX))+4, (-h*(Self.handleY))+25, (-w*(Self.handleX)), (-h*(Self.handleY))+29 ' / Leg
DrawLine (-w*(self.handleX))+4, (-h*(Self.handleY))+25, (-w*(Self.handleX))+8, (-h*(Self.handleY))+29 ' \ Leg
PopMatrix
Case ftEngine.otOval
DrawOval xPos - w * (Self.handleX) + xoff, yPos - h * (Self.handleY) + yoff, w, h
Case ftEngine.otLine
DrawLine xPos - w * (Self.handleX) + xoff, yPos - h * (Self.handleY) + yoff, x2 - w * (Self.handleX) + xoff, y2 - h * (Self.handleY) + yoff
Case ftEngine.otPoly
DrawPoly (verts)

'**------------------------------------------------------------------------------------------------------------------------------------------------------**

')

Add code to "cftEngine.monkey" in appropriate place

format_codebox('

Class ftEngine:
'**-----------------------------------**

Const otPoint% = 8
Const otStickMan% = 9
Const otOval% = 10
Const otLine% = 11
Const otPoly% = 12

'**-----------------------------------**


'**---------------------------------------------------------------------------------------------------------------**

#Rem
'summery:Creates a point at the given xpos/ypos.
#End
Method CreatePoint:ftObject(xpos:Float, ypos:Float, _ucob:Object=Null)
Local obj:ftObject
If _ucob = Null Then
obj = New ftObject
Else
obj = ftObject(_ucob)
endif
obj.engine = Self
obj.xPos = xpos
obj.yPos = ypos
obj.type = otPoint

obj.w = 1
obj.h = 1

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

obj.SetLayer(Self.defaultLayer)
obj.SetActive(Self.defaultActive)
obj.SetVisible(Self.defaultVisible)
obj.collType = ctBound
obj.internal_RotateSpriteCol(obj)
Return obj
End
'------------------------------------------
#Rem
'summery:Creates a stickman with top left corner at position xpos/ypos with size of width:8 / height:29
#End
Method CreateStickMan:ftObject(xpos:Float, ypos:Float, _ucob:Object=Null)
Local obj:ftObject
If _ucob = Null Then
obj = New ftObject
Else
obj = ftObject(_ucob)
endif
obj.engine = Self
obj.xPos = xpos
obj.yPos = ypos
obj.type = otStickMan

obj.w = 8
obj.h = 29

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

obj.SetHandle(0.0, 0.0) 'Upper Left

obj.SetLayer(Self.defaultLayer)
obj.SetActive(Self.defaultActive)
obj.SetVisible(Self.defaultVisible)
obj.collType = ctBound
obj.internal_RotateSpriteCol(obj)
Return obj
End
'------------------------------------------
#Rem
'summery:Creates a oval with the given width/height and the center at xpos/ypos.
#End
Method CreateOval:ftObject(width:Float, height:Float, xpos:Float, ypos:Float, _ucob:Object=Null)
Local obj:ftObject
If _ucob = Null Then
obj = New ftObject
Else
obj = ftObject(_ucob)
endif
obj.engine = Self
obj.xPos = xpos
obj.yPos = ypos
obj.type = otOval

obj.w = width
obj.h = 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
'------------------------------------------
#Rem
'summery:Creates a line starting at xpos/ypos and ending at x/y.
#End
Method CreateLine:ftObject(xpos:Float, ypos:Float, x2:Float, y2:Float, _ucob:Object=Null)
Local obj:ftObject
If _ucob = Null Then
obj = New ftObject
Else
obj = ftObject(_ucob)
endif
obj.engine = Self
obj.xPos = xpos
obj.yPos = ypos
obj.x2 = x2
obj.y2 = y2
obj.type = otLine

'obj.w =
'obj.h =

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

obj.SetLayer(Self.defaultLayer)
obj.SetActive(Self.defaultActive)
obj.SetVisible(Self.defaultVisible)
obj.collType = ctBound
obj.internal_RotateSpriteCol(obj)
Return obj
End
'------------------------------------------
#Rem
'summery:Creates a polygon with supplied vertices pairs (Minimum of 3 pairs required).
#End
Method CreatePoly:ftObject(verts:Float[], _ucob:Object=Null)
Local obj:ftObject
If _ucob = Null Then
obj = New ftObject
Else
obj = ftObject(_ucob)
endif
obj.engine = Self
obj.xPos = canvasWidth
obj.yPos = canvasHeight
obj.verts = verts
obj.type = otPoly

obj.w = canvasWidth
obj.h = canvasHeight

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

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

'**-------------------------------------------------------------------------------------------------------------------**

')

Example script:

format_codebox('

Strict

#rem
Script: Create.monkey
Description: This fantomEngine sample script shows how to create the following:
box, circle, polygon, oval, point, stickman (with visable bound box), line
Author: Douglas Williams
Version: 1.00
#End

' Import the fantomEngine framework which imports mojo itself
Import fantomEngine

' The _g variable holds an instance to the cGame class
Global _g:cGame

'***************************************
' The cGame class controls the app
Class cGame Extends App
' Create a field to store the instance of the cEngine class, which is an instance
' of the ftEngine class itself
Field fE:cEngine

'Store canvas width/height
Field cw:Float = 0.0
Field ch:Float = 0.0

'Store stickMan
Field stickMan:ftObject 'For storing STICKMAN
Field stickManY:Float = 0.0 'For storing STICKMAN Y position

'------------------------------------------
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 cEngine class
fE = New cEngine

'Set canvas Width/Height field variables
cw = fE.canvasWidth
ch = fE.canvasHeight

'Print directions in debug window
Print("Press LEFT and RIGHT to move and UP to jump.~n")

'Print canvas X & Y in debug window
Print("Canvas Width (X) = "+cw)
Print("Canvas Height (Y) = "+ch)

'Print info in debug window
Print("~nOBJECTS ARE DRAWN IN THE FOLLOWING ORDER:")
Print(" Box = Canvas Width x Height at middle of canvas")
Print(" Circle = 1/2 Canvas Height at middle of canvas")
Print(" Polygon = X/Y vertices pairs = 100,232/300,100/480,232/320,300/160,300")
Print(" Oval = Width:100, Height:50, at middle of canvas")
Print(" Point = At middle of canvas")
Print(" Stickman = Top Left Corner starts at middle of canvas, Width:8, Height:29")
Print(" Line = Below Stickman")

'Create Box
Local box := fE.CreateBox(cw, ch, cw/2, ch/2) '(width, height, x, y)
box.SetColor(192,192,192) 'Silver

'Create Circle
Local circle := fE.CreateCircle(ch/2, cw/2, ch/2) '(radius, x, y)
circle.SetColor(70,130,180) 'Steel blue

'Create Polygon **** A minimum of 3 x/y pairs are required ****
Local poly := fE.CreatePoly( [100.0,232.0, 300.0,100.0, 480.0,232.0, 480.0,248.0, 320.0,300.0, 160.0,300.0] )
poly.SetColor(255,255,224) 'Light yellow
poly.SetAlpha(0.8)

'Create Oval
Local oval := fE.CreateOval(100, 50, cw/2, ch/2) '(width, height, x, y)
oval.SetColor(218,165,32) 'Golden rod

'Create point
Local point := fE.CreatePoint(cw/2, ch/2) '(x, y)
point.SetColor(0,0,0) 'Black

'Create stickman (Top left corner is at x/y with size of width:8 / height:29)
stickMan = fE.CreateStickMan(cw/2, ch/2) '(x, y) = Upper left of stickman
stickMan.SetColor(0,0,0) 'Black
stickMan.SetID(1)
stickManY = stickMan.GetPosY()
stickMan.SetWrapScreenX(True)

Local boundBox := fE.CreateBox(8, 29, cw/2, ch/2)
boundBox.SetColor(255,255,255) 'White
boundBox.SetAlpha(0.3) 'Set alpha to 30%
boundBox.SetHandle(0.0, 0.0) 'Set handle to top left corner
boundBox.SetParent(stickMan)

'Create Line (line is left (x/y) to right (x2, y2))
Local line := fE.CreateLine(0,ch/2+30, cw,ch/2+30) '(x, y, x2, y2)
line.SetColor(139,69,19) 'Saddle brown

'Create X using 2 lines
Local leftX := fE.CreateLine(0,0, cw,ch)
leftX.SetColor(255,255,255) 'White
leftX.SetAlpha(0.2) 'Set alpha to 20%
Local rightX := fE.CreateLine(0,ch, cw,0)
rightX.SetColor(255,255,255) 'White
rightX.SetAlpha(0.2) 'Set alpha to 20%

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

' Update all objects of the engine
If fE.GetPause() = False Then
fE.Update(d)
Endif
Return 0
End
'------------------------------------------
Method OnRender:Int()
' Check if the engine is not paused
If fE.GetPause() = False Then
' Clear the screen
Cls

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

Endif
Return 0
End
'------------------------------------------
Method OnResume:Int()
' Set the pause flag of the engine to FALSE so objects, timers and transitions are updated again
fE.SetPause(False)

Return 0
End
'------------------------------------------
Method OnSuspend:Int()
' Set the pause flag of the engine to TRUE so objects, timers and transitions are paused (not updated)
fE.SetPause(True)

Return 0
End
End

'***************************************
' The cEngine class extends the ftEngine class to override the On... methods
Class cEngine Extends ftEngine
'------------------------------------------
Method OnLayerTransition:Int(transId:Int, layer:ftLayer)
' This method is called when a layer finishes its transition
Return 0
End
'------------------------------------------
Method OnLayerUpdate:Int(layer:ftLayer)
' This method is called when a layer finishes its update
Return 0
End
'------------------------------------------
Method OnObjectCollision:Int(obj:ftObject, obj2:ftObject)
' This method is called when an object collided with another object
Return 0
End
'------------------------------------------
Method OnObjectRender:Int(obj:ftObject)
' This method is called when an object was being rendered
Return 0
End
'------------------------------------------
Method OnObjectSort:Int(obj1:ftObject, obj2:ftObject)
' This method is called when objects are compared during a sort of its layer list
Return 0
End
'------------------------------------------
Method OnObjectTimer:Int(timerId:Int, obj:ftObject)
' This method is called when an objects' timer was being fired
Return 0
End
'------------------------------------------
Method OnObjectTouch:Int(obj:ftObject, touchId:Int)
' This method is called when an object was touched
Return 0
End
'------------------------------------------
Method OnObjectTransition:Int(transId:Int, obj:ftObject)
' This method is called when an object finishes its transition
Return 0
End
'------------------------------------------
Method OnObjectUpdate:Int(obj:ftObject)
' This method is called when an object finishes its update

'If stickMan
If obj.GetID() = 1

'Jump
If KeyDown(KEY_UP)
If obj.GetPosY() >= _g.stickManY 'If stickman at or above ground
obj.SetSpeedY(-10) 'Move stickman up
Endif
Endif

'Fall
If obj.GetPosY() <= (_g.stickManY - 60) 'If stickman jump height is reached
obj.SetSpeedY(10) 'Move stickman down
Endif

'Stop
If obj.GetPosY() > _g.stickManY 'If stickman below ground
obj.SetPosY(_g.stickManY) 'Stop movement at ground
Endif

'Move right
If KeyDown(KEY_RIGHT)
obj.SetPosX(1, True)
Endif

'Move left
If KeyDown(KEY_LEFT)
obj.SetPosX(-1, True)
Endif

Endif

Return 0
End
'------------------------------------------
Method OnSwipeDone:Int(touchIndex:Int, sAngle:Float, sDist:Float, sSpeed:Float)
' This method is called when a swipe gesture was detected
Return 0
End
'------------------------------------------
Method OnTimer:Int(timerId:Int)
' This method is called when an engine timer was being fired.
Return 0
End
End

'***************************************
Function Main:Int()
' Create an instance of the cGame class and store it inside the global var 'g'
_g = New cGame

Return 0
End

')


MikeHart(Posted 2013) [#136]
Thanks man, I always wanted to add point, oval, line and poly to fE. But a stickman..., I think it is to specific. That could be build from these primitives inside a script and using a parent/child relationship.


ordigdug(Posted 2013) [#137]
Mike,

Well the idea to make a stickman in fE is what lead me down the path to add the additional primitives that are needed to make one. This exploration allowed me to learn a bit how fE works. I coded a point first and then the stickman. After I was able to get both working correctly I decided to add oval, line, and poly. I think a stickman is a good addition for quick prototyping an idea that requires minimum user code, especially for new users.

Use what code you choose. I just enjoy exploring ideas and then sharing the code when successful.

Douglas


MikeHart(Posted 2013) [#138]
Ok Douglas, you have convinced me. And for prototyping, it is a good idea.


MikeHart(Posted 2013) [#139]
I am planning the next release in about a week or two. This is how the change log looks like at the moment:


Version 1.51

*New functionalities*

- With the new class ftLocalization, you can support several languages inside your app.
- You can pause and resume transitions now.
- You can add extra polygon fixtures now to a b2body via ftbox2D.AddPolygon (code provided by the Monkey user CalebDev).
- Quite a few sound related commands were added.
- You can set now the maximum sound channels to be used via ftEngine.SetMaxSoundChannel.
- Because of a typo I had to depreciate ftEngine.GetPause and ftEngine.SetPause. Use GetPaused and SetPaused instead.
- Added code and examples from Douglas Williams to provide more primitives (Point, Line, Oval, Polygon, Stickman)
- Added quite a few things to the sound section of fE.


*Changes*

- Several help descriptions were reworded.
- The folder structure of the example scripts was reorganized.
- Fixed several examples regarding useless SetUpdateRate calls in OnResume and OnSuspend events.

*New commands*

- Please look at the modules help files to see what is new.

*Fixes*

- several

*New example*

- Layer/ScrollingLayers (by Douglas Williams)
- Localization/Localization
- Objects/Appearance/FlashObject2 (by Douglas Williams)
- Misc/RunJump (by Douglas Williams)
- Objects/Creation/CreatePrimitives (by Douglas Williams)



I will also include the proposed functionality to get object data from Tiled layers.

Cheers
Michael


Landon(Posted 2013) [#140]
awesome


Why0Why(Posted 2013) [#141]
Hey Mike, would you consider adding an importer for the format on SKN's free atlas tool that is listed here?

http://www.monkeycoder.co.nz/Community/posts.php?topic=5088

I don't need all the functionality of TexturePacker and this tool is free :)

Thanks! All of the work you do on this is appreciated(I do own the book too.)


MikeHart(Posted 2013) [#142]
Is there an OSX version of the tool? And from what I get, he is undecided again if he wants to charge for it or not. Let's wait till the tool is finished and he knows what he wants.


Why0Why(Posted 2013) [#143]
Pretty sure it is done and it is definitely staying free. Not sure on the OS X support.


Why0Why(Posted 2013) [#144]
Mike,

For many of my projects I use randomly generated maps that are tile based. I have gotten pretty comfortable with fE and done lots of tests. However, I was wondering what your preferred method was for using large quantities of tiles? In stock mojo I assign the tile(which is a custom object) with an int value and then in the draw routine I just use a select statement and draw it that way.

In fE, I want to take advantage of layers, which would be done easiest by extending an ftObject for each tile. If I do this and assign an image to each ftObject(there will be thousands, since they are 32x32 tiles), will fE only assign the image once per tile type? I am not using an atlas because I currently don't have texturepacker and fE doesn't support any other atlas type.

Do you have any sample code for how you would do this with a player sprite on top? This came up because I was migrating a larger project to fE from straight Monkey and I had no issues with the UI layer and the player but the tile layer was more complicated. The map is a 2D array of tiles(which are currently extending an ftObject with some additional fields) and is 50x200 tiles in size.

Thanks for the help...


MikeHart(Posted 2013) [#145]
For large tile maps I personally would build the map in Tiled and load it with ftEngine.CreateTileMap. There is an example for it already in the newer versions of fE.
Performance wise it will be the best when the map is drawn. The next update of fE will also have support for object layers in a Tiled map.

But if you want a single ftObject for each tile, then I would create one for each different tile and copy that object. This way they will definately share the same image.

Does this free texture packer supports the LibGDX (JSON) file format during export? Then you could use that already.


Why0Why(Posted 2013) [#146]
My maps are randomly generated, like a roguelike, so Tiled doesn't work for me.

The exporter outputs XML and JSON, but I think sparrow is the only format that isn't custom.


MikeHart(Posted 2013) [#147]
Well, JSON is just a way of saving data. How it is saved is the question. So it runs their own format, right?


Why0Why(Posted 2013) [#148]
Yep, that is the way it appears. Just thought it would be a nice option for fE.

So for a roguelike, your recommendation is just to make one base object for each tile type (wall, floor, door, etc.) and then copy those for the rest of the map?


MikeHart(Posted 2013) [#149]
Without using a spritesheet, it would be an option. But I can think of other solutions as well. For a tilemap, you need to speed up the drawing process. And with using hundreds of tiles, it might not be fast enough on a mobile.

Your tiles are simgle images, right? Can you at least bring them into one file as spritesheet. Like this for an example:

1,2,3,4
5,6,7,8
9,10,11,12
and so on.

Then you could use an ftObject as a tile map too and build the map in fE by hand. I could build a sample tommorow if you need it. Gotta hit the bed now.


Why0Why(Posted 2013) [#150]
My concern was definitely with mobile, because it is fine on a PC, even in HTML5.

I have used the animimage approach that you are suggesting. For example, floor might be 1 and wall is a 2 and then I store a 1 in the object and draw that sprite from the strip.

If you have time I would be interested to see what you come up with. I am sure that this is a regular use of Monkey and I would like to see how someone that is obviously a better coder than me handles it. My skills are intermediate at best.

Thanks!


MikeHart(Posted 2013) [#151]
Ok I have uploaded a preview of V1.51 to google code.

There in the examples, you will find TileMaps/DynamicMap. Your tiles need to be put in such a sprite sheet as you see there.

Anything else will be to slow. Or you need to run your own solution via a custom ftObject.

Btw. during building the example, I was able to speed up the tilempa drawing tremendously. So thank you for bringing this to my attention.

Landon, Tiled tilemaps with Object layers are read now fine and the data is also stored. But I still need to document this and build some helper methods to read the data from the tilemap object. Give me a few days and it should be fine.

Btw, if you rebuild the docs, there will be fantomEngine docs right from within Ted now. But I still need to refine these too.


Why0Why(Posted 2013) [#152]
Looks really nice, thanks so much! Also, the dynamic code has an extra d on the end of getpause and setpause that shouldn't be there.


Why0Why(Posted 2013) [#153]
Looking at this for a little longer, this definitely far exceeds what I asked for. You really implemented everything very nicely. The camera and getting the tileid is great. Almost everything I code uses something like this and I like this better than what I have already. I will definitely be playing around and rewriting some demos this weekend!


MikeHart(Posted 2013) [#154]
I accidently called it Get/setPause before, but to be consistant (mostly) I renamed it to Get/SetPaused. Both version work in 1.51.

Glad you like it.


Why0Why(Posted 2013) [#155]
And I think it is time for a new thread. This one is getting long ;)


MikeHart(Posted 2013) [#156]
Will do so with the official release of 1.51


Why0Why(Posted 2013) [#157]
Hey Mike,

I have been using the dynamic tilemap example and expanding it to add a player and multiple layers. Even though I have a separate layer for the GUI, it is attached to the tilemap layer and moves with it. How do I make the GUI stationary? Also, what is the best way to have a non movable border around the tilemap. For example, 100 pixels on the right side to show things like inventory and stats for an RPG?

Thanks again for fantom and all the help. I have been going through the source and it is a massive beast. I know there are many, many hours in there!


MikeHart(Posted 2013) [#158]
Hours? What hours? :-))) Yeah sometimes I wonder myself.

You meant that when the camera moves, the gui moves too? :-)) I guess I have an idea why? Didn't thought about guis when I implemented a simple camera. The camera at the moment is simply an offset for EVERYTHING when it will be drawn. I will add a flag so you can set a layer not to be affected by this. That should fix it.

I hope to have 1.51 out this weekend so I will add this before the release too.

About the inventory, I would use a layer on top of the map with its own background. For other implementation, I can envision several cameras/viewports but so far I had no time in implemting this. It is on my roadmap but I can't tell when I get to it.

Anyway, thanks for the nice words. It is always great to read when someone sees the power of fE. I don't say it is perfect and for sure, I would redo some things now if I would start again, but it is a pretty damn good game framework and I like it. :-)))


Why0Why(Posted 2013) [#159]
I have used many frameworks over the years in Max and Monkey with mixed success, but fE and I just seem to get on well and I am more productive with it.

I think viewports are something that are very useful. I have used them in the past for minimaps or automapping and to place borders around the screen. Definitely handy! I will go with the layer approach on the UI that you recommend in the mean time.