Data-driven and components

posted in Event-driven engine for project Hangman
Published August 02, 2021
Advertisement

After too many changes, I have taken the decision that the engine will manage its own data types. So they will be part of the engine and the infrastructure layer will need to know them and use them.

Also, I have started with the data-driven approach removing all the data from code (still there are a lot…)

I have created plain text files with the entities definitions, basically they are a list of components and their properties. Using java reflection, the objects are created and linked to the entities.
This shows the entity that displays the text in the game

{
	class:class:entity.Entity,
	
	list:componentList: {
		class:class:components.Transformation,
		Float:xTopLeft:0.0,
		Float:yTopLeft:0.0,
		Float:xWidth:0.5,
		Float:yHeight:1.0,
	},
		
	list:componentList: {
		class:class:components.Text,
		boolean:wordWrap:true,
		int:splitLineCode:10,
	},	
	
}

The components are POJO (Plain Old Java Object) classes with getters, setters.

package components;

public class Transformation {

	// 2D
	private float xTopLeft;
	private float yTopLeft;
	private float xWidth;
	private float yHeight;
	
	public Transformation() {
		// reflection
	}

	public float getxTopLeft() {
		return xTopLeft;
	}

	public void setxTopLeft(float xTopLeft) {
		this.xTopLeft = xTopLeft;
	}

	public float getyTopLeft() {
		return yTopLeft;
	}

	public void setyTopLeft(float yTopLeft) {
		this.yTopLeft = yTopLeft;
	}

	public float getxWidth() {
		return xWidth;
	}

	public void setxWidth(float xWidth) {
		this.xWidth = xWidth;
	}

	public float getyHeight() {
		return yHeight;
	}

	public void setyHeight(float yHeight) {
		this.yHeight = yHeight;
	}
	
}

Very simple when the properties a built-in types (int, float, String, boolean, …) but it is more complicated when it is a custom type because the object builder needs to manage it.

{
	class:class:entity.Entity,
	
	list:componentList: {
		class:class:components.Transformation,
		Float:xTopLeft:0.5,
		Float:yTopLeft:0.0,
		Float:xWidth:0.5,
		Float:yHeight:0.5,
	},
		
	list:componentList: {
		class:class:components.ImageAtlas,
		int:tilesPerRow:4,
		int:tilesPerCol:4,
		int:index:1,
		Image:image:hangman_atlas.png,
	},	
	
}

And the first thing it needs is access to the permanent storage, I use resources at the moment but I have prepared it to accept Files, Network or others in the future.
That's why the object builder receives an object as parameter that will manage the I/O. The object builder access to the methods provided by an interface and the current ResourceStorage and the future *Storage implements it.
At the moment, I only need to access to plain text files and images of our project custom type “Image”

package permanentStorage;

import components.Image;

public interface IPermanentStorage {

	Image getImage(String imageFileName);

	String getPlainTextFile(String trim);

}


Also, to avoid that low level classes in the infrastructure layer have knowledge of our components, I have created a gateway that extract the components properties needed by the low level classes and call the low level classes.
Main class → gateway → low level class

For example, the main class uses this interface to draw all the entities

package gateways.screen;

import entity.Entity;

public interface IScreenOutput {
	
	public void clear();

	public void draw(Entity entity);

}

The gateway, extract the components needed and call the low level classes methods.

Low level classes do not known anything about the components, entities or complex objects like the ImageAtlas, They just draw text or pictures…

public void printLineCharacters(int col, int row, String str);
public void printImage(Object image, float pctXmin, float pctXmax, float pctYmin, float pctYmax);

Using the same data-driven architecture, I have extracted the Logic data out of the code in two classes (components?).
For this simple game, just the list of words and the attempts you have.
But this way, we let that the game designers can change the game behavior without modifying the code!!!
Of course I know that for a simple game it makes no sense, remember that it is the same mini-game that we played with the monolithic approach. But it will make the difference when things a getting complex.
This is the hard part of the game-engines, too much work and no external changes in the user experience… yet…

{
	class:class:entity.Entity,
	
	list:componentList: {
		class:class:hungman.Database,
		StringArray:words:lemon;strawberry;banana;apple;orange;watermelon;kiwi;pear;coconut;pineapple;apricot;clementine;cherry;figs;mango;pe[...],
	},
		
	list:componentList: {
		class:class:hungman.LogicHungman,
		int:attempts:7,			
	},	
}

Finally, let me share a video of the mini-game

Previous Entry Release 0.1.0
0 likes 1 comments

Comments

pari__1308

Hey,

Thanks for sharing this blog its very helpful to implement in our work

Regards

<a href="https://hirecryptohacker.com/bitcoin-account-recovery">Bitcoin Account Recovery</a>

August 04, 2021 11:27 AM
You must log in to join the conversation.
Don't have a GameDev.net account? Sign up!
Profile
Author
Advertisement
Advertisement