@@ -0,0 +1,90 @@
/*******************************************************************************
* Copyright 2015 Maximilian Stark | Dakror <mail@dakror.de>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/

package de.dakror.wargame;

/**
* @author Maximilian Stark | Dakror
*
*/
public class Unit extends Entity {
public static enum AttackKind {
Machine_Gun,
Handgun,
Rocket,
Arc_Missile,
Cannon,
Long_Cannon,
Bomb,
Torpedo
}

public static enum Type implements EntityLifeCycle {
Infantry(20, 35, false, AttackKind.Machine_Gun, null, 1, 0, null),

;

public final int hp, costs;
public final boolean superAvailable;
public final AttackKind weapon0, weapon1;
public final int receiveStrength0, receiveStrength1;
public final String alias;

private Type(int hp, int costs, boolean superAvailable, AttackKind weapon0, AttackKind weapon1, int receiveStrength0, int receiveStrength1, String alias) {
this.hp = hp;
this.costs = costs;
this.superAvailable = superAvailable;
this.weapon0 = weapon0;
this.weapon1 = weapon1;
this.receiveStrength0 = receiveStrength0;
this.receiveStrength1 = receiveStrength1;
this.alias = alias;
}

@Override
public void onCreate() {}

@Override
public void onSpawn() {}

@Override
public void update(float timePassed) {}

@Override
public void onDeath() {}

@Override
public void onRemoval() {}

}

public Unit(int x, int y, int z, int face, int color, String name) {
super(x, y, z, face, color, false, name);
}

@Override
public void onCreate() {}

@Override
public void onSpawn() {}

@Override
public void onDeath() {}

@Override
public void onRemoval() {}

}
@@ -37,65 +37,20 @@
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;
import android.view.View.OnTouchListener;
import de.dakror.wargame.Building.Type;

/**
* @author Maximilian Stark | Dakror
*/
public class MainActivity extends Activity {
GLSurfaceView glView;
WargameRenderer renderer;
public static MainActivity instance;

public static int width, height;
public static TextureAtlas terrain, standing, animation;

float prevX, prevY, prevNum;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

instance = this;
renderer = new WargameRenderer();
glView = new GLSurfaceView(this);
glView.setEGLContextClientVersion(2);
glView.setRenderer(renderer);
glView.setOnTouchListener(renderer);
renderer.gestureDetector = new ScaleGestureDetector(this, renderer);
setContentView(glView);
}

@TargetApi(Build.VERSION_CODES.KITKAT)
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (hasFocus) {
glView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY | View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
}
}

@Override
protected void onResume() {
// Ideally a game should implement onResume() and onPause()
// to take appropriate action when the activity looses focus
super.onResume();
glView.onResume();
}

@Override
protected void onPause() {
// Ideally a game should implement onResume() and onPause()
// to take appropriate action when the activity looses focus
super.onPause();
glView.onPause();
}

public class WargameRenderer implements GLSurfaceView.Renderer, OnTouchListener, ScaleGestureDetector.OnScaleGestureListener {
ScaleGestureDetector gestureDetector;
public class Wargame extends Activity {
public class WargameRenderer implements GLSurfaceView.Renderer, OnTouchListener, GestureDetector.OnGestureListener, ScaleGestureDetector.OnScaleGestureListener {
GestureDetector gestureDetector;
ScaleGestureDetector scaleGestureDetector;

SpriteRenderer spriteRenderer;
TextRenderer textRenderer;
@@ -105,15 +60,20 @@ public class WargameRenderer implements GLSurfaceView.Renderer, OnTouchListener,
long lastTimestamp;
long lastFrame;

float scale = 1;
float scale = 5;
float ratio;

float prevX, prevY, prevNum;

float vX, vY;

World map;

@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouch(View v, MotionEvent e) {
gestureDetector.onTouchEvent(e);
scaleGestureDetector.onTouchEvent(e);
float x = e.getX();
float y = e.getY();

@@ -150,15 +110,20 @@ public void onSurfaceCreated(GL10 gl10, EGLConfig config) {

map = new World("maps/lake.map");

map.addEntity(new Building(0, 1, 0, true, Building.Type.Dock));

Building b = new Building(5, 2, 7, 0, Type.City);
map.addEntity(b);
map.center(b);
// for (int i = 0; i < 8; i++)
// for (Type t : Type.values())
// map.addEntity(new Building(t.ordinal(), 2, i * 2, i, t));
//
glClearColor(130 / 255f, 236 / 255f, 255 / 255f, 1);
}

@Override
public void onSurfaceChanged(GL10 gl10, int width, int height) {
MainActivity.width = width;
MainActivity.height = height;
Wargame.width = width;
Wargame.height = height;
glViewport(0, 0, width, height);
ratio = (float) width / height;
// System.out.println("ratio: " + ratio);
@@ -212,6 +177,7 @@ public void onDrawFrame(GL10 gl) {
@Override
public boolean onScale(ScaleGestureDetector detector) {
scale *= detector.getScaleFactor();
scale = Math.min(15, Math.max(0.3f, scale));
return true;
}

@@ -222,6 +188,80 @@ public boolean onScaleBegin(ScaleGestureDetector detector) {

@Override
public void onScaleEnd(ScaleGestureDetector detector) {}

@Override
public boolean onDown(MotionEvent e) {
return false;
}

@Override
public void onShowPress(MotionEvent e) {}

@Override
public boolean onSingleTapUp(MotionEvent e) {
System.out.println(e);
return false;
}

@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
return false;
}

@Override
public void onLongPress(MotionEvent e) {}

@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
return false;
}
}

GLSurfaceView glView;
WargameRenderer renderer;
public static Wargame instance;

public static int width, height;
public static TextureAtlas terrain, standing, animation;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

instance = this;
renderer = new WargameRenderer();
glView = new GLSurfaceView(this);
glView.setEGLContextClientVersion(2);
glView.setRenderer(renderer);
glView.setOnTouchListener(renderer);
renderer.gestureDetector = new GestureDetector(this, renderer);
renderer.scaleGestureDetector = new ScaleGestureDetector(this, renderer);
setContentView(glView);
}

@TargetApi(Build.VERSION_CODES.KITKAT)
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (hasFocus) {
glView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY | View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
}
}

@Override
protected void onResume() {
// Ideally a game should implement onResume() and onPause()
// to take appropriate action when the activity looses focus
super.onResume();
glView.onResume();
}

@Override
protected void onPause() {
// Ideally a game should implement onResume() and onPause()
// to take appropriate action when the activity looses focus
super.onPause();
glView.onPause();
}

public int createProgram(String vertexShaderFile, String fragmentShaderFile) {
@@ -281,6 +321,18 @@ public int loadTexture(String textureFile, int filterMin, int filterMag) {
return id[0];
}

public static String read(InputStream is) throws IOException {
StringBuilder content = new StringBuilder();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String line = "";
while ((line = br.readLine()) != null) {
content.append(line);
content.append("\r\n");
}
br.close();
return content.toString();
}

public static void printMatrix(float[] m) {
int len = 8;
for (int i = 0; i < 4; i++) {
@@ -294,16 +346,4 @@ static String l(float f, int len) {
s = f % 1 == 0 ? " " + s : s + "0";
return s;
}

public static String read(InputStream is) throws IOException {
StringBuilder content = new StringBuilder();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String line = "";
while ((line = br.readLine()) != null) {
content.append(line);
content.append("\r\n");
}
br.close();
return content.toString();
}
}
@@ -29,8 +29,23 @@
* @author Maximilian Stark | Dakror
*/
public class World {
public static enum Types {
Air, Basement, Custom0, Custom1, Custom2, Desert, Forest, Hills, Jungle, Mountains, Plains, River, Road, Ruins, Sea, Tundra // 16
public static enum Type {
Air,
Basement,
Custom0,
Custom1,
Custom2,
Desert,
Forest,
Hills,
Jungle,
Mountains,
Plains,
River,
Road,
Ruins,
Sea,
Tundra // 16
}

public static enum Directions {
@@ -59,7 +74,7 @@ public static enum Directions {
protected Vector pos, newPos;

public static final float WIDTH = 129f;
public static final float HEIGHT = 19f;
public static final float HEIGHT = 18f;
public static final float DEPTH = 64f;

public boolean dirty = true;
@@ -88,7 +103,7 @@ public World(int width, int height, int depth) {

void parse(String worldFile) {
try {
BufferedReader br = new BufferedReader(new InputStreamReader(MainActivity.instance.getAssets().open(worldFile)));
BufferedReader br = new BufferedReader(new InputStreamReader(Wargame.instance.getAssets().open(worldFile)));

String line = "";
int y = 0;
@@ -109,7 +124,7 @@ void parse(String worldFile) {
for (int i = 0; i < width; i++) {
String s = line.substring(i, i + 1);
if (s.equals(" ")) s = "0";
set(i, y, z, Types.values()[Integer.valueOf(s, 16)]);
set(i, y, z, Type.values()[Integer.valueOf(s, 16)]);
}
z--;
}
@@ -123,7 +138,7 @@ void parse(String worldFile) {
}

void generate() {
Types[] t = { Types.Desert, Types.Forest, Types.Mountains, Types.River, Types.Tundra };
Type[] t = { Type.Desert, Type.Forest, Type.Mountains, Type.River, Type.Tundra };
for (int i = 0; i < width; i++)
for (int j = 0; j < depth; j++)
set(i, 0, j, t[(int) (Math.random() * t.length)]);//, i == width - 1, j == 0, i == 0, j == depth - 1);
@@ -169,11 +184,20 @@ void init() {
// glBindFramebuffer(GL_FRAMEBUFFER, 0);
}

public void center(Entity e) {
center(e.getRealX() + (e.getWidth() / WIDTH) * 2, e.getRealY(), e.getRealZ());
}

public void center(float x, float y, float z) {
newPos.x = -(x * WIDTH / 2 + z * WIDTH / 2) / 2;
newPos.y = -(y * HEIGHT - x * DEPTH / 2 + z * DEPTH / 2);
}

public boolean isInBounds(int x, int y, int z) {
return x >= 0 && x < width && y >= 0 && y < height && z >= 0 && z < depth;
}

public boolean set(int x, int y, int z, Types type) {
public boolean set(int x, int y, int z, Type type) {
if (!isInBounds(x, y, z)) return false;
byte oldVal = map[y][x][z];
map[y][x][z] = (byte) (map[y][x][z] >> 4 << 4 | type.ordinal());
@@ -188,7 +212,7 @@ public boolean set(int x, int y, int z, Directions d, boolean set) {
return oldVal != map[y][x][z];
}

public boolean set(int x, int y, int z, Types type, boolean se, boolean sw, boolean nw, boolean ne) {
public boolean set(int x, int y, int z, Type type, boolean se, boolean sw, boolean nw, boolean ne) {
if (!isInBounds(x, y, z)) return false;
byte oldVal = map[y][x][z];
map[y][x][z] = (byte) (type.ordinal() | (se ? 1 : 0) << 7 | (sw ? 1 : 0) << 6 | (nw ? 1 : 0) << 5 | (ne ? 1 : 0) << 4);
@@ -199,22 +223,22 @@ public void updateDirections() {
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
for (int k = 0; k < depth; k++) {
Types t = get(j, i, k);
boolean solid = t != Types.River || t != Types.Sea || t != Types.Air;
boolean sky = get(j, i + 1, k) == Types.Air;
Type t = get(j, i, k);
boolean solid = t != Type.River || t != Type.Sea || t != Type.Air;
boolean sky = get(j, i + 1, k) == Type.Air;

set(j, i, k, Directions.SE, (j == width - 1 || get(j + 1, i, k) == Types.Air) && solid && sky);
set(j, i, k, Directions.SW, (k == 0 || get(j, i, k - 1) == Types.Air) && solid && sky);
set(j, i, k, Directions.NW, (j == 0 || get(j - 1, i, k) == Types.Air) && solid && sky);
set(j, i, k, Directions.NE, (k == depth - 1 || get(j, i, k + 1) == Types.Air) && solid && sky);
set(j, i, k, Directions.SE, (j == width - 1 || get(j + 1, i, k) == Type.Air) && solid && sky);
set(j, i, k, Directions.SW, (k == 0 || get(j, i, k - 1) == Type.Air) && solid && sky);
set(j, i, k, Directions.NW, (j == 0 || get(j - 1, i, k) == Type.Air) && solid && sky);
set(j, i, k, Directions.NE, (k == depth - 1 || get(j, i, k + 1) == Type.Air) && solid && sky);
}
}
}
}

public Types get(int x, int y, int z) {
if (!isInBounds(x, y, z)) return Types.Air;
return Types.values()[map[y][x][z] & 0xf];
public Type get(int x, int y, int z) {
if (!isInBounds(x, y, z)) return Type.Air;
return Type.values()[map[y][x][z] & 0xf];
}

public boolean is(int x, int y, int z, Directions d) {
@@ -236,14 +260,16 @@ public String getFile(int x, int y, int z) {
public void update(float timePassed) {
for (Iterator<Entity> iter = entities.iterator(); iter.hasNext();) {
Entity e = iter.next();
if (e.isDead()) iter.remove();
else e.update(timePassed);
if (e.isDead()) {
e.onRemoval();
iter.remove();
} else e.update(timePassed);
}
}

public void render(SpriteRenderer r) {
float ratio = MainActivity.instance.renderer.ratio;
float scale = 1 / 1024f * MainActivity.instance.renderer.scale;
float ratio = Wargame.instance.renderer.ratio;
float scale = 1 / 1024f * Wargame.instance.renderer.scale;
int rendered = 0, all = 0, rEntities = 0;

// if (dirty) {
@@ -266,13 +292,13 @@ public void render(SpriteRenderer r) {
for (int x = 0; x < width; x++) {
for (int z = 0; z < depth; z++) {
for (int y = 0; y < height; y++) {
Tile t = MainActivity.terrain.getTile(getFile(x, y, z));
Tile t = Wargame.terrain.getTile(getFile(x, y, z));
if (t == null) continue;
TextureRegion tr = t.regions.get(0);
float x1 = pos.x + x * WIDTH / 2 + z * WIDTH / 2;
float y1 = pos.y + y * HEIGHT - x * DEPTH / 2 + z * DEPTH / 2;

if (get(x, y + 1, z) == Types.Air || get(x + 1, y, z) == Types.Air || get(x, y, z - 1) == Types.Air) {
if (get(x, y + 1, z) == Type.Air || get(x + 1, y, z) == Type.Air || get(x, y, z - 1) == Type.Air) {
if ((x1 + tr.width * 2048) * scale >= -ratio && x1 * scale <= ratio && y1 * scale <= 1 && (y1 + tr.width * 2048) * scale >= -1) {
r.render(x1, y1, pos.z + y * HEIGHT + x * DEPTH / 2, tr.width * 2048, tr.height * 2048, tr.x, tr.y, tr.width, tr.height, 8, tr.texture.textureId);
rendered++;
@@ -352,6 +378,7 @@ public void render(SpriteRenderer r) {
public void addEntity(Entity e) {
e.setWorld(this);
entities.add(e);
e.onSpawn();
}

public void move(float x, float y) {