mirror of
https://github.com/RandomityGuy/MBHaxe.git
synced 2025-10-30 08:11:25 +00:00
finally added proper highscore saving shit and save load shit
This commit is contained in:
parent
df30d81697
commit
7d3c373a40
10 changed files with 306 additions and 25 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -8,3 +8,4 @@ data
|
|||
native
|
||||
*.exe
|
||||
*.obj
|
||||
settings.json
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
package;
|
||||
|
||||
import src.Settings;
|
||||
import src.MarbleGame;
|
||||
import gui.MainMenuGui;
|
||||
import hxd.res.DefaultFont;
|
||||
|
|
@ -14,6 +15,7 @@ class Main extends hxd.App {
|
|||
override function init() {
|
||||
super.init();
|
||||
|
||||
Settings.load();
|
||||
marbleGame = new MarbleGame(s2d, s3d);
|
||||
MarbleGame.canvas.setContent(new MainMenuGui());
|
||||
// world = new MarbleWorld(s3d, s2d, mission);
|
||||
|
|
|
|||
|
|
@ -628,8 +628,6 @@ class MarbleWorld extends Scheduler {
|
|||
|
||||
public function updateTimer(dt:Float) {
|
||||
this.timeState.dt = dt;
|
||||
this.timeState.currentAttemptTime += dt;
|
||||
this.timeState.timeSinceLoad += dt;
|
||||
if (this.bonusTime != 0 && this.timeState.currentAttemptTime >= 3.5) {
|
||||
this.bonusTime -= dt;
|
||||
if (this.bonusTime < 0) {
|
||||
|
|
@ -639,7 +637,12 @@ class MarbleWorld extends Scheduler {
|
|||
} else {
|
||||
if (this.timeState.currentAttemptTime >= 3.5)
|
||||
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)
|
||||
this.timeState.gameplayClock = finishTime.gameplayClock;
|
||||
playGui.formatTimer(this.timeState.gameplayClock);
|
||||
|
|
@ -805,7 +808,7 @@ class MarbleWorld extends Scheduler {
|
|||
MarbleGame.canvas.popDialog(egg);
|
||||
this.setCursorLock(true);
|
||||
this.restart();
|
||||
});
|
||||
}, mission, finishTime);
|
||||
MarbleGame.canvas.pushDialog(egg);
|
||||
this.setCursorLock(false);
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -21,20 +21,21 @@ class ResourceLoader {
|
|||
static var dtsResources:Map<String, DtsFile> = new Map();
|
||||
static var textureCache:Map<String, Texture> = 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) {
|
||||
if (interiorResources.exists(path))
|
||||
return interiorResources.get(path);
|
||||
else {
|
||||
var itr:Dif;
|
||||
var lock = new Lock();
|
||||
threadPool.run(() -> {
|
||||
// var lock = new Lock();
|
||||
// threadPool.run(() -> {
|
||||
itr = Dif.Load(path);
|
||||
interiorResources.set(path, itr);
|
||||
lock.release();
|
||||
});
|
||||
lock.wait();
|
||||
// lock.release();
|
||||
// });
|
||||
// lock.wait();
|
||||
return itr;
|
||||
}
|
||||
}
|
||||
|
|
@ -44,13 +45,13 @@ class ResourceLoader {
|
|||
return dtsResources.get(path);
|
||||
else {
|
||||
var dts = new DtsFile();
|
||||
var lock = new Lock();
|
||||
threadPool.run(() -> {
|
||||
// var lock = new Lock();
|
||||
// threadPool.run(() -> {
|
||||
dts.read(path);
|
||||
dtsResources.set(path, dts);
|
||||
lock.release();
|
||||
});
|
||||
lock.wait();
|
||||
// lock.release();
|
||||
// });
|
||||
// lock.wait();
|
||||
return dts;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
52
src/Settings.hx
Normal file
52
src/Settings.hx
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
18
src/Util.hx
18
src/Util.hx
|
|
@ -157,4 +157,22 @@ class Util {
|
|||
}
|
||||
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}';
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,17 +1,28 @@
|
|||
package gui;
|
||||
|
||||
import src.MarbleGame;
|
||||
import src.Settings.Score;
|
||||
import src.Settings.Settings;
|
||||
import src.Mission;
|
||||
import h2d.filter.DropShadow;
|
||||
import hxd.res.BitmapFont;
|
||||
import h3d.Vector;
|
||||
import src.ResourceLoader;
|
||||
import src.TimeState;
|
||||
import src.Util;
|
||||
|
||||
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();
|
||||
this.horizSizing = Width;
|
||||
this.vertSizing = Height;
|
||||
this.position = new Vector(0, 0);
|
||||
this.extent = new Vector(640, 480);
|
||||
this.mission = mission;
|
||||
|
||||
function loadButtonImages(path:String) {
|
||||
var normal = ResourceLoader.getImage('${path}_n.png').toTile();
|
||||
|
|
@ -69,7 +80,7 @@ class EndGameGui extends GuiControl {
|
|||
|
||||
var congrats = new GuiMLText(expo50, mlFontLoader);
|
||||
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.position = new Vector(43, 17);
|
||||
congrats.extent = new Vector(408, 50);
|
||||
|
|
@ -84,17 +95,31 @@ class EndGameGui extends GuiControl {
|
|||
finishMessage.extent = new Vector(200, 100);
|
||||
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);
|
||||
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.position = new Vector(108, 103);
|
||||
leftColumn.extent = new Vector(208, 50);
|
||||
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);
|
||||
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.position = new Vector(274, 103);
|
||||
rightColumn.extent = new Vector(208, 50);
|
||||
|
|
@ -104,5 +129,36 @@ class EndGameGui extends GuiControl {
|
|||
pg.addChild(restartButton);
|
||||
|
||||
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
87
src/gui/EnterNameDlg.hx
Normal 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
53
src/gui/GuiTextInput.hx
Normal 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"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,7 @@
|
|||
package gui;
|
||||
|
||||
import src.Settings.Score;
|
||||
import src.Settings.Settings;
|
||||
import haxe.io.Path;
|
||||
import h2d.Scene;
|
||||
import h2d.Text;
|
||||
|
|
@ -297,11 +299,17 @@ class PlayMissionGui extends GuiImage {
|
|||
pmNext.disabled = false;
|
||||
|
||||
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/>'
|
||||
+ splitTextWithPadding(pmDescription.text, Util.unescape(currentMission.description));
|
||||
descText += '<br/><br/><font face="DomCasual24">Best Times:</font><br/>';
|
||||
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;
|
||||
|
||||
|
|
@ -309,7 +317,7 @@ class PlayMissionGui extends GuiImage {
|
|||
+ '<font opacity="0">${splitTextWithPadding(pmDescriptionOther.text, Util.unescape(currentMission.description))}</font>';
|
||||
descText2 += '<br/><br/><br/>';
|
||||
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;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue