It starts at 0 because the index value tells the computer how far it needs to move away from the starting point in the array. In some programming languages, if you use an array (without giving an index number in brackets), you are really only referring to the memory address of the starting point of the array. When you reference a specific value in the array, you are telling the programming language to start at the memory address of the beginning of the array and then move up the memory address as needed. So lets say a program allocates space in the memory between address numbers 1024 and 2048 and it starts at 1024 and each item in the array is 8 bytes long. Then saying arrayName is the same as telling it to look at the data stored at the memory address of (1024 + (0 * 8)), or 1024. If you want the value stored at arrayName, then it looks at the value held at (1024 + (1*8)), which is 1032. If you wanted the value held at arrayName, then it would look at the data stored in the memory address of 1024 + (10 * 8), which is 1104. You get the idea. This is how things work with older languages and some languages that work with more memory manipulations.
However, many new languages that don't force the user to work with memory and pointers as much keep the old format to make transitions from one language to another programming language easier and less confusing.