A Working Heaps & HaxeUI Example

I was banging my head against the wall trying to get Domkit working with Heaps. I spent around 8 hours trying to get a data store working with components.

I decided to try HaxeUI, and it only took me about an hour to get it up and running.

Here is the demo code for anybody that is looking to get started.

Spacebar shows and hides the HUD component.
H updates the HP label.
I adds a fish to your inventory.

example

compile.hxml:

-cp src
-lib heaps
-lib domkit
-lib haxeui-core
-lib haxeui-heaps
-js game.js
-main Main

src/Main.hx:

import haxe.ui.core.ItemRenderer;
import haxe.ui.core.Screen;
import haxe.ui.*;
import haxe.ui.containers.*;
import haxe.ui.components.*;
import haxe.ui.data.*;

@:xml('
<box height="100%" width="100%">
	<style>
		.custom {
			color: #FFFFFF;
			border: 1px solid #FFFFFF;
			padding: 10px;
			font-size: 24px;
		}
	</style>
	<vbox>
		<hbox>
			<label id="textfield" styleName="custom" text="0" />
			<button id="deinc" styleName="red" text="-" />
			<button id="inc" text="+" />
		</hbox>
		<listview id="inventory" width="100%">
			<item-renderer id="inventoryList" layoutName="vertical" width="100%" style="border: 1px solid #ff0000;">
				<label id="itemName" style="font-size: 24px;" text="0" width="100%" />
			</item-renderer>
		</listview>
	</vbox>
</box>
')
class HUDComponent extends Box {
	public function new() {
		super();

		// anything with an id becomes a correctly typed member variable
		textfield.text = "HP: " + Main.hp;

		deinc.onClick = function(e) {
			Main.hp = Std.string(Std.parseInt(Main.hp) - 1);
			textfield.text = "HP: " + Main.hp;
		}
		inc.onClick = function(e) {
			Main.hp = Std.string(Std.parseInt(Main.hp) + 1);
			textfield.text = "HP: " + Main.hp;
		}

		// Init Inventory
		for (item in Main.inventory) {
			inventory.dataSource.add({ itemName: item });
		}

		// Removes At Index
		inventory.onClick = function(e) {
			inventory.dataSource.removeAt(inventory.selectedIndex);
			Main.inventory.splice(inventory.selectedIndex, 1);
		}
	}
}

class Main extends hxd.App {
	// State
	public static var hp:String = '100';
	public static var inventory:Array<String> = ['Stick'];

	// UI
	public static var myComp:HUDComponent;
	public static var showHud:Bool = false;

	override function init() {
		// Initialize HaxeUI
		Toolkit.init({root: s2d});

		// Add HUD
		myComp = new HUDComponent();
		Screen.instance.addComponent(myComp);
		showHud = true;
	}

	override function update(dt:Float) {
		// Show/Hide Hud
		if (hxd.Key.isPressed(hxd.Key.SPACE)) {
			if (showHud) {
				Screen.instance.removeComponent(myComp);
				showHud = false;
			} else {
				myComp = new HUDComponent();
				Screen.instance.addComponent(myComp);
				showHud = true;
			}
		}

		// Change Inventory
		if (hxd.Key.isPressed(hxd.Key.I)) {
			var list = myComp.findComponent("inventory", ListView);
			inventory.push("Fish" + Std.random(100));
			list.dataSource.clear();
			for (item in inventory) {
				list.dataSource.add({ itemName: item });
			}
		}

		// Change HP
		if (hxd.Key.isPressed(hxd.Key.H)) {
			// Increase by 1
			Main.hp = Std.string(Std.parseInt(Main.hp) + 1);
			myComp.findComponent("textfield", Label).text = "HP: " + Main.hp;
		}
	}

	static function main() {
		#if hl
		hxd.Res.initLocal();
		#else
		hxd.Res.initEmbed();
		#end
		new Main();
	}
}

I hope this helps someone, and saves them time!

Edit: Thanks to Ian for the assist.

1 Like

great! Glad it went somewhat smoothly :slight_smile:

fyi, there are some other features you can use that will make your code a little more compact / typesafe:

// can build the component directly, dont need the "ui"
@:xml('
<box height="100%" width="100%">
	<style>
		.custom {
			color: #FFFFFF;
			border: 1px solid #FFFFFF;
			padding: 10px;
			font-size: 24px;
		}
	</style>
	<vbox>
		<hbox>
			<label id="textfield" styleName="custom" text="0" />
			<button id="deinc" styleName="red" text="-" />
			<button id="inc" text="+" />
		</hbox>
		<listview id="inventory" width="100%">
			<item-renderer id="inventoryList" layoutName="vertical" width="100%" style="border: 1px solid #ff0000;">
				<label id="itemName" style="font-size: 24px;" text="0" width="100%" />
			</item-renderer>
		</listview>
	</vbox>
</box>
')
class HUDComponent extends Box {
	public function new() {
		super();

		// anything with an id becomes a correctly typed member variable
		textfield.text = "HP: " + Main.hp;

		deinc.onClick = function(e) {
			Main.hp = Std.string(Std.parseInt(Main.hp) - 1);
			textfield.text = "HP: " + Main.hp;
		}
		inc.onClick = function(e) {
			Main.hp = Std.string(Std.parseInt(Main.hp) + 1);
			textfield.text = "HP: " + Main.hp;
		}

		// Init Inventory
		for (item in Main.inventory) {
			list.dataSource.add({ itemName: item });
		}

		// Removes At Index
		list.onClick = function(e) {
			list.dataSource.removeAt(list.selectedIndex);
			Main.inventory.splice(list.selectedIndex, 1);
		}
	}
}

Hope that helps!

Cheers,
Ian

1 Like

Thank you, Ian! This much cleaner!
I am going to update the examples with your changes.
It went a lot smoother than Domkit, and now that I have it working, it’s very easy to work with.

I am going to try to play with animations shortly for a dialogue system, and will post it for others to use.