summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/math/aabb.h18
-rw-r--r--core/math/octree.h12
-rw-r--r--core/ustring.cpp31
-rw-r--r--core/ustring.h2
-rw-r--r--demos/3d/polygon_path_finder/engine.cfg5
-rw-r--r--demos/3d/polygon_path_finder/icon.pngbin712 -> 0 bytes
-rw-r--r--demos/3d/polygon_path_finder/poly_with_holes.scnbin2974 -> 0 bytes
-rw-r--r--demos/3d/polygon_path_finder/polygonpathfinder.gd77
-rw-r--r--doc/base/classes.xml35
-rw-r--r--main/input_default.cpp3
-rw-r--r--scene/2d/navigation_polygon.cpp4
-rw-r--r--tools/docker/Dockerfile13
-rw-r--r--tools/docker/README.md40
-rw-r--r--tools/docker/scripts/install-android-tools90
14 files changed, 210 insertions, 120 deletions
diff --git a/core/math/aabb.h b/core/math/aabb.h
index 7c9c3081ac..0fada859c0 100644
--- a/core/math/aabb.h
+++ b/core/math/aabb.h
@@ -66,6 +66,7 @@ public:
bool operator!=(const AABB& p_rval) const;
_FORCE_INLINE_ bool intersects(const AABB& p_aabb) const; /// Both AABBs overlap
+ _FORCE_INLINE_ bool intersects_inclusive(const AABB& p_aabb) const; /// Both AABBs (or their faces) overlap
_FORCE_INLINE_ bool encloses(const AABB & p_aabb) const; /// p_aabb is completely inside this
AABB merge(const AABB& p_with) const;
@@ -126,6 +127,23 @@ inline bool AABB::intersects(const AABB& p_aabb) const {
return true;
}
+inline bool AABB::intersects_inclusive(const AABB& p_aabb) const {
+
+ if ( pos.x > (p_aabb.pos.x + p_aabb.size.x) )
+ return false;
+ if ( (pos.x+size.x) < p_aabb.pos.x )
+ return false;
+ if ( pos.y > (p_aabb.pos.y + p_aabb.size.y) )
+ return false;
+ if ( (pos.y+size.y) < p_aabb.pos.y )
+ return false;
+ if ( pos.z > (p_aabb.pos.z + p_aabb.size.z) )
+ return false;
+ if ( (pos.z+size.z) < p_aabb.pos.z )
+ return false;
+
+ return true;
+}
inline bool AABB::encloses(const AABB & p_aabb) const {
diff --git a/core/math/octree.h b/core/math/octree.h
index b51c4bcba7..69edf80e09 100644
--- a/core/math/octree.h
+++ b/core/math/octree.h
@@ -201,7 +201,7 @@ private:
_FORCE_INLINE_ void _pair_check(PairData *p_pair) {
- bool intersect=p_pair->A->aabb.intersects( p_pair->B->aabb );
+ bool intersect=p_pair->A->aabb.intersects_inclusive( p_pair->B->aabb );
if (intersect!=p_pair->intersect) {
@@ -480,7 +480,7 @@ void Octree<T,use_pairs,AL>::_insert_element(Element *p_element,Octant *p_octant
if (p_octant->children[i]) {
/* element exists, go straight to it */
- if (p_octant->children[i]->aabb.intersects( p_element->aabb ) ) {
+ if (p_octant->children[i]->aabb.intersects_inclusive( p_element->aabb ) ) {
_insert_element( p_element, p_octant->children[i] );
splits++;
}
@@ -497,7 +497,7 @@ void Octree<T,use_pairs,AL>::_insert_element(Element *p_element,Octant *p_octant
if (i&4)
aabb.pos.z+=aabb.size.z;
- if (aabb.intersects( p_element->aabb) ) {
+ if (aabb.intersects_inclusive( p_element->aabb) ) {
/* if actually intersects, create the child */
Octant *child = memnew_allocator( Octant, AL );
@@ -1146,7 +1146,7 @@ void Octree<T,use_pairs,AL>::_cull_AABB(Octant *p_octant,const AABB& p_aabb, T**
continue;
e->last_pass=pass;
- if (p_aabb.intersects(e->aabb)) {
+ if (p_aabb.intersects_inclusive(e->aabb)) {
if (*p_result_idx<p_result_max) {
@@ -1175,7 +1175,7 @@ void Octree<T,use_pairs,AL>::_cull_AABB(Octant *p_octant,const AABB& p_aabb, T**
continue;
e->last_pass=pass;
- if (p_aabb.intersects(e->aabb)) {
+ if (p_aabb.intersects_inclusive(e->aabb)) {
if (*p_result_idx<p_result_max) {
@@ -1193,7 +1193,7 @@ void Octree<T,use_pairs,AL>::_cull_AABB(Octant *p_octant,const AABB& p_aabb, T**
for (int i=0;i<8;i++) {
- if (p_octant->children[i] && p_octant->children[i]->aabb.intersects(p_aabb)) {
+ if (p_octant->children[i] && p_octant->children[i]->aabb.intersects_inclusive(p_aabb)) {
_cull_AABB(p_octant->children[i],p_aabb, p_result_array,p_result_idx,p_result_max,p_subindex_array,p_mask);
}
}
diff --git a/core/ustring.cpp b/core/ustring.cpp
index ee750c39e5..1017fc0ca3 100644
--- a/core/ustring.cpp
+++ b/core/ustring.cpp
@@ -507,26 +507,35 @@ String String::capitalize() const {
return cap;
}
-String String::camelcase_to_underscore() const {
+String String::camelcase_to_underscore(bool lowercase) const {
const CharType * cstr = c_str();
- String newString;
+ String new_string;
const char A = 'A', Z = 'Z';
- int startIndex = 0;
+ const char a = 'a', z = 'z';
+ int start_index = 0;
- for ( int i = 1; i < this->size()-1; i++ ) {
- bool isCapital = cstr[i] >= A && cstr[i] <= Z;
+ for ( size_t i = 1; i < this->size(); i++ ) {
+ bool is_upper = cstr[i] >= A && cstr[i] <= Z;
+ bool are_next_2_lower = false;
+ bool was_precedent_upper = cstr[i-1] >= A && cstr[i-1] <= Z;
- if ( isCapital ) {
- newString += "_" + this->substr(startIndex, i-startIndex);
- startIndex = i;
+ if (i+2 < this->size()) {
+ are_next_2_lower = cstr[i+1] >= a && cstr[i+1] <= z && cstr[i+2] >= a && cstr[i+2] <= z;
}
- }
- newString += "_" + this->substr(startIndex, this->size()-startIndex);
+ bool should_split = ((is_upper && !was_precedent_upper) || (was_precedent_upper && is_upper && are_next_2_lower));
+ if (should_split) {
+ new_string += this->substr(start_index, i - start_index) + "_";
+ start_index = i;
+ }
+ }
- return newString;
+ new_string += this->substr(start_index, this->size() - start_index);
+ return lowercase ? new_string.to_lower() : new_string;
}
+
+
int String::get_slice_count(String p_splitter) const{
if (empty())
diff --git a/core/ustring.h b/core/ustring.h
index 9276afa0f7..e65103ff99 100644
--- a/core/ustring.h
+++ b/core/ustring.h
@@ -149,7 +149,7 @@ public:
static double to_double(const CharType* p_str, const CharType **r_end=NULL);
static int64_t to_int(const CharType* p_str,int p_len=-1);
String capitalize() const;
- String camelcase_to_underscore() const;
+ String camelcase_to_underscore(bool lowercase=true) const;
int get_slice_count(String p_splitter) const;
String get_slice(String p_splitter,int p_slice) const;
diff --git a/demos/3d/polygon_path_finder/engine.cfg b/demos/3d/polygon_path_finder/engine.cfg
deleted file mode 100644
index 47450408af..0000000000
--- a/demos/3d/polygon_path_finder/engine.cfg
+++ /dev/null
@@ -1,5 +0,0 @@
-[application]
-
-name="Polygon Pathfinder"
-main_scene="res://poly_with_holes.scn"
-icon="res://icon.png"
diff --git a/demos/3d/polygon_path_finder/icon.png b/demos/3d/polygon_path_finder/icon.png
deleted file mode 100644
index 643f5595ee..0000000000
--- a/demos/3d/polygon_path_finder/icon.png
+++ /dev/null
Binary files differ
diff --git a/demos/3d/polygon_path_finder/poly_with_holes.scn b/demos/3d/polygon_path_finder/poly_with_holes.scn
deleted file mode 100644
index 6b340377b7..0000000000
--- a/demos/3d/polygon_path_finder/poly_with_holes.scn
+++ /dev/null
Binary files differ
diff --git a/demos/3d/polygon_path_finder/polygonpathfinder.gd b/demos/3d/polygon_path_finder/polygonpathfinder.gd
deleted file mode 100644
index 1e843043da..0000000000
--- a/demos/3d/polygon_path_finder/polygonpathfinder.gd
+++ /dev/null
@@ -1,77 +0,0 @@
-
-extends Spatial
-
-
-func _ready():
- var pf = PolygonPathFinder.new()
-
- var points = Vector2Array()
- var connections = IntArray()
-
- # Poly 1
- points.push_back(Vector2(0, 0)) # 0
- points.push_back(Vector2(10, 0)) # 1
- points.push_back(Vector2(10, 10)) # 2
- points.push_back(Vector2(0, 10)) # 3
-
- connections.push_back(0) # Connect vertex 0...
- connections.push_back(1) # ... to 1
- drawLine(points[0], points[1], get_node("/root/Spatial/Polys"))
- connections.push_back(1) # Connect vertex 1...
- connections.push_back(2) # ... to 2
- drawLine(points[1], points[2], get_node("/root/Spatial/Polys"))
- connections.push_back(2) # Etc.
- connections.push_back(3)
- drawLine(points[2], points[3], get_node("/root/Spatial/Polys"))
- connections.push_back(3) # Connect vertex 3...
- connections.push_back(0) # ... back to vertex 0, to close the polygon
- drawLine(points[3], points[0], get_node("/root/Spatial/Polys"))
-
- # Poly 2, as obstacle inside poly 1
- points.push_back(Vector2(2, 0.5)) # 4
- points.push_back(Vector2(4, 0.5)) # 5
- points.push_back(Vector2(4, 9.5)) # 6
- points.push_back(Vector2(2, 9.5)) # 7
-
- connections.push_back(4)
- connections.push_back(5)
- drawLine(points[4], points[5], get_node("/root/Spatial/Polys"))
- connections.push_back(5)
- connections.push_back(6)
- drawLine(points[5], points[6], get_node("/root/Spatial/Polys"))
- connections.push_back(6)
- connections.push_back(7)
- drawLine(points[6], points[7], get_node("/root/Spatial/Polys"))
- connections.push_back(7)
- connections.push_back(4)
- drawLine(points[7], points[4], get_node("/root/Spatial/Polys"))
-
- print("points: ", points)
- print("connections: ", connections)
-
- pf.setup(points, connections)
-
- var path = pf.find_path(Vector2(1, 5), Vector2(8, 5))
-
- var lastStep = null
- print("path: ", path)
- for step in path:
- print("step: ", step)
- if (lastStep != null):
- var currPathSegment = Vector2Array()
- drawLine(lastStep, step, get_node("/root/Spatial/Path"))
- lastStep = step
-
-
-func drawLine(pointA, pointB, immediateGeo):
- var drawPosY = 0.1
- var im = immediateGeo
-
- im.begin(Mesh.PRIMITIVE_POINTS, null)
- im.add_vertex(Vector3(pointA.x, drawPosY, pointA.y))
- im.add_vertex(Vector3(pointB.x, drawPosY, pointB.y))
- im.end()
- im.begin(Mesh.PRIMITIVE_LINE_STRIP, null)
- im.add_vertex(Vector3(pointA.x, drawPosY, pointA.y))
- im.add_vertex(Vector3(pointB.x, drawPosY, pointB.y))
- im.end()
diff --git a/doc/base/classes.xml b/doc/base/classes.xml
index a11297789c..164557578d 100644
--- a/doc/base/classes.xml
+++ b/doc/base/classes.xml
@@ -9412,7 +9412,7 @@ This approximation makes straight segments between each point, then subdivides t
Damped spring constraint for 2D physics.
</brief_description>
<description>
- Damped spring constraint for 2D physics. This resembles a spring joint that always want to go back to a given length.
+ Damped spring constraint for 2D physics. This resembles a spring joint that always wants to go back to a given length.
</description>
<methods>
<method name="set_length">
@@ -9447,28 +9447,28 @@ This approximation makes straight segments between each point, then subdivides t
<argument index="0" name="stiffness" type="float">
</argument>
<description>
- Set the stiffness of the spring joint.
+ Set the stiffness of the spring joint. The joint applies a force equal to the stiffness times the distance from its resting length.
</description>
</method>
<method name="get_stiffness" qualifiers="const">
<return type="float">
</return>
<description>
- Return the stiffness of the spring joint.
+ Return the stiffness of the spring joint. The joint applies a force equal to the stiffness times the distance from its resting length.
</description>
</method>
<method name="set_damping">
<argument index="0" name="damping" type="float">
</argument>
<description>
- Set the damping of the spring joint.
+ Set the damping ratio of the spring joint. A value of 0 indicates an undamped spring, while 1 causes the system to reach equilibrium as fast as possible (critical damping).
</description>
</method>
<method name="get_damping" qualifiers="const">
<return type="float">
</return>
<description>
- Return the damping of the spring joint.
+ Return the damping ratio of the spring joint. A value of 0 indicates an undamped spring, while 1 causes the system to reach equilibrium as fast as possible (critical damping).
</description>
</method>
</methods>
@@ -9608,7 +9608,8 @@ This approximation makes straight segments between each point, then subdivides t
<brief_description>
Directory type.
</brief_description>
- <description>Directory type. Is used to manage directories and their content (not restricted to the project folder).
+ <description>
+ Directory type. Is used to manage directories and their content (not restricted to the project folder).
How to iterate through the files of a directory example:
@@ -9633,21 +9634,21 @@ func dir(path):
<argument index="0" name="path" type="String">
</argument>
<description>
-Opens a directory to work with. Needs a path, example "res://folder"
+ Opens a directory to work with. Needs a path, example "res://folder"
</description>
</method>
<method name="list_dir_begin">
<return type="bool">
</return>
<description>
-Loads all file names of the current directory (prepares the get_next() function).
+ Loads all file names of the current directory (prepares the get_next() function).
</description>
</method>
<method name="get_next">
<return type="String">
</return>
<description>
-Is used to iterate through the files of the current directory. Returns the name(no path) of the current file/directory, it also contains "." and ".." .
+ Is used to iterate through the files of the current directory. Returns the name(no path) of the current file/directory, it also contains "." and ".." .
Returns an empty String "" at the end of the list.
</description>
</method>
@@ -9655,12 +9656,12 @@ Returns an empty String "" at the end of the list.
<return type="bool">
</return>
<description>
-Returns true if the current file you are looking at with get_next() is a directory or "." or ".." otherwise false.
+ Returns true if the current file you are looking at with get_next() is a directory or "." or ".." otherwise false.
</description>
</method>
<method name="list_dir_end">
<description>
-Run this to empty the list of remaining files in get_next(). You can use it to end the iteration, as soon as your goal is reached.
+ Run this to empty the list of remaining files in get_next(). You can use it to end the iteration, as soon as your goal is reached.
</description>
</method>
<method name="get_drive_count">
@@ -9683,14 +9684,14 @@ Run this to empty the list of remaining files in get_next(). You can use it to e
<argument index="0" name="todir" type="String">
</argument>
<description>
-Needs a path or name to the next directory. When the target directory is in the current directory you can use "newfolder" otherwise you need the full path "res://currentfolder/newfolder"
+ Needs a path or name to the next directory. When the target directory is in the current directory you can use "newfolder" otherwise you need the full path "res://currentfolder/newfolder"
</description>
</method>
<method name="get_current_dir">
<return type="String">
</return>
<description>
-Returns a path to the current directory, example: "res://folder"
+ Returns a path to the current directory, example: "res://folder"
</description>
</method>
<method name="make_dir">
@@ -9723,7 +9724,7 @@ Returns a path to the current directory, example: "res://folder"
<argument index="0" name="name" type="String">
</argument>
<description>
-Returns true if directory exists otherwise false. Needs a path, example: "res://folder"
+ Returns true if directory exists otherwise false. Needs a path, example: "res://folder"
</description>
</method>
<method name="get_space_left">
@@ -18475,13 +18476,13 @@ verify_host will check the SSL identity of the host if set to true.
</description>
<methods>
<method name="set_navigation_polygon">
- <argument index="0" name="navpoly" type="Object">
+ <argument index="0" name="navpoly" type="NavigationPolygon">
</argument>
<description>
</description>
</method>
<method name="get_navigation_polygon" qualifiers="const">
- <return type="Object">
+ <return type="NavigationPolygon">
</return>
<description>
</description>
@@ -36428,7 +36429,7 @@ This method controls whether the position between two cached points is interpola
<argument index="1" name="y" type="int">
</argument>
<description>
- Return whether the referenced cell is transposed, i.e. the X and Y axes are swapped (mirroring with regard to the (1,1) vector).
+ Return whether the referenced cell is transposed, i.e. the X and Y axes are swapped (mirroring with regard to the (1,1) vector).
</description>
</method>
<method name="clear">
diff --git a/main/input_default.cpp b/main/input_default.cpp
index 3af02b2b1f..90d406810a 100644
--- a/main/input_default.cpp
+++ b/main/input_default.cpp
@@ -498,6 +498,7 @@ static const char *s_ControllerMappings [] =
"03000000a306000023f6000011010000,Saitek Cyborg V.1 Game Pad,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a4,lefttrigger:b6,righttrigger:b7,",
"03000000ad1b000001f5000033050000,Hori Pad EX Turbo 2,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,",
"03000000ba2200002010000001010000,Jess Technology USB Game Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,",
+ "03000000c9110000f055000011010000,HJC Game GAMEPAD,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b4,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,",
"03000000de280000ff11000001000000,Valve Streaming Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"03000000f0250000c183000010010000,Goodbetterbest Ltd USB Controller,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,",
"03000000ff1100003133000010010000,PC Game Controller,a:b2,b:b1,y:b0,x:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,",
@@ -914,7 +915,7 @@ String InputDefault::get_joy_guid(int p_device) const {
//platforms that use the remapping system can override and call to these ones
bool InputDefault::is_joy_mapped(int p_device) {
int mapping = joy_names[p_device].mapping;
- return mapping != -1 ? (mapping == fallback_mapping) : false;
+ return mapping != -1 ? (mapping != fallback_mapping) : false;
}
String InputDefault::get_joy_guid_remapped(int p_device) const {
diff --git a/scene/2d/navigation_polygon.cpp b/scene/2d/navigation_polygon.cpp
index 4c00d8cec9..376aeb2d85 100644
--- a/scene/2d/navigation_polygon.cpp
+++ b/scene/2d/navigation_polygon.cpp
@@ -429,8 +429,8 @@ void NavigationPolygonInstance::_navpoly_changed() {
void NavigationPolygonInstance::_bind_methods() {
- ObjectTypeDB::bind_method(_MD("set_navigation_polygon","navpoly"),&NavigationPolygonInstance::set_navigation_polygon);
- ObjectTypeDB::bind_method(_MD("get_navigation_polygon"),&NavigationPolygonInstance::get_navigation_polygon);
+ ObjectTypeDB::bind_method(_MD("set_navigation_polygon","navpoly:NavigationPolygon"),&NavigationPolygonInstance::set_navigation_polygon);
+ ObjectTypeDB::bind_method(_MD("get_navigation_polygon:NavigationPolygon"),&NavigationPolygonInstance::get_navigation_polygon);
ObjectTypeDB::bind_method(_MD("set_enabled","enabled"),&NavigationPolygonInstance::set_enabled);
ObjectTypeDB::bind_method(_MD("is_enabled"),&NavigationPolygonInstance::is_enabled);
diff --git a/tools/docker/Dockerfile b/tools/docker/Dockerfile
new file mode 100644
index 0000000000..428de9d1a7
--- /dev/null
+++ b/tools/docker/Dockerfile
@@ -0,0 +1,13 @@
+FROM ubuntu:14.04
+MAINTAINER Mohammad Rezai, https://github.com/mrezai
+WORKDIR /godot-dev
+COPY scripts/install-android-tools /godot-dev/
+ENV DEBIAN_FRONTEND noninteractive
+RUN dpkg --add-architecture i386 && \
+ apt-get update && \
+ apt-get upgrade -y && \
+ apt-get install --no-install-recommends -y -q \
+ build-essential gcc-multilib g++-multilib mingw32 mingw-w64 scons pkg-config libx11-dev libxcursor-dev \
+ libasound2-dev libfreetype6-dev libgl1-mesa-dev libglu-dev libssl-dev libxinerama-dev libudev-dev \
+ git wget openjdk-7-jdk libbcprov-java libc6:i386 libncurses5:i386 libstdc++6:i386 zlib1g:i386 lib32z1
+
diff --git a/tools/docker/README.md b/tools/docker/README.md
new file mode 100644
index 0000000000..7f10b46ad8
--- /dev/null
+++ b/tools/docker/README.md
@@ -0,0 +1,40 @@
+## A Docker image to build Linux, Windows and Android godot binaries.
+
+The main reason to write this, is to provide a simple way in all platforms to integrate external godot modules and build a custom version of godot.
+
+## usage
+1. Install docker on Linux or docker toolbox on Windows or Mac.
+2. Open a terminal on linux or "Docker Quickstart Terminal" on Windows or Mac.
+3. Run command:
+ - Linux: `cd`
+ - Windows: `cd /c/Users/YOUR_USERNAME`
+ - Mac: `cd /Users/YOUR_USERNAME`
+4. Get godot source code: `git clone https://github.com/godotengine/godot.git`
+5. Run command: `cd godot/tools/docker`
+6. Run command: `docker build -t godot .`(In Linux run Docker commands with `sudo` or add your user to docker group before run the Docker commands). The godot docker image will be build after a while.
+7. Run command:
+ - Linux: `docker run -it --name=godot-dev -v /home/YOUR_USERNAME/godot:/godot-dev/godot godot`
+ - Windows: `docker run -it --name=godot-dev -v /c/Users/YOUR_USERNAME/godot:/godot-dev/godot godot`
+ - Mac: `docker run -it --name=godot-dev -v /Users/YOUR_USERNAME/godot:/godot-dev/godot godot`
+ You are in the godot-dev container and /godot-dev directory now.
+8. Run `./install-android-tools` to download and install all android development tools.
+9. Run command: `source ~/.bashrc`
+10. Run command: `cd godot`
+11. Run command: `scons p=android target=release` to test everything is ok. You can set platform to x11, windows, android, haiku and server.
+
+After use and exit, you can use this environment again by open terminal and type commands: `docker start godot-dev && docker attach godot-dev`.
+
+### Windows and Mac stuffs:
+
+- Speed up compilation:
+ - Exit from container.
+ - Run command: `docker-machine stop`
+ - Open "Oracle VM VirtualBox".
+ - In settings of default VM increase CPU cores and RAM to suitable values.
+ - Run command: `docker-machine start`
+ - Run command: `docker start godot-dev && docker attach godot-dev`
+
+- ssh to VM(can be useful sometimes):
+ - `docker-machine ssh`
+
+Check docker and boot2docker projects for more details.
diff --git a/tools/docker/scripts/install-android-tools b/tools/docker/scripts/install-android-tools
new file mode 100644
index 0000000000..8a617d9942
--- /dev/null
+++ b/tools/docker/scripts/install-android-tools
@@ -0,0 +1,90 @@
+#!/bin/bash
+
+BASH_RC=~/.bashrc
+GODOT_BUILD_TOOLS_PATH=/godot-dev/build-tools
+mkdir -p $GODOT_BUILD_TOOLS_PATH
+cd $GODOT_BUILD_TOOLS_PATH
+
+ANDROID_BASE_URL=http://dl.google.com/android
+
+ANDROID_SDK_RELEASE=android-sdk_r24.4.1
+ANDROID_SDK_DIR=android-sdk-linux
+ANDROID_SDK_FILENAME=$ANDROID_SDK_RELEASE-linux.tgz
+ANDROID_SDK_URL=$ANDROID_BASE_URL/$ANDROID_SDK_FILENAME
+ANDROID_SDK_PATH=$GODOT_BUILD_TOOLS_PATH/$ANDROID_SDK_DIR
+ANDROID_SDK_SHA1=725bb360f0f7d04eaccff5a2d57abdd49061326d
+
+ANDROID_NDK_RELEASE=android-ndk-r10e
+ANDROID_NDK_DIR=$ANDROID_NDK_RELEASE
+ANDROID_NDK_FILENAME=$ANDROID_NDK_RELEASE-linux-x86_64.bin
+ANDROID_NDK_URL=$ANDROID_BASE_URL/ndk/$ANDROID_NDK_FILENAME
+ANDROID_NDK_PATH=$GODOT_BUILD_TOOLS_PATH/$ANDROID_NDK_DIR
+ANDROID_NDK_MD5=19af543b068bdb7f27787c2bc69aba7f
+
+echo
+echo "Download and install Android development tools ..."
+echo
+
+if [ ! -e $ANDROID_SDK_FILENAME ]; then
+ echo "Downloading: Android SDK ..."
+ wget $ANDROID_SDK_URL
+else
+ echo $ANDROID_SDK_SHA1 $ANDROID_SDK_FILENAME > $ANDROID_SDK_FILENAME.sha1
+ sha1sum --check --strict $ANDROID_SDK_FILENAME.sha1
+ if [ ! $? -eq 0 ]; then
+ echo "Downloading: Android SDK ..."
+ wget $ANDROID_SDK_URL
+ fi
+fi
+
+if [ ! -d $ANDROID_SDK_DIR ]; then
+ tar -xvzf $ANDROID_SDK_FILENAME
+fi
+
+if [ ! -e $ANDROID_NDK_FILENAME ]; then
+ echo "Downloading: Android NDK ..."
+ wget $ANDROID_NDK_URL
+else
+ echo $ANDROID_NDK_MD5 $ANDROID_NDK_FILENAME > $ANDROID_NDK_FILENAME.md5
+ md5sum --check --strict $ANDROID_NDK_FILENAME.md5
+ if [ ! $? -eq 0 ]; then
+ echo "Downloading: Android NDK ..."
+ wget $ANDROID_NDK_URL
+ fi
+fi
+
+if [ ! -d $ANDROID_NDK_DIR ]; then
+ chmod a+x $ANDROID_NDK_FILENAME
+ ./$ANDROID_NDK_FILENAME
+ echo
+fi
+
+cd $ANDROID_SDK_DIR/tools
+chmod a+x android
+
+if ! ./android list target | grep -q 'android-19'; then
+ echo "Installing: Android Tools ..."
+ echo y | ./android update sdk --no-ui --all --filter "platform-tools,android-19,build-tools-19.1.0,\
+ extra-android-m2repository,extra-android-support,extra-google-google_play_services,extra-google-m2repository,\
+ extra-google-play_apk_expansion,extra-google-play_billing,extra-google-play_licensing"
+fi
+
+EXPORT_VAL="export ANDROID_HOME=$ANDROID_SDK_PATH"
+if ! grep -q "^$EXPORT_VAL" $BASH_RC; then
+ echo $EXPORT_VAL >> ~/.bashrc
+fi
+
+
+EXPORT_VAL="export ANDROID_NDK_ROOT=$ANDROID_NDK_PATH"
+if ! grep -q "^$EXPORT_VAL" $BASH_RC; then
+ echo $EXPORT_VAL >> ~/.bashrc
+fi
+
+EXPORT_VAL="export PATH=$PATH:$ANDROID_SDK_PATH/tools"
+if ! grep -q "^export PATH=.*$ANDROID_SDK_PATH/tools.*" $BASH_RC; then
+ echo $EXPORT_VAL >> ~/.bashrc
+fi
+
+echo
+echo "Done!"
+echo \ No newline at end of file