Abu FrameworkMonkey Programming Forums/User Modules/Abu Framework
It is 2D only, with a lean towards retro-style action games.
Abu is a work in progress; I am cleaning up and consolidating my somewhat scattered code base so that it is useful and easy to implement.
This first incarnation contains only three parts of the eventual whole, but the main file 'abu.monkey' shows what is to come.
Also included is a demo of the animation submodule; if you do not have Diddy then simply comment out 'Import diddy' and it will still work.
'To use abucolor, add these two lines to your header:
Alias SetColor = abucolor.SetColor
Alias Cls = abucolor.Cls
'This allows you to call mojo's SetColor() and Cls() functions using colors
'in the hex format $rrggbb, in addition to the standard usage.
'You can also use the Color class to define your own colors in hex:
Global myColor := New Color($112233)
'...or access the individual components of a hex color easily:
'This class is not intended to be used for pixel-level manipulations of images.
'this is a simple class that adds a little functionality to mojo's Image.
'load a single image like this:
Global myImage := New AbuImage("myImage.png")
'or load an animation sheet like this:
Global mySheet := New AnimationSheet("mySheet.png", 16, 16)
'these constructors can be called anywhere in your code,
'however the LoadImages() function must be called before drawing anything.
'the AbuImage class has the following significant methods:
Draw:Void(x:Int, y:Int, rotation:Float = 0, scaleX:Float = 1, scaleY:Float = 1)
DrawFlipped:Void(x:Int, y:Int, flip:Int = FLIP_X, rotation:Float = 0, scaleX:Float = 1, scaleY:Float = 1)
'the flip parameter can be FLIP_X, FLIP_Y, or FLIP_X|FLIP_Y
'flipping is applied before rotation and preserves the handle of the image
'the AnimationSheet class has these additional significant methods:
DrawFrame:Void(x:Int, y:Int, frame:Int, rotation:Float = 0, scaleX:Float = 1, scaleY:Float = 1)
DrawFrameFlipped:Void(x:Int, y:Int, frame:Int, flip:Int = FLIP_X, rotation:Float = 0, sX:Float = 1, sY:Float = 1)
'these function the same as AbuImage.Draw() and DrawFlipped(), but take a frame parameter.
'this is the largest submodule, the star of which is the AbuSprite class.
'here is partial documentation for that class:
Property animationSheet:AnimationSheet '[read-only]
Property currentAnimation:String '[read-only], name of current animation
Property nextAnimation:String '[read-only], name of qeue'd animation
Property loopCount:Int '[read-only], number of times the current animation has looped
Method SetHandle:Void(x:Int, y:Int)
Method SetAnimationSheet:Void(path:String, frameWidth:Int, frameHeight:Int)
Method AddAnimation:Void(name:String, sequence:Int, frameDuration:Int, loop:Bool = True)
Method AddAnimation:Void(name:String, subAnimations:String)
Method PlayAnimation:Void(name:String, reset:Bool = True, rate:Float = 1)
Method QeueAnimation:Void(name:String, reset:Bool = True, rate:Float = 1)
Method AddOffset:Void(name:String, offsetX:Int, offsetY:Int, cumulative:Bool = False)
Method AddDisplacement:Void(name:String, displaceX:Int, displaceY:Int)
Method Draw:Void(x:Int, y:Int, rotation:Float = 0, scaleX:Float = 1, scaleY:Float = 1)
'animationdemo.monkey is an example of how to use this class.
'the AddOffset() and AddDisplacement() methods are not yet implemented.
In animationdemo.monkey I have imported Diddy to show that there are no indentifier conflictions so far between my code and Diddy. I love using Diddy myself and have no intention of reinventing all of the simple utilities that can be found in it, or any other publicly available module for that matter.
I also intend to make Abu as "buffet-style" as possible; low inter-dependency between submodules so that they can be used individually.
| Loading from texture atlases now works and I've borrowed the css from the monkey docs to make nice looking documentation (still a work-in-progress). |
| Added abutime & abuinput submodules and a lot of documentation.|
Looking for assets I can distribute with the bananas.
| Nice! I like how simple it is. How are you planning to implement abureplay? |
| Thank you :)|
You can see I've put abureplay next to abuinput and aburandom, basically the plan is to store whatever input the user gives and any random numbers generated on a timeline in record mode, and then those modules will read from the timeline instead of functioning normally during playback mode.
I'd like to make this easy to use with physics libraries such as nape, box2d, and chipmunk so I'm researching the best ways to make those deterministic.
In the meantime I've got a very simple "physics" module for collisions and such that will be deterministic for sure. It's tied into the whole entity system which is what I'm finishing up now.
| Sounds promising, especially functions like Sprites, Timers and Colors are very useful. |
I noticed some traces of Image variations in AbuImage, are you still planning on implementing such a feature? I've been wanting to do palette shifting a while.
Also the repo is acting strange, when I "hg clone https://code.google.com/p/abu-framework/" I don't get the most recent version (visible when browsing on google code), I get the same version as the .zip download.
| EDIT: Yeah I see that the Timer files are missing. |
| Trying to fix cloning issues, but I just added entitytest.monkey that previews the incomplete entity system.|
I am still pursuing palette-swapping capability but it involves target-specific considerations, I think.
Trying to decide on the best way to standardize the palette information that you feed it, without requiring png8's or something.
EDIT: I believe the cloning works now, also there's a more recent zip. Requires diddy for its xml module.
| I also had issues with palette-shifting; I ended per-pixel redrawing the image, which was too ugly. If you know a solution I could look into it.|
Wouldn't png palette swapping be hard also, needing target specific code?
I'll check the new code tomorrow; I just adapted my project to use Abu for all sprites :)
| Cool :) I'd like to see what you make with it.|
I'm still looking into image variations in general. That includes palette shifting and also tinting since doing it by way of SetColor is so slow on the HTML5 target. I've got a half-baked idea for a system that helps with smart video memory usage that is tied in with this (That's the AbuTextureAtlas fragments you can see lying around).
If I can get that to work in an elegant way it would allow for some neat effects like 'real-time' tinting for HTML5 and temporal aliasing for animations that are animating faster than the given framerate.
We'll see if I can manage it. I don't want this project to get leaky.
| Just realized that not having a DrawFlipped() method at the Sprite level is a flaw. I have been testing things with one animation each for left and right-facing things but that's obviously not ideal. The capability is there at the AbuImage level, I just need to extend it up the hierarchy.|
EDIT: On further contemplation, including it would add some complexity to the displacement aspect of sprites when they are an entity component. How does it know which direction to displace the entity? I'd like to think of a solution that doesn't require that I add a mandatory orientation component to the Entity class.
One solution could be to add a flip:Int parameter to the PlayAnimation() method, but this doesn't allow for changing direction in the middle of an animation without some maintenance code.
I've also been thinking about how/if to allow sprites to take their animation frames from multiple images. I've been assembling simple games to test all the framework's aspects and one of those involved a sprite atlas that had been constructed from many related images, one for each of the protagonist's animations. Counting the frames to see where a specific animation started was tedious, I'd like to be able to do this in a more intelligent way.
| Just finished the first draft of abutween. I am very happy with it :)|
It uses reflection to tween properties via Invoke(). It can only tween Float properties at the moment, and it only does linear interpolation but it works!
This is the first time I've used the reflection module for anything, I'm very pleased with how everything turned out.
When it is finalized it will be integrated with the entity system, which is still a work in progress.
In the meantime, here is the code if anyone wants to take it for a spin:
'abutween.monkey by Belimoth
Const TWEEN_DEFAULT:Int = 0
Method AddTween:Void(name:String, value:Float, duration:Int, flags:Int = TWEEN_DEFAULT)
Class Tweener Implements ITweener
Method AddTween:Void(name:String, value:Float, duration:Int, flags:Int = TWEEN_DEFAULT)
Local tweenNew := New AbuTween(Self, name, value, duration, flags)
Field _tweens := New StringMap<AbuTween>
Function UpdateTweens:Void(timePassed:Int = -1)
If timePassed = -1 Then timePassed = Tick()
Class AbuTween Implements IJuggleable
'Global ARGUMENT:ClassInfo = [ FloatClass() ]
Global juggler := New Juggler<AbuTween>
Field _active:Bool = True
Field valueStart:Float, valueEnd:Float
Field timeStart:Int, timeEnd:Int
Method New(targetObject:Object, name:String, value:Float, duration:Int, flags:Int = TWEEN_DEFAULT)
Self.targetObject = targetObject
Local classInfo := GetClass(targetObject)
If classInfo = Null Then Error("Reflected class not found.")
Self.targetGetProperty = classInfo.GetMethod(name, , True)
If targetGetProperty = Null Then Error("Reflected get method '" + name +"' not found.")
Self.targetSetProperty = classInfo.GetMethod(name, [ FloatClass() ], True)
If targetSetProperty = Null Then Error("Reflected set method '" + name +"' not found.")
Self.valueCurrentBoxed = New Object
Self.valueStart = FloatObject(valueCurrentBoxed).value
Self.valueEnd = value
Self.timeStart = CurrentTime()
Self.duration = duration
Self.timeEnd = timeStart + duration
juggler.Remove(Self) 'TODO this doesn't remove the tween from the tweener
Method Active:Bool() Property
Self.timePassed += timePassed
Self.completion = Float(Self.timePassed) / Float(duration)
If completion >= 1
valueCurrent = valueEnd
valueCurrent = valueStart * (1 - completion) + valueEnd * completion
FloatObject(valueCurrentBoxed).value = valueCurrent
If completion >= 1 Then Destroy()
valueCurrentBoxed = targetGetProperty.Invoke(targetObject, )
And here is an example file:
'tweentest.monkey by Belimoth
Class Thing Extends Tweener
Method X:Float() Property Return _x End
Method X:Void(xNew:Float) Property _x = xNew End
Method Y:Float() Property Return _y End
Method Y:Void(yNew:Float) Property _y = yNew End
Method New(x:Int, y:Int)
Self._x = x
Self._y = y
DrawOval _x - 7, _y - 7, 15, 15
Class MyApp Extends App
thing = New Thing(50, 240)
thing.AddTween("X", MouseX(), 1000)
thing.AddTween("Y", MouseY(), 1000)
SetColor(255, 255, 255)
I haven't downloaded the newest version of Monkey, I think maybe there have been some changes to #REFLECTION_FILTER? Adjust if necessary.
It's as easy as:
Class MyObject Extends Tweener
Method X:Float() Property
Method X:Void(xNew:Float) Property
myObject.AddTween("X", xDestination, tweenDuration)
The only restrictions are that the property you are tweening must have identically named get and set methods, and you must include the relevant class in the reflection filter.
| Here is what the example looks like. Click to tween the ball's position :) |
| Cool :) |
| Whew, big update today! I am exhausted.|
The repository is fresh and I'll have a new zip up in mere moments.
- abutween.monkey has been renamed abuschedule.monkey and has added support for named Timer management.
- abujuggler.monkey has been merged into abutime.monkey
- The modified SetColor and Cls commands have been moved into a new submodule called 'mojomodifications'. This isn't imported by the main abu module.
- abucolorconstants.monkey has been merged into abucolor.monkey
- AbuTimer.Unpause() renamed to Resume().
- Support for Animations outside of an AbuSprite object has been removed. Stand-alone animations didn't add any usefulness and were harder to use.
- All property methods renamed in 'PascalCase'.
- The scheduling module works for tweening both Float and Int properties without having to specify.
- The AddAnimation function now takes an optional start parameter, similar to the first_cell parameter of LoadAnimImage from BlitzMax.
- The AddAnimation function can now accept an array of values for the frameDuration parameter.
- Much more documentation.
- What used to be the Entity class is now the EntityBuilder<> class.
- The AbuEntity class is now a prebuilt EntityBuilder<> with default components.
- The Physics component of Entities isn't done yet.
- Tweening only uses linear interpolation, and there are no easing options yet.
- No modules add themselves to the #REFLECTION_FILTER. If you want to use the tweening features the easiest way is to just add "abu*" to the filter.
- Finishing all of the above incomplete features.
- The abucamera, abuactor, and abustage submodule block. These are all interrelated.
- Bananas! I've got a few good demos already, but I'd like to make more before I add them to the repository.
- Finishing the abudebug module. Really I'm just deciding on the best API for this.
Merry Christmas, and Happy Holidays :)
| New update!|
EntityComponent.Tie renamed to Initialize
juggler.Juggle and IJuggleable.Update switched
Color moved to mojomodifications and made private
SetColor(rgb:Int) and Cls(rgb:Int) added to mojomodifications
abuimagebank merged into abuimage and all classes made private
ISprite.QeueAnimation renamed to QueueAnimation
jugglers exposed for AbuSprite, VelocityComponent, and ScheduleComponent
abuanimation restructured, Animation class made private. standalone animations now fully deprecated
basic physics now mostly functional
abutilemap and abucollisionmap added, these are unfinished
Be aware, for identifier conflict reasons, that there is an AABB class floating around in there somewhere. It isn't documented because it hasn't found a submodule to call home yet.
| Cameras are coming along nicely: demo |
| Okay! Cameras are finished now, except for a few small details I'd like to add. Here is a demo showing what they are capable of.|
Also new is virtual resolution capabilities, which the cameras adjust to, and a shift towards more thorough encapsulation in the form of a state-based framework.
For the curious, here is the demo source:
'cameratest.monkey by Belimoth
Class Background Extends AbuEntity
Field image := New AbuImage("landscape.png")
Class MyApp Extends AbuApp
SetState( New GameState() )
Class GameState Extends AbuState
background = New Background()
camera = New AbuCamera(10, 10, 64, 64)
Print "virtual resolution: 320 x 200"
Print "use QAZ to change zoom"
camera.xTarget = VirtualMouseX()
camera.yTarget = VirtualMouseY()
If KeyHit(KEY_Q) Then camera.zoom = 2.0
If KeyHit(KEY_A) Then camera.zoom = 1.0
If KeyHit(KEY_Z) Then camera.zoom = 0.5
I've updated the repository.
| I've experimented with a lot of different options for tween equations, and decided to go with Skn3's code from the bananas folder.|
Integrating it took about 30 seconds, I really shouldn't have taken this long to make that decision.
Anyhow, see the difference here.
| I've uploaded a zip containing all the new stuff.|
Position.AngleTo() output adjusted to match coordinate system (0-360)
MapX(), MapY(), & At() added to abutilemap; MapX() and MapY() removed from abucollisionmap
bug with collision map bumpers fixed
abucolor removed, color constants moved into mojomodifications
IRenderable and AbuRenderObject added, these may be temporary
switched to skn3.xml for atlas loading
tweening equations usable via Skn3's tween code
tweens can now be applied to fields
| Nice work Belimoth! |
| Thank you very much! I appreciate the affirmation.|
I've been experimenting with dithering velocities and have started to converge on a solution that resembles the AddDisplacement aspect of sprites.
I've also got a working prototype of real-time tinting in HTML5, but I don't like the idea of having native code to maintain. Maybe as the dust settles on the new versions of Monkey I won't be so apprehensive. In order to do it right I've also got some figuring to do as far as video memory management.
I am excited by the possibilities!
| Doing another pass on sprites, the way I handled handles doesn't really make sense in the big picture.|
The DrawFlipped methods won't do much now which makes me weary but I guess that's the cost of trying new things.
| Silly typos. The abuvelocitycomponent.VelocityComponent methods should look like this:|
Method XDisplacement:Int() Property
Local xTemp:Float = _xVelocity + _xRemainder
Local dx:Int = Int(xTemp)
_xRemainder = xTemp - dx
Method YDisplacement:Int() Property
Local yTemp:Float = _yVelocity + _yRemainder
Local dy:Int = Int(yTemp)
_yRemainder = yTemp - dy
It works how it is but movement is very jagged.