/** * Copyright 2008 - 2012 * * 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. * * @project loon * @author cping * @email:javachenpeng@yahoo.com * @version 0.3.3 */ package loon.action.collision; import java.util.ArrayList; import loon.LSystem; import loon.action.ActionBind; import loon.core.LRelease; import loon.utils.MathUtils; public class GravityHandler implements LRelease { public static interface GravityUpdate { public void action(Gravity g, float x, float y); } private GravityUpdate listener; private int width, height; private int bindWidth; private int bindHeight; private float bindX; private float bindY; private float velocityX, velocityY; boolean isBounded; boolean isListener; boolean isEnabled; Gravity[] lazyObjects; ArrayList<Gravity> objects; ArrayList<Gravity> pendingAdd; ArrayList<Gravity> pendingRemove; public GravityHandler() { this(LSystem.screenRect.width, LSystem.screenRect.height); } public GravityHandler(int w, int h) { this.setLimit(w, h); this.objects = new ArrayList<Gravity>(10); this.pendingAdd = new ArrayList<Gravity>(10); this.pendingRemove = new ArrayList<Gravity>(10); this.lazyObjects = new Gravity[] {}; this.isEnabled = true; } public boolean isGravityRunning() { if (objects != null) { for (Gravity g : objects) { if (g != null && !g.enabled) { return true; } } } return false; } public void setLimit(int w, int h) { this.width = w; this.height = h; } public void update(long elapsedTime) { if (!isEnabled) { return; } commits(); final float second = elapsedTime / 1000f; for (Gravity g : lazyObjects) { if (g.enabled && g.bind != null) { final float accelerationX = g.accelerationX; final float accelerationY = g.accelerationY; final float angularVelocity = g.angularVelocity; bindWidth = g.bind.getWidth(); bindHeight = g.bind.getHeight(); bindX = g.bind.getX(); bindY = g.bind.getY(); if (angularVelocity != 0) { final float rotate = g.bind.getRotation() + angularVelocity * second; int[] newObjectRect = MathUtils.getLimit(bindX, bindY, bindWidth, bindHeight, rotate); bindWidth = newObjectRect[2]; bindHeight = newObjectRect[3]; newObjectRect = null; g.bind.setRotation(rotate); } if (accelerationX != 0 || accelerationY != 0) { g.velocityX += accelerationX * second; g.velocityY += accelerationY * second; } velocityX = g.velocityX; velocityY = g.velocityY; if (velocityX != 0 || velocityY != 0) { velocityX = bindX + velocityX * second; velocityY = bindY + velocityY * second; if (isBounded) { if (g.g != 0) { velocityY += g.gadd; g.gadd += g.g; } if (g.bounce != 0) { final int limitWidth = width - bindWidth; final int limitHeight = height - bindHeight; final boolean chageWidth = bindX >= limitWidth; final boolean chageHeight = bindY >= limitHeight; if (chageWidth) { bindX -= g.bounce + g.g; if (g.bounce > 0) { g.bounce -= (g.bounce / MathUtils.random( 1, 5)) + second; } else if (g.bounce < 0) { g.bounce = 0; bindX = limitWidth; } } if (chageHeight) { bindY -= g.bounce + g.g; if (g.bounce > 0) { g.bounce -= (g.bounce / MathUtils.random( 1, 5)) + second; } else if (g.bounce < 0) { g.bounce = 0; bindY = limitHeight; } } if (chageWidth || chageHeight) { g.bind.setLocation(bindX, bindY); if (isListener) { listener.action(g, bindX, bindY); } return; } } velocityX = limitValue(velocityX, width - bindWidth); velocityY = limitValue(velocityY, height - bindHeight); } g.bind.setLocation(velocityX, velocityY); if (isListener) { listener.action(g, velocityX, velocityY); } } } } } private float limitValue(float value, float limit) { if (value < 0) { value = 0; } if (limit < value) { value = limit; } return value; } public void commits() { boolean changes = false; final int additionCount = pendingAdd.size(); if (additionCount > 0) { final Object[] additionsArray = pendingAdd.toArray(); for (int i = 0; i < additionCount; i++) { Gravity object = (Gravity) additionsArray[i]; objects.add(object); } pendingAdd.clear(); changes = true; } final int removalCount = pendingRemove.size(); if (removalCount > 0) { final Object[] removalsArray = pendingRemove.toArray(); for (int i = 0; i < removalCount; i++) { Gravity object = (Gravity) removalsArray[i]; objects.remove(object); } pendingRemove.clear(); changes = true; } if (changes) { lazyObjects = objects.toArray(new Gravity[] {}); } } public Gravity[] getObjects() { return lazyObjects; } public int getCount() { return lazyObjects.length; } public int getConcreteCount() { return lazyObjects.length + pendingAdd.size() - pendingRemove.size(); } public Gravity get(int index) { return lazyObjects[index]; } public Gravity add(ActionBind o, float vx, float vy) { return add(o, vx, vy, 0); } public Gravity add(ActionBind o, float vx, float vy, float ave) { return add(o, vx, vy, 0, 0, ave); } public Gravity add(ActionBind o, float vx, float vy, float ax, float ay, float ave) { Gravity g = new Gravity(o); g.velocityX = vx; g.velocityY = vy; g.accelerationX = ax; g.accelerationY = ay; g.angularVelocity = ave; add(g); return g; } public void add(Gravity object) { pendingAdd.add(object); } public void remove(Gravity object) { pendingRemove.add(object); } public void removeAll() { final int count = objects.size(); final Object[] objectArray = objects.toArray(); for (int i = 0; i < count; i++) { pendingRemove.add((Gravity) objectArray[i]); } pendingAdd.clear(); } public Gravity getObject(String name) { commits(); for (Gravity object : lazyObjects) { if (object != null) { if (object.name != null) { if (object.name.equals(name)) { return object; } } } } return null; } public boolean isEnabled() { return isEnabled; } public void setEnabled(boolean isEnabled) { this.isEnabled = isEnabled; } public boolean isBounded() { return isBounded; } public void setBounded(boolean isBounded) { this.isBounded = isBounded; } public boolean isListener() { return isListener; } public void onUpdate(GravityUpdate listener) { this.listener = listener; if (listener != null) { isListener = true; } else { isListener = false; } } @Override public void dispose() { this.isEnabled = false; if (objects != null) { objects.clear(); objects = null; } if (pendingAdd != null) { pendingAdd.clear(); pendingAdd = null; } if (pendingAdd != null) { pendingAdd.clear(); pendingAdd = null; } if (lazyObjects != null) { for (Gravity g : lazyObjects) { if (g != null) { g.dispose(); g = null; } } } } }