import "./const.ecal" as const import "./helper.ecal" as hlp /* Constant rate for moving. The higher the less movement we do in a given time. */ moveRate := 30 /* Time the move loop was executed last (used for time correction) */ lastMoveCycleTime := 0 /* Game engine object which moves objects in a game world. */ GameEngine := { /* Partition to manage */ "part" : null, /* Game world */ "world" : null, /* Constructor */ "init" : func (part, world) { this.part := part this.world := world }, /* updateStats updates the statistic node in the DB.*/ "updateStats" : func (state) { state["key"] := "stats" state["kind"] := "stats" db.updateNode(this.part, state) }, /* moveLoop handles object movement in the game world. */ "moveLoop" : func () { let moveLoopTime := now() let timeDelta := moveLoopTime - lastMoveCycleTime # Do the move /* Do a single move step with compensation for the time delta */ time := now() this.move(timeDelta) this.updateStats({"time_total_move" : now() - time}) lastMoveCycleTime := moveLoopTime }, /* move calculates one move step */ "move" : func (timeDelta) { /* Calculate a correction multiplier for the time lag */ let timeCorrection := timeDelta / moveRate if math.isNaN(timeCorrection) or math.isInf(timeCorrection, 0) { timeCorrection := 1 } /* Store the latest time correction */ this.updateStats({"time_move_correction" : timeCorrection}) gq := "{ obj { key, kind, x, y, dim, displayLoop, dir, rot, rotSpeed, speed, strafe, moveSpeed } }" time := now() res := db.graphQL(this.part, gq) this.updateStats({"time_move_graphql" : now() - time}) if len(res.data.obj) > 0 { trans := db.newTrans() time := now() for obj in res.data.obj { if not this.moveObject(timeCorrection, obj, trans) { 0 # TODO Decide if the entity should be removed } } this.updateStats({"time_move_update" : now() - time}) time := now() db.commit(trans) this.updateStats({"time_move_commit" : now() - time}) } }, /* Move a specific object in the game world. Return false if the object should be removed from the world. */ "moveObject" : func (timeCorrection, obj, trans) { let keepObj := true /* Calculate new entity coordinates */ let moveStep := timeCorrection * obj.speed * obj.moveSpeed let strafeStep := timeCorrection * obj.strafe * obj.moveSpeed * 20 /* Forward / backward movement */ let newX := obj.x + math.cos(obj.rot) * moveStep let newY := obj.y + math.sin(obj.rot) * moveStep /* Left / right strafe movement */ newX := newX - math.sin(obj.rot) * strafeStep newY := newY + math.cos(obj.rot) * strafeStep /* Rotate the entity */ obj.rot := obj.rot + timeCorrection * obj.dir * obj.rotSpeed obj.x := math.floor(newX) obj.y := math.floor(newY) /* Ensure the entity does not move outside the boundaries */ if obj.displayLoop { hmin := 0 - obj.dim - 20 hmax := this.world.screenWidth + obj.dim + 20 if obj.x > hmax { obj.x := 0 - obj.dim - 10 } elif obj.x < hmin { obj.x := this.world.screenWidth + obj.dim + 10 } vmin := 0 - obj.dim - 20 vmax := this.world.screenHeight + obj.dim + 20 if obj.y > vmax { obj.y := 0 - obj.dim - 10 } elif obj.y < vmin { obj.y := this.world.screenHeight + obj.dim + 10 } } elif obj.x > this.world.screenWidth or obj.x < 0 or obj.y > this.world.screenHeight or obj.y < 0 { keepObj := false } db.updateNode(this.part, { "key" : obj.key, "kind" : obj.kind, "x" : obj.x, "y" : obj.y, "rot" : obj.rot }, trans) return keepObj } }