/*
* Copyright (C) 2016 Google Inc. All Rights Reserved.
*
* 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 com.google.android.apps.santatracker.games.simpleengine.game;
import com.google.android.apps.santatracker.games.simpleengine.Renderer;
import android.graphics.RectF;
import java.util.ArrayList;
public final class World {
// renderer
Renderer mRenderer;
public ArrayList<GameObject> gameObjects = new ArrayList<GameObject>();
// recycle bin of objects for reuse
private ArrayList<GameObject> mRecycleBin = new ArrayList<GameObject>(64);
public World(Renderer r) {
mRenderer = r;
}
private GameObject newGameObject(int type, float x, float y, boolean createSprite,
int texIndex, int color, float tintFactor, float spriteWidth, float spriteHeight) {
GameObject o;
if (mRecycleBin.isEmpty()) {
o = new GameObject(this);
} else {
o = mRecycleBin.remove(mRecycleBin.size() - 1);
}
o.x = x;
o.y = y;
o.type = type;
if (createSprite) {
Renderer.Sprite s = o.getSprite(o.addSprite());
s.texIndex = texIndex;
s.tintFactor = tintFactor;
s.color = color;
s.width = spriteWidth;
s.height = spriteHeight;
}
gameObjects.add(o);
return o;
}
public GameObject newGameObject(int type, float x, float y) {
return newGameObject(type, x, y, false, -1, 0, 0.0f, 0.0f, 0.0f);
}
public GameObject newGameObjectWithImage(int type, float x, float y,
int texIndex, float spriteWidth, float spriteHeight) {
return newGameObject(type, x, y, true, texIndex, 0, 0.0f, spriteWidth, spriteHeight);
}
public GameObject newGameObjectWithColor(int type, float x, float y, int color,
float spriteWidth, float spriteHeight) {
return newGameObject(type, x, y, true, -1, color, 1.0f, spriteWidth, spriteHeight);
}
public void doFrame(float deltaT) {
int i;
// we iterate backwards so that the iteration is not affected by things
// getting added as part of the update process
for (i = gameObjects.size() - 1; i >= 0; --i) {
gameObjects.get(i).update(deltaT);
}
// remove dead objects
for (i = gameObjects.size() - 1; i >= 0; --i) {
if (gameObjects.get(i).dead) {
// more efficient than remove() because this doesn't cause
// the whole array to shift. In other words, remove() is O(n),
// this method is O(1):
GameObject deleted = gameObjects.get(i);
int last = gameObjects.size() - 1;
gameObjects.set(i, gameObjects.get(last));
gameObjects.remove(last);
// recycle it!
deleted.clear();
mRecycleBin.add(deleted);
}
}
}
public boolean detectCollisions(GameObject object,
ArrayList<GameObject> result, boolean clear) {
int i;
boolean found = false;
if (clear) {
result.clear();
}
if (object.dead || !object.collides) {
return false;
}
for (i = 0; i < gameObjects.size(); i++) {
GameObject o = gameObjects.get(i);
if (!o.dead && o != object && o.collides && objectsCollide(object, o)) {
found = true;
result.add(o);
}
}
return found;
}
RectF mRect1 = new RectF();
RectF mRect2 = new RectF();
private boolean objectsCollide(GameObject a, GameObject b) {
if (a.dead || b.dead || !a.collides || !b.collides) {
return false;
}
getColliderBounds(a, mRect1);
getColliderBounds(b, mRect2);
return mRect1.intersect(mRect2);
}
private void getColliderBounds(GameObject obj, RectF result) {
result.left = obj.x - obj.collBoxWidth * 0.5f;
result.right = obj.x + obj.collBoxWidth * 0.5f;
result.top = obj.y - obj.collBoxHeight * 0.5f;
result.bottom = obj.y + obj.collBoxHeight * 0.5f;
}
public Renderer getRenderer() {
return mRenderer;
}
}