diff --git a/graphics/ui/map.svg b/graphics/ui/map.svg index ac1326d..21c7329 100644 --- a/graphics/ui/map.svg +++ b/graphics/ui/map.svg @@ -226,10 +226,10 @@ inkscape:pageopacity="0" inkscape:pageshadow="2" inkscape:zoom="2.1771152" - inkscape:cx="1247.613" - inkscape:cy="542.95678" + inkscape:cx="1424.0698" + inkscape:cy="540.88968" inkscape:document-units="mm" - inkscape:current-layer="layer5" + inkscape:current-layer="g7289" showgrid="false" units="px" inkscape:snap-bbox="false" @@ -293,12 +293,6 @@ inkscape:groupmode="layer" id="layer5" inkscape:label="Zoom 3"> - + - - + + + + + id="g7284" + inkscape:export-filename="/home/michael/workspace/perso/spacetac/out/assets/images/map/state-unknown.png" + inkscape:export-xdpi="96" + inkscape:export-ydpi="96"> + sodipodi:nodetypes="ccc" + inkscape:export-filename="/home/michael/workspace/perso/spacetac/out/assets/images/map/state-clear.png" + inkscape:export-xdpi="96" + inkscape:export-ydpi="96" /> + id="g7323" + inkscape:export-filename="/home/michael/workspace/perso/spacetac/out/assets/images/map/state-enemy.png" + inkscape:export-xdpi="96" + inkscape:export-ydpi="96"> { - var universe = new Universe(); - universe.stars.push(new Star(universe, 0, 0)); - universe.stars.push(new Star(universe, 1, 0)); - universe.stars.push(new Star(universe, 1, 1)); - universe.addLink(universe.stars[0], universe.stars[1]); - universe.addLink(universe.stars[0], universe.stars[2]); - - var getWarps = (star: Star): StarLocation[] => { - var result: StarLocation[] = []; - star.locations.forEach((location: StarLocation) => { - if (location.type === StarLocationType.WARP) { - result.push(location); - } - }); - return result; - }; - - expect(getWarps(universe.stars[0]).length).toBe(0); - expect(getWarps(universe.stars[1]).length).toBe(0); - expect(getWarps(universe.stars[2]).length).toBe(0); - - universe.stars[0].generate(); - - expect(getWarps(universe.stars[0]).length).toBe(2); - expect(getWarps(universe.stars[1]).length).toBe(0); - expect(getWarps(universe.stars[2]).length).toBe(0); - - universe.stars[1].generate(); - - expect(getWarps(universe.stars[0]).length).toBe(2); - expect(getWarps(universe.stars[1]).length).toBe(1); - expect(getWarps(universe.stars[2]).length).toBe(0); - - universe.stars[2].generate(); - - var warps = getWarps(universe.stars[0]); - expect(warps.length).toBe(2); - expect(warps[0].jump_dest).toBe(universe.stars[2].locations[1]); - expect(warps[1].jump_dest).toBe(universe.stars[1].locations[1]); - warps = getWarps(universe.stars[1]); - expect(warps.length).toBe(1); - expect(warps[0].jump_dest).toBe(universe.stars[0].locations[2]); - warps = getWarps(universe.stars[2]); - expect(warps.length).toBe(1); - expect(warps[0].jump_dest).toBe(universe.stars[0].locations[1]); + expect(universe.stars[0].getLinkTo(universe.stars[1])).toEqual(universe.starlinks[0]); + expect(universe.stars[0].getLinkTo(universe.stars[2])).toBeNull(); + expect(universe.stars[0].getLinkTo(universe.stars[3])).toEqual(universe.starlinks[1]); + expect(universe.stars[1].getLinkTo(universe.stars[0])).toEqual(universe.starlinks[0]); + expect(universe.stars[1].getLinkTo(universe.stars[2])).toBeNull(); + expect(universe.stars[1].getLinkTo(universe.stars[3])).toBeNull(); + expect(universe.stars[2].getLinkTo(universe.stars[0])).toBeNull(); + expect(universe.stars[2].getLinkTo(universe.stars[1])).toBeNull(); + expect(universe.stars[2].getLinkTo(universe.stars[3])).toBeNull(); + expect(universe.stars[3].getLinkTo(universe.stars[0])).toEqual(universe.starlinks[1]); + expect(universe.stars[3].getLinkTo(universe.stars[1])).toBeNull(); + expect(universe.stars[3].getLinkTo(universe.stars[2])).toBeNull(); }); }); } diff --git a/src/game/Star.ts b/src/game/Star.ts index a8c30c4..1dbe862 100644 --- a/src/game/Star.ts +++ b/src/game/Star.ts @@ -77,15 +77,20 @@ module SpaceTac.Game { // Base level for encounters in this system level: number; - constructor(universe: Universe = null, x: number = 0, y: number = 0) { + constructor(universe: Universe = null, x = 0, y = 0, name = "") { super(); this.universe = universe || new Universe(); this.x = x; this.y = y; this.radius = 0.1; - this.locations = []; + this.locations = [new StarLocation(this, StarLocationType.STAR, 0, 0)]; this.level = 1; + this.name = name; + } + + jasmineToString(): string { + return `Star ${this.name}`; } // Get the distance to another star @@ -99,38 +104,22 @@ module SpaceTac.Game { // Generate the contents of this star system generate(random: RandomGenerator = new RandomGenerator()): void { var location_count = random.throwInt(2, 10); - this.locations = this.generateLocations(location_count, random); + this.name = random.choice(Star.NAMES_POOL); + this.generateLocations(location_count, random); } // Generate points of interest (*count* doesn't include the star and warp locations) - generateLocations(count: number, random: RandomGenerator = new RandomGenerator()): StarLocation[] { - var result: StarLocation[] = []; - - // Add the star - result.push(new StarLocation(this, StarLocationType.STAR, 0, 0)); - - // Add warp locations around the star - var links = this.getLinks(); - links.forEach((link: StarLink) => { - var warp = this.generateOneLocation(StarLocationType.WARP, result, this.radius * 0.3, random); - - // If there is an unbound warp location on destination sector, bind with it - var peer_star = link.getPeer(this); - var peer_location = peer_star.findUnboundWarp(); - if (peer_location) { - peer_location.setJumpDestination(warp); - warp.setJumpDestination(peer_location); - } - - result.push(warp); - }); - - // Add random locations + generateLocations(count: number, random = new RandomGenerator()): void { while (count--) { - result.push(this.generateOneLocation(StarLocationType.PLANET, result, this.radius, random)); + this.generateOneLocation(StarLocationType.PLANET, this.locations, this.radius * 0.2, this.radius * 0.7, random); } + } - return result; + // Generate a warp location to another star (to be bound later) + generateWarpLocationTo(other: Star, random = new RandomGenerator()): StarLocation { + let fav_phi = Math.atan2(other.y - this.y, other.x - this.x); + var warp = this.generateOneLocation(StarLocationType.WARP, this.locations, this.radius * 0.8, this.radius * 1, random, fav_phi); + return warp; } // Get the number of links to other stars @@ -146,6 +135,32 @@ module SpaceTac.Game { return result; } + // Get the link to another star, null of not found + getLinkTo(other: Star): StarLink | null { + var result: StarLink | null = null; + + this.universe.starlinks.forEach(link => { + if (link.isLinking(this, other)) { + result = link; + } + }); + + return result; + } + + // Get the warp location to another star, null if not found + getWarpLocationTo(other: Star): StarLocation | null { + var result: StarLocation | null = null; + + this.locations.forEach(location => { + if (location.type == StarLocationType.WARP && location.jump_dest && location.jump_dest.star == other) { + result = location; + } + }); + + return result; + } + // Find an unbound warp location to bind, null if none found findUnboundWarp(): StarLocation { var result: StarLocation = null; @@ -160,18 +175,20 @@ module SpaceTac.Game { // Check if a location is far enough from all other ones private checkMinDistance(loc: StarLocation, others: StarLocation[]): boolean { return others.every((iloc: StarLocation): boolean => { - return iloc.getDistanceTo(loc) > this.radius * 0.1; + return iloc.getDistanceTo(loc) > this.radius * 0.15; }); } // Generate a single location - private generateOneLocation(type: StarLocationType, others: StarLocation[], radius: number, random: RandomGenerator): StarLocation { + private generateOneLocation(type: StarLocationType, others: StarLocation[], radius_min: number, radius_max: number, random: RandomGenerator, fav_phi: number | null = null): StarLocation { do { - var x = (random.throw(2) - 1) * radius; - var y = (random.throw(2) - 1) * radius; - var result = new StarLocation(this, type, x, y); + var phi = fav_phi ? (fav_phi + random.throw(0.4) - 0.2) : random.throw(Math.PI * 2); + var r = random.throw(radius_max - radius_min) + radius_min; + var result = new StarLocation(this, type, r * Math.cos(phi), r * Math.sin(phi)); } while (!this.checkMinDistance(result, others)); + this.locations.push(result); + return result; } } diff --git a/src/game/Universe.spec.ts b/src/game/Universe.spec.ts index 5ebab5d..2c8eb0c 100644 --- a/src/game/Universe.spec.ts +++ b/src/game/Universe.spec.ts @@ -33,5 +33,44 @@ module SpaceTac.Game.Specs { var filtered = universe.filterCrossingLinks(result); expect(filtered.length).toBe(5); }); + + it("generates warp locations", () => { + var universe = new Universe(); + universe.stars.push(new Star(universe, 0, 0, "0")); + universe.stars.push(new Star(universe, 1, 0, "1")); + universe.stars.push(new Star(universe, 1, 1, "2")); + universe.addLink(universe.stars[0], universe.stars[1]); + universe.addLink(universe.stars[0], universe.stars[2]); + + var getWarps = (star: Star): StarLocation[] => { + var result: StarLocation[] = []; + star.locations.forEach((location: StarLocation) => { + if (location.type === StarLocationType.WARP) { + result.push(location); + } + }); + return result; + }; + + expect(getWarps(universe.stars[0]).length).toBe(0); + expect(getWarps(universe.stars[1]).length).toBe(0); + expect(getWarps(universe.stars[2]).length).toBe(0); + + universe.generateWarpLocations(); + + var warps = getWarps(universe.stars[0]); + expect(warps.length).toBe(2); + expect(warps[0].jump_dest.star).toBe(universe.stars[1]); + expect(warps[1].jump_dest.star).toBe(universe.stars[2]); + expect(universe.stars[0].getWarpLocationTo(universe.stars[1])).toBe(warps[0]); + expect(universe.stars[0].getWarpLocationTo(universe.stars[2])).toBe(warps[1]); + warps = getWarps(universe.stars[1]); + expect(warps.length).toBe(1); + expect(warps[0].jump_dest.star).toBe(universe.stars[0]); + expect(universe.stars[1].getWarpLocationTo(universe.stars[2])).toBeNull(); + warps = getWarps(universe.stars[2]); + expect(warps.length).toBe(1); + expect(warps[0].jump_dest.star).toBe(universe.stars[0]); + }); }); } diff --git a/src/game/Universe.ts b/src/game/Universe.ts index 8ece908..8d08d28 100644 --- a/src/game/Universe.ts +++ b/src/game/Universe.ts @@ -17,7 +17,7 @@ module SpaceTac.Game { this.stars = []; this.starlinks = []; - this.radius = 50; + this.radius = 5; } // Generates a universe, with star systems and such @@ -27,6 +27,8 @@ module SpaceTac.Game { var links = this.getPotentialLinks(); this.starlinks = this.filterCrossingLinks(links); + this.generateWarpLocations(random); + this.stars.forEach((star: Star) => { star.generate(random); }); @@ -76,7 +78,7 @@ module SpaceTac.Game { // Filter a list of potential links to avoid crossing ones filterCrossingLinks(links: StarLink[]): StarLink[] { - var result : StarLink[] = []; + var result: StarLink[] = []; links.forEach((link1: StarLink) => { var crossed = false; @@ -93,6 +95,18 @@ module SpaceTac.Game { return result; } + // Generate warp locations for the links between stars + generateWarpLocations(random = new RandomGenerator()) { + this.starlinks.forEach(link => { + let warp1 = link.first.generateWarpLocationTo(link.second, random); + let warp2 = link.second.generateWarpLocationTo(link.first, random); + + warp1.setJumpDestination(warp2); + warp2.setJumpDestination(warp1); + }); + + } + // Get the star nearest to another getNearestTo(star: Star, others: Star[] = null): Star { if (others === null) { @@ -105,7 +119,7 @@ module SpaceTac.Game { var nearest: Star = null; others.forEach((istar: Star) => { if (istar !== star) { - var dist = star.getDistanceTo(istar); + var dist = star.getDistanceTo(istar); if (dist < mindist) { nearest = istar; mindist = dist; diff --git a/src/view/Preload.ts b/src/view/Preload.ts index 2e6d491..cceca04 100644 --- a/src/view/Preload.ts +++ b/src/view/Preload.ts @@ -59,8 +59,12 @@ module SpaceTac.View { this.loadImage("map/starsystem-background.png"); this.loadImage("map/zoom-in.png"); this.loadImage("map/zoom-out.png"); - this.loadImage("map/star.png"); - this.loadImage("map/planet.png"); + this.loadImage("map/location-star.png"); + this.loadImage("map/location-planet.png"); + this.loadImage("map/location-warp.png"); + this.loadImage("map/state-unknown.png"); + this.loadImage("map/state-enemy.png"); + this.loadImage("map/state-clear.png"); // Load ships this.loadShip("scout"); diff --git a/src/view/map/StarSystemDisplay.ts b/src/view/map/StarSystemDisplay.ts index 268e165..c47407f 100644 --- a/src/view/map/StarSystemDisplay.ts +++ b/src/view/map/StarSystemDisplay.ts @@ -12,26 +12,36 @@ module SpaceTac.View { this.starsystem = starsystem; - let boundary = this.game.add.graphics(0, 0); - boundary.lineStyle(3, 0x424242); - boundary.drawCircle(0, 0, scale); - this.addChild(boundary); + // Show boundary + this.addCircle(starsystem.radius); + // Show locations starsystem.locations.forEach(location => { if (location.type == Game.StarLocationType.STAR) { - this.addImage(location.x, location.y, "map-star"); + this.addImage(location.x, location.y, "map-location-star"); } else if (location.type == Game.StarLocationType.PLANET) { - let planet = this.addImage(location.x, location.y, "map-planet"); + let planet = this.addImage(location.x, location.y, "map-location-planet"); planet.rotation = Math.atan2(location.y, location.x); + this.addCircle(Math.sqrt(location.x * location.x + location.y * location.y), 1); + } else if (location.type == Game.StarLocationType.WARP) { + let warp = this.addImage(location.x, location.y, "map-location-warp"); } }); } addImage(x: number, y: number, key: string): Phaser.Image { - let image = this.game.add.image(x * 0.5 / this.scale.x, y * 0.5 / this.scale.y, key); + let image = this.game.add.image(x / this.scale.x, y / this.scale.y, key); image.anchor.set(0.5, 0.5); this.addChild(image); return image; } + + addCircle(radius, width = 3, color = 0x424242): Phaser.Graphics { + let circle = this.game.add.graphics(0, 0); + circle.lineStyle(width, color); + circle.drawCircle(0, 0, radius * 2 / this.scale.x); + this.addChild(circle); + return circle; + } } } diff --git a/src/view/map/UniverseMapView.ts b/src/view/map/UniverseMapView.ts index 26250c6..db7241f 100644 --- a/src/view/map/UniverseMapView.ts +++ b/src/view/map/UniverseMapView.ts @@ -12,6 +12,7 @@ module SpaceTac.View { // Star systems group: Phaser.Group; starsystems: StarSystemDisplay[] = []; + starlinks: Phaser.Graphics[] = []; // Zoom level zoom = 0; @@ -31,6 +32,18 @@ module SpaceTac.View { this.group = new Phaser.Group(this.game); this.add.existing(this.group); + this.starlinks = this.universe.starlinks.map(starlink => { + let loc1 = starlink.first.getWarpLocationTo(starlink.second); + let loc2 = starlink.second.getWarpLocationTo(starlink.first); + + let result = new Phaser.Graphics(this.game); + result.lineStyle(0.005, 0x8bbeff); + result.moveTo(starlink.first.x - 0.5 + loc1.x, starlink.first.y - 0.5 + loc1.y); + result.lineTo(starlink.second.x - 0.5 + loc2.x, starlink.second.y - 0.5 + loc2.y); + return result; + }); + this.starlinks.forEach(starlink => this.group.addChild(starlink)); + this.starsystems = this.universe.stars.map(star => new StarSystemDisplay(this, star)); this.starsystems.forEach(starsystem => this.group.addChild(starsystem)); @@ -63,8 +76,8 @@ module SpaceTac.View { // Set the camera to center on a target, and to display a given span in height setCamera(x: number, y: number, span: number) { let scale = 1000 / span; - this.tweens.create(this.group.position).to({ x: 960 - x * scale, y: 540 - y * scale }).start(); - this.tweens.create(this.group.scale).to({ x: scale, y: scale }).start(); + this.tweens.create(this.group.position).to({ x: 960 - x * scale, y: 540 - y * scale }, 500, Phaser.Easing.Cubic.InOut).start(); + this.tweens.create(this.group.scale).to({ x: scale, y: scale }, 500, Phaser.Easing.Cubic.InOut).start(); } setZoom(level: number) { @@ -73,6 +86,7 @@ module SpaceTac.View { this.setCamera(0, 0, this.universe.radius * 2); this.zoom = 0; } else if (level == 1) { + // TODO Zoom to next-jump accessible this.setCamera(current_star.x, current_star.y, this.universe.radius * 0.5); this.zoom = 1; } else {