[Tutorial] How to make your own Haxball map
Oct 13, 2014 15:12:14 GMT 1
lorZ, Michi', and 1 more like this
Post by Gele on Oct 13, 2014 15:12:14 GMT 1
I have created the Haxball map Spiceball myself, and would like to share what I know about creating Haxball maps with all who want to learn it as well.
In this tutorial I try to explain all elements to make a map from scratch. You can of course also start making a map based on an allready existing map.
If you need more help, or have questions, please ask!
Basics
Definitions:
Some words you just need to know what they are:
Vertex: an invisible solid 2D point where discs can't go through.
Segment: a segment connects two vertexes with a wall. They can be visible or invisible, curved or straight.
Plane: defines a one sided boundary, objects can only be on one side of a plane.
Disc: defines a physical disc (Same as the goal posts, the player discs or the ball).
Goal: is a segment defined by two points, when the ball passes through this line a goal will be scored.
Trait: is an optional feature which lets you avoid repetition by defining properties which are common to many objects.
Vertexes, Segments, Planes and Discs all share the following properties:
"bCoef" : <Number from 0.0 to 1.0> - Defines the bouncing coefficient.
"cMask" : <Array of collision layers, eg: ["ball", "red", "blue"]> - Stands for collision mask, it defines which layers this object can collide with.
"cGroup" : <Array of collision layers, eg: ["ball", "red", "blue"]> - Stands for collision group, it defines in which collision layers this object lives.
"trait" : <Name of a trait to inherit from> - When this property is specified the object will inherit the properties defined on the trait.
In addition there are properties specific to each one:
Vertexes:
"x" : <Number> - The X coordinate of the vertex.
"y" : <Number> - The Y coordinate of the vertex.
Segments:
"v0" : <Integer number> - The index of a vertex to connect with this segment.
"v1" : <Integer number> - The index of the other vertex to connect with this segment.
"curve" : <Angle in degrees from -350.0 to 350.0> - How much this segment curves.
"vis" : <true or false> - Wether this segment is visible or not.
"color" : <Color> - Defines the color of the segment.
Plane:
"normal" : <[Number, Number]> - The normal(direction vector) of the plane.
"dist" : <Number> - The distance to <0,0>.
Disc:
"radius" : <Number> - The radius of the disc.
"invMass" : <Number >= 0 > - The inverse of the mass, the closer to 0 the heavier this object is. (Discs with 0 invMass can't move and act as static objects)
"color" : <Color> - The fill color of the disc.
Goal:
"p0" : <[Number, Number]> - First point of the goal.
"p1" : <[Number, Number]> - Second point of the goal.
"team" : <Either "red" or "blue"> - The team whose this goal belongs to.
Some other useful info:
Collision layers are defined as arrays of the following strings:
"ball" - The collision group of the ball.
"red" - The collision group for red players.
"blue" - The collision group for blue players.
"wall" - The default collision group for all stadium objects.
"redKO" - A collision group players will only collide with during the red kickoff. (Useful for kickoff barriers)
"blueKO" - A collision group players will only collide with during the blue kickoff. (Useful for kickoff barriers)
Colors can be defined in two ways (always RGB):
* As a hexa string, eg "F7A2DD"
* As an array of numbers from 0 to 255, eg: [255, 128, 0].
Example map - Spiceball ('//' are comments)
(www.haxmaps.com/map/1673)
{
"name" : "SpIceball by GeleBanaan", // Set the name of the stadium
"width" : 900, // width and height only constrain the camera scrolling
"height" : 540, // width and height only constrain the camera scrolling
"spawnDistance" : 350, // Set how far from the ball the teams will spawn
"bg" : { "type" : "hockey", "width" : 550, "height" : 240, "kickOffRadius" : 80, "cornerRadius" : 0 }, // Set the background. This is only visual, it doesnt' affect the physics at all.
// List of vertexes:
"vertexes" : [
// Left side of the ball area:
{ "x" : -550, "y" : 240, "trait" : "ballArea" }, // Index 0 - Bottom corner
{ "x" : -550, "y" : 80, "trait" : "ballArea" }, // Index 1 - Bottom goal post
{ "x" : -550, "y" : -80, "trait" : "ballArea" }, // Index 2 - Top goal post
{ "x" : -550, "y" : -240, "trait" : "ballArea" }, // Index 3 - Top corner
// Right side of the ball area:
{ "x" : 550, "y" : 240, "trait" : "ballArea" }, // Index 4 - Bottom corner
{ "x" : 550, "y" : 80, "trait" : "ballArea" }, // Index 5 - Bottom goal post
{ "x" : 550, "y" : -80, "trait" : "ballArea" }, // Index 6 - Top goal post
{ "x" : 550, "y" : -240, "trait" : "ballArea" }, // Index 7 - Top corner
// Vertexes involved on the kickoff barrier:
{ "x" : 0, "y" : 550, "trait" : "kickOffBarrier" }, // Index 8 - Bottom center
{ "x" : 0, "y" : 80, "trait" : "kickOffBarrier" }, // Index 9 - Bottom of the kickoff circle
{ "x" : 0, "y" : -80, "trait" : "kickOffBarrier" }, // Index 10 - Top of the kickoff circle
{ "x" : 0, "y" : -550, "trait" : "kickOffBarrier" }, // Index 11 - Top center
// Vertexes involved on the red goal:
{ "x" : -560, "y" : -80, "trait" : "goalNet" }, // Index 12
{ "x" : -580, "y" : -60, "trait" : "goalNet" }, // Index 13
{ "x" : -580, "y" : 60, "trait" : "goalNet" }, // Index 14
{ "x" : -560, "y" : 80, "trait" : "goalNet" }, // Index 15
// Vertexes involved on the blue goal:
{ "x" : 560, "y" : -80, "trait" : "goalNet" }, // Index 16
{ "x" : 580, "y" : -60, "trait" : "goalNet" }, // Index 17
{ "x" : 580, "y" : 60, "trait" : "goalNet" }, // Index 18
{ "x" : 560, "y" : 80, "trait" : "goalNet" } // Index 19
],
// List of segments:
"segments" : [
// Left side ball area walls:
{ "v0" : 0, "v1" : 1, "trait" : "ballArea" }, // Connects bottom corner to bottom goal post
{ "v0" : 2, "v1" : 3, "trait" : "ballArea" }, // Connects top corner to top goal post
// Right side ball area walls:
{ "v0" : 4, "v1" : 5, "trait" : "ballArea" }, // Connects bottom corner to bottom goal post
{ "v0" : 6, "v1" : 7, "trait" : "ballArea" }, // Connects top corner to top goal post
// Goal nets:
{ "v0" : 12, "v1" : 13, "trait" : "goalNet", "curve" : -90 }, // Left goal
{ "v0" : 13, "v1" : 14, "trait" : "goalNet" }, // Left goal
{ "v0" : 14, "v1" : 15, "trait" : "goalNet", "curve" : -90 }, // Left goal
{ "v0" : 16, "v1" : 17, "trait" : "goalNet", "curve" : 90 }, // Right goal
{ "v0" : 17, "v1" : 18, "trait" : "goalNet" }, // Right goal
{ "v0" : 18, "v1" : 19, "trait" : "goalNet", "curve" : 90 }, // Right goal
// Kickoff barriers:
{ "v0" : 8, "v1" : 9, "trait" : "kickOffBarrier" }, // Connects bottom center to kickoff circle bottom
{ "v0" : 9, "v1" : 10, "trait" : "kickOffBarrier", "curve" : 180, "cGroup" : ["blueKO"] }, // Connects Kickoff circle top and bottom, curve = 180 makes half a circle
{ "v0" : 9, "v1" : 10, "trait" : "kickOffBarrier", "curve" : -180, "cGroup" : ["redKO"] }, // Connects Kickoff circle top and bottom again, curve = -180 makes the other half
{ "v0" : 10, "v1" : 11, "trait" : "kickOffBarrier" } // Connects kickoff circle top to top center
],
// List of goals:
"goals" : [
{ "p0" : [-550, 80], "p1" : [-550,-80], "team" : "red" },
{ "p0" : [550, 80], "p1" : [550,-80], "team" : "blue" }
],
// List of discs:
"discs" : [
// Left posts:
{ "pos" : [-550, 80], "trait" : "goalPost", "color" : "FFFFFF" },
{ "pos" : [-550, -80], "trait" : "goalPost", "color" : "FFFFFF" },
// Right posts:
{ "pos" : [ 550, 80], "trait" : "goalPost", "color" : "FFFFFF" },
{ "pos" : [ 550, -80], "trait" : "goalPost", "color" : "FFFFFF" }
],
// List of planes:
"planes" : [
{ "normal" : [0, 1], "dist" : -240, "trait" : "ballArea" }, // Top ball area wall
{ "normal" : [0,-1], "dist" : -240, "trait" : "ballArea" }, // Bottom ball area wall
// Player bounds:
{ "normal" : [ 0, 1], "dist" : -540, "bCoef" : 0.1 }, // Top wall
{ "normal" : [ 0,-1], "dist" : -540, "bCoef" : 0.1 }, // Bottom wall
{ "normal" : [ 1, 0], "dist" : -900, "bCoef" : 0.1 }, // Left wall
{ "normal" : [-1, 0], "dist" : -900, "bCoef" : 0.1 } // Right wall
],
// List of traits:
"traits" : {
"ballArea" : { "vis" : false, "bCoef" : 1, "cMask" : ["ball"] },
"goalPost" : { "radius" : 8, "invMass" : 0, "bCoef" : 0.5 },
"goalNet" : { "vis" : true, "bCoef" : 0.1, "cMask" : ["ball"] },
"kickOffBarrier" : { "vis" : false, "bCoef" : 0.1, "cGroup" : ["redKO", "blueKO"], "cMask" : ["red", "blue"] }
},
// List of ball physics:
"ballPhysics" : {
"radius":10,
"bCoef":0.95,
"damping":0.999,
"invMass":1,
"color":"FFFFFF",
"cMask" : ["all"],
"cGroup" : ["ball"]
},
// List of player physics:
"playerPhysics" : {
"bCoef" : 0.95,
"invMass" : 0.5,
"damping" : 0.9995,
"acceleration" : 0.025,
"kickingAcceleration" : 0.0175,
"kickingDamping" : 0.9995,
"kickStrength" : 5
}
}
In this tutorial I try to explain all elements to make a map from scratch. You can of course also start making a map based on an allready existing map.
If you need more help, or have questions, please ask!
Basics
Definitions:
Some words you just need to know what they are:
Vertex: an invisible solid 2D point where discs can't go through.
Segment: a segment connects two vertexes with a wall. They can be visible or invisible, curved or straight.
Plane: defines a one sided boundary, objects can only be on one side of a plane.
Disc: defines a physical disc (Same as the goal posts, the player discs or the ball).
Goal: is a segment defined by two points, when the ball passes through this line a goal will be scored.
Trait: is an optional feature which lets you avoid repetition by defining properties which are common to many objects.
Vertexes, Segments, Planes and Discs all share the following properties:
"bCoef" : <Number from 0.0 to 1.0> - Defines the bouncing coefficient.
"cMask" : <Array of collision layers, eg: ["ball", "red", "blue"]> - Stands for collision mask, it defines which layers this object can collide with.
"cGroup" : <Array of collision layers, eg: ["ball", "red", "blue"]> - Stands for collision group, it defines in which collision layers this object lives.
"trait" : <Name of a trait to inherit from> - When this property is specified the object will inherit the properties defined on the trait.
In addition there are properties specific to each one:
Vertexes:
"x" : <Number> - The X coordinate of the vertex.
"y" : <Number> - The Y coordinate of the vertex.
Segments:
"v0" : <Integer number> - The index of a vertex to connect with this segment.
"v1" : <Integer number> - The index of the other vertex to connect with this segment.
"curve" : <Angle in degrees from -350.0 to 350.0> - How much this segment curves.
"vis" : <true or false> - Wether this segment is visible or not.
"color" : <Color> - Defines the color of the segment.
Plane:
"normal" : <[Number, Number]> - The normal(direction vector) of the plane.
"dist" : <Number> - The distance to <0,0>.
Disc:
"radius" : <Number> - The radius of the disc.
"invMass" : <Number >= 0 > - The inverse of the mass, the closer to 0 the heavier this object is. (Discs with 0 invMass can't move and act as static objects)
"color" : <Color> - The fill color of the disc.
Goal:
"p0" : <[Number, Number]> - First point of the goal.
"p1" : <[Number, Number]> - Second point of the goal.
"team" : <Either "red" or "blue"> - The team whose this goal belongs to.
Some other useful info:
Collision layers are defined as arrays of the following strings:
"ball" - The collision group of the ball.
"red" - The collision group for red players.
"blue" - The collision group for blue players.
"wall" - The default collision group for all stadium objects.
"redKO" - A collision group players will only collide with during the red kickoff. (Useful for kickoff barriers)
"blueKO" - A collision group players will only collide with during the blue kickoff. (Useful for kickoff barriers)
Colors can be defined in two ways (always RGB):
* As a hexa string, eg "F7A2DD"
* As an array of numbers from 0 to 255, eg: [255, 128, 0].
Example map - Spiceball ('//' are comments)
(www.haxmaps.com/map/1673)
{
"name" : "SpIceball by GeleBanaan", // Set the name of the stadium
"width" : 900, // width and height only constrain the camera scrolling
"height" : 540, // width and height only constrain the camera scrolling
"spawnDistance" : 350, // Set how far from the ball the teams will spawn
"bg" : { "type" : "hockey", "width" : 550, "height" : 240, "kickOffRadius" : 80, "cornerRadius" : 0 }, // Set the background. This is only visual, it doesnt' affect the physics at all.
// List of vertexes:
"vertexes" : [
// Left side of the ball area:
{ "x" : -550, "y" : 240, "trait" : "ballArea" }, // Index 0 - Bottom corner
{ "x" : -550, "y" : 80, "trait" : "ballArea" }, // Index 1 - Bottom goal post
{ "x" : -550, "y" : -80, "trait" : "ballArea" }, // Index 2 - Top goal post
{ "x" : -550, "y" : -240, "trait" : "ballArea" }, // Index 3 - Top corner
// Right side of the ball area:
{ "x" : 550, "y" : 240, "trait" : "ballArea" }, // Index 4 - Bottom corner
{ "x" : 550, "y" : 80, "trait" : "ballArea" }, // Index 5 - Bottom goal post
{ "x" : 550, "y" : -80, "trait" : "ballArea" }, // Index 6 - Top goal post
{ "x" : 550, "y" : -240, "trait" : "ballArea" }, // Index 7 - Top corner
// Vertexes involved on the kickoff barrier:
{ "x" : 0, "y" : 550, "trait" : "kickOffBarrier" }, // Index 8 - Bottom center
{ "x" : 0, "y" : 80, "trait" : "kickOffBarrier" }, // Index 9 - Bottom of the kickoff circle
{ "x" : 0, "y" : -80, "trait" : "kickOffBarrier" }, // Index 10 - Top of the kickoff circle
{ "x" : 0, "y" : -550, "trait" : "kickOffBarrier" }, // Index 11 - Top center
// Vertexes involved on the red goal:
{ "x" : -560, "y" : -80, "trait" : "goalNet" }, // Index 12
{ "x" : -580, "y" : -60, "trait" : "goalNet" }, // Index 13
{ "x" : -580, "y" : 60, "trait" : "goalNet" }, // Index 14
{ "x" : -560, "y" : 80, "trait" : "goalNet" }, // Index 15
// Vertexes involved on the blue goal:
{ "x" : 560, "y" : -80, "trait" : "goalNet" }, // Index 16
{ "x" : 580, "y" : -60, "trait" : "goalNet" }, // Index 17
{ "x" : 580, "y" : 60, "trait" : "goalNet" }, // Index 18
{ "x" : 560, "y" : 80, "trait" : "goalNet" } // Index 19
],
// List of segments:
"segments" : [
// Left side ball area walls:
{ "v0" : 0, "v1" : 1, "trait" : "ballArea" }, // Connects bottom corner to bottom goal post
{ "v0" : 2, "v1" : 3, "trait" : "ballArea" }, // Connects top corner to top goal post
// Right side ball area walls:
{ "v0" : 4, "v1" : 5, "trait" : "ballArea" }, // Connects bottom corner to bottom goal post
{ "v0" : 6, "v1" : 7, "trait" : "ballArea" }, // Connects top corner to top goal post
// Goal nets:
{ "v0" : 12, "v1" : 13, "trait" : "goalNet", "curve" : -90 }, // Left goal
{ "v0" : 13, "v1" : 14, "trait" : "goalNet" }, // Left goal
{ "v0" : 14, "v1" : 15, "trait" : "goalNet", "curve" : -90 }, // Left goal
{ "v0" : 16, "v1" : 17, "trait" : "goalNet", "curve" : 90 }, // Right goal
{ "v0" : 17, "v1" : 18, "trait" : "goalNet" }, // Right goal
{ "v0" : 18, "v1" : 19, "trait" : "goalNet", "curve" : 90 }, // Right goal
// Kickoff barriers:
{ "v0" : 8, "v1" : 9, "trait" : "kickOffBarrier" }, // Connects bottom center to kickoff circle bottom
{ "v0" : 9, "v1" : 10, "trait" : "kickOffBarrier", "curve" : 180, "cGroup" : ["blueKO"] }, // Connects Kickoff circle top and bottom, curve = 180 makes half a circle
{ "v0" : 9, "v1" : 10, "trait" : "kickOffBarrier", "curve" : -180, "cGroup" : ["redKO"] }, // Connects Kickoff circle top and bottom again, curve = -180 makes the other half
{ "v0" : 10, "v1" : 11, "trait" : "kickOffBarrier" } // Connects kickoff circle top to top center
],
// List of goals:
"goals" : [
{ "p0" : [-550, 80], "p1" : [-550,-80], "team" : "red" },
{ "p0" : [550, 80], "p1" : [550,-80], "team" : "blue" }
],
// List of discs:
"discs" : [
// Left posts:
{ "pos" : [-550, 80], "trait" : "goalPost", "color" : "FFFFFF" },
{ "pos" : [-550, -80], "trait" : "goalPost", "color" : "FFFFFF" },
// Right posts:
{ "pos" : [ 550, 80], "trait" : "goalPost", "color" : "FFFFFF" },
{ "pos" : [ 550, -80], "trait" : "goalPost", "color" : "FFFFFF" }
],
// List of planes:
"planes" : [
{ "normal" : [0, 1], "dist" : -240, "trait" : "ballArea" }, // Top ball area wall
{ "normal" : [0,-1], "dist" : -240, "trait" : "ballArea" }, // Bottom ball area wall
// Player bounds:
{ "normal" : [ 0, 1], "dist" : -540, "bCoef" : 0.1 }, // Top wall
{ "normal" : [ 0,-1], "dist" : -540, "bCoef" : 0.1 }, // Bottom wall
{ "normal" : [ 1, 0], "dist" : -900, "bCoef" : 0.1 }, // Left wall
{ "normal" : [-1, 0], "dist" : -900, "bCoef" : 0.1 } // Right wall
],
// List of traits:
"traits" : {
"ballArea" : { "vis" : false, "bCoef" : 1, "cMask" : ["ball"] },
"goalPost" : { "radius" : 8, "invMass" : 0, "bCoef" : 0.5 },
"goalNet" : { "vis" : true, "bCoef" : 0.1, "cMask" : ["ball"] },
"kickOffBarrier" : { "vis" : false, "bCoef" : 0.1, "cGroup" : ["redKO", "blueKO"], "cMask" : ["red", "blue"] }
},
// List of ball physics:
"ballPhysics" : {
"radius":10,
"bCoef":0.95,
"damping":0.999,
"invMass":1,
"color":"FFFFFF",
"cMask" : ["all"],
"cGroup" : ["ball"]
},
// List of player physics:
"playerPhysics" : {
"bCoef" : 0.95,
"invMass" : 0.5,
"damping" : 0.9995,
"acceleration" : 0.025,
"kickingAcceleration" : 0.0175,
"kickingDamping" : 0.9995,
"kickStrength" : 5
}
}