/*******************************************************************************
* Copyright (c) 2013 Philip Collin.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
*
* Contributors:
* Philip Collin - initial API and implementation
******************************************************************************/
package com.lyeeedar.Roguelike3D.Game;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Random;
import com.badlogic.gdx.graphics.Camera;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.math.Matrix4;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.utils.Pools;
import com.lyeeedar.Graphics.ParticleEffects.ParticleEffect;
import com.lyeeedar.Graphics.ParticleEffects.ParticleEmitter;
import com.lyeeedar.Roguelike3D.Game.Level.Level;
import com.lyeeedar.Roguelike3D.Game.Level.Tile;
import com.lyeeedar.Roguelike3D.Graphics.Lights.LightManager;
import com.lyeeedar.Roguelike3D.Graphics.Models.VisibleObject;
import com.lyeeedar.Roguelike3D.Graphics.Renderers.Renderer;
public abstract class GameObject implements Serializable {
private static final long serialVersionUID = 1356577977889288007L;
public static final float PHYSICS_DAMAGE_THRESHHOLD = 2.0f;
public static final float X_ROTATE = -360f/500f;
public static final float Y_ROTATE = -360f/500f;
public static final int MAX_SPEED = 4;
public final String UID;
public final Vector3 position = new Vector3();
public final Vector3 rotation = new Vector3(1, 0, 1);
public final Vector3 velocity = new Vector3();
public final Vector3 up = new Vector3(0, 1, 0);
public float radius;
public VisibleObject vo;
public ParticleEffect particleEffect;
public boolean grounded = true;
public boolean visible = true;
public boolean solid = true;
public String shortDesc = "";
public String longDesc = "";
public transient Random ran;
public transient Vector3 offsetPos;
public transient Vector3 offsetRot;
public GameObject(Color colour, String texture, float x, float y, float z, float scale, int primitive_type, String... model)
{
UID = this.toString()+System.currentTimeMillis()+this.hashCode()+System.nanoTime();
VisibleObject vo = new VisibleObject(primitive_type, colour, texture, scale, model);
this.vo = vo;
position.set(x, y, z);
}
// ----- Movement and rotation ----- //
public void applyMovement(float delta, float vertical_acceleration)
{
if (velocity.len2() == 0) return;
if (velocity.x < -MAX_SPEED) velocity.x = -MAX_SPEED;
if (velocity.x > MAX_SPEED) velocity.x = MAX_SPEED;
if (velocity.y < -MAX_SPEED) velocity.y = -MAX_SPEED;
if (velocity.y > MAX_SPEED) velocity.y = MAX_SPEED;
if (velocity.z < -MAX_SPEED) velocity.z = -MAX_SPEED;
if (velocity.z > MAX_SPEED) velocity.z = MAX_SPEED;
Level lvl = GameData.level;
Vector3 tmp = Pools.obtain(Vector3.class);
Vector3 v = Pools.obtain(Vector3.class).set(velocity.x, (velocity.y - 0.5f*vertical_acceleration*delta), velocity.z);
v.mul(delta*100);
Tile below = lvl.getTile(position.x+v.x, position.z+v.z);
if (below == null) {
velocity.x = 0;
velocity.z = 0;
}
// Check for collision
if (lvl.collideSphereAll(position.x+v.x, position.y+v.y, position.z+v.z, radius, UID))
{
// Collision! Now time to find which axis the collision was on. (Vertical or Horizontal)
// ----- Check Vertical START ----- //
if (lvl.collideSphereActorsAll(position.x, position.y+v.y, position.z, radius, UID) != null ||
lvl.collideSphereLevelObjectsAll(position.x, position.y+v.y, position.z, radius) != null)
{
velocity.y = 0;
grounded = true;
}
// below
else if (position.y+v.y-radius < below.floor) {
velocity.y = 0;
grounded = true;
tmp.set(position.x, below.floor+radius, position.z);
if (!lvl.collideSphereAll(tmp.x, tmp.y, tmp.z, radius, UID))
{
this.positionAbsolutely(tmp.x, tmp.y, tmp.z);
}
}
// above
else if (lvl.hasRoof && position.y+v.y+radius > below.roof) {
velocity.y = 0;
grounded = false;
tmp.set(position.x, below.roof-radius, position.z);
if (!lvl.collideSphereAll(tmp.x, tmp.y, tmp.z, radius, UID))
{
this.positionAbsolutely(tmp.x, tmp.y, tmp.z);
}
}
// No y collision
else
{
this.translate(0, v.y, 0);
grounded = false;
}
// ----- Check Vertical END ----- //
// ----- Check Horizontal START ----- //
if (lvl.collideSphereAll(position.x+v.x, position.y, position.z+v.z, radius, UID)) {
if (lvl.collideSphereAll(position.x+v.x, position.y, position.z, radius, UID)) {
velocity.x = 0;
v.x = 0;
}
if (lvl.collideSphereAll(position.x, position.y, position.z+v.z, radius, UID)) {
velocity.z = 0;
v.z = 0;
}
}
this.translate(v.x, 0, v.z);
// ----- Check Horizontal END ----- //
}
// No collision! So move normally
else
{
this.translate(v.x, v.y, v.z);
grounded = false;
}
if (grounded)
{
velocity.x = 0;
velocity.z = 0;
}
Pools.free(v);
Pools.free(tmp);
}
public abstract void changeTile(Tile src, Tile dst);
public void Yrotate (float angle) {
Vector3 dir = Pools.obtain(Vector3.class);
dir.set(rotation).nor();
if(dir.y>-0.7 && angle<0 || dir.y<+0.7 && angle>0)
{
Vector3 localAxisX = Pools.obtain(Vector3.class).set(rotation);
localAxisX.crs(up).nor();
rotate(localAxisX.x, localAxisX.y, localAxisX.z, angle);
Pools.free(localAxisX);
}
Pools.free(dir);
}
public void Xrotate (float angle) {
rotate(0, 1, 0, angle);
}
public void rotate (float x, float y, float z, float angle) {
Vector3 axis = Pools.obtain(Vector3.class).set(x, y, z);
Matrix4 tmpMat = Pools.obtain(Matrix4.class).idt();
tmpMat.setToRotation(axis, angle);
Pools.free(axis);
rotation.mul(tmpMat).nor();
up.mul(tmpMat).nor();
Pools.free(tmpMat);
if (vo.attributes != null) {
Vector3 lookAt = Pools.obtain(Vector3.class).set(0, 0, 0).add(rotation);
vo.attributes.getRotation().setToLookAt(lookAt, up).inv();
Pools.free(lookAt);
}
}
public void translate(float x, float y, float z)
{
positionAbsolutely(position.x+x, position.y+y, position.z+z);
}
public void positionAbsolutely(float x, float y, float z)
{
Tile start = GameData.level.getTile(position.x, position.z);
position.set(x, y, z);
Tile end = GameData.level.getTile(position.x, position.z);
if (!start.equals(end))
{
changeTile(start, end);
}
if (vo.attributes != null) vo.attributes.position.setToTranslation(position);
if (particleEffect != null) particleEffect.setPosition(vo.attributes.getSortCenter());
}
public void positionYAbsolutely(float y)
{
positionAbsolutely(position.x, y, position.z);
}
public void left_right(float mag)
{
velocity.x += (float)Math.sin(rotation.z) * mag;
velocity.z += -(float)Math.sin(rotation.x) * mag;
}
public void forward_backward(float mag)
{
velocity.x += (float)Math.sin(rotation.x) * mag;
velocity.z += (float)Math.sin(rotation.z) * mag;
}
// ----- Rendering and Updating ----- //
public void render(Renderer renderer, ArrayList<ParticleEmitter> emitters, Camera cam)
{
if (particleEffect != null)
{
particleEffect.getVisibleEmitters(emitters, cam);
}
if (visible) vo.render(renderer);
rendered(renderer, emitters, cam);
}
protected abstract void rendered(Renderer renderer, ArrayList<ParticleEmitter> emitters, Camera cam);
public abstract void update(float delta, Camera cam);
public abstract void activate();
public abstract String getActivatePrompt();
// ----- Creation and Destruction ----- //
public void getLight(LightManager lightManager)
{
if (particleEffect != null) particleEffect.getLight(lightManager);
}
public void addParticleEffect(ParticleEffect effect)
{
if (particleEffect != null)
{
particleEffect.dispose();
particleEffect.delete();
}
this.particleEffect = effect;
}
public void create()
{
ran = new Random();
offsetPos = Pools.obtain(Vector3.class).set(0, 0, 0);
offsetRot = Pools.obtain(Vector3.class).set(0, 0, 0);
vo.create();
radius = vo.attributes.radius;
if (particleEffect != null) {
particleEffect.setPosition(position);
particleEffect.create();
}
created();
}
protected abstract void created();
public void dispose()
{
Pools.free(offsetPos);
offsetPos = null;
Pools.free(offsetRot);
offsetRot = null;
vo.dispose();
if (particleEffect != null) {
particleEffect.dispose();
}
disposed();
}
protected abstract void disposed();
public void bakeLights(LightManager lightManager, boolean bakeStatics)
{
vo.bakeLights(lightManager, bakeStatics);
}
public abstract void fixReferences();
// ----- Getters ----- //
public Matrix4 getTransform()
{
return vo.attributes.position;
}
public Matrix4 getRotationMatrix()
{
return vo.attributes.rotation;
}
public Vector3 getBoundingBox()
{
return vo.attributes.box;
}
}