Browse Source

Start data binding example with invaders

Michael Ragazzon 5 years ago
parent
commit
70f3bcc95f
2 changed files with 133 additions and 36 deletions
  1. 20 2
      Samples/basic/databinding/data/databinding.rml
  2. 113 34
      Samples/basic/databinding/src/main.cpp

+ 20 - 2
Samples/basic/databinding/data/databinding.rml

@@ -180,7 +180,7 @@ form h2
 <panel id="welcome" data-model="my_model">
 	<p class="title" style="margin-top: 1.8em;">{{hello_world}}<span style="color: blue;"> Rated: {{rating}}</span></p>
 	<p>Data binding demo. We rate this a good old {{rating}}!</p>
-	<input type="range" name="rating" min="0" max="100" step="1" value="50" data-value="rating" data-attribute="rating"/>
+	<input type="range" name="rating" min="0" max="100" step="1" value="50" data-value="rating"/>
 	<div data-if="rating > 50">Thanks for the <span data-if="rating < 80">good</span><span data-if="rating >= 80">awesome</span> rating!</div>
 	<div class="mouse_detector" style="height: 70px;"
 		data-event-mousemove="mouse_detector = 'x: ' + ev.mouse_x + '<br/>y: ' + ev.mouse_y"
@@ -198,12 +198,30 @@ form h2
 	</p>
 	<div data-for="invader : invaders">
 		<h1 data-class-red="rating < 30" data-class-big="rating == 0">{{invader.name}}</h1>
+		<p>Invader {{'it_index '+ 1}} of {{ invaders.size }}.</p>
 		<img data-attr-sprite="invader.sprite" data-style-image-color="invader.color"/>
 		<p>
-			Numbers: <span data-for="invader.numbers"> {{it}} </span>
+			Damage: <span data-for="invader.damage"> {{it}} </span>
 		</p>
 	</div> 
 </panel>
+<tab>Invaders</tab>
+<panel id="invaders" data-model="invaders">
+	<p>Incoming invaders:
+		<input type="range" name="rating" min="0" max="20" step="5" data-value="incoming_invaders_rate"/>
+		{{ incoming_invaders_rate }} / min.
+	</p>
+	<button data-event-click="launch_weapons">Launch weapons!</button>
+	<div data-for="invader : invaders">
+		<h1 data-class-red="invader.danger_rating > 70">{{invader.name}}</h1>
+		<p>Invader {{'it_index' + 1}} of {{ invaders.size }}.</p>
+		<img data-attr-sprite="invader.sprite" data-style-image-color="invader.color"/>
+		<p>
+			Damage per shot: <span data-for="invader.damage"> {{it}} </span>
+		</p>
+	</div>
+	<h1 data-if="invaders.size == 0">It's all safe and sound, sir!</h1>
+</panel>
 <tab>Decorators</tab>
 <panel id="decorators">
 	<h1>Gradient decorator</h1>

+ 113 - 34
Samples/basic/databinding/src/main.cpp

@@ -108,7 +108,8 @@ struct Invader {
 	Rml::Core::String name;
 	Rml::Core::String sprite;
 	Rml::Core::Colourb color{ 255, 255, 255 };
-	std::vector<int> numbers = { 1, 2, 3, 4, 5 };
+	std::vector<int> damage;
+	float danger_rating = 50;
 
 	void GetColor(Rml::Core::Variant& variant) {
 		variant = "rgba(" + Rml::Core::ToString(color) + ')';
@@ -153,60 +154,100 @@ void HasGoodRating(Rml::Core::Variant& variant) {
 	variant = int(my_data.rating > 50);
 }
 
+struct InvaderModelData {
+	double time_last_invader_spawn = 0;
+	double time_last_invader_shot = 0;
 
-Rml::Core::DataModelHandle my_model;
+	float incoming_invaders_rate = 10; // Per minute
+
+	std::vector<Invader> invaders = {
+		Invader{"Angry invader", "icon-invader", {255, 40, 30}, {3, 6, 7}, 80}
+	};
+
+	void LaunchWeapons(Rml::Core::DataModelHandle model_handle, Rml::Core::Event& /*ev*/, const Rml::Core::VariantList& /*arguments*/)
+	{
+		invaders.clear();
+		model_handle.DirtyVariable("invaders");
+	}
+
+} invaders_data;
+
+
+Rml::Core::DataModelHandle invaders_model, my_model;
 
 
 bool SetupDataBinding(Rml::Core::Context* context)
 {
-	Rml::Core::DataModelConstructor constructor = context->CreateDataModel("my_model");
-	if (!constructor)
-		return false;
 
-	constructor.Bind("hello_world", &my_data.hello_world);
-	constructor.Bind("mouse_detector", &my_data.mouse_detector);
-	constructor.Bind("rating", &my_data.rating);
-	constructor.BindFunc("good_rating", &HasGoodRating);
-	constructor.BindFunc("great_rating", [](Rml::Core::Variant& variant) {
-		variant = int(my_data.rating > 80);
-	});
+	// The invaders model
+	{
+		Rml::Core::DataModelConstructor constructor = context->CreateDataModel("invaders");
+		if (!constructor)
+			return false;
 
-	constructor.RegisterArray<std::vector<int>>();
+		constructor.Bind("incoming_invaders_rate", &invaders_data.incoming_invaders_rate);
 
-	if(auto invader_handle = constructor.RegisterStruct<Invader>())
-	{
-		invader_handle.AddMember("name", &Invader::name);
-		invader_handle.AddMember("sprite", &Invader::sprite);
-		invader_handle.AddMember("numbers", &Invader::numbers);
-		invader_handle.AddMemberFunc("color", &Invader::GetColor);
-	}
+		constructor.RegisterArray<std::vector<int>>();
 
-	constructor.Bind("delightful_invader", &my_data.delightful_invader);
+		if (auto invader_handle = constructor.RegisterStruct<Invader>())
+		{
+			invader_handle.AddMember("name", &Invader::name);
+			invader_handle.AddMember("sprite", &Invader::sprite);
+			invader_handle.AddMember("damage", &Invader::damage);
+			invader_handle.AddMember("danger_rating", &Invader::danger_rating);
+			invader_handle.AddMemberFunc("color", &Invader::GetColor);
+		}
 
-	constructor.RegisterArray<std::vector<Invader>>();
+		constructor.RegisterArray<std::vector<Invader>>();
+		constructor.Bind("invaders", &invaders_data.invaders);
 
-	constructor.Bind("indices", &my_data.indices);
-	constructor.Bind("invaders", &my_data.invaders);
+		constructor.BindEventCallback("launch_weapons", &InvaderModelData::LaunchWeapons, &invaders_data);
 
-	if (auto vec2_handle = constructor.RegisterStruct<Rml::Core::Vector2f>())
-	{
-		vec2_handle.AddMember("x", &Rml::Core::Vector2f::x);
-		vec2_handle.AddMember("y", &Rml::Core::Vector2f::y);
+		invaders_model = constructor.GetModelHandle();
 	}
 
-	constructor.RegisterArray<std::vector<Rml::Core::Vector2f>>();
-	constructor.Bind("positions", &my_data.positions);
 
-	constructor.BindEventCallback("clear_positions", &ClearPositions);
-	constructor.BindEventCallback("add_mouse_pos", &MyData::AddMousePos, &my_data);
+	// The main model
+	{
+		Rml::Core::DataModelConstructor constructor = context->CreateDataModel("my_model");
+		if (!constructor)
+			return false;
+
+		constructor.Bind("hello_world", &my_data.hello_world);
+		constructor.Bind("mouse_detector", &my_data.mouse_detector);
+		constructor.Bind("rating", &my_data.rating);
+		constructor.BindFunc("good_rating", &HasGoodRating);
+		constructor.BindFunc("great_rating", [](Rml::Core::Variant& variant) {
+			variant = int(my_data.rating > 80);
+			});
+
+		constructor.Bind("delightful_invader", &my_data.delightful_invader);
+
+		//constructor.RegisterArray<std::vector<Invader>>();
+
+		constructor.Bind("indices", &my_data.indices);
+		constructor.Bind("invaders", &my_data.invaders);
+
+		if (auto vec2_handle = constructor.RegisterStruct<Rml::Core::Vector2f>())
+		{
+			vec2_handle.AddMember("x", &Rml::Core::Vector2f::x);
+			vec2_handle.AddMember("y", &Rml::Core::Vector2f::y);
+		}
+
+		constructor.RegisterArray<std::vector<Rml::Core::Vector2f>>();
+		constructor.Bind("positions", &my_data.positions);
+
+		constructor.BindEventCallback("clear_positions", &ClearPositions);
+		constructor.BindEventCallback("add_mouse_pos", &MyData::AddMousePos, &my_data);
+
+		my_model = constructor.GetModelHandle();
+	}
 
-	my_model = constructor.GetModelHandle();
 
 	return true;
 }
 
 
-
 Rml::Core::Context* context = nullptr;
 ShellRenderInterfaceExtensions *shell_renderer;
 std::unique_ptr<DemoWindow> demo_window;
@@ -227,8 +268,46 @@ void GameLoop()
 		}
 	}
 
+	const double t = Rml::Core::GetSystemInterface()->GetElapsedTime();
+
+	const double t_next_spawn = invaders_data.time_last_invader_spawn + 60.0 / double(invaders_data.incoming_invaders_rate);
+	if (t >= t_next_spawn)
+	{
+		using namespace Rml::Core;
+		const int num_items = 4;
+		static std::array<String, num_items> names = { "Angry invader", "Harmless invader", "Deceitful invader", "Cute invader" };
+		static std::array<String, num_items> sprites = { "icon-invader", "icon-flag", "icon-game", "icon-waves" };
+		static std::array<Colourb, num_items> colors = {{ { 255, 40, 30 }, {20, 40, 255}, {255, 255, 30}, {230, 230, 230} }};
+
+		Invader new_invader;
+		new_invader.name = names[rand() % num_items];
+		new_invader.sprite = sprites[rand() % num_items];
+		new_invader.color = colors[rand() % num_items];
+		new_invader.danger_rating = float((rand() % 100) + 1);
+		invaders_data.invaders.push_back(new_invader);
+
+		invaders_model.DirtyVariable("invaders");
+		invaders_data.time_last_invader_spawn = t;
+	}
+
+	if (t >= invaders_data.time_last_invader_shot + 1.0)
+	{
+		if (!invaders_data.invaders.empty())
+		{
+			const size_t index = size_t(rand() % int(invaders_data.invaders.size()));
+
+			Invader& invader = invaders_data.invaders[index];
+			invader.damage.push_back(rand() % int(invader.danger_rating));
+
+			invaders_model.DirtyVariable("invaders");
+		}
+		invaders_data.time_last_invader_shot = t;
+	}
+
 	my_model.Update();
 
+	invaders_model.Update();
+
 	demo_window->Update();
 	context->Update();