Author: Brian A. Ree
1: The MmgObj Class
A game API is a set of software libraries and classes to facilitate the creation of a video game.
The MMG Game API is a 2D java game API that I used to demonstrate game coding examples and tutorials.
The java classes in the MMG API sit on top of the lower level drawing framework. In this case we'll be using the java drawing framework
Java Swing. It's an older GUI interface for java but it'll give us what we need.
Take a look at the first set of game tutorials, here, to refresh your memory on the code
we'll be using to run our API demos. First thing we'll do is review the MmgObj class. This is an important class in our API and it provides the basis for all drawn
images in our game and our game UI. Let's review the field summary for our MmgObj class.
The full class source code is listed below. You can also view its javadoc here.
package net.middlemind.MmgGameApiJava.MmgBase;
/**
* The base drawable class of the MmgApi.
* Created by Middlemind Games
*
* @author Victor G. Brusca
*/
public class MmgObj {
/**
* The screen position to draw this object.
*/
protected MmgVector2 pos;
/**
* The width of this object.
*/
protected int w;
/**
* The height of this object.
*/
protected int h;
/**
* The visibility of this object.
*/
protected boolean isVisible;
/**
* The color of this object.
*/
protected MmgColor color;
/**
* The version of this MmgApi.
*/
private final String version = "1.0.1"; //"1.0.0";
/**
* Flag indicating if this MmgObj has a parent container.
*/
protected boolean hasParent;
/**
* Parent object if available.
*/
protected MmgObj parent;
/**
* The name of this MmgObj.
*/
protected String name;
/**
* The id of this MmgObj.
*/
protected String mmgUid;
/**
* Constructor for this class.
*/
public MmgObj() {
pos = MmgVector2.GetOriginVec();
w = 0;
h = 0;
isVisible = true;
color = MmgColor.GetWhite();
hasParent = false;
parent = null;
name = "";
mmgUid = "";
}
/**
* Constructor with identification.
*
* @param n Name of the MmgObj.
* @param i Id of the MmgObj.
*/
public MmgObj(String n, String i) {
pos = MmgVector2.GetOriginVec();
w = 0;
h = 0;
isVisible = true;
color = MmgColor.GetWhite();
hasParent = false;
parent = null;
name = n;
mmgUid = i;
}
/**
* Constructor for this class that sets the position, dimensions, visibility, and color of this object.
*
* @param X The X coordinate of this object's position.
* @param Y The Y coordinate of this object's position.
* @param W The width of this object.
* @param H The height of this object.
* @param isv The visibility of this object.
* @param c The color of this object.
*/
public MmgObj(int X, int Y, int W, int H, boolean isv, MmgColor c) {
pos = new MmgVector2(X, Y);
w = W;
h = H;
isVisible = isv;
color = c;
hasParent = false;
parent = null;
name = "";
mmgUid = "";
}
/**
* Constructor for this class that sets the position, dimensions, visibility, and color of this object.
*
* @param X The X coordinate of this object's position.
* @param Y The Y coordinate of this object's position.
* @param W The width of this object.
* @param H The height of this object.
* @param isv The visibility of this object.
* @param c The color of this object.
* @param n The name you want to give this object.
* @param i The id you want to give this object.
*/
public MmgObj(int X, int Y, int W, int H, boolean isv, MmgColor c, String n, String i) {
pos = new MmgVector2(X, Y);
w = W;
h = H;
isVisible = isv;
color = c;
hasParent = false;
parent = null;
name = n;
mmgUid = i;
}
/**
* Constructor for this class that sets the position, dimensions, visibility, and color of this object.
*
* @param v2 The position of this object.
* @param W The width of this object.
* @param H The height of this object.
* @param isv The visibility of this object.
* @param c The color of this object.
*/
public MmgObj(MmgVector2 v2, int W, int H, boolean isv, MmgColor c) {
pos = v2;
w = W;
h = H;
isVisible = isv;
color = c;
hasParent = false;
parent = null;
name = "";
mmgUid = "";
}
/**
* Constructor for this class that sets the position, dimensions, visibility, and color of this object.
*
* @param v2 The position of this object.
* @param W The width of this object.
* @param H The height of this object.
* @param isv The visibility of this object.
* @param c The color of this object.
* @param n The name you want to give this object.
* @param i The id you want to give this object.
*/
public MmgObj(MmgVector2 v2, int W, int H, boolean isv, MmgColor c, String n, String i) {
pos = v2;
w = W;
h = H;
isVisible = isv;
color = c;
hasParent = false;
parent = null;
name = n;
mmgUid = i;
}
/**
* Constructor for this object that sets all the attribute values to the values of the attributes
* of the given argument.
*
* @param obj The object to use to set all local attributes.
*/
@SuppressWarnings("OverridableMethodCallInConstructor")
public MmgObj(MmgObj obj) {
if(obj.GetPosition() != null) {
SetPosition(obj.GetPosition().Clone());
}else {
SetPosition(obj.GetPosition());
}
SetWidth(obj.GetWidth());
SetHeight(obj.GetHeight());
SetIsVisible(obj.GetIsVisible());
if(obj.GetMmgColor() != null) {
SetMmgColor(obj.GetMmgColor().Clone());
}else {
SetMmgColor(obj.GetMmgColor());
}
SetHasParent(obj.GetHasParent());
SetParent(obj.GetParent());
SetName(obj.GetName());
SetId(obj.GetId());
}
/**
* Clones this object.
*
* @return A clone of this object.
*/
public MmgObj Clone() {
MmgObj ret = new MmgObj(this);
return ret;
}
/**
* Gets the API version number.
*
* @return The API version number.
*/
public String GetVersion() {
return version;
}
/**
* Base drawing class, does nothing.
*
* @param p The MmgPen that would be used to draw this object.
*/
public void MmgDraw(MmgPen p) {
//do nothing
if(isVisible == true) {
}else {
//do nothing
}
}
public boolean MmgUpdate(int updateTick, long currentTimeMs, long msSinceLastFrame) {
if(isVisible == true) {
}else {
//do nothing
}
return false;
}
/**
* Gets the visibility of this class.
*
* @return True if this class is visible, false otherwise.
*/
public boolean GetIsVisible() {
return isVisible;
}
/**
* Sets the invisibility of this class.
*
* @param bl True if this class is visible, false otherwise.
*/
public void SetIsVisible(boolean bl) {
isVisible = bl;
}
/**
* Gets the width of this object.
*
* @return The width of this object.
*/
public int GetWidth() {
return w;
}
/**
* Sets the width of this object.
*
* @param W The width of this object.
*/
public void SetWidth(int W) {
w = W;
}
/**
* Gets the height of this object.
*
* @return The height of this object.
*/
public int GetHeight() {
return h;
}
/**
* Sets the height of this object.
*
* @param H The height of this object.
*/
public void SetHeight(int H) {
h = H;
}
/**
* Sets the position of this object.
*
* @param v The position of this object.
*/
public void SetPosition(MmgVector2 v) {
pos = v;
}
/**
* Gets the position of this object.
*
* @return The position of this object.
*/
public MmgVector2 GetPosition() {
return pos;
}
/**
* Gets the color of this object.
*
* @return The color of this object.
*/
public MmgColor GetMmgColor() {
return color;
}
/**
* Sets the color of this object.
*
* @param c The color of this object.
*/
public void SetMmgColor(MmgColor c) {
color = c;
}
/**
* Sets the X coordinate of this object.
*
* @param inX The X coordinate of this object.
*/
public void SetX(int inX) {
this.GetPosition().SetX(inX);
}
/**
* Gets the X coordinate of this object.
*
* @return The X coordinate of this object.
*/
public int GetX() {
return this.GetPosition().GetX();
}
/**
* Sets the Y coordinate of this object.
*
* @param inY The Y coordinate of this object.
*/
public void SetY(int inY) {
this.GetPosition().SetY(inY);
}
/**
* Gets the Y coordinate of this object.
*
* @return The Y coordinate of this object.
*/
public int GetY() {
return this.GetPosition().GetY();
}
public String GetName() {
return name;
}
public void SetName(String n) {
name = n;
}
public String GetId() {
return mmgUid;
}
public void SetId(String i) {
mmgUid = i;
}
public void SetHasParent(boolean b) {
hasParent = b;
}
public void SetParent(MmgObj o) {
parent = o;
}
public boolean GetHasParent() {
return hasParent;
}
public MmgObj GetParent() {
return parent;
}
public String ToString() {
return "Name: " + GetName() + " Id: " + GetId() + " - " + GetPosition();
}
public boolean Equals(MmgObj o) {
if(o != null
&& o.GetHasParent() == GetHasParent()
&& o.GetIsVisible() == GetIsVisible()
&& o.GetHeight() == GetHeight()
&& ((o.GetId() == null && GetId() == null) || (o.GetId() != null && GetId() != null && o.GetId().equals(GetId())))
&& ((o.GetName() == null && GetName() == null) || (o.GetName() != null && GetName() != null && o.GetName().equals(GetName())))
&& ((o.GetParent() == null && GetParent() == null) || (o.GetParent() != null && GetParent() != null && o.GetParent().Equals(GetParent())))
&& ((o.GetPosition() == null && GetPosition() == null) || (o.GetPosition() != null && GetPosition() != null && o.GetPosition().Equals(GetPosition())))
) {
return true;
}else {
return false;
}
}
}
- color: The MmgColor object sets the color of this object if applicable.
- h: An integer representing the height of this MmgObj.
- hasParent: A boolean flag indicating if this MmgObj has a parent.
- isVisible: A boolean flag indicating if this object should be drawn or not.
- mmgUid: A unique integer for this object if API level image caching is on this integer is used as a unique index into an image lookup object.
- name: The name of this object in string form.
- parent: The parent MmgObj of this object.
- pos: An MmgVector2 object that is the position of this object.
- w: An integer representing the width of this object.
As you can see the class contains variables that are used in tracking the position of the object and it's size. The class
offers a number of constructors you can look over them here.
They allow customization of internal variables on instantation. There are also a number of getter and setter methods but these
are straight forward as well. Let's look at some of the special, game API specific, methods in our class.
- Clone()
- Equals(MmgObj o)
- MmgDraw(MmgPen p)
- MmgUpdate(int updateTick, long currentTimeMs, long msSinceLastFrame)
- ToString()
We'll begin to go over these one by one. First up Clone, this method returns an object that is new but has the same internal
variable state as the instance it is called from. This is a useful method for keeping copies of objects at a given state.
The cloned object will result in cloned_copy.equals(original_copy) == false always being the case. The cloned instance shares
references with the original instance.
Next up we have the Equals method this method is not like the java equals method it compares the internal variable state of this
instance with that of the passed in instance. This is very useful for testing equality at the API level. Our MmgDraw method is
where our drawing will be done. It takes an MmgPen object instance as an argument. The MmgPen class supports drawing higher
level API objects. You can also access lower level drawing objects, java swing graphics contexts, for drawing at a slightly lower level.
This method will get called once a frame for visible MmgObjs.
The next method in our list is the MmgUpdate method. It is called before the MmgDraw method. The MmgUpdate
method should be used to update an visible children MmgObjs before the next draw call. There are a few special parameters
passed into this method. They have to do with call sequencing and timing. The updateTick is the number of MmgUpdate
made since the main drawing loop began. The currentTimeMs parameter is the system time the main update call began, time in between
previous MmgUpdate calls is not tracked. The last parameter, msSinceLastFrame, is the number of milliseconds since the last update
call. This can be very useful in timing, animations, and triggers.
We'll attempt to use our MmgObj class in a little demo and show you how to begin drawing graphics on the screen. Let's take a look
at the code below.
MmgBmp tB = null;
tB = TyreDatGameUtils.GetBasicBmp("../cfg/drawable/logo_large.jpg");
Hmmm, there are some new classes here. A quick inspection seems to indicate that we're loading up an image from the file logo_large.jpg
and storing it in a local variable. We haven't seen the MmgBmp class yet so let's take a look at it and see how images are drawn.
2: The MmgBmp Class
The full class source code is listed below. You can also view its javadoc here.
package net.middlemind.MmgGameApiJava.MmgBase;
import java.awt.*;
/**
* Class that wraps the lower level bitmap object. Created by Middlemind Games
*
* @author Victor G. Brusca
*/
public class MmgBmp extends MmgObj {
/**
* Drawing mode to determine the best way to handle drawing a bitmap.
*/
public enum MmgBmpDrawMode {
DRAW_BMP_FULL,
DRAW_BMP_BASIC_CACHE,
DRAW_BMP_BASIC
};
/**
* The initial value to use for bitmap IDs in unique id mode.
*/
private static int ID_SRC = 0;
/**
* The origin of this object.
*/
private MmgVector2 origin;
/**
* The scaling to apply to this object, if defined.
*/
private MmgVector2 scaling;
/**
* The source drawing rectangle if defined.
*/
private MmgRect srcRect;
/**
* The destination drawing rectangle if defined.
*/
private MmgRect dstRect;
/**
* The image representing this object, if defined.
*/
private Image b;
/**
* The rotation to apply to this object, if defined.
*/
private float rotation;
/**
* The string representation of this objects id.
*/
private String idStr;
/**
* The integer representation of this objects id.
*/
private int id;
/**
* The strategy to use when drawing bitmaps.
*/
public MmgBmpDrawMode DRAW_MODE = MmgBmpDrawMode.DRAW_BMP_BASIC;
/**
* Generic constructor.
*/
public MmgBmp() {
super();
origin = new MmgVector2(0, 0);
scaling = new MmgVector2(1, 1);
srcRect = new MmgRect(0, 0, 0, 0);
dstRect = new MmgRect(0, 0, 0, 0);
b = null;
rotation = 0f;
SetBmpId();
}
/**
* Construct from a previous instance of MmgObj.
*
* @param obj The object to create this class from.
*/
public MmgBmp(MmgObj obj) {
super(obj);
origin = new MmgVector2(0, 0);
scaling = new MmgVector2(1, 1);
srcRect = new MmgRect(0, 0, 0, 0);
dstRect = new MmgRect(0, 0, 0, 0);
b = null;
rotation = 0f;
SetBmpId();
}
/**
* Construct from a previous instance of MmgBmp.
*
* @param bmp The object to create this class from.
*/
@SuppressWarnings("OverridableMethodCallInConstructor")
public MmgBmp(MmgBmp bmp) {
SetRotation(bmp.GetRotation());
if (bmp.GetOrigin() == null) {
SetOrigin(bmp.GetOrigin());
} else {
SetOrigin(bmp.GetOrigin().Clone());
}
if (bmp.GetSrcRect() == null) {
SetSrcRect(bmp.GetSrcRect());
} else {
SetSrcRect(bmp.GetSrcRect().Clone());
}
if (bmp.GetDstRect() == null) {
SetDstRect(bmp.GetDstRect());
} else {
SetDstRect(bmp.GetDstRect().Clone());
}
SetTexture2D(bmp.GetTexture2D());
if (bmp.GetPosition() == null) {
SetPosition(bmp.GetPosition());
} else {
SetPosition(bmp.GetPosition().Clone());
}
if (bmp.GetScaling() == null) {
SetScaling(bmp.GetScaling());
} else {
SetScaling(bmp.GetScaling().Clone());
}
SetWidth(bmp.GetUnscaledWidth());
SetHeight(bmp.GetUnscaledHeight());
SetIsVisible(bmp.GetIsVisible());
if (bmp.GetMmgColor() == null) {
SetMmgColor(bmp.GetMmgColor());
} else {
SetMmgColor(bmp.GetMmgColor().Clone());
}
SetBmpId();
}
/**
* Construct from a lower level Image objects.
*
* @param t The object to create this instance from.
* @see Image
*/
@SuppressWarnings("OverridableMethodCallInConstructor")
public MmgBmp(Image t) {
SetRotation(0f);
SetOrigin(MmgVector2.GetOriginVec());
SetScaling(MmgVector2.GetUnitVec());
MmgRect r = new MmgRect(MmgVector2.GetOriginVec(), t.getWidth(null), t.getHeight(null));
SetSrcRect(r);
SetDstRect(null);
SetTexture2D(t);
SetPosition(MmgVector2.GetOriginVec());
SetWidth(b.getWidth(null));
SetHeight(b.getHeight(null));
SetIsVisible(true);
SetMmgColor(null);
SetBmpId();
}
/**
* Construct this instance from a lower level image object and some
* rendering hints.
*
* @param t The lower level Image object to create this instance from.
* @param Src The source drawing rectangle.
* @param Dst The destination drawing rectangle.
* @param Origin The origin this image should be rotated from.
* @param Scaling The scaling values to use when drawing this image.
* @param Rotation The rotation values to use when drawing this image.
*/
@SuppressWarnings("OverridableMethodCallInConstructor")
public MmgBmp(Image t, MmgRect Src, MmgRect Dst, MmgVector2 Origin, MmgVector2 Scaling, float Rotation) {
SetRotation(Rotation);
SetOrigin(Origin);
SetScaling(Scaling);
SetSrcRect(Src);
SetDstRect(Dst);
SetTexture2D(t);
SetPosition(MmgVector2.GetOriginVec());
SetWidth(b.getWidth(null));
SetHeight(b.getHeight(null));
SetIsVisible(true);
SetMmgColor(null);
SetBmpId();
}
/**
* Construct this instance from a lower level image object and some
* rendering hints.
*
* @param t The lower level Image object to create this instance from.
* @param Position The position this object should be drawn at.
* @param Origin The origin this image should be rotated from.
* @param Scaling The scaling values to use when drawing this image.
* @param Rotation The rotation values to use when drawing this image.
*/
@SuppressWarnings("OverridableMethodCallInConstructor")
public MmgBmp(Image t, MmgVector2 Position, MmgVector2 Origin, MmgVector2 Scaling, float Rotation) {
SetRotation(Rotation);
SetOrigin(Origin);
SetScaling(Scaling);
MmgRect r = new MmgRect(Position, t.getWidth(null), t.getHeight(null));
SetSrcRect(r);
SetDstRect(null);
SetTexture2D(t);
SetPosition(Position);
SetWidth(b.getWidth(null));
SetHeight(b.getHeight(null));
SetIsVisible(true);
SetMmgColor(null);
SetBmpId();
}
/**
* Returns an id string, used in image caching, based on rotation.
*
* @param rotation The rotation value to use in id string creation.
* @return A new id string.
* @see MmgPen
*/
public String GetIdStr(float rotation) {
return (idStr + "_" + rotation);
}
/**
* Returns an id string, used in image caching, based on scaling.
*
* @param scaling The scaling value to use in id string creation.
* @return A new id string.
* @see MmgPen
*/
public String GetIdStr(MmgVector2 scaling) {
return (idStr + "_" + scaling.GetXFloat() + "x" + scaling.GetYFloat());
}
/**
*
*
* @param rotation
* @param scaling
* @return
*/
public String GetIdStr(float rotation, MmgVector2 scaling) {
return (idStr + "_" + rotation + "_" + scaling.GetXFloat() + "x" + scaling.GetYFloat());
}
/**
* Id helper method, takes rotation into account when making an id.
*
* @param rotation The rotation of the bitmap.
* @return The unique id of the bitmap.
*/
public int GetId(float rotation) {
return Integer.parseInt((id + "0" + (int) (rotation)));
}
/**
* Id helper method, takes scaling into account when making an id.
*
* @param scaling The scaling to apply to the object.
* @return The unique id of the bitmap.
*/
public int GetId(MmgVector2 scaling) {
return Integer.parseInt((idStr + "0" + (int) (scaling.GetXFloat() * 10) + "0" + (int) (scaling.GetYFloat() * 10)));
}
/**
* If helper method, takes rotation, and scaling into account when making an
* id.
*
* @param rotation The rotation of the bitmap.
* @param scaling The scaling of the bitmap.
* @return The unique id of the bitmap.
*/
public int GetId(float rotation, MmgVector2 scaling) {
return Integer.parseInt((idStr + "0" + (int) (rotation) + "0" + (int) (scaling.GetXFloat() * 10) + "0" + (int) (scaling.GetYFloat() * 10)));
}
/**
* Get the unique id of the bitmap in string form.
*
* @return The string form of the unique id.
*/
public String GetBmpIdStr() {
return idStr;
}
/**
* Sets the string form of the id.
*
* @param IdStr A unique id string.
*/
public void SetBmpIdStr(String IdStr) {
idStr = IdStr;
}
/**
* Gets the string form of the id.
*
* @return A unique id integer.
*/
public int GetBmpId() {
return id;
}
/**
* Sets the unique id integer and string representations using a common
* method.
*/
private void SetBmpId() {
id = MmgBmp.ID_SRC;
idStr = (id + "");
MmgBmp.ID_SRC++;
}
/**
* Clones the current object.
*
* @return Returns a new MmgObj based on the original MmgObj.
*/
@Override
public MmgObj Clone() {
MmgBmp ret = new MmgBmp(this);
return (MmgObj) ret;
}
/**
* Returns the image of this bitmap.
*
* @return This bitmaps image.
*/
public Image GetTexture2D() {
return b;
}
/**
* Sets the image of this bitmap.
*
* @param d The image to set for this bitmap.
*/
public void SetTexture2D(Image d) {
b = d;
}
/**
* Gets the image of this bitmap. Same as GetTexture2D.
*
* @return The image of this bitmap.
*/
public Image GetImage() {
return GetTexture2D();
}
/**
* Sets the image of this bitmap. Same as SetTexture2D.
*
* @param d The image to set for this bitmap.
*/
public void SetImage(Image d) {
SetTexture2D(d);
}
/**
* Gets the source drawing rectangle of this bitmap. Only used by drawing
* methods in the MmgPen class that supports, source, or source, destination
* drawing methods.
*
* @return The source drawing rectangle.
* @see MmgPen
*/
public MmgRect GetSrcRect() {
return srcRect;
}
/**
* Sets the source drawing rectangle. Only used by drawing methods in the
* MmgPen class that supports, source, or source, destination drawing
* methods.
*
* @param r The source drawing rectangle.
* @see MmgPen
*/
public void SetSrcRect(MmgRect r) {
srcRect = r;
}
/**
* Gets the destination drawing rectangle.
*
* @return The destination drawing rectangle.
*/
public MmgRect GetDstRect() {
return dstRect;
}
/**
* Sets the destination drawing rectangle.
*
* @param r The destination drawing rectangle.
*/
public void SetDstRect(MmgRect r) {
dstRect = r;
}
/**
* Gets the rotation of the bitmap.
*
* @return The rotation of the bitmap.
*/
public float GetRotation() {
return rotation;
}
/**
* Sets the rotation of the bitmap.
*
* @param r The rotation of the bitmap.
*/
public final void SetRotation(float r) {
rotation = r;
}
/**
* Gets the origin used in drawing the bitmap.
*
* @return The drawing origin of the bitmap.
*/
public MmgVector2 GetOrigin() {
return origin;
}
/**
* Sets the origin used in drawing the bitmap.
*
* @param v The drawing origin of the bitmap.
*/
public void SetOrigin(MmgVector2 v) {
origin = v;
}
/**
* Gets the scaling value used to scale the bitmap.
*
* @return The drawing scaling value.
*/
public MmgVector2 GetScaling() {
return scaling;
}
/**
* Sets the scaling value used to scale the bitmap.
*
* @param v The drawing scaling value.
*/
public void SetScaling(MmgVector2 v) {
scaling = v;
}
/**
* Gets the scaled height of this bitmap.
*
* @return The scaled height of this bitmap.
*/
public double GetScaledHeight() {
if (GetScaling() == null) {
return super.GetHeight();
} else {
return ((double) super.GetHeight() * GetScaling().GetXDouble());
}
}
/**
* Gets the un-scaled, original height of the bitmap.
*
* @return The un-scaled, original height of the bitmap.
*/
public int GetUnscaledHeight() {
return super.GetHeight();
}
/**
* Gets the scaled height of the bitmap.
*
* @return The scaled height of the bitmap.
*/
@Override
public int GetHeight() {
return (int) GetScaledHeight();
}
/**
* Gets the scaled height of the bitmap in float form.
*
* @return The scaled height of the bitmap.
*/
public float GetHeightFloat() {
return (float) GetScaledHeight();
}
/**
* Gets the un-scaled, original width of the bitmap.
*
* @return The un-scaled, original width of the bitmap.
*/
public int GetUnscaledWidth() {
return super.GetWidth();
}
/**
* Gets the scaled width of the bitmap.
*
* @return The scaled width of the bitmap.
*/
public double GetScaledWidth() {
if (GetScaling() == null) {
return super.GetWidth();
} else {
return ((double) super.GetWidth() * GetScaling().GetYDouble());
}
}
/**
* Gets the scaled width of the bitmap.
*
* @return The scaled width of the bitmap.
*/
@Override
public int GetWidth() {
return (int) GetScaledWidth();
}
/**
* Gets the scaled width of the bitmap in float form.
*
* @return
*/
public float GetWidthFloat() {
return (float) GetScaledWidth();
}
/**
* The base drawing method for the bitmap object.
*
* @param p The MmgPen used to draw this bitmap.
*/
@Override
public void MmgDraw(MmgPen p) {
if (GetIsVisible() == true) {
if (DRAW_MODE == MmgBmpDrawMode.DRAW_BMP_FULL) {
p.DrawBmp(this);
} else if (DRAW_MODE == MmgBmpDrawMode.DRAW_BMP_BASIC) {
p.DrawBmpBasic(this);
} else if (DRAW_MODE == MmgBmpDrawMode.DRAW_BMP_BASIC_CACHE) {
p.DrawBmpFromCache(this);
}
} else {
//do nothing
}
}
public boolean Equals(MmgBmp b) {
if (b != null) {
//ORIGIN
if (GetOrigin() == null && b.GetOrigin() != null) {
return false;
}
if (GetOrigin() != null && b.GetOrigin() == null) {
return false;
}
if (GetOrigin() != null && b.GetOrigin() != null && GetOrigin().Equals(b.GetOrigin()) == false) {
return false;
}
//SCALING
if (GetScaling() == null && b.GetScaling() != null) {
return false;
}
if (GetScaling() != null && b.GetScaling() == null) {
return false;
}
if (GetScaling() != null && b.GetScaling() != null && GetScaling().Equals(b.GetScaling()) == false) {
return false;
}
//SRC RECT
if (GetSrcRect() == null && b.GetSrcRect() != null) {
return false;
}
if (GetSrcRect() != null && b.GetSrcRect() == null) {
return false;
}
if (GetSrcRect() != null && b.GetSrcRect() != null && GetSrcRect().Equals(b.GetSrcRect()) == false) {
return false;
}
//DST RECT
if (GetDstRect() == null && b.GetDstRect() != null) {
return false;
}
if (GetDstRect() != null && b.GetDstRect() == null) {
return false;
}
if (GetDstRect() != null && b.GetDstRect() != null && GetDstRect().Equals(b.GetDstRect()) == false) {
return false;
}
//IMAGE
if (GetImage() == null && b.GetImage() != null) {
return false;
}
if (GetImage() != null && b.GetImage() == null) {
return false;
}
if (GetImage() != null && b.GetImage() != null && GetImage().equals(b.GetImage()) == false) {
return false;
}
//OTHER VARS
if (GetRotation() != b.GetRotation()) {
return false;
}
if (GetBmpIdStr().equals(b.GetBmpIdStr()) == true) {
return false;
}
if (GetBmpId() == b.GetBmpId()) {
return false;
}
if (DRAW_MODE != b.DRAW_MODE) {
return false;
}
MmgObj o1 = (MmgObj) this;
MmgObj o2 = (MmgObj) b;
if (o1 != null && o2 != null && o1.Equals(o2) == false) {
return false;
}
} else {
return false;
}
return true;
}
}
Now let's review the local class variables.
- ID_SRC: A static variable used to track unique image ids.
- origin: An MmgVector2 instance that stores the image's origin point.
- scaling: An MmgVector2 instance that stores the horizontal nad vertical scaling value.
- srcRect: The source rectangle for rectangle based drawing of an image region.
- dstRect: The destination rectangle for rectangle based drawing of an image region.
- b: The graphics context class that holds our image.
- rotation: A float representation of this image's rotation to be applied when drawn.
- idStr: A string representation of this object's id.
- id: An integer representation of this object's id.
- DRAW_MODE: Set's some general guidelines for the object's drawing mode.
Most of the variables seem reasonable and self explanatory for an image drawing class. They are things we need to think about and keep track of
when drawing images. So what's so cool about MmgBmp? And how does it draw to a specific screen location if it doesn't have variables for tracking its X,Y
coordinate you ask? If you noticed have a coke and a smile. Tae a closer look at how MmgBmp is declared.
public class MmgBmp extends MmgObj {
This means that our MmgBmp class has all the functionality of our MmgObj class built in. Let's take a look at the MmgDraw method of our class, we'll post the code below.
package net.middlemind.MmgGameApiJava.MmgBase;
import java.awt.*;
/**
* Class that wraps the lower level bitmap object. Created by Middlemind Games
*
* @author Victor G. Brusca
*/
public class MmgBmp extends MmgObj {
/**
* Drawing mode to determine the best way to handle drawing a bitmap.
*/
public enum MmgBmpDrawMode {
DRAW_BMP_FULL,
DRAW_BMP_BASIC_CACHE,
DRAW_BMP_BASIC
};
/**
* The initial value to use for bitmap IDs in unique id mode.
*/
private static int ID_SRC = 0;
/**
* The origin of this object.
*/
private MmgVector2 origin;
/**
* The scaling to apply to this object, if defined.
*/
private MmgVector2 scaling;
/**
* The source drawing rectangle if defined.
*/
private MmgRect srcRect;
/**
* The destination drawing rectangle if defined.
*/
private MmgRect dstRect;
/**
* The image representing this object, if defined.
*/
private Image b;
/**
* The rotation to apply to this object, if defined.
*/
private float rotation;
/**
* The string representation of this objects id.
*/
private String idStr;
/**
* The integer representation of this objects id.
*/
private int id;
/**
* The strategy to use when drawing bitmaps.
*/
public MmgBmpDrawMode DRAW_MODE = MmgBmpDrawMode.DRAW_BMP_BASIC;
/**
* Generic constructor.
*/
public MmgBmp() {
super();
origin = new MmgVector2(0, 0);
scaling = new MmgVector2(1, 1);
srcRect = new MmgRect(0, 0, 0, 0);
dstRect = new MmgRect(0, 0, 0, 0);
b = null;
rotation = 0f;
SetBmpId();
}
/**
* Construct from a previous instance of MmgObj.
*
* @param obj The object to create this class from.
*/
public MmgBmp(MmgObj obj) {
super(obj);
origin = new MmgVector2(0, 0);
scaling = new MmgVector2(1, 1);
srcRect = new MmgRect(0, 0, 0, 0);
dstRect = new MmgRect(0, 0, 0, 0);
b = null;
rotation = 0f;
SetBmpId();
}
/**
* Construct from a previous instance of MmgBmp.
*
* @param bmp The object to create this class from.
*/
@SuppressWarnings("OverridableMethodCallInConstructor")
public MmgBmp(MmgBmp bmp) {
SetRotation(bmp.GetRotation());
if (bmp.GetOrigin() == null) {
SetOrigin(bmp.GetOrigin());
} else {
SetOrigin(bmp.GetOrigin().Clone());
}
if (bmp.GetSrcRect() == null) {
SetSrcRect(bmp.GetSrcRect());
} else {
SetSrcRect(bmp.GetSrcRect().Clone());
}
if (bmp.GetDstRect() == null) {
SetDstRect(bmp.GetDstRect());
} else {
SetDstRect(bmp.GetDstRect().Clone());
}
SetTexture2D(bmp.GetTexture2D());
if (bmp.GetPosition() == null) {
SetPosition(bmp.GetPosition());
} else {
SetPosition(bmp.GetPosition().Clone());
}
if (bmp.GetScaling() == null) {
SetScaling(bmp.GetScaling());
} else {
SetScaling(bmp.GetScaling().Clone());
}
SetWidth(bmp.GetUnscaledWidth());
SetHeight(bmp.GetUnscaledHeight());
SetIsVisible(bmp.GetIsVisible());
if (bmp.GetMmgColor() == null) {
SetMmgColor(bmp.GetMmgColor());
} else {
SetMmgColor(bmp.GetMmgColor().Clone());
}
SetBmpId();
}
/**
* Construct from a lower level Image objects.
*
* @param t The object to create this instance from.
* @see Image
*/
@SuppressWarnings("OverridableMethodCallInConstructor")
public MmgBmp(Image t) {
SetRotation(0f);
SetOrigin(MmgVector2.GetOriginVec());
SetScaling(MmgVector2.GetUnitVec());
MmgRect r = new MmgRect(MmgVector2.GetOriginVec(), t.getWidth(null), t.getHeight(null));
SetSrcRect(r);
SetDstRect(null);
SetTexture2D(t);
SetPosition(MmgVector2.GetOriginVec());
SetWidth(b.getWidth(null));
SetHeight(b.getHeight(null));
SetIsVisible(true);
SetMmgColor(null);
SetBmpId();
}
/**
* Construct this instance from a lower level image object and some
* rendering hints.
*
* @param t The lower level Image object to create this instance from.
* @param Src The source drawing rectangle.
* @param Dst The destination drawing rectangle.
* @param Origin The origin this image should be rotated from.
* @param Scaling The scaling values to use when drawing this image.
* @param Rotation The rotation values to use when drawing this image.
*/
@SuppressWarnings("OverridableMethodCallInConstructor")
public MmgBmp(Image t, MmgRect Src, MmgRect Dst, MmgVector2 Origin, MmgVector2 Scaling, float Rotation) {
SetRotation(Rotation);
SetOrigin(Origin);
SetScaling(Scaling);
SetSrcRect(Src);
SetDstRect(Dst);
SetTexture2D(t);
SetPosition(MmgVector2.GetOriginVec());
SetWidth(b.getWidth(null));
SetHeight(b.getHeight(null));
SetIsVisible(true);
SetMmgColor(null);
SetBmpId();
}
/**
* Construct this instance from a lower level image object and some
* rendering hints.
*
* @param t The lower level Image object to create this instance from.
* @param Position The position this object should be drawn at.
* @param Origin The origin this image should be rotated from.
* @param Scaling The scaling values to use when drawing this image.
* @param Rotation The rotation values to use when drawing this image.
*/
@SuppressWarnings("OverridableMethodCallInConstructor")
public MmgBmp(Image t, MmgVector2 Position, MmgVector2 Origin, MmgVector2 Scaling, float Rotation) {
SetRotation(Rotation);
SetOrigin(Origin);
SetScaling(Scaling);
MmgRect r = new MmgRect(Position, t.getWidth(null), t.getHeight(null));
SetSrcRect(r);
SetDstRect(null);
SetTexture2D(t);
SetPosition(Position);
SetWidth(b.getWidth(null));
SetHeight(b.getHeight(null));
SetIsVisible(true);
SetMmgColor(null);
SetBmpId();
}
/**
* Returns an id string, used in image caching, based on rotation.
*
* @param rotation The rotation value to use in id string creation.
* @return A new id string.
* @see MmgPen
*/
public String GetIdStr(float rotation) {
return (idStr + "_" + rotation);
}
/**
* Returns an id string, used in image caching, based on scaling.
*
* @param scaling The scaling value to use in id string creation.
* @return A new id string.
* @see MmgPen
*/
public String GetIdStr(MmgVector2 scaling) {
return (idStr + "_" + scaling.GetXFloat() + "x" + scaling.GetYFloat());
}
/**
*
*
* @param rotation
* @param scaling
* @return
*/
public String GetIdStr(float rotation, MmgVector2 scaling) {
return (idStr + "_" + rotation + "_" + scaling.GetXFloat() + "x" + scaling.GetYFloat());
}
/**
* Id helper method, takes rotation into account when making an id.
*
* @param rotation The rotation of the bitmap.
* @return The unique id of the bitmap.
*/
public int GetId(float rotation) {
return Integer.parseInt((id + "0" + (int) (rotation)));
}
/**
* Id helper method, takes scaling into account when making an id.
*
* @param scaling The scaling to apply to the object.
* @return The unique id of the bitmap.
*/
public int GetId(MmgVector2 scaling) {
return Integer.parseInt((idStr + "0" + (int) (scaling.GetXFloat() * 10) + "0" + (int) (scaling.GetYFloat() * 10)));
}
/**
* If helper method, takes rotation, and scaling into account when making an
* id.
*
* @param rotation The rotation of the bitmap.
* @param scaling The scaling of the bitmap.
* @return The unique id of the bitmap.
*/
public int GetId(float rotation, MmgVector2 scaling) {
return Integer.parseInt((idStr + "0" + (int) (rotation) + "0" + (int) (scaling.GetXFloat() * 10) + "0" + (int) (scaling.GetYFloat() * 10)));
}
/**
* Get the unique id of the bitmap in string form.
*
* @return The string form of the unique id.
*/
public String GetBmpIdStr() {
return idStr;
}
/**
* Sets the string form of the id.
*
* @param IdStr A unique id string.
*/
public void SetBmpIdStr(String IdStr) {
idStr = IdStr;
}
/**
* Gets the string form of the id.
*
* @return A unique id integer.
*/
public int GetBmpId() {
return id;
}
/**
* Sets the unique id integer and string representations using a common
* method.
*/
private void SetBmpId() {
id = MmgBmp.ID_SRC;
idStr = (id + "");
MmgBmp.ID_SRC++;
}
/**
* Clones the current object.
*
* @return Returns a new MmgObj based on the original MmgObj.
*/
@Override
public MmgObj Clone() {
MmgBmp ret = new MmgBmp(this);
return (MmgObj) ret;
}
/**
* Returns the image of this bitmap.
*
* @return This bitmaps image.
*/
public Image GetTexture2D() {
return b;
}
/**
* Sets the image of this bitmap.
*
* @param d The image to set for this bitmap.
*/
public void SetTexture2D(Image d) {
b = d;
}
/**
* Gets the image of this bitmap. Same as GetTexture2D.
*
* @return The image of this bitmap.
*/
public Image GetImage() {
return GetTexture2D();
}
/**
* Sets the image of this bitmap. Same as SetTexture2D.
*
* @param d The image to set for this bitmap.
*/
public void SetImage(Image d) {
SetTexture2D(d);
}
/**
* Gets the source drawing rectangle of this bitmap. Only used by drawing
* methods in the MmgPen class that supports, source, or source, destination
* drawing methods.
*
* @return The source drawing rectangle.
* @see MmgPen
*/
public MmgRect GetSrcRect() {
return srcRect;
}
/**
* Sets the source drawing rectangle. Only used by drawing methods in the
* MmgPen class that supports, source, or source, destination drawing
* methods.
*
* @param r The source drawing rectangle.
* @see MmgPen
*/
public void SetSrcRect(MmgRect r) {
srcRect = r;
}
/**
* Gets the destination drawing rectangle.
*
* @return The destination drawing rectangle.
*/
public MmgRect GetDstRect() {
return dstRect;
}
/**
* Sets the destination drawing rectangle.
*
* @param r The destination drawing rectangle.
*/
public void SetDstRect(MmgRect r) {
dstRect = r;
}
/**
* Gets the rotation of the bitmap.
*
* @return The rotation of the bitmap.
*/
public float GetRotation() {
return rotation;
}
/**
* Sets the rotation of the bitmap.
*
* @param r The rotation of the bitmap.
*/
public final void SetRotation(float r) {
rotation = r;
}
/**
* Gets the origin used in drawing the bitmap.
*
* @return The drawing origin of the bitmap.
*/
public MmgVector2 GetOrigin() {
return origin;
}
/**
* Sets the origin used in drawing the bitmap.
*
* @param v The drawing origin of the bitmap.
*/
public void SetOrigin(MmgVector2 v) {
origin = v;
}
/**
* Gets the scaling value used to scale the bitmap.
*
* @return The drawing scaling value.
*/
public MmgVector2 GetScaling() {
return scaling;
}
/**
* Sets the scaling value used to scale the bitmap.
*
* @param v The drawing scaling value.
*/
public void SetScaling(MmgVector2 v) {
scaling = v;
}
/**
* Gets the scaled height of this bitmap.
*
* @return The scaled height of this bitmap.
*/
public double GetScaledHeight() {
if (GetScaling() == null) {
return super.GetHeight();
} else {
return ((double) super.GetHeight() * GetScaling().GetXDouble());
}
}
/**
* Gets the un-scaled, original height of the bitmap.
*
* @return The un-scaled, original height of the bitmap.
*/
public int GetUnscaledHeight() {
return super.GetHeight();
}
/**
* Gets the scaled height of the bitmap.
*
* @return The scaled height of the bitmap.
*/
@Override
public int GetHeight() {
return (int) GetScaledHeight();
}
/**
* Gets the scaled height of the bitmap in float form.
*
* @return The scaled height of the bitmap.
*/
public float GetHeightFloat() {
return (float) GetScaledHeight();
}
/**
* Gets the un-scaled, original width of the bitmap.
*
* @return The un-scaled, original width of the bitmap.
*/
public int GetUnscaledWidth() {
return super.GetWidth();
}
/**
* Gets the scaled width of the bitmap.
*
* @return The scaled width of the bitmap.
*/
public double GetScaledWidth() {
if (GetScaling() == null) {
return super.GetWidth();
} else {
return ((double) super.GetWidth() * GetScaling().GetYDouble());
}
}
/**
* Gets the scaled width of the bitmap.
*
* @return The scaled width of the bitmap.
*/
@Override
public int GetWidth() {
return (int) GetScaledWidth();
}
/**
* Gets the scaled width of the bitmap in float form.
*
* @return
*/
public float GetWidthFloat() {
return (float) GetScaledWidth();
}
/**
* The base drawing method for the bitmap object.
*
* @param p The MmgPen used to draw this bitmap.
*/
@Override
public void MmgDraw(MmgPen p) {
if (GetIsVisible() == true) {
if (DRAW_MODE == MmgBmpDrawMode.DRAW_BMP_FULL) {
p.DrawBmp(this);
} else if (DRAW_MODE == MmgBmpDrawMode.DRAW_BMP_BASIC) {
p.DrawBmpBasic(this);
} else if (DRAW_MODE == MmgBmpDrawMode.DRAW_BMP_BASIC_CACHE) {
p.DrawBmpFromCache(this);
}
} else {
//do nothing
}
}
public boolean Equals(MmgBmp b) {
if (b != null) {
//ORIGIN
if (GetOrigin() == null && b.GetOrigin() != null) {
return false;
}
if (GetOrigin() != null && b.GetOrigin() == null) {
return false;
}
if (GetOrigin() != null && b.GetOrigin() != null && GetOrigin().Equals(b.GetOrigin()) == false) {
return false;
}
//SCALING
if (GetScaling() == null && b.GetScaling() != null) {
return false;
}
if (GetScaling() != null && b.GetScaling() == null) {
return false;
}
if (GetScaling() != null && b.GetScaling() != null && GetScaling().Equals(b.GetScaling()) == false) {
return false;
}
//SRC RECT
if (GetSrcRect() == null && b.GetSrcRect() != null) {
return false;
}
if (GetSrcRect() != null && b.GetSrcRect() == null) {
return false;
}
if (GetSrcRect() != null && b.GetSrcRect() != null && GetSrcRect().Equals(b.GetSrcRect()) == false) {
return false;
}
//DST RECT
if (GetDstRect() == null && b.GetDstRect() != null) {
return false;
}
if (GetDstRect() != null && b.GetDstRect() == null) {
return false;
}
if (GetDstRect() != null && b.GetDstRect() != null && GetDstRect().Equals(b.GetDstRect()) == false) {
return false;
}
//IMAGE
if (GetImage() == null && b.GetImage() != null) {
return false;
}
if (GetImage() != null && b.GetImage() == null) {
return false;
}
if (GetImage() != null && b.GetImage() != null && GetImage().equals(b.GetImage()) == false) {
return false;
}
//OTHER VARS
if (GetRotation() != b.GetRotation()) {
return false;
}
if (GetBmpIdStr().equals(b.GetBmpIdStr()) == true) {
return false;
}
if (GetBmpId() == b.GetBmpId()) {
return false;
}
if (DRAW_MODE != b.DRAW_MODE) {
return false;
}
MmgObj o1 = (MmgObj) this;
MmgObj o2 = (MmgObj) b;
if (o1 != null && o2 != null && o1.Equals(o2) == false) {
return false;
}
} else {
return false;
}
return true;
}
}
Let's take a dive into some code. The drawing mode is used to choose which method the MmgPen will use to draw our image. The DRAW_BMP_FULL enumeration option
takes into account all the local variables when drawing our image but this might be overkill for a game because we most likely will have our images setup such that they
need as little programmatic manipulation as possible. Also, if we need to manipulate an image it would make more sense to do it once and save the altered image and use that
in our drawing routines than to constantly make sure the image is rotated, resized, etc. when drawing it. For a quick review of enumerations, I highly suggest you
read it if you're fuzzy on enums - they are super useful - can be found here. The DRAW_BMP_BASIC
enum option is for simple image drawing with little to no on the fly manipulations. The DRAW_BMP_BASIC_CACHE is similar to DRAW_BMP_BASIC but it uses an internal image cache
to cut down on the number of redundant images in memory.
But wait we missed something subtle. Look again at our MmgBmp class's MmgDraw method again. You'll notice this little line of code.
if(GetIsVisible() == true) {
A quick inspection shows us that method is not in our MmgBmp class. So where did it come from? It comes from the MmgObj that MmgBmp has extended.
So you can think of the MmgBmp class as a special version of the MmgObj class that is designed to draw images. Think of it like a trout java class as being a
special version of a fish java class. The trout class extends the fish class by adding some trout specific variables and values to the mix but it's still a fish.
3: Drawing Images to the Screen
The next step in this tutorial is to draw some images to the screen. The project for this step can be found here and is listed
above as the base project for this tutorial. Drawing images to the screen will give us an idea hwo the API is used and how our MmgBmp, MmgObj classes plug into
the java GUI framework we setup in an earlier tutorial, in case you want to the first tutorial is located here. Let's
take a look at how we can introduce some image drawing to our GamePanel class for a down and dirty test. Let's open up our GamePanel class and add an MmgBmp member variable
to it, and we can initialize that variable in our constructor.
MmgBmp tB;
....
tB = TyreDatGameUtils.GetBasicBmp("../cfg/drawable/logo-large.png");
Now we can add some code to the GamePanel class's MmgDraw method such that the image is drawn in the center of the screen.
But wait let's see how we can set the location of the MmgBmp instance. We'll set the position after we instatiate our variable.
MmgHelper.CenterHorAndVert(tB);
We're going to use the help class method, a conveinience method, CenterHorAndVert to position our image. In the MmgDraw method
by the commented out currentScreen code, let's add a check and try and draw our logo in the center of the screen.
if(tB != null) { tb.MmgDraw(p); }
You'll notice that the API is flexible and allows you to draw the MmgBmp from a load class method of from the pen class.
Generally we let the MmgBmp object handle the drawing. Now let's compile and run the project, these changes already exist in the code
you only have to follow along and make sure you understand what we're doing. You should configure you project's run settings to match the following
image if it is not that way already.
If we run our project we should see an image on the sceen that looks like the screenshot below. Take a moment to look at the frame rate while the software runs.
4: Game Screen Class
Now that we can draw images on the screen we are going to implement a splash screen and game state such that our application will change it's game state and render
an encapsulated game screen class. Game screens are just what they sound like a screen in our game. Here are some exmaples you might come across, splash screen,
loading screen, main menu screen, game rendering screen. A splash screen is very simple in nature so it's a great place to start. Fist we're going to take a look
at the MmgGameScreen class, this is an API level class and not directly a part of our projects mind you. We'll be exploring the code and trying to get an idea
of how we can use it to make more customized game screens.
package net.middlemind.MmgGameApiJava.MmgBase;
/**
* Class that represents a basic game screen. Created by Middlemind Games
*
* @author Victor G. Brusca
*/
public class MmgGameScreen extends MmgObj {
/**
* Pause this screen.
*/
protected boolean pause;
/**
* Is this screen ready.
*/
protected boolean ready;
/**
* The MmgContainer that holds all the child objects.
*/
private MmgContainer objects;
/**
* A place holder for the background object of the game screen.
*/
private MmgObj background;
/**
* A place holder for the foreground object of the game screen.
*/
private MmgObj foreground;
/**
* A place holder for the header object.
*/
private MmgObj header;
/**
* A place holder for the footer object.
*/
private MmgObj footer;
/**
* A place holder for the left menu cursor.
*/
private MmgObj leftCursor;
/**
* A place holder for the right menu cursor.
*/
private MmgObj rightCursor;
/**
* A place holder for the message object of the game screen.
*/
private MmgObj message;
/**
* The MmgMenuContainer place holder for holding a menu.
*/
private MmgMenuContainer menu;
/**
* Helper variables for the menu.
*/
private int menuIdx;
/**
* Helper variables for the menu.
*/
private int menuStart;
/**
* Helper variables for the menu.
*/
private int menuStop;
private int menuCursorLeftOffsetX;
private int menuCursorLeftOffsetY;
private int menuCursorRightOffsetX;
private int menuCursorRightOffsetY;
/**
* Event handler for update events.
*/
private MmgUpdateHandler updateHandler;
/**
* Flag to indicate if the menu is used on this game screen.
*/
private boolean menuOn;
/**
* Constructor for this class.
*/
@SuppressWarnings("OverridableMethodCallInConstructor")
public MmgGameScreen() {
super();
pause = false;
ready = false;
objects = new MmgContainer();
menu = new MmgMenuContainer();
background = null;
foreground = null;
header = null;
footer = null;
leftCursor = null;
rightCursor = null;
message = null;
menuIdx = 0;
menuStart = 0;
menuStop = 0;
SetMenuOn(false);
SetWidth(MmgScreenData.GetGameWidth());
SetHeight(MmgScreenData.GetGameHeight());
SetPosition(MmgVector2.GetOriginVec());
}
/**
* Constructor that sets attributes based on the given argument.
*
* @param gm The MmgGameScreen to use for attribute settings.
*/
@SuppressWarnings("OverridableMethodCallInConstructor")
public MmgGameScreen(MmgGameScreen gm) {
SetObjects(gm.GetObjects());
SetMenu(gm.GetMenu());
SetBackground(gm.GetBackground());
SetForeground(gm.GetForeground());
SetHeader(gm.GetHeader());
SetFooter(gm.GetFooter());
SetLeftCursor(gm.GetLeftCursor());
SetRightCursor(gm.GetRightCursor());
SetMessage(gm.GetMessage());
SetMenuOn(gm.GetMenuOn());
SetMenuIdx(gm.GetMenuIdx());
SetMenuStart(gm.GetMenuStart());
SetMenuStop(gm.GetMenuStop());
if (gm.GetPosition() != null) {
SetPosition(gm.GetPosition().Clone());
} else {
SetPosition(gm.GetPosition());
}
SetWidth(gm.GetWidth());
SetHeight(gm.GetHeight());
SetMmgColor(gm.GetMmgColor());
}
/**
* Clone of this object.
*
* @return A clone of this object.
*/
@Override
public MmgObj Clone() {
MmgGameScreen ret = new MmgGameScreen(this);
return (MmgObj) ret;
}
public int GetMenuCursorLeftOffsetX() {
return menuCursorLeftOffsetX;
}
public void SetMenuCursorLeftOffsetX(int i) {
menuCursorLeftOffsetX = i;
}
public int GetMenuCursorLeftOffsetY() {
return menuCursorLeftOffsetY;
}
public void SetMenuCursorLeftOffsetY(int i) {
menuCursorLeftOffsetY = i;
}
public int GetMenuCursorRightOffsetX() {
return menuCursorRightOffsetX;
}
public void SetMenuCursorRightOffsetX(int i) {
menuCursorRightOffsetX = i;
}
public int GetMenuCursorRightOffsetY() {
return menuCursorRightOffsetY;
}
public void SetMenuCursorRightOffsetY(int i) {
menuCursorRightOffsetY = i;
}
/**
* Gets true if this game screen has loaded its resources and is ready to
* display itself.
*
* @return True if this object is ready, false otherwise.
*/
public final boolean IsReady() {
return ready;
}
/**
* Sets if this game screen is ready to display itself.
*
* @param b A boolean indicating if this object is ready for display.
*/
public final void SetReady(boolean b) {
ready = b;
}
/**
* Pauses this object. If paused no drawing occurs.
*/
public final void Pause() {
pause = true;
SetIsVisible(false);
}
/**
* Un-pause this object. If paused no drawing occurs.
*/
public final void UnPause() {
pause = false;
SetIsVisible(true);
}
/**
* Gets the pause state of this object.
*
* @return True if this object was paused, false otherwise.
*/
public final boolean IsPaused() {
if (pause == true) {
return true;
} else {
return false;
}
}
/**
* Gets if the menu is on.
*
* @return The menu on flag.
*/
public boolean GetMenuOn() {
return menuOn;
}
/**
* Sets if the menu is on.
*
* @param m The menu on flag.
*/
public void SetMenuOn(boolean m) {
menuOn = m;
}
/**
* Adds an MmgObj to the game screen.
*
* @param obj The object to add.
*/
public void AddObj(MmgObj obj) {
if (objects != null) {
objects.Add(obj);
}
}
/**
* Removes an MmgObj from the game screen.
*
* @param obj The object to remove.
*/
public void RemoveObj(MmgObj obj) {
if (objects != null) {
objects.Remove(obj);
}
}
/**
* Clears the objects on this screen.
*/
public void ClearObjs() {
if (objects != null) {
objects.Clear();
}
}
/**
* Event handler for processing simple menu events.
*
* @param e The MmgEvent object to handle.
*/
@SuppressWarnings("UnusedAssignment")
public void EventHandler(MmgEvent e) {
if (e.GetEventId() == MmgEvent.EVENT_ID_UP) {
MoveMenuSelUp();
} else if (e.GetEventId() == MmgEvent.EVENT_ID_DOWN) {
MoveMenuSelDown();
} else if (e.GetEventId() == MmgEvent.EVENT_ID_ENTER) {
if (menu != null) {
Object[] objs = menu.GetArray();
MmgMenuItem item = null;
item = (MmgMenuItem) objs[menuIdx];
ProcessMenuItemSel(item);
}
} else if (e.GetEventId() == MmgEvent.EVENT_ID_SPACE) {
if (menu != null) {
Object[] objs = menu.GetArray();
MmgMenuItem item = null;
item = (MmgMenuItem) objs[menuIdx];
ProcessMenuItemSel(item);
}
}
}
/**
* Gets the object container for this game screen.
*
* @return The MmgContainer used by this game screen.
*/
public MmgContainer GetObjects() {
return objects;
}
/**
* Sets the object container for this game screen.
*
* @param c The MmgContainer used by this game screen.
*/
public void SetObjects(MmgContainer c) {
objects = c;
}
/**
* Gets the background object for this game screen.
*
* @return The background object.
*/
public MmgObj GetBackground() {
return background;
}
/**
* Sets the background object for this game screen.
*
* @param b The background object.
*/
public void SetBackground(MmgObj b) {
background = b;
}
/**
* Sets the background object centered.
*
* @param b The background object.
* @see MmgHelper
*/
public void SetCenteredBackground(MmgObj b) {
MmgHelper.CenterHorAndVert(b);
SetBackground(b);
}
/**
* Gets the foreground object.
*
* @return The foreground object.
*/
public MmgObj GetForeground() {
return foreground;
}
/**
* Sets the foreground object.
*
* @param b The foreground object.
*/
public void SetForeground(MmgObj b) {
foreground = b;
}
/**
* Gets the header object.
*
* @return The header object.
*/
public MmgObj GetHeader() {
return header;
}
/**
* Sets the header object.
*
* @param m The header object.
*/
public void SetHeader(MmgObj m) {
header = m;
MmgHelper.CenterHorAndTop(header);
}
/**
* Gets the footer object.
*
* @return The footer object.
*/
public MmgObj GetFooter() {
return footer;
}
/**
* Sets the footer object.
*
* @param m The footer object.
*/
public void SetFooter(MmgObj m) {
footer = m;
MmgHelper.CenterHorAndBot(footer);
}
/**
* Gets the left menu cursor.
*
* @return The left menu cursor.
*/
public MmgObj GetLeftCursor() {
return leftCursor;
}
/**
* Sets the left menu cursor.
*
* @param m The left menu cursor.
*/
public void SetLeftCursor(MmgObj m) {
leftCursor = m;
}
/**
* Gets the right menu cursor.
*
* @return The right menu cursor.
*/
public MmgObj GetRightCursor() {
return rightCursor;
}
/**
* Sets the right menu cursor.
*
* @param m The right menu cursor.
*/
public void SetRightCursor(MmgObj m) {
rightCursor = m;
}
/**
* Gets the message object.
*
* @return The message object.
*/
public MmgObj GetMessage() {
return message;
}
/**
* Sets the message object.
*
* @param m The message object.
*/
public void SetMessage(MmgObj m) {
message = m;
}
/**
* Gets the MmgMenuContainer object.
*
* @return The MmgMenuContainer object.
*/
public MmgMenuContainer GetMenu() {
return menu;
}
/**
* Sets the MmgMenuContainer object.
*
* @param m The MmgMenuContainer object.
*/
public void SetMenu(MmgMenuContainer m) {
menu = m;
}
/**
* Gets the current menu item index.
*
* @return The menu item index.
*/
public int GetMenuIdx() {
return menuIdx;
}
/**
* Sets the current menu item index.
*
* @param i The menu item index.
*/
public void SetMenuIdx(int i) {
menuIdx = i;
}
/**
* Gets the menu start index.
*
* @return The menu start index.
*/
public int GetMenuStart() {
return menuStart;
}
/**
* Sets the menu start index.
*
* @param i The menu start index.
*/
public void SetMenuStart(int i) {
menuStart = i;
}
/**
* Gets the meu stop index.
*
* @return The menu stop index.
*/
public int GetMenuStop() {
return menuStop;
}
/**
* Sets the menu stop index.
*
* @param i The menu stop index.
*/
public void SetMenuStop(int i) {
menuStop = i;
}
/**
* Centers all default place holder object of this game screen.
*/
public void CenterObjects() {
if (background != null) {
background.SetPosition(new MmgVector2((MmgScreenData.GetGameWidth() - background.GetWidth()) / 2, (MmgScreenData.GetGameHeight() - background.GetHeight()) / 2));
}
if (header != null) {
header.SetPosition(new MmgVector2((MmgScreenData.GetGameWidth() - header.GetWidth()) / 2, (MmgScreenData.GetGameHeight() - header.GetHeight()) / 2));
}
if (footer != null) {
footer.SetPosition(new MmgVector2((MmgScreenData.GetGameWidth() - footer.GetWidth()) / 2, (MmgScreenData.GetGameHeight() - footer.GetHeight()) / 2));
}
if (message != null) {
message.SetPosition(new MmgVector2((MmgScreenData.GetGameWidth() - message.GetWidth()) / 2, (MmgScreenData.GetGameHeight() - message.GetHeight()) / 2));
}
if (foreground != null) {
foreground.SetPosition(new MmgVector2((MmgScreenData.GetGameWidth() - foreground.GetWidth()) / 2, (MmgScreenData.GetGameHeight() - foreground.GetHeight()) / 2));
}
}
/**
* Sets a handler for the update event.
*
* @param u An MmgUpdateHandler to handle events from this object.
*/
public void SetMmgUpdateHandler(MmgUpdateHandler u) {
updateHandler = u;
}
/**
* Gets a handler for the update event.
*
* @return The MmgUpdateHandler that handles update events from this class.
*/
public MmgUpdateHandler GetMmgUpdateHandler() {
return updateHandler;
}
/**
* Fires an update event to the update handler.
*
* @param data The event data to process.
*/
public void Update(Object data) {
if (updateHandler != null) {
updateHandler.MmgHandleUpdate(data);
}
}
/**
* Base draw method, handles drawing this class.
*
* @param p The MmgPen used to draw this object.
*/
@Override
public void MmgDraw(MmgPen p) {
if (IsPaused() == true) {
//do nothing
} else {
if (GetIsVisible() == true) {
if (background != null) {
background.MmgDraw(p);
}
if (header != null) {
header.MmgDraw(p);
}
if (footer != null) {
footer.MmgDraw(p);
}
if (message != null) {
message.MmgDraw(p);
}
if (objects != null) {
objects.MmgDraw(p);
}
if (menuOn == true) {
DrawMenu(p);
}
if (foreground != null) {
foreground.MmgDraw(p);
}
} else {
//do nothing
}
}
}
@Override
public boolean MmgUpdate(int updateTick, long currentTimeMs, long msSinceLastFrame) {
boolean ret = false;
if (IsPaused() == true) {
//do nothing
} else {
if (GetIsVisible() == true) {
if (message != null) {
if (message.MmgUpdate(updateTick, currentTimeMs, msSinceLastFrame) == true) {
ret = true;
}
}
if (objects != null) {
if (objects.MmgUpdate(updateTick, currentTimeMs, msSinceLastFrame) == true) {
ret = true;
}
}
if (foreground != null) {
if (foreground.MmgUpdate(updateTick, currentTimeMs, msSinceLastFrame) == true) {
ret = true;
}
}
} else {
//do nothing
}
}
return ret;
}
public boolean ProcessScreenPress(MmgVector2 v) {
return ProcessScreenPress(v.GetX(), v.GetY());
}
public boolean ProcessScreenPress(int x, int y) {
return true;
}
public boolean ProcessScreenRelease(MmgVector2 v) {
return ProcessScreenPress(v.GetX(), v.GetY());
}
public boolean ProcessScreenRelease(int x, int y) {
return true;
}
public boolean ProcessAClick() {
return true;
}
public boolean ProcessBClick() {
return true;
}
public void ProcessDebugClick() {
}
public boolean ProcessDpadPress(int dir) {
return true;
}
public boolean ProcessDpadRelease(int dir) {
return true;
}
public boolean ProcessDpadClick(int dir) {
return true;
}
/**
* Process a screen click.
*
* @param v The coordinates of the click.
* @return Boolean indicating if a menu item was the target of the click,
* menu item event is fired automatically by this class.
*/
public boolean ProcessScreenClick(MmgVector2 v) {
return ProcessScreenClick(v.GetX(), v.GetY());
}
/**
* Process a screen click.
*
* @param x The X axis coordinate of the screen click.
* @param y The Y axis coordinate of the screen click.
* @return Boolean indicating if a menu item was the target of the click,
* menu item event is fired automatically by this class.
*/
@SuppressWarnings("UnusedAssignment")
public boolean ProcessScreenClick(int x, int y) {
if (menuOn == true && menu != null) {
//MmgDebug.wr("ProcessScreenClick:AAA");
Object[] objs = menu.GetArray();
MmgMenuItem item = null;
if (objs != null) {
//MmgDebug.wr("ProcessScreenClick:BBB");
for (int i = 0; i < objs.length; i++) {
//MmgDebug.wr("ProcessScreenClick:CCC:" + i);
item = (MmgMenuItem) objs[i];
//MmgDebug.wr("ProcessScreenClick:CCC2: [" + x + "] [" + item.GetX() + "," + (item.GetX() + item.GetWidth()) + "]");
if (x >= item.GetX() && x <= (item.GetX() + item.GetWidth())) {
//MmgDebug.wr("ProcessScreenClick:CCC3: [" + y + "] [" + item.GetY() + "," + (item.GetY() + item.GetHeight()) + "]");
if (y >= item.GetY() && y <= (item.GetY() + item.GetHeight())) {
//MmgDebug.wr("ProcessScreenClick:DDD:" + i);
menuIdx = i;
ProcessMenuItemSel(item);
return true;
}
}
}
}
}
return false;
}
/**
* Fire the click event registered in the target menu item object.
*
* @param item The menu item to fire a click event for.
* @see MmgMenuItem
*/
public void ProcessMenuItemSel(MmgMenuItem item) {
if (item != null) {
MmgEvent me = item.GetEventPress();
if (me != null && me.GetTargetEventHandler() != null) {
me.GetTargetEventHandler().MmgHandleEvent(me);
}
}
}
/**
* Move the current menu selection up.
*/
public void MoveMenuSelUp() {
if (menuIdx - 1 >= menuStart) {
menuIdx--;
}
}
/**
* Move the current menu selection down.
*/
public void MoveMenuSelDown() {
if (menuIdx + 1 <= menuStop) {
menuIdx++;
}
}
/**
* Draws the current menu.
*
* @param p The MmgPen object used to draw the menu.
*/
private void DrawMenu(MmgPen p) {
if (menu != null) {
int padPosY = 5;
int padPosX = 5;
Object[] objs = menu.GetArray();
for (int i = 0; i < objs.length; i++) {
if (objs[i] != null) {
MmgMenuItem tmp = (MmgMenuItem) objs[i];
if (tmp != null && tmp.GetIsVisible() == true) {
if (i == menuIdx) {
if (tmp.GetState() != MmgMenuItem.STATE_INACTIVE) {
tmp.SetState(MmgMenuItem.STATE_SELECTED);
}
} else {
if (tmp.GetState() != MmgMenuItem.STATE_INACTIVE) {
tmp.SetState(MmgMenuItem.STATE_NORMAL);
}
}
tmp.MmgDraw(p);
if (menuIdx == i) {
if (leftCursor != null) {
leftCursor.SetPosition(new MmgVector2((tmp.GetX() - leftCursor.GetWidth() - padPosX + menuCursorLeftOffsetX), tmp.GetY() + menuCursorLeftOffsetY));
leftCursor.MmgDraw(p);
}
if (rightCursor != null) {
rightCursor.SetPosition(new MmgVector2((tmp.GetX() + tmp.GetWidth() + padPosX + menuCursorRightOffsetY), tmp.GetY() + menuCursorRightOffsetY));
rightCursor.MmgDraw(p);
}
}
}
}
}
} else {
//menu is null;
}
}
}
You can also view the java documentation here.
First we'll talk a little bit about how the MmgGameScreen class works. It extends the MmgObj
super class so it will plug right into our MmgDraw calling structure. The is an example of the flexibility of our design, the
MmgGameScreen class will contain other MmgObjs that it is incharge of drawing, some of those will in turn
have their own MmgObjs, and so on and so forth. We can create all kinds of structures and interactions this way.
Let's review the MmgGameScreen class variables.
- pause: A boolean toggle to pause the game screen.
- ready: A boolean toggle indicating the object is ready to draw.
- objects: An MmgContainer instance that contains all child objects.
- background: A special place holder MmgObj for storing a background object.
- foreground: A special place holder MmgObj for storing a foreground object.
- header: A speacial place holder MmgObj for storing a header object.
- footer: A speacial place holder MmgObj for storing a footer object.
- leftCursor: Left cursor image for menu screens.
- rightCursor: Right cursor image for menu screens.
- message: A special placeholder MmgObj for storing a message object.
- menuIdx: The current menu cursor position index.
- menuStart: The menu position where the active menu starts.
- menuStop: The menu position where the active menu stops.
- menuCursorLeftOffsetX: Left cursor positioning offset.
- menuCursorLeftOffsetY: Left cursor positioning offset.
- menuCursorRightOffsetX: Right cursor positioning offset.
- menuCursorRightOffsetY: Right cursor positioning offset.
- updateHandler: Special Mmg API even handler.
- menuOn: A boolean toggle that turns the menu system on or off.
The internal variables look pretty straight forward. They provide a couple of special placeholders for things that are common
to game screens and game menu screens. Next up we're going to review the functionality of the game screen class. As usual we will
skip the dry stuff like getters, setters,and constructors. You can read over them and familiarize yourself with as you see fit.
- AddObj: Adds a new object to this object's child array.
- CenterObjects: Centers default place holder objects.
- ClearObjs: Clears the objects in the child array.
- EventHandler: Event handler callback for handling MmgEvent calls.
- MmgDraw: Standard MmgObj drawing method.
- MmgUpdate: Standard MmgObj update method.
- MoveMenuSelDown: Move the menu selection index down.
- MoveMenuSelUp: Move the menu selection index up.
- ProcessAClick: Mapped to handle the current A button click.
- ProcessBClick: Mapped to handle the current B button click.
- ProcessDebugClick: Mapped to handle the current debug button click.
- ProcessDpadClick: Mapped to handle the current d-pad button click.
- ProcessDpadPress: Mapped to handle the current d-pad button press.
- ProcessDpadRelease: Mapped to handle the current d-pad button release.
- ProcessMenuItemSel: Mapped to handle selecting the current menu position.
- ProcessScreenClick: Mapped to handle the current screen click.
- ProcessScreenPress: Mapped to handle the current screen press.
- ProcessScreenRelease: Mapped to handle the current screen release.
- RemoveObj: Removes an upject from the children's array.
- SetCenteredBackground: Sets a centered background MmgObj.
- Update: Fires an update event to the update hander.
I want to cover the methods that control the child objects of our game screen first.
The game screen object contains other MmgObjs or extensions of the MmgObj super class.
To that end there are methods available for managing child objects in the MmgGameScreen class.
Remember that the MmgGameScreen class also extends the MmgObj class so it plugs right into our
MmgDraw and MmgUpdate render pipeline. The first method we'll cover is the AddObj method. It expects an MmgObj
instance to add to the internal child array. Remember classes that extend the MmgObj super class are also
MmgObj instances.
The next method we'll review is the ClearObjs method. This clears all of the objects stored in the child object array.
The RemoveObjs method allows you to remove specific objects from the child object array. This will come in handy if we want to clear
a specific child object from our array of child objects. That should cover the child object management code.
There are a few methods that interact with our special place holders. One such method is the CenterObjects method, which will
center horizontally all of the place holder objects in our class. The place holder objects are really just convenience class members
for commonly used objects on a game screen. Another method for handling a common task is the SetCenteredBackground method, which
will set the current background object and center it horzontally and vertically. The MoveMenuSelUp, MoveMenuSelDown are
used to adjust the menu cursor position when the game screen is being used as a menu screen.
There are event handlers for touch, mouse clicks, and/or keyboard input. For now we just have place holder methods but we will see
them in action a little bit down the road in our tutorial series. You'll notice that there is an EventHandler method that we'll show you
how to use with certain types of game screens. Last but not least there is an Update method that we can use for redrawing our screen if
certain criteria are met in our MmgUpdate callback.
5: Game Screen Class: Splash Screen
This brings us to an actual implementation of our MmgGameScreen class, we'll choose a simple game screen type, let's create
a splash screen. A splash screen is a simple game screen that almost every game uses, it displays an image, usually a logo, for a few seconds then
it goes away and another type of game screen takes over. THis doesn't sound too difficult, we already drew an image to the screen so we're already almost
there.
We're going to want our splash screen to go away after a few seconds so we're expecting to use the GenericEventHandler, and the
GenericEventMessage objects. The GenericEventHandler is an interface class that must be implemented by some class the handles the
target events. It defines one method that has to be implemented, the HandleGenericEvent method. This method takes one argument a
GenericEventMessage object. Let's take a look at our GenericEventMessage class. First we'll show you the class code.
package com.middlemindgames.MmgApi2Tutorial0Page1;
import com.middlemindgames.MmgApi2Tutorial0Page1.GamePanel.GameStates;
/**
* A base class used to represent a generic event message. This is the event
* message argument used by the GenericEventHandler class. Created on August 1,
* 2015, 10:57 PM by Middlemind Games Created by Middlemind Games
*
* @author Victor G. Brusca
*/
public final class GenericEventMessage {
/**
* The identifier of this generic event message.
*/
private final int id;
/**
* The information payload of this generic event message.
*/
private final Object payload;
/**
* The game state of this generic event message.
*/
private final GameStates gameState;
/**
* Constructor for the generic event message object, sets the message id,
* the message payload, and the game state the message is associated with.
*
* @param Id The id of the message.
* @param Payload The information payload of the message.
* @param GameState The game state of the message.
*/
public GenericEventMessage(int Id, Object Payload, GameStates GameState) {
id = Id;
payload = Payload;
gameState = GameState;
}
/**
* Gets the id of this message.
*
* @return The id of the message.
*/
public final int GetId() {
return id;
}
/**
* Gets the payload of the message.
*
* @return The payload of the message.
*/
public final Object GetPayload() {
return payload;
}
/**
* The game state of the message.
*
* @return The game state of the message.
*/
public final GameStates GetGameState() {
return gameState;
}
}
As per usual let's take a look at our class variables.
- id: A special identifier for this generic event message.
- payload: An object that has special infromation associated with the event.
- gameState: A special game state id to associate with this message.
The class methods are very straight forward so I'll let you review them yourself. You can see though how a custom message
object can provide information to perform certain actions when an even with a certain id is received.
Let's take a look at the first verison of our API's MmgSplashScreen class. The full source code for the class is listed below.
We'll be covering the class variables first. Remember that MmgSplashScreen is an API level class that extends the MmgGameScreen
class that extands the MmgObj class. Take a close look at what we've done. We're going from a very general class in MmgObj to
a more specific class in MmgSplashScreen building on existing code and taking advantage of existing functionality.
package net.middlemind.MmgGameApiJava.MmgBase;
/**
* A class that represents a splash screen. Created on June 1, 2005, 10:57 PM by
* Middlemind Games Created by Middlemind Games
*
* @author Victor G. Brusca
*/
public class MmgSplashScreen extends MmgGameScreen implements MmgUpdateHandler {
/**
* Inner class used to time how long to display the splash screen. Created
* on June 1, 2005, 10:57 PM by Middlemind Games Created by Middlemind Games
*
* @author Victor G. Brusca
*/
public class MmgSplashScreenTimer implements Runnable {
/**
* The display time to show the given splash screen.
*/
private final long displayTime;
/**
* The update handler to handle update event messages.
*/
private MmgUpdateHandler update;
/**
* Generic constructor sets the display time in ms.
*
* @param DisplayTime Splash screen display time in ms.
*/
public MmgSplashScreenTimer(long DisplayTime) {
displayTime = DisplayTime;
}
/**
* Sets the update handler for this runnable. Calls back to the update
* handler once the display time has passed.
*
* @param Update A class that supports the MmgUpdateHandler interface.
*/
public void SetUpdateHandler(MmgUpdateHandler Update) {
update = Update;
}
/**
* Start the display wait thread.
*/
@Override
public void run() {
try {
Thread.sleep(displayTime);
if (update != null) {
update.MmgHandleUpdate(null);
}
} catch (Exception e) {
}
}
}
/**
* The display time to show this splash screen.
*/
private int displayTime;
/**
* The update handler to handle update events.
*/
private MmgUpdateHandler update;
/**
* The default display time.
*/
public final int DEFAULT_DISPLAY_TIME_MS = 3000;
/**
* Constructor that sets the splash screen display time.
*
* @param DisplayTime The display time for this splash screen, in
* milliseconds.
*/
@SuppressWarnings("OverridableMethodCallInConstructor")
public MmgSplashScreen(int DisplayTime) {
super();
displayTime = DisplayTime;
}
/**
* Constructor that sets the splash screen attributes based on the values of
* the given argument.
*
* @param mls The display time in milliseconds.
*/
@SuppressWarnings("OverridableMethodCallInConstructor")
public MmgSplashScreen(MmgSplashScreen mls) {
super(mls);
SetBackground(mls.GetBackground());
SetFooter(mls.GetFooter());
SetHeader(mls.GetHeader());
SetHeight(mls.GetHeight());
SetIsVisible(mls.GetIsVisible());
SetLeftCursor(mls.GetLeftCursor());
SetRightCursor(mls.GetRightCursor());
SetWidth(mls.GetWidth());
displayTime = DEFAULT_DISPLAY_TIME_MS;
}
/**
* Constructor that sets the display time to the default display time.
*/
public MmgSplashScreen() {
super();
displayTime = DEFAULT_DISPLAY_TIME_MS;
}
/**
* Starts the splash screen display.
*/
public void StartDisplay() {
MmgSplashScreenTimer s = new MmgSplashScreenTimer(displayTime);
s.SetUpdateHandler(this);
Runnable r = s;
Thread t = new Thread(r);
t.start();
}
/**
* Sets the update event handler.
*
* @param Update The update event handler.
*/
public void SetUpdateHandler(MmgUpdateHandler Update) {
update = Update;
}
/**
* Handles update events.
*
* @param obj The update event to handle.
*/
@Override
public void MmgHandleUpdate(Object obj) {
if (update != null) {
update.MmgHandleUpdate(obj);
}
}
/**
* Clone this object.
*
* @return A clone of this object.
*/
@Override
public MmgObj Clone() {
MmgSplashScreen ret = new MmgSplashScreen(this);
return (MmgObj) ret;
}
/**
* Sets the background centered.
*
* @param b The object to set as a centered background.
*/
@Override
public void SetCenteredBackground(MmgObj b) {
MmgHelper.CenterHorAndVert(b);
super.SetBackground(b);
}
/**
* Gets the current display time.
*
* @return The current display time.
*/
public int GetDisplayTime() {
return displayTime;
}
/**
* Sets the current display time.
*
* @param DisplayTime The current display time.
*/
public void SetDisplayTime(int DisplayTime) {
displayTime = DisplayTime;
}
/**
* Draws this object to the screen.
*
* @param p The MmgPen to draw this object with.
*/
@Override
public void MmgDraw(MmgPen p) {
if (GetIsVisible() == true) {
super.MmgDraw(p);
} else {
//do nothing
}
}
}
As usual let's go over our class variables, remember we're inheriting the power and design of our super classes so we only
one new class variable to mention.
- DEFAULT_DISPLAY_TIME_MS: The number of milliseconds to wait before firing and event.
Let's take a look at the methods in our MmgSplashScreen class. We'll exclude inherited methods and focus on the
methods new to MmgSplashScreen.
- GetDisplayTime: Gets the display time in ms.
- SetCenteredBackground: Sets a centered background object.
- SetDisplayTime: Sets the display time in ms.
- StartDisplay: Starts the splash screen display.
The expressed functionality is very simple, you'll remember we're going from very general super classes to more and more specific
inherited classes. Generally speaking this is good API design and code reuse. Are you ready for one more class? Yes we'll be
implementing our final splash screen class in a package outside the API and local to our game engine. We don't always have to this, sometimes
the API code is just fine, our MmgImage class for instance. But game screens are inherently complex and have to be connected to an over-arching
game management system. This is the ideal scenario for utilizing inheritence to extend and customize a more general super class.
The full source code is listed below.
package com.middlemindgames.MmgApi2Tutorial0Page1;
import com.middlemindgames.MmgApi2Tutorial0Page1.GamePanel.GameStates;
import net.middlemind.MmgGameApiJava.MmgBase.MmgBmp;
import net.middlemind.MmgGameApiJava.MmgBase.MmgPen;
import net.middlemind.MmgGameApiJava.MmgBase.MmgScreenData;
import net.middlemind.MmgGameApiJava.MmgBase.MmgSplashScreen;
import net.middlemind.MmgGameApiJava.MmgBase.MmgUpdateHandler;
/**
* A game screen object, ScreenSplash, that extends the MmgGameScreen base
* class. This game screen is for displaying a splash screen before the game
* loading screen. Created on August 1, 2015, 10:57 PM by Middlemind Games.
* Created by Middlemind Games.
*
* @author Victor G. Brusca
*/
public final class ScreenSplash extends MmgSplashScreen implements MmgUpdateHandler {
/**
* Event display time complete id.
*/
public static int EVENT_DISPLAY_COMPLETE = 0;
/**
* The game state this screen has.
*/
private final GameStates state;
/**
* Event handler for firing generic events. Events would fire when the
* screen has non UI actions to broadcast.
*/
private GenericEventHandler handler;
/**
* The GamePanel that owns this game screen. Usually a JPanel instance that
* holds a reference to this game screen object.
*/
private final GamePanel owner;
/**
* Constructor, sets the game state associated with this screen, and sets
* the owner GamePanel instance.
*
* @param State The game state of this game screen.
* @param Owner The owner of this game screen.
*/
@SuppressWarnings("LeakingThisInConstructor")
public ScreenSplash(GameStates State, GamePanel Owner) {
super();
pause = false;
ready = false;
state = State;
owner = Owner;
SetUpdateHandler(this);
}
/**
* Sets a generic event handler that will receive generic events from this
* object.
*
* @param Handler A class that implements the GenericEventHandler interface.
*/
public final void SetGenericEventHandler(GenericEventHandler Handler) {
handler = Handler;
}
/**
* Public method that fires the local generic event, the listener will
* receive a display complete event.
*
* @param obj The information payload to send along with this message.
*/
@Override
public final void MmgHandleUpdate(Object obj) {
if (handler != null) {
handler.HandleGenericEvent(new GenericEventMessage(ScreenSplash.EVENT_DISPLAY_COMPLETE, null, GetGameState()));
}
}
/**
* Loads all the resources needed to display this game screen.
*/
@SuppressWarnings("UnusedAssignment")
public final void LoadResources() {
pause = true;
SetHeight(MmgScreenData.GetGameHeight());
SetWidth(MmgScreenData.GetGameWidth());
SetPosition(MmgScreenData.GetPosition());
MmgBmp tB = null;
MmgPen p;
p = new MmgPen();
p.SetCacheOn(false);
tB = TyreDatGameUtils.GetBasicBmp("../cfg/drawable/logo_large.jpg");
if (tB != null) {
SetCenteredBackground(tB);
}
ready = true;
pause = false;
}
/**
* Unloads resources needed to display this game screen.
*/
public final void UnloadResources() {
pause = true;
SetBackground(null);
ClearObjs();
ready = false;
}
/**
* Returns the game state of this game screen.
*
* @return The game state of this game screen.
*/
public final GameStates GetGameState() {
return state;
}
/**
* The main drawing routine.
*
* @param p An MmgPen object to use for drawing this game screen.
*/
@Override
public final void MmgDraw(MmgPen p) {
if (pause == false && GetIsVisible() == true) {
super.MmgDraw(p);
} else {
//do nothing
}
}
}
Let's go over our class variables first.
- EVENT_DISPLAY_COMPLETE: A value for a local event id.
- state: The GameState this screen represents.
- handler: A generic event handler for sending the display complete event.
- owner: The GamePanel instance that owns this screen.
You'll notice some of the objects in the variable list are local project classes. You'll also notice that our ScreenSplash
class extends the MmgSplashScreen class, creating a new layer of abstraction between the two classes that allows us to tie the
functionality to our game engine. The GameState enumeration is going to be used to track our game screens in future code.
The GamePanel instance that owns this class, allows us to interact at a deeper level with our game engine.
Let's review our class methods.
- UnloadResources: Clears loaded resources.
- GetGameState: Returns this screen's game state id.
- LoadResources: Loads the resources needed to draw the splash screen.
- MmgDraw: Lower level game API drawing call, used to render the screen.
- MmgHandleUpdate: Game API update event handler.
- SetGenericEventHandler: Fires an internal event on the registered event handler with event ID and the current game state.
Some of the methods are self explanatory. We'll look into the LoadResources method next.
/**
* Loads all the resources needed to display this game screen.
*/
@SuppressWarnings("UnusedAssignment")
public final void LoadResources() {
pause = true;
SetHeight(MmgScreenData.GetGameHeight());
SetWidth(MmgScreenData.GetGameWidth());
SetPosition(MmgScreenData.GetPosition());
MmgBmp tB = null;
MmgPen p;
p = new MmgPen();
p.SetCacheOn(false);
tB = TyreDatGameUtils.GetBasicBmp("../cfg/drawable/logo_large.jpg");
if (tB != null) {
SetCenteredBackground(tB);
}
ready = true;
pause = false;
}
The LoadResources method prepares our custom implementation of the MmgSplashScreen class. First the pause flag is toggled, next
we set the dimensions and position of the game screen based on the parameters in the MmgScreenData class. Next up we prep some local
variables and then we load our image as a background of our super class. Finally the ready flag is toggled.
/**
* Unloads resources needed to display this game screen.
*/
public final void UnloadResources() {
pause = true;
SetBackground(null);
ClearObjs();
ready = false;
}
In the UnloadResources method the pause flag is set to true, ready is set to false and the super class background is cleared. Next up we'll
take a look at the MmgDraw method followed by an exploration on how we can integrate our new class.
/**
* The main drawing routine.
*
* @param p An MmgPen object to use for drawing this game screen.
*/
@Override
public final void MmgDraw(MmgPen p) {
if (pause == false && GetIsVisible() == true) {
super.MmgDraw(p);
} else {
//do nothing
}
}
You'll notice that the MmgDraw method is ver simple because the super class takes care of a lot of work for us.
The method is marked with the @Override annotation because it overrides the super class method with the same name.
This allows us to customize how the method is implemented and we can still utilize the power of the super class implementation
by using a call to super as shown above. We protect access to the drawing routine by checking the state of local and inhereted
boolean variables. Essentially we do no work if the class is not ready or not visible.
Let's look at how we're going to integrate our splash screen class, the GamePanel class is going to be the integration point.
5: Game Screen Class: Game Panel Integration
Let's take a look at the game panel constructor.
/**
* Constructor, sets the MainFrame, window dimensions, and position of this
* JPanel.
*
* @param Mf The MainFrame class this panel belongs to.
* @param WinWidth The target window width.
* @param WinHeight The target window height.
* @param X The X coordinate of this JPanel.
* @param Y The Y coordinate of this JPanel.
*/
@SuppressWarnings({"LeakingThisInConstructor", "OverridableMethodCallInConstructor"})
public GamePanel(MainFrame Mf, int WinWidth, int WinHeight, int X, int Y) {
//Store main frame instance
mf = Mf;
//Set dimensions
winWidth = WinWidth;
winHeight = WinHeight;
sWinWidth = (int) (winWidth * scale);
sWinHeight = (int) (winHeight * scale);
//Set position values
myX = X;
myY = Y;
sMyX = myX + (winWidth - sWinWidth);
sMyY = myY + (winHeight - sWinHeight);
now = System.currentTimeMillis();
prev = System.currentTimeMillis();
//Prep the drawing canvas
canvas = new Canvas(MmgBmpScaler.GRAPHICS_CONFIG);
canvas.setSize(winWidth, winHeight);
MmgApiUtils.wr("GamePanel Window Width: " + winWidth);
MmgApiUtils.wr("GamePanel Window Height: " + winHeight);
MmgApiUtils.wr("GamePanel Offset X: " + myX);
MmgApiUtils.wr("GamePanel Offset Y: " + myY);
//Prep the screen data values, used in positioning helper methods
MmgScreenData screenData = new MmgScreenData(winWidth, winHeight, GamePanel.GAME_WIDTH, GamePanel.GAME_HEIGHT);
MmgApiUtils.wr(MmgScreenData.ToString());
MmgFontData fontData = new MmgFontData();
MmgApiUtils.wr(MmgFontData.ToString());
debugFont = MmgFontData.CreateDefaultFontSm();
p = new MmgPen();
MmgPen.ADV_RENDER_HINTS = true;
//Prep game states
gameScreens = new Hashtable(20);
gameScreens.put(GameStates.SPLASH, new ScreenSplash(GameStates.SPLASH, this));
gameState = GameStates.BLANK;
SwitchGameState(GameStates.SPLASH);
canvas.addMouseMotionListener(new MouseMotionListener() {
@Override
public void mouseDragged(MouseEvent e) {
lastX = e.getX();
lastY = e.getY();
}
@Override
public void mouseMoved(MouseEvent e) {
lastX = e.getX();
lastY = e.getY();
}
});
canvas.addKeyListener(new KeyListener() {
@Override
public void keyTyped(KeyEvent e) {
//MmgApiUtils.wr("KeyTyped: " + e.getKeyCode() + " KeyChar: " + e.getKeyChar() + " X: " + lastX + " Y: " + lastY);
}
@Override
public void keyPressed(KeyEvent e) {
//MmgApiUtils.wr("KeyPressed: " + e.getKeyCode() + " KeyChar: " + e.getKeyChar());
}
@Override
public void keyReleased(KeyEvent e) {
//MmgApiUtils.wr("KeyReleased: " + e.getKeyCode() + " KeyChar: " + e.getKeyChar());
}
});
canvas.addMouseListener(new MouseListener() {
@Override
public void mouseClicked(MouseEvent e) {
ProcessClick(e.getX(), e.getY());
}
@Override
public void mousePressed(MouseEvent e) {
ProcessPress(e.getX(), e.getY());
}
@Override
public void mouseReleased(MouseEvent e) {
ProcessRelease(e.getX(), e.getY());
}
@Override
public void mouseEntered(MouseEvent e) {
}
@Override
public void mouseExited(MouseEvent e) {
}
});
//MmgApi 2 Tutorial 0 Page 0
tB = TyreDatGameUtils.GetBasicBmp("../cfg/drawable/logo_large.jpg");
MmgHelper.CenterHorAndVert(tB);
}
First we store a reference to the MainFrame class and prepare our local dimension and position variables.
We prepare our local canvas dimensions, and we initialize the MmgScreenData class. This prepares our helper methods
used to position objects in the game, like centering, etc. You'll notice the game screen registration code below.
gameScreens.put(GameStates.SPLASH, new ScreenSplash(GameStates.SPLASH, this));
Now we have a way to pull our game scrren class out of the local lookup object via the GameState enumeration.
We've stores our ScreenSplash instance under the SPLASH game state. Let's take a look at how we can change our
game state and display different game screens to the user. We'll take a look at the SwitchGameState method next.
/**
* Switches the current game state, cleans up the current state, then loads
* up the next state. Currently does not use the gameScreens hash table.
* Uses direct references instead, for now.
*
* @param g The game state to switch to.
*/
public final void SwitchGameState(GameStates g) {
MmgApiUtils.wr("Switching Game State To: " + g);
if (gameState != prevGameState) {
prevGameState = gameState;
}
if (g != gameState) {
gameState = g;
} else {
return;
}
//unload
if (prevGameState == GameStates.BLANK) {
MmgApiUtils.wr("Hiding BLANK screen.");
} else if (prevGameState == GameStates.SPLASH) {
TyreDatGameUtils.wr("Hiding SPLASH screen.");
ScreenSplash ss = (ScreenSplash) currentScreen;
ss.Pause();
ss.SetIsVisible(false);
ss.UnloadResources();
}
//load
if (gameState == GameStates.BLANK) {
TyreDatGameUtils.wr("Showing BLANK screen.");
} else if (gameState == GameStates.SPLASH) {
TyreDatGameUtils.wr("Showing SPLASH screen.");
ScreenSplash ss = (ScreenSplash) this.gameScreens.get(GameStates.SPLASH);
ss.LoadResources();
ss.UnPause();
ss.SetIsVisible(true);
ss.SetGenericEventHandler(this);
ss.StartDisplay();
currentScreen = ss;
}
}
The SwitchGameState method takes care of a few details we should review. The first few lines of code help us accurately track
our game state. We store the previous game state is the new game state is in fact new, we also check to see if the state we are
switching to is in fact a new game state. If not we exit out because we don't want to re-instantiate the current game state,
we should assume the request is an error.
The remainder of the method is separated into two main blocks of code, the unload section and the load section.
Looking at the unload code first we see that we need to take into account the preGameState value. The code in the unload block
is meant to free up resources and clean up the current game state in preparation for a switch to a new game state.
The cleanup code is designed to safely remove the current game screen from the drawing loop. This is very important, we don't
know when the next update/draw call will fire and if we don't remove our game screen from the main drawing loop we could get
exceptions, which we don't want.
To this end the first two calls in our game state cleanup code should prevent any drawing errors because the game screen
is paused and is set to be invisible which will remove it from the drawing loop. Finally we call UnloadResources to free up an images
or other resources before starting up the next game screen. Notice that we use the current screen and cast it to its object so that we
can use the extended methods of the class.
This brings us to our load code block. It is very similar to the unload code block except we're using our game state value as
opposed to the previous game state value. We take similar steps here except we load our resources first, unpause, then toggle our
visibility, and finally start any timing or triggered events. Now we can see how our class integrates with out game engine. We can also see how
powerful inheritence and abstraction layers are when integrating code from other APIs oe libraries.
Next up we're going to take a look at the RenderGame method of the GamePanel class of our project. You'll notice that there is
an escape clause in the drawing method that does nothing is the current game screen is null, paused, or not ready. The local graphics
context comes from the following line.
g = backgroundGraphics;
This means that our game is being drawn to a local buffer. If the current game screen is not able to be drawn nothing is done to our local buffer.
The line of code bg = GetBuffer() is also an important line. This is a reference to our game engine's drawing buffer, the actual buffer of the game window
from the underlying java API. Near the end of the render method the background image buffer we have been drawing is drawn to the screen in one step.
Take a minute to thinl about this process. What are the advantages of doing it this way?
Did you figure it out? We do al of our game rendering to a local image buffer then draw that image on the screen. If our game is changing game screens
and there are a few frames where the current screen is not yet ready to render itself our game would flicker during game screen changes. THis would look bad and
give our game a unprofessional feel. But our rendering method is setup to always draw what was in the image buffer. So our code wouldn't flicker it would just
continue to draw draw the last good frame until the current game screen finished loading and is ready to be drawn.
There's one more thing we want to cover and then we'll be ready to run our project and see the results. The next method we're going to look at is the
HandleGeneric Event method of the GamePanel class. This is the event handler registered in ScreenSplash's constructor. Let's take a look.
/**
* A generic event, GenericEventHandler, callback method. Used to handle
* generic events from certain game screens, MmgGameScreen.
*
* @param obj
*/
@Override
public final void HandleGenericEvent(GenericEventMessage obj) {
if (obj != null) {
MmgApiUtils.wr("HandleGenericEvent " + obj.GetGameState());
if (obj.GetGameState() == GameStates.SPLASH) {
if (obj.GetId() == ScreenSplash.EVENT_DISPLAY_COMPLETE) {
SwitchGameState(GameStates.BLANK);
}
}
}
}
The internal time of the MmgSplashScreen class fires a generic event to it's internal event handler.
When handled in an overridden method of our ScreenSplash class, which has access to our GamePanel
class and can trigger the GamePanel class to change game states. You'll have to keep an eye on the output to catch
the event result, we don't have another game screen to change to just yet. Well that wraps up this tutorial, hope you enjoyed it.
Hello world!
Found Key: LOGGING Value: true Type: bool From: MmgApiUtils
Found Key: FPS Value: 16 Type: long From: Tutorial0Page0App
Found Key: WIN_WIDTH Value: 860 Type: int From: Tutorial0Page0App
Found Key: WIN_HEIGHT Value: 602 Type: int From: Tutorial0Page0App
Engine config load result: true
Importing MmgApiUtils field: LOGGING with value: true with type: bool from: MmgApiUtils
Window Width: 858
Window Height: 600
Panel Width: 854
Panel Height: 596
MainFrame: Found Screen Dimen: 858x600
MainFrame: Found Position: 2x2
GamePanel Window Width: 854
GamePanel Window Height: 596
GamePanel Offset X: 2
GamePanel Offset Y: 2
ScaleX: true ScaleY: true
Found X Scale: 1.0, ResF: 32.0, ResI: 32.0, Diff: 0.0, Count: 0
Screen Width: 854
Screen Height: 596
Game Width: 854
Game Height: 416
Game Offset X: 0
Game Offset Y: 90
Scale X: 1.0
Scale Y: 1.0
Font Size: 22
Target Pixel Height (Unscaled): 22
Target Pixel Height (Scaled): 22
Switching Game State To: SPLASH
Hiding BLANK screen.
Showing SPLASH screen.
Target Frame Rate: 16
Target Frame Time: 62
HandleGenericEvent SPLASH
Switching Game State To: BLANK
Hiding SPLASH screen.
Showing BLANK screen.
You can see at the end of the output the attempt to change to the blank game state, which disconnects
any game screen from the drawing loop, the result is that the game engine will draw the last good game frame.