The new, simplistic, stylish default A-Engine icon. Thanks to Z-Studios for making me this!

A-Engine Update #6: The Beast has been Reborn

A-Engine default icon

The new, simplistic, stylish default A-Engine icon. Thanks to Z-Studios for making me this!

Roses are red, violets are blue, you want me to get to the point, and I do too.

So the plan is to have an attempt at briefly iterating over the most important features and changes the A-Engine has went through thanks to the reboot.

The FileManager Component:

This was the first thing I worked on after I decided on the reboot. The idea was to create a little class which can parse .a files all by itself and provide easy methods to extract parameters out of tags. What I ended up with is a mini markup language engine that is very easy to use and self-containing enough to allow using for other applications that might want to use this markup language. Unlike the method I had used to parse .a files before, this one doesn’t use any search or string manipulation methods. It actually goes over the whole file character per character.

As a consequence:

1- More descriptive error messages related to parsing files:

You’ll find that the A-Engine will no longer crash silently or after giving you a vague message when you have any mistake in syntax or a typo in your file. It now informs you of the file name, line number and column (index of the character in a line) the parser found the mistake at. Further more, if a mistake was found in a file that was >imported by another file, or a hierarchy of files, the error message will return what’s similar to a callback tree to tell you exactly where the mistake came from.

2- The ability navigate frames and call objects by names:

Before this, this was not possible, as my older “parser” was simply a search for a tag name and taking the few characters following it until a letter or a line break is met. So it was impossible to introduce a text type for tags, as text itself may contain characters that make up a tag name, which may then end up getting parsed (and eventually things get messed up and the whole thing crashes). The only place where I felt text was really needed was with assets directories, but I bodged my way through with ugly hacks so that it works only for that. However, with the new class, parsing quotes enclosed text became no problem at all, and now, I was finally able to allow navigation between frames by name!

[F= 1  NAME= "someframe"]
  image = 1 delay= 2 center= 50, 0, 0 goto= 2
[F= 2]
  image= 2 delay= 2 center= 50, 0, 0 goto= "someframe" #same as goto= 1
  call_object[ id= "fire ball" x= 0 y= 0 z= 0] #object ids can be either names or numbers

Although, I’d advice against using names entirely instead of numbers, as it requires a look-up what maps to the name in a map container which makes it slower. An okay-use would be to only name frames marking the beginning of attacks for example and then use those names when you want to navigate to the beginning of the attack action. Objects maps will probably be much smaller compared to frames’, so using names for them would be fine.

3- Nested frame-components:

Before now, you couldn’t have a frame-component only activate if another does, without some On and Off business with variables. However, one can now nest frame-components such that they only activate if the parent frame component activates. For instance, here is a frame with a key_combination[ ] frame-component, which once activates (by pressing button ‘0’), will use a call_object component to spawn some effect:

[F = 10]
  image= 1 delay= 100 center= 50, 0, 0
    click_sequence = "<0>"
      x= 20 y= 10 id= 10 frame= 20  # spawns every time <0> is clicked

Now of course, you may freely place another frame-component inside call_object[ ] which will only activate once that does and so on. However, it’s very important to note that nesting components inside ones that has to do with collision detection (hit_box, hurt_box..etc) or physics (rigidbody_box, rigidbody_sphere..etc) will result in these components being forwarded to the next timestep. This is because these are only tested and processed at a later time in the game loop.

Furthermore, I’ve also come up with a new dummy frame component, segment[ ], which serves no specific purpose but can assist in grouping components. For instance, you can group components together for a specific power-up for your player:

[F= 0 NAME= "idle"]
  image= 0 delay= 2 center= 50, 0, 0
  hurt_box[ x= 0 y= 0 w= 70 h= 30 ]
  segment[ #components inside will only work in power-up mode 
    hurt_box[ /#...#/ ]
    hit_box[ /#...#/ ]
    key_combination[ /#...#/ ]
    enable = $power_up == TRUE

4-Tag swizzling:

Inspired by a feature of GLSL (openGL Shading Language) which allows accessing a vector’s component in any order possible, I’ve come about doing this for some A-Engine tags as well. A couple of tags like center= taking 3 parameters x, y and z for the origin of the graphic from the object position, or velocity= which also takes 3 parameters x, y and z for a new velocity for the object, are in reality vectors of 3 components too. So next time you want to only set the x and y values of such a tag, you may use xy_center= or yx_acceleration= for that matter; any combination of x, y and z will work, and it will take the number of coordinates stated in the beginning as parameters – and in that given order.

The ScopeManager Component:

When I began (re)working on this part of the A-Engine, particularly the AExpressions, I had put in mind that this is to become the foundation of a greater feature the engine will see in the future, a little custom scripting language to be used to achieve more complicated stuff and, hopefully, for AI; we’ll call it A-Script. While this is not what we’ll be talking about today, it’s important to understand that a script is really just a number of ordered expressions together with branching and functions and other hodgepodge. What we’ll be covering today is the part which I consider ready; expressions. But first, just to clarify to those who have been following for a while, I’ve come to a subtle change in terms after recording this. From now on, what we referred to as variables (begin with ‘@’) will now be called system-variables, and what were registers (begin with ‘$’) will now be called variables.

If you don’t know yet, the A-Engine allows feeding expressions to tags as follows:

image = 1 + 2 #3
x_velocity = $myVariable/2
add_hp = @max_hp * 0.1 + random{10, 50} # gain 1 tenth of your max + a random number between 10 and 50

You may now redefine a system-variable or a variable with one common tag, set_variable=. However, I’ll continue asking you NOT to set system-variables directly if you don’t know what you’re doing. I really wanted to forbid modifying them in the first place, but I felt maybe someone may need to modify one for some smart thing I haven’t considered.

New features:

1-New data types:

As mentioned before, the A-Engine now supports text type in expressions. This means that you’re able to store text in variables as well:

set_variable = $level, "1"
goto = "blast level " + $level #'blast level 1'

Also, the value NONE which is used when you mean to set no value to a tag is no longer an alias of a magic number (4321), but has now got a type for itself. TRUE and FALSE have been put again, however I chose to make them still be aliases of 1 and 0 respectively as that makes them more handy. There’s also a new data type called bitfield with which you may do binary operations if you ever need to, but that’s barely useful.

2-The new interpolator operator ( -> ):

Suppose you have an object which you’d like to make fade-out smoothly in a period 1 second. Assuming your game is running a 60 frame per second, then 60 timesteps would be the time during which you require all of this to happen. You could use 60 frames with delay = 0 and the alpha = tag’s value decreasing throughout, or perhaps use a sequence and do some variable manipulation decreasing the value by a fraction of 1/60. But that would be a waste of 60 frames for something so simple! The linear interpolator operator is here to solve exactly this problem:

[F = 100]
  image = 0 delay = 60 alpha = 0 -> 1 /# other tags #/

0 -> 1 is a linear interpolation from 0 to 1 in 60 steps:

0.0, 0.0166666666667, 0.0333333333333, 0.05, 0.0666666666667, 0.0833333333333, 0.1, 0.116666666667, 0.133333333333, 0.15, 0.166666666667, 0.183333333333, 0.2, 0.216666666667, 0.233333333333, 0.25, 0.266666666667, 0.283333333333, 0.3, 0.316666666667, 0.333333333333, 0.35, 0.366666666667, 0.383333333333, 0.4, 0.416666666667, 0.433333333333, 0.45, 0.466666666667, 0.483333333333, 0.5, 0.516666666667, 0.533333333333, 0.55, 0.566666666667, 0.583333333333, 0.6, 0.616666666667, 0.633333333333, 0.65, 0.666666666667, 0.683333333333, 0.7, 0.716666666667, 0.733333333333, 0.75, 0.766666666667, 0.783333333333, 0.8, 0.816666666667, 0.833333333333, 0.85, 0.866666666667, 0.883333333333, 0.9, 0.916666666667, 0.933333333333, 0.95, 0.966666666667, 0.983333333333, 1.0

You may also use this to display a number of images for an animation in one frame:

  image = 0->10 xy_center=50, 0 delay= 10


0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10

3-Scope navigation with ( : ):

Previously, if you had the on-screen id of your parent object stored inside “$parent”, and you wish to know the its HP, you’d do “fetch_obj_data{$parent, @hp}”. This was really made simpler now with a new way to access variables or system-variables of some object: “@parent:hp” would give you what you need. You’d like the parent’s parent’s HP? “@parent:parent:hp”! And you could go on. You may assign any reached variable directly using the set_variable= tag as well.

The EventManager Component:

I have mistakenly referred to this by the “Input Manager” in the last blog post, but “Event Manager” is what the class is really called. As deduced from the name, this is what’s responsible for handling key presses and inputs from various devices in the A-Engine. The A-Engine allows for 14 mapped keys for every player; 4 of which are directions: “<up>”, “<down>”, “<left>” and “<right>”, and 10 others with no specific functions: “<0>”, “<1>”, …. “<9>”. With the new EventManager component, I’ve took this further, and allowed for things the A-Engine didn’t have before, like taking input from raw buttons and reacting to key release and mouse events. To accommodate, the input buffer been split into 6 parts and much more.

1-Raw buttons can now be used:

You’re able to use c<K_RETURN>= 10 to let the control take you to frame 10 when the Return (enter) key is clicked, or h<K_J> = “jump” to goto the frame with the name “jump” when the J button is held. Putting these aside, some more practical uses would be to have cheat buttons or set the numeral keys to gain control of a particular army of many in the field in a particular game mode. Almost any key that can be found on a keyboard can be used as a tag. Click here for a list.

2-Input buffers has been split:

The A-Engine has got a key_combination[ ] from component designed for performing an action when particular sequences of key presses have been made. Every time a mapped button is clicked, released or click/released, it gets pushed to the mapped key click buffer, mapped key release buffer or mapped key buffer respectively.

[F = 0]
  image = 0 /# other tags #/
  key_combination[ click_sequence = "<down>", "<up>", "<0>" goto= "upper cut"] #goto frame with name "upper cut"

click_sequence= will compare a list of buttons to what was last pushed to mapped key click buffer, and if it matches (if the buttons were clicked in order), the frame component tags and any other frame components inside it will activate. There is another similar group of 3 buffers which store raw key events, raw key click buffer, raw key release buffer and raw key buffer for both clicks and releases. Below is an example of a key_combination[ ] which demonstrates how the character will spawn thunder when “THUNDER” is typed on the keyboard followed by a right mouse button click and a left mouse button click:

  raw_click_sequence = "<K_T>","<K_H>","<K_U>","<K_N>","<K_D>","<K_R>","<M_RIGHT>","<M_LEFT>"
    id= "thunder" #spawns and object with the name "thunder"

3-New on key-release tags and keys state system variables:

In addition to the c<X>= tags and the h<X>= tags for clicking and holding key X respectively (can be mapped or raw), tags in the form of r<X>= for releasing key X has been added. Also, system variables @X_held (X being the key name in all lower-case) is now available and will return TRUE or 1 if the X is currently held or FALSE or 0 if it isn’t.

The GraphicsManager Component:

You already know about most what this has introduced to the A-Engine; using 3D and models, customizable cameras and programmable shaders for rendering your graphics in unique ways. There is planned a way with which you can define “display modes” with multiple viewports and then assign every viewport a camera for things like split screen, but that’s not for today.

-New frame-component display_graphic[]:

There is only one new thing to write about, and that’s a new frame-component, display_graphic[ ]. In a frame, there are tags which are really only concerned with displaying a graphic to the screen correctly, image=, model=, center=, shader=, scale=, rotate=, red=, blue=, base_green=, alpha= to name a few. In many cases, you’ll want to show more than 1 image or 1 model for your object, and having that be a separate object would just be complicated and wasteful. For that, you can now use the display_graphic[] frame component to specify more graphics to display in a frame:

  image = 1 yx_center = 0, 50 delay = 0 scale = 1.0
  display_graphic[ model = 2 xy_center = 39, 10 scale = 2.0 ]
  display_graphic[ image = 3 center = 19, 52, -2 rotate = 30 ]

And here is where I stop. I have missed quite a lot of bits here and there, but that’s just to prevent the post from getting more lengthy. I also wanted to write about what the PhysicsManager features, but I guess that’s for next time. As always, if you have any inquiries or comments, you may drop them below, and I’ll try to respond to them as soon as I can.

Comments (3)

Add A Comment

Your email address will not be published. Required fields are marked *