├── ashley ├── .gitignore ├── src │ └── com │ │ └── badlogic │ │ ├── ashley_gwt.gwt.xml │ │ └── ashley │ │ ├── core │ │ ├── Component.java │ │ ├── EntityListener.java │ │ ├── ComponentMapper.java │ │ ├── SystemManager.java │ │ ├── ComponentOperationHandler.java │ │ ├── EntitySystem.java │ │ ├── ComponentType.java │ │ ├── EntityManager.java │ │ ├── FamilyManager.java │ │ ├── Family.java │ │ ├── PooledEngine.java │ │ └── Entity.java │ │ ├── signals │ │ ├── Listener.java │ │ └── Signal.java │ │ ├── systems │ │ ├── IntervalSystem.java │ │ ├── IntervalIteratingSystem.java │ │ ├── IteratingSystem.java │ │ └── SortedIteratingSystem.java │ │ └── utils │ │ ├── ImmutableArray.java │ │ └── Bag.java ├── build.gradle └── tests │ └── com │ └── badlogic │ └── ashley │ ├── utils │ ├── BagTest.java │ └── ImmutableArrayTests.java │ ├── systems │ ├── IntervalSystemTest.java │ ├── IntervalIteratingTest.java │ └── IteratingSystemTest.java │ ├── core │ ├── ComponentTypeTests.java │ ├── ComponentClassFactory.java │ ├── ComponentOperationHandlerTests.java │ ├── EntityManagerTests.java │ ├── SystemManagerTests.java │ ├── EntityTests.java │ └── EntityListenerTests.java │ └── signals │ └── SignalTests.java ├── tests ├── .gitignore ├── assets │ ├── coin.png │ └── crate.png ├── build.gradle └── src │ └── com │ └── badlogic │ └── ashley │ └── tests │ ├── components │ ├── CameraComponent.java │ ├── PositionComponent.java │ ├── VisualComponent.java │ └── MovementComponent.java │ ├── SignalTest.java │ ├── SystemPriorityTest.java │ ├── utils │ └── Timer.java │ ├── systems │ ├── MovementSystem.java │ └── RenderSystem.java │ ├── IgnoreSystemTest.java │ ├── SpeedTest.java │ ├── RenderSystemTest.java │ └── BasicTest.java ├── logo.png ├── settings.gradle ├── .github ├── CODEOWNERS └── workflows │ ├── publish_snapshot.yml │ ├── compile.yml │ └── publish_release.yml ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── benchmarks ├── libs │ ├── junit-benchmarks-0.7.2.jar │ └── artemis-a609b2076aacc0ef5ecf0b390205d01bb88ceae2.jar ├── build.gradle └── src │ └── main │ └── java │ └── com │ └── badlogic │ └── ashley │ └── benchmark │ ├── artemis │ ├── components │ │ ├── RemovalComponent.java │ │ ├── RadiusComponent.java │ │ ├── MovementComponent.java │ │ ├── StateComponent.java │ │ └── PositionComponent.java │ ├── systems │ │ ├── RemovalSystem.java │ │ ├── CollisionSystem.java │ │ ├── StateSystem.java │ │ └── MovementSystem.java │ └── ArtemisBenchmark.java │ ├── ashley │ ├── components │ │ ├── RemovalComponent.java │ │ ├── RadiusComponent.java │ │ ├── MovementComponent.java │ │ ├── StateComponent.java │ │ └── PositionComponent.java │ ├── systems │ │ ├── CollisionSystem.java │ │ ├── StateSystem.java │ │ ├── RemovalSystem.java │ │ └── MovementSystem.java │ └── AshleyBenchmark.java │ └── Constants.java ├── NOTICE ├── .gitignore ├── RELEASE.md ├── AUTHORS ├── gradlew.bat ├── README.md ├── publish.gradle └── gradlew /ashley/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /tests/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libgdx/ashley/HEAD/logo.png -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include 'ashley', 'tests', 'benchmarks' 2 | 3 | -------------------------------------------------------------------------------- /tests/assets/coin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libgdx/ashley/HEAD/tests/assets/coin.png -------------------------------------------------------------------------------- /tests/assets/crate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libgdx/ashley/HEAD/tests/assets/crate.png -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | /.github/workflows/ @libgdx/libgdx-signing 2 | /.github/CODEOWNERS @libgdx/libgdx-signing 3 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libgdx/ashley/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /benchmarks/libs/junit-benchmarks-0.7.2.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libgdx/ashley/HEAD/benchmarks/libs/junit-benchmarks-0.7.2.jar -------------------------------------------------------------------------------- /benchmarks/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: "java" 2 | sourceCompatibility = 1.7 3 | 4 | eclipse.project { 5 | name = "ecs-benchmarks" 6 | } 7 | 8 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | Ashley 2 | Copyright 2013 Stefan Bachmann 3 | 4 | This software contains code derived from Ash (http://www.ashframework.org/) and Artemis (http://gamadu.com/artemis/). -------------------------------------------------------------------------------- /benchmarks/libs/artemis-a609b2076aacc0ef5ecf0b390205d01bb88ceae2.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libgdx/ashley/HEAD/benchmarks/libs/artemis-a609b2076aacc0ef5ecf0b390205d01bb88ceae2.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Sat Sep 21 13:08:26 CEST 2013 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-all.zip 7 | -------------------------------------------------------------------------------- /ashley/src/com/badlogic/ashley_gwt.gwt.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /tests/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: "java" 2 | sourceCompatibility = 1.7 3 | 4 | sourceSets.main.java.srcDirs = [ "src/" ] 5 | sourceSets.main.resources.srcDirs = [ "src/" ] 6 | sourceSets.test.java.srcDirs = [ "tests/" ] 7 | sourceSets.test.resources.srcDirs = [ "tests/" ] 8 | 9 | eclipse.project { 10 | name = projectGroup + "-tests" 11 | } 12 | 13 | -------------------------------------------------------------------------------- /ashley/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: "java" 2 | sourceCompatibility = 1.7 3 | 4 | sourceSets.main.java.srcDirs = [ "src/" ] 5 | sourceSets.main.resources.srcDirs = [ "src/" ] 6 | sourceSets.test.java.srcDirs = [ "tests/" ] 7 | sourceSets.test.resources.srcDirs = [ "tests/" ] 8 | 9 | javadoc { 10 | title = 'Ashley Entity System API' 11 | } 12 | 13 | eclipse.project { 14 | name = projectGroup + "-core" 15 | } 16 | 17 | -------------------------------------------------------------------------------- /ashley/tests/com/badlogic/ashley/utils/BagTest.java: -------------------------------------------------------------------------------- 1 | package com.badlogic.ashley.utils; 2 | 3 | import org.junit.Assert; 4 | import org.junit.Test; 5 | 6 | public class BagTest { 7 | 8 | @Test 9 | public void testSet(){ 10 | final Bag bag = new Bag(); 11 | bag.add("a"); 12 | bag.add("b"); 13 | bag.add("c"); 14 | Assert.assertEquals(3, bag.size()); 15 | 16 | bag.set(1, "d"); 17 | Assert.assertEquals(3, bag.size()); 18 | Assert.assertEquals("d", bag.get(1)); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Temporary Files 2 | *~ 3 | .*.swp 4 | .DS_STORE 5 | *.mdb 6 | # per project ignores, it's cumbersome, but reduces the risk of missing something 7 | 8 | # Gradle 9 | .gradle 10 | build/ 11 | dist/ 12 | 13 | # Intellij 14 | .idea/ 15 | *.ipr 16 | *.iws 17 | *.iml 18 | out/ 19 | com_crashlytics_export_strings.xml 20 | 21 | # Eclipse 22 | .classpath 23 | .project 24 | .metadata 25 | **/bin/ 26 | tmp/ 27 | *.tmp 28 | *.bak 29 | *.swp 30 | *~.nib 31 | local.properties 32 | .settings/ 33 | .loadpath 34 | .externalToolBuilders/ 35 | *.launch -------------------------------------------------------------------------------- /RELEASE.md: -------------------------------------------------------------------------------- 1 | Release steps for Ashley: 2 | 3 | 1. Make sure [`publish.gradle`](https://github.com/libgdx/ashley/blob/master/publish.gradle) has the correct version. API breaking releases cannot just increase the patch version. 4 | 2. Create [tag](https://github.com/libgdx/ashley/releases) with the new version. 5 | 3. Run release script and publish on Maven. 6 | 4. Increase patch version for the next release. 7 | 5. [Blog post](http://saltares.com/blog/projects/ashley-1-7-0-released/) with changes. 8 | 6. Update Ashley version on [gdx-setup](https://github.com/libgdx/libgdx/blob/master/extensions/gdx-setup/src/com/badlogic/gdx/setup/DependencyBank.java). -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | # This is the official list of the AUTHORS of Ashley 2 | # Names should be added to this file as 3 | # Name or Organization 4 | # The email address is not required for organizations. 5 | 6 | Stefan Bachmann https://github.com/stbachmann 7 | David Saltares https://github.com/siondream 8 | Peter Siegmund https://github.com/mars3142 9 | Andres Araujo https://github.com/andresaraujo 10 | Tomski https://github.com/Tom-Ski 11 | Xavier Guzman https://github.com/xaguzman 12 | adeluiz https://github.com/adeluiz 13 | Matthew Johnston https://github.com/warmwaffles 14 | Mario Zechner https://github.com/badlogic 15 | Ashley Davis https://github.com/SgtCoDFish 16 | Santo Pfingsten https://github.com/Lusito 17 | -------------------------------------------------------------------------------- /.github/workflows/publish_snapshot.yml: -------------------------------------------------------------------------------- 1 | name: Compile and publish snapshot 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | - release/** 8 | jobs: 9 | build: 10 | 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - uses: actions/checkout@v2 15 | - name: Set up JDK 1.8 16 | uses: actions/setup-java@v1 17 | with: 18 | java-version: 1.8 19 | - name: Grant execute permission for gradlew 20 | run: chmod +x gradlew 21 | - name: Build and test 22 | run: ./gradlew clean ashley:test 23 | - name: Publish snapshot 24 | env: 25 | NEXUS_USERNAME: ${{ secrets.NEXUS_USERNAME }} 26 | NEXUS_PASSWORD: ${{ secrets.NEXUS_PASSWORD }} 27 | run: ./gradlew uploadArchives -PSNAPSHOT=true 28 | -------------------------------------------------------------------------------- /.github/workflows/compile.yml: -------------------------------------------------------------------------------- 1 | # This workflow will build a Java project with Gradle 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle 3 | 4 | name: Compile and publish local 5 | 6 | on: 7 | pull_request: 8 | branches: [ master ] 9 | 10 | jobs: 11 | build: 12 | 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - uses: actions/checkout@v2 17 | - name: Set up JDK 1.8 18 | uses: actions/setup-java@v1 19 | with: 20 | java-version: 1.8 21 | - name: Grant execute permission for gradlew 22 | run: chmod +x gradlew 23 | - name: Build and test 24 | run: ./gradlew clean ashley:test 25 | - name: Local install 26 | run: ./gradlew uploadArchives 27 | -------------------------------------------------------------------------------- /tests/src/com/badlogic/ashley/tests/components/CameraComponent.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2014 See AUTHORS file. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | ******************************************************************************/ 16 | 17 | package com.badlogic.ashley.tests.components; 18 | 19 | import com.badlogic.ashley.core.Component; 20 | 21 | public class CameraComponent implements Component { 22 | 23 | } 24 | -------------------------------------------------------------------------------- /benchmarks/src/main/java/com/badlogic/ashley/benchmark/artemis/components/RemovalComponent.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2014 See AUTHORS file. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | ******************************************************************************/ 16 | 17 | package com.badlogic.ashley.benchmark.artemis.components; 18 | 19 | import com.artemis.Component; 20 | 21 | public class RemovalComponent extends Component { 22 | 23 | } 24 | -------------------------------------------------------------------------------- /benchmarks/src/main/java/com/badlogic/ashley/benchmark/ashley/components/RemovalComponent.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2014 See AUTHORS file. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | ******************************************************************************/ 16 | 17 | package com.badlogic.ashley.benchmark.ashley.components; 18 | 19 | import com.badlogic.ashley.core.Component; 20 | 21 | public class RemovalComponent implements Component { 22 | 23 | } 24 | -------------------------------------------------------------------------------- /benchmarks/src/main/java/com/badlogic/ashley/benchmark/artemis/components/RadiusComponent.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2014 See AUTHORS file. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | ******************************************************************************/ 16 | 17 | package com.badlogic.ashley.benchmark.artemis.components; 18 | 19 | import com.artemis.Component; 20 | 21 | public class RadiusComponent extends Component { 22 | public float radius = 1.0f; 23 | } 24 | -------------------------------------------------------------------------------- /benchmarks/src/main/java/com/badlogic/ashley/benchmark/ashley/components/RadiusComponent.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2014 See AUTHORS file. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | ******************************************************************************/ 16 | 17 | package com.badlogic.ashley.benchmark.ashley.components; 18 | 19 | import com.badlogic.ashley.core.Component; 20 | 21 | public class RadiusComponent implements Component { 22 | public float radius = 1.0f; 23 | } 24 | -------------------------------------------------------------------------------- /ashley/src/com/badlogic/ashley/core/Component.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2014 See AUTHORS file. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | ******************************************************************************/ 16 | 17 | package com.badlogic.ashley.core; 18 | 19 | /** 20 | * Interface for all Components. A Component is intended as a data holder and provides data to be processed in an 21 | * {@link EntitySystem}. But do as you wish. 22 | * @author Stefan Bachmann 23 | */ 24 | public interface Component { 25 | 26 | } 27 | -------------------------------------------------------------------------------- /tests/src/com/badlogic/ashley/tests/components/PositionComponent.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2014 See AUTHORS file. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | ******************************************************************************/ 16 | 17 | package com.badlogic.ashley.tests.components; 18 | 19 | import com.badlogic.ashley.core.Component; 20 | 21 | public class PositionComponent implements Component { 22 | public float x, y; 23 | 24 | public PositionComponent (float x, float y) { 25 | this.x = x; 26 | this.y = y; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /.github/workflows/publish_release.yml: -------------------------------------------------------------------------------- 1 | name: Compile and publish release 2 | 3 | on: 4 | release: 5 | types: [published] 6 | 7 | jobs: 8 | build: 9 | 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - uses: actions/checkout@v2 14 | - name: Set up JDK 1.8 15 | uses: actions/setup-java@v1 16 | with: 17 | java-version: 1.8 18 | - name: Grant execute permission for gradlew 19 | run: chmod +x gradlew 20 | - name: Build and test 21 | run: ./gradlew clean ashley:test 22 | - name: Import GPG key 23 | id: import_gpg 24 | uses: crazy-max/ghaction-import-gpg@1c6a9e9d3594f2d743f1b1dd7669ab0dfdffa922 25 | with: 26 | gpg-private-key: ${{ secrets.GPG_PRIVATE_KEY }} 27 | passphrase: ${{ secrets.GPG_PASSPHRASE }} 28 | - name: Release build deploy 29 | env: 30 | NEXUS_USERNAME: ${{ secrets.NEXUS_USERNAME }} 31 | NEXUS_PASSWORD: ${{ secrets.NEXUS_PASSWORD }} 32 | run: 33 | ./gradlew clean uploadArchives -PRELEASE=true -Psigning.gnupg.keyId=${{ secrets.GPG_KEYID }} -Psigning.gnupg.passphrase=${{ secrets.GPG_PASSPHRASE }} -Psigning.gnupg.keyName=${{ secrets.GPG_KEYID }} 34 | -------------------------------------------------------------------------------- /benchmarks/src/main/java/com/badlogic/ashley/benchmark/artemis/components/MovementComponent.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2014 See AUTHORS file. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | ******************************************************************************/ 16 | 17 | package com.badlogic.ashley.benchmark.artemis.components; 18 | 19 | import com.artemis.Component; 20 | import com.badlogic.gdx.math.Vector2; 21 | 22 | public class MovementComponent extends Component { 23 | public final Vector2 velocity = new Vector2(); 24 | public final Vector2 accel = new Vector2(); 25 | } 26 | -------------------------------------------------------------------------------- /benchmarks/src/main/java/com/badlogic/ashley/benchmark/ashley/components/MovementComponent.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2014 See AUTHORS file. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | ******************************************************************************/ 16 | 17 | package com.badlogic.ashley.benchmark.ashley.components; 18 | 19 | import com.badlogic.ashley.core.Component; 20 | import com.badlogic.gdx.math.Vector2; 21 | 22 | public class MovementComponent implements Component { 23 | public final Vector2 velocity = new Vector2(); 24 | public final Vector2 accel = new Vector2(); 25 | } 26 | -------------------------------------------------------------------------------- /tests/src/com/badlogic/ashley/tests/components/VisualComponent.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2014 See AUTHORS file. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | ******************************************************************************/ 16 | 17 | package com.badlogic.ashley.tests.components; 18 | 19 | import com.badlogic.ashley.core.Component; 20 | import com.badlogic.gdx.graphics.g2d.TextureRegion; 21 | 22 | public class VisualComponent implements Component { 23 | public TextureRegion region; 24 | 25 | public VisualComponent (TextureRegion region) { 26 | this.region = region; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /ashley/src/com/badlogic/ashley/signals/Listener.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2014 See AUTHORS file. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | ******************************************************************************/ 16 | 17 | package com.badlogic.ashley.signals; 18 | 19 | /** 20 | * A simple Listener interface used to listen to a {@link Signal}. 21 | * @author Stefan Bachmann 22 | */ 23 | public interface Listener { 24 | /** 25 | * @param signal The Signal that triggered event 26 | * @param object The object passed on dispatch 27 | */ 28 | public void receive (Signal signal, T object); 29 | } 30 | -------------------------------------------------------------------------------- /tests/src/com/badlogic/ashley/tests/components/MovementComponent.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2014 See AUTHORS file. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | ******************************************************************************/ 16 | 17 | package com.badlogic.ashley.tests.components; 18 | 19 | import com.badlogic.ashley.core.Component; 20 | 21 | public class MovementComponent implements Component { 22 | public float velocityX; 23 | public float velocityY; 24 | 25 | public MovementComponent (float velocityX, float velocityY) { 26 | this.velocityX = velocityX; 27 | this.velocityY = velocityY; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /benchmarks/src/main/java/com/badlogic/ashley/benchmark/artemis/components/StateComponent.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2014 See AUTHORS file. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | ******************************************************************************/ 16 | 17 | package com.badlogic.ashley.benchmark.artemis.components; 18 | 19 | import com.artemis.Component; 20 | 21 | public class StateComponent extends Component { 22 | private int state = 0; 23 | public float time = 0.0f; 24 | 25 | public int get () { 26 | return state; 27 | } 28 | 29 | public void set (int newState) { 30 | state = newState; 31 | time = 0.0f; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /benchmarks/src/main/java/com/badlogic/ashley/benchmark/artemis/components/PositionComponent.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2014 See AUTHORS file. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | ******************************************************************************/ 16 | 17 | package com.badlogic.ashley.benchmark.artemis.components; 18 | 19 | import com.artemis.Component; 20 | import com.badlogic.gdx.math.Vector2; 21 | import com.badlogic.gdx.math.Vector3; 22 | 23 | public class PositionComponent extends Component { 24 | public final Vector3 pos = new Vector3(); 25 | public final Vector2 scale = new Vector2(1.0f, 1.0f); 26 | public float rotation = 0.0f; 27 | } 28 | -------------------------------------------------------------------------------- /benchmarks/src/main/java/com/badlogic/ashley/benchmark/ashley/components/StateComponent.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2014 See AUTHORS file. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | ******************************************************************************/ 16 | 17 | package com.badlogic.ashley.benchmark.ashley.components; 18 | 19 | import com.badlogic.ashley.core.Component; 20 | 21 | public class StateComponent implements Component { 22 | private int state = 0; 23 | public float time = 0.0f; 24 | 25 | public int get () { 26 | return state; 27 | } 28 | 29 | public void set (int newState) { 30 | state = newState; 31 | time = 0.0f; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /benchmarks/src/main/java/com/badlogic/ashley/benchmark/ashley/components/PositionComponent.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2014 See AUTHORS file. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | ******************************************************************************/ 16 | 17 | package com.badlogic.ashley.benchmark.ashley.components; 18 | 19 | import com.badlogic.ashley.core.Component; 20 | import com.badlogic.gdx.math.Vector2; 21 | import com.badlogic.gdx.math.Vector3; 22 | 23 | public class PositionComponent implements Component { 24 | public final Vector3 pos = new Vector3(); 25 | public final Vector2 scale = new Vector2(1.0f, 1.0f); 26 | public float rotation = 0.0f; 27 | } 28 | -------------------------------------------------------------------------------- /benchmarks/src/main/java/com/badlogic/ashley/benchmark/Constants.java: -------------------------------------------------------------------------------- 1 | 2 | package com.badlogic.ashley.benchmark; 3 | 4 | public class Constants { 5 | public static enum ComponentType { 6 | POSITION, MOVEMENT, RADIUS, STATE, 7 | }; 8 | 9 | public static final int FRAMES = 100; 10 | public static final float DELTA_TIME = 1.0f / 60.0f; 11 | 12 | public static final int BENCHMARK_ROUNDS = 20; 13 | public static final int WARMUP_ROUNDS = 20; 14 | 15 | public static final int ENTITIES_SMALL_TEST = 10000; 16 | public static final int ENTITIES_MEDIUM_TEST = 20000; 17 | public static final int ENTITIES_BIG_TEST = 50000; 18 | 19 | public static final float MIN_RADIUS = 0.1f; 20 | public static final float MAX_RADIUS = 10.0f; 21 | public static final float MIN_POS = -10.f; 22 | public static final float MAX_POS = 10.0f; 23 | public static final float MIN_VEL = -1.0f; 24 | public static final float MAX_VEL = 1.0f; 25 | public static final float MIN_ACC = -0.1f; 26 | public static final float MAX_ACC = 0.1f; 27 | 28 | public static final int FRAMES_PER_REMOVAL = 10; 29 | 30 | public static boolean shouldHaveComponent (ComponentType type, int index) { 31 | switch (type) { 32 | case MOVEMENT: 33 | return index % 4 == 0; 34 | case RADIUS: 35 | return index % 3 == 0; 36 | case STATE: 37 | return index % 2 == 0; 38 | case POSITION: 39 | return true; 40 | } 41 | 42 | return false; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /tests/src/com/badlogic/ashley/tests/SignalTest.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2014 See AUTHORS file. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | ******************************************************************************/ 16 | 17 | package com.badlogic.ashley.tests; 18 | 19 | import com.badlogic.ashley.signals.Listener; 20 | import com.badlogic.ashley.signals.Signal; 21 | 22 | public class SignalTest { 23 | public static void main (String[] args) { 24 | Signal signal = new Signal(); 25 | 26 | Listener listener = new Listener() { 27 | @Override 28 | public void receive (Signal signal, String object) { 29 | System.out.println("Received event: " + object); 30 | } 31 | }; 32 | 33 | signal.add(listener); 34 | signal.dispatch("Hello World!"); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /benchmarks/src/main/java/com/badlogic/ashley/benchmark/ashley/systems/CollisionSystem.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2014 See AUTHORS file. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | ******************************************************************************/ 16 | 17 | package com.badlogic.ashley.benchmark.ashley.systems; 18 | 19 | import com.badlogic.ashley.benchmark.ashley.components.RadiusComponent; 20 | import com.badlogic.ashley.core.Engine; 21 | import com.badlogic.ashley.core.Entity; 22 | import com.badlogic.ashley.core.EntitySystem; 23 | import com.badlogic.ashley.core.Family; 24 | import com.badlogic.ashley.utils.ImmutableArray; 25 | 26 | public class CollisionSystem extends EntitySystem { 27 | ImmutableArray entities; 28 | 29 | @Override 30 | public void addedToEngine (Engine engine) { 31 | entities = engine.getEntitiesFor(Family.all(RadiusComponent.class).get()); 32 | } 33 | 34 | @Override 35 | public void update (float deltaTime) { 36 | 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /benchmarks/src/main/java/com/badlogic/ashley/benchmark/ashley/systems/StateSystem.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2014 See AUTHORS file. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | ******************************************************************************/ 16 | 17 | package com.badlogic.ashley.benchmark.ashley.systems; 18 | 19 | import com.badlogic.ashley.benchmark.ashley.components.StateComponent; 20 | import com.badlogic.ashley.core.ComponentMapper; 21 | import com.badlogic.ashley.core.Entity; 22 | import com.badlogic.ashley.core.Family; 23 | import com.badlogic.ashley.systems.IteratingSystem; 24 | 25 | public class StateSystem extends IteratingSystem { 26 | private ComponentMapper sm = ComponentMapper.getFor(StateComponent.class); 27 | 28 | public StateSystem () { 29 | super(Family.all(StateComponent.class).get()); 30 | } 31 | 32 | @Override 33 | public void processEntity (Entity entity, float deltaTime) { 34 | sm.get(entity).time += deltaTime; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /benchmarks/src/main/java/com/badlogic/ashley/benchmark/artemis/systems/RemovalSystem.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2014 See AUTHORS file. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | ******************************************************************************/ 16 | 17 | package com.badlogic.ashley.benchmark.artemis.systems; 18 | 19 | import com.artemis.Aspect; 20 | import com.artemis.Entity; 21 | import com.artemis.EntitySystem; 22 | import com.artemis.utils.ImmutableBag; 23 | import com.badlogic.ashley.benchmark.artemis.components.RemovalComponent; 24 | 25 | public class RemovalSystem extends EntitySystem { 26 | 27 | public RemovalSystem () { 28 | super(Aspect.getAspectForAll(RemovalComponent.class)); 29 | } 30 | 31 | @Override 32 | protected void processEntities (ImmutableBag entities) { 33 | while (!entities.isEmpty()) { 34 | world.deleteEntity(entities.get(0)); 35 | } 36 | } 37 | 38 | @Override 39 | protected boolean checkProcessing () { 40 | return true; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /benchmarks/src/main/java/com/badlogic/ashley/benchmark/artemis/systems/CollisionSystem.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2014 See AUTHORS file. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | ******************************************************************************/ 16 | 17 | package com.badlogic.ashley.benchmark.artemis.systems; 18 | 19 | import com.artemis.Aspect; 20 | import com.artemis.Entity; 21 | import com.artemis.EntitySystem; 22 | import com.artemis.utils.ImmutableBag; 23 | import com.badlogic.ashley.benchmark.artemis.components.PositionComponent; 24 | import com.badlogic.ashley.benchmark.artemis.components.RadiusComponent; 25 | 26 | public class CollisionSystem extends EntitySystem { 27 | 28 | public CollisionSystem () { 29 | super(Aspect.getAspectForAll(PositionComponent.class, RadiusComponent.class)); 30 | } 31 | 32 | @Override 33 | protected boolean checkProcessing () { 34 | return true; 35 | } 36 | 37 | @Override 38 | protected void processEntities (ImmutableBag entities) { 39 | 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /ashley/tests/com/badlogic/ashley/utils/ImmutableArrayTests.java: -------------------------------------------------------------------------------- 1 | 2 | package com.badlogic.ashley.utils; 3 | 4 | import static org.junit.Assert.*; 5 | 6 | import org.junit.Test; 7 | 8 | import com.badlogic.gdx.utils.Array; 9 | import com.badlogic.gdx.utils.GdxRuntimeException; 10 | 11 | public class ImmutableArrayTests { 12 | 13 | @Test 14 | public void sameValues () { 15 | Array array = new Array(); 16 | ImmutableArray immutable = new ImmutableArray(array); 17 | 18 | assertEquals(array.size, immutable.size()); 19 | 20 | for (int i = 0; i < 10; ++i) { 21 | array.add(i); 22 | } 23 | 24 | assertEquals(array.size, immutable.size()); 25 | 26 | for (int i = 0; i < array.size; ++i) { 27 | assertEquals(array.get(i), immutable.get(i)); 28 | } 29 | } 30 | 31 | @Test 32 | public void iteration () { 33 | Array array = new Array(); 34 | ImmutableArray immutable = new ImmutableArray(array); 35 | 36 | for (int i = 0; i < 10; ++i) { 37 | array.add(i); 38 | } 39 | 40 | Integer expected = 0; 41 | for (Integer value : immutable) { 42 | assertEquals(expected++, value); 43 | } 44 | } 45 | 46 | @Test 47 | public void forbiddenRemoval () { 48 | Array array = new Array(); 49 | ImmutableArray immutable = new ImmutableArray(array); 50 | 51 | for (int i = 0; i < 10; ++i) { 52 | array.add(i); 53 | } 54 | 55 | boolean thrown = false; 56 | 57 | try { 58 | immutable.iterator().remove(); 59 | } catch (GdxRuntimeException e) { 60 | thrown = true; 61 | } 62 | 63 | assertEquals(true, thrown); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /ashley/src/com/badlogic/ashley/core/EntityListener.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2014 See AUTHORS file. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | ******************************************************************************/ 16 | 17 | package com.badlogic.ashley.core; 18 | 19 | /** 20 | * Gets notified of {@link Entity} related events. 21 | * @author David Saltares 22 | */ 23 | public interface EntityListener { 24 | /** 25 | * Called whenever an {@link Entity} is added to {@link Engine} or a specific {@link Family} See 26 | * {@link Engine#addEntityListener(EntityListener)} and {@link Engine#addEntityListener(Family, EntityListener)} 27 | * @param entity 28 | */ 29 | public void entityAdded (Entity entity); 30 | 31 | /** 32 | * Called whenever an {@link Entity} is removed from {@link Engine} or a specific {@link Family} See 33 | * {@link Engine#addEntityListener(EntityListener)} and {@link Engine#addEntityListener(Family, EntityListener)} 34 | * @param entity 35 | */ 36 | public void entityRemoved (Entity entity); 37 | } 38 | -------------------------------------------------------------------------------- /benchmarks/src/main/java/com/badlogic/ashley/benchmark/artemis/systems/StateSystem.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2014 See AUTHORS file. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | ******************************************************************************/ 16 | 17 | package com.badlogic.ashley.benchmark.artemis.systems; 18 | 19 | import com.artemis.Aspect; 20 | import com.artemis.ComponentMapper; 21 | import com.artemis.Entity; 22 | import com.artemis.annotations.Mapper; 23 | import com.artemis.systems.EntityProcessingSystem; 24 | import com.badlogic.ashley.benchmark.artemis.components.StateComponent; 25 | 26 | public class StateSystem extends EntityProcessingSystem { 27 | @Mapper ComponentMapper sm; 28 | 29 | public StateSystem () { 30 | super(Aspect.getAspectForAll(StateComponent.class)); 31 | } 32 | 33 | @Override 34 | protected void initialize () { 35 | sm = world.getMapper(StateComponent.class); 36 | }; 37 | 38 | @Override 39 | protected void process (Entity entity) { 40 | sm.get(entity).time += world.getDelta(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /benchmarks/src/main/java/com/badlogic/ashley/benchmark/ashley/systems/RemovalSystem.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2014 See AUTHORS file. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | ******************************************************************************/ 16 | 17 | package com.badlogic.ashley.benchmark.ashley.systems; 18 | 19 | import com.badlogic.ashley.benchmark.ashley.components.RemovalComponent; 20 | import com.badlogic.ashley.core.Engine; 21 | import com.badlogic.ashley.core.Entity; 22 | import com.badlogic.ashley.core.EntitySystem; 23 | import com.badlogic.ashley.core.Family; 24 | import com.badlogic.ashley.utils.ImmutableArray; 25 | 26 | public class RemovalSystem extends EntitySystem { 27 | private ImmutableArray entities; 28 | 29 | @Override 30 | public void addedToEngine (Engine engine) { 31 | entities = engine.getEntitiesFor(Family.all(RemovalComponent.class).get()); 32 | } 33 | 34 | @Override 35 | public void update (float deltaTime) { 36 | while (entities.size() > 0) { 37 | getEngine().removeEntity(entities.get(0)); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /tests/src/com/badlogic/ashley/tests/SystemPriorityTest.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2014 See AUTHORS file. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | ******************************************************************************/ 16 | 17 | package com.badlogic.ashley.tests; 18 | 19 | import com.badlogic.ashley.core.Engine; 20 | import com.badlogic.ashley.core.EntitySystem; 21 | 22 | public class SystemPriorityTest { 23 | public static void main (String[] args) { 24 | Engine engine = new Engine(); 25 | 26 | engine.addSystem(new SystemA(10)); 27 | engine.addSystem(new SystemB(5)); 28 | engine.addSystem(new SystemA(2)); 29 | 30 | engine.update(0); 31 | } 32 | 33 | public static class SystemA extends EntitySystem { 34 | public SystemA (int priority) { 35 | super(priority); 36 | } 37 | 38 | @Override 39 | public void update (float deltaTime) { 40 | System.out.println("SystemA"); 41 | } 42 | 43 | } 44 | 45 | public static class SystemB extends EntitySystem { 46 | public SystemB (int priority) { 47 | super(priority); 48 | } 49 | 50 | @Override 51 | public void update (float deltaTime) { 52 | System.out.println("SystemB"); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /tests/src/com/badlogic/ashley/tests/utils/Timer.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2014 See AUTHORS file. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | ******************************************************************************/ 16 | 17 | package com.badlogic.ashley.tests.utils; 18 | 19 | import com.badlogic.gdx.utils.ObjectMap; 20 | 21 | /** 22 | * A simple Timer class that let's you measure multiple times and are identified via an id. 23 | * @author Stefan Bachmann 24 | */ 25 | public class Timer { 26 | private ObjectMap times; 27 | 28 | public Timer () { 29 | times = new ObjectMap(); 30 | } 31 | 32 | /** 33 | * Start tracking a time with name as id. 34 | * @param name The timer's id 35 | */ 36 | public void start (String name) { 37 | times.put(name, System.currentTimeMillis()); 38 | } 39 | 40 | /** 41 | * Stop tracking the specified id 42 | * @param name The timer's id 43 | * @return the elapsed time 44 | */ 45 | public long stop (String name) { 46 | if (times.containsKey(name)) { 47 | long startTime = times.remove(name); 48 | return System.currentTimeMillis() - startTime; 49 | } else 50 | throw new RuntimeException("Timer id doesn't exist."); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /tests/src/com/badlogic/ashley/tests/systems/MovementSystem.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2014 See AUTHORS file. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | ******************************************************************************/ 16 | 17 | package com.badlogic.ashley.tests.systems; 18 | 19 | import com.badlogic.ashley.core.ComponentMapper; 20 | import com.badlogic.ashley.core.Entity; 21 | import com.badlogic.ashley.core.Family; 22 | import com.badlogic.ashley.systems.IteratingSystem; 23 | import com.badlogic.ashley.tests.components.MovementComponent; 24 | import com.badlogic.ashley.tests.components.PositionComponent; 25 | 26 | public class MovementSystem extends IteratingSystem { 27 | private ComponentMapper pm = ComponentMapper.getFor(PositionComponent.class); 28 | private ComponentMapper mm = ComponentMapper.getFor(MovementComponent.class); 29 | 30 | public MovementSystem () { 31 | super(Family.all(PositionComponent.class, MovementComponent.class).get()); 32 | } 33 | 34 | @Override 35 | public void processEntity (Entity entity, float deltaTime) { 36 | PositionComponent position = pm.get(entity); 37 | MovementComponent movement = mm.get(entity); 38 | 39 | position.x += movement.velocityX * deltaTime; 40 | position.y += movement.velocityY * deltaTime; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /ashley/tests/com/badlogic/ashley/systems/IntervalSystemTest.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2014 See AUTHORS file. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | ******************************************************************************/ 16 | 17 | package com.badlogic.ashley.systems; 18 | 19 | import org.junit.Test; 20 | 21 | import com.badlogic.ashley.core.Engine; 22 | 23 | import static org.junit.Assert.*; 24 | 25 | public class IntervalSystemTest { 26 | private static final float deltaTime = 0.1f; 27 | 28 | private static class IntervalSystemSpy extends IntervalSystem { 29 | public int numUpdates; 30 | 31 | public IntervalSystemSpy () { 32 | super(deltaTime * 2.0f); 33 | } 34 | 35 | @Override 36 | protected void updateInterval () { 37 | ++numUpdates; 38 | } 39 | } 40 | 41 | @Test 42 | public void intervalSystem () { 43 | Engine engine = new Engine(); 44 | IntervalSystemSpy intervalSystemSpy = new IntervalSystemSpy(); 45 | 46 | engine.addSystem(intervalSystemSpy); 47 | 48 | for (int i = 1; i <= 10; ++i) { 49 | engine.update(deltaTime); 50 | assertEquals(i / 2, intervalSystemSpy.numUpdates); 51 | } 52 | } 53 | 54 | @Test 55 | public void testGetInterval () { 56 | IntervalSystemSpy intervalSystemSpy = new IntervalSystemSpy(); 57 | assertEquals(intervalSystemSpy.getInterval(), deltaTime * 2.0f, 0); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /ashley/src/com/badlogic/ashley/core/ComponentMapper.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2014 See AUTHORS file. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | ******************************************************************************/ 16 | 17 | package com.badlogic.ashley.core; 18 | 19 | /** 20 | * Provides super fast {@link Component} retrieval from {@Link Entity} objects. 21 | * @param the class type of the {@link Component}. 22 | * @author David Saltares 23 | */ 24 | public final class ComponentMapper { 25 | private final ComponentType componentType; 26 | 27 | /** 28 | * @param componentClass Component class to be retrieved by the mapper. 29 | * @return New instance that provides fast access to the {@link Component} of the specified class. 30 | */ 31 | public static ComponentMapper getFor (Class componentClass) { 32 | return new ComponentMapper(componentClass); 33 | } 34 | 35 | /** @return The {@link Component} of the specified class belonging to entity. */ 36 | public T get (Entity entity) { 37 | return entity.getComponent(componentType); 38 | } 39 | 40 | /** @return Whether or not entity has the component of the specified class. */ 41 | public boolean has (Entity entity) { 42 | return entity.hasComponent(componentType); 43 | } 44 | 45 | private ComponentMapper (Class componentClass) { 46 | componentType = ComponentType.getFor(componentClass); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /tests/src/com/badlogic/ashley/tests/IgnoreSystemTest.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2014 See AUTHORS file. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | ******************************************************************************/ 16 | 17 | package com.badlogic.ashley.tests; 18 | 19 | import com.badlogic.ashley.core.EntitySystem; 20 | import com.badlogic.ashley.core.PooledEngine; 21 | 22 | public class IgnoreSystemTest { 23 | 24 | public static void main (String[] args) { 25 | PooledEngine engine = new PooledEngine(); 26 | 27 | CounterSystem counter = new CounterSystem(); 28 | IgnoredSystem ignored = new IgnoredSystem(); 29 | 30 | engine.addSystem(counter); 31 | engine.addSystem(ignored); 32 | 33 | for (int i = 0; i < 10; i++) { 34 | engine.update(0.25f); 35 | } 36 | } 37 | 38 | private static class CounterSystem extends EntitySystem { 39 | @Override 40 | public void update (float deltaTime) { 41 | log("Running " + getClass().getSimpleName()); 42 | } 43 | } 44 | 45 | private static class IgnoredSystem extends EntitySystem { 46 | 47 | int counter = 0; 48 | 49 | @Override 50 | public boolean checkProcessing () { 51 | counter = 1 - counter; 52 | return counter == 1; 53 | } 54 | 55 | @Override 56 | public void update (float deltaTime) { 57 | log("Running " + getClass().getSimpleName()); 58 | } 59 | } 60 | 61 | public static void log (String string) { 62 | System.out.println(string); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /benchmarks/src/main/java/com/badlogic/ashley/benchmark/ashley/systems/MovementSystem.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2014 See AUTHORS file. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | ******************************************************************************/ 16 | 17 | package com.badlogic.ashley.benchmark.ashley.systems; 18 | 19 | import com.badlogic.ashley.benchmark.ashley.components.MovementComponent; 20 | import com.badlogic.ashley.benchmark.ashley.components.PositionComponent; 21 | import com.badlogic.ashley.core.ComponentMapper; 22 | import com.badlogic.ashley.core.Entity; 23 | import com.badlogic.ashley.core.Family; 24 | import com.badlogic.ashley.systems.IteratingSystem; 25 | import com.badlogic.gdx.math.Vector2; 26 | 27 | public class MovementSystem extends IteratingSystem { 28 | private Vector2 tmp = new Vector2(); 29 | private ComponentMapper pm = ComponentMapper.getFor(PositionComponent.class); 30 | private ComponentMapper mm = ComponentMapper.getFor(MovementComponent.class); 31 | 32 | public MovementSystem () { 33 | super(Family.all(PositionComponent.class, MovementComponent.class).get()); 34 | } 35 | 36 | @Override 37 | public void processEntity (Entity entity, float deltaTime) { 38 | PositionComponent pos = pm.get(entity); 39 | MovementComponent mov = mm.get(entity); 40 | 41 | tmp.set(mov.accel).scl(deltaTime); 42 | mov.velocity.add(tmp); 43 | 44 | tmp.set(mov.velocity).scl(deltaTime); 45 | pos.pos.add(tmp.x, tmp.y, 0.0f); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /benchmarks/src/main/java/com/badlogic/ashley/benchmark/artemis/systems/MovementSystem.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2014 See AUTHORS file. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | ******************************************************************************/ 16 | 17 | package com.badlogic.ashley.benchmark.artemis.systems; 18 | 19 | import com.artemis.Aspect; 20 | import com.artemis.ComponentMapper; 21 | import com.artemis.Entity; 22 | import com.artemis.annotations.Mapper; 23 | import com.artemis.systems.EntityProcessingSystem; 24 | import com.badlogic.ashley.benchmark.artemis.components.MovementComponent; 25 | import com.badlogic.ashley.benchmark.artemis.components.PositionComponent; 26 | import com.badlogic.gdx.math.Vector2; 27 | 28 | public class MovementSystem extends EntityProcessingSystem { 29 | private Vector2 tmp = new Vector2(); 30 | @Mapper ComponentMapper pm; 31 | @Mapper ComponentMapper mm; 32 | 33 | public MovementSystem () { 34 | super(Aspect.getAspectForAll(PositionComponent.class, MovementComponent.class)); 35 | } 36 | 37 | @Override 38 | protected void initialize () { 39 | pm = world.getMapper(PositionComponent.class); 40 | mm = world.getMapper(MovementComponent.class); 41 | }; 42 | 43 | @Override 44 | protected void process (Entity entity) { 45 | PositionComponent pos = pm.get(entity); 46 | MovementComponent mov = mm.get(entity); 47 | 48 | tmp.set(mov.accel).scl(world.getDelta()); 49 | mov.velocity.add(tmp); 50 | 51 | tmp.set(mov.velocity).scl(world.getDelta()); 52 | pos.pos.add(tmp.x, tmp.y, 0.0f); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /ashley/src/com/badlogic/ashley/systems/IntervalSystem.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2014 See AUTHORS file. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | ******************************************************************************/ 16 | 17 | package com.badlogic.ashley.systems; 18 | 19 | import com.badlogic.ashley.core.EntitySystem; 20 | 21 | /** 22 | * A simple {@link EntitySystem} that does not run its update logic every call to {@link EntitySystem#update(float)}, but after a 23 | * given interval. The actual logic should be placed in {@link IntervalSystem#updateInterval()}. 24 | * @author David Saltares 25 | */ 26 | public abstract class IntervalSystem extends EntitySystem { 27 | private float interval; 28 | private float accumulator; 29 | 30 | /** 31 | * @param interval time in seconds between calls to {@link IntervalSystem#updateInterval()}. 32 | */ 33 | public IntervalSystem (float interval) { 34 | this(interval, 0); 35 | } 36 | 37 | /** 38 | * @param interval time in seconds between calls to {@link IntervalSystem#updateInterval()}. 39 | * @param priority 40 | */ 41 | public IntervalSystem (float interval, int priority) { 42 | super(priority); 43 | this.interval = interval; 44 | this.accumulator = 0; 45 | } 46 | 47 | public float getInterval() { 48 | return interval; 49 | } 50 | 51 | @Override 52 | public void update (float deltaTime) { 53 | accumulator += deltaTime; 54 | 55 | while (accumulator >= interval) { 56 | accumulator -= interval; 57 | updateInterval(); 58 | } 59 | } 60 | 61 | /** 62 | * The processing logic of the system should be placed here. 63 | */ 64 | protected abstract void updateInterval (); 65 | } 66 | -------------------------------------------------------------------------------- /ashley/src/com/badlogic/ashley/core/SystemManager.java: -------------------------------------------------------------------------------- 1 | package com.badlogic.ashley.core; 2 | 3 | import java.util.Comparator; 4 | 5 | import com.badlogic.ashley.signals.Listener; 6 | import com.badlogic.ashley.signals.Signal; 7 | import com.badlogic.ashley.utils.ImmutableArray; 8 | import com.badlogic.gdx.utils.Array; 9 | import com.badlogic.gdx.utils.ObjectMap; 10 | 11 | class SystemManager { 12 | private SystemComparator systemComparator = new SystemComparator(); 13 | private Array systems = new Array(true, 16); 14 | private ImmutableArray immutableSystems = new ImmutableArray(systems); 15 | private ObjectMap, EntitySystem> systemsByClass = new ObjectMap, EntitySystem>(); 16 | private SystemListener listener; 17 | 18 | public SystemManager(SystemListener listener) { 19 | this.listener = listener; 20 | } 21 | 22 | public void addSystem(EntitySystem system){ 23 | Class systemType = system.getClass(); 24 | EntitySystem oldSystem = getSystem(systemType); 25 | 26 | if (oldSystem != null) { 27 | removeSystem(oldSystem); 28 | } 29 | 30 | systems.add(system); 31 | systemsByClass.put(systemType, system); 32 | systems.sort(systemComparator); 33 | listener.systemAdded(system); 34 | } 35 | 36 | public void removeSystem(EntitySystem system){ 37 | if(systems.removeValue(system, true)) { 38 | systemsByClass.remove(system.getClass()); 39 | listener.systemRemoved(system); 40 | } 41 | } 42 | 43 | public void removeAllSystems() { 44 | while(systems.size > 0) { 45 | removeSystem(systems.first()); 46 | } 47 | } 48 | 49 | @SuppressWarnings("unchecked") 50 | public T getSystem(Class systemType) { 51 | return (T) systemsByClass.get(systemType); 52 | } 53 | 54 | public ImmutableArray getSystems() { 55 | return immutableSystems; 56 | } 57 | 58 | private static class SystemComparator implements Comparator{ 59 | @Override 60 | public int compare(EntitySystem a, EntitySystem b) { 61 | return a.priority > b.priority ? 1 : (a.priority == b.priority) ? 0 : -1; 62 | } 63 | } 64 | 65 | interface SystemListener { 66 | void systemAdded(EntitySystem system); 67 | void systemRemoved(EntitySystem system); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /ashley/src/com/badlogic/ashley/signals/Signal.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2014 See AUTHORS file. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | ******************************************************************************/ 16 | 17 | package com.badlogic.ashley.signals; 18 | 19 | import com.badlogic.gdx.utils.SnapshotArray; 20 | 21 | /** 22 | * A Signal is a basic event class that can dispatch an event to multiple listeners. It uses generics to allow any type of object 23 | * to be passed around on dispatch. 24 | * @author Stefan Bachmann 25 | */ 26 | public class Signal { 27 | private SnapshotArray> listeners; 28 | 29 | public Signal () { 30 | listeners = new SnapshotArray>(); 31 | } 32 | 33 | /** 34 | * Add a Listener to this Signal 35 | * @param listener The Listener to be added 36 | */ 37 | public void add (Listener listener) { 38 | listeners.add(listener); 39 | } 40 | 41 | /** 42 | * Remove a listener from this Signal 43 | * @param listener The Listener to remove 44 | */ 45 | public void remove (Listener listener) { 46 | listeners.removeValue(listener, true); 47 | } 48 | 49 | /** Removes all listeners attached to this {@link Signal}. */ 50 | public void removeAllListeners () { 51 | listeners.clear(); 52 | } 53 | 54 | /** 55 | * Dispatches an event to all Listeners registered to this Signal 56 | * @param object The object to send off 57 | */ 58 | public void dispatch (T object) { 59 | final Object[] items = listeners.begin(); 60 | for (int i = 0, n = listeners.size; i < n; i++) { 61 | Listener listener = (Listener)items[i]; 62 | listener.receive(this, object); 63 | } 64 | listeners.end(); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /ashley/src/com/badlogic/ashley/core/ComponentOperationHandler.java: -------------------------------------------------------------------------------- 1 | package com.badlogic.ashley.core; 2 | 3 | import com.badlogic.gdx.utils.Array; 4 | import com.badlogic.gdx.utils.Pool; 5 | 6 | 7 | class ComponentOperationHandler { 8 | private BooleanInformer delayed; 9 | private ComponentOperationPool operationPool = new ComponentOperationPool();; 10 | private Array operations = new Array();; 11 | 12 | public ComponentOperationHandler(BooleanInformer delayed) { 13 | this.delayed = delayed; 14 | } 15 | 16 | public void add(Entity entity) { 17 | if (delayed.value()) { 18 | ComponentOperation operation = operationPool.obtain(); 19 | operation.makeAdd(entity); 20 | operations.add(operation); 21 | } 22 | else { 23 | entity.notifyComponentAdded(); 24 | } 25 | } 26 | 27 | public void remove(Entity entity) { 28 | if (delayed.value()) { 29 | ComponentOperation operation = operationPool.obtain(); 30 | operation.makeRemove(entity); 31 | operations.add(operation); 32 | } 33 | else { 34 | entity.notifyComponentRemoved(); 35 | } 36 | } 37 | 38 | public boolean hasOperationsToProcess() { 39 | return operations.size > 0; 40 | } 41 | 42 | public void processOperations() { 43 | for (int i = 0; i < operations.size; ++i) { 44 | ComponentOperation operation = operations.get(i); 45 | 46 | switch(operation.type) { 47 | case Add: 48 | operation.entity.notifyComponentAdded(); 49 | break; 50 | case Remove: 51 | operation.entity.notifyComponentRemoved(); 52 | break; 53 | default: break; 54 | } 55 | 56 | operationPool.free(operation); 57 | } 58 | 59 | operations.clear(); 60 | } 61 | 62 | private static class ComponentOperation implements Pool.Poolable { 63 | public enum Type { 64 | Add, 65 | Remove, 66 | } 67 | 68 | public Type type; 69 | public Entity entity; 70 | 71 | public void makeAdd(Entity entity) { 72 | this.type = Type.Add; 73 | this.entity = entity; 74 | } 75 | 76 | public void makeRemove(Entity entity) { 77 | this.type = Type.Remove; 78 | this.entity = entity; 79 | } 80 | 81 | @Override 82 | public void reset() { 83 | entity = null; 84 | } 85 | } 86 | 87 | private static class ComponentOperationPool extends Pool { 88 | @Override 89 | protected ComponentOperation newObject() { 90 | return new ComponentOperation(); 91 | } 92 | } 93 | 94 | interface BooleanInformer { 95 | public boolean value(); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /ashley/tests/com/badlogic/ashley/core/ComponentTypeTests.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2014 See AUTHORS file. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | ******************************************************************************/ 16 | 17 | package com.badlogic.ashley.core; 18 | 19 | import static org.junit.Assert.*; 20 | 21 | import org.junit.Test; 22 | 23 | import com.badlogic.ashley.core.Component; 24 | import com.badlogic.ashley.core.ComponentType; 25 | 26 | public class ComponentTypeTests { 27 | 28 | private static class ComponentA implements Component { 29 | 30 | } 31 | 32 | private static class ComponentB implements Component { 33 | 34 | } 35 | 36 | @Test 37 | public void validComponentType () { 38 | assertNotNull(ComponentType.getFor(ComponentA.class)); 39 | assertNotNull(ComponentType.getFor(ComponentB.class)); 40 | } 41 | 42 | @Test 43 | public void sameComponentType () { 44 | ComponentType componentType1 = ComponentType.getFor(ComponentA.class); 45 | ComponentType componentType2 = ComponentType.getFor(ComponentA.class); 46 | 47 | assertEquals(true, componentType1.equals(componentType2)); 48 | assertEquals(true, componentType2.equals(componentType1)); 49 | assertEquals(componentType1.getIndex(), componentType2.getIndex()); 50 | assertEquals(componentType1.getIndex(), ComponentType.getIndexFor(ComponentA.class)); 51 | assertEquals(componentType2.getIndex(), ComponentType.getIndexFor(ComponentA.class)); 52 | } 53 | 54 | @Test 55 | public void differentComponentType () { 56 | ComponentType componentType1 = ComponentType.getFor(ComponentA.class); 57 | ComponentType componentType2 = ComponentType.getFor(ComponentB.class); 58 | 59 | assertEquals(false, componentType1.equals(componentType2)); 60 | assertEquals(false, componentType2.equals(componentType1)); 61 | assertNotEquals(componentType1.getIndex(), componentType2.getIndex()); 62 | assertNotEquals(componentType1.getIndex(), ComponentType.getIndexFor(ComponentB.class)); 63 | assertNotEquals(componentType2.getIndex(), ComponentType.getIndexFor(ComponentA.class)); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /tests/src/com/badlogic/ashley/tests/systems/RenderSystem.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2014 See AUTHORS file. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | ******************************************************************************/ 16 | 17 | package com.badlogic.ashley.tests.systems; 18 | 19 | import com.badlogic.ashley.core.ComponentMapper; 20 | import com.badlogic.ashley.core.Engine; 21 | import com.badlogic.ashley.core.Entity; 22 | import com.badlogic.ashley.core.EntitySystem; 23 | import com.badlogic.ashley.core.Family; 24 | import com.badlogic.ashley.tests.components.PositionComponent; 25 | import com.badlogic.ashley.tests.components.VisualComponent; 26 | import com.badlogic.ashley.utils.ImmutableArray; 27 | import com.badlogic.gdx.graphics.OrthographicCamera; 28 | import com.badlogic.gdx.graphics.g2d.SpriteBatch; 29 | 30 | public class RenderSystem extends EntitySystem { 31 | private ImmutableArray entities; 32 | 33 | private SpriteBatch batch; 34 | private OrthographicCamera camera; 35 | 36 | private ComponentMapper pm = ComponentMapper.getFor(PositionComponent.class); 37 | private ComponentMapper vm = ComponentMapper.getFor(VisualComponent.class); 38 | 39 | public RenderSystem (OrthographicCamera camera) { 40 | batch = new SpriteBatch(); 41 | 42 | this.camera = camera; 43 | } 44 | 45 | @Override 46 | public void addedToEngine (Engine engine) { 47 | entities = engine.getEntitiesFor(Family.all(PositionComponent.class, VisualComponent.class).get()); 48 | } 49 | 50 | @Override 51 | public void removedFromEngine (Engine engine) { 52 | 53 | } 54 | 55 | @Override 56 | public void update (float deltaTime) { 57 | PositionComponent position; 58 | VisualComponent visual; 59 | 60 | camera.update(); 61 | 62 | batch.begin(); 63 | batch.setProjectionMatrix(camera.combined); 64 | 65 | for (int i = 0; i < entities.size(); ++i) { 66 | Entity e = entities.get(i); 67 | 68 | position = pm.get(e); 69 | visual = vm.get(e); 70 | 71 | batch.draw(visual.region, position.x, position.y); 72 | } 73 | 74 | batch.end(); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /ashley/tests/com/badlogic/ashley/core/ComponentClassFactory.java: -------------------------------------------------------------------------------- 1 | package com.badlogic.ashley.core; 2 | 3 | import org.mockito.asm.ClassWriter; 4 | import org.mockito.asm.MethodVisitor; 5 | import org.mockito.asm.Opcodes; 6 | 7 | /** 8 | * Class loader allowing dynamic {@link Component} class definitions. 9 | * 10 | * Useful for tests that need several different component types. 11 | * 12 | * Adapted from https://dzone.com/articles/fully-dynamic-classes-with-asm 13 | * 14 | * @author mgsx 15 | * 16 | */ 17 | public class ComponentClassFactory extends ClassLoader 18 | { 19 | /** 20 | * create new {@link Component} type 21 | * @param name name of the class to create 22 | * @return created class 23 | */ 24 | @SuppressWarnings("unchecked") 25 | public Class createComponentType(String name){ 26 | 27 | ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); 28 | 29 | String interfacePath = Component.class.getName().replaceAll("\\.", "/"); 30 | 31 | // create public class (default package) implementing Component 32 | 33 | cw.visit(Opcodes.V1_6, // Java 1.6 34 | Opcodes.ACC_PUBLIC, // public class 35 | name, // package and name 36 | null, // signature (null means not generic) 37 | "java/lang/Object", // superclass 38 | new String[]{ interfacePath }); // interfaces 39 | 40 | // create public no-arg constructor 41 | 42 | MethodVisitor con = cw.visitMethod( 43 | Opcodes.ACC_PUBLIC, // public method 44 | "", // method name 45 | "()V", // descriptor 46 | null, // signature (null means not generic) 47 | null); // exceptions (array of strings) 48 | 49 | // define constructor body : call super constructor (java.lang.Object) 50 | 51 | con.visitCode(); // Start the code for this method 52 | con.visitVarInsn(Opcodes.ALOAD, 0); // Load "this" onto the stack 53 | con.visitMethodInsn(Opcodes.INVOKESPECIAL, // Invoke an instance method (non-virtual) 54 | "java/lang/Object", // Class on which the method is defined 55 | "", // Name of the method 56 | "()V"); // Descriptor 57 | con.visitInsn(Opcodes.RETURN); // End the constructor method 58 | con.visitMaxs(1, 1); // Specify max stack and local vars 59 | 60 | // close class definition. 61 | 62 | cw.visitEnd(); 63 | 64 | // load and return class. 65 | byte[] b = cw.toByteArray(); 66 | return (Class)defineClass(name, b, 0, b.length); 67 | } 68 | } -------------------------------------------------------------------------------- /ashley/tests/com/badlogic/ashley/core/ComponentOperationHandlerTests.java: -------------------------------------------------------------------------------- 1 | package com.badlogic.ashley.core; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import org.junit.Test; 6 | 7 | import com.badlogic.ashley.core.ComponentOperationHandler.BooleanInformer; 8 | import com.badlogic.ashley.signals.Listener; 9 | import com.badlogic.ashley.signals.Signal; 10 | 11 | public class ComponentOperationHandlerTests { 12 | 13 | private static class BooleanInformerMock implements BooleanInformer { 14 | public boolean delayed = false; 15 | 16 | @Override 17 | public boolean value () { 18 | return delayed; 19 | } 20 | } 21 | 22 | private static class ComponentSpy implements Listener { 23 | public boolean called; 24 | 25 | @Override 26 | public void receive(Signal signal, Entity object) { 27 | called = true; 28 | } 29 | } 30 | 31 | @Test 32 | public void add() { 33 | ComponentSpy spy = new ComponentSpy(); 34 | BooleanInformerMock informer = new BooleanInformerMock(); 35 | ComponentOperationHandler handler = new ComponentOperationHandler(informer); 36 | 37 | Entity entity = new Entity(); 38 | entity.componentOperationHandler = handler; 39 | entity.componentAdded.add(spy); 40 | 41 | handler.add(entity); 42 | 43 | assertTrue(spy.called); 44 | } 45 | 46 | @Test 47 | public void addDelayed() { 48 | ComponentSpy spy = new ComponentSpy(); 49 | BooleanInformerMock informer = new BooleanInformerMock(); 50 | ComponentOperationHandler handler = new ComponentOperationHandler(informer); 51 | 52 | informer.delayed = true; 53 | 54 | Entity entity = new Entity(); 55 | entity.componentOperationHandler = handler; 56 | entity.componentAdded.add(spy); 57 | 58 | handler.add(entity); 59 | 60 | assertFalse(spy.called); 61 | handler.processOperations(); 62 | assertTrue(spy.called); 63 | } 64 | 65 | @Test 66 | public void remove() { 67 | ComponentSpy spy = new ComponentSpy(); 68 | BooleanInformerMock informer = new BooleanInformerMock(); 69 | ComponentOperationHandler handler = new ComponentOperationHandler(informer); 70 | 71 | Entity entity = new Entity(); 72 | entity.componentOperationHandler = handler; 73 | entity.componentRemoved.add(spy); 74 | 75 | handler.remove(entity); 76 | 77 | assertTrue(spy.called); 78 | } 79 | 80 | @Test 81 | public void removeDelayed() { 82 | ComponentSpy spy = new ComponentSpy(); 83 | BooleanInformerMock informer = new BooleanInformerMock(); 84 | ComponentOperationHandler handler = new ComponentOperationHandler(informer); 85 | 86 | informer.delayed = true; 87 | 88 | Entity entity = new Entity(); 89 | entity.componentOperationHandler = handler; 90 | entity.componentRemoved.add(spy); 91 | 92 | handler.remove(entity); 93 | 94 | assertFalse(spy.called); 95 | handler.processOperations(); 96 | assertTrue(spy.called); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /ashley/src/com/badlogic/ashley/utils/ImmutableArray.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2014 See AUTHORS file. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | ******************************************************************************/ 16 | 17 | package com.badlogic.ashley.utils; 18 | 19 | import java.util.Iterator; 20 | 21 | import com.badlogic.gdx.utils.Array; 22 | import com.badlogic.gdx.utils.Array.ArrayIterable; 23 | 24 | /** 25 | * Wrapper class to treat {@link Array} objects as if they were immutable. However, note that the values could be modified if they 26 | * are mutable. 27 | * @author David Saltares 28 | */ 29 | public class ImmutableArray implements Iterable { 30 | private final Array array; 31 | private ArrayIterable iterable; 32 | 33 | public ImmutableArray() { 34 | this(new Array()); 35 | } 36 | 37 | public ImmutableArray (Array array) { 38 | this.array = array; 39 | } 40 | 41 | public int size () { 42 | return array.size; 43 | } 44 | 45 | public T get (int index) { 46 | return array.get(index); 47 | } 48 | 49 | public boolean contains (T value, boolean identity) { 50 | return array.contains(value, identity); 51 | } 52 | 53 | public int indexOf (T value, boolean identity) { 54 | return array.indexOf(value, identity); 55 | } 56 | 57 | public int lastIndexOf (T value, boolean identity) { 58 | return array.lastIndexOf(value, identity); 59 | } 60 | 61 | public T peek () { 62 | return array.peek(); 63 | } 64 | 65 | public T first () { 66 | return array.first(); 67 | } 68 | 69 | public T random () { 70 | return array.random(); 71 | } 72 | 73 | public T[] toArray () { 74 | return array.toArray(); 75 | } 76 | 77 | public V[] toArray (Class type) { 78 | return array.toArray(type); 79 | } 80 | 81 | public int hashCode() { 82 | return array.hashCode(); 83 | } 84 | 85 | public boolean equals (Object object) { 86 | return array.equals(object); 87 | } 88 | 89 | public String toString () { 90 | return array.toString(); 91 | } 92 | 93 | public String toString (String separator) { 94 | return array.toString(separator); 95 | } 96 | 97 | @Override 98 | public Iterator iterator () { 99 | if (iterable == null) { 100 | iterable = new ArrayIterable(array, false); 101 | } 102 | 103 | return iterable.iterator(); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /tests/src/com/badlogic/ashley/tests/SpeedTest.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2014 See AUTHORS file. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | ******************************************************************************/ 16 | 17 | package com.badlogic.ashley.tests; 18 | 19 | import com.badlogic.ashley.core.Entity; 20 | import com.badlogic.ashley.core.PooledEngine; 21 | import com.badlogic.ashley.tests.components.MovementComponent; 22 | import com.badlogic.ashley.tests.components.PositionComponent; 23 | import com.badlogic.ashley.tests.systems.MovementSystem; 24 | import com.badlogic.ashley.tests.utils.Timer; 25 | import com.badlogic.gdx.utils.Array; 26 | 27 | public class SpeedTest { 28 | public static int NUMBER_ENTITIES = 100000; 29 | 30 | public static void main (String[] args) { 31 | Timer timer = new Timer(); 32 | Array entities = new Array(); 33 | 34 | PooledEngine engine = new PooledEngine(); 35 | 36 | engine.addSystem(new MovementSystem()); 37 | 38 | System.out.println("Number of entities: " + NUMBER_ENTITIES); 39 | 40 | /** Adding entities */ 41 | timer.start("entities"); 42 | 43 | entities.ensureCapacity(NUMBER_ENTITIES); 44 | 45 | for (int i = 0; i < NUMBER_ENTITIES; i++) { 46 | Entity entity = engine.createEntity(); 47 | 48 | entity.add(new MovementComponent(10, 10)); 49 | entity.add(new PositionComponent(0, 0)); 50 | 51 | engine.addEntity(entity); 52 | 53 | entities.add(entity); 54 | } 55 | 56 | System.out.println("Entities added time: " + timer.stop("entities") + "ms"); 57 | 58 | /** Removing components */ 59 | timer.start("componentRemoved"); 60 | 61 | for (Entity e : entities) { 62 | e.remove(PositionComponent.class); 63 | } 64 | 65 | System.out.println("Component removed time: " + timer.stop("componentRemoved") + "ms"); 66 | 67 | /** Adding components */ 68 | timer.start("componentAdded"); 69 | 70 | for (Entity e : entities) { 71 | e.add(new PositionComponent(0, 0)); 72 | } 73 | 74 | System.out.println("Component added time: " + timer.stop("componentAdded") + "ms"); 75 | 76 | /** System processing */ 77 | timer.start("systemProcessing"); 78 | 79 | engine.update(0); 80 | 81 | System.out.println("System processing times " + timer.stop("systemProcessing") + "ms"); 82 | 83 | /** Removing entities */ 84 | timer.start("entitiesRemoved"); 85 | 86 | engine.removeAllEntities(); 87 | 88 | System.out.println("Entity removed time: " + timer.stop("entitiesRemoved") + "ms"); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /ashley/src/com/badlogic/ashley/core/EntitySystem.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2014 See AUTHORS file. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | ******************************************************************************/ 16 | 17 | package com.badlogic.ashley.core; 18 | 19 | /** 20 | * Abstract class for processing sets of {@link Entity} objects. 21 | * @author Stefan Bachmann 22 | */ 23 | public abstract class EntitySystem { 24 | /** Use this to set the priority of the system. Lower means it'll get executed first. */ 25 | public int priority; 26 | 27 | private boolean processing; 28 | private Engine engine; 29 | 30 | /** Default constructor that will initialise an EntitySystem with priority 0. */ 31 | public EntitySystem () { 32 | this(0); 33 | } 34 | 35 | /** 36 | * Initialises the EntitySystem with the priority specified. 37 | * @param priority The priority to execute this system with (lower means higher priority). 38 | */ 39 | public EntitySystem (int priority) { 40 | this.priority = priority; 41 | this.processing = true; 42 | } 43 | 44 | /** 45 | * Called when this EntitySystem is added to an {@link Engine}. 46 | * @param engine The {@link Engine} this system was added to. 47 | */ 48 | public void addedToEngine (Engine engine) { 49 | } 50 | 51 | /** 52 | * Called when this EntitySystem is removed from an {@link Engine}. 53 | * @param engine The {@link Engine} the system was removed from. 54 | */ 55 | public void removedFromEngine (Engine engine) { 56 | } 57 | 58 | /** 59 | * The update method called every tick. 60 | * @param deltaTime The time passed since last frame in seconds. 61 | */ 62 | public void update (float deltaTime) { 63 | } 64 | 65 | /** @return Whether or not the system should be processed. */ 66 | public boolean checkProcessing () { 67 | return processing; 68 | } 69 | 70 | /** Sets whether or not the system should be processed by the {@link Engine}. */ 71 | public void setProcessing (boolean processing) { 72 | this.processing = processing; 73 | } 74 | 75 | /** @return engine instance the system is registered to. 76 | * It will be null if the system is not associated to any engine instance. */ 77 | public Engine getEngine () { 78 | return engine; 79 | } 80 | 81 | final void addedToEngineInternal(Engine engine) { 82 | this.engine = engine; 83 | addedToEngine(engine); 84 | } 85 | 86 | final void removedFromEngineInternal(Engine engine) { 87 | this.engine = null; 88 | removedFromEngine(engine); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![](http://i.imgur.com/w8oAC73.png?1) 2 | 3 | [![GitHub Actions build status](https://img.shields.io/github/workflow/status/libgdx/ashley/Compile%20and%20publish%20snapshot)](https://github.com/libgdx/ashley/actions/workflows/publish_snapshot.yml) 4 | 5 | [![Sonatype Nexus (Releases)](https://img.shields.io/nexus/r/com.badlogicgames.ashley/ashley?nexusVersion=2&server=https%3A%2F%2Foss.sonatype.org&label=release)](https://search.maven.org/artifact/com.badlogicgames.ashley/ashley) 6 | [![Sonatype Nexus (Snapshots)](https://img.shields.io/nexus/s/com.badlogicgames.ashley/ashley?server=https%3A%2F%2Foss.sonatype.org&label=snapshot)](https://oss.sonatype.org/#nexus-search;gav~com.badlogicgames.ashley~ashley) 7 | 8 | 9 | A tiny entity framework written in Java. It's inspired by frameworks like 10 | [Ash](http://www.ashframework.org/) (hence the name) and 11 | [Artemis](http://gamadu.com/artemis/). Ashley tries to be a high-performance 12 | entity framework without the use of black-magic and thus making the API easy 13 | and transparent to use. 14 | 15 | Ashley is awesome, if you don't believe it, check out some [games](https://github.com/libgdx/ashley/wiki/Games-made-with-Ashley) made with it! 16 | 17 | Ashley lives under the [libGDX](https://github.com/libgdx) family but it does not force you to use that specific framework if you do not wish to do so. 18 | 19 | libGDX Discord : [![Discord Chat](https://img.shields.io/discord/348229412858101762?logo=discord)](https://libgdx.com/community/discord/) 20 | 21 | ### Get started 22 | 23 | * [Use Ashley in your project](https://github.com/libgdx/ashley/wiki/Getting-started-with-Ashley) 24 | * [Read the wiki](https://github.com/libgdx/ashley/wiki) 25 | * [Refer to the javadocs](https://javadoc.io/doc/com.badlogicgames.ashley/ashley) 26 | * [Read the examples](https://github.com/libgdx/ashley/tree/master/tests) 27 | 28 | 29 | ### News and community 30 | 31 | Stay up to date in Ashley matters by following [@d_saltares](https://twitter.com/d_saltares) and reading [saltares.com](http://saltares.com). Check the [libGDX](https://libgdx.com/) blog as well for additional updates. 32 | 33 | ### Report issues 34 | 35 | Something not working quite as expected? Do you need a feature that has not been implemented yet? Check the [issue tracker](https://github.com/libgdx/ashley/issues) and add a new one if your problem is not already listed. Please try to provide a detailed description of your problem, including the steps to reproduce it. 36 | 37 | ### Contribute 38 | 39 | Awesome! If you would like to contribute with a new feature or submit a bugfix, fork this repo and send a pull request. Please, make sure all the [unit tests](https://github.com/libgdx/ashley/tree/master/ashley/tests/com/badlogic/ashley) are passing before submitting and add new ones in case you introduced new features. 40 | 41 | ### License 42 | 43 | Ashley is licensed under the [Apache 2 License](https://github.com/libgdx/ashley/blob/master/LICENSE), meaning you 44 | can use it free of charge, without strings attached in commercial and non-commercial projects. We love to 45 | get (non-mandatory) credit in case you release a game or app using Ashley! 46 | 47 | -------------------------------------------------------------------------------- /tests/src/com/badlogic/ashley/tests/RenderSystemTest.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2014 See AUTHORS file. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | ******************************************************************************/ 16 | 17 | package com.badlogic.ashley.tests; 18 | 19 | import com.badlogic.ashley.core.Entity; 20 | import com.badlogic.ashley.core.PooledEngine; 21 | import com.badlogic.ashley.tests.components.MovementComponent; 22 | import com.badlogic.ashley.tests.components.PositionComponent; 23 | import com.badlogic.ashley.tests.components.VisualComponent; 24 | import com.badlogic.ashley.tests.systems.MovementSystem; 25 | import com.badlogic.ashley.tests.systems.RenderSystem; 26 | import com.badlogic.gdx.ApplicationAdapter; 27 | import com.badlogic.gdx.Gdx; 28 | import com.badlogic.gdx.backends.lwjgl.LwjglApplication; 29 | import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration; 30 | import com.badlogic.gdx.graphics.GL20; 31 | import com.badlogic.gdx.graphics.OrthographicCamera; 32 | import com.badlogic.gdx.graphics.Texture; 33 | import com.badlogic.gdx.graphics.g2d.TextureRegion; 34 | import com.badlogic.gdx.math.MathUtils; 35 | 36 | public class RenderSystemTest { 37 | public static void main (String[] args) { 38 | LwjglApplicationConfiguration config = new LwjglApplicationConfiguration(); 39 | config.width = 640; 40 | config.height = 480; 41 | 42 | new LwjglApplication(new MainClass(), config); 43 | } 44 | 45 | public static class MainClass extends ApplicationAdapter { 46 | PooledEngine engine; 47 | 48 | @Override 49 | public void create () { 50 | OrthographicCamera camera = new OrthographicCamera(640, 480); 51 | camera.position.set(320, 240, 0); 52 | camera.update(); 53 | 54 | Texture crateTexture = new Texture("assets/crate.png"); 55 | Texture coinTexture = new Texture("assets/coin.png"); 56 | 57 | engine = new PooledEngine(); 58 | engine.addSystem(new RenderSystem(camera)); 59 | engine.addSystem(new MovementSystem()); 60 | 61 | Entity crate = engine.createEntity(); 62 | crate.add(new PositionComponent(50, 50)); 63 | crate.add(new VisualComponent(new TextureRegion(crateTexture))); 64 | 65 | engine.addEntity(crate); 66 | 67 | TextureRegion coinRegion = new TextureRegion(coinTexture); 68 | 69 | for (int i = 0; i < 100; i++) { 70 | Entity coin = engine.createEntity(); 71 | coin.add(new PositionComponent(MathUtils.random(640), MathUtils.random(480))); 72 | coin.add(new MovementComponent(10.0f, 10.0f)); 73 | coin.add(new VisualComponent(coinRegion)); 74 | engine.addEntity(coin); 75 | } 76 | } 77 | 78 | @Override 79 | public void render () { 80 | Gdx.gl.glClearColor(0, 0, 0, 1); 81 | Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); 82 | 83 | engine.update(Gdx.graphics.getDeltaTime()); 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /ashley/src/com/badlogic/ashley/systems/IntervalIteratingSystem.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2014 See AUTHORS file. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | ******************************************************************************/ 16 | 17 | package com.badlogic.ashley.systems; 18 | 19 | import com.badlogic.ashley.core.Engine; 20 | import com.badlogic.ashley.core.Entity; 21 | import com.badlogic.ashley.core.EntitySystem; 22 | import com.badlogic.ashley.core.Family; 23 | import com.badlogic.ashley.utils.ImmutableArray; 24 | 25 | /** 26 | * A simple {@link EntitySystem} that processes a {@link Family} of entities not once per frame, but after a given interval. 27 | * Entity processing logic should be placed in {@link IntervalIteratingSystem#processEntity(Entity)}. 28 | * @author David Saltares 29 | */ 30 | public abstract class IntervalIteratingSystem extends IntervalSystem { 31 | private Family family; 32 | private ImmutableArray entities; 33 | 34 | /** 35 | * @param family represents the collection of family the system should process 36 | * @param interval time in seconds between calls to {@link IntervalIteratingSystem#updateInterval()}. 37 | */ 38 | public IntervalIteratingSystem (Family family, float interval) { 39 | this(family, interval, 0); 40 | } 41 | 42 | /** 43 | * @param family represents the collection of family the system should process 44 | * @param interval time in seconds between calls to {@link IntervalIteratingSystem#updateInterval()}. 45 | * @param priority 46 | */ 47 | public IntervalIteratingSystem (Family family, float interval, int priority) { 48 | super(interval, priority); 49 | this.family = family; 50 | } 51 | 52 | @Override 53 | public void addedToEngine (Engine engine) { 54 | entities = engine.getEntitiesFor(family); 55 | } 56 | 57 | @Override 58 | protected void updateInterval () { 59 | startProcessing(); 60 | for (int i = 0; i < entities.size(); ++i) { 61 | processEntity(entities.get(i)); 62 | } 63 | endProcessing(); 64 | } 65 | 66 | /** 67 | * @return set of entities processed by the system 68 | */ 69 | public ImmutableArray getEntities () { 70 | return entities; 71 | } 72 | 73 | /** 74 | * @return the Family used when the system was created 75 | */ 76 | public Family getFamily () { 77 | return family; 78 | } 79 | 80 | /** 81 | * The user should place the entity processing logic here. 82 | * @param entity 83 | */ 84 | protected abstract void processEntity (Entity entity); 85 | 86 | /** 87 | * This method is called once on every update call of the EntitySystem, before entity processing begins. Override this method to 88 | * implement your specific startup conditions. 89 | */ 90 | public void startProcessing() {} 91 | 92 | /** 93 | * This method is called once on every update call of the EntitySystem after entity processing is complete. Override this method to 94 | * implement your specific end conditions. 95 | */ 96 | public void endProcessing() {} 97 | } 98 | -------------------------------------------------------------------------------- /ashley/tests/com/badlogic/ashley/systems/IntervalIteratingTest.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2014 See AUTHORS file. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | ******************************************************************************/ 16 | 17 | package com.badlogic.ashley.systems; 18 | 19 | import org.junit.Test; 20 | 21 | import com.badlogic.ashley.core.Component; 22 | import com.badlogic.ashley.core.ComponentMapper; 23 | import com.badlogic.ashley.core.Engine; 24 | import com.badlogic.ashley.core.Entity; 25 | import com.badlogic.ashley.core.Family; 26 | import com.badlogic.ashley.utils.ImmutableArray; 27 | 28 | import static org.junit.Assert.*; 29 | 30 | public class IntervalIteratingTest { 31 | private static final float deltaTime = 0.1f; 32 | 33 | private static class IntervalComponentSpy implements Component { 34 | public int numUpdates = 0; 35 | } 36 | 37 | private static class IntervalIteratingSystemSpy extends IntervalIteratingSystem { 38 | private ComponentMapper im; 39 | public int numStartProcessing; 40 | public int numEndProcessing; 41 | 42 | 43 | public IntervalIteratingSystemSpy () { 44 | super(Family.all(IntervalComponentSpy.class).get(), deltaTime * 2.0f); 45 | 46 | im = ComponentMapper.getFor(IntervalComponentSpy.class); 47 | } 48 | 49 | @Override 50 | public void startProcessing() { 51 | numStartProcessing++; 52 | } 53 | 54 | @Override 55 | protected void processEntity (Entity entity) { 56 | im.get(entity).numUpdates++; 57 | } 58 | 59 | @Override 60 | public void endProcessing() { 61 | numEndProcessing++; 62 | } 63 | } 64 | 65 | @Test 66 | public void intervalSystem () { 67 | Engine engine = new Engine(); 68 | IntervalIteratingSystemSpy intervalSystemSpy = new IntervalIteratingSystemSpy(); 69 | ImmutableArray entities = engine.getEntitiesFor(Family.all(IntervalComponentSpy.class).get()); 70 | ComponentMapper im = ComponentMapper.getFor(IntervalComponentSpy.class); 71 | 72 | engine.addSystem(intervalSystemSpy); 73 | 74 | for (int i = 0; i < 10; ++i) { 75 | Entity entity = new Entity(); 76 | entity.add(new IntervalComponentSpy()); 77 | engine.addEntity(entity); 78 | } 79 | 80 | for (int i = 1; i <= 10; ++i) { 81 | engine.update(deltaTime); 82 | 83 | for (int j = 0; j < entities.size(); ++j) { 84 | assertEquals(i / 2, im.get(entities.get(j)).numUpdates); 85 | } 86 | } 87 | } 88 | 89 | @Test 90 | public void processingUtilityFunctions() { 91 | final Engine engine = new Engine(); 92 | 93 | final IntervalIteratingSystemSpy system = new IntervalIteratingSystemSpy(); 94 | 95 | engine.addSystem(system); 96 | 97 | engine.update(deltaTime); 98 | assertEquals(0, system.numStartProcessing); 99 | assertEquals(0, system.numEndProcessing); 100 | 101 | engine.update(deltaTime); 102 | assertEquals(1, system.numStartProcessing); 103 | assertEquals(1, system.numEndProcessing); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /ashley/src/com/badlogic/ashley/core/ComponentType.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2014 See AUTHORS file. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | ******************************************************************************/ 16 | 17 | package com.badlogic.ashley.core; 18 | 19 | import com.badlogic.gdx.utils.Bits; 20 | import com.badlogic.gdx.utils.ObjectMap; 21 | 22 | /** 23 | * Uniquely identifies a {@link Component} sub-class. It assigns them an index which is used internally for fast comparison and 24 | * retrieval. See {@link Family} and {@link Entity}. ComponentType is a package protected class. You cannot instantiate a 25 | * ComponentType. They can only be accessed via {@link #getIndexFor(Class)}. Each component class will always 26 | * return the same instance of ComponentType. 27 | * @author Stefan Bachmann 28 | */ 29 | public final class ComponentType { 30 | private static ObjectMap, ComponentType> assignedComponentTypes = new ObjectMap, ComponentType>(); 31 | private static int typeIndex = 0; 32 | 33 | private final int index; 34 | 35 | private ComponentType () { 36 | index = typeIndex++; 37 | } 38 | 39 | /** @return This ComponentType's unique index */ 40 | public int getIndex () { 41 | return index; 42 | } 43 | 44 | /** 45 | * @param componentType The {@link Component} class 46 | * @return A ComponentType matching the Component Class 47 | */ 48 | public static ComponentType getFor (Class componentType) { 49 | ComponentType type = assignedComponentTypes.get(componentType); 50 | 51 | if (type == null) { 52 | type = new ComponentType(); 53 | assignedComponentTypes.put(componentType, type); 54 | } 55 | 56 | return type; 57 | } 58 | 59 | /** 60 | * Quick helper method. The same could be done via {@link ComponentType.getFor(Class)}. 61 | * @param componentType The {@link Component} class 62 | * @return The index for the specified {@link Component} Class 63 | */ 64 | public static int getIndexFor (Class componentType) { 65 | return getFor(componentType).getIndex(); 66 | } 67 | 68 | /** 69 | * @param componentTypes list of {@link Component} classes 70 | * @return Bits representing the collection of components for quick comparison and matching. See 71 | * {@link Family#getFor(Bits, Bits, Bits)}. 72 | */ 73 | public static Bits getBitsFor (Class... componentTypes) { 74 | Bits bits = new Bits(); 75 | 76 | int typesLength = componentTypes.length; 77 | for (int i = 0; i < typesLength; i++) { 78 | bits.set(ComponentType.getIndexFor(componentTypes[i])); 79 | } 80 | 81 | return bits; 82 | } 83 | 84 | @Override 85 | public int hashCode () { 86 | return index; 87 | } 88 | 89 | @Override 90 | public boolean equals (Object obj) { 91 | if (this == obj) return true; 92 | if (obj == null) return false; 93 | if (getClass() != obj.getClass()) return false; 94 | ComponentType other = (ComponentType)obj; 95 | return index == other.index; 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /publish.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'maven' 2 | apply plugin: 'signing' 3 | 4 | group = 'com.badlogicgames.ashley' 5 | version = '1.8.0' 6 | ext.packaging = 'jar' 7 | 8 | def isDevBuild 9 | def isCiBuild 10 | def isReleaseBuild 11 | 12 | def sonatypeRepositoryUrl 13 | 14 | //set build variables based on build type (release, continuous integration, development) 15 | if(hasProperty("RELEASE")) { 16 | isReleaseBuild = true 17 | sonatypeRepositoryUrl = "https://oss.sonatype.org/service/local/staging/deploy/maven2/" 18 | println "Performing release build" 19 | } else if (hasProperty("SNAPSHOT")) { 20 | isCiBuild = true 21 | version += "-SNAPSHOT" 22 | sonatypeRepositoryUrl = "https://oss.sonatype.org/content/repositories/snapshots/" 23 | println "Performing snapshot build" 24 | } else { 25 | isDevBuild = true 26 | println "Performing local build" 27 | } 28 | 29 | def getRepositoryUsername = { 30 | return project.hasProperty('NEXUS_USERNAME') ? NEXUS_USERNAME : "$System.env.NEXUS_USERNAME" 31 | } 32 | 33 | def getRepositoryPassword = { 34 | return project.hasProperty('NEXUS_PASSWORD') ? NEXUS_PASSWORD : "$System.env.NEXUS_PASSWORD" 35 | } 36 | 37 | repositories { 38 | mavenCentral() 39 | } 40 | 41 | task artifactDocs(type: Jar, dependsOn: javadoc) { 42 | classifier = 'javadoc' 43 | from 'build/docs/javadoc' 44 | } 45 | 46 | task artifactSources(type: Jar) { 47 | from sourceSets.main.allSource 48 | classifier = 'sources' 49 | } 50 | 51 | artifacts { 52 | archives jar 53 | archives artifactDocs 54 | archives artifactSources 55 | } 56 | 57 | if(isReleaseBuild) { 58 | signing { 59 | useGpgCmd() 60 | sign configurations.archives 61 | } 62 | } else { 63 | task signArchives { 64 | // do nothing 65 | } 66 | } 67 | 68 | uploadArchives { 69 | repositories { 70 | if (isDevBuild) { 71 | mavenLocal() 72 | } 73 | else { 74 | mavenDeployer { 75 | if(isReleaseBuild) { 76 | beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) } 77 | } 78 | 79 | repository(url: sonatypeRepositoryUrl) { 80 | authentication(userName: getRepositoryUsername(), password: getRepositoryPassword()) 81 | } 82 | 83 | pom.version = version 84 | pom.packaging = 'jar' 85 | 86 | pom.project { 87 | name 'Ashley' 88 | description 'Ashley, a minimal entity framework inspired by Ash and Artemis' 89 | url 'https://github.com/libgdx/ashley' 90 | 91 | scm { 92 | url 'scm:git@github.com:libgdx/ashley.git' 93 | connection 'scm:git@github.com:libgdx/ashley.git' 94 | developerConnection 'scm:git@github.com:libgdx/ashley.git' 95 | } 96 | 97 | licenses { 98 | license { 99 | name 'The Apache Software License, Version 2.0' 100 | url 'http://www.apache.org/licenses/LICENSE-2.0.txt' 101 | distribution 'repo' 102 | } 103 | } 104 | 105 | developers { 106 | developer { 107 | id 'stbachmann' 108 | name 'Stefan Bachmann' 109 | } 110 | developer { 111 | id 'saltares' 112 | name 'David Saltares' 113 | } 114 | } 115 | } 116 | } 117 | } 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /ashley/src/com/badlogic/ashley/systems/IteratingSystem.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2014 See AUTHORS file. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | ******************************************************************************/ 16 | 17 | package com.badlogic.ashley.systems; 18 | 19 | import com.badlogic.ashley.core.Engine; 20 | import com.badlogic.ashley.core.Entity; 21 | import com.badlogic.ashley.core.EntitySystem; 22 | import com.badlogic.ashley.core.Family; 23 | import com.badlogic.ashley.utils.ImmutableArray; 24 | 25 | /** 26 | * A simple EntitySystem that iterates over each entity and calls processEntity() for each entity every time the EntitySystem is 27 | * updated. This is really just a convenience class as most systems iterate over a list of entities. 28 | * @author Stefan Bachmann 29 | */ 30 | public abstract class IteratingSystem extends EntitySystem { 31 | private Family family; 32 | private ImmutableArray entities; 33 | 34 | /** 35 | * Instantiates a system that will iterate over the entities described by the Family. 36 | * @param family The family of entities iterated over in this System 37 | */ 38 | public IteratingSystem (Family family) { 39 | this(family, 0); 40 | } 41 | 42 | /** 43 | * Instantiates a system that will iterate over the entities described by the Family, with a specific priority. 44 | * @param family The family of entities iterated over in this System 45 | * @param priority The priority to execute this system with (lower means higher priority) 46 | */ 47 | public IteratingSystem (Family family, int priority) { 48 | super(priority); 49 | 50 | this.family = family; 51 | } 52 | 53 | @Override 54 | public void addedToEngine (Engine engine) { 55 | entities = engine.getEntitiesFor(family); 56 | } 57 | 58 | @Override 59 | public void removedFromEngine (Engine engine) { 60 | entities = null; 61 | } 62 | 63 | @Override 64 | public void update (float deltaTime) { 65 | startProcessing(); 66 | for (int i = 0; i < entities.size(); ++i) { 67 | processEntity(entities.get(i), deltaTime); 68 | } 69 | endProcessing(); 70 | } 71 | 72 | /** 73 | * @return set of entities processed by the system 74 | */ 75 | public ImmutableArray getEntities () { 76 | return entities; 77 | } 78 | 79 | /** 80 | * @return the Family used when the system was created 81 | */ 82 | public Family getFamily () { 83 | return family; 84 | } 85 | 86 | /** 87 | * This method is called on every entity on every update call of the EntitySystem. Override this to implement your system's 88 | * specific processing. 89 | * @param entity The current Entity being processed 90 | * @param deltaTime The delta time between the last and current frame 91 | */ 92 | protected abstract void processEntity (Entity entity, float deltaTime); 93 | 94 | /** 95 | * This method is called once on every update call of the EntitySystem, before entity processing begins. Override this method to 96 | * implement your specific startup conditions. 97 | */ 98 | public void startProcessing() {} 99 | 100 | /** 101 | * This method is called once on every update call of the EntitySystem after entity processing is complete. Override this method to 102 | * implement your specific end conditions. 103 | */ 104 | public void endProcessing() {} 105 | } 106 | -------------------------------------------------------------------------------- /benchmarks/src/main/java/com/badlogic/ashley/benchmark/ashley/AshleyBenchmark.java: -------------------------------------------------------------------------------- 1 | 2 | package com.badlogic.ashley.benchmark.ashley; 3 | 4 | import org.junit.BeforeClass; 5 | import org.junit.Test; 6 | 7 | import com.badlogic.ashley.benchmark.Constants; 8 | import com.badlogic.ashley.benchmark.Constants.ComponentType; 9 | import com.badlogic.ashley.benchmark.ashley.components.MovementComponent; 10 | import com.badlogic.ashley.benchmark.ashley.components.PositionComponent; 11 | import com.badlogic.ashley.benchmark.ashley.components.RadiusComponent; 12 | import com.badlogic.ashley.benchmark.ashley.components.StateComponent; 13 | import com.badlogic.ashley.benchmark.ashley.systems.CollisionSystem; 14 | import com.badlogic.ashley.benchmark.ashley.systems.MovementSystem; 15 | import com.badlogic.ashley.benchmark.ashley.systems.RemovalSystem; 16 | import com.badlogic.ashley.benchmark.ashley.systems.StateSystem; 17 | import com.badlogic.ashley.core.Engine; 18 | import com.badlogic.ashley.core.Entity; 19 | import com.badlogic.gdx.math.MathUtils; 20 | import com.carrotsearch.junitbenchmarks.AbstractBenchmark; 21 | import com.carrotsearch.junitbenchmarks.BenchmarkOptions; 22 | 23 | public class AshleyBenchmark extends AbstractBenchmark { 24 | private static Engine engineSmall; 25 | private static Engine engineMedium; 26 | private static Engine engineBig; 27 | 28 | @BeforeClass 29 | public static void prepare () { 30 | engineSmall = prepareEngine(Constants.ENTITIES_SMALL_TEST); 31 | engineMedium = prepareEngine(Constants.ENTITIES_MEDIUM_TEST); 32 | engineBig = prepareEngine(Constants.ENTITIES_BIG_TEST); 33 | } 34 | 35 | @BenchmarkOptions(benchmarkRounds = Constants.BENCHMARK_ROUNDS, warmupRounds = Constants.WARMUP_ROUNDS) 36 | @Test 37 | public void ashleySmallTest () { 38 | runEngineTest(engineSmall); 39 | } 40 | 41 | @BenchmarkOptions(benchmarkRounds = Constants.BENCHMARK_ROUNDS, warmupRounds = Constants.WARMUP_ROUNDS) 42 | @Test 43 | public void ashleyMediumTest () { 44 | runEngineTest(engineMedium); 45 | } 46 | 47 | @BenchmarkOptions(benchmarkRounds = Constants.BENCHMARK_ROUNDS, warmupRounds = Constants.WARMUP_ROUNDS) 48 | @Test 49 | public void ashleyBigTest () { 50 | runEngineTest(engineBig); 51 | } 52 | 53 | private void runEngineTest (Engine engine) { 54 | for (int i = 0; i < Constants.FRAMES; ++i) { 55 | engine.update(Constants.DELTA_TIME); 56 | } 57 | } 58 | 59 | private static Engine prepareEngine (int numEntities) { 60 | Engine engine = new Engine(); 61 | 62 | engine.addSystem(new MovementSystem()); 63 | engine.addSystem(new StateSystem()); 64 | engine.addSystem(new CollisionSystem()); 65 | engine.addSystem(new RemovalSystem()); 66 | 67 | for (int i = 0; i < numEntities; ++i) { 68 | Entity entity = new Entity(); 69 | 70 | if (Constants.shouldHaveComponent(ComponentType.POSITION, i)) { 71 | PositionComponent pos = new PositionComponent(); 72 | pos.pos.x = MathUtils.random(Constants.MIN_POS, Constants.MAX_POS); 73 | pos.pos.y = MathUtils.random(Constants.MIN_POS, Constants.MAX_POS); 74 | entity.add(pos); 75 | } 76 | 77 | if (Constants.shouldHaveComponent(ComponentType.MOVEMENT, i)) { 78 | MovementComponent mov = new MovementComponent(); 79 | mov.velocity.x = MathUtils.random(Constants.MIN_VEL, Constants.MAX_VEL); 80 | mov.velocity.y = MathUtils.random(Constants.MIN_VEL, Constants.MAX_VEL); 81 | mov.accel.x = MathUtils.random(Constants.MIN_ACC, Constants.MAX_ACC); 82 | mov.accel.y = MathUtils.random(Constants.MIN_ACC, Constants.MAX_ACC); 83 | 84 | entity.add(mov); 85 | } 86 | 87 | if (Constants.shouldHaveComponent(ComponentType.RADIUS, i)) { 88 | RadiusComponent rad = new RadiusComponent(); 89 | rad.radius = MathUtils.random(Constants.MIN_RADIUS, Constants.MAX_RADIUS); 90 | entity.add(rad); 91 | } 92 | 93 | if (Constants.shouldHaveComponent(ComponentType.STATE, i)) { 94 | entity.add(new StateComponent()); 95 | } 96 | 97 | engine.addEntity(entity); 98 | } 99 | 100 | return engine; 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /benchmarks/src/main/java/com/badlogic/ashley/benchmark/artemis/ArtemisBenchmark.java: -------------------------------------------------------------------------------- 1 | 2 | package com.badlogic.ashley.benchmark.artemis; 3 | 4 | import org.junit.BeforeClass; 5 | import org.junit.Test; 6 | 7 | import com.artemis.Entity; 8 | import com.artemis.World; 9 | import com.badlogic.ashley.benchmark.Constants; 10 | import com.badlogic.ashley.benchmark.Constants.ComponentType; 11 | import com.badlogic.ashley.benchmark.artemis.components.MovementComponent; 12 | import com.badlogic.ashley.benchmark.artemis.components.PositionComponent; 13 | import com.badlogic.ashley.benchmark.artemis.components.RadiusComponent; 14 | import com.badlogic.ashley.benchmark.artemis.components.StateComponent; 15 | import com.badlogic.ashley.benchmark.artemis.systems.CollisionSystem; 16 | import com.badlogic.ashley.benchmark.artemis.systems.MovementSystem; 17 | import com.badlogic.ashley.benchmark.artemis.systems.RemovalSystem; 18 | import com.badlogic.ashley.benchmark.artemis.systems.StateSystem; 19 | import com.badlogic.gdx.math.MathUtils; 20 | import com.carrotsearch.junitbenchmarks.AbstractBenchmark; 21 | import com.carrotsearch.junitbenchmarks.BenchmarkOptions; 22 | 23 | public class ArtemisBenchmark extends AbstractBenchmark { 24 | private static World worldSmall; 25 | private static World worldMedium; 26 | private static World worldBig; 27 | 28 | @BeforeClass 29 | public static void prepare () { 30 | worldSmall = prepareWorld(Constants.ENTITIES_SMALL_TEST); 31 | worldMedium = prepareWorld(Constants.ENTITIES_MEDIUM_TEST); 32 | worldBig = prepareWorld(Constants.ENTITIES_BIG_TEST); 33 | } 34 | 35 | @BenchmarkOptions(benchmarkRounds = Constants.BENCHMARK_ROUNDS, warmupRounds = Constants.WARMUP_ROUNDS) 36 | @Test 37 | public void worldSmallTest () { 38 | runWorldTest(worldSmall); 39 | } 40 | 41 | @BenchmarkOptions(benchmarkRounds = Constants.BENCHMARK_ROUNDS, warmupRounds = Constants.WARMUP_ROUNDS) 42 | @Test 43 | public void worldMediumTest () { 44 | runWorldTest(worldMedium); 45 | } 46 | 47 | @BenchmarkOptions(benchmarkRounds = Constants.BENCHMARK_ROUNDS, warmupRounds = Constants.WARMUP_ROUNDS) 48 | @Test 49 | public void worldBigTest () { 50 | runWorldTest(worldBig); 51 | } 52 | 53 | private void runWorldTest (World world) { 54 | for (int i = 0; i < Constants.FRAMES; ++i) { 55 | world.setDelta(Constants.DELTA_TIME); 56 | world.process(); 57 | } 58 | } 59 | 60 | private static World prepareWorld (int numEntities) { 61 | World world = new World(); 62 | 63 | world.setSystem(new MovementSystem()); 64 | world.setSystem(new StateSystem()); 65 | world.setSystem(new CollisionSystem()); 66 | world.setSystem(new RemovalSystem()); 67 | 68 | world.initialize(); 69 | 70 | for (int i = 0; i < numEntities; ++i) { 71 | Entity entity = world.createEntity(); 72 | 73 | if (Constants.shouldHaveComponent(ComponentType.POSITION, i)) { 74 | PositionComponent pos = new PositionComponent(); 75 | pos.pos.x = MathUtils.random(Constants.MIN_POS, Constants.MAX_POS); 76 | pos.pos.y = MathUtils.random(Constants.MIN_POS, Constants.MAX_POS); 77 | entity.addComponent(pos); 78 | } 79 | 80 | if (Constants.shouldHaveComponent(ComponentType.MOVEMENT, i)) { 81 | MovementComponent mov = new MovementComponent(); 82 | mov.velocity.x = MathUtils.random(Constants.MIN_VEL, Constants.MAX_VEL); 83 | mov.velocity.y = MathUtils.random(Constants.MIN_VEL, Constants.MAX_VEL); 84 | mov.accel.x = MathUtils.random(Constants.MIN_ACC, Constants.MAX_ACC); 85 | mov.accel.y = MathUtils.random(Constants.MIN_ACC, Constants.MAX_ACC); 86 | 87 | entity.addComponent(mov); 88 | } 89 | 90 | if (Constants.shouldHaveComponent(ComponentType.RADIUS, i)) { 91 | RadiusComponent rad = new RadiusComponent(); 92 | rad.radius = MathUtils.random(Constants.MIN_RADIUS, Constants.MAX_RADIUS); 93 | entity.addComponent(rad); 94 | } 95 | 96 | if (Constants.shouldHaveComponent(ComponentType.STATE, i)) { 97 | entity.addComponent(new StateComponent()); 98 | } 99 | 100 | world.addEntity(entity); 101 | } 102 | 103 | return world; 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /tests/src/com/badlogic/ashley/tests/BasicTest.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2014 See AUTHORS file. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | ******************************************************************************/ 16 | 17 | package com.badlogic.ashley.tests; 18 | 19 | import com.badlogic.ashley.core.ComponentMapper; 20 | import com.badlogic.ashley.core.Engine; 21 | import com.badlogic.ashley.core.Entity; 22 | import com.badlogic.ashley.core.EntityListener; 23 | import com.badlogic.ashley.core.EntitySystem; 24 | import com.badlogic.ashley.core.Family; 25 | import com.badlogic.ashley.core.PooledEngine; 26 | import com.badlogic.ashley.tests.components.MovementComponent; 27 | import com.badlogic.ashley.tests.components.PositionComponent; 28 | import com.badlogic.ashley.utils.ImmutableArray; 29 | 30 | public class BasicTest { 31 | 32 | public static void main (String[] args) { 33 | PooledEngine engine = new PooledEngine(); 34 | 35 | MovementSystem movementSystem = new MovementSystem(); 36 | PositionSystem positionSystem = new PositionSystem(); 37 | 38 | engine.addSystem(movementSystem); 39 | engine.addSystem(positionSystem); 40 | 41 | Listener listener = new Listener(); 42 | engine.addEntityListener(listener); 43 | 44 | for (int i = 0; i < 10; i++) { 45 | Entity entity = engine.createEntity(); 46 | entity.add(new PositionComponent(10, 0)); 47 | if (i > 5) entity.add(new MovementComponent(10, 2)); 48 | 49 | engine.addEntity(entity); 50 | } 51 | 52 | log("MovementSystem has: " + movementSystem.entities.size() + " entities."); 53 | log("PositionSystem has: " + positionSystem.entities.size() + " entities."); 54 | 55 | for (int i = 0; i < 10; i++) { 56 | engine.update(0.25f); 57 | 58 | if (i > 5) engine.removeSystem(movementSystem); 59 | } 60 | 61 | engine.removeEntityListener(listener); 62 | } 63 | 64 | public static class PositionSystem extends EntitySystem { 65 | public ImmutableArray entities; 66 | 67 | @Override 68 | public void addedToEngine (Engine engine) { 69 | entities = engine.getEntitiesFor(Family.all(PositionComponent.class).get()); 70 | log("PositionSystem added to engine."); 71 | } 72 | 73 | @Override 74 | public void removedFromEngine (Engine engine) { 75 | log("PositionSystem removed from engine."); 76 | entities = null; 77 | } 78 | } 79 | 80 | public static class MovementSystem extends EntitySystem { 81 | public ImmutableArray entities; 82 | 83 | private ComponentMapper pm = ComponentMapper.getFor(PositionComponent.class); 84 | private ComponentMapper mm = ComponentMapper.getFor(MovementComponent.class); 85 | 86 | @Override 87 | public void addedToEngine (Engine engine) { 88 | entities = engine.getEntitiesFor(Family.all(PositionComponent.class, MovementComponent.class).get()); 89 | log("MovementSystem added to engine."); 90 | } 91 | 92 | @Override 93 | public void removedFromEngine (Engine engine) { 94 | log("MovementSystem removed from engine."); 95 | entities = null; 96 | } 97 | 98 | @Override 99 | public void update (float deltaTime) { 100 | 101 | for (int i = 0; i < entities.size(); ++i) { 102 | Entity e = entities.get(i); 103 | 104 | PositionComponent p = pm.get(e); 105 | MovementComponent m = mm.get(e); 106 | 107 | p.x += m.velocityX * deltaTime; 108 | p.y += m.velocityY * deltaTime; 109 | } 110 | 111 | log(entities.size() + " Entities updated in MovementSystem."); 112 | } 113 | } 114 | 115 | public static class Listener implements EntityListener { 116 | 117 | @Override 118 | public void entityAdded (Entity entity) { 119 | log("Entity added " + entity); 120 | } 121 | 122 | @Override 123 | public void entityRemoved (Entity entity) { 124 | log("Entity removed " + entity); 125 | } 126 | } 127 | 128 | public static void log (String string) { 129 | System.out.println(string); 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /ashley/src/com/badlogic/ashley/core/EntityManager.java: -------------------------------------------------------------------------------- 1 | package com.badlogic.ashley.core; 2 | 3 | 4 | import com.badlogic.ashley.utils.ImmutableArray; 5 | import com.badlogic.gdx.utils.Array; 6 | import com.badlogic.gdx.utils.ObjectSet; 7 | import com.badlogic.gdx.utils.Pool; 8 | 9 | class EntityManager { 10 | private EntityListener listener; 11 | private Array entities = new Array(false, 16); 12 | private ObjectSet entitySet = new ObjectSet(); 13 | private ImmutableArray immutableEntities = new ImmutableArray(entities); 14 | private Array pendingOperations = new Array(false, 16); 15 | private EntityOperationPool entityOperationPool = new EntityOperationPool(); 16 | 17 | public EntityManager(EntityListener listener) { 18 | this.listener = listener; 19 | } 20 | 21 | public void addEntity(Entity entity){ 22 | addEntity(entity, false); 23 | } 24 | 25 | public void addEntity(Entity entity, boolean delayed){ 26 | entity.scheduledForRemoval = false; 27 | if (delayed) { 28 | EntityOperation operation = entityOperationPool.obtain(); 29 | operation.entity = entity; 30 | operation.type = EntityOperation.Type.Add; 31 | pendingOperations.add(operation); 32 | } 33 | else { 34 | addEntityInternal(entity); 35 | } 36 | } 37 | 38 | public void removeEntity(Entity entity){ 39 | removeEntity(entity, false); 40 | } 41 | 42 | public void removeEntity(Entity entity, boolean delayed){ 43 | if (delayed) { 44 | if(entity.scheduledForRemoval) { 45 | return; 46 | } 47 | entity.scheduledForRemoval = true; 48 | EntityOperation operation = entityOperationPool.obtain(); 49 | operation.entity = entity; 50 | operation.type = EntityOperation.Type.Remove; 51 | pendingOperations.add(operation); 52 | } 53 | else { 54 | removeEntityInternal(entity); 55 | } 56 | } 57 | 58 | public void removeAllEntities() { 59 | removeAllEntities(immutableEntities); 60 | } 61 | 62 | public void removeAllEntities(boolean delayed) { 63 | removeAllEntities(immutableEntities, delayed); 64 | } 65 | 66 | public void removeAllEntities(ImmutableArray entities) { 67 | removeAllEntities(entities, false); 68 | } 69 | 70 | public void removeAllEntities(ImmutableArray entities, boolean delayed) { 71 | if (delayed) { 72 | for(Entity entity: entities) { 73 | entity.scheduledForRemoval = true; 74 | } 75 | EntityOperation operation = entityOperationPool.obtain(); 76 | operation.type = EntityOperation.Type.RemoveAll; 77 | operation.entities = entities; 78 | pendingOperations.add(operation); 79 | } 80 | else { 81 | while(entities.size() > 0) { 82 | removeEntity(entities.first(), false); 83 | } 84 | } 85 | } 86 | 87 | public ImmutableArray getEntities() { 88 | return immutableEntities; 89 | } 90 | 91 | public boolean hasPendingOperations() { 92 | return pendingOperations.size > 0; 93 | } 94 | 95 | public void processPendingOperations() { 96 | for (int i = 0; i < pendingOperations.size; ++i) { 97 | EntityOperation operation = pendingOperations.get(i); 98 | 99 | switch(operation.type) { 100 | case Add: addEntityInternal(operation.entity); break; 101 | case Remove: removeEntityInternal(operation.entity); break; 102 | case RemoveAll: 103 | while(operation.entities.size() > 0) { 104 | removeEntityInternal(operation.entities.first()); 105 | } 106 | break; 107 | default: 108 | throw new AssertionError("Unexpected EntityOperation type"); 109 | } 110 | 111 | entityOperationPool.free(operation); 112 | } 113 | 114 | pendingOperations.clear(); 115 | } 116 | 117 | protected void removeEntityInternal(Entity entity) { 118 | boolean removed = entitySet.remove(entity); 119 | 120 | if (removed) { 121 | entity.scheduledForRemoval = false; 122 | entity.removing = true; 123 | entities.removeValue(entity, true); 124 | listener.entityRemoved(entity); 125 | entity.removing = false; 126 | } 127 | } 128 | 129 | protected void addEntityInternal(Entity entity) { 130 | if (entitySet.contains(entity)) { 131 | throw new IllegalArgumentException("Entity is already registered " + entity); 132 | } 133 | 134 | entities.add(entity); 135 | entitySet.add(entity); 136 | 137 | listener.entityAdded(entity); 138 | } 139 | 140 | private static class EntityOperation implements Pool.Poolable { 141 | public enum Type { 142 | Add, 143 | Remove, 144 | RemoveAll 145 | } 146 | 147 | public Type type; 148 | public Entity entity; 149 | public ImmutableArray entities; 150 | 151 | @Override 152 | public void reset() { 153 | entity = null; 154 | } 155 | } 156 | 157 | private static class EntityOperationPool extends Pool { 158 | @Override 159 | protected EntityOperation newObject() { 160 | return new EntityOperation(); 161 | } 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /ashley/tests/com/badlogic/ashley/signals/SignalTests.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2014 See AUTHORS file. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | ******************************************************************************/ 16 | 17 | package com.badlogic.ashley.signals; 18 | 19 | import static org.junit.Assert.*; 20 | 21 | import org.junit.Test; 22 | 23 | import com.badlogic.ashley.signals.Listener; 24 | import com.badlogic.ashley.signals.Signal; 25 | import com.badlogic.gdx.utils.Array; 26 | 27 | public class SignalTests { 28 | 29 | private static class Dummy { 30 | 31 | } 32 | 33 | private static class ListenerMock implements Listener { 34 | 35 | public int count = 0; 36 | 37 | @Override 38 | public void receive (Signal signal, Dummy object) { 39 | ++count; 40 | 41 | assertNotNull(signal); 42 | assertNotNull(object); 43 | } 44 | } 45 | 46 | private static class RemoveWhileDispatchListenerMock implements Listener { 47 | public int count = 0; 48 | 49 | @Override 50 | public void receive (Signal signal, Dummy object) { 51 | ++count; 52 | signal.remove(this); 53 | } 54 | } 55 | 56 | @Test 57 | public void addListenerAndDispatch () { 58 | Dummy dummy = new Dummy(); 59 | Signal signal = new Signal(); 60 | ListenerMock listener = new ListenerMock(); 61 | signal.add(listener); 62 | 63 | for (int i = 0; i < 10; ++i) { 64 | assertEquals(i, listener.count); 65 | signal.dispatch(dummy); 66 | assertEquals(i + 1, listener.count); 67 | } 68 | } 69 | 70 | @Test 71 | public void addListenersAndDispatch () { 72 | Dummy dummy = new Dummy(); 73 | Signal signal = new Signal(); 74 | Array listeners = new Array(); 75 | 76 | int numListeners = 10; 77 | 78 | while (listeners.size < numListeners) { 79 | ListenerMock listener = new ListenerMock(); 80 | listeners.add(listener); 81 | signal.add(listener); 82 | } 83 | 84 | int numDispatchs = 10; 85 | 86 | for (int i = 0; i < numDispatchs; ++i) { 87 | for (ListenerMock listener : listeners) { 88 | assertEquals(i, listener.count); 89 | } 90 | 91 | signal.dispatch(dummy); 92 | 93 | for (ListenerMock listener : listeners) { 94 | assertEquals(i + 1, listener.count); 95 | } 96 | } 97 | } 98 | 99 | @Test 100 | public void addListenerDispatchAndRemove () { 101 | Dummy dummy = new Dummy(); 102 | Signal signal = new Signal(); 103 | ListenerMock listenerA = new ListenerMock(); 104 | ListenerMock listenerB = new ListenerMock(); 105 | 106 | signal.add(listenerA); 107 | signal.add(listenerB); 108 | 109 | int numDispatchs = 5; 110 | 111 | for (int i = 0; i < numDispatchs; ++i) { 112 | assertEquals(i, listenerA.count); 113 | assertEquals(i, listenerB.count); 114 | 115 | signal.dispatch(dummy); 116 | 117 | assertEquals(i + 1, listenerA.count); 118 | assertEquals(i + 1, listenerB.count); 119 | } 120 | 121 | signal.remove(listenerB); 122 | 123 | for (int i = 0; i < numDispatchs; ++i) { 124 | assertEquals(i + numDispatchs, listenerA.count); 125 | assertEquals(numDispatchs, listenerB.count); 126 | 127 | signal.dispatch(dummy); 128 | 129 | assertEquals(i + 1 + numDispatchs, listenerA.count); 130 | assertEquals(numDispatchs, listenerB.count); 131 | } 132 | } 133 | 134 | @Test 135 | public void removeWhileDispatch () { 136 | Dummy dummy = new Dummy(); 137 | Signal signal = new Signal(); 138 | RemoveWhileDispatchListenerMock listenerA = new RemoveWhileDispatchListenerMock(); 139 | ListenerMock listenerB = new ListenerMock(); 140 | 141 | signal.add(listenerA); 142 | signal.add(listenerB); 143 | 144 | signal.dispatch(dummy); 145 | 146 | assertEquals(1, listenerA.count); 147 | assertEquals(1, listenerB.count); 148 | } 149 | 150 | @Test 151 | public void removeAll () { 152 | Dummy dummy = new Dummy(); 153 | Signal signal = new Signal(); 154 | 155 | ListenerMock listenerA = new ListenerMock(); 156 | ListenerMock listenerB = new ListenerMock(); 157 | 158 | signal.add(listenerA); 159 | signal.add(listenerB); 160 | 161 | signal.dispatch(dummy); 162 | 163 | assertEquals(1, listenerA.count); 164 | assertEquals(1, listenerB.count); 165 | 166 | signal.removeAllListeners(); 167 | 168 | signal.dispatch(dummy); 169 | 170 | assertEquals(1, listenerA.count); 171 | assertEquals(1, listenerB.count); 172 | } 173 | 174 | } 175 | -------------------------------------------------------------------------------- /ashley/src/com/badlogic/ashley/utils/Bag.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2014 See AUTHORS file. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | ******************************************************************************/ 16 | 17 | package com.badlogic.ashley.utils; 18 | 19 | /** 20 | * Fast collection similar to Array that grows on demand as elements are accessed. It does not preserve order of elements. 21 | * Inspired by Artemis Bag. 22 | */ 23 | public class Bag { 24 | private E[] data; 25 | private int size = 0; 26 | 27 | /** 28 | * Empty Bag with an initial capacity of 64. 29 | */ 30 | public Bag () { 31 | this(64); 32 | } 33 | 34 | /** 35 | * Empty Bag with the specified initial capacity. 36 | * @param capacity the initial capacity of Bag. 37 | */ 38 | @SuppressWarnings("unchecked") 39 | public Bag (int capacity) { 40 | data = (E[])new Object[capacity]; 41 | } 42 | 43 | /** 44 | * Removes the element at the specified position in this Bag. Order of elements is not preserved. 45 | * @param index 46 | * @return element that was removed from the Bag. 47 | */ 48 | public E remove (int index) { 49 | E e = data[index]; // make copy of element to remove so it can be returned 50 | data[index] = data[--size]; // overwrite item to remove with last element 51 | data[size] = null; // null last element, so gc can do its work 52 | return e; 53 | } 54 | 55 | /** 56 | * Removes and return the last object in the bag. 57 | * @return the last object in the bag, null if empty. 58 | */ 59 | public E removeLast () { 60 | if (size > 0) { 61 | E e = data[--size]; 62 | data[size] = null; 63 | return e; 64 | } 65 | 66 | return null; 67 | } 68 | 69 | /** 70 | * Removes the first occurrence of the specified element from this Bag, if it is present. If the Bag does not contain the 71 | * element, it is unchanged. It does not preserve order of elements. 72 | * @param e 73 | * @return true if the element was removed. 74 | */ 75 | public boolean remove (E e) { 76 | for (int i = 0; i < size; i++) { 77 | E e2 = data[i]; 78 | 79 | if (e == e2) { 80 | data[i] = data[--size]; // overwrite item to remove with last element 81 | data[size] = null; // null last element, so gc can do its work 82 | return true; 83 | } 84 | } 85 | 86 | return false; 87 | } 88 | 89 | /** 90 | * Check if bag contains this element. The operator == is used to check for equality. 91 | */ 92 | public boolean contains (E e) { 93 | for (int i = 0; size > i; i++) { 94 | if (e == data[i]) { 95 | return true; 96 | } 97 | } 98 | return false; 99 | } 100 | 101 | /** 102 | * @return the element at the specified position in Bag. 103 | */ 104 | public E get (int index) { 105 | return data[index]; 106 | } 107 | 108 | /** 109 | * @return the number of elements in this bag. 110 | */ 111 | public int size () { 112 | return size; 113 | } 114 | 115 | /** 116 | * @return the number of elements the bag can hold without growing. 117 | */ 118 | public int getCapacity () { 119 | return data.length; 120 | } 121 | 122 | /** 123 | * @param index 124 | * @return whether or not the index is within the bounds of the collection 125 | */ 126 | public boolean isIndexWithinBounds (int index) { 127 | return index < getCapacity(); 128 | } 129 | 130 | /** 131 | * @return true if this list contains no elements 132 | */ 133 | public boolean isEmpty () { 134 | return size == 0; 135 | } 136 | 137 | /** 138 | * Adds the specified element to the end of this bag. if needed also increases the capacity of the bag. 139 | */ 140 | public void add (E e) { 141 | // is size greater than capacity increase capacity 142 | if (size == data.length) { 143 | grow(); 144 | } 145 | 146 | data[size++] = e; 147 | } 148 | 149 | /** 150 | * Set element at specified index in the bag. 151 | */ 152 | public void set (int index, E e) { 153 | if (index >= data.length) { 154 | grow(index * 2); 155 | } 156 | size = Math.max(size, index + 1); 157 | data[index] = e; 158 | } 159 | 160 | /** 161 | * Removes all of the elements from this bag. The bag will be empty after this call returns. 162 | */ 163 | public void clear () { 164 | // null all elements so gc can clean up 165 | for (int i = 0; i < size; i++) { 166 | data[i] = null; 167 | } 168 | 169 | size = 0; 170 | } 171 | 172 | private void grow () { 173 | int newCapacity = (data.length * 3) / 2 + 1; 174 | grow(newCapacity); 175 | } 176 | 177 | @SuppressWarnings("unchecked") 178 | private void grow (int newCapacity) { 179 | E[] oldData = data; 180 | data = (E[])new Object[newCapacity]; 181 | System.arraycopy(oldData, 0, data, 0, oldData.length); 182 | } 183 | } 184 | -------------------------------------------------------------------------------- /ashley/tests/com/badlogic/ashley/core/EntityManagerTests.java: -------------------------------------------------------------------------------- 1 | package com.badlogic.ashley.core; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import org.junit.Test; 6 | 7 | import com.badlogic.ashley.utils.ImmutableArray; 8 | import com.badlogic.gdx.utils.Array; 9 | 10 | public class EntityManagerTests { 11 | 12 | private static class EntityListenerMock implements EntityListener { 13 | 14 | public int addedCount = 0; 15 | public int removedCount = 0; 16 | 17 | @Override 18 | public void entityAdded (Entity entity) { 19 | ++addedCount; 20 | assertNotNull(entity); 21 | } 22 | 23 | @Override 24 | public void entityRemoved (Entity entity) { 25 | ++removedCount; 26 | assertNotNull(entity); 27 | } 28 | } 29 | 30 | @Test 31 | public void addAndRemoveEntity () { 32 | EntityListenerMock listener = new EntityListenerMock(); 33 | EntityManager manager = new EntityManager(listener); 34 | 35 | Entity entity1 = new Entity(); 36 | manager.addEntity(entity1); 37 | 38 | assertEquals(1, listener.addedCount); 39 | Entity entity2 = new Entity(); 40 | manager.addEntity(entity2); 41 | 42 | assertEquals(2, listener.addedCount); 43 | 44 | manager.removeAllEntities(); 45 | 46 | assertEquals(2, listener.removedCount); 47 | } 48 | 49 | @Test 50 | public void getEntities () { 51 | int numEntities = 10; 52 | 53 | EntityListenerMock listener = new EntityListenerMock(); 54 | EntityManager manager = new EntityManager(listener); 55 | 56 | Array entities = new Array(); 57 | 58 | for (int i = 0; i < numEntities; ++i) { 59 | Entity entity = new Entity(); 60 | entities.add(entity); 61 | manager.addEntity(entity); 62 | } 63 | 64 | ImmutableArray engineEntities = manager.getEntities(); 65 | 66 | assertEquals(entities.size, engineEntities.size()); 67 | 68 | for (int i = 0; i < numEntities; ++i) { 69 | assertEquals(entities.get(i), engineEntities.get(i)); 70 | } 71 | 72 | manager.removeAllEntities(); 73 | 74 | assertEquals(0, engineEntities.size()); 75 | } 76 | 77 | @Test(expected=IllegalArgumentException.class) 78 | public void addEntityTwice1 () { 79 | EntityListenerMock listener = new EntityListenerMock(); 80 | EntityManager manager = new EntityManager(listener); 81 | Entity entity = new Entity(); 82 | manager.addEntity(entity); 83 | manager.addEntity(entity); 84 | } 85 | 86 | @Test(expected=IllegalArgumentException.class) 87 | public void addEntityTwice2() { 88 | EntityListenerMock listener = new EntityListenerMock(); 89 | EntityManager manager = new EntityManager(listener); 90 | Entity entity = new Entity(); 91 | manager.addEntity(entity, false); 92 | manager.addEntity(entity, false); 93 | } 94 | 95 | @Test(expected=IllegalArgumentException.class) 96 | public void addEntityTwiceDelayed() { 97 | EntityListenerMock listener = new EntityListenerMock(); 98 | EntityManager manager = new EntityManager(listener); 99 | 100 | Entity entity = new Entity(); 101 | manager.addEntity(entity, true); 102 | manager.addEntity(entity, true); 103 | manager.processPendingOperations(); 104 | } 105 | 106 | @Test 107 | public void delayedOperationsOrder() { 108 | EntityListenerMock listener = new EntityListenerMock(); 109 | EntityManager manager = new EntityManager(listener); 110 | 111 | Entity entityA = new Entity(); 112 | Entity entityB = new Entity(); 113 | 114 | boolean delayed = true; 115 | manager.addEntity(entityA); 116 | manager.addEntity(entityB); 117 | 118 | assertEquals(2, manager.getEntities().size()); 119 | 120 | Entity entityC = new Entity(); 121 | Entity entityD = new Entity(); 122 | manager.removeAllEntities(delayed); 123 | manager.addEntity(entityC, delayed); 124 | manager.addEntity(entityD, delayed); 125 | manager.processPendingOperations(); 126 | 127 | assertEquals(2, manager.getEntities().size()); 128 | assertNotEquals(-1, manager.getEntities().indexOf(entityC, true)); 129 | assertNotEquals(-1, manager.getEntities().indexOf(entityD, true)); 130 | } 131 | 132 | @Test 133 | public void removeAndAddEntityDelayed() { 134 | EntityListenerMock listener = new EntityListenerMock(); 135 | EntityManager manager = new EntityManager(listener); 136 | 137 | Entity entity = new Entity(); 138 | manager.addEntity(entity, false); // immediate 139 | assertEquals(1, manager.getEntities().size()); 140 | 141 | manager.removeEntity(entity, true); // delayed 142 | assertEquals(1, manager.getEntities().size()); 143 | 144 | manager.addEntity(entity, true); // delayed 145 | assertEquals(1, manager.getEntities().size()); 146 | 147 | manager.processPendingOperations(); 148 | assertEquals(1, manager.getEntities().size()); 149 | } 150 | 151 | @Test 152 | public void removeAllAndAddEntityDelayed() { 153 | EntityListenerMock listener = new EntityListenerMock(); 154 | EntityManager manager = new EntityManager(listener); 155 | 156 | Entity entity = new Entity(); 157 | manager.addEntity(entity, false); // immediate 158 | assertEquals(1, manager.getEntities().size()); 159 | 160 | manager.removeAllEntities(true); // delayed 161 | assertEquals(1, manager.getEntities().size()); 162 | 163 | manager.addEntity(entity, true); // delayed 164 | assertEquals(1, manager.getEntities().size()); 165 | 166 | manager.processPendingOperations(); 167 | assertEquals(1, manager.getEntities().size()); 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /ashley/src/com/badlogic/ashley/core/FamilyManager.java: -------------------------------------------------------------------------------- 1 | package com.badlogic.ashley.core; 2 | 3 | import com.badlogic.ashley.utils.ImmutableArray; 4 | import com.badlogic.gdx.utils.Array; 5 | import com.badlogic.gdx.utils.Bits; 6 | import com.badlogic.gdx.utils.ObjectMap; 7 | import com.badlogic.gdx.utils.Pool; 8 | import com.badlogic.gdx.utils.SnapshotArray; 9 | 10 | class FamilyManager { 11 | ImmutableArray entities; 12 | private ObjectMap> families = new ObjectMap>(); 13 | private ObjectMap> immutableFamilies = new ObjectMap>(); 14 | private SnapshotArray entityListeners = new SnapshotArray(true, 16); 15 | private ObjectMap entityListenerMasks = new ObjectMap(); 16 | private BitsPool bitsPool = new BitsPool(); 17 | private boolean notifying = false; 18 | 19 | public FamilyManager(ImmutableArray entities) { 20 | this.entities = entities; 21 | } 22 | 23 | public ImmutableArray getEntitiesFor(Family family) { 24 | return registerFamily(family); 25 | } 26 | 27 | public boolean notifying() { 28 | return notifying; 29 | } 30 | 31 | public void addEntityListener (Family family, int priority, EntityListener listener) { 32 | registerFamily(family); 33 | 34 | int insertionIndex = 0; 35 | while (insertionIndex < entityListeners.size) { 36 | if (entityListeners.get(insertionIndex).priority <= priority) { 37 | insertionIndex++; 38 | } else { 39 | break; 40 | } 41 | } 42 | 43 | // Shift up bitmasks by one step 44 | for (Bits mask : entityListenerMasks.values()) { 45 | for (int k = mask.length(); k > insertionIndex; k--) { 46 | if (mask.get(k - 1)) { 47 | mask.set(k); 48 | } else { 49 | mask.clear(k); 50 | } 51 | } 52 | mask.clear(insertionIndex); 53 | } 54 | 55 | entityListenerMasks.get(family).set(insertionIndex); 56 | 57 | EntityListenerData entityListenerData = new EntityListenerData(); 58 | entityListenerData.listener = listener; 59 | entityListenerData.priority = priority; 60 | entityListeners.insert(insertionIndex, entityListenerData); 61 | } 62 | 63 | public void removeEntityListener (EntityListener listener) { 64 | for (int i = 0; i < entityListeners.size; i++) { 65 | EntityListenerData entityListenerData = entityListeners.get(i); 66 | if (entityListenerData.listener == listener) { 67 | // Shift down bitmasks by one step 68 | for (Bits mask : entityListenerMasks.values()) { 69 | for (int k = i, n = mask.length(); k < n; k++) { 70 | if (mask.get(k + 1)) { 71 | mask.set(k); 72 | } else { 73 | mask.clear(k); 74 | } 75 | } 76 | } 77 | 78 | entityListeners.removeIndex(i--); 79 | } 80 | } 81 | } 82 | 83 | public void updateFamilyMembership (Entity entity) { 84 | // Find families that the entity was added to/removed from, and fill 85 | // the bitmasks with corresponding listener bits. 86 | Bits addListenerBits = bitsPool.obtain(); 87 | Bits removeListenerBits = bitsPool.obtain(); 88 | 89 | for (Family family : entityListenerMasks.keys()) { 90 | final int familyIndex = family.getIndex(); 91 | final Bits entityFamilyBits = entity.getFamilyBits(); 92 | 93 | boolean belongsToFamily = entityFamilyBits.get(familyIndex); 94 | boolean matches = family.matches(entity) && !entity.removing; 95 | 96 | if (belongsToFamily != matches) { 97 | final Bits listenersMask = entityListenerMasks.get(family); 98 | final Array familyEntities = families.get(family); 99 | if (matches) { 100 | addListenerBits.or(listenersMask); 101 | familyEntities.add(entity); 102 | entityFamilyBits.set(familyIndex); 103 | } else { 104 | removeListenerBits.or(listenersMask); 105 | familyEntities.removeValue(entity, true); 106 | entityFamilyBits.clear(familyIndex); 107 | } 108 | } 109 | } 110 | 111 | // Notify listeners; set bits match indices of listeners 112 | notifying = true; 113 | Object[] items = entityListeners.begin(); 114 | 115 | try { 116 | for (int i = removeListenerBits.nextSetBit(0); i >= 0; i = removeListenerBits.nextSetBit(i + 1)) { 117 | ((EntityListenerData)items[i]).listener.entityRemoved(entity); 118 | } 119 | 120 | for (int i = addListenerBits.nextSetBit(0); i >= 0; i = addListenerBits.nextSetBit(i + 1)) { 121 | ((EntityListenerData)items[i]).listener.entityAdded(entity); 122 | } 123 | } 124 | finally { 125 | addListenerBits.clear(); 126 | removeListenerBits.clear(); 127 | bitsPool.free(addListenerBits); 128 | bitsPool.free(removeListenerBits); 129 | entityListeners.end(); 130 | notifying = false; 131 | } 132 | } 133 | 134 | private ImmutableArray registerFamily(Family family) { 135 | ImmutableArray entitiesInFamily = immutableFamilies.get(family); 136 | 137 | if (entitiesInFamily == null) { 138 | Array familyEntities = new Array(false, 16); 139 | entitiesInFamily = new ImmutableArray(familyEntities); 140 | families.put(family, familyEntities); 141 | immutableFamilies.put(family, entitiesInFamily); 142 | entityListenerMasks.put(family, new Bits()); 143 | 144 | for (Entity entity : entities){ 145 | updateFamilyMembership(entity); 146 | } 147 | } 148 | 149 | return entitiesInFamily; 150 | } 151 | 152 | private static class EntityListenerData { 153 | public EntityListener listener; 154 | public int priority; 155 | } 156 | 157 | private static class BitsPool extends Pool { 158 | @Override 159 | protected Bits newObject () { 160 | return new Bits(); 161 | } 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /ashley/tests/com/badlogic/ashley/core/SystemManagerTests.java: -------------------------------------------------------------------------------- 1 | package com.badlogic.ashley.core; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import org.junit.Test; 6 | 7 | import com.badlogic.ashley.core.SystemManager.SystemListener; 8 | import com.badlogic.ashley.utils.ImmutableArray; 9 | import com.badlogic.gdx.utils.Array; 10 | 11 | public class SystemManagerTests { 12 | 13 | private static class SystemListenerSpy implements SystemListener { 14 | public int addedCount = 0; 15 | public int removedCount = 0; 16 | 17 | @Override 18 | public void systemAdded (EntitySystem system) { 19 | system.addedToEngine(null); 20 | ++addedCount; 21 | } 22 | 23 | @Override 24 | public void systemRemoved (EntitySystem system) { 25 | system.removedFromEngine(null); 26 | removedCount++; 27 | } 28 | } 29 | 30 | private static class EntitySystemMock extends EntitySystem { 31 | public int addedCalls = 0; 32 | public int removedCalls = 0; 33 | 34 | private Array updates; 35 | 36 | public EntitySystemMock () { 37 | super(); 38 | } 39 | 40 | public EntitySystemMock (Array updates) { 41 | super(); 42 | 43 | this.updates = updates; 44 | } 45 | 46 | @Override 47 | public void update (float deltaTime) { 48 | if (updates != null) { 49 | updates.add(priority); 50 | } 51 | } 52 | 53 | @Override 54 | public void addedToEngine (Engine engine) { 55 | ++addedCalls; 56 | } 57 | 58 | @Override 59 | public void removedFromEngine (Engine engine) { 60 | ++removedCalls; 61 | } 62 | } 63 | 64 | private static class EntitySystemMockA extends EntitySystemMock { 65 | 66 | public EntitySystemMockA () { 67 | super(); 68 | } 69 | 70 | public EntitySystemMockA (Array updates) { 71 | super(updates); 72 | } 73 | } 74 | 75 | private static class EntitySystemMockB extends EntitySystemMock { 76 | 77 | public EntitySystemMockB () { 78 | super(); 79 | } 80 | 81 | public EntitySystemMockB (Array updates) { 82 | super(updates); 83 | } 84 | } 85 | 86 | @Test 87 | public void addAndRemoveSystem () { 88 | EntitySystemMockA systemA = new EntitySystemMockA(); 89 | EntitySystemMockB systemB = new EntitySystemMockB(); 90 | 91 | SystemListenerSpy systemSpy = new SystemListenerSpy(); 92 | SystemManager manager = new SystemManager(systemSpy); 93 | 94 | assertNull(manager.getSystem(EntitySystemMockA.class)); 95 | assertNull(manager.getSystem(EntitySystemMockB.class)); 96 | 97 | manager.addSystem(systemA); 98 | manager.addSystem(systemB); 99 | 100 | assertNotNull(manager.getSystem(EntitySystemMockA.class)); 101 | assertNotNull(manager.getSystem(EntitySystemMockB.class)); 102 | assertEquals(1, systemA.addedCalls); 103 | assertEquals(1, systemB.addedCalls); 104 | 105 | manager.removeSystem(systemA); 106 | manager.removeSystem(systemB); 107 | 108 | assertNull(manager.getSystem(EntitySystemMockA.class)); 109 | assertNull(manager.getSystem(EntitySystemMockB.class)); 110 | assertEquals(1, systemA.removedCalls); 111 | assertEquals(1, systemB.removedCalls); 112 | 113 | manager.addSystem(systemA); 114 | manager.addSystem(systemB); 115 | manager.removeAllSystems(); 116 | 117 | assertNull(manager.getSystem(EntitySystemMockA.class)); 118 | assertNull(manager.getSystem(EntitySystemMockB.class)); 119 | assertEquals(2, systemA.removedCalls); 120 | assertEquals(2, systemB.removedCalls); 121 | } 122 | 123 | @Test 124 | public void getSystems () { 125 | SystemListenerSpy systemSpy = new SystemListenerSpy(); 126 | SystemManager manager = new SystemManager(systemSpy); 127 | EntitySystemMockA systemA = new EntitySystemMockA(); 128 | EntitySystemMockB systemB = new EntitySystemMockB(); 129 | 130 | assertEquals(0, manager.getSystems().size()); 131 | 132 | manager.addSystem(systemA); 133 | manager.addSystem(systemB); 134 | 135 | assertEquals(2, manager.getSystems().size()); 136 | assertEquals(2, systemSpy.addedCount); 137 | 138 | manager.removeSystem(systemA); 139 | manager.removeSystem(systemB); 140 | 141 | assertEquals(0, manager.getSystems().size()); 142 | assertEquals(2, systemSpy.addedCount); 143 | assertEquals(2, systemSpy.removedCount); 144 | } 145 | 146 | @Test 147 | public void addTwoSystemsOfSameClass () { 148 | SystemListenerSpy systemSpy = new SystemListenerSpy(); 149 | SystemManager manager = new SystemManager(systemSpy); 150 | EntitySystemMockA system1 = new EntitySystemMockA(); 151 | EntitySystemMockA system2 = new EntitySystemMockA(); 152 | 153 | assertEquals(0, manager.getSystems().size()); 154 | 155 | manager.addSystem(system1); 156 | 157 | assertEquals(1, manager.getSystems().size()); 158 | assertEquals(system1, manager.getSystem(EntitySystemMockA.class)); 159 | assertEquals(1, systemSpy.addedCount); 160 | 161 | manager.addSystem(system2); 162 | 163 | assertEquals(1, manager.getSystems().size()); 164 | assertEquals(system2, manager.getSystem(EntitySystemMockA.class)); 165 | assertEquals(2, systemSpy.addedCount); 166 | assertEquals(1, systemSpy.removedCount); 167 | } 168 | 169 | @Test 170 | public void systemUpdateOrder () { 171 | Array updates = new Array(); 172 | 173 | SystemListenerSpy systemSpy = new SystemListenerSpy(); 174 | SystemManager manager = new SystemManager(systemSpy); 175 | EntitySystemMock system1 = new EntitySystemMockA(updates); 176 | EntitySystemMock system2 = new EntitySystemMockB(updates); 177 | 178 | system1.priority = 2; 179 | system2.priority = 1; 180 | 181 | manager.addSystem(system1); 182 | manager.addSystem(system2); 183 | 184 | ImmutableArray systems = manager.getSystems(); 185 | assertEquals(system2, systems.get(0)); 186 | assertEquals(system1, systems.get(1)); 187 | } 188 | } 189 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # For Cygwin, ensure paths are in UNIX format before anything is touched. 46 | if $cygwin ; then 47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 48 | fi 49 | 50 | # Attempt to set APP_HOME 51 | # Resolve links: $0 may be a link 52 | PRG="$0" 53 | # Need this for relative symlinks. 54 | while [ -h "$PRG" ] ; do 55 | ls=`ls -ld "$PRG"` 56 | link=`expr "$ls" : '.*-> \(.*\)$'` 57 | if expr "$link" : '/.*' > /dev/null; then 58 | PRG="$link" 59 | else 60 | PRG=`dirname "$PRG"`"/$link" 61 | fi 62 | done 63 | SAVED="`pwd`" 64 | cd "`dirname \"$PRG\"`/" >&- 65 | APP_HOME="`pwd -P`" 66 | cd "$SAVED" >&- 67 | 68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 69 | 70 | # Determine the Java command to use to start the JVM. 71 | if [ -n "$JAVA_HOME" ] ; then 72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 73 | # IBM's JDK on AIX uses strange locations for the executables 74 | JAVACMD="$JAVA_HOME/jre/sh/java" 75 | else 76 | JAVACMD="$JAVA_HOME/bin/java" 77 | fi 78 | if [ ! -x "$JAVACMD" ] ; then 79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 80 | 81 | Please set the JAVA_HOME variable in your environment to match the 82 | location of your Java installation." 83 | fi 84 | else 85 | JAVACMD="java" 86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 87 | 88 | Please set the JAVA_HOME variable in your environment to match the 89 | location of your Java installation." 90 | fi 91 | 92 | # Increase the maximum file descriptors if we can. 93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 94 | MAX_FD_LIMIT=`ulimit -H -n` 95 | if [ $? -eq 0 ] ; then 96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 97 | MAX_FD="$MAX_FD_LIMIT" 98 | fi 99 | ulimit -n $MAX_FD 100 | if [ $? -ne 0 ] ; then 101 | warn "Could not set maximum file descriptor limit: $MAX_FD" 102 | fi 103 | else 104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 105 | fi 106 | fi 107 | 108 | # For Darwin, add options to specify how the application appears in the dock 109 | if $darwin; then 110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 111 | fi 112 | 113 | # For Cygwin, switch paths to Windows format before running java 114 | if $cygwin ; then 115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 165 | -------------------------------------------------------------------------------- /ashley/src/com/badlogic/ashley/systems/SortedIteratingSystem.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2014 See AUTHORS file. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | ******************************************************************************/ 16 | 17 | package com.badlogic.ashley.systems; 18 | 19 | import com.badlogic.ashley.core.Engine; 20 | import com.badlogic.ashley.core.Entity; 21 | import com.badlogic.ashley.core.EntityListener; 22 | import com.badlogic.ashley.core.EntitySystem; 23 | import com.badlogic.ashley.core.Family; 24 | import com.badlogic.ashley.utils.ImmutableArray; 25 | import com.badlogic.gdx.utils.Array; 26 | import java.util.Comparator; 27 | 28 | /** 29 | * A simple EntitySystem that processes each entity of a given family in the order specified by a comparator and calls 30 | * processEntity() for each entity every time the EntitySystem is updated. This is really just a convenience class as rendering 31 | * systems tend to iterate over a list of entities in a sorted manner. Adding entities will cause the entity list to be resorted. 32 | * Call forceSort() if you changed your sorting criteria. 33 | * @author Santo Pfingsten 34 | */ 35 | public abstract class SortedIteratingSystem extends EntitySystem implements EntityListener { 36 | private Family family; 37 | private Array sortedEntities; 38 | private final ImmutableArray entities; 39 | private boolean shouldSort; 40 | private Comparator comparator; 41 | 42 | /** 43 | * Instantiates a system that will iterate over the entities described by the Family. 44 | * @param family The family of entities iterated over in this System 45 | * @param comparator The comparator to sort the entities 46 | */ 47 | public SortedIteratingSystem (Family family, Comparator comparator) { 48 | this(family, comparator, 0); 49 | } 50 | 51 | /** 52 | * Instantiates a system that will iterate over the entities described by the Family, with a specific priority. 53 | * @param family The family of entities iterated over in this System 54 | * @param comparator The comparator to sort the entities 55 | * @param priority The priority to execute this system with (lower means higher priority) 56 | */ 57 | public SortedIteratingSystem (Family family, Comparator comparator, int priority) { 58 | super(priority); 59 | 60 | this.family = family; 61 | sortedEntities = new Array(false, 16); 62 | entities = new ImmutableArray(sortedEntities); 63 | this.comparator = comparator; 64 | } 65 | 66 | /** 67 | * Call this if the sorting criteria have changed. The actual sorting will be delayed until the entities are processed. 68 | */ 69 | public void forceSort () { 70 | shouldSort = true; 71 | } 72 | 73 | private void sort () { 74 | if (shouldSort) { 75 | sortedEntities.sort(comparator); 76 | shouldSort = false; 77 | } 78 | } 79 | 80 | @Override 81 | public void addedToEngine (Engine engine) { 82 | ImmutableArray newEntities = engine.getEntitiesFor(family); 83 | sortedEntities.clear(); 84 | if (newEntities.size() > 0) { 85 | for (int i = 0; i < newEntities.size(); ++i) { 86 | sortedEntities.add(newEntities.get(i)); 87 | } 88 | sortedEntities.sort(comparator); 89 | } 90 | shouldSort = false; 91 | engine.addEntityListener(family, this); 92 | } 93 | 94 | @Override 95 | public void removedFromEngine (Engine engine) { 96 | engine.removeEntityListener(this); 97 | sortedEntities.clear(); 98 | shouldSort = false; 99 | } 100 | 101 | @Override 102 | public void entityAdded (Entity entity) { 103 | sortedEntities.add(entity); 104 | shouldSort = true; 105 | } 106 | 107 | @Override 108 | public void entityRemoved (Entity entity) { 109 | sortedEntities.removeValue(entity, true); 110 | shouldSort = true; 111 | } 112 | 113 | @Override 114 | public void update (float deltaTime) { 115 | sort(); 116 | startProcessing(); 117 | for (int i = 0; i < sortedEntities.size; ++i) { 118 | processEntity(sortedEntities.get(i), deltaTime); 119 | } 120 | endProcessing(); 121 | } 122 | 123 | /** 124 | * @return set of entities processed by the system 125 | */ 126 | public ImmutableArray getEntities () { 127 | sort(); 128 | return entities; 129 | } 130 | 131 | /** 132 | * @return the Family used when the system was created 133 | */ 134 | public Family getFamily () { 135 | return family; 136 | } 137 | 138 | /** 139 | * This method is called on every entity on every update call of the EntitySystem. Override this to implement your system's 140 | * specific processing. 141 | * @param entity The current Entity being processed 142 | * @param deltaTime The delta time between the last and current frame 143 | */ 144 | protected abstract void processEntity (Entity entity, float deltaTime); 145 | 146 | /** 147 | * This method is called once on every update call of the EntitySystem, before entity processing begins. Override this method to 148 | * implement your specific startup conditions. 149 | */ 150 | public void startProcessing() {} 151 | 152 | /** 153 | * This method is called once on every update call of the EntitySystem after entity processing is complete. Override this method to 154 | * implement your specific end conditions. 155 | */ 156 | public void endProcessing() {} 157 | } 158 | -------------------------------------------------------------------------------- /ashley/src/com/badlogic/ashley/core/Family.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2014 See AUTHORS file. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | ******************************************************************************/ 16 | 17 | package com.badlogic.ashley.core; 18 | 19 | import com.badlogic.gdx.utils.Bits; 20 | import com.badlogic.gdx.utils.ObjectMap; 21 | 22 | /** 23 | * Represents a group of {@link Component}s. It is used to describe what {@link Entity} objects an {@link EntitySystem} should 24 | * process. Example: {@code Family.all(PositionComponent.class, VelocityComponent.class).get()} Families can't be instantiated 25 | * directly but must be accessed via a builder ( start with {@code Family.all()}, {@code Family.one()} or {@code Family.exclude()} 26 | * ), this is to avoid duplicate families that describe the same components. 27 | * @author Stefan Bachmann 28 | */ 29 | public class Family { 30 | private static ObjectMap families = new ObjectMap(); 31 | private static int familyIndex = 0; 32 | private static final Builder builder = new Builder(); 33 | private static final Bits zeroBits = new Bits(); 34 | 35 | private final Bits all; 36 | private final Bits one; 37 | private final Bits exclude; 38 | private final int index; 39 | 40 | /** Private constructor, use static method Family.getFamilyFor() */ 41 | private Family (Bits all, Bits any, Bits exclude) { 42 | this.all = all; 43 | this.one = any; 44 | this.exclude = exclude; 45 | this.index = familyIndex++; 46 | } 47 | 48 | /** @return This family's unique index */ 49 | public int getIndex () { 50 | return this.index; 51 | } 52 | 53 | /** @return Whether the entity matches the family requirements or not */ 54 | public boolean matches (Entity entity) { 55 | Bits entityComponentBits = entity.getComponentBits(); 56 | 57 | if (!entityComponentBits.containsAll(all)) { 58 | return false; 59 | } 60 | 61 | if (!one.isEmpty() && !one.intersects(entityComponentBits)) { 62 | return false; 63 | } 64 | 65 | if (!exclude.isEmpty() && exclude.intersects(entityComponentBits)) { 66 | return false; 67 | } 68 | 69 | return true; 70 | } 71 | 72 | /** 73 | * @param componentTypes entities will have to contain all of the specified components. 74 | * @return A Builder singleton instance to get a family 75 | */ 76 | @SafeVarargs 77 | public static final Builder all (Class... componentTypes) { 78 | return builder.reset().all(componentTypes); 79 | } 80 | 81 | /** 82 | * @param componentTypes entities will have to contain at least one of the specified components. 83 | * @return A Builder singleton instance to get a family 84 | */ 85 | @SafeVarargs 86 | public static final Builder one (Class... componentTypes) { 87 | return builder.reset().one(componentTypes); 88 | } 89 | 90 | /** 91 | * @param componentTypes entities cannot contain any of the specified components. 92 | * @return A Builder singleton instance to get a family 93 | */ 94 | @SafeVarargs 95 | public static final Builder exclude (Class... componentTypes) { 96 | return builder.reset().exclude(componentTypes); 97 | } 98 | 99 | public static class Builder { 100 | private Bits all = zeroBits; 101 | private Bits one = zeroBits; 102 | private Bits exclude = zeroBits; 103 | 104 | Builder() { 105 | 106 | } 107 | 108 | /** 109 | * Resets the builder instance 110 | * @return A Builder singleton instance to get a family 111 | */ 112 | public Builder reset () { 113 | all = zeroBits; 114 | one = zeroBits; 115 | exclude = zeroBits; 116 | return this; 117 | } 118 | 119 | /** 120 | * @param componentTypes entities will have to contain all of the specified components. 121 | * @return A Builder singleton instance to get a family 122 | */ 123 | @SafeVarargs 124 | public final Builder all (Class... componentTypes) { 125 | all = ComponentType.getBitsFor(componentTypes); 126 | return this; 127 | } 128 | 129 | /** 130 | * @param componentTypes entities will have to contain at least one of the specified components. 131 | * @return A Builder singleton instance to get a family 132 | */ 133 | @SafeVarargs 134 | public final Builder one (Class... componentTypes) { 135 | one = ComponentType.getBitsFor(componentTypes); 136 | return this; 137 | } 138 | 139 | /** 140 | * @param componentTypes entities cannot contain any of the specified components. 141 | * @return A Builder singleton instance to get a family 142 | */ 143 | @SafeVarargs 144 | public final Builder exclude (Class... componentTypes) { 145 | exclude = ComponentType.getBitsFor(componentTypes); 146 | return this; 147 | } 148 | 149 | /** @return A family for the configured component types */ 150 | public Family get () { 151 | String hash = getFamilyHash(all, one, exclude); 152 | Family family = families.get(hash, null); 153 | if (family == null) { 154 | family = new Family(all, one, exclude); 155 | families.put(hash, family); 156 | } 157 | return family; 158 | } 159 | } 160 | 161 | @Override 162 | public int hashCode () { 163 | return index; 164 | } 165 | 166 | @Override 167 | public boolean equals (Object obj) { 168 | return this == obj; 169 | } 170 | 171 | private static String getFamilyHash (Bits all, Bits one, Bits exclude) { 172 | StringBuilder stringBuilder = new StringBuilder(); 173 | if (!all.isEmpty()) { 174 | stringBuilder.append("{all:").append(getBitsString(all)).append("}"); 175 | } 176 | if (!one.isEmpty()) { 177 | stringBuilder.append("{one:").append(getBitsString(one)).append("}"); 178 | } 179 | if (!exclude.isEmpty()) { 180 | stringBuilder.append("{exclude:").append(getBitsString(exclude)).append("}"); 181 | } 182 | return stringBuilder.toString(); 183 | } 184 | 185 | private static String getBitsString (Bits bits) { 186 | StringBuilder stringBuilder = new StringBuilder(); 187 | 188 | int numBits = bits.length(); 189 | for (int i = 0; i < numBits; ++i) { 190 | stringBuilder.append(bits.get(i) ? "1" : "0"); 191 | } 192 | 193 | return stringBuilder.toString(); 194 | } 195 | } 196 | -------------------------------------------------------------------------------- /ashley/src/com/badlogic/ashley/core/PooledEngine.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2014 See AUTHORS file. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | ******************************************************************************/ 16 | 17 | package com.badlogic.ashley.core; 18 | 19 | import com.badlogic.gdx.utils.Array; 20 | import com.badlogic.gdx.utils.ObjectMap; 21 | import com.badlogic.gdx.utils.Pool; 22 | import com.badlogic.gdx.utils.Pool.Poolable; 23 | import com.badlogic.gdx.utils.ReflectionPool; 24 | 25 | /** 26 | * Supports {@link Entity} and {@link Component} pooling. This improves performance in environments where creating/deleting 27 | * entities is frequent as it greatly reduces memory allocation. 28 | *
    29 | *
  • Create entities using {@link #createEntity()}
  • 30 | *
  • Create components using {@link #createComponent(Class)}
  • 31 | *
  • Components should implement the {@link Poolable} interface when in need to reset its state upon removal
  • 32 | *
33 | * @author David Saltares 34 | */ 35 | @SuppressWarnings({"rawtypes", "unchecked"}) 36 | public class PooledEngine extends Engine { 37 | 38 | private EntityPool entityPool; 39 | private ComponentPools componentPools; 40 | 41 | /** 42 | * Creates a new PooledEngine with a maximum of 100 entities and 100 components of each type. Use 43 | * {@link #PooledEngine(int, int, int, int)} to configure the entity and component pools. 44 | */ 45 | public PooledEngine () { 46 | this(10, 100, 10, 100); 47 | } 48 | 49 | /** 50 | * Creates new PooledEngine with the specified pools size configurations. 51 | * @param entityPoolInitialSize initial number of pre-allocated entities. 52 | * @param entityPoolMaxSize maximum number of pooled entities. 53 | * @param componentPoolInitialSize initial size for each component type pool. 54 | * @param componentPoolMaxSize maximum size for each component type pool. 55 | */ 56 | public PooledEngine (int entityPoolInitialSize, int entityPoolMaxSize, int componentPoolInitialSize, int componentPoolMaxSize) { 57 | super(); 58 | 59 | entityPool = new EntityPool(entityPoolInitialSize, entityPoolMaxSize); 60 | componentPools = new ComponentPools(componentPoolInitialSize, componentPoolMaxSize); 61 | } 62 | 63 | /** @return Clean {@link Entity} from the Engine pool. In order to add it to the {@link Engine}, use {@link #addEntity(Entity)}. @{@link Override {@link Engine#createEntity()}} */ 64 | @Override 65 | public Entity createEntity () { 66 | return entityPool.obtain(); 67 | } 68 | 69 | /** 70 | * Retrieves a new {@link Component} from the {@link Engine} pool. It will be placed back in the pool whenever it's removed 71 | * from an {@link Entity} or the {@link Entity} itself it's removed. 72 | * Overrides the default implementation of Engine (creating a new Object) 73 | */ 74 | @Override 75 | public T createComponent (Class componentType) { 76 | return componentPools.obtain(componentType); 77 | } 78 | 79 | /** 80 | * Removes all free entities and components from their pools. Although this will likely result in garbage collection, it will 81 | * free up memory. 82 | */ 83 | public void clearPools () { 84 | entityPool.clear(); 85 | componentPools.clear(); 86 | } 87 | 88 | @Override 89 | protected void removeEntityInternal (Entity entity) { 90 | super.removeEntityInternal(entity); 91 | 92 | if (entity instanceof PooledEntity) { 93 | entityPool.free((PooledEntity)entity); 94 | } 95 | } 96 | 97 | private class PooledEntity extends Entity implements Poolable { 98 | @Override 99 | Component removeInternal(Class componentClass) { 100 | Component removed = super.removeInternal(componentClass); 101 | if (removed != null) { 102 | componentPools.free(removed); 103 | } 104 | 105 | return removed; 106 | } 107 | 108 | @Override 109 | public void reset () { 110 | removeAll(); 111 | flags = 0; 112 | componentAdded.removeAllListeners(); 113 | componentRemoved.removeAllListeners(); 114 | scheduledForRemoval = false; 115 | removing = false; 116 | } 117 | } 118 | 119 | private class EntityPool extends Pool { 120 | 121 | public EntityPool (int initialSize, int maxSize) { 122 | super(initialSize, maxSize); 123 | } 124 | 125 | @Override 126 | protected PooledEntity newObject () { 127 | return new PooledEntity(); 128 | } 129 | 130 | /** 131 | * Forwarding this call ensures {@link Poolable} {@link Component} instances are returned to their respective 132 | * {@link ComponentPools}s even if the {@link EntityPool} is full. 133 | */ 134 | @Override 135 | protected void discard(PooledEntity pooledEntity) { 136 | pooledEntity.reset(); 137 | } 138 | } 139 | 140 | private class ComponentPools { 141 | private ObjectMap, ReflectionPool> pools; 142 | private int initialSize; 143 | private int maxSize; 144 | 145 | public ComponentPools (int initialSize, int maxSize) { 146 | this.pools = new ObjectMap, ReflectionPool>(); 147 | this.initialSize = initialSize; 148 | this.maxSize = maxSize; 149 | } 150 | 151 | public T obtain (Class type) { 152 | ReflectionPool pool = pools.get(type); 153 | 154 | if (pool == null) { 155 | pool = new ReflectionPool(type, initialSize, maxSize); 156 | pools.put(type, pool); 157 | } 158 | 159 | return (T)pool.obtain(); 160 | } 161 | 162 | public void free (Object object) { 163 | if (object == null) { 164 | throw new IllegalArgumentException("object cannot be null."); 165 | } 166 | 167 | ReflectionPool pool = pools.get(object.getClass()); 168 | 169 | if (pool == null) { 170 | return; // Ignore freeing an object that was never retained. 171 | } 172 | 173 | pool.free(object); 174 | } 175 | 176 | public void freeAll (Array objects) { 177 | if (objects == null) throw new IllegalArgumentException("objects cannot be null."); 178 | 179 | for (int i = 0, n = objects.size; i < n; i++) { 180 | Object object = objects.get(i); 181 | if (object == null) continue; 182 | free(object); 183 | } 184 | } 185 | 186 | public void clear () { 187 | for (Pool pool : pools.values()) { 188 | pool.clear(); 189 | } 190 | } 191 | } 192 | } 193 | -------------------------------------------------------------------------------- /ashley/tests/com/badlogic/ashley/core/EntityTests.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2014 See AUTHORS file. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | ******************************************************************************/ 16 | 17 | package com.badlogic.ashley.core; 18 | 19 | import static org.junit.Assert.*; 20 | 21 | import java.util.HashSet; 22 | import java.util.Set; 23 | 24 | import org.junit.Test; 25 | 26 | import com.badlogic.ashley.signals.Listener; 27 | import com.badlogic.ashley.signals.Signal; 28 | import com.badlogic.gdx.utils.Array; 29 | import com.badlogic.gdx.utils.Bits; 30 | 31 | public class EntityTests { 32 | 33 | private static class ComponentA implements Component { 34 | } 35 | 36 | private static class ComponentB implements Component { 37 | } 38 | 39 | private static class EntityListenerMock implements Listener { 40 | 41 | public int counter = 0; 42 | 43 | @Override 44 | public void receive (Signal signal, Entity object) { 45 | ++counter; 46 | 47 | assertNotNull(signal); 48 | assertNotNull(object); 49 | } 50 | } 51 | 52 | private ComponentMapper am = ComponentMapper.getFor(ComponentA.class); 53 | private ComponentMapper bm = ComponentMapper.getFor(ComponentB.class); 54 | 55 | @Test 56 | public void addAndReturnComponent(){ 57 | Entity entity = new Entity(); 58 | ComponentA componentA = new ComponentA(); 59 | ComponentB componentB = new ComponentB(); 60 | 61 | assertEquals(componentA, entity.addAndReturn(componentA)); 62 | assertEquals(componentB, entity.addAndReturn(componentB)); 63 | 64 | assertEquals(2, entity.getComponents().size()); 65 | } 66 | 67 | @Test 68 | public void addAndReturnComponentGeneric () { 69 | Entity entity = new Entity(); 70 | ComponentA componentA = entity.addAndReturn(new ComponentA()); 71 | } 72 | 73 | @Test 74 | public void noComponents () { 75 | Entity entity = new Entity(); 76 | 77 | assertEquals(0, entity.getComponents().size()); 78 | assertTrue(entity.getComponentBits().isEmpty()); 79 | assertNull(am.get(entity)); 80 | assertNull(bm.get(entity)); 81 | assertFalse(am.has(entity)); 82 | assertFalse(bm.has(entity)); 83 | } 84 | 85 | @Test 86 | public void addAndRemoveComponent () { 87 | Entity entity = new Entity(); 88 | 89 | entity.add(new ComponentA()); 90 | 91 | assertEquals(1, entity.getComponents().size()); 92 | 93 | Bits componentBits = entity.getComponentBits(); 94 | int componentAIndex = ComponentType.getIndexFor(ComponentA.class); 95 | 96 | for (int i = 0; i < componentBits.length(); ++i) { 97 | assertEquals(i == componentAIndex, componentBits.get(i)); 98 | } 99 | 100 | assertNotNull(am.get(entity)); 101 | assertNull(bm.get(entity)); 102 | assertTrue(am.has(entity)); 103 | assertFalse(bm.has(entity)); 104 | 105 | entity.remove(ComponentA.class); 106 | 107 | assertEquals(0, entity.getComponents().size()); 108 | 109 | for (int i = 0; i < componentBits.length(); ++i) { 110 | assertFalse(componentBits.get(i)); 111 | } 112 | 113 | assertNull(am.get(entity)); 114 | assertNull(bm.get(entity)); 115 | assertFalse(am.has(entity)); 116 | assertFalse(bm.has(entity)); 117 | } 118 | 119 | @Test 120 | public void removeUnexistingComponent () throws Exception { 121 | // ensure remove unexisting component work with 122 | // new component type at default bag limits (64) 123 | Entity entity = new Entity(); 124 | 125 | ComponentClassFactory cl = new ComponentClassFactory(); 126 | 127 | for(int i=0 ; i<65 ; i++){ 128 | Class type = cl.createComponentType("Component" + i); 129 | entity.remove(type); 130 | entity.add(type.newInstance()); 131 | } 132 | } 133 | 134 | @Test 135 | public void addAndRemoveAllComponents () { 136 | Entity entity = new Entity(); 137 | 138 | entity.add(new ComponentA()); 139 | entity.add(new ComponentB()); 140 | 141 | assertEquals(2, entity.getComponents().size()); 142 | 143 | Bits componentBits = entity.getComponentBits(); 144 | int componentAIndex = ComponentType.getIndexFor(ComponentA.class); 145 | int componentBIndex = ComponentType.getIndexFor(ComponentB.class); 146 | 147 | for (int i = 0; i < componentBits.length(); ++i) { 148 | assertEquals(i == componentAIndex || i == componentBIndex, componentBits.get(i)); 149 | } 150 | 151 | assertNotNull(am.get(entity)); 152 | assertNotNull(bm.get(entity)); 153 | assertTrue(am.has(entity)); 154 | assertTrue(bm.has(entity)); 155 | 156 | entity.removeAll(); 157 | 158 | assertEquals(0, entity.getComponents().size()); 159 | 160 | for (int i = 0; i < componentBits.length(); ++i) { 161 | assertFalse(componentBits.get(i)); 162 | } 163 | 164 | assertNull(am.get(entity)); 165 | assertNull(bm.get(entity)); 166 | assertFalse(am.has(entity)); 167 | assertFalse(bm.has(entity)); 168 | } 169 | 170 | @Test 171 | public void addSameComponent () { 172 | Entity entity = new Entity(); 173 | 174 | ComponentA a1 = new ComponentA(); 175 | ComponentA a2 = new ComponentA(); 176 | 177 | entity.add(a1); 178 | entity.add(a2); 179 | 180 | assertEquals(1, entity.getComponents().size()); 181 | assertTrue(am.has(entity)); 182 | assertNotEquals(a1, am.get(entity)); 183 | assertEquals(a2, am.get(entity)); 184 | } 185 | 186 | @Test 187 | public void componentListener () { 188 | EntityListenerMock addedListener = new EntityListenerMock(); 189 | EntityListenerMock removedListener = new EntityListenerMock(); 190 | 191 | Entity entity = new Entity(); 192 | entity.componentAdded.add(addedListener); 193 | entity.componentRemoved.add(removedListener); 194 | 195 | assertEquals(0, addedListener.counter); 196 | assertEquals(0, removedListener.counter); 197 | 198 | entity.add(new ComponentA()); 199 | 200 | assertEquals(1, addedListener.counter); 201 | assertEquals(0, removedListener.counter); 202 | 203 | entity.remove(ComponentA.class); 204 | 205 | assertEquals(1, addedListener.counter); 206 | assertEquals(1, removedListener.counter); 207 | 208 | entity.add(new ComponentB()); 209 | 210 | assertEquals(2, addedListener.counter); 211 | 212 | entity.remove(ComponentB.class); 213 | 214 | assertEquals(2, removedListener.counter); 215 | } 216 | 217 | @Test 218 | public void getComponentByClass () { 219 | ComponentA compA = new ComponentA(); 220 | ComponentB compB = new ComponentB(); 221 | 222 | Entity entity = new Entity(); 223 | entity.add(compA).add(compB); 224 | 225 | ComponentA retA = entity.getComponent(ComponentA.class); 226 | ComponentB retB = entity.getComponent(ComponentB.class); 227 | 228 | assertNotNull(retA); 229 | assertNotNull(retB); 230 | 231 | assertTrue(retA == compA); 232 | assertTrue(retB == compB); 233 | } 234 | } 235 | -------------------------------------------------------------------------------- /ashley/tests/com/badlogic/ashley/core/EntityListenerTests.java: -------------------------------------------------------------------------------- 1 | 2 | package com.badlogic.ashley.core; 3 | 4 | import static org.mockito.Mockito.*; 5 | 6 | import org.junit.Test; 7 | import org.mockito.InOrder; 8 | 9 | public class EntityListenerTests { 10 | 11 | @Test 12 | public void addEntityListenerFamilyRemove () { 13 | final Engine engine = new Engine(); 14 | 15 | Entity e = new Entity(); 16 | e.add(new PositionComponent()); 17 | engine.addEntity(e); 18 | 19 | @SuppressWarnings("unchecked") 20 | Family family = Family.all(PositionComponent.class).get(); 21 | engine.addEntityListener(family, new EntityListener() { 22 | 23 | public void entityRemoved (Entity entity) { 24 | engine.addEntity(new Entity()); 25 | } 26 | 27 | public void entityAdded (Entity entity) { 28 | 29 | } 30 | }); 31 | 32 | engine.removeEntity(e); 33 | } 34 | 35 | @Test 36 | public void addEntityListenerFamilyAdd () { 37 | final Engine engine = new Engine(); 38 | 39 | Entity e = new Entity(); 40 | e.add(new PositionComponent()); 41 | 42 | @SuppressWarnings("unchecked") 43 | Family family = Family.all(PositionComponent.class).get(); 44 | engine.addEntityListener(family, new EntityListener() { 45 | 46 | public void entityRemoved (Entity entity) { 47 | 48 | } 49 | 50 | public void entityAdded (Entity entity) { 51 | engine.addEntity(new Entity()); 52 | } 53 | }); 54 | 55 | engine.addEntity(e); 56 | } 57 | 58 | @Test 59 | public void addEntityListenerNoFamilyRemove () { 60 | final Engine engine = new Engine(); 61 | 62 | Entity e = new Entity(); 63 | e.add(new PositionComponent()); 64 | engine.addEntity(e); 65 | 66 | @SuppressWarnings("unchecked") 67 | final Family family = Family.all(PositionComponent.class).get(); 68 | engine.addEntityListener(new EntityListener() { 69 | 70 | public void entityRemoved (Entity entity) { 71 | if (family.matches(entity)) engine.addEntity(new Entity()); 72 | } 73 | 74 | public void entityAdded (Entity entity) { 75 | 76 | } 77 | }); 78 | 79 | engine.removeEntity(e); 80 | } 81 | 82 | @Test 83 | public void addEntityListenerNoFamilyAdd () { 84 | final Engine engine = new Engine(); 85 | 86 | Entity e = new Entity(); 87 | e.add(new PositionComponent()); 88 | 89 | @SuppressWarnings("unchecked") 90 | final Family family = Family.all(PositionComponent.class).get(); 91 | engine.addEntityListener(new EntityListener() { 92 | 93 | public void entityRemoved (Entity entity) { 94 | 95 | } 96 | 97 | public void entityAdded (Entity entity) { 98 | if (family.matches(entity)) engine.addEntity(new Entity()); 99 | } 100 | }); 101 | 102 | engine.addEntity(e); 103 | } 104 | 105 | public class PositionComponent implements Component { 106 | } 107 | 108 | @Test 109 | public void entityListenerPriority () { 110 | EntityListener a = mock(EntityListener.class); 111 | EntityListener b = mock(EntityListener.class); 112 | EntityListener c = mock(EntityListener.class); 113 | InOrder inOrder = inOrder(a, b, c); 114 | 115 | Entity entity = new Entity(); 116 | Engine engine = new Engine(); 117 | engine.addEntityListener(-3, b); 118 | engine.addEntityListener(c); 119 | engine.addEntityListener(-4, a); 120 | inOrder.verifyNoMoreInteractions(); 121 | 122 | engine.addEntity(entity); 123 | inOrder.verify(a).entityAdded(entity); 124 | inOrder.verify(b).entityAdded(entity); 125 | inOrder.verify(c).entityAdded(entity); 126 | inOrder.verifyNoMoreInteractions(); 127 | 128 | engine.removeEntity(entity); 129 | inOrder.verify(a).entityRemoved(entity); 130 | inOrder.verify(b).entityRemoved(entity); 131 | inOrder.verify(c).entityRemoved(entity); 132 | inOrder.verifyNoMoreInteractions(); 133 | 134 | engine.removeEntityListener(b); 135 | inOrder.verifyNoMoreInteractions(); 136 | 137 | engine.addEntity(entity); 138 | inOrder.verify(a).entityAdded(entity); 139 | inOrder.verify(c).entityAdded(entity); 140 | inOrder.verifyNoMoreInteractions(); 141 | 142 | engine.addEntityListener(4, b); 143 | inOrder.verifyNoMoreInteractions(); 144 | 145 | engine.removeEntity(entity); 146 | inOrder.verify(a).entityRemoved(entity); 147 | inOrder.verify(c).entityRemoved(entity); 148 | inOrder.verify(b).entityRemoved(entity); 149 | inOrder.verifyNoMoreInteractions(); 150 | } 151 | 152 | private static class ComponentA implements Component { 153 | } 154 | 155 | private static class ComponentB implements Component { 156 | } 157 | 158 | @Test 159 | public void familyListenerPriority () { 160 | EntityListener a = mock(EntityListener.class); 161 | EntityListener b = mock(EntityListener.class); 162 | InOrder inOrder = inOrder(a, b); 163 | 164 | Engine engine = new Engine(); 165 | engine.addEntityListener(Family.all(ComponentB.class).get(), -2, b); 166 | engine.addEntityListener(Family.all(ComponentA.class).get(), -3, a); 167 | inOrder.verifyNoMoreInteractions(); 168 | 169 | Entity entity = new Entity(); 170 | entity.add(new ComponentA()); 171 | entity.add(new ComponentB()); 172 | 173 | engine.addEntity(entity); 174 | inOrder.verify(a).entityAdded(entity); 175 | inOrder.verify(b).entityAdded(entity); 176 | inOrder.verifyNoMoreInteractions(); 177 | 178 | entity.remove(ComponentB.class); 179 | inOrder.verify(b).entityRemoved(entity); 180 | inOrder.verifyNoMoreInteractions(); 181 | 182 | entity.remove(ComponentA.class); 183 | inOrder.verify(a).entityRemoved(entity); 184 | inOrder.verifyNoMoreInteractions(); 185 | 186 | entity.add(new ComponentA()); 187 | inOrder.verify(a).entityAdded(entity); 188 | inOrder.verifyNoMoreInteractions(); 189 | 190 | entity.add(new ComponentB()); 191 | inOrder.verify(b).entityAdded(entity); 192 | inOrder.verifyNoMoreInteractions(); 193 | } 194 | 195 | private interface ComponentRecorder { 196 | void addingComponentA(); 197 | 198 | void removingComponentA(); 199 | 200 | void addingComponentB(); 201 | 202 | void removingComponentB(); 203 | } 204 | 205 | @Test 206 | public void componentHandlingInListeners() { 207 | final Engine engine = new Engine(); 208 | 209 | final ComponentRecorder recorder = mock(ComponentRecorder.class); 210 | 211 | engine.addEntityListener(new EntityListener() { 212 | @Override 213 | public void entityAdded(Entity entity) { 214 | recorder.addingComponentA(); 215 | entity.add(new ComponentA()); 216 | } 217 | 218 | @Override 219 | public void entityRemoved(Entity entity) { 220 | recorder.removingComponentA(); 221 | entity.remove(ComponentA.class); 222 | } 223 | }); 224 | 225 | engine.addEntityListener(new EntityListener() { 226 | @Override 227 | public void entityAdded(Entity entity) { 228 | recorder.addingComponentB(); 229 | entity.add(new ComponentB()); 230 | } 231 | 232 | @Override 233 | public void entityRemoved(Entity entity) { 234 | recorder.removingComponentB(); 235 | entity.remove(ComponentB.class); 236 | } 237 | }); 238 | 239 | engine.update(0); 240 | Entity e = new Entity(); 241 | engine.addEntity(e); 242 | engine.update(0); 243 | engine.removeEntity(e); 244 | engine.update(0); 245 | 246 | verify(recorder).addingComponentA(); 247 | verify(recorder).removingComponentA(); 248 | verify(recorder).addingComponentB(); 249 | verify(recorder).removingComponentB(); 250 | } 251 | } 252 | -------------------------------------------------------------------------------- /ashley/tests/com/badlogic/ashley/systems/IteratingSystemTest.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2014 See AUTHORS file. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | ******************************************************************************/ 16 | 17 | package com.badlogic.ashley.systems; 18 | 19 | import org.junit.Test; 20 | 21 | import com.badlogic.ashley.core.Component; 22 | import com.badlogic.ashley.core.ComponentMapper; 23 | import com.badlogic.ashley.core.Engine; 24 | import com.badlogic.ashley.core.Entity; 25 | import com.badlogic.ashley.core.Family; 26 | import com.badlogic.ashley.systems.IteratingSystem; 27 | import com.badlogic.ashley.utils.ImmutableArray; 28 | 29 | import static org.junit.Assert.*; 30 | 31 | public class IteratingSystemTest { 32 | private static final float deltaTime = 0.16f; 33 | 34 | private static class ComponentA implements Component { 35 | } 36 | 37 | private static class ComponentB implements Component { 38 | } 39 | 40 | private static class ComponentC implements Component { 41 | } 42 | 43 | private static class IteratingSystemMock extends IteratingSystem { 44 | public int numUpdates; 45 | public int numStartProcessing; 46 | public int numEndProcessing; 47 | 48 | public IteratingSystemMock (Family family) { 49 | super(family); 50 | } 51 | 52 | @Override 53 | public void startProcessing() { 54 | ++numStartProcessing; 55 | } 56 | 57 | @Override 58 | public void processEntity (Entity entity, float deltaTime) { 59 | ++numUpdates; 60 | } 61 | 62 | @Override 63 | public void endProcessing() { 64 | ++numEndProcessing; 65 | } 66 | } 67 | 68 | private static class SpyComponent implements Component { 69 | public int updates = 0; 70 | } 71 | 72 | private static class IndexComponent implements Component { 73 | public int index = 0; 74 | } 75 | 76 | private static class IteratingComponentRemovalSystem extends IteratingSystem { 77 | 78 | private ComponentMapper sm; 79 | private ComponentMapper im; 80 | 81 | public IteratingComponentRemovalSystem () { 82 | super(Family.all(SpyComponent.class, IndexComponent.class).get()); 83 | 84 | sm = ComponentMapper.getFor(SpyComponent.class); 85 | im = ComponentMapper.getFor(IndexComponent.class); 86 | } 87 | 88 | @Override 89 | public void processEntity (Entity entity, float deltaTime) { 90 | int index = im.get(entity).index; 91 | if (index % 2 == 0) { 92 | entity.remove(SpyComponent.class); 93 | entity.remove(IndexComponent.class); 94 | } else { 95 | sm.get(entity).updates++; 96 | } 97 | } 98 | 99 | } 100 | 101 | private static class IteratingRemovalSystem extends IteratingSystem { 102 | private ComponentMapper sm; 103 | private ComponentMapper im; 104 | 105 | public IteratingRemovalSystem () { 106 | super(Family.all(SpyComponent.class, IndexComponent.class).get()); 107 | 108 | sm = ComponentMapper.getFor(SpyComponent.class); 109 | im = ComponentMapper.getFor(IndexComponent.class); 110 | } 111 | 112 | @Override 113 | public void addedToEngine (Engine engine) { 114 | super.addedToEngine(engine); 115 | } 116 | 117 | @Override 118 | public void processEntity (Entity entity, float deltaTime) { 119 | int index = im.get(entity).index; 120 | if (index % 2 == 0) { 121 | getEngine().removeEntity(entity); 122 | } else { 123 | sm.get(entity).updates++; 124 | } 125 | } 126 | 127 | } 128 | 129 | @Test 130 | @SuppressWarnings("unchecked") 131 | public void shouldIterateEntitiesWithCorrectFamily () { 132 | final Engine engine = new Engine(); 133 | 134 | final Family family = Family.all(ComponentA.class, ComponentB.class).get(); 135 | final IteratingSystemMock system = new IteratingSystemMock(family); 136 | final Entity e = new Entity(); 137 | 138 | engine.addSystem(system); 139 | engine.addEntity(e); 140 | 141 | // When entity has ComponentA 142 | e.add(new ComponentA()); 143 | engine.update(deltaTime); 144 | 145 | assertEquals(0, system.numUpdates); 146 | 147 | // When entity has ComponentA and ComponentB 148 | system.numUpdates = 0; 149 | e.add(new ComponentB()); 150 | engine.update(deltaTime); 151 | 152 | assertEquals(1, system.numUpdates); 153 | 154 | // When entity has ComponentA, ComponentB and ComponentC 155 | system.numUpdates = 0; 156 | e.add(new ComponentC()); 157 | engine.update(deltaTime); 158 | 159 | assertEquals(1, system.numUpdates); 160 | 161 | // When entity has ComponentB and ComponentC 162 | system.numUpdates = 0; 163 | e.remove(ComponentA.class); 164 | e.add(new ComponentC()); 165 | engine.update(deltaTime); 166 | 167 | assertEquals(0, system.numUpdates); 168 | } 169 | 170 | @Test 171 | public void entityRemovalWhileIterating () { 172 | Engine engine = new Engine(); 173 | ImmutableArray entities = engine.getEntitiesFor(Family.all(SpyComponent.class, IndexComponent.class).get()); 174 | ComponentMapper sm = ComponentMapper.getFor(SpyComponent.class); 175 | 176 | engine.addSystem(new IteratingRemovalSystem()); 177 | 178 | final int numEntities = 10; 179 | 180 | for (int i = 0; i < numEntities; ++i) { 181 | Entity e = new Entity(); 182 | e.add(new SpyComponent()); 183 | 184 | IndexComponent in = new IndexComponent(); 185 | in.index = i + 1; 186 | 187 | e.add(in); 188 | 189 | engine.addEntity(e); 190 | } 191 | 192 | engine.update(deltaTime); 193 | 194 | assertEquals(numEntities / 2, entities.size()); 195 | 196 | for (int i = 0; i < entities.size(); ++i) { 197 | Entity e = entities.get(i); 198 | 199 | assertEquals(1, sm.get(e).updates); 200 | } 201 | } 202 | 203 | @Test 204 | public void componentRemovalWhileIterating () { 205 | Engine engine = new Engine(); 206 | ImmutableArray entities = engine.getEntitiesFor(Family.all(SpyComponent.class, IndexComponent.class).get()); 207 | ComponentMapper sm = ComponentMapper.getFor(SpyComponent.class); 208 | 209 | engine.addSystem(new IteratingComponentRemovalSystem()); 210 | 211 | final int numEntities = 10; 212 | 213 | for (int i = 0; i < numEntities; ++i) { 214 | Entity e = new Entity(); 215 | e.add(new SpyComponent()); 216 | 217 | IndexComponent in = new IndexComponent(); 218 | in.index = i + 1; 219 | 220 | e.add(in); 221 | 222 | engine.addEntity(e); 223 | } 224 | 225 | engine.update(deltaTime); 226 | 227 | assertEquals(numEntities / 2, entities.size()); 228 | 229 | for (int i = 0; i < entities.size(); ++i) { 230 | Entity e = entities.get(i); 231 | 232 | assertEquals(1, sm.get(e).updates); 233 | } 234 | } 235 | 236 | @Test 237 | public void processingUtilityFunctions() { 238 | final Engine engine = new Engine(); 239 | 240 | final IteratingSystemMock system = new IteratingSystemMock(Family.all().get()); 241 | 242 | engine.addSystem(system); 243 | 244 | engine.update(deltaTime); 245 | assertEquals(1, system.numStartProcessing); 246 | assertEquals(1, system.numEndProcessing); 247 | 248 | engine.update(deltaTime); 249 | assertEquals(2, system.numStartProcessing); 250 | assertEquals(2, system.numEndProcessing); 251 | } 252 | 253 | } 254 | -------------------------------------------------------------------------------- /ashley/src/com/badlogic/ashley/core/Entity.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2014 See AUTHORS file. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | ******************************************************************************/ 16 | 17 | package com.badlogic.ashley.core; 18 | 19 | import com.badlogic.ashley.signals.Signal; 20 | import com.badlogic.ashley.utils.Bag; 21 | import com.badlogic.ashley.utils.ImmutableArray; 22 | import com.badlogic.gdx.utils.Array; 23 | import com.badlogic.gdx.utils.Bits; 24 | 25 | /** 26 | * Simple containers of {@link Component}s that give them "data". The component's data is then processed by {@link EntitySystem}s. 27 | * @author Stefan Bachmann 28 | */ 29 | public class Entity { 30 | /** A flag that can be used to bit mask this entity. Up to the user to manage. */ 31 | public int flags; 32 | /** Will dispatch an event when a component is added. */ 33 | public final Signal componentAdded; 34 | /** Will dispatch an event when a component is removed. */ 35 | public final Signal componentRemoved; 36 | 37 | boolean scheduledForRemoval; 38 | boolean removing; 39 | ComponentOperationHandler componentOperationHandler; 40 | 41 | private Bag components; 42 | private Array componentsArray; 43 | private ImmutableArray immutableComponentsArray; 44 | private Bits componentBits; 45 | private Bits familyBits; 46 | 47 | /** Creates an empty Entity. */ 48 | public Entity () { 49 | components = new Bag(); 50 | componentsArray = new Array(false, 16); 51 | immutableComponentsArray = new ImmutableArray(componentsArray); 52 | componentBits = new Bits(); 53 | familyBits = new Bits(); 54 | flags = 0; 55 | 56 | componentAdded = new Signal(); 57 | componentRemoved = new Signal(); 58 | } 59 | 60 | /** 61 | * Adds a {@link Component} to this Entity. If a {@link Component} of the same type already exists, it'll be replaced. 62 | * @return The Entity for easy chaining 63 | */ 64 | public Entity add (Component component) { 65 | if (addInternal(component)) { 66 | if (componentOperationHandler != null) { 67 | componentOperationHandler.add(this); 68 | } 69 | else { 70 | notifyComponentAdded(); 71 | } 72 | } 73 | 74 | return this; 75 | } 76 | 77 | /** 78 | * Adds a {@link Component} to this Entity. If a {@link Component} of the same type already exists, it'll be replaced. 79 | * @return The Component for direct component manipulation (e.g. PooledComponent) 80 | */ 81 | public T addAndReturn(T component) { 82 | add(component); 83 | return component; 84 | } 85 | 86 | /** 87 | * Removes the {@link Component} of the specified type. Since there is only ever one component of one type, we don't need an 88 | * instance reference. 89 | * @return The removed {@link Component}, or null if the Entity did not contain such a component. 90 | */ 91 | public T remove (Class componentClass) { 92 | ComponentType componentType = ComponentType.getFor(componentClass); 93 | int componentTypeIndex = componentType.getIndex(); 94 | 95 | if(components.isIndexWithinBounds(componentTypeIndex)){ 96 | Component removeComponent = components.get(componentTypeIndex); 97 | 98 | if (removeComponent != null && removeInternal(componentClass) != null) { 99 | if (componentOperationHandler != null) { 100 | componentOperationHandler.remove(this); 101 | } 102 | else { 103 | notifyComponentRemoved(); 104 | } 105 | } 106 | 107 | return (T) removeComponent; 108 | } 109 | 110 | return null; 111 | } 112 | 113 | /** Removes all the {@link Component}'s from the Entity. */ 114 | public void removeAll () { 115 | while (componentsArray.size > 0) { 116 | remove(componentsArray.get(0).getClass()); 117 | } 118 | } 119 | 120 | /** @return immutable collection with all the Entity {@link Component}s. */ 121 | public ImmutableArray getComponents () { 122 | return immutableComponentsArray; 123 | } 124 | 125 | /** 126 | * Retrieve a component from this {@link Entity} by class. Note: the preferred way of retrieving {@link Component}s is 127 | * using {@link ComponentMapper}s. This method is provided for convenience; using a ComponentMapper provides O(1) access to 128 | * components while this method provides only O(logn). 129 | * @param componentClass the class of the component to be retrieved. 130 | * @return the instance of the specified {@link Component} attached to this {@link Entity}, or null if no such 131 | * {@link Component} exists. 132 | */ 133 | public T getComponent (Class componentClass) { 134 | return getComponent(ComponentType.getFor(componentClass)); 135 | } 136 | 137 | /** 138 | * Internal use. 139 | * @return The {@link Component} object for the specified class, null if the Entity does not have any components for that class. 140 | */ 141 | @SuppressWarnings("unchecked") 142 | T getComponent (ComponentType componentType) { 143 | int componentTypeIndex = componentType.getIndex(); 144 | 145 | if (componentTypeIndex < components.getCapacity()) { 146 | return (T)components.get(componentType.getIndex()); 147 | } else { 148 | return null; 149 | } 150 | } 151 | 152 | /** 153 | * @return Whether or not the Entity has a {@link Component} for the specified class. 154 | */ 155 | boolean hasComponent (ComponentType componentType) { 156 | return componentBits.get(componentType.getIndex()); 157 | } 158 | 159 | /** 160 | * @return This Entity's component bits, describing all the {@link Component}s it contains. 161 | */ 162 | Bits getComponentBits () { 163 | return componentBits; 164 | } 165 | 166 | /** @return This Entity's {@link Family} bits, describing all the {@link EntitySystem}s it currently is being processed by. */ 167 | Bits getFamilyBits () { 168 | return familyBits; 169 | } 170 | 171 | /** 172 | * @param component 173 | * @return whether or not the component was added. 174 | */ 175 | boolean addInternal (Component component) { 176 | Class componentClass = component.getClass(); 177 | Component oldComponent = getComponent(componentClass); 178 | 179 | if (component == oldComponent) { 180 | return false; 181 | } 182 | 183 | if (oldComponent != null) { 184 | removeInternal(componentClass); 185 | } 186 | 187 | int componentTypeIndex = ComponentType.getIndexFor(componentClass); 188 | components.set(componentTypeIndex, component); 189 | componentsArray.add(component); 190 | componentBits.set(componentTypeIndex); 191 | 192 | return true; 193 | } 194 | 195 | /** 196 | * @param componentClass 197 | * @return the component if the specified class was found and removed. Otherwise, null 198 | */ 199 | Component removeInternal (Class componentClass) { 200 | ComponentType componentType = ComponentType.getFor(componentClass); 201 | int componentTypeIndex = componentType.getIndex(); 202 | Component removeComponent = components.get(componentTypeIndex); 203 | 204 | if (removeComponent != null) { 205 | components.set(componentTypeIndex, null); 206 | componentsArray.removeValue(removeComponent, true); 207 | componentBits.clear(componentTypeIndex); 208 | 209 | return removeComponent; 210 | } 211 | 212 | return null; 213 | } 214 | 215 | void notifyComponentAdded() { 216 | componentAdded.dispatch(this); 217 | } 218 | 219 | void notifyComponentRemoved() { 220 | componentRemoved.dispatch(this); 221 | } 222 | 223 | /** @return true if the entity is scheduled to be removed */ 224 | public boolean isScheduledForRemoval () { 225 | return scheduledForRemoval; 226 | } 227 | 228 | /** @return true if the entity is being removed */ 229 | public boolean isRemoving() { 230 | return removing; 231 | } 232 | } 233 | --------------------------------------------------------------------------------