/* * Copyright (C) 2006, 2007 Clam <clamisgood@gmail.com> * Copyright (C) 2008, 2009 Quadduc <quadduc@gmail.com> * * This file is part of LateralGM. * LateralGM is free software and comes with ABSOLUTELY NO WARRANTY. * See LICENSE for details. */ package org.lateralgm.resources; import java.awt.image.BufferedImage; import java.util.Arrays; import java.util.Collections; import java.util.EnumMap; import java.util.HashSet; import java.util.List; import org.lateralgm.main.UpdateSource.UpdateEvent; import org.lateralgm.main.UpdateSource.UpdateListener; import org.lateralgm.main.Util; import org.lateralgm.resources.sub.Event; import org.lateralgm.resources.sub.MainEvent; import org.lateralgm.resources.sub.ShapePoint; import org.lateralgm.util.ActiveArrayList; import org.lateralgm.util.PropertyMap; import org.lateralgm.util.PropertyMap.PropertyUpdateEvent; import org.lateralgm.util.PropertyMap.PropertyUpdateListener; import org.lateralgm.util.PropertyMap.PropertyValidationException; public class GmObject extends InstantiableResource<GmObject,GmObject.PGmObject> implements Resource.Viewable,UpdateListener { public static final ResourceReference<GmObject> OBJECT_SELF = new ResourceReference<GmObject>( null); public static final ResourceReference<GmObject> OBJECT_OTHER = new ResourceReference<GmObject>( null); public static int refAsInt(ResourceReference<GmObject> ref) { if (ref == OBJECT_SELF) return -1; if (ref == OBJECT_OTHER) return -2; GmObject obj = Util.deRef(ref); return obj == null ? -100 : obj.getId(); } private final ObjectPropertyListener opl = new ObjectPropertyListener(); private ResourceReference<?> sprite = null; //kept for listening purposes public final List<MainEvent> mainEvents; public final ActiveArrayList<ShapePoint> shapePoints = new ActiveArrayList<ShapePoint>(); public enum PhysicsShape { CIRCLE,BOX,SHAPE } public enum PGmObject { SPRITE,SOLID,VISIBLE,DEPTH,PERSISTENT,PARENT,MASK,PHYSICS_OBJECT,PHYSICS_SENSOR,PHYSICS_SHAPE, PHYSICS_DENSITY,PHYSICS_RESTITUTION,PHYSICS_GROUP,PHYSICS_DAMPING_LINEAR, PHYSICS_DAMPING_ANGULAR,PHYSICS_FRICTION,PHYSICS_AWAKE,PHYSICS_KINEMATIC } private static final EnumMap<PGmObject,Object> DEFS = PropertyMap.makeDefaultMap(PGmObject.class, null,false,true,0,false,null,null,false,false,PhysicsShape.CIRCLE,0.5,0.1,0,0.1,0.1,0.2,true, false); public GmObject() { this(null); } public GmObject(ResourceReference<GmObject> r) { super(r); MainEvent[] e = new MainEvent[12]; for (int j = 0; j < 12; j++) e[j] = new MainEvent(); mainEvents = Collections.unmodifiableList(Arrays.asList(e)); properties.getUpdateSource(PGmObject.SPRITE).addListener(opl); } public GmObject makeInstance(ResourceReference<GmObject> r) { return new GmObject(r); } @Override protected void postCopy(GmObject dest) { super.postCopy(dest); for (int i = 0; i < 12; i++) { MainEvent mev = mainEvents.get(i); MainEvent mev2 = dest.mainEvents.get(i); for (Event ev : mev.events) { mev2.events.add(ev.copy()); } } for (ShapePoint point : shapePoints) { ShapePoint point2 = new ShapePoint(point.getX(),point.getY()); dest.shapePoints.add(point2); } } public BufferedImage getDisplayImage() { ResourceReference<Sprite> r = get(PGmObject.SPRITE); Sprite s = Util.deRef(r); return s == null ? null : s.getDisplayImage(); } public void updated(UpdateEvent e) { reference.updateTrigger.fire(e); } @Override protected PropertyMap<PGmObject> makePropertyMap() { return new PropertyMap<PGmObject>(PGmObject.class,this,DEFS); } private boolean isValidParent(GmObject p) { if (p == this) return false; if (p == null) return true; HashSet<GmObject> traversed = new HashSet<GmObject>(); traversed.add(p); while (true) { ResourceReference<GmObject> r = p.get(PGmObject.PARENT); p = Util.deRef(r); if (p == null) return true; if (p == this || !traversed.add(p)) return false; } } @Override public Object validate(PGmObject k, Object v) { switch (k) { case SPRITE: ResourceReference<?> r = (ResourceReference<?>) v; if (r != null) { Object o = r.get(); if (o == null) r = null; else if (!(o instanceof Sprite)) throw new PropertyValidationException(); } if (sprite != null) sprite.updateSource.removeListener(this); sprite = r; if (sprite != null) sprite.updateSource.addListener(this); break; case PARENT: if (v == null) break; GmObject p = (GmObject) ((ResourceReference<?>) v).get(); if (!isValidParent(p)) throw new ParentLoopException(); default: //TODO: maybe put a failsafe here? break; } return v; } public static class ParentLoopException extends PropertyValidationException { private static final long serialVersionUID = 1L; } private class ObjectPropertyListener extends PropertyUpdateListener<PGmObject> { @Override public void updated(PropertyUpdateEvent<PGmObject> e) { if (e.key == PGmObject.SPRITE) fireUpdate(); } } }