shuffle analytics and ad loading around after the gdpr message

This commit is contained in:
Ellpeck 2020-06-14 01:18:12 +02:00
parent c1438464cd
commit 6408be7646
11 changed files with 136 additions and 104 deletions

View file

@ -31,9 +31,13 @@ namespace Android {
protected override void OnCreate(Bundle bundle) {
base.OnCreate(bundle);
// ad layout
var adLayout = new LinearLayout(this) {Orientation = Orientation.Vertical};
adLayout.SetGravity(GravityFlags.Bottom);
// set up the game
TextInputWrapper.Current = new TextInputWrapper.Mobile();
this.game = new GameImpl(new AndroidAnalytics(this));
this.game = new GameImpl(new AndroidPlatform(this, adLayout));
this.game.GraphicsDeviceManager.ResetWidthAndHeight(this.game.Window);
this.game.GraphicsDeviceManager.IsFullScreen = true;
this.game.OnLoadContent += game => {
@ -53,18 +57,6 @@ namespace Android {
if (Build.VERSION.SdkInt >= BuildVersionCodes.P)
this.Window.Attributes.LayoutInDisplayCutoutMode = LayoutInDisplayCutoutMode.ShortEdges;
// ad layout
var adLayout = new LinearLayout(this) {Orientation = Orientation.Vertical};
adLayout.SetGravity(GravityFlags.Bottom);
var ad = new AdView(this) {
AdUnitId = "ca-app-pub-5754829579653773/7841535920",
AdSize = AdSize.SmartBanner
};
ad.LoadAd(new AdRequest.Builder()
.AddTestDevice("14B965C6457E17D2808061ADF7E34923")
.Build());
adLayout.AddView(ad);
// total layout that is displayed
this.mainView = new LinearLayout(this) {Orientation = Orientation.Vertical};
this.mainView.LayoutParameters = new LinearLayout.LayoutParams(MatchParent, MatchParent);

View file

@ -54,7 +54,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="Activity1.cs" />
<Compile Include="AndroidAnalytics.cs" />
<Compile Include="AndroidPlatform.cs" />
<Compile Include="Resources\Resource.Designer.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>

View file

@ -1,26 +0,0 @@
using System.Collections;
using System.Collections.Generic;
using Android.App;
using GameAnalyticsSDK;
using GameAnalyticsSDK.Utilities;
using TouchyTickets;
namespace Android {
public class AndroidAnalytics : Analytics {
private readonly Activity activity;
public AndroidAnalytics(Activity activity) {
this.activity = activity;
}
public override void Setup(Dictionary<string, object> json) {
GameAnalytics.Initialize(this.activity, GA_MiniJSON.JsonEncode(new Hashtable(json)));
}
public override void AddResourceEvent(bool sink, string currency, float amount, string itemType, string itemId) {
GameAnalytics.NewResourceEvent(sink ? GAResourceFlowType.Sink : GAResourceFlowType.Source, currency, amount, itemType, itemId);
}
}
}

View file

@ -0,0 +1,41 @@
using System.Collections;
using System.Collections.Generic;
using Android.App;
using Android.Gms.Ads;
using Android.Widget;
using GameAnalyticsSDK;
using GameAnalyticsSDK.Utilities;
using TouchyTickets;
namespace Android {
public class AndroidPlatform : Platform {
private readonly Activity activity;
private readonly LinearLayout adLayout;
public AndroidPlatform(Activity activity, LinearLayout adLayout) {
this.activity = activity;
this.adLayout = adLayout;
}
public override void SetupAds() {
var ad = new AdView(this.activity) {
AdUnitId = "ca-app-pub-5754829579653773/7841535920",
AdSize = AdSize.SmartBanner
};
ad.LoadAd(new AdRequest.Builder()
.AddTestDevice("14B965C6457E17D2808061ADF7E34923")
.Build());
this.adLayout.AddView(ad);
}
public override void SetupAnalytics(Dictionary<string, object> json) {
GameAnalytics.Initialize(this.activity, GA_MiniJSON.JsonEncode(new Hashtable(json)));
}
public override void AddResourceEvent(bool sink, string currency, float amount, string itemType, string itemId) {
GameAnalytics.NewResourceEvent(sink ? GAResourceFlowType.Sink : GAResourceFlowType.Source, currency, amount, itemType, itemId);
}
}
}

View file

@ -12,23 +12,32 @@ namespace TouchyTickets {
public static GameImpl Instance { get; private set; }
public readonly ISet<Upgrade> AppliedUpgrades = new HashSet<Upgrade>();
public readonly Tutorial Tutorial = new Tutorial();
public bool ReadAnalyticsInfo;
public readonly Analytics Analytics;
public readonly Platform Platform;
public BigInteger Tickets;
public int TimesRestarted;
public int Stars;
public ParkMap Map;
public Tutorial Tutorial { get; private set; }
public Camera Camera { get; private set; }
public Ui Ui { get; private set; }
public bool DrawMap;
public DateTime LastUpdate;
private double saveCounter;
public GameImpl(Analytics analytics) {
this.Analytics = analytics;
public GameImpl(Platform platform) {
this.Platform = platform;
Instance = this;
}
protected override void LoadContent() {
base.LoadContent();
// start the load sequence
Ui.SetupUiSystem(this.UiSystem);
CoroutineHandler.Start(Ui.DisplaySplash(this.LoadGame));
}
private void LoadGame() {
// set up analytics
var settings = new Dictionary<string, object>();
settings["InfoLog"] = true;
@ -39,15 +48,15 @@ namespace TouchyTickets {
// ios comes first, then android. For now they're the same
settings["GameKey"] = new[] {"cc18de06eebbc5d5e987c384fcd28000", "cc18de06eebbc5d5e987c384fcd28000"};
settings["SecretKey"] = new[] {"82ca1a930ee38e2383ffb02db7631e16033b511d", "82ca1a930ee38e2383ffb02db7631e16033b511d"};
this.Analytics.Setup(settings);
}
this.Platform.SetupAnalytics(settings);
this.Platform.SetupAds();
protected override void LoadContent() {
base.LoadContent();
this.Tutorial = new Tutorial();
if (!SaveHandler.Load(this))
this.Map = new ParkMap(20, 20);
// load other stuff
this.Ui = new Ui(this.UiSystem);
this.Camera = new Camera(this.GraphicsDevice) {
Scale = 4,
@ -56,32 +65,32 @@ namespace TouchyTickets {
MaxScale = 24,
MinScale = 2
};
CoroutineHandler.Start(this.Ui.DisplaySplash());
}
protected override void DoUpdate(GameTime gameTime) {
base.DoUpdate(gameTime);
var now = DateTime.Now;
if (this.LastUpdate != default) {
var passed = now - this.LastUpdate;
// if more than 1 second passed, the app is minimized or a save was loaded, so we penalize
if (passed.TotalSeconds >= 1)
passed = new TimeSpan(passed.Ticks / 2);
this.Map.Update(gameTime, passed);
}
this.LastUpdate = now;
if (this.Map != null) {
var now = DateTime.Now;
if (this.LastUpdate != default) {
var passed = now - this.LastUpdate;
// if more than 1 second passed, the app is minimized or a save was loaded, so we penalize
if (passed.TotalSeconds >= 1)
passed = new TimeSpan(passed.Ticks / 2);
this.Map.Update(gameTime, passed);
}
this.LastUpdate = now;
this.Ui.Update(gameTime);
this.Tutorial.Update(this);
// save every 3 seconds
this.saveCounter += gameTime.ElapsedGameTime.TotalSeconds;
if (this.saveCounter >= 3) {
this.saveCounter = 0;
SaveHandler.Save(this);
// save every 3 seconds
this.saveCounter += gameTime.ElapsedGameTime.TotalSeconds;
if (this.saveCounter >= 3) {
this.saveCounter = 0;
SaveHandler.Save(this);
}
}
this.Ui?.Update(gameTime);
this.Tutorial?.Update(this);
}
protected override void DoDraw(GameTime gameTime) {

View file

@ -1,9 +1,11 @@
using System.Collections.Generic;
namespace TouchyTickets {
public abstract class Analytics {
public abstract class Platform {
public abstract void Setup(Dictionary<string, object> json);
public abstract void SetupAds();
public abstract void SetupAnalytics(Dictionary<string, object> json);
public abstract void AddResourceEvent(bool sink, string currency, float amount, string itemType, string itemId);

View file

@ -25,8 +25,7 @@ namespace TouchyTickets {
Stars = game.Stars,
TimesRestarted = game.TimesRestarted,
Upgrades = game.AppliedUpgrades.Select(u => u.Name).ToList(),
TutorialStep = game.Tutorial.CurrentStep,
ReadAnalyticsInfo = game.ReadAnalyticsInfo
TutorialStep = game.Tutorial.CurrentStep
};
Serializer.Serialize(stream, data);
}
@ -49,7 +48,6 @@ namespace TouchyTickets {
foreach (var name in data.Upgrades)
game.AppliedUpgrades.Add(Upgrade.Upgrades[name]);
game.Tutorial.CurrentStep = data.TutorialStep;
game.ReadAnalyticsInfo = data.ReadAnalyticsInfo;
// version 1 had smaller maps
if (data.SaveVersion <= 1) {

View file

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Numerics;
using Coroutine;
@ -28,19 +29,7 @@ namespace TouchyTickets {
private bool finishingSwipe;
public Ui(UiSystem uiSystem) {
InputHandler.EnableGestures(GestureType.HorizontalDrag, GestureType.FreeDrag, GestureType.Pinch, GestureType.Tap);
this.uiSystem = uiSystem;
this.uiSystem.GlobalScale = 4;
this.uiSystem.AutoScaleWithScreen = true;
this.uiSystem.AutoScaleReferenceSize = new Point(720, 1280);
this.uiSystem.Style.Font = new GenericSpriteFont(MlemGame.LoadContent<SpriteFont>("Fonts/Regular"));
this.uiSystem.Style.PanelTexture = this.uiSystem.Style.ScrollBarBackground = new NinePatch(Texture[2, 1], 4);
this.uiSystem.Style.ButtonTexture = this.uiSystem.Style.ScrollBarScrollerTexture = new NinePatch(Texture[3, 1], 4);
this.uiSystem.Style.TextScale = 0.1F;
this.uiSystem.TextFormatter.AddImage("ticket", Texture[2, 0]);
this.uiSystem.TextFormatter.AddImage("star", Texture[3, 0]);
foreach (var modifier in AttractionModifier.Modifiers.Values)
this.uiSystem.TextFormatter.AddImage(modifier.Name, modifier.Texture);
// main ticket store ui
var rainingTickets = new List<RainingTicket>();
@ -174,7 +163,7 @@ namespace TouchyTickets {
yesNoUi.AddChild(new Button(Anchor.AutoInlineIgnoreOverflow, new Vector2(0.5F, 30), Localization.Get("Place")) {
OnPressed = e2 => {
GameImpl.Instance.Tickets -= price;
GameImpl.Instance.Analytics.AddResourceEvent(true, "Tickets", price, "Attraction", attraction.Key);
GameImpl.Instance.Platform.AddResourceEvent(true, "Tickets", price, "Attraction", attraction.Key);
map.Place(map.PlacingPosition, map.PlacingAttraction);
this.FadeUi(false, () => this.uiSystem.Remove(e2.Root.Name));
@ -241,7 +230,7 @@ namespace TouchyTickets {
var price = attraction.GetModifierPrice(map.PlacingModifier);
GameImpl.Instance.Tickets -= price;
GameImpl.Instance.Analytics.AddResourceEvent(true, "Tickets", price, "Modifier", modifier.Name);
GameImpl.Instance.Platform.AddResourceEvent(true, "Tickets", price, "Modifier", modifier.Name);
attraction.ApplyModifier(map.PlacingModifier);
},
@ -305,8 +294,8 @@ namespace TouchyTickets {
this.uiSystem.Remove(e2.Root.Name);
var game = GameImpl.Instance;
game.Analytics.AddResourceEvent(true, "Tickets", (long) game.Tickets, "Restart", "Restart" + game.TimesRestarted);
game.Analytics.AddResourceEvent(false, "Stars", game.GetBuyableStars(), "Restart", "Restart" + game.TimesRestarted);
game.Platform.AddResourceEvent(true, "Tickets", (long) game.Tickets, "Restart", "Restart" + game.TimesRestarted);
game.Platform.AddResourceEvent(false, "Stars", game.GetBuyableStars(), "Restart", "Restart" + game.TimesRestarted);
game.Stars += game.GetBuyableStars();
game.TimesRestarted++;
@ -381,41 +370,64 @@ namespace TouchyTickets {
}
}
public IEnumerator<IWait> DisplaySplash() {
public static void SetupUiSystem(UiSystem uiSystem) {
InputHandler.EnableGestures(GestureType.HorizontalDrag, GestureType.FreeDrag, GestureType.Pinch, GestureType.Tap);
uiSystem.GlobalScale = 4;
uiSystem.AutoScaleWithScreen = true;
uiSystem.AutoScaleReferenceSize = new Point(720, 1280);
uiSystem.Style.Font = new GenericSpriteFont(MlemGame.LoadContent<SpriteFont>("Fonts/Regular"));
uiSystem.Style.PanelTexture = uiSystem.Style.ScrollBarBackground = new NinePatch(Texture[2, 1], 4);
uiSystem.Style.ButtonTexture = uiSystem.Style.ScrollBarScrollerTexture = new NinePatch(Texture[3, 1], 4);
uiSystem.Style.TextScale = 0.1F;
uiSystem.TextFormatter.AddImage("ticket", Texture[2, 0]);
uiSystem.TextFormatter.AddImage("star", Texture[3, 0]);
foreach (var modifier in AttractionModifier.Modifiers.Values)
uiSystem.TextFormatter.AddImage(modifier.Name, modifier.Texture);
}
public static IEnumerator<IWait> DisplaySplash(Action loadGame) {
var splash = new Group(Anchor.TopLeft, Vector2.One, false) {
OnDrawn = (e, time, batch, alpha) => batch.Draw(batch.GetBlankTexture(), e.DisplayArea, Color.Black * alpha)
};
var center = splash.AddChild(new Group(Anchor.Center, new Vector2(0.5F, 0.5F), false) {DrawAlpha = 0});
center.AddChild(new Image(Anchor.AutoCenter, new Vector2(1, -1), Texture[4, 0]));
center.AddChild(new Paragraph(Anchor.AutoCenter, 10000, "A game by Ellpeck", true));
this.uiSystem.Add("Splash", splash).Priority = 100000;
GameImpl.Instance.UiSystem.Add("Splash", splash).Priority = 100000;
while (center.DrawAlpha < 1) {
center.DrawAlpha += 0.015F;
yield return new WaitEvent(CoroutineEvents.Update);
}
yield return new WaitSeconds(1);
while (center.DrawAlpha > 0) {
center.DrawAlpha -= 0.015F;
yield return new WaitEvent(CoroutineEvents.Update);
}
if (!GameImpl.Instance.ReadAnalyticsInfo) {
yield return new WaitSeconds(0.5);
var analyticsFlag = new FileInfo(Path.Combine(SaveHandler.GetGameDirectory(true).FullName, "_ReadGdpr"));
if (!analyticsFlag.Exists) {
var evt = new Event();
var panel = splash.AddChild(new Panel(Anchor.Center, new Vector2(0.8F), Vector2.Zero, true));
panel.AddChild(new Paragraph(Anchor.AutoLeft, 1, Localization.Get("GDPRInfo")));
panel.AddChild(new Button(Anchor.AutoLeft, new Vector2(1, 30), Localization.Get("Okay")) {
OnPressed = e2 => {
GameImpl.Instance.ReadAnalyticsInfo = true;
// create the (empty) flag file
using (analyticsFlag.Create()) {
}
splash.RemoveChild(panel);
CoroutineHandler.RaiseEvent(evt);
}
});
yield return new WaitEvent(evt);
}
yield return new WaitSeconds(0.25);
loadGame();
yield return new WaitSeconds(0.25);
while (center.DrawAlpha > 0) {
center.DrawAlpha -= 0.015F;
yield return new WaitEvent(CoroutineEvents.Update);
}
while (splash.DrawAlpha > 0) {
splash.DrawAlpha -= 0.015F;
yield return new WaitEvent(CoroutineEvents.Update);
}
this.uiSystem.Remove(splash.Root.Name);
splash.System.Remove(splash.Root.Name);
}
private void FadeUi(bool fadeOut, Action after = null) {
@ -481,7 +493,7 @@ namespace TouchyTickets {
ChildPadding = new Vector2(4),
OnPressed = e => {
GameImpl.Instance.Stars -= upgrade.Price;
GameImpl.Instance.Analytics.AddResourceEvent(true, "Stars", upgrade.Price, "Upgrade", upgrade.Name);
GameImpl.Instance.Platform.AddResourceEvent(true, "Stars", upgrade.Price, "Upgrade", upgrade.Name);
GameImpl.Instance.AppliedUpgrades.Add(upgrade);
upgrade.OnApplied();

View file

@ -5,9 +5,13 @@ using GameAnalyticsSDK.Utilities;
using TouchyTickets;
namespace iOS {
public class IosAnalytics : Analytics {
public class IosPlatform : Platform {
public override void Setup(Dictionary<string, object> json) {
public override void SetupAds() {
throw new System.NotImplementedException();
}
public override void SetupAnalytics(Dictionary<string, object> json) {
GameAnalytics.Initialize(GA_MiniJSON.JsonEncode(new Hashtable(json)));
}

View file

@ -11,7 +11,7 @@ namespace iOS {
private static void RunGame() {
TextInputWrapper.Current = new TextInputWrapper.Mobile();
game = new GameImpl(new IosAnalytics());
game = new GameImpl(new IosPlatform());
game.Run();
}

View file

@ -111,7 +111,7 @@
<Reference Include="Xamarin.iOS" />
</ItemGroup>
<ItemGroup>
<Compile Include="IosAnalytics.cs" />
<Compile Include="IosPlatform.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>