- Home /
Asymmetricly placed, data containing, predefined movement locations for a 2d, top down turn based tactical game that takes place on a topographic map
Please forgive any misuse of terms, I am very new to game making in general. I am trying to make a 2d tactical game that takes place on a topographic map where I create the move spaces based off of terrain features. This means that each move space will have a different shape and I will also have to set which spaces each movement space has a LOS to.
Could anyone help point me in a direction for how to accomplish this or how to better pose this question if I am being unclear?
Thank you so much in advance for any help.
Edit: I updated the title to what I believe conveys the concept much better than the previous one.
Please forgive the poor drawing: https://docs.google.com/file/d/0B1G5FQvunF5uNmtleF9YaEpTckk/edit
The idea is that I create predeter$$anonymous$$ed position points that conform to line-of-sight blocking terrain features. This is similar to a grid move system but different in that the move spots are not aligned with the x,z axes, rather along natural topographic formations.
$$anonymous$$y thinking is that for a 2D top-down tactical infantry combat game this will make it easier to deter$$anonymous$$e LOS because I will tell each position which other positions it can see. Each position will have ratings for cover, concealment, and elevation that I will input from studying the satellite imagery. This will hopefully make it easier for creating an AI that will seek out preferred ratings for cover, concealment, and LOS when when the situation becomes less desirable for the unit. These points will also be nodes for path-finding. Again, please forgive me if any of this doesn't make sense given I may be misusing ter$$anonymous$$ology as I am new to this.
Thank you so much for responding and if you could help in any way please do not hesitate to ask more clarifying questions.
have you already got height information for the map etc. What have you achieved so far?
I have the World Composer asset addon and have learned how to make 3d real world models of terrain. I also have a lot of experience with topographic maps and I was planning on just using the contour lines to see elevation and inputting it by hand unless there is an easier way to do it. So far this project is still very early and I only recently began learning Unity but I am very serious about this project and any help and more questions are greatly appreciated.
For me so far, gathering the data is the easy part. I am just unsure where to go and how to proceed to implement my ideas. I am spending as much time as I can watching tutorials and learning Unity, but again I am very new to this.
Answer by Scribe · Nov 16, 2014 at 10:46 PM
Coding your own line of sight check is NOT easy, if you have a height map then I would suggest creating the terrain or mesh that goes with it and then using the built in raycast functions to check for each 'grid space' which other grid spaces it can see.
you can do that quite simply by having a few embedded for loops:
Vector3[,] gridSpace;
//For each grid space
for(int z = 0; z < depth; z++){
for(int x = 0; x < width; x++){
Vector3 parentSpace = gridSpace[x, z];
//Check all grid spaces
for(int zi = 0; zi < depth; zi++){
for(int xi = 0; xi < width; xi++){
Vector3 childSpace = gridSpace[xi, zi];
// shoot a ray from your gridSpace[x, z] to gridSpace[xi, zi] and see if it hits anything on the way, if not, then this 'childSpace' grid space if visible from the 'parentSpace'
// save that information somewhere!
}
}
}
}
Because I had lots of work to do I decided to procrastinate and see if I could write my own line of sightcode so here is a basic (and bad) implementation of how you could do it from scratch using some heightmap data:
using UnityEngine;
using System;
using System.Collections;
using System.Collections.Generic;
public class heightmap : MonoBehaviour {
float[,] heights;
HeightMap hMap;
public int xSize = 12;
public int zSize = 3;
void Start(){
heights = new float[xSize,zSize];
for(int z = 0; z < zSize; z++){
for(int x = 0; x < xSize; x++){
heights[x, z] = UnityEngine.Random.Range(0f, 1f);
}
}
hMap = new HeightMap(heights, Vector3.zero, 1, 0.5f);
}
}
public class HeightMap {
HeightPoint[,] hPoints;
float pointSpacing;
Vector3 origin;
int width;
int depth;
float viewUpHeight;
public HeightMap(float[,] h, Vector3 o, float space, float viewUH){
pointSpacing = space;
origin = o;
width = h.GetLength(0);
depth = h.GetLength(1);
viewUpHeight = viewUH;
hPoints = new HeightPoint[width, depth];
for(int z = 0; z < depth; z++){
for(int x = 0; x < width; x++){
hPoints[x, z] = new HeightPoint(x, z, new Vector3(origin.x+x*pointSpacing, origin.y+h[x, z], origin.z+z*pointSpacing), this);
}
}
CalcLineOfSight();
CreateMap();
}
public void CreateMap(){
for(int z = 0; z < depth; z++){
for(int x = 0; x < width; x++){
GameObject o = GameObject.CreatePrimitive(PrimitiveType.Plane);
o.transform.position = hPoints[x, z].pos;
o.transform.localScale = Vector3.one*pointSpacing/10;
o.name = x + ", " + z;
}
}
}
public void CalcLineOfSight(){
HeightPoint p;
for(int z = 0; z < depth; z++){
for(int x = 0; x < width; x++){
List<Point> haveChecked = new List<Point>();
p = hPoints[x, z];
p.Add(p);
for(int zi = 0; zi < depth; zi++){
for(int xi = 0; xi < width; xi++){
if(zi == z && xi == x){
continue;
}
//check indexes on line to target
List<Point> points = FindIntersectedIndexes(x, z, xi, zi);
//check visibility through each index on line
float maxViewGrad = viewUpHeight;
float minViewGrad = Mathf.NegativeInfinity;
float grad = 0;
for(int i = 0; i < points.Count; i++){
if(points[i].x == x && points[i].y == z){
continue;
}
grad = (hPoints[points[i].x, points[i].y].height - p.height)/(new Vector2(x-points[i].x, z-points[i].y).magnitude);
minViewGrad = Mathf.Max(minViewGrad, grad);
if(minViewGrad > maxViewGrad){
break;
}
if(grad > maxViewGrad){
break;
}
if(grad < minViewGrad){
continue;
}
if(p.visiblePoints.Contains(hPoints[points[i].x, points[i].y])){
continue;
}
p.Add(hPoints[points[i].x, points[i].y]);
}
}
}
}
}
}
List<Point> FindIntersectedIndexes(int y1, int x1, int y2, int x2){
//Implements a variation on Bresenham's line algorithm
List<Point> points = new List<Point>();
int i;
int ystep;
int xstep;
int error;
int errorprev;
int y = y1;
int x = x1;
int ddy, ddx;
int dx = x2 - x1;
int dy = y2 - y1;
points.Add(new Point(y1, x1));
if (dy < 0){
ystep = -1;
dy = -dy;
}else{
ystep = 1;
}
if (dx < 0){
xstep = -1;
dx = -dx;
}else{
xstep = 1;
}
ddy = 2 * dy;
ddx = 2 * dx;
if(ddx >= ddy){
errorprev = error = dx;
for (i=0 ; i < dx ; i++){
x += xstep;
error += ddy;
if (error > ddx){
y += ystep;
error -= ddx;
if (error + errorprev < ddx){
points.Add(new Point(y-ystep, x));
}else if (error + errorprev > ddx){
points.Add(new Point(y, x-xstep));
}else{
points.Add(new Point(y-ystep, x));
points.Add(new Point(y, x-xstep));
}
}
points.Add(new Point(y, x));
errorprev = error;
}
}else{
errorprev = error = dy;
for (i=0 ; i < dy ; i++){
y += ystep;
error += ddx;
if (error > ddy){
x += xstep;
error -= ddy;
if (error + errorprev < ddy){
points.Add(new Point(y, x-xstep));
}else if (error + errorprev > ddy){
points.Add(new Point(y-ystep, x));
}else{
points.Add(new Point(y, x-xstep));
points.Add(new Point(y-ystep, x));
}
}
points.Add(new Point(y, x));
errorprev = error;
}
}
return points;
}
}
public class HeightPoint{
int x;
int y;
float h;
public Vector3 pos;
public List<HeightPoint> visiblePoints = new List<HeightPoint>();
HeightMap hMap;
public HeightPoint(int xi, int yi, Vector3 p, HeightMap container){
pos = p;
h = p.y;
hMap = container;
x = xi;
y = yi;
}
public HeightPoint(int xi, int yi, Vector2 p, float he, HeightMap container){
pos = new Vector3(p.x, h, p.y);
h = he;
hMap = container;
x = xi;
y = yi;
}
public void Add(HeightPoint hP){
visiblePoints.Add(hP);
}
public void DebugVisible(){
foreach(HeightPoint a in visiblePoints){
Debug.Log(a.x + ", " + a.y);
}
}
public float height{
get { return h; }
set { h = value; }
}
}
public class Point{
public int x;
public int y;
public Point(int xi, int yi){
x = xi;
y = yi;
}
}
The each 'HeightPoint' instance should contain a list of the HeightPoint's that it can 'see'
I would not advise anyone to use that code over the former alternative I suggested, but it was an interesting challenge to get working, so enjoy that headache!
Scribe
Wow, thank you so much! This is great! How do I place the height points? Could I do it by creating empty objects? Thank you again!
You could do, at the moment it is just randomized at line 16, normally you would get this data from your map, but you said 'For me so far, gathering the data is the easy part' so I'll leave that up to you or you could post a new question, this is just demonstrating how to check line of sight once you have your data in a 2D float array :)
Your answer
Follow this Question
Related Questions
Player movement on a grid? 1 Answer
How can I Stop grid based movement on One or more access? 0 Answers
Road placement and road removement during run mode 0 Answers
Grid-based movement with auto-move 1 Answer
Collision with grid based movement 0 Answers