Data Types

From mugen-net
Revision as of 09:52, 18 April 2019 by Jesuszilla (talk | contribs) (Initial commit)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

M.U.G.E.N only provides two standard data types to users who are coding characters: signed int and float.

Supported Bitwise Operations in M.U.G.E.N

Since M.U.G.E.N is written in C, users are given most of the bitwise operators that C has, with the exception of the shift operators (which can be covered). M.U.G.E.N provides the following bitwise operators:

  • & - Bitwise AND
  • | - Bitwise OR
  • ^ - Bitwise XOR
  • ~ - Bitwise NOT

Reading the Wikipedia article on C Bitwise operators is recommended. This explains everything one needs to know about their usage.

Common Data Types

Bit

A bit is a unit which represents one of two possible values (1 or 0, on or off, true or false). A value that is either 0 or 1 (false or true) is also called a Boolean (or bool). These terms are not interchangeable and in fact, the representation of a Boolean may be more than one bit, but for the simplicity of this article, a boolean Boolean value is considered 1-bit.

Byte

The second unit to know in computing is known as a byte, which is composed of 8 bits. A byte can hold up to 256 unique values ([0,255] for unsigned, or [-128,127] for signed).

Short

The third unit is 16 bits, or two bytes, and is known as a short. A short can hold up to 65536 possible unique values. The fourth unit we're concerned about is the simple integer (or int) type, which is 32 bits and can hold up to 2147483648 unique values.

Float

There are other integer types, but of course, there are also float types we need to use to deal with real numbers and fractions. A float can represent many unique values and they are also 32-bit.

Problem

Users are only given 60 int variables and 40 float variables to work with. This is done so that memory can be managed more efficiently, but at the same time, users are limited in terms of how many variables they can declare.

Solution

One 32-bit variable can be split into several variables when utilizing only the bits necessary.

Example

Felicia by Jesuszilla's Cat Ride makes use of this for the bind position for her custom state. The following code fits an x coordinate and y coordinate into one int variable.

[State -2, Cat Ride Pos]
type = VarSet
trigger1 = Anim != 9545
trigger1 = Enemy, Name = "Felicia_LG" || Enemy, Name = "Felicia_Y"
trigger1 = StateNo != 132 && StateNo != 155; Air guard
trigger1 = StateNo != [5000,5999]          ; Gethits
sysvar(0) = (14 & 65535) | (-100 * 65536)  ; Store (14,-100) into sysvar(0)

Normally, two float variables are used to store an X and Y position, but since this is dealing with sprite binding, two short variables work perfectly for this use case. This is because the chances of a sprite being larger than 65536 pixels in width or 65536 pixels in height is slim to none. Most GPU's can't even have textures larger than 2048✕2048px (which is considered a safe value in this era due to the graphics limitations of tablets)[1]. By limiting the data size to only the bits necessary, more efficient use of memory can be made.

The operation can be reversed to retrieve the individual X and Y components like so:

[State 60, VarSet]
type = VarSet
trigger1 = NumTarget(60)
var(39) = Target(60),SysVar(0)

[State 60, BindToTarget]
type = BindToTarget
triggerall = NumTarget(60) && Var(39)
trigger1 = target(60), SelfAnimExist(9545)
pos = ceil(((var(39)&65535) | ifElse(var(39)&32768,-65536,0)) * target(60),Const(Size.XScale)), ceil((var(39)/65536) * target(60),Const(Size.YScale)), Foot

Although this provides readability issues, there's really no way around it, and this is actually the more readable version that uses Var(39) to temporarily store the value of the enemy's Cat Ride position.

For the x component, the bitwise AND of the first 15 bits is taken. The 16th bit, which is known as the "sign" bit, is then checked in the ifElse statement. The sign bit is only used in what's known as "signed" values. A signed value is one that can be either positive or negative. A 1 for the sign bit indicates that the value is negative, whereas a 0 indicates that it is positive. The bitwise OR is then taken with -65536 so that it converts a signed 16-bit short back into a signed 32-bit int with the sign intact that M.U.G.E.N can understand.

Retrieving the y component is much simpler. The original value is divided by 65536 in order to mimic a right arithmetic shift by 16 bits. In most languages, the binary shift operator, >>, would be used. However, M.U.G.E.N has no shift operations, so multiplication by powers of 2 must be utilized (x*(2**y)) for shifting x left by y bits, and division by powers of 2 (x/(2**y)) for arithmetic right shifting x by y bits.

Any data type smaller than 32 bits can be recreated using bitwise operations. This means that for a single integer, up to 32 Boolean values can be defined

[State -2, Flags]
type = Null
trigger1 = e||(var(0) := 1*(2**0))      ; Set 1st bit of var(0) to 1
trigger1 = e||(var(0) := 0*(2**1))      ; Set 2nd bit of var(0) to 0
...
trigger1 = e||(var(0) := 1*(2**30))     ; Set 31st bit of var(0) to 1
trigger1 = e||(var(0) := 1*-2147483648) ; Set 32nd bit of var(0) to 1

The 32nd bit utilizes the value -2147483648 rather than (2**31). This is due to the limitations of the max value for a signed 32-bit int. 2**31 would return 2147483648, which requires at least 33 bits when signed. Since this cannot fit in 32 bits, the two's complement value must be used directly.

References

Template:Reflist