finally added proper highscore saving shit and save load shit

This commit is contained in:
RandomityGuy 2021-06-26 23:03:41 +05:30
parent df30d81697
commit 7d3c373a40
10 changed files with 306 additions and 25 deletions

1
.gitignore vendored
View file

@ -8,3 +8,4 @@ data
native native
*.exe *.exe
*.obj *.obj
settings.json

View file

@ -1,5 +1,6 @@
package; package;
import src.Settings;
import src.MarbleGame; import src.MarbleGame;
import gui.MainMenuGui; import gui.MainMenuGui;
import hxd.res.DefaultFont; import hxd.res.DefaultFont;
@ -14,6 +15,7 @@ class Main extends hxd.App {
override function init() { override function init() {
super.init(); super.init();
Settings.load();
marbleGame = new MarbleGame(s2d, s3d); marbleGame = new MarbleGame(s2d, s3d);
MarbleGame.canvas.setContent(new MainMenuGui()); MarbleGame.canvas.setContent(new MainMenuGui());
// world = new MarbleWorld(s3d, s2d, mission); // world = new MarbleWorld(s3d, s2d, mission);

View file

@ -628,8 +628,6 @@ class MarbleWorld extends Scheduler {
public function updateTimer(dt:Float) { public function updateTimer(dt:Float) {
this.timeState.dt = dt; this.timeState.dt = dt;
this.timeState.currentAttemptTime += dt;
this.timeState.timeSinceLoad += dt;
if (this.bonusTime != 0 && this.timeState.currentAttemptTime >= 3.5) { if (this.bonusTime != 0 && this.timeState.currentAttemptTime >= 3.5) {
this.bonusTime -= dt; this.bonusTime -= dt;
if (this.bonusTime < 0) { if (this.bonusTime < 0) {
@ -639,7 +637,12 @@ class MarbleWorld extends Scheduler {
} else { } else {
if (this.timeState.currentAttemptTime >= 3.5) if (this.timeState.currentAttemptTime >= 3.5)
this.timeState.gameplayClock += dt; this.timeState.gameplayClock += dt;
else if (this.timeState.currentAttemptTime + dt >= 3.5) {
this.timeState.gameplayClock += (this.timeState.currentAttemptTime + dt) - 3.5;
}
} }
this.timeState.currentAttemptTime += dt;
this.timeState.timeSinceLoad += dt;
if (finishTime != null) if (finishTime != null)
this.timeState.gameplayClock = finishTime.gameplayClock; this.timeState.gameplayClock = finishTime.gameplayClock;
playGui.formatTimer(this.timeState.gameplayClock); playGui.formatTimer(this.timeState.gameplayClock);
@ -805,7 +808,7 @@ class MarbleWorld extends Scheduler {
MarbleGame.canvas.popDialog(egg); MarbleGame.canvas.popDialog(egg);
this.setCursorLock(true); this.setCursorLock(true);
this.restart(); this.restart();
}); }, mission, finishTime);
MarbleGame.canvas.pushDialog(egg); MarbleGame.canvas.pushDialog(egg);
this.setCursorLock(false); this.setCursorLock(false);
return 0; return 0;

View file

@ -21,20 +21,21 @@ class ResourceLoader {
static var dtsResources:Map<String, DtsFile> = new Map(); static var dtsResources:Map<String, DtsFile> = new Map();
static var textureCache:Map<String, Texture> = new Map(); static var textureCache:Map<String, Texture> = new Map();
static var imageCache:Map<String, Image> = new Map(); static var imageCache:Map<String, Image> = new Map();
static var threadPool:FixedThreadPool = new FixedThreadPool(4);
// static var threadPool:FixedThreadPool = new FixedThreadPool(4);
public static function loadInterior(path:String) { public static function loadInterior(path:String) {
if (interiorResources.exists(path)) if (interiorResources.exists(path))
return interiorResources.get(path); return interiorResources.get(path);
else { else {
var itr:Dif; var itr:Dif;
var lock = new Lock(); // var lock = new Lock();
threadPool.run(() -> { // threadPool.run(() -> {
itr = Dif.Load(path); itr = Dif.Load(path);
interiorResources.set(path, itr); interiorResources.set(path, itr);
lock.release(); // lock.release();
}); // });
lock.wait(); // lock.wait();
return itr; return itr;
} }
} }
@ -44,13 +45,13 @@ class ResourceLoader {
return dtsResources.get(path); return dtsResources.get(path);
else { else {
var dts = new DtsFile(); var dts = new DtsFile();
var lock = new Lock(); // var lock = new Lock();
threadPool.run(() -> { // threadPool.run(() -> {
dts.read(path); dts.read(path);
dtsResources.set(path, dts); dtsResources.set(path, dts);
lock.release(); // lock.release();
}); // });
lock.wait(); // lock.wait();
return dts; return dts;
} }
} }

52
src/Settings.hx Normal file
View file

@ -0,0 +1,52 @@
package src;
import haxe.DynamicAccess;
import sys.io.File;
import src.ResourceLoader;
import haxe.Json;
typedef Score = {
var name:String;
var time:Float;
}
class Settings {
public static var highScores:Map<String, Array<Score>> = [];
public static function saveScore(mapPath:String, score:Score) {
if (highScores.exists(mapPath)) {
var scoreList = highScores.get(mapPath);
scoreList.push(score);
scoreList.sort((a, b) -> a.time == b.time ? 0 : (a.time > b.time ? 1 : -1));
} else {
highScores.set(mapPath, [score]);
}
save();
}
public static function getScores(mapPath:String) {
if (highScores.exists(mapPath)) {
return highScores.get(mapPath).copy();
} else {
return [];
}
}
public static function save() {
var outputData = {
highScores: highScores
};
var json = Json.stringify(outputData);
File.saveContent("settings.json", json);
}
public static function load() {
if (ResourceLoader.fileSystem.exists("settings.json")) {
var json = Json.parse(ResourceLoader.fileSystem.get("settings.json").getText());
var highScoreData:DynamicAccess<Array<Score>> = json.highScores;
for (key => value in highScoreData) {
highScores.set(key, value);
}
}
}
}

View file

@ -157,4 +157,22 @@ class Util {
} }
return false; return false;
} }
public static function formatTime(time:Float) {
var et = time * 1000;
var thousandth = Math.floor(et % 10);
var hundredth = Math.floor((et % 1000) / 10);
var totalSeconds = Math.floor(et / 1000);
var seconds = totalSeconds % 60;
var minutes = (totalSeconds - seconds) / 60;
var secondsOne = seconds % 10;
var secondsTen = (seconds - secondsOne) / 10;
var minutesOne = minutes % 10;
var minutesTen = (minutes - minutesOne) / 10;
var hundredthOne = hundredth % 10;
var hundredthTen = (hundredth - hundredthOne) / 10;
return '${minutesTen}${minutesOne}:${secondsTen}${secondsOne}.${hundredthTen}${hundredthOne}${thousandth}';
}
} }

View file

@ -1,17 +1,28 @@
package gui; package gui;
import src.MarbleGame;
import src.Settings.Score;
import src.Settings.Settings;
import src.Mission;
import h2d.filter.DropShadow; import h2d.filter.DropShadow;
import hxd.res.BitmapFont; import hxd.res.BitmapFont;
import h3d.Vector; import h3d.Vector;
import src.ResourceLoader; import src.ResourceLoader;
import src.TimeState;
import src.Util;
class EndGameGui extends GuiControl { class EndGameGui extends GuiControl {
public function new(continueFunc:GuiControl->Void, restartFunc:GuiControl->Void) { var mission:Mission;
var scoreSubmitted:Bool = false;
public function new(continueFunc:GuiControl->Void, restartFunc:GuiControl->Void, mission:Mission, timeState:TimeState) {
super(); super();
this.horizSizing = Width; this.horizSizing = Width;
this.vertSizing = Height; this.vertSizing = Height;
this.position = new Vector(0, 0); this.position = new Vector(0, 0);
this.extent = new Vector(640, 480); this.extent = new Vector(640, 480);
this.mission = mission;
function loadButtonImages(path:String) { function loadButtonImages(path:String) {
var normal = ResourceLoader.getImage('${path}_n.png').toTile(); var normal = ResourceLoader.getImage('${path}_n.png').toTile();
@ -69,7 +80,7 @@ class EndGameGui extends GuiControl {
var congrats = new GuiMLText(expo50, mlFontLoader); var congrats = new GuiMLText(expo50, mlFontLoader);
congrats.text.textColor = 0xffff00; congrats.text.textColor = 0xffff00;
congrats.text.text = 'Final Time: <font color="#FFF090">99:59.999</font>'; congrats.text.text = 'Final Time: <font color="#FFF090">${Util.formatTime(timeState.gameplayClock)}</font>';
congrats.text.filter = new DropShadow(1.414, 0.785, 0, 1, 0, 0.4, 1, true); congrats.text.filter = new DropShadow(1.414, 0.785, 0, 1, 0, 0.4, 1, true);
congrats.position = new Vector(43, 17); congrats.position = new Vector(43, 17);
congrats.extent = new Vector(408, 50); congrats.extent = new Vector(408, 50);
@ -84,17 +95,31 @@ class EndGameGui extends GuiControl {
finishMessage.extent = new Vector(200, 100); finishMessage.extent = new Vector(200, 100);
pg.addChild(finishMessage); pg.addChild(finishMessage);
var scoreData:Array<Score> = Settings.getScores(mission.path);
while (scoreData.length < 3) {
scoreData.push({name: "Nardo Polo", time: 5999.999});
}
var leftColumn = new GuiMLText(domcasual32, mlFontLoader); var leftColumn = new GuiMLText(domcasual32, mlFontLoader);
leftColumn.text.textColor = 0x000000; leftColumn.text.textColor = 0x000000;
leftColumn.text.text = 'Qualify Time:<br/>Gold Time:<br/>Elapsed Time:<br/>Bonus Time:<br/><font face="Arial14"><br/></font>Best Times:<br/>1. Nardo Polo<br/>2. Nardo Polo<br/>3. Nardo Polo'; leftColumn.text.text = 'Qualify Time:<br/>Gold Time:<br/>Elapsed Time:<br/>Bonus Time:<br/><font face="Arial14"><br/></font>Best Times:<br/>';
for (i in 0...3) {
leftColumn.text.text += '${i + 1}. ${scoreData[i].name}<br/>';
}
leftColumn.text.filter = new DropShadow(1.414, 0.785, 0xffffff, 1, 0, 0.4, 1, true); leftColumn.text.filter = new DropShadow(1.414, 0.785, 0xffffff, 1, 0, 0.4, 1, true);
leftColumn.position = new Vector(108, 103); leftColumn.position = new Vector(108, 103);
leftColumn.extent = new Vector(208, 50); leftColumn.extent = new Vector(208, 50);
pg.addChild(leftColumn); pg.addChild(leftColumn);
var elapsedTime = Math.max(timeState.currentAttemptTime - 5.5, 0);
var bonusTime = Math.max(0, elapsedTime - timeState.gameplayClock);
var rightColumn = new GuiMLText(domcasual32, mlFontLoader); var rightColumn = new GuiMLText(domcasual32, mlFontLoader);
rightColumn.text.textColor = 0x000000; rightColumn.text.textColor = 0x000000;
rightColumn.text.text = '99:59.999<br/>99:59.999<br/>99:59.999<br/>99:59.999<br/><font face="Arial14"><br/></font><br/>99:59.999<br/>99:59.999<br/>99:59.999'; rightColumn.text.text = '${Util.formatTime(mission.qualifyTime == Math.POSITIVE_INFINITY ? 5999.999 : mission.qualifyTime)}<br/>${Util.formatTime(mission.goldTime)}<br/>${Util.formatTime(elapsedTime)}<br/>${Util.formatTime(bonusTime)}<br/><font face="Arial14"><br/></font><br/>';
for (i in 0...3) {
rightColumn.text.text += '${Util.formatTime(scoreData[i].time)}<br/>';
}
rightColumn.text.filter = new DropShadow(1.414, 0.785, 0xffffff, 1, 0, 0.4, 1, true); rightColumn.text.filter = new DropShadow(1.414, 0.785, 0xffffff, 1, 0, 0.4, 1, true);
rightColumn.position = new Vector(274, 103); rightColumn.position = new Vector(274, 103);
rightColumn.extent = new Vector(208, 50); rightColumn.extent = new Vector(208, 50);
@ -104,5 +129,36 @@ class EndGameGui extends GuiControl {
pg.addChild(restartButton); pg.addChild(restartButton);
this.addChild(pg); this.addChild(pg);
var scoreTimes = scoreData.map(x -> x.time).concat([timeState.gameplayClock]);
scoreTimes.sort((a, b) -> a == b ? 0 : (a > b ? 1 : -1));
var idx = scoreTimes.indexOf(timeState.gameplayClock);
if (idx <= 2) {
var end = new EnterNameDlg(idx, (name) -> {
if (scoreSubmitted)
return;
var myScore = {name: name, time: timeState.gameplayClock};
scoreData.push(myScore);
scoreData.sort((a, b) -> a.time == b.time ? 0 : (a.time > b.time ? 1 : -1));
leftColumn.text.text = 'Qualify Time:<br/>Gold Time:<br/>Elapsed Time:<br/>Bonus Time:<br/><font face="Arial14"><br/></font>Best Times:<br/>';
for (i in 0...3) {
leftColumn.text.text += '${i + 1}. ${scoreData[i].name}<br/>';
}
rightColumn.text.text = '${Util.formatTime(mission.qualifyTime == Math.POSITIVE_INFINITY ? 5999.999 : mission.qualifyTime)}<br/>${Util.formatTime(mission.goldTime)}<br/>${Util.formatTime(elapsedTime)}<br/>${Util.formatTime(bonusTime)}<br/><font face="Arial14"><br/></font><br/>';
for (i in 0...3) {
rightColumn.text.text += '${Util.formatTime(scoreData[i].time)}<br/>';
}
Settings.saveScore(mission.path, myScore);
scoreSubmitted = true;
});
this.addChild(end);
}
} }
} }

87
src/gui/EnterNameDlg.hx Normal file
View file

@ -0,0 +1,87 @@
package gui;
import hxd.res.BitmapFont;
import h3d.Vector;
import src.ResourceLoader;
import src.MarbleGame;
class EnterNameDlg extends GuiControl {
public function new(place:Int, okFunc:String->Void) {
super();
this.position = new Vector();
this.extent = new Vector(640, 480);
this.horizSizing = Width;
this.vertSizing = Height;
function loadButtonImages(path:String) {
var normal = ResourceLoader.getImage('${path}_n.png').toTile();
var hover = ResourceLoader.getImage('${path}_h.png').toTile();
var pressed = ResourceLoader.getImage('${path}_d.png').toTile();
return [normal, hover, pressed];
}
var arial14fontdata = ResourceLoader.loader.load("data/font/Arial14.fnt");
var arial14 = new BitmapFont(arial14fontdata.entry);
@:privateAccess arial14.loader = ResourceLoader.loader;
var domcasual32fontdata = ResourceLoader.loader.load("data/font/DomCasual32px.fnt");
var domcasual32 = new BitmapFont(domcasual32fontdata.entry);
@:privateAccess domcasual32.loader = ResourceLoader.loader;
var expo50fontdata = ResourceLoader.loader.load("data/font/Expo50.fnt");
var expo50 = new BitmapFont(expo50fontdata.entry);
@:privateAccess expo50.loader = ResourceLoader.loader;
var expo32fontdata = ResourceLoader.loader.load("data/font/Expo32.fnt");
var expo32 = new BitmapFont(expo32fontdata.entry);
@:privateAccess expo32.loader = ResourceLoader.loader;
function mlFontLoader(text:String) {
switch (text) {
case "DomCasual32":
return domcasual32.toFont();
case "Arial14":
return arial14.toFont();
case "Expo50":
return expo50.toFont();
default:
return null;
}
}
var dlg = new GuiImage(ResourceLoader.getImage("data/ui/common/dialog.png").toTile());
dlg.horizSizing = Center;
dlg.vertSizing = Center;
dlg.position = new Vector(112, 111);
dlg.extent = new Vector(416, 257);
this.addChild(dlg);
var enterNameEdit = new GuiTextInput(domcasual32);
enterNameEdit.position = new Vector(87, 136);
enterNameEdit.extent = new Vector(255, 36);
var okbutton = new GuiButton(loadButtonImages("data/ui/common/ok"));
okbutton.position = new Vector(163, 182);
okbutton.extent = new Vector(78, 59);
okbutton.pressedAction = (sender) -> {
MarbleGame.canvas.popDialog(this);
okFunc(enterNameEdit.text.text);
}
dlg.addChild(okbutton);
var wnd = new GuiImage(ResourceLoader.getImage("data/ui/common/window.png").toTile());
wnd.position = new Vector(58, 124);
wnd.extent = new Vector(295, 55);
dlg.addChild(wnd);
var enterNameText = new GuiMLText(domcasual32, mlFontLoader);
enterNameText.text.textColor = 0;
enterNameText.position = new Vector(41, 30);
enterNameText.extent = new Vector(345, 14);
// enterNameText.justify = Center;
enterNameText.text.text = '<p align="center"><font face="Expo50">Congratulations<br/></font>You got the${["", " 2nd", " 3rd"][place]} best time!</p>';
dlg.addChild(enterNameText);
dlg.addChild(enterNameEdit);
}
}

53
src/gui/GuiTextInput.hx Normal file
View file

@ -0,0 +1,53 @@
package gui;
import h2d.TextInput;
import h2d.Scene;
import hxd.res.BitmapFont;
import gui.GuiText.Justification;
import h2d.Text;
import src.ResourceLoader;
import src.MarbleGame;
class GuiTextInput extends GuiControl {
var text:TextInput;
var justify:Justification = Left;
public function new(font:BitmapFont) {
super();
this.text = new TextInput(font.toFont());
this.text.textColor = 0;
}
public override function render(scene2d:Scene) {
var renderRect = this.getRenderRectangle();
if (justify == Left) {
text.setPosition(renderRect.position.x, renderRect.position.y);
text.textAlign = Left;
}
if (justify == Right) {
text.setPosition(renderRect.position.x + renderRect.extent.x, renderRect.position.y);
text.textAlign = Right;
}
if (justify == Center) {
text.setPosition(renderRect.position.x + renderRect.extent.x / 2, renderRect.position.y);
text.textAlign = Center;
}
if (scene2d.contains(text))
scene2d.removeChild(text);
scene2d.addChild(text);
this.text.inputWidth = cast renderRect.extent.x;
super.render(scene2d);
}
public override function dispose() {
super.dispose();
this.text.remove();
}
public override function onRemove() {
super.onRemove();
if (MarbleGame.canvas.scene2d.contains(text)) {
MarbleGame.canvas.scene2d.removeChild(text); // Refresh "layer"
}
}
}

View file

@ -1,5 +1,7 @@
package gui; package gui;
import src.Settings.Score;
import src.Settings.Settings;
import haxe.io.Path; import haxe.io.Path;
import h2d.Scene; import h2d.Scene;
import h2d.Text; import h2d.Text;
@ -297,11 +299,17 @@ class PlayMissionGui extends GuiImage {
pmNext.disabled = false; pmNext.disabled = false;
var currentMission = currentList[currentSelection]; var currentMission = currentList[currentSelection];
var scoreData:Array<Score> = Settings.getScores(currentMission.path);
while (scoreData.length < 3) {
scoreData.push({name: "Nardo Polo", time: 5999.999});
}
var descText = '<font face="DomCasual24" color="#000000">${currentMission.title}</font><br/><br/>' var descText = '<font face="DomCasual24" color="#000000">${currentMission.title}</font><br/><br/>'
+ splitTextWithPadding(pmDescription.text, Util.unescape(currentMission.description)); + splitTextWithPadding(pmDescription.text, Util.unescape(currentMission.description));
descText += '<br/><br/><font face="DomCasual24">Best Times:</font><br/>'; descText += '<br/><br/><font face="DomCasual24">Best Times:</font><br/>';
for (i in 0...3) { for (i in 0...3) {
descText += '<br/>ÂÂ<font face="ArialBold14">${i + 1}. Nardo Polo</font>'; descText += '<br/>ÂÂ<font face="ArialBold14">${i + 1}. ${scoreData[i].name}</font>';
} }
pmDescription.text.text = descText; pmDescription.text.text = descText;
@ -309,7 +317,7 @@ class PlayMissionGui extends GuiImage {
+ '<font opacity="0">${splitTextWithPadding(pmDescriptionOther.text, Util.unescape(currentMission.description))}</font>'; + '<font opacity="0">${splitTextWithPadding(pmDescriptionOther.text, Util.unescape(currentMission.description))}</font>';
descText2 += '<br/><br/><br/>'; descText2 += '<br/><br/><br/>';
for (i in 0...3) { for (i in 0...3) {
descText2 += '<br/>ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ<font face="ArialBold14">00:00.000</font>'; descText2 += '<br/>ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ<font face="ArialBold14">${Util.formatTime(scoreData[i].time)}</font>';
} }
pmDescriptionOther.text.text = descText2; pmDescriptionOther.text.text = descText2;