├── .classpath
├── .gitignore
├── .project
├── .settings
├── org.eclipse.core.resources.prefs
├── org.eclipse.jdt.core.prefs
└── org.eclipse.ltk.core.refactoring.prefs
├── LICENSE
├── README.md
├── assets-raw
├── alien
│ ├── alien.spine
│ └── images
│ │ ├── back_foot.png
│ │ ├── back_shin.png
│ │ ├── back_thigh.png
│ │ ├── backarmor.png
│ │ ├── blown_up_nck.png
│ │ ├── body.png
│ │ ├── burst01.png
│ │ ├── burst02.png
│ │ ├── front_foot.png
│ │ ├── front_lower_arm.png
│ │ ├── front_shin.png
│ │ ├── front_thigh.png
│ │ ├── front_upper_arm.png
│ │ ├── head.png
│ │ ├── jaw.png
│ │ ├── lower_back_arm.png
│ │ ├── metaljaw.png
│ │ ├── splat01.png
│ │ ├── splat02.png
│ │ ├── splat03.png
│ │ └── upper_back_arm.png
├── spineboy
│ ├── images
│ │ ├── eye_indifferent.png
│ │ ├── eye_surprised.png
│ │ ├── front_bracer.png
│ │ ├── front_fist_closed.png
│ │ ├── front_fist_open.png
│ │ ├── front_foot.png
│ │ ├── front_foot_bend1.png
│ │ ├── front_foot_bend2.png
│ │ ├── front_shin.png
│ │ ├── front_thigh.png
│ │ ├── front_upper_arm.png
│ │ ├── goggles.png
│ │ ├── gun.png
│ │ ├── head.png
│ │ ├── mouth_grind.png
│ │ ├── mouth_oooo.png
│ │ ├── mouth_smile.png
│ │ ├── muzzle.png
│ │ ├── neck.png
│ │ ├── rear_bracer.png
│ │ ├── rear_foot.png
│ │ ├── rear_foot_bend1.png
│ │ ├── rear_foot_bend2.png
│ │ ├── rear_shin.png
│ │ ├── rear_thigh.png
│ │ ├── rear_upper_arm.png
│ │ ├── torso.png
│ │ └── torso_twisted.png
│ └── spineboy.spine
└── tiles
│ ├── decals
│ ├── ceiling-lamp-wire-01.png
│ ├── ceiling_lamp-01.png
│ ├── collision.png
│ ├── column-01.png
│ ├── column-02.png
│ ├── column-03.png
│ ├── crate-01.png
│ ├── crate-02.png
│ ├── crate-3.png
│ ├── fill.png
│ ├── fusebox-01.png
│ ├── metal-01.png
│ └── pack.json
│ ├── decals02
│ ├── ceiling-01.png
│ ├── concrete-01.png
│ ├── edge-left-01.png
│ ├── ground-01.png
│ ├── wall-left-01.png
│ ├── wall-left_bottom-01.png
│ ├── wall-right-01.png
│ └── wall-right_top-01.png
│ ├── decals03
│ ├── concrete-02.png
│ ├── concrete-03.png
│ ├── metal-02.png
│ └── metal-03.png
│ ├── lights
│ ├── light-01.png
│ ├── light-02.png
│ └── pack.json
│ ├── map.tmx
│ ├── pack.json
│ ├── rock
│ ├── pack.json
│ ├── rock-01.png
│ ├── rock-02.png
│ ├── rock-03.png
│ └── rock-04.png
│ ├── tint01
│ ├── pack.json
│ ├── tint-01.png
│ ├── tint-02.png
│ ├── tint-03.png
│ └── tint-04.png
│ ├── tint02
│ ├── pack.json
│ ├── tint-01.png
│ ├── tint-02.png
│ ├── tint-03.png
│ └── tint-04.png
│ ├── tint03
│ ├── tint-01.png
│ ├── tint-02.png
│ ├── tint-03.png
│ ├── tint-04.png
│ ├── tint-05.png
│ ├── tint-06.png
│ ├── tint-07.png
│ ├── tint-08.png
│ ├── tint-09.png
│ ├── tint-10.png
│ ├── tint-11.png
│ └── tint-12.png
│ └── walls
│ ├── pack.json
│ ├── wall-01.png
│ ├── wall-02.png
│ ├── wall-03.png
│ └── wall-04.png
├── assets
├── alien
│ ├── alien.atlas
│ ├── alien.json
│ └── alien.png
├── bullet-hit.png
├── bullet.png
├── crosshair.png
├── gameOver.png
├── map
│ ├── map.atlas
│ ├── map.png
│ ├── map.tmx
│ ├── map2.png
│ ├── map3.png
│ ├── map4.png
│ ├── map5.png
│ ├── map6.png
│ ├── map7.png
│ ├── map8.png
│ └── map9.png
├── sounds
│ ├── footstep1.ogg
│ ├── footstep2.ogg
│ ├── hit.ogg
│ ├── hurt-alien.ogg
│ ├── hurt-player.ogg
│ ├── shoot.ogg
│ └── squish.ogg
├── spineboy
│ ├── spineboy.atlas
│ ├── spineboy.json
│ └── spineboy.png
├── start.png
├── title.png
├── youLose.png
└── youWin.png
├── pom.xml
├── src
└── com
│ └── esotericsoftware
│ └── spine
│ └── superspineboy
│ ├── Assets.java
│ ├── Character.java
│ ├── CharacterView.java
│ ├── Enemy.java
│ ├── EnemyView.java
│ ├── Model.java
│ ├── Player.java
│ ├── PlayerView.java
│ ├── SuperSpineboy.java
│ ├── UI.java
│ └── View.java
├── update-dependencies.cmd
└── update-dependencies.sh
/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | bin
2 | *.psd
3 |
--------------------------------------------------------------------------------
/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | super-spineboy
4 | NO_M2ECLIPSE_SUPPORT: Project files created with the maven-eclipse-plugin are not supported in M2Eclipse.
5 |
6 |
7 |
8 | org.eclipse.jdt.core.javabuilder
9 |
10 |
11 |
12 | org.eclipse.jdt.core.javanature
13 |
14 |
--------------------------------------------------------------------------------
/.settings/org.eclipse.core.resources.prefs:
--------------------------------------------------------------------------------
1 | eclipse.preferences.version=1
2 | encoding/=UTF-8
3 |
--------------------------------------------------------------------------------
/.settings/org.eclipse.jdt.core.prefs:
--------------------------------------------------------------------------------
1 | eclipse.preferences.version=1
2 | org.eclipse.jdt.core.builder.annotationPath.allLocations=disabled
3 | org.eclipse.jdt.core.compiler.annotation.inheritNullAnnotations=disabled
4 | org.eclipse.jdt.core.compiler.annotation.missingNonNullByDefaultAnnotation=ignore
5 | org.eclipse.jdt.core.compiler.annotation.nonnull=org.eclipse.jdt.annotation.NonNull
6 | org.eclipse.jdt.core.compiler.annotation.nonnull.secondary=
7 | org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jdt.annotation.NonNullByDefault
8 | org.eclipse.jdt.core.compiler.annotation.nonnullbydefault.secondary=
9 | org.eclipse.jdt.core.compiler.annotation.notowning=org.eclipse.jdt.annotation.NotOwning
10 | org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nullable
11 | org.eclipse.jdt.core.compiler.annotation.nullable.secondary=
12 | org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled
13 | org.eclipse.jdt.core.compiler.annotation.owning=org.eclipse.jdt.annotation.Owning
14 | org.eclipse.jdt.core.compiler.annotation.resourceanalysis=disabled
15 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
16 | org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
17 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
18 | org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
19 | org.eclipse.jdt.core.compiler.compliance=1.8
20 | org.eclipse.jdt.core.compiler.debug.lineNumber=generate
21 | org.eclipse.jdt.core.compiler.debug.localVariable=generate
22 | org.eclipse.jdt.core.compiler.debug.sourceFile=generate
23 | org.eclipse.jdt.core.compiler.problem.APILeak=warning
24 | org.eclipse.jdt.core.compiler.problem.annotatedTypeArgumentToUnannotated=info
25 | org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning
26 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
27 | org.eclipse.jdt.core.compiler.problem.autoboxing=ignore
28 | org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning
29 | org.eclipse.jdt.core.compiler.problem.deadCode=ignore
30 | org.eclipse.jdt.core.compiler.problem.deprecation=ignore
31 | org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
32 | org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
33 | org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
34 | org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore
35 | org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
36 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
37 | org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=ignore
38 | org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore
39 | org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled
40 | org.eclipse.jdt.core.compiler.problem.fieldHiding=ignore
41 | org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning
42 | org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning
43 | org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
44 | org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning
45 | org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=disabled
46 | org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning
47 | org.eclipse.jdt.core.compiler.problem.incompatibleOwningContract=warning
48 | org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=ignore
49 | org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore
50 | org.eclipse.jdt.core.compiler.problem.insufficientResourceAnalysis=warning
51 | org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore
52 | org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning
53 | org.eclipse.jdt.core.compiler.problem.missingDefaultCase=ignore
54 | org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=ignore
55 | org.eclipse.jdt.core.compiler.problem.missingEnumCaseDespiteDefault=disabled
56 | org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=ignore
57 | org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=ignore
58 | org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled
59 | org.eclipse.jdt.core.compiler.problem.missingSerialVersion=ignore
60 | org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=ignore
61 | org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning
62 | org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning
63 | org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore
64 | org.eclipse.jdt.core.compiler.problem.nonnullParameterAnnotationDropped=warning
65 | org.eclipse.jdt.core.compiler.problem.nonnullTypeVariableFromLegacyInvocation=warning
66 | org.eclipse.jdt.core.compiler.problem.nullAnnotationInferenceConflict=error
67 | org.eclipse.jdt.core.compiler.problem.nullReference=warning
68 | org.eclipse.jdt.core.compiler.problem.nullSpecViolation=error
69 | org.eclipse.jdt.core.compiler.problem.nullUncheckedConversion=warning
70 | org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning
71 | org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore
72 | org.eclipse.jdt.core.compiler.problem.pessimisticNullAnalysisForFreeTypeVariables=warning
73 | org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=warning
74 | org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore
75 | org.eclipse.jdt.core.compiler.problem.potentiallyUnclosedCloseable=ignore
76 | org.eclipse.jdt.core.compiler.problem.rawTypeReference=ignore
77 | org.eclipse.jdt.core.compiler.problem.redundantNullAnnotation=warning
78 | org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore
79 | org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=ignore
80 | org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=ignore
81 | org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore
82 | org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore
83 | org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning
84 | org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
85 | org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
86 | org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled
87 | org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
88 | org.eclipse.jdt.core.compiler.problem.suppressWarningsNotFullyAnalysed=info
89 | org.eclipse.jdt.core.compiler.problem.syntacticNullAnalysisForFields=disabled
90 | org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore
91 | org.eclipse.jdt.core.compiler.problem.terminalDeprecation=warning
92 | org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning
93 | org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=enabled
94 | org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=ignore
95 | org.eclipse.jdt.core.compiler.problem.unclosedCloseable=ignore
96 | org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore
97 | org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning
98 | org.eclipse.jdt.core.compiler.problem.unlikelyCollectionMethodArgumentType=warning
99 | org.eclipse.jdt.core.compiler.problem.unlikelyCollectionMethodArgumentTypeStrict=disabled
100 | org.eclipse.jdt.core.compiler.problem.unlikelyEqualsArgumentType=info
101 | org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore
102 | org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=ignore
103 | org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore
104 | org.eclipse.jdt.core.compiler.problem.unstableAutoModuleName=warning
105 | org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore
106 | org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
107 | org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled
108 | org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=enabled
109 | org.eclipse.jdt.core.compiler.problem.unusedExceptionParameter=ignore
110 | org.eclipse.jdt.core.compiler.problem.unusedImport=ignore
111 | org.eclipse.jdt.core.compiler.problem.unusedLabel=warning
112 | org.eclipse.jdt.core.compiler.problem.unusedLambdaParameter=warning
113 | org.eclipse.jdt.core.compiler.problem.unusedLocal=ignore
114 | org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=ignore
115 | org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore
116 | org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled
117 | org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=enabled
118 | org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=enabled
119 | org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=ignore
120 | org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=ignore
121 | org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
122 | org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
123 | org.eclipse.jdt.core.compiler.release=disabled
124 | org.eclipse.jdt.core.compiler.source=1.8
125 |
--------------------------------------------------------------------------------
/.settings/org.eclipse.ltk.core.refactoring.prefs:
--------------------------------------------------------------------------------
1 | eclipse.preferences.version=1
2 | org.eclipse.ltk.core.refactoring.enable.project.refactoring.history=false
3 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Spine Runtimes License Agreement
2 | Last updated February 20, 2024. Replaces all prior versions.
3 |
4 | Copyright (c) 2013-2024, Esoteric Software LLC
5 |
6 | Integration of the Spine Runtimes into software or otherwise creating derivative works
7 | of the Spine Runtimes is permitted under the terms and conditions of Section 2 of the
8 | Spine Editor License Agreement:
9 | https://esotericsoftware.com/spine-editor-license
10 |
11 | Otherwise, it is permitted to integrate the Spine Runtimes into software or otherwise
12 | create derivative works of the Spine Runtimes (collectively, "Products"), provided that
13 | each user of the Products must obtain their own Spine Editor license and redistribution
14 | of the Products in any form must include this license and copyright notice.
15 |
16 | THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY EXPRESS OR IMPLIED
17 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18 | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR
19 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
21 | BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY
22 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE SPINE RUNTIMES,
24 | EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | Super Spineboy is a platformer game for Windows, Mac and Linux written using [Spine](https://esotericsoftware.com/) and [spine-libgdx](https://github.com/EsotericSoftware/spine-runtimes/tree/master/spine-libgdx). Spine is a 2D animation tool specifically for games and Super Spineboy shows some of the ways to make use of Spine skeletons and animations in an actual game.
4 |
5 | [](https://www.youtube.com/watch?v=zAZ_PxxEgDI)
6 |
7 | ## Download
8 |
9 | Super Spineboy can be [downloaded](https://esotericsoftware.com/files/runtimes/superSpineboy.jar) in binary form and run on Windows, Mac or Linux. Java 1.6+ is required. To run Super Spineboy, double click the `superSpineboy.jar` file or run it from the command line:
10 |
11 | ```
12 | java -jar superSpineboy.jar
13 | ```
14 |
15 | ## Controls
16 |
17 | * Left click shoots toward the mouse position. Hold to keep shooting.
18 | * `A` is left, `D` is right, `W` is jump.
19 | * Alternatively, `left arrow` is left, `right arrow` is right, `space` is jump.
20 | * Press `alt + enter` or click `Fullscreen` in the menu to run the game fullscreen.
21 | * Press the number keys `1` through `6` to control the game speed, allowing you to see how smooth the animations are and the transitions between animations.
22 | * Press `tilda` or `P` to pause.
23 | * Press `Z` to zoom in/out so you can see the animations more easily.
24 |
25 | ## Gameplay tips
26 |
27 | You may find Super Spineboy difficult at first. The game is relatively short, so the difficulty ramps up quickly. These tips may help you overcome the hordes!
28 |
29 | * Don't move through further into the level until you've killed all the enemies you find.
30 | * Spineboy's weapon shoots very fast, but suffers from reduced accuracy when shot continuously. Cease firing momentarily to regain accuracy.
31 | * You cannot shoot backward when running away, but you can jump while running away and shoot backward in the air.
32 | * Standing your ground and mowing down enemies is great, but there are quickly so many enemies that you get overrun. When this happens, goomba head stomp the enemies. This is key to winning!
33 | * Getting sandwiched between two groups of enemies is a sure way to die. Head stomp your way to one side so you aren't surrounded.
34 | * If the game runs poorly, try unchecking `Background` in the menu.
35 |
36 | ## Source
37 |
38 | Super Spineboy is written in Java and uses OpenGL, [libgdx](http://libgdx.badlogicgames.com/), [Spine](https://esotericsoftware.com/) and [spine-libgdx](https://github.com/EsotericSoftware/spine-runtimes/tree/master/spine-libgdx). A loose [MVC](http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller) design pattern is used for code organization. This makes for a clean separation between the game logic and what is drawn.
39 |
40 | The Super Spineboy source can be downloaded from GitHub using a Git client or as a [zip file](https://github.com/EsotericSoftware/spine-superspineboy/archive/master.zip). To run from source using Eclipse, click `File` -> `Import` -> `Existing projects`.
41 |
42 | ## License
43 |
44 | Super Spineboy is licensed under the [Spine Runtime License](https://github.com/EsotericSoftware/spine-superspineboy/blob/master/LICENSE). Please see the license for full details, but this basically means that if you license [Spine](https://esotericsoftware.com/), you can create derivative works or otherwise use Super Spineboy however you like.
45 |
46 | ## Screenshots
47 |
48 | 
49 |
50 | 
51 |
52 | 
53 |
--------------------------------------------------------------------------------
/assets-raw/alien/alien.spine:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/alien/alien.spine
--------------------------------------------------------------------------------
/assets-raw/alien/images/back_foot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/alien/images/back_foot.png
--------------------------------------------------------------------------------
/assets-raw/alien/images/back_shin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/alien/images/back_shin.png
--------------------------------------------------------------------------------
/assets-raw/alien/images/back_thigh.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/alien/images/back_thigh.png
--------------------------------------------------------------------------------
/assets-raw/alien/images/backarmor.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/alien/images/backarmor.png
--------------------------------------------------------------------------------
/assets-raw/alien/images/blown_up_nck.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/alien/images/blown_up_nck.png
--------------------------------------------------------------------------------
/assets-raw/alien/images/body.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/alien/images/body.png
--------------------------------------------------------------------------------
/assets-raw/alien/images/burst01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/alien/images/burst01.png
--------------------------------------------------------------------------------
/assets-raw/alien/images/burst02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/alien/images/burst02.png
--------------------------------------------------------------------------------
/assets-raw/alien/images/front_foot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/alien/images/front_foot.png
--------------------------------------------------------------------------------
/assets-raw/alien/images/front_lower_arm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/alien/images/front_lower_arm.png
--------------------------------------------------------------------------------
/assets-raw/alien/images/front_shin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/alien/images/front_shin.png
--------------------------------------------------------------------------------
/assets-raw/alien/images/front_thigh.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/alien/images/front_thigh.png
--------------------------------------------------------------------------------
/assets-raw/alien/images/front_upper_arm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/alien/images/front_upper_arm.png
--------------------------------------------------------------------------------
/assets-raw/alien/images/head.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/alien/images/head.png
--------------------------------------------------------------------------------
/assets-raw/alien/images/jaw.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/alien/images/jaw.png
--------------------------------------------------------------------------------
/assets-raw/alien/images/lower_back_arm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/alien/images/lower_back_arm.png
--------------------------------------------------------------------------------
/assets-raw/alien/images/metaljaw.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/alien/images/metaljaw.png
--------------------------------------------------------------------------------
/assets-raw/alien/images/splat01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/alien/images/splat01.png
--------------------------------------------------------------------------------
/assets-raw/alien/images/splat02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/alien/images/splat02.png
--------------------------------------------------------------------------------
/assets-raw/alien/images/splat03.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/alien/images/splat03.png
--------------------------------------------------------------------------------
/assets-raw/alien/images/upper_back_arm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/alien/images/upper_back_arm.png
--------------------------------------------------------------------------------
/assets-raw/spineboy/images/eye_indifferent.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/spineboy/images/eye_indifferent.png
--------------------------------------------------------------------------------
/assets-raw/spineboy/images/eye_surprised.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/spineboy/images/eye_surprised.png
--------------------------------------------------------------------------------
/assets-raw/spineboy/images/front_bracer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/spineboy/images/front_bracer.png
--------------------------------------------------------------------------------
/assets-raw/spineboy/images/front_fist_closed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/spineboy/images/front_fist_closed.png
--------------------------------------------------------------------------------
/assets-raw/spineboy/images/front_fist_open.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/spineboy/images/front_fist_open.png
--------------------------------------------------------------------------------
/assets-raw/spineboy/images/front_foot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/spineboy/images/front_foot.png
--------------------------------------------------------------------------------
/assets-raw/spineboy/images/front_foot_bend1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/spineboy/images/front_foot_bend1.png
--------------------------------------------------------------------------------
/assets-raw/spineboy/images/front_foot_bend2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/spineboy/images/front_foot_bend2.png
--------------------------------------------------------------------------------
/assets-raw/spineboy/images/front_shin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/spineboy/images/front_shin.png
--------------------------------------------------------------------------------
/assets-raw/spineboy/images/front_thigh.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/spineboy/images/front_thigh.png
--------------------------------------------------------------------------------
/assets-raw/spineboy/images/front_upper_arm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/spineboy/images/front_upper_arm.png
--------------------------------------------------------------------------------
/assets-raw/spineboy/images/goggles.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/spineboy/images/goggles.png
--------------------------------------------------------------------------------
/assets-raw/spineboy/images/gun.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/spineboy/images/gun.png
--------------------------------------------------------------------------------
/assets-raw/spineboy/images/head.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/spineboy/images/head.png
--------------------------------------------------------------------------------
/assets-raw/spineboy/images/mouth_grind.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/spineboy/images/mouth_grind.png
--------------------------------------------------------------------------------
/assets-raw/spineboy/images/mouth_oooo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/spineboy/images/mouth_oooo.png
--------------------------------------------------------------------------------
/assets-raw/spineboy/images/mouth_smile.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/spineboy/images/mouth_smile.png
--------------------------------------------------------------------------------
/assets-raw/spineboy/images/muzzle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/spineboy/images/muzzle.png
--------------------------------------------------------------------------------
/assets-raw/spineboy/images/neck.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/spineboy/images/neck.png
--------------------------------------------------------------------------------
/assets-raw/spineboy/images/rear_bracer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/spineboy/images/rear_bracer.png
--------------------------------------------------------------------------------
/assets-raw/spineboy/images/rear_foot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/spineboy/images/rear_foot.png
--------------------------------------------------------------------------------
/assets-raw/spineboy/images/rear_foot_bend1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/spineboy/images/rear_foot_bend1.png
--------------------------------------------------------------------------------
/assets-raw/spineboy/images/rear_foot_bend2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/spineboy/images/rear_foot_bend2.png
--------------------------------------------------------------------------------
/assets-raw/spineboy/images/rear_shin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/spineboy/images/rear_shin.png
--------------------------------------------------------------------------------
/assets-raw/spineboy/images/rear_thigh.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/spineboy/images/rear_thigh.png
--------------------------------------------------------------------------------
/assets-raw/spineboy/images/rear_upper_arm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/spineboy/images/rear_upper_arm.png
--------------------------------------------------------------------------------
/assets-raw/spineboy/images/torso.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/spineboy/images/torso.png
--------------------------------------------------------------------------------
/assets-raw/spineboy/images/torso_twisted.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/spineboy/images/torso_twisted.png
--------------------------------------------------------------------------------
/assets-raw/spineboy/spineboy.spine:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/spineboy/spineboy.spine
--------------------------------------------------------------------------------
/assets-raw/tiles/decals/ceiling-lamp-wire-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/tiles/decals/ceiling-lamp-wire-01.png
--------------------------------------------------------------------------------
/assets-raw/tiles/decals/ceiling_lamp-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/tiles/decals/ceiling_lamp-01.png
--------------------------------------------------------------------------------
/assets-raw/tiles/decals/collision.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/tiles/decals/collision.png
--------------------------------------------------------------------------------
/assets-raw/tiles/decals/column-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/tiles/decals/column-01.png
--------------------------------------------------------------------------------
/assets-raw/tiles/decals/column-02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/tiles/decals/column-02.png
--------------------------------------------------------------------------------
/assets-raw/tiles/decals/column-03.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/tiles/decals/column-03.png
--------------------------------------------------------------------------------
/assets-raw/tiles/decals/crate-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/tiles/decals/crate-01.png
--------------------------------------------------------------------------------
/assets-raw/tiles/decals/crate-02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/tiles/decals/crate-02.png
--------------------------------------------------------------------------------
/assets-raw/tiles/decals/crate-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/tiles/decals/crate-3.png
--------------------------------------------------------------------------------
/assets-raw/tiles/decals/fill.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/tiles/decals/fill.png
--------------------------------------------------------------------------------
/assets-raw/tiles/decals/fusebox-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/tiles/decals/fusebox-01.png
--------------------------------------------------------------------------------
/assets-raw/tiles/decals/metal-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/tiles/decals/metal-01.png
--------------------------------------------------------------------------------
/assets-raw/tiles/decals/pack.json:
--------------------------------------------------------------------------------
1 | {
2 | combineSubdirectories: true,
3 | }
--------------------------------------------------------------------------------
/assets-raw/tiles/decals02/ceiling-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/tiles/decals02/ceiling-01.png
--------------------------------------------------------------------------------
/assets-raw/tiles/decals02/concrete-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/tiles/decals02/concrete-01.png
--------------------------------------------------------------------------------
/assets-raw/tiles/decals02/edge-left-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/tiles/decals02/edge-left-01.png
--------------------------------------------------------------------------------
/assets-raw/tiles/decals02/ground-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/tiles/decals02/ground-01.png
--------------------------------------------------------------------------------
/assets-raw/tiles/decals02/wall-left-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/tiles/decals02/wall-left-01.png
--------------------------------------------------------------------------------
/assets-raw/tiles/decals02/wall-left_bottom-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/tiles/decals02/wall-left_bottom-01.png
--------------------------------------------------------------------------------
/assets-raw/tiles/decals02/wall-right-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/tiles/decals02/wall-right-01.png
--------------------------------------------------------------------------------
/assets-raw/tiles/decals02/wall-right_top-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/tiles/decals02/wall-right_top-01.png
--------------------------------------------------------------------------------
/assets-raw/tiles/decals03/concrete-02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/tiles/decals03/concrete-02.png
--------------------------------------------------------------------------------
/assets-raw/tiles/decals03/concrete-03.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/tiles/decals03/concrete-03.png
--------------------------------------------------------------------------------
/assets-raw/tiles/decals03/metal-02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/tiles/decals03/metal-02.png
--------------------------------------------------------------------------------
/assets-raw/tiles/decals03/metal-03.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/tiles/decals03/metal-03.png
--------------------------------------------------------------------------------
/assets-raw/tiles/lights/light-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/tiles/lights/light-01.png
--------------------------------------------------------------------------------
/assets-raw/tiles/lights/light-02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/tiles/lights/light-02.png
--------------------------------------------------------------------------------
/assets-raw/tiles/lights/pack.json:
--------------------------------------------------------------------------------
1 | {
2 | paddingX: 0,
3 | paddingY: 0,
4 | combineSubdirectories: true,
5 | wrapX: ClampToEdge,
6 | wrapY: ClampToEdge,
7 | grid: true
8 | }
--------------------------------------------------------------------------------
/assets-raw/tiles/map.tmx:
--------------------------------------------------------------------------------
1 |
2 |
234 |
--------------------------------------------------------------------------------
/assets-raw/tiles/pack.json:
--------------------------------------------------------------------------------
1 | {
2 | scale: [ 1 ],
3 | maxWidth: 1024,
4 | stripWhitespaceX: false,
5 | stripWhitespaceY: false,
6 | duplicatePadding: true,
7 | filterMin: Linear,
8 | flattenPaths: false,
9 | scaleSuffix: [
10 | "",
11 | "",
12 | "",
13 | "",
14 | ""
15 | ],
16 | wrapX: ClampToEdge,
17 | wrapY: ClampToEdge,
18 | alias: true,
19 | debug: false,
20 | edgePadding: false,
21 | pot: true,
22 | premultiplyAlpha: false,
23 | outputFormat: png,
24 | minHeight: 16,
25 | fast: false,
26 | square: false,
27 | limitMemory: true,
28 | minWidth: 16,
29 | paddingX: 2,
30 | paddingY: 2,
31 | grid: false,
32 | combineSubdirectories: false,
33 | maxHeight: 1024,
34 | alphaThreshold: 0,
35 | jpegQuality: 0.9,
36 | bleed: true,
37 | format: RGBA8888,
38 | useIndexes: false,
39 | ignoreBlankImages: true,
40 | filterMag: Linear,
41 | rotation: false
42 | }
--------------------------------------------------------------------------------
/assets-raw/tiles/rock/pack.json:
--------------------------------------------------------------------------------
1 | {
2 | paddingX: 0,
3 | paddingY: 0,
4 | combineSubdirectories: true,
5 | wrapX: ClampToEdge,
6 | wrapY: ClampToEdge,
7 | grid: true
8 | }
--------------------------------------------------------------------------------
/assets-raw/tiles/rock/rock-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/tiles/rock/rock-01.png
--------------------------------------------------------------------------------
/assets-raw/tiles/rock/rock-02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/tiles/rock/rock-02.png
--------------------------------------------------------------------------------
/assets-raw/tiles/rock/rock-03.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/tiles/rock/rock-03.png
--------------------------------------------------------------------------------
/assets-raw/tiles/rock/rock-04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/tiles/rock/rock-04.png
--------------------------------------------------------------------------------
/assets-raw/tiles/tint01/pack.json:
--------------------------------------------------------------------------------
1 | {
2 | paddingX: 0,
3 | paddingY: 0,
4 | combineSubdirectories: true,
5 | wrapX: ClampToEdge,
6 | wrapY: ClampToEdge,
7 | grid: true
8 | }
--------------------------------------------------------------------------------
/assets-raw/tiles/tint01/tint-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/tiles/tint01/tint-01.png
--------------------------------------------------------------------------------
/assets-raw/tiles/tint01/tint-02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/tiles/tint01/tint-02.png
--------------------------------------------------------------------------------
/assets-raw/tiles/tint01/tint-03.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/tiles/tint01/tint-03.png
--------------------------------------------------------------------------------
/assets-raw/tiles/tint01/tint-04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/tiles/tint01/tint-04.png
--------------------------------------------------------------------------------
/assets-raw/tiles/tint02/pack.json:
--------------------------------------------------------------------------------
1 | {
2 | paddingX: 0,
3 | paddingY: 0,
4 | combineSubdirectories: true,
5 | wrapX: ClampToEdge,
6 | wrapY: ClampToEdge,
7 | grid: true
8 | }
--------------------------------------------------------------------------------
/assets-raw/tiles/tint02/tint-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/tiles/tint02/tint-01.png
--------------------------------------------------------------------------------
/assets-raw/tiles/tint02/tint-02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/tiles/tint02/tint-02.png
--------------------------------------------------------------------------------
/assets-raw/tiles/tint02/tint-03.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/tiles/tint02/tint-03.png
--------------------------------------------------------------------------------
/assets-raw/tiles/tint02/tint-04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/tiles/tint02/tint-04.png
--------------------------------------------------------------------------------
/assets-raw/tiles/tint03/tint-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/tiles/tint03/tint-01.png
--------------------------------------------------------------------------------
/assets-raw/tiles/tint03/tint-02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/tiles/tint03/tint-02.png
--------------------------------------------------------------------------------
/assets-raw/tiles/tint03/tint-03.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/tiles/tint03/tint-03.png
--------------------------------------------------------------------------------
/assets-raw/tiles/tint03/tint-04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/tiles/tint03/tint-04.png
--------------------------------------------------------------------------------
/assets-raw/tiles/tint03/tint-05.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/tiles/tint03/tint-05.png
--------------------------------------------------------------------------------
/assets-raw/tiles/tint03/tint-06.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/tiles/tint03/tint-06.png
--------------------------------------------------------------------------------
/assets-raw/tiles/tint03/tint-07.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/tiles/tint03/tint-07.png
--------------------------------------------------------------------------------
/assets-raw/tiles/tint03/tint-08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/tiles/tint03/tint-08.png
--------------------------------------------------------------------------------
/assets-raw/tiles/tint03/tint-09.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/tiles/tint03/tint-09.png
--------------------------------------------------------------------------------
/assets-raw/tiles/tint03/tint-10.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/tiles/tint03/tint-10.png
--------------------------------------------------------------------------------
/assets-raw/tiles/tint03/tint-11.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/tiles/tint03/tint-11.png
--------------------------------------------------------------------------------
/assets-raw/tiles/tint03/tint-12.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/tiles/tint03/tint-12.png
--------------------------------------------------------------------------------
/assets-raw/tiles/walls/pack.json:
--------------------------------------------------------------------------------
1 | {
2 | paddingX: 0,
3 | paddingY: 0,
4 | combineSubdirectories: true,
5 | wrapX: ClampToEdge,
6 | wrapY: ClampToEdge,
7 | grid: true
8 | }
--------------------------------------------------------------------------------
/assets-raw/tiles/walls/wall-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/tiles/walls/wall-01.png
--------------------------------------------------------------------------------
/assets-raw/tiles/walls/wall-02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/tiles/walls/wall-02.png
--------------------------------------------------------------------------------
/assets-raw/tiles/walls/wall-03.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/tiles/walls/wall-03.png
--------------------------------------------------------------------------------
/assets-raw/tiles/walls/wall-04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets-raw/tiles/walls/wall-04.png
--------------------------------------------------------------------------------
/assets/alien/alien.atlas:
--------------------------------------------------------------------------------
1 | alien.png
2 | size:1361,1032
3 | filter:Linear,Linear
4 | pma:true
5 | back_foot
6 | bounds:326,5,16,11
7 | rotate:90
8 | back_shin
9 | bounds:974,294,42,48
10 | back_thigh
11 | bounds:1301,167,45,47
12 | offsets:2,0,47,47
13 | rotate:90
14 | backarmor
15 | bounds:1018,124,162,181
16 | offsets:0,1,162,182
17 | blown_up_nck
18 | bounds:974,19,153,103
19 | offsets:0,0,153,104
20 | body
21 | bounds:515,318,196,235
22 | rotate:90
23 | burst01
24 | bounds:2,9,285,308
25 | offsets:1,1,286,309
26 | rotate:90
27 | burst02
28 | bounds:611,9,307,361
29 | offsets:4,0,311,361
30 | rotate:90
31 | front_foot
32 | bounds:312,2,19,12
33 | rotate:90
34 | front_lower_arm
35 | bounds:1129,12,110,125
36 | rotate:90
37 | front_shin
38 | bounds:1256,75,49,56
39 | rotate:90
40 | front_thigh
41 | bounds:1182,138,52,54
42 | offsets:2,0,54,54
43 | rotate:90
44 | front_upper_arm
45 | bounds:1182,192,113,55
46 | rotate:90
47 | head
48 | bounds:312,23,297,271
49 | offsets:0,1,297,272
50 | lower_back_arm
51 | bounds:1256,214,101,91
52 | metaljaw
53 | bounds:752,344,242,170
54 | offsets:1,2,243,172
55 | splat01
56 | bounds:515,516,514,503
57 | rotate:90
58 | splat02
59 | bounds:2,296,734,511
60 | rotate:90
61 | splat03
62 | bounds:1020,307,723,339
63 | rotate:90
64 | upper_back_arm
65 | bounds:1239,126,60,86
66 |
--------------------------------------------------------------------------------
/assets/alien/alien.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets/alien/alien.png
--------------------------------------------------------------------------------
/assets/bullet-hit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets/bullet-hit.png
--------------------------------------------------------------------------------
/assets/bullet.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets/bullet.png
--------------------------------------------------------------------------------
/assets/crosshair.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets/crosshair.png
--------------------------------------------------------------------------------
/assets/gameOver.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets/gameOver.png
--------------------------------------------------------------------------------
/assets/map/map.atlas:
--------------------------------------------------------------------------------
1 |
2 | map.png
3 | format: RGBA8888
4 | filter: Linear,Linear
5 | repeat: none
6 | decals/ceiling-lamp-wire-01
7 | rotate: false
8 | xy: 0, 66
9 | size: 128, 128
10 | orig: 128, 128
11 | offset: 0, 0
12 | index: -1
13 | decals/ceiling_lamp-01
14 | rotate: false
15 | xy: 514, 584
16 | size: 128, 128
17 | orig: 128, 128
18 | offset: 0, 0
19 | index: -1
20 | decals/collision
21 | rotate: false
22 | xy: 0, 0
23 | size: 64, 64
24 | orig: 64, 64
25 | offset: 0, 0
26 | index: -1
27 | decals/column-01
28 | rotate: false
29 | xy: 0, 650
30 | size: 512, 320
31 | orig: 512, 320
32 | offset: 0, 0
33 | index: -1
34 | decals/column-02
35 | rotate: false
36 | xy: 0, 196
37 | size: 512, 64
38 | orig: 512, 64
39 | offset: 0, 0
40 | index: -1
41 | decals/column-03
42 | rotate: false
43 | xy: 0, 392
44 | size: 512, 256
45 | orig: 512, 256
46 | offset: 0, 0
47 | index: -1
48 | decals/crate-01
49 | rotate: false
50 | xy: 514, 714
51 | size: 256, 256
52 | orig: 256, 256
53 | offset: 0, 0
54 | index: -1
55 | decals/crate-02
56 | rotate: false
57 | xy: 772, 842
58 | size: 128, 128
59 | orig: 128, 128
60 | offset: 0, 0
61 | index: -1
62 | decals/crate-3
63 | rotate: false
64 | xy: 130, 66
65 | size: 128, 128
66 | orig: 128, 128
67 | offset: 0, 0
68 | index: -1
69 | decals/fill
70 | rotate: false
71 | xy: 644, 648
72 | size: 64, 64
73 | orig: 64, 64
74 | offset: 0, 0
75 | index: -1
76 | decals/fusebox-01
77 | rotate: false
78 | xy: 514, 454
79 | size: 128, 128
80 | orig: 128, 128
81 | offset: 0, 0
82 | index: -1
83 | decals/metal-01
84 | rotate: false
85 | xy: 0, 262
86 | size: 512, 128
87 | orig: 512, 128
88 | offset: 0, 0
89 | index: -1
90 |
91 | map2.png
92 | format: RGBA8888
93 | filter: Linear,Linear
94 | repeat: none
95 | decals02/ceiling-01
96 | rotate: false
97 | xy: 0, 840
98 | size: 512, 128
99 | orig: 512, 128
100 | offset: 0, 0
101 | index: -1
102 | decals02/concrete-01
103 | rotate: false
104 | xy: 0, 710
105 | size: 512, 128
106 | orig: 512, 128
107 | offset: 0, 0
108 | index: -1
109 | decals02/edge-left-01
110 | rotate: false
111 | xy: 0, 0
112 | size: 64, 64
113 | orig: 64, 64
114 | offset: 0, 0
115 | index: -1
116 | decals02/ground-01
117 | rotate: false
118 | xy: 0, 580
119 | size: 512, 128
120 | orig: 512, 128
121 | offset: 0, 0
122 | index: -1
123 | decals02/wall-left-01
124 | rotate: false
125 | xy: 0, 66
126 | size: 128, 512
127 | orig: 128, 512
128 | offset: 0, 0
129 | index: -1
130 | decals02/wall-left_bottom-01
131 | rotate: false
132 | xy: 514, 840
133 | size: 128, 128
134 | orig: 128, 128
135 | offset: 0, 0
136 | index: -1
137 | decals02/wall-right-01
138 | rotate: false
139 | xy: 130, 66
140 | size: 128, 512
141 | orig: 128, 512
142 | offset: 0, 0
143 | index: -1
144 | decals02/wall-right_top-01
145 | rotate: false
146 | xy: 260, 450
147 | size: 128, 128
148 | orig: 128, 128
149 | offset: 0, 0
150 | index: -1
151 |
152 | map3.png
153 | format: RGBA8888
154 | filter: Linear,Linear
155 | repeat: none
156 | decals03/concrete-02
157 | rotate: false
158 | xy: 0, 390
159 | size: 512, 128
160 | orig: 512, 128
161 | offset: 0, 0
162 | index: -1
163 | decals03/concrete-03
164 | rotate: false
165 | xy: 0, 260
166 | size: 512, 128
167 | orig: 512, 128
168 | offset: 0, 0
169 | index: -1
170 | decals03/metal-02
171 | rotate: false
172 | xy: 0, 130
173 | size: 512, 128
174 | orig: 512, 128
175 | offset: 0, 0
176 | index: -1
177 | decals03/metal-03
178 | rotate: false
179 | xy: 0, 0
180 | size: 512, 128
181 | orig: 512, 128
182 | offset: 0, 0
183 | index: -1
184 |
185 | map4.png
186 | format: RGBA8888
187 | filter: Linear,Linear
188 | repeat: none
189 | lights/light-01
190 | rotate: false
191 | xy: 0, 0
192 | size: 512, 512
193 | orig: 512, 512
194 | offset: 0, 0
195 | index: -1
196 | lights/light-02
197 | rotate: false
198 | xy: 512, 0
199 | size: 512, 512
200 | orig: 512, 512
201 | offset: 0, 0
202 | index: -1
203 |
204 | map5.png
205 | format: RGBA8888
206 | filter: Linear,Linear
207 | repeat: none
208 | rock/rock-01
209 | rotate: false
210 | xy: 0, 0
211 | size: 512, 512
212 | orig: 512, 512
213 | offset: 0, 0
214 | index: -1
215 | rock/rock-02
216 | rotate: false
217 | xy: 512, 0
218 | size: 512, 512
219 | orig: 512, 512
220 | offset: 0, 0
221 | index: -1
222 | rock/rock-03
223 | rotate: false
224 | xy: 0, 512
225 | size: 512, 512
226 | orig: 512, 512
227 | offset: 0, 0
228 | index: -1
229 | rock/rock-04
230 | rotate: false
231 | xy: 512, 512
232 | size: 512, 512
233 | orig: 512, 512
234 | offset: 0, 0
235 | index: -1
236 |
237 | map6.png
238 | format: RGBA8888
239 | filter: Linear,Linear
240 | repeat: none
241 | tint01/tint-01
242 | rotate: false
243 | xy: 0, 0
244 | size: 512, 512
245 | orig: 512, 512
246 | offset: 0, 0
247 | index: -1
248 | tint01/tint-02
249 | rotate: false
250 | xy: 512, 0
251 | size: 512, 512
252 | orig: 512, 512
253 | offset: 0, 0
254 | index: -1
255 | tint01/tint-03
256 | rotate: false
257 | xy: 0, 512
258 | size: 512, 512
259 | orig: 512, 512
260 | offset: 0, 0
261 | index: -1
262 | tint01/tint-04
263 | rotate: false
264 | xy: 512, 512
265 | size: 512, 512
266 | orig: 512, 512
267 | offset: 0, 0
268 | index: -1
269 |
270 | map7.png
271 | format: RGBA8888
272 | filter: Linear,Linear
273 | repeat: none
274 | tint02/tint-01
275 | rotate: false
276 | xy: 0, 0
277 | size: 512, 512
278 | orig: 512, 512
279 | offset: 0, 0
280 | index: -1
281 | tint02/tint-02
282 | rotate: false
283 | xy: 512, 0
284 | size: 512, 512
285 | orig: 512, 512
286 | offset: 0, 0
287 | index: -1
288 | tint02/tint-03
289 | rotate: false
290 | xy: 0, 512
291 | size: 512, 512
292 | orig: 512, 512
293 | offset: 0, 0
294 | index: -1
295 | tint02/tint-04
296 | rotate: false
297 | xy: 512, 512
298 | size: 512, 512
299 | orig: 512, 512
300 | offset: 0, 0
301 | index: -1
302 |
303 | map8.png
304 | format: RGBA8888
305 | filter: Linear,Linear
306 | repeat: none
307 | tint03/tint-01
308 | rotate: false
309 | xy: 260, 64
310 | size: 64, 64
311 | orig: 64, 64
312 | offset: 0, 0
313 | index: -1
314 | tint03/tint-02
315 | rotate: false
316 | xy: 390, 194
317 | size: 64, 64
318 | orig: 64, 64
319 | offset: 0, 0
320 | index: -1
321 | tint03/tint-03
322 | rotate: false
323 | xy: 904, 388
324 | size: 64, 64
325 | orig: 64, 64
326 | offset: 0, 0
327 | index: -1
328 | tint03/tint-04
329 | rotate: false
330 | xy: 0, 260
331 | size: 512, 192
332 | orig: 512, 192
333 | offset: 0, 0
334 | index: -1
335 | tint03/tint-05
336 | rotate: false
337 | xy: 0, 130
338 | size: 128, 128
339 | orig: 128, 128
340 | offset: 0, 0
341 | index: -1
342 | tint03/tint-06
343 | rotate: false
344 | xy: 514, 324
345 | size: 128, 128
346 | orig: 128, 128
347 | offset: 0, 0
348 | index: -1
349 | tint03/tint-07
350 | rotate: false
351 | xy: 0, 0
352 | size: 128, 128
353 | orig: 128, 128
354 | offset: 0, 0
355 | index: -1
356 | tint03/tint-08
357 | rotate: false
358 | xy: 130, 130
359 | size: 128, 128
360 | orig: 128, 128
361 | offset: 0, 0
362 | index: -1
363 | tint03/tint-09
364 | rotate: false
365 | xy: 644, 324
366 | size: 128, 128
367 | orig: 128, 128
368 | offset: 0, 0
369 | index: -1
370 | tint03/tint-10
371 | rotate: false
372 | xy: 130, 0
373 | size: 128, 128
374 | orig: 128, 128
375 | offset: 0, 0
376 | index: -1
377 | tint03/tint-11
378 | rotate: false
379 | xy: 260, 130
380 | size: 128, 128
381 | orig: 128, 128
382 | offset: 0, 0
383 | index: -1
384 | tint03/tint-12
385 | rotate: false
386 | xy: 774, 324
387 | size: 128, 128
388 | orig: 128, 128
389 | offset: 0, 0
390 | index: -1
391 |
392 | map9.png
393 | format: RGBA8888
394 | filter: Linear,Linear
395 | repeat: none
396 | walls/wall-01
397 | rotate: false
398 | xy: 0, 0
399 | size: 512, 512
400 | orig: 512, 512
401 | offset: 0, 0
402 | index: -1
403 | walls/wall-02
404 | rotate: false
405 | xy: 512, 0
406 | size: 512, 512
407 | orig: 512, 512
408 | offset: 0, 0
409 | index: -1
410 | walls/wall-03
411 | rotate: false
412 | xy: 0, 512
413 | size: 512, 512
414 | orig: 512, 512
415 | offset: 0, 0
416 | index: -1
417 | walls/wall-04
418 | rotate: false
419 | xy: 512, 512
420 | size: 512, 512
421 | orig: 512, 512
422 | offset: 0, 0
423 | index: -1
424 |
--------------------------------------------------------------------------------
/assets/map/map.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets/map/map.png
--------------------------------------------------------------------------------
/assets/map/map.tmx:
--------------------------------------------------------------------------------
1 |
2 |
237 |
--------------------------------------------------------------------------------
/assets/map/map2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets/map/map2.png
--------------------------------------------------------------------------------
/assets/map/map3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets/map/map3.png
--------------------------------------------------------------------------------
/assets/map/map4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets/map/map4.png
--------------------------------------------------------------------------------
/assets/map/map5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets/map/map5.png
--------------------------------------------------------------------------------
/assets/map/map6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets/map/map6.png
--------------------------------------------------------------------------------
/assets/map/map7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets/map/map7.png
--------------------------------------------------------------------------------
/assets/map/map8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets/map/map8.png
--------------------------------------------------------------------------------
/assets/map/map9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets/map/map9.png
--------------------------------------------------------------------------------
/assets/sounds/footstep1.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets/sounds/footstep1.ogg
--------------------------------------------------------------------------------
/assets/sounds/footstep2.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets/sounds/footstep2.ogg
--------------------------------------------------------------------------------
/assets/sounds/hit.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets/sounds/hit.ogg
--------------------------------------------------------------------------------
/assets/sounds/hurt-alien.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets/sounds/hurt-alien.ogg
--------------------------------------------------------------------------------
/assets/sounds/hurt-player.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets/sounds/hurt-player.ogg
--------------------------------------------------------------------------------
/assets/sounds/shoot.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets/sounds/shoot.ogg
--------------------------------------------------------------------------------
/assets/sounds/squish.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets/sounds/squish.ogg
--------------------------------------------------------------------------------
/assets/spineboy/spineboy.atlas:
--------------------------------------------------------------------------------
1 | spineboy.png
2 | size:1056,542
3 | filter:Linear,Linear
4 | pma:true
5 | eye_indifferent
6 | bounds:961,274,93,89
7 | eye_surprised
8 | bounds:961,183,93,89
9 | front_bracer
10 | bounds:369,59,58,80
11 | front_fist_closed
12 | bounds:828,94,75,82
13 | rotate:90
14 | front_fist_open
15 | bounds:777,6,86,87
16 | rotate:90
17 | front_foot
18 | bounds:429,77,126,68
19 | offsets:0,1,126,69
20 | front_foot_bend1
21 | bounds:698,99,128,70
22 | front_foot_bend2
23 | bounds:604,132,108,92
24 | offsets:0,0,108,93
25 | rotate:90
26 | front_shin
27 | bounds:184,59,80,183
28 | offsets:1,1,82,184
29 | rotate:90
30 | front_thigh
31 | bounds:912,262,47,112
32 | offsets:0,0,48,112
33 | front_upper_arm
34 | bounds:257,3,54,97
35 | rotate:90
36 | goggles
37 | bounds:701,376,261,164
38 | offsets:0,2,261,166
39 | gun
40 | bounds:701,171,209,203
41 | offsets:0,0,210,203
42 | head
43 | bounds:428,242,271,298
44 | mouth_grind
45 | bounds:961,122,93,59
46 | mouth_oooo
47 | bounds:866,33,93,59
48 | mouth_smile
49 | bounds:961,61,93,59
50 | muzzle
51 | bounds:2,141,424,399
52 | offsets:20,1,462,400
53 | neck
54 | bounds:2,5,35,41
55 | offsets:0,0,36,41
56 | rotate:90
57 | rear_bracer
58 | bounds:184,2,55,71
59 | offsets:0,1,56,72
60 | rotate:90
61 | rear_foot
62 | bounds:557,70,113,60
63 | rear_foot_bend1
64 | bounds:429,9,117,66
65 | rear_foot_bend2
66 | bounds:672,14,103,83
67 | rear_shin
68 | bounds:964,365,74,175
69 | offsets:1,1,75,178
70 | rear_thigh
71 | bounds:548,11,57,103
72 | offsets:8,1,65,104
73 | rotate:90
74 | rear_upper_arm
75 | bounds:912,173,47,87
76 | torso
77 | bounds:2,42,97,180
78 | offsets:0,0,98,180
79 | rotate:90
80 | torso_twisted
81 | bounds:428,147,93,174
82 | offsets:1,0,94,174
83 | rotate:90
84 |
--------------------------------------------------------------------------------
/assets/spineboy/spineboy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets/spineboy/spineboy.png
--------------------------------------------------------------------------------
/assets/start.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets/start.png
--------------------------------------------------------------------------------
/assets/title.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets/title.png
--------------------------------------------------------------------------------
/assets/youLose.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets/youLose.png
--------------------------------------------------------------------------------
/assets/youWin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EsotericSoftware/spine-superspineboy/c3d1901e2fc8f01812878fd1837aca24fe485ae3/assets/youWin.png
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 | 4.0.0
7 |
8 | com.esotericsoftware
9 | super-spineboy
10 | 1.0-SNAPSHOT
11 |
12 | super-spineboy
13 |
14 |
15 | UTF-8
16 | 16
17 | 16
18 |
19 |
20 |
21 |
22 | com.esotericsoftware.spine
23 | spine-libgdx
24 | 4.2.7
25 |
26 |
27 | com.badlogicgames.gdx
28 | gdx
29 | 1.13.0
30 |
31 |
32 | com.badlogicgames.gdx
33 | gdx-backend-lwjgl
34 | 1.13.0
35 |
36 |
37 | com.badlogicgames.gdx
38 | gdx-platform
39 | 1.13.0
40 | natives-desktop
41 |
42 |
43 |
44 |
45 | src
46 | bin
47 |
48 |
49 | assets
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 | maven-clean-plugin
58 | 3.1.0
59 |
60 |
61 |
62 |
63 | maven-resources-plugin
64 | 3.0.2
65 |
66 |
67 | maven-compiler-plugin
68 | 3.8.0
69 |
70 |
71 | maven-surefire-plugin
72 | 2.22.1
73 |
74 |
75 | maven-jar-plugin
76 | 3.0.2
77 |
78 |
79 | maven-install-plugin
80 | 2.5.2
81 |
82 |
83 | maven-deploy-plugin
84 | 2.8.2
85 |
86 |
87 |
88 |
89 | maven-site-plugin
90 | 3.7.1
91 |
92 |
93 | maven-project-info-reports-plugin
94 | 3.0.0
95 |
96 |
97 |
98 |
99 | org.apache.maven.plugins
100 | maven-eclipse-plugin
101 | 2.10
102 |
103 | true
104 |
105 |
106 |
107 |
108 |
109 |
110 |
--------------------------------------------------------------------------------
/src/com/esotericsoftware/spine/superspineboy/Assets.java:
--------------------------------------------------------------------------------
1 | /******************************************************************************
2 | * Spine Runtimes License Agreement
3 | * Last updated February 20, 2024. Replaces all prior versions.
4 | *
5 | * Copyright (c) 2013-2024, Esoteric Software LLC
6 | *
7 | * Integration of the Spine Runtimes into software or otherwise creating derivative works
8 | * of the Spine Runtimes is permitted under the terms and conditions of Section 2 of the
9 | * Spine Editor License Agreement:
10 | * https://esotericsoftware.com/spine-editor-license
11 | *
12 | * Otherwise, it is permitted to integrate the Spine Runtimes into software or otherwise
13 | * create derivative works of the Spine Runtimes (collectively, "Products"), provided that
14 | * each user of the Products must obtain their own Spine Editor license and redistribution
15 | * of the Products in any form must include this license and copyright notice.
16 | *
17 | * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY EXPRESS OR IMPLIED
18 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
19 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR
20 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
22 | * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY
23 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE SPINE RUNTIMES,
25 | * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 | *****************************************************************************/
27 |
28 | package com.esotericsoftware.spine.superspineboy;
29 |
30 | import static com.esotericsoftware.spine.superspineboy.Model.*;
31 |
32 | import com.esotericsoftware.spine.Animation;
33 | import com.esotericsoftware.spine.AnimationStateData;
34 | import com.esotericsoftware.spine.SkeletonData;
35 | import com.esotericsoftware.spine.SkeletonJson;
36 | import com.esotericsoftware.spine.superspineboy.Model.State;
37 | import com.esotericsoftware.spine.superspineboy.View.StateView;
38 |
39 | import com.badlogic.gdx.Gdx;
40 | import com.badlogic.gdx.audio.Sound;
41 | import com.badlogic.gdx.graphics.Texture;
42 | import com.badlogic.gdx.graphics.Texture.TextureFilter;
43 | import com.badlogic.gdx.graphics.g2d.TextureAtlas;
44 | import com.badlogic.gdx.graphics.g2d.TextureRegion;
45 | import com.badlogic.gdx.utils.ObjectMap;
46 |
47 | /** Centralized place to load and store assets. */
48 | class Assets {
49 | TextureAtlas playerAtlas, enemyAtlas;
50 | TextureRegion bulletRegion, hitRegion, crosshair;
51 | TextureRegion titleRegion, gameOverRegion, youLoseRegion, youWinRegion, startRegion;
52 |
53 | SkeletonData playerSkeletonData, enemySkeletonData;
54 | AnimationStateData playerAnimationData, enemyAnimationData;
55 | ObjectMap playerStates = new ObjectMap(), enemyStates = new ObjectMap();
56 |
57 | Assets () {
58 | bulletRegion = loadRegion("bullet.png");
59 | hitRegion = loadRegion("bullet-hit.png");
60 | titleRegion = loadRegion("title.png");
61 | gameOverRegion = loadRegion("gameOver.png");
62 | youLoseRegion = loadRegion("youLose.png");
63 | youWinRegion = loadRegion("youWin.png");
64 | startRegion = loadRegion("start.png");
65 | crosshair = loadRegion("crosshair.png");
66 |
67 | SoundEffect.shoot.sound = Gdx.audio.newSound(Gdx.files.internal("sounds/shoot.ogg"));
68 | SoundEffect.hit.sound = Gdx.audio.newSound(Gdx.files.internal("sounds/hit.ogg"));
69 | SoundEffect.footstep1.sound = Gdx.audio.newSound(Gdx.files.internal("sounds/footstep1.ogg"));
70 | SoundEffect.footstep2.sound = Gdx.audio.newSound(Gdx.files.internal("sounds/footstep2.ogg"));
71 | SoundEffect.squish.sound = Gdx.audio.newSound(Gdx.files.internal("sounds/squish.ogg"));
72 | SoundEffect.squish.volume = 0.6f;
73 | SoundEffect.hurtPlayer.sound = Gdx.audio.newSound(Gdx.files.internal("sounds/hurt-player.ogg"));
74 | SoundEffect.hurtAlien.sound = Gdx.audio.newSound(Gdx.files.internal("sounds/hurt-alien.ogg"));
75 | SoundEffect.hurtAlien.volume = 0.5f;
76 |
77 | loadPlayerAssets();
78 | loadEnemyAssets();
79 | }
80 |
81 | TextureRegion loadRegion (String name) {
82 | Texture texture = new Texture(name);
83 | texture.setFilter(TextureFilter.Nearest, TextureFilter.Linear);
84 | return new TextureRegion(texture);
85 | }
86 |
87 | void loadPlayerAssets () {
88 | playerAtlas = new TextureAtlas(Gdx.files.internal("spineboy/spineboy.atlas"));
89 |
90 | SkeletonJson json = new SkeletonJson(playerAtlas);
91 | json.setScale(Player.height / Player.heightSource);
92 | playerSkeletonData = json.readSkeletonData(Gdx.files.internal("spineboy/spineboy.json"));
93 |
94 | playerAnimationData = new AnimationStateData(playerSkeletonData);
95 | playerAnimationData.setDefaultMix(0.2f);
96 | setMix(playerAnimationData, "idle", "run", 0.3f);
97 | setMix(playerAnimationData, "run", "idle", 0.1f);
98 | setMix(playerAnimationData, "shoot", "shoot", 0);
99 |
100 | setupState(playerStates, State.death, playerSkeletonData, "death", false);
101 | StateView idle = setupState(playerStates, State.idle, playerSkeletonData, "idle", true);
102 | StateView jump = setupState(playerStates, State.jump, playerSkeletonData, "jump", false);
103 | StateView run = setupState(playerStates, State.run, playerSkeletonData, "run", true);
104 | if (idle.animation != null) run.startTimes.put(idle.animation, 8 * fps);
105 | if (jump.animation != null) run.startTimes.put(jump.animation, 22 * fps);
106 | StateView fall = setupState(playerStates, State.fall, playerSkeletonData, "jump", false);
107 | fall.defaultStartTime = 22 * fps;
108 | }
109 |
110 | void loadEnemyAssets () {
111 | enemyAtlas = new TextureAtlas(Gdx.files.internal("alien/alien.atlas"));
112 |
113 | SkeletonJson json = new SkeletonJson(enemyAtlas);
114 | json.setScale(Enemy.height / Enemy.heightSource);
115 | enemySkeletonData = json.readSkeletonData(Gdx.files.internal("alien/alien.json"));
116 |
117 | enemyAnimationData = new AnimationStateData(enemySkeletonData);
118 | enemyAnimationData.setDefaultMix(0.1f);
119 |
120 | setupState(enemyStates, State.idle, enemySkeletonData, "run", true);
121 | setupState(enemyStates, State.jump, enemySkeletonData, "jump", true);
122 | setupState(enemyStates, State.run, enemySkeletonData, "run", true);
123 | setupState(enemyStates, State.death, enemySkeletonData, "death", false);
124 | setupState(enemyStates, State.fall, enemySkeletonData, "run", false);
125 | }
126 |
127 | void setMix (AnimationStateData data, String from, String to, float mix) {
128 | Animation fromAnimation = data.getSkeletonData().findAnimation(from);
129 | Animation toAnimation = data.getSkeletonData().findAnimation(to);
130 | if (fromAnimation == null || toAnimation == null) return;
131 | data.setMix(fromAnimation, toAnimation, mix);
132 | }
133 |
134 | StateView setupState (ObjectMap map, State state, SkeletonData skeletonData, String name, boolean loop) {
135 | StateView stateView = new StateView();
136 | stateView.animation = skeletonData.findAnimation(name);
137 | stateView.loop = loop;
138 | map.put(state, stateView);
139 | return stateView;
140 | }
141 |
142 | void dispose () {
143 | playerAtlas.dispose();
144 | enemyAtlas.dispose();
145 | }
146 |
147 | enum SoundEffect {
148 | shoot, hit, footstep1, footstep2, squish, hurtPlayer, hurtAlien;
149 |
150 | Sound sound;
151 | float volume = 1;
152 |
153 | void play () {
154 | sound.play(volume);
155 | }
156 | }
157 | }
158 |
--------------------------------------------------------------------------------
/src/com/esotericsoftware/spine/superspineboy/Character.java:
--------------------------------------------------------------------------------
1 | /******************************************************************************
2 | * Spine Runtimes License Agreement
3 | * Last updated February 20, 2024. Replaces all prior versions.
4 | *
5 | * Copyright (c) 2013-2024, Esoteric Software LLC
6 | *
7 | * Integration of the Spine Runtimes into software or otherwise creating derivative works
8 | * of the Spine Runtimes is permitted under the terms and conditions of Section 2 of the
9 | * Spine Editor License Agreement:
10 | * https://esotericsoftware.com/spine-editor-license
11 | *
12 | * Otherwise, it is permitted to integrate the Spine Runtimes into software or otherwise
13 | * create derivative works of the Spine Runtimes (collectively, "Products"), provided that
14 | * each user of the Products must obtain their own Spine Editor license and redistribution
15 | * of the Products in any form must include this license and copyright notice.
16 | *
17 | * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY EXPRESS OR IMPLIED
18 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
19 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR
20 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
22 | * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY
23 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE SPINE RUNTIMES,
25 | * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 | *****************************************************************************/
27 |
28 | package com.esotericsoftware.spine.superspineboy;
29 |
30 | import static com.esotericsoftware.spine.superspineboy.Model.*;
31 |
32 | import com.esotericsoftware.spine.superspineboy.Model.State;
33 |
34 | import com.badlogic.gdx.math.Rectangle;
35 | import com.badlogic.gdx.math.Vector2;
36 |
37 | /** The model class for an enemy or player that moves around the map. */
38 | class Character {
39 | static float minVelocityX = 0.001f, maxVelocityY = 20f;
40 | static float groundedTime = 0.15f;
41 | static float dampingGroundX = 36, dampingAirX = 15, collideDampingX = 0.7f;
42 | static float runGroundX = 80, runAirSame = 45, runAirOpposite = 45;
43 |
44 | Model model;
45 | Vector2 position = new Vector2();
46 | Vector2 velocity = new Vector2();
47 | State state = State.idle;
48 | float stateTime;
49 | float dir;
50 | float airTime;
51 | Rectangle rect = new Rectangle();
52 | boolean stateChanged;
53 | float hp;
54 |
55 | float maxVelocityX;
56 | float collisionOffsetY;
57 | float jumpVelocity;
58 |
59 | Character (Model model) {
60 | this.model = model;
61 | }
62 |
63 | void setState (State newState) {
64 | if ((state == newState && state != State.fall) || state == State.death) return;
65 | state = newState;
66 | stateTime = 0;
67 | stateChanged = true;
68 | }
69 |
70 | void update (float delta) {
71 | stateTime += delta;
72 |
73 | // If moving downward, change state to fall.
74 | if (velocity.y < 0 && state != State.jump && state != State.fall) {
75 | setState(State.fall);
76 | setGrounded(false);
77 | }
78 |
79 | // Apply gravity.
80 | velocity.y -= gravity * delta;
81 | if (velocity.y < 0 && -velocity.y > maxVelocityY) velocity.y = Math.signum(velocity.y) * maxVelocityY;
82 |
83 | boolean grounded = isGrounded();
84 |
85 | // Damping reduces velocity so the character eventually comes to a complete stop.
86 | float damping = (grounded ? dampingGroundX : dampingAirX) * delta;
87 | if (velocity.x > 0)
88 | velocity.x = Math.max(0, velocity.x - damping);
89 | else
90 | velocity.x = Math.min(0, velocity.x + damping);
91 | if (Math.abs(velocity.x) < minVelocityX && grounded) {
92 | velocity.x = 0;
93 | setState(State.idle);
94 | }
95 |
96 | velocity.scl(delta); // Change velocity from units/sec to units since last frame.
97 | collideX();
98 | collideY();
99 | position.add(velocity);
100 | velocity.scl(1 / delta); // Change velocity back.
101 | }
102 |
103 | boolean isGrounded () {
104 | // The character is considered grounded for a short time after leaving the ground, making jumping over gaps easier.
105 | return airTime < groundedTime;
106 | }
107 |
108 | void setGrounded (boolean grounded) {
109 | airTime = grounded ? 0 : groundedTime;
110 | }
111 |
112 | boolean collideX () {
113 | rect.x = position.x + velocity.x;
114 | rect.y = position.y + collisionOffsetY;
115 |
116 | int x;
117 | if (velocity.x >= 0)
118 | x = (int)(rect.x + rect.width);
119 | else
120 | x = (int)rect.x;
121 | int startY = (int)rect.y;
122 | int endY = (int)(rect.y + rect.height);
123 | for (Rectangle tile : model.getCollisionTiles(x, startY, x, endY)) {
124 | if (!rect.overlaps(tile)) continue;
125 | if (velocity.x >= 0)
126 | position.x = tile.x - rect.width;
127 | else
128 | position.x = tile.x + tile.width;
129 | velocity.x *= collideDampingX;
130 | return true;
131 | }
132 | return false;
133 | }
134 |
135 | boolean collideY () {
136 | rect.x = position.x;
137 | rect.y = position.y + velocity.y + collisionOffsetY;
138 |
139 | int y;
140 | if (velocity.y > 0)
141 | y = (int)(rect.y + rect.height);
142 | else
143 | y = (int)rect.y;
144 | int startX = (int)rect.x;
145 | int endX = (int)(rect.x + rect.width);
146 | for (Rectangle tile : model.getCollisionTiles(startX, y, endX, y)) {
147 | if (!rect.overlaps(tile)) continue;
148 | if (velocity.y > 0)
149 | position.y = tile.y - rect.height;
150 | else {
151 | position.y = tile.y + tile.height;
152 | if (state == State.jump) setState(State.idle);
153 | setGrounded(true);
154 | }
155 | velocity.y = 0;
156 | return true;
157 | }
158 | return false;
159 | }
160 |
161 | void moveLeft (float delta) {
162 | float adjust;
163 | if (isGrounded()) {
164 | adjust = runGroundX;
165 | setState(State.run);
166 | } else
167 | adjust = velocity.x <= 0 ? runAirSame : runAirOpposite;
168 | if (velocity.x > -maxVelocityX) velocity.x = Math.max(velocity.x - adjust * delta, -maxVelocityX);
169 | dir = -1;
170 | }
171 |
172 | void moveRight (float delta) {
173 | float adjust;
174 | if (isGrounded()) {
175 | adjust = runGroundX;
176 | setState(State.run);
177 | } else
178 | adjust = velocity.x >= 0 ? runAirSame : runAirOpposite;
179 | if (velocity.x < maxVelocityX) velocity.x = Math.min(velocity.x + adjust * delta, maxVelocityX);
180 | dir = 1;
181 | }
182 |
183 | void jump () {
184 | velocity.y += jumpVelocity;
185 | setState(State.jump);
186 | setGrounded(false);
187 | }
188 | }
189 |
--------------------------------------------------------------------------------
/src/com/esotericsoftware/spine/superspineboy/CharacterView.java:
--------------------------------------------------------------------------------
1 | /******************************************************************************
2 | * Spine Runtimes License Agreement
3 | * Last updated February 20, 2024. Replaces all prior versions.
4 | *
5 | * Copyright (c) 2013-2024, Esoteric Software LLC
6 | *
7 | * Integration of the Spine Runtimes into software or otherwise creating derivative works
8 | * of the Spine Runtimes is permitted under the terms and conditions of Section 2 of the
9 | * Spine Editor License Agreement:
10 | * https://esotericsoftware.com/spine-editor-license
11 | *
12 | * Otherwise, it is permitted to integrate the Spine Runtimes into software or otherwise
13 | * create derivative works of the Spine Runtimes (collectively, "Products"), provided that
14 | * each user of the Products must obtain their own Spine Editor license and redistribution
15 | * of the Products in any form must include this license and copyright notice.
16 | *
17 | * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY EXPRESS OR IMPLIED
18 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
19 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR
20 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
22 | * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY
23 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE SPINE RUNTIMES,
25 | * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 | *****************************************************************************/
27 |
28 | package com.esotericsoftware.spine.superspineboy;
29 |
30 | import com.esotericsoftware.spine.Animation;
31 | import com.esotericsoftware.spine.AnimationState;
32 | import com.esotericsoftware.spine.AnimationState.TrackEntry;
33 | import com.esotericsoftware.spine.Skeleton;
34 | import com.esotericsoftware.spine.superspineboy.View.StateView;
35 |
36 | /** The view class for an enemy or player that moves around the map. */
37 | class CharacterView {
38 | View view;
39 | Model model;
40 | Skeleton skeleton;
41 | AnimationState animationState;
42 |
43 | CharacterView (View view) {
44 | this.view = view;
45 | model = view.model;
46 | }
47 |
48 | boolean setAnimation (StateView state, boolean force) {
49 | // Changes the current animation on track 0 of the AnimationState, if needed.
50 | Animation animation = state.animation;
51 | TrackEntry current = animationState.getCurrent(0);
52 | Animation oldAnimation = current == null ? null : current.getAnimation();
53 | if (force || oldAnimation != animation) {
54 | if (state.animation == null) return true;
55 | TrackEntry entry = animationState.setAnimation(0, state.animation, state.loop);
56 | if (oldAnimation != null) entry.setTrackTime(state.startTimes.get(oldAnimation, state.defaultStartTime));
57 | if (!state.loop) entry.setTrackEnd(Float.MAX_VALUE);
58 | return true;
59 | }
60 | return false;
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/src/com/esotericsoftware/spine/superspineboy/Enemy.java:
--------------------------------------------------------------------------------
1 | /******************************************************************************
2 | * Spine Runtimes License Agreement
3 | * Last updated February 20, 2024. Replaces all prior versions.
4 | *
5 | * Copyright (c) 2013-2024, Esoteric Software LLC
6 | *
7 | * Integration of the Spine Runtimes into software or otherwise creating derivative works
8 | * of the Spine Runtimes is permitted under the terms and conditions of Section 2 of the
9 | * Spine Editor License Agreement:
10 | * https://esotericsoftware.com/spine-editor-license
11 | *
12 | * Otherwise, it is permitted to integrate the Spine Runtimes into software or otherwise
13 | * create derivative works of the Spine Runtimes (collectively, "Products"), provided that
14 | * each user of the Products must obtain their own Spine Editor license and redistribution
15 | * of the Products in any form must include this license and copyright notice.
16 | *
17 | * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY EXPRESS OR IMPLIED
18 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
19 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR
20 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
22 | * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY
23 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE SPINE RUNTIMES,
25 | * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 | *****************************************************************************/
27 |
28 | package com.esotericsoftware.spine.superspineboy;
29 |
30 | import static com.esotericsoftware.spine.superspineboy.Model.*;
31 |
32 | import com.esotericsoftware.spine.superspineboy.Model.State;
33 |
34 | import com.badlogic.gdx.math.MathUtils;
35 |
36 | /** The model class for an enemy. */
37 | class Enemy extends Character {
38 | static float heightSource = 398, width = 105 * scale, height = 200 * scale;
39 |
40 | static float maxVelocityMinX = 4f, maxVelocityMaxX = 8.5f, maxVelocityAirX = 19f;
41 | static float hpWeak = 1, hpSmall = 2, hpNormal = 3, hpStrong = 5, hpBecomesBig = 8, hpBig = 20;
42 | static float corpseTime = 5 * 60, fadeTime = 3;
43 | static float jumpDistanceNormal = 20, jumpDelayNormal = 1.6f, jumpVelocityNormal = 12, jumpVelocityBig = 18;
44 | static float sizeSmall = 0.5f, sizeBig = 2.5f, sizeStrong = 1.3f, bigDuration = 2, smallCount = 14;
45 |
46 | static float normalKnockbackX = 19, normalKnockbackY = 9, bigKnockbackX = 12, bigKnockbackY = 6;
47 | static float collisionDelay = 0.3f;
48 |
49 | float deathTimer = corpseTime;
50 | float maxVelocityGroundX;
51 | float collisionTimer;
52 | float jumpDelayTimer, jumpDistance, jumpDelay;
53 | Type type;
54 | float size = 1;
55 | float bigTimer;
56 | float spawnSmallsTimer;
57 | boolean move;
58 | boolean forceJump;
59 | int collisions;
60 | float knockbackX = normalKnockbackX, knockbackY = normalKnockbackY;
61 |
62 | // This is here for convenience, the model should never touch the view.
63 | EnemyView view;
64 |
65 | Enemy (Model model, Type type) {
66 | super(model);
67 | this.type = type;
68 |
69 | rect.width = width;
70 | rect.height = height;
71 |
72 | maxVelocityGroundX = MathUtils.random(maxVelocityMinX, maxVelocityMaxX);
73 | maxVelocityX = maxVelocityGroundX;
74 | jumpVelocity = jumpVelocityNormal;
75 | jumpDelay = jumpDelayNormal;
76 | jumpDistance = jumpDistanceNormal;
77 |
78 | if (type == Type.big) {
79 | size = sizeBig;
80 | rect.width = width * size * 0.7f;
81 | rect.height = height * size * 0.7f;
82 | hp = hpBig;
83 | knockbackX = normalKnockbackX;
84 | knockbackY = normalKnockbackY;
85 | } else if (type == Type.small) {
86 | size = sizeSmall;
87 | rect.width = width * size;
88 | rect.height = height * size;
89 | hp = hpSmall;
90 | } else if (type == Type.weak)
91 | hp = hpWeak;
92 | else if (type == Type.becomesBig)
93 | hp = hpBecomesBig;
94 | else if (type == Type.strong) {
95 | hp = hpStrong;
96 | size = sizeStrong;
97 | jumpVelocity *= 1.5f;
98 | jumpDistance *= 1.4f;
99 | } else
100 | hp = hpNormal;
101 |
102 | jumpDelayTimer = MathUtils.random(0, jumpDelay);
103 | }
104 |
105 | void update (float delta) {
106 | stateChanged = false;
107 |
108 | if (state == State.death) {
109 | if (type == Type.becomesBig && size == 1) {
110 | bigTimer = bigDuration;
111 | collisionTimer = bigDuration;
112 | state = State.run;
113 | hp = hpBig;
114 | knockbackX = bigKnockbackX;
115 | knockbackY = bigKnockbackY;
116 | type = Type.big;
117 | jumpVelocity = jumpVelocityBig;
118 | } else if (type == Type.big) {
119 | spawnSmallsTimer = 0.8333f;
120 | type = Type.normal;
121 | }
122 | }
123 |
124 | // Enemy grows to a big enemy.
125 | if (bigTimer > 0) {
126 | bigTimer -= delta;
127 | size = 1 + (sizeBig - 1) * (1 - Math.max(0, bigTimer / bigDuration));
128 | rect.width = width * size * 0.7f;
129 | rect.height = height * size * 0.7f;
130 | }
131 |
132 | // Big enemy explodes into small ones.
133 | if (spawnSmallsTimer > 0) {
134 | spawnSmallsTimer -= delta;
135 | if (spawnSmallsTimer < 0) {
136 | for (int i = 0; i < smallCount; i++) {
137 | Enemy small = new Enemy(model, Type.small);
138 | small.position.set(position.x, position.y + 2);
139 | small.velocity.x = MathUtils.random(5, 15) * (MathUtils.randomBoolean() ? 1 : -1);
140 | small.velocity.y = MathUtils.random(10, 25);
141 | small.setGrounded(false);
142 | model.enemies.add(small);
143 | }
144 | }
145 | }
146 |
147 | // Nearly dead enemies jump at the player right away.
148 | if (hp == 1 && type != Type.weak && type != Type.small) jumpDelayTimer = 0;
149 |
150 | // Kill enemies stuck in the map or those that have somehow fallen out of the map.
151 | if (state != State.death && (hp <= 0 || position.y < -100 || collisions > 100)) {
152 | state = State.death;
153 | hp = 0;
154 | }
155 |
156 | // Simple enemy AI.
157 | boolean grounded = isGrounded();
158 | if (grounded) move = true;
159 | collisionTimer -= delta;
160 | maxVelocityX = grounded ? maxVelocityGroundX : maxVelocityAirX;
161 | if (state == State.death)
162 | deathTimer -= delta;
163 | else if (collisionTimer < 0) {
164 | if (model.player.hp == 0) {
165 | // Enemies win, jump for joy!
166 | if (grounded && velocity.x == 0) {
167 | jumpVelocity = jumpVelocityNormal / 2;
168 | dir = -dir;
169 | jump();
170 | }
171 | } else {
172 | // Jump if within range of the player.
173 | if (grounded && (forceJump || Math.abs(model.player.position.x - position.x) < jumpDistance)) {
174 | jumpDelayTimer -= delta;
175 | if (state != State.jump && jumpDelayTimer < 0 && position.y <= model.player.position.y) {
176 | jump();
177 | jumpDelayTimer = MathUtils.random(0, jumpDelay);
178 | forceJump = false;
179 | }
180 | }
181 | // Move toward the player.
182 | if (move) {
183 | if (model.player.position.x > position.x) {
184 | if (velocity.x >= 0) moveRight(delta);
185 | } else if (velocity.x <= 0) //
186 | moveLeft(delta);
187 | }
188 | }
189 | }
190 |
191 | int previousCollision = collisions;
192 | super.update(delta);
193 | if (!grounded || collisions == previousCollision) collisions = 0;
194 | }
195 |
196 | boolean collideX () {
197 | boolean result = super.collideX();
198 | if (result) {
199 | // If grounded and collided with the map, jump to avoid the obstacle.
200 | if (isGrounded()) forceJump = true;
201 | collisions++;
202 | }
203 | return result;
204 | }
205 |
206 | enum Type {
207 | weak, normal, strong, becomesBig, big, small
208 | }
209 | }
210 |
--------------------------------------------------------------------------------
/src/com/esotericsoftware/spine/superspineboy/EnemyView.java:
--------------------------------------------------------------------------------
1 | /******************************************************************************
2 | * Spine Runtimes License Agreement
3 | * Last updated February 20, 2024. Replaces all prior versions.
4 | *
5 | * Copyright (c) 2013-2024, Esoteric Software LLC
6 | *
7 | * Integration of the Spine Runtimes into software or otherwise creating derivative works
8 | * of the Spine Runtimes is permitted under the terms and conditions of Section 2 of the
9 | * Spine Editor License Agreement:
10 | * https://esotericsoftware.com/spine-editor-license
11 | *
12 | * Otherwise, it is permitted to integrate the Spine Runtimes into software or otherwise
13 | * create derivative works of the Spine Runtimes (collectively, "Products"), provided that
14 | * each user of the Products must obtain their own Spine Editor license and redistribution
15 | * of the Products in any form must include this license and copyright notice.
16 | *
17 | * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY EXPRESS OR IMPLIED
18 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
19 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR
20 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
22 | * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY
23 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE SPINE RUNTIMES,
25 | * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 | *****************************************************************************/
27 |
28 | package com.esotericsoftware.spine.superspineboy;
29 |
30 | import com.esotericsoftware.spine.Animation;
31 | import com.esotericsoftware.spine.AnimationState;
32 | import com.esotericsoftware.spine.AnimationState.AnimationStateAdapter;
33 | import com.esotericsoftware.spine.Bone;
34 | import com.esotericsoftware.spine.Event;
35 | import com.esotericsoftware.spine.EventData;
36 | import com.esotericsoftware.spine.Skeleton;
37 | import com.esotericsoftware.spine.Skeleton.Physics;
38 | import com.esotericsoftware.spine.Slot;
39 | import com.esotericsoftware.spine.attachments.Attachment;
40 | import com.esotericsoftware.spine.superspineboy.Assets.SoundEffect;
41 | import com.esotericsoftware.spine.superspineboy.Enemy.Type;
42 |
43 | import com.badlogic.gdx.graphics.Color;
44 | import com.badlogic.gdx.math.MathUtils;
45 |
46 | /** The view class for an enemy. */
47 | class EnemyView extends CharacterView {
48 | Enemy enemy;
49 | Animation hitAnimation;
50 | Slot headSlot;
51 | Attachment burstHeadAttachment;
52 | Color headColor;
53 |
54 | EnemyView (final View view, Enemy enemy) {
55 | super(view);
56 | this.enemy = enemy;
57 |
58 | skeleton = new Skeleton(view.assets.enemySkeletonData);
59 | burstHeadAttachment = skeleton.getAttachment("head", "burst01");
60 | headSlot = skeleton.findSlot("head");
61 | hitAnimation = skeleton.getData().findAnimation("hit");
62 |
63 | animationState = new AnimationState(view.assets.enemyAnimationData);
64 |
65 | // Play squish sound when enemies die.
66 | final EventData squishEvent = view.assets.enemySkeletonData.findEvent("squish");
67 | animationState.addListener(new AnimationStateAdapter() {
68 | public void event (int trackIndex, Event event) {
69 | if (event.getData() == squishEvent) SoundEffect.squish.play();
70 | }
71 | });
72 |
73 | // Enemies have slight color variations.
74 | if (enemy.type == Type.strong)
75 | headColor = new Color(1, 0.6f, 1, 1);
76 | else
77 | headColor = new Color(MathUtils.random(0.8f, 1), MathUtils.random(0.8f, 1), MathUtils.random(0.8f, 1), 1);
78 | headSlot.getColor().set(headColor);
79 | }
80 |
81 | void update (float delta) {
82 | // Change head attachment for enemies that are about to die.
83 | if (enemy.hp == 1 && enemy.type != Type.weak) headSlot.setAttachment(burstHeadAttachment);
84 |
85 | // Change color for big enemies.
86 | if (enemy.type == Type.big) headSlot.getColor().set(headColor).lerp(0, 1, 1, 1, 1 - enemy.bigTimer / Enemy.bigDuration);
87 |
88 | skeleton.setX(enemy.position.x + Enemy.width / 2);
89 | skeleton.setY(enemy.position.y);
90 |
91 | if (!setAnimation(view.assets.enemyStates.get(enemy.state), enemy.stateChanged)) animationState.update(delta);
92 | animationState.apply(skeleton);
93 |
94 | Bone root = skeleton.getRootBone();
95 | root.setScaleX(root.getScaleX() * enemy.size);
96 | root.setScaleY(root.getScaleY() * enemy.size);
97 |
98 | skeleton.setScaleX(enemy.dir);
99 | skeleton.updateWorldTransform(Physics.none);
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/src/com/esotericsoftware/spine/superspineboy/Model.java:
--------------------------------------------------------------------------------
1 | /******************************************************************************
2 | * Spine Runtimes License Agreement
3 | * Last updated February 20, 2024. Replaces all prior versions.
4 | *
5 | * Copyright (c) 2013-2024, Esoteric Software LLC
6 | *
7 | * Integration of the Spine Runtimes into software or otherwise creating derivative works
8 | * of the Spine Runtimes is permitted under the terms and conditions of Section 2 of the
9 | * Spine Editor License Agreement:
10 | * https://esotericsoftware.com/spine-editor-license
11 | *
12 | * Otherwise, it is permitted to integrate the Spine Runtimes into software or otherwise
13 | * create derivative works of the Spine Runtimes (collectively, "Products"), provided that
14 | * each user of the Products must obtain their own Spine Editor license and redistribution
15 | * of the Products in any form must include this license and copyright notice.
16 | *
17 | * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY EXPRESS OR IMPLIED
18 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
19 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR
20 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
22 | * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY
23 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE SPINE RUNTIMES,
25 | * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 | *****************************************************************************/
27 |
28 | package com.esotericsoftware.spine.superspineboy;
29 |
30 | import com.esotericsoftware.spine.superspineboy.Enemy.Type;
31 |
32 | import com.badlogic.gdx.maps.tiled.AtlasTmxMapLoader;
33 | import com.badlogic.gdx.maps.tiled.TiledMap;
34 | import com.badlogic.gdx.maps.tiled.TiledMapTileLayer;
35 | import com.badlogic.gdx.maps.tiled.TiledMapTileLayer.Cell;
36 | import com.badlogic.gdx.math.Interpolation;
37 | import com.badlogic.gdx.math.MathUtils;
38 | import com.badlogic.gdx.math.Rectangle;
39 | import com.badlogic.gdx.math.Vector2;
40 | import com.badlogic.gdx.utils.Array;
41 | import com.badlogic.gdx.utils.FloatArray;
42 | import com.badlogic.gdx.utils.Pools;
43 |
44 | /** The core of the game logic. The model manages all game information but knows nothing about the view, ie it knows nothing about
45 | * how this information might be drawn to the screen. This model-view separation is a clean way to organize the code. */
46 | class Model {
47 | static float scale = 1 / 64f;
48 | static float gravity = 32;
49 | static float fps = 1 / 30f;
50 | static float gameOverSlowdown = 5.5f;
51 | static int mapCollisionLayer = 0;
52 |
53 | SuperSpineboy controller;
54 | Player player;
55 | TiledMap map;
56 | TiledMapTileLayer collisionLayer;
57 | Array tiles = new Array();
58 | float timeScale = 1;
59 | Array triggers = new Array();
60 | FloatArray bullets = new FloatArray();
61 | Array enemies = new Array();
62 | Vector2 temp = new Vector2();
63 | float gameOverTimer;
64 |
65 | Model (SuperSpineboy controller) {
66 | this.controller = controller;
67 |
68 | map = new AtlasTmxMapLoader().load("map/map.tmx");
69 | collisionLayer = (TiledMapTileLayer)map.getLayers().get(mapCollisionLayer);
70 |
71 | restart();
72 | }
73 |
74 | void restart () {
75 | player = new Player(this);
76 | player.position.set(4, 8);
77 |
78 | bullets.clear();
79 | enemies.clear();
80 | gameOverTimer = 0;
81 |
82 | // Setup triggers to spawn enemies based on the x coordinate of the player.
83 | triggers.clear();
84 | addTrigger(17, 17 + 22, 8, Type.normal, 2);
85 | addTrigger(17, 17 + 22, 8, Type.strong, 1);
86 | addTrigger(31, 31 + 22, 8, Type.normal, 3);
87 | addTrigger(43, 43 + 22, 8, Type.strong, 3);
88 | addTrigger(64, 64 + 22, 8, Type.normal, 10);
89 | addTrigger(64, 64 + 29, 8, Type.strong, 1);
90 | addTrigger(76, 76 - 19, 8, Type.strong, 2);
91 | addTrigger(87, 87 - 19, 8, Type.normal, 2);
92 | addTrigger(97, 97 - 19, 8, Type.normal, 2);
93 | addTrigger(100, 100 + 34, 8, Type.strong, 2);
94 | addTrigger(103, 103 + 34, 8, Type.normal, 4);
95 | addTrigger(125, 60 - 19, 8, Type.normal, 10);
96 | addTrigger(125, 125 - 19, 8, Type.weak, 10);
97 | addTrigger(125, 125 - 45, 8, Type.becomesBig, 1);
98 | addTrigger(125, 125 + 22, 22, Type.normal, 5);
99 | addTrigger(125, 125 + 32, 22, Type.normal, 2);
100 | addTrigger(125, 220, 23, Type.strong, 3);
101 | addTrigger(158, 158 - 19, 8, Type.weak, 10);
102 | addTrigger(158, 158 - 23, 8, Type.strong, 1);
103 | addTrigger(158, 158 + 22, 23, Type.normal, 3);
104 | addTrigger(165, 165 + 22, 23, Type.strong, 4);
105 | addTrigger(176, 176 + 22, 23, Type.normal, 12);
106 | addTrigger(176, 176 + 22, 23, Type.weak, 10);
107 | addTrigger(176, 151, 8, Type.strong, 1);
108 | addTrigger(191, 191 - 19, 23, Type.normal, 5);
109 | addTrigger(191, 191 - 19, 23, Type.weak, 15);
110 | addTrigger(191, 191 - 27, 23, Type.strong, 2);
111 | addTrigger(191, 191 + 34, 23, Type.weak, 10);
112 | addTrigger(191, 191 + 34, 23, Type.weak, 8);
113 | addTrigger(191, 191 + 34, 23, Type.normal, 2);
114 | addTrigger(191, 191 + 42, 23, Type.strong, 2);
115 | addTrigger(213, 213 + 22, 23, Type.normal, 3);
116 | addTrigger(213, 213 + 22, 23, Type.strong, 3);
117 | addTrigger(213, 213 - 19, 23, Type.normal, 7);
118 | addTrigger(246, 247 - 30, 23, Type.strong, 7);
119 | addTrigger(246, 225, 23, Type.normal, 2);
120 | addTrigger(246, 220, 23, Type.becomesBig, 3);
121 | }
122 |
123 | void addTrigger (float triggerX, float spawnX, float spawnY, Type type, int count) {
124 | Trigger trigger = new Trigger();
125 | trigger.x = triggerX;
126 | triggers.add(trigger);
127 | int offset = spawnX > triggerX ? 2 : -2;
128 | for (int i = 0; i < count; i++) {
129 | Enemy enemy = new Enemy(this, type);
130 | enemy.position.set(spawnX, spawnY);
131 | trigger.enemies.add(enemy);
132 | spawnX += offset;
133 | }
134 | }
135 |
136 | void update (float delta) {
137 | if (player.hp == 0) {
138 | gameOverTimer += delta / getTimeScale() * timeScale; // Isn't affected by player death time scaling.
139 | controller.eventGameOver(false);
140 | }
141 | updateEnemies(delta);
142 | updateBullets(delta);
143 | player.update(delta);
144 | updateTriggers();
145 | }
146 |
147 | void updateTriggers () {
148 | for (int i = 0, n = triggers.size; i < n; i++) {
149 | Trigger trigger = triggers.get(i);
150 | if (player.position.x > trigger.x) {
151 | enemies.addAll(trigger.enemies);
152 | triggers.removeIndex(i);
153 | break;
154 | }
155 | }
156 | }
157 |
158 | void updateEnemies (float delta) {
159 | int alive = 0;
160 | for (int i = enemies.size - 1; i >= 0; i--) {
161 | Enemy enemy = enemies.get(i);
162 | enemy.update(delta);
163 | if (enemy.deathTimer < 0) {
164 | enemies.removeIndex(i);
165 | continue;
166 | }
167 | if (enemy.hp > 0) alive++;
168 | if (enemy.hp > 0 && player.hp > 0) {
169 | if (enemy.collisionTimer < 0 && enemy.rect.overlaps(player.rect)) {
170 | if (enemy.rect.y + enemy.rect.height * 0.6f < player.rect.y) {
171 | // Enemy head bounce.
172 | float bounceX = Player.headBounceX
173 | * (enemy.position.x + enemy.rect.width / 2 < player.position.x + player.rect.width / 2 ? 1 : -1);
174 |
175 | enemy.collisionTimer = Enemy.collisionDelay;
176 | enemy.velocity.x -= bounceX;
177 | enemy.velocity.y -= 10f;
178 | enemy.setGrounded(false);
179 | enemy.hp -= 2;
180 | if (enemy.hp <= 0)
181 | enemy.state = State.death;
182 | else
183 | enemy.state = State.fall;
184 |
185 | player.velocity.x = bounceX;
186 | player.velocity.y = Player.headBounceY;
187 | player.setGrounded(false);
188 | player.setState(State.fall);
189 |
190 | controller.eventHitEnemy(enemy);
191 |
192 | } else if (player.collisionTimer < 0) {
193 | // Player gets hit.
194 | player.dir = enemy.position.x + enemy.rect.width / 2 < player.position.x + player.rect.width / 2 ? -1 : 1;
195 | float amount = Player.knockbackX * player.dir;
196 | player.velocity.x = -amount;
197 | player.velocity.y += Player.knockbackY;
198 | player.setGrounded(false);
199 | player.hp--;
200 | if (player.hp > 0) {
201 | player.setState(State.fall);
202 | player.collisionTimer = Player.collisionDelay;
203 |
204 | enemy.velocity.x = amount * 1.6f;
205 | enemy.velocity.y += 5f;
206 | enemy.setState(State.fall);
207 | enemy.jumpDelayTimer = MathUtils.random(0, enemy.jumpDelay);
208 | } else {
209 | player.setState(State.death);
210 | player.velocity.y *= 0.5f;
211 | }
212 | enemy.setGrounded(false);
213 | enemy.collisionTimer = Enemy.collisionDelay;
214 |
215 | controller.eventHitPlayer(enemy);
216 | }
217 | }
218 | }
219 | }
220 | // End the game when all enemies are dead and all triggers have occurred.
221 | if (alive == 0 && triggers.size == 0) controller.eventGameOver(true);
222 | }
223 |
224 | void updateBullets (float delta) {
225 | outer:
226 | for (int i = bullets.size - 5; i >= 0; i -= 5) {
227 | float vx = bullets.get(i);
228 | float vy = bullets.get(i + 1);
229 | float x = bullets.get(i + 2);
230 | float y = bullets.get(i + 3);
231 | if (collisionLayer.getCell((int)x, (int)y) != null) {
232 | // Bullet hit map.
233 | controller.eventHitBullet(x, y, vx, vy);
234 | bullets.removeRange(i, i + 4);
235 | continue;
236 | }
237 | if (Math.abs(x - player.position.x) > 25) {
238 | // Bullet traveled too far.
239 | bullets.removeRange(i, i + 4);
240 | continue;
241 | }
242 | for (Enemy enemy : enemies) {
243 | if (enemy.state == State.death) continue;
244 | if (enemy.bigTimer <= 0 && enemy.rect.contains(x, y)) {
245 | // Bullet hit enemy.
246 | bullets.removeRange(i, i + 4);
247 | controller.eventHitBullet(x, y, vx, vy);
248 | controller.eventHitEnemy(enemy);
249 | enemy.collisionTimer = Enemy.collisionDelay;
250 | enemy.hp--;
251 | if (enemy.hp <= 0) {
252 | enemy.state = State.death;
253 | enemy.velocity.y *= 0.5f;
254 | } else
255 | enemy.state = State.fall;
256 | enemy.velocity.x = MathUtils.random(enemy.knockbackX / 2, enemy.knockbackX)
257 | * (player.position.x < enemy.position.x + enemy.rect.width / 2 ? 1 : -1);
258 | enemy.velocity.y += MathUtils.random(enemy.knockbackY / 2, enemy.knockbackY);
259 | continue outer;
260 | }
261 | }
262 | x += vx * delta;
263 | y += vy * delta;
264 | bullets.set(i + 2, x);
265 | bullets.set(i + 3, y);
266 | }
267 | }
268 |
269 | void addBullet (float startX, float startY, float vx, float vy, float angle) {
270 | bullets.add(vx);
271 | bullets.add(vy);
272 | bullets.add(startX);
273 | bullets.add(startY);
274 | bullets.add(angle);
275 | }
276 |
277 | /** Returns rectangles for the tiles within the specified area. */
278 | Array getCollisionTiles (int startX, int startY, int endX, int endY) {
279 | Pools.freeAll(tiles, true);
280 | tiles.clear();
281 | for (int y = startY; y <= endY; y++) {
282 | for (int x = startX; x <= endX; x++) {
283 | Cell cell = collisionLayer.getCell(x, y);
284 | if (cell != null) {
285 | Rectangle rect = Pools.obtain(Rectangle.class);
286 | rect.set(x, y, 1, 1);
287 | tiles.add(rect);
288 | }
289 | }
290 | }
291 | return tiles;
292 | }
293 |
294 | float getTimeScale () {
295 | if (player.hp == 0)
296 | return timeScale * Interpolation.pow2In.apply(0, 1, MathUtils.clamp(gameOverTimer / gameOverSlowdown, 0.01f, 1));
297 | return timeScale;
298 | }
299 |
300 | enum State {
301 | idle, run, jump, death, fall
302 | }
303 |
304 | static class Trigger {
305 | float x;
306 | Array enemies = new Array();
307 | }
308 | }
309 |
--------------------------------------------------------------------------------
/src/com/esotericsoftware/spine/superspineboy/Player.java:
--------------------------------------------------------------------------------
1 | /******************************************************************************
2 | * Spine Runtimes License Agreement
3 | * Last updated February 20, 2024. Replaces all prior versions.
4 | *
5 | * Copyright (c) 2013-2024, Esoteric Software LLC
6 | *
7 | * Integration of the Spine Runtimes into software or otherwise creating derivative works
8 | * of the Spine Runtimes is permitted under the terms and conditions of Section 2 of the
9 | * Spine Editor License Agreement:
10 | * https://esotericsoftware.com/spine-editor-license
11 | *
12 | * Otherwise, it is permitted to integrate the Spine Runtimes into software or otherwise
13 | * create derivative works of the Spine Runtimes (collectively, "Products"), provided that
14 | * each user of the Products must obtain their own Spine Editor license and redistribution
15 | * of the Products in any form must include this license and copyright notice.
16 | *
17 | * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY EXPRESS OR IMPLIED
18 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
19 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR
20 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
22 | * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY
23 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE SPINE RUNTIMES,
25 | * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 | *****************************************************************************/
27 |
28 | package com.esotericsoftware.spine.superspineboy;
29 |
30 | import static com.esotericsoftware.spine.superspineboy.Model.*;
31 |
32 | /** The model class for the player. */
33 | class Player extends Character {
34 | static float heightSource = 625, width = 67 * scale, height = 285 * scale;
35 | static float hpStart = 4, hpDuration = 15;
36 |
37 | static float maxVelocityGroundX = 12.5f, maxVelocityAirX = 13.5f;
38 | static float playerJumpVelocity = 22f, jumpDamping = 0.5f, jumpOffsetVelocity = 10, jumpOffsetY = 120 * scale;
39 | static float airJumpTime = 0.1f;
40 |
41 | static float shootDelay = 0.1f, shootOffsetX = 160, shootOffsetY = 11;
42 | static float bulletSpeed = 34, bulletInheritVelocity = 0.4f, burstDuration = 0.18f;
43 | static float kickbackShots = 33, kickbackAngle = 30, kickbackVarianceShots = 11, kickbackVariance = 6, kickback = 1.6f;
44 |
45 | static float knockbackX = 14, knockbackY = 5, collisionDelay = 2.5f, flashTime = 0.07f;
46 | static float headBounceX = 12, headBounceY = 20;
47 |
48 | float shootTimer;
49 | float collisionTimer;
50 | float hpTimer;
51 |
52 | // This is here for convenience, the model should never touch the view.
53 | PlayerView view;
54 |
55 | Player (Model model) {
56 | super(model);
57 | rect.width = width;
58 | rect.height = height;
59 | hp = hpStart;
60 | jumpVelocity = playerJumpVelocity;
61 | }
62 |
63 | void update (float delta) {
64 | stateChanged = false;
65 |
66 | shootTimer -= delta;
67 |
68 | if (hp > 0) {
69 | hpTimer -= delta;
70 | if (hpTimer < 0) {
71 | hpTimer = hpDuration;
72 | if (hp < hpStart) hp++;
73 | }
74 | }
75 |
76 | collisionTimer -= delta;
77 | rect.height = height - collisionOffsetY;
78 | maxVelocityX = isGrounded() ? maxVelocityGroundX : maxVelocityAirX;
79 | super.update(delta);
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/src/com/esotericsoftware/spine/superspineboy/PlayerView.java:
--------------------------------------------------------------------------------
1 | /******************************************************************************
2 | * Spine Runtimes License Agreement
3 | * Last updated February 20, 2024. Replaces all prior versions.
4 | *
5 | * Copyright (c) 2013-2024, Esoteric Software LLC
6 | *
7 | * Integration of the Spine Runtimes into software or otherwise creating derivative works
8 | * of the Spine Runtimes is permitted under the terms and conditions of Section 2 of the
9 | * Spine Editor License Agreement:
10 | * https://esotericsoftware.com/spine-editor-license
11 | *
12 | * Otherwise, it is permitted to integrate the Spine Runtimes into software or otherwise
13 | * create derivative works of the Spine Runtimes (collectively, "Products"), provided that
14 | * each user of the Products must obtain their own Spine Editor license and redistribution
15 | * of the Products in any form must include this license and copyright notice.
16 | *
17 | * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY EXPRESS OR IMPLIED
18 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
19 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR
20 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
22 | * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY
23 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE SPINE RUNTIMES,
25 | * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 | *****************************************************************************/
27 |
28 | package com.esotericsoftware.spine.superspineboy;
29 |
30 | import static com.esotericsoftware.spine.superspineboy.Model.*;
31 | import static com.esotericsoftware.spine.superspineboy.Player.*;
32 |
33 | import com.badlogic.gdx.Gdx;
34 | import com.badlogic.gdx.math.Interpolation;
35 | import com.badlogic.gdx.math.MathUtils;
36 | import com.badlogic.gdx.math.Vector2;
37 |
38 | import com.esotericsoftware.spine.Animation;
39 | import com.esotericsoftware.spine.AnimationState;
40 | import com.esotericsoftware.spine.AnimationState.AnimationStateAdapter;
41 | import com.esotericsoftware.spine.Bone;
42 | import com.esotericsoftware.spine.Event;
43 | import com.esotericsoftware.spine.EventData;
44 | import com.esotericsoftware.spine.Skeleton;
45 | import com.esotericsoftware.spine.Skeleton.Physics;
46 | import com.esotericsoftware.spine.superspineboy.Assets.SoundEffect;
47 | import com.esotericsoftware.spine.superspineboy.Model.State;
48 |
49 | /** The view class for the player. */
50 | class PlayerView extends CharacterView {
51 | Player player;
52 | Bone rearUpperArmBone, rearBracerBone, gunBone, headBone, torsoBone, frontUpperArmBone;
53 | Animation shootAnimation, hitAnimation;
54 | boolean canShoot;
55 | float burstShots, burstTimer;
56 | Vector2 temp1 = new Vector2(), temp2 = new Vector2();
57 |
58 | PlayerView (final View view) {
59 | super(view);
60 | player = view.player;
61 |
62 | skeleton = new Skeleton(view.assets.playerSkeletonData);
63 |
64 | // We'll allow any of the bones or animations to be null in case someone has swapped out spineboy for a different skeleton.
65 | rearUpperArmBone = skeleton.findBone("rear_upper_arm");
66 | rearBracerBone = skeleton.findBone("rear_bracer");
67 | gunBone = skeleton.findBone("gun");
68 | headBone = skeleton.findBone("head");
69 | torsoBone = skeleton.findBone("torso");
70 | frontUpperArmBone = skeleton.findBone("front_upper_arm");
71 | shootAnimation = view.assets.playerSkeletonData.findAnimation("shoot");
72 | hitAnimation = view.assets.playerSkeletonData.findAnimation("hit");
73 |
74 | animationState = new AnimationState(view.assets.playerAnimationData);
75 |
76 | // Play footstep sounds.
77 | final EventData footstepEvent = view.assets.playerSkeletonData.findEvent("footstep");
78 | animationState.addListener(new AnimationStateAdapter() {
79 | public void event (int trackIndex, Event event) {
80 | if (event.getData() == footstepEvent) {
81 | if (event.getInt() == 1)
82 | SoundEffect.footstep1.play();
83 | else
84 | SoundEffect.footstep2.play();
85 | }
86 | }
87 | });
88 | }
89 |
90 | void update (float delta) {
91 | // When not shooting, reset the number of burst shots.
92 | if (!view.touched && burstTimer > 0) {
93 | burstTimer -= delta;
94 | if (burstTimer < 0) burstShots = 0;
95 | }
96 |
97 | // If jump was pressed in the air, jump as soon as grounded.
98 | if (view.jumpPressed && player.isGrounded()) jump();
99 |
100 | skeleton.setX(player.position.x + width / 2);
101 | skeleton.setY(player.position.y);
102 |
103 | if (!setAnimation(view.assets.playerStates.get(player.state), player.stateChanged)) animationState.update(delta);
104 | animationState.apply(skeleton);
105 |
106 | Vector2 mouse = temp1.set(Gdx.input.getX(), Gdx.input.getY());
107 | view.viewport.unproject(mouse);
108 |
109 | // Determine if the player can shoot at the mouse position.
110 | canShoot = false;
111 | if (rearUpperArmBone == null || rearBracerBone == null || gunBone == null)
112 | canShoot = true;
113 | else if (player.hp > 0 && !view.ui.hasSplash
114 | && (Math.abs(skeleton.getY() - mouse.y) > 2.7f || Math.abs(skeleton.getX() - mouse.x) > 0.75f)) {
115 | // Store bone rotations from the animation that was applied.
116 | float rearUpperArmRotation = rearUpperArmBone.getRotation();
117 | float rearBracerRotation = rearBracerBone.getRotation();
118 | float gunRotation = gunBone.getRotation();
119 | // Straighten the arm and don't flipX, so the arm can more easily point at the mouse.
120 | rearUpperArmBone.setRotation(0);
121 | float shootRotation = 11;
122 | if (animationState.getCurrent(1) == null) {
123 | rearBracerBone.setRotation(0);
124 | gunBone.setRotation(0);
125 | } else
126 | shootRotation += 25; // Use different rotation when shoot animation was applied.
127 | skeleton.setScaleX(1);
128 | skeleton.updateWorldTransform(Physics.none);
129 |
130 | // Compute the arm's angle to the mouse, flipping it based on the direction the player faces.
131 | Vector2 bonePosition = temp2.set(rearUpperArmBone.getWorldX(), rearUpperArmBone.getWorldY());
132 | float angle = bonePosition.sub(mouse).angle();
133 | float behind = (angle < 90 || angle > 270) ? -1 : 1;
134 | if (behind == -1) angle = -angle;
135 | if (player.state == State.idle || (view.touched && (player.state == State.jump || player.state == State.fall)))
136 | player.dir = behind;
137 | if (behind != player.dir) angle = -angle;
138 | if (player.state != State.idle && behind != player.dir) {
139 | // Don't allow the player to shoot behind themselves unless idle. Use the rotations stored earlier from the animation.
140 | rearBracerBone.setRotation(rearBracerRotation);
141 | rearUpperArmBone.setRotation(rearUpperArmRotation);
142 | gunBone.setRotation(gunRotation);
143 | } else {
144 | if (behind == 1) angle += 180;
145 | // Adjust the angle upward based on the number of shots in the current burst.
146 | angle += kickbackAngle * Math.min(1, burstShots / kickbackShots) * (burstTimer / burstDuration);
147 | float gunArmAngle = angle - shootRotation;
148 | // Compute the head, torso and front arm angles so the player looks up or down.
149 | float headAngle;
150 | if (player.dir == -1) {
151 | angle += 360;
152 | if (angle < 180)
153 | headAngle = 25 * Interpolation.pow2In.apply(Math.min(1, angle / 50f));
154 | else
155 | headAngle = -15 * Interpolation.pow2In.apply(1 - Math.max(0, angle - 310) / 50f);
156 | } else {
157 | if (angle < 360)
158 | headAngle = -15 * Interpolation.pow2In.apply(1 - Math.max(0, (angle - 310) / 50f));
159 | else
160 | headAngle = 25 * Interpolation.pow2In.apply(1 - Math.max(0, (410 - angle) / 50f));
161 | }
162 | float torsoAngle = headAngle * 0.75f;
163 | if (headBone != null) headBone.setRotation(headBone.getRotation() + headAngle);
164 | if (torsoBone != null) torsoBone.setRotation(torsoBone.getRotation() + torsoAngle);
165 | if (frontUpperArmBone != null) frontUpperArmBone.setRotation(frontUpperArmBone.getRotation() - headAngle * 1.4f);
166 | rearUpperArmBone.setRotation(gunArmAngle - torsoAngle - rearUpperArmBone.getWorldRotationX());
167 | canShoot = true;
168 | }
169 | }
170 |
171 | skeleton.setScaleX(player.dir);
172 | skeleton.updateWorldTransform(null);
173 | }
174 |
175 | void jump () {
176 | view.jumpPressed = false;
177 | player.jump();
178 | setAnimation(view.assets.playerStates.get(State.jump), true);
179 | }
180 |
181 | void shoot () {
182 | if (!canShoot || player.shootTimer >= 0) return;
183 | player.shootTimer = shootDelay;
184 | burstTimer = burstDuration;
185 |
186 | // Compute the position and velocity to spawn a new bullet.
187 | float x = 0, y = 0;
188 | if (rearUpperArmBone != null && rearBracerBone != null && gunBone != null) {
189 | x += rearUpperArmBone.getWorldX();
190 | y += rearUpperArmBone.getWorldY();
191 | } else {
192 | x += width / 2;
193 | y += height / 2;
194 | }
195 | float mouseX = Gdx.input.getX(), mouseY = Gdx.input.getY();
196 |
197 | float angle = view.viewport.unproject(temp1.set(mouseX, mouseY)).sub(x, y).angle();
198 | angle += kickbackAngle * Math.min(1, burstShots / kickbackShots) * player.dir;
199 | float variance = kickbackVariance * Math.min(1, burstShots / kickbackVarianceShots);
200 | angle += MathUtils.random(-variance, variance);
201 |
202 | float cos = MathUtils.cosDeg(angle), sin = MathUtils.sinDeg(angle);
203 | float vx = cos * bulletSpeed + player.velocity.x * bulletInheritVelocity;
204 | float vy = sin * bulletSpeed + player.velocity.y * bulletInheritVelocity;
205 | if (rearUpperArmBone != null && rearBracerBone != null && gunBone != null) {
206 | x = gunBone.getWorldX();
207 | y = gunBone.getWorldY() + shootOffsetY * scale;
208 | x += cos * shootOffsetX * scale;
209 | y += sin * shootOffsetX * scale;
210 | }
211 | model.addBullet(x, y, vx, vy, temp1.set(vx, vy).angle());
212 | if (shootAnimation != null) animationState.setAnimation(1, shootAnimation, false);
213 |
214 | view.camera.position.sub(view.shakeX, view.shakeY, 0);
215 | view.shakeX += View.cameraShake * (MathUtils.randomBoolean() ? 1 : -1);
216 | view.shakeY += View.cameraShake * (MathUtils.randomBoolean() ? 1 : -1);
217 | view.camera.position.add(view.shakeX, view.shakeY, 0);
218 |
219 | player.velocity.x -= kickback * player.dir;
220 | SoundEffect.shoot.play();
221 |
222 | burstShots = Math.min(kickbackShots, burstShots + 1);
223 | }
224 | }
225 |
--------------------------------------------------------------------------------
/src/com/esotericsoftware/spine/superspineboy/SuperSpineboy.java:
--------------------------------------------------------------------------------
1 | /******************************************************************************
2 | * Spine Runtimes License Agreement
3 | * Last updated February 20, 2024. Replaces all prior versions.
4 | *
5 | * Copyright (c) 2013-2024, Esoteric Software LLC
6 | *
7 | * Integration of the Spine Runtimes into software or otherwise creating derivative works
8 | * of the Spine Runtimes is permitted under the terms and conditions of Section 2 of the
9 | * Spine Editor License Agreement:
10 | * https://esotericsoftware.com/spine-editor-license
11 | *
12 | * Otherwise, it is permitted to integrate the Spine Runtimes into software or otherwise
13 | * create derivative works of the Spine Runtimes (collectively, "Products"), provided that
14 | * each user of the Products must obtain their own Spine Editor license and redistribution
15 | * of the Products in any form must include this license and copyright notice.
16 | *
17 | * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY EXPRESS OR IMPLIED
18 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
19 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR
20 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
22 | * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY
23 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE SPINE RUNTIMES,
25 | * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 | *****************************************************************************/
27 |
28 | package com.esotericsoftware.spine.superspineboy;
29 |
30 | import com.badlogic.gdx.ApplicationAdapter;
31 | import com.badlogic.gdx.Gdx;
32 | import com.badlogic.gdx.backends.lwjgl.LwjglApplication;
33 | import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration;
34 | import com.badlogic.gdx.math.Vector2;
35 |
36 | import com.esotericsoftware.spine.AnimationState.TrackEntry;
37 | import com.esotericsoftware.spine.superspineboy.Assets.SoundEffect;
38 |
39 | /** The controller class for the game. It knows about both the model and view and provides a way for the view to know about events
40 | * that occur in the model. */
41 | class SuperSpineboy extends ApplicationAdapter {
42 | static Vector2 temp = new Vector2();
43 |
44 | View view;
45 | Model model;
46 |
47 | public void create () {
48 | model = new Model(this);
49 | view = new View(model);
50 | }
51 |
52 | public void render () {
53 | float delta = Math.min(Gdx.graphics.getDeltaTime(), 1 / 30f) * model.getTimeScale();
54 | if (delta > 0) {
55 | model.update(delta);
56 | view.update(delta);
57 | }
58 | view.render();
59 | }
60 |
61 | public void resize (int width, int height) {
62 | view.resize(width, height);
63 | }
64 |
65 | void restart () {
66 | model.restart();
67 | view.restart();
68 | }
69 |
70 | void eventHitPlayer (Enemy enemy) {
71 | SoundEffect.hurtPlayer.play();
72 | if (view.player.hp > 0 && view.player.view.hitAnimation != null) {
73 | TrackEntry entry = view.player.view.animationState.setAnimation(1, view.player.view.hitAnimation, false);
74 | entry.setTrackEnd(view.player.view.hitAnimation.getDuration());
75 | }
76 | }
77 |
78 | void eventHitEnemy (Enemy enemy) {
79 | SoundEffect.hurtAlien.play();
80 | if (enemy.view.hitAnimation != null) {
81 | TrackEntry entry = enemy.view.animationState.setAnimation(1, enemy.view.hitAnimation, false);
82 | entry.setTrackEnd(enemy.view.hitAnimation.getDuration());
83 | }
84 | }
85 |
86 | void eventHitBullet (float x, float y, float vx, float vy) {
87 | Vector2 offset = temp.set(vx, vy).nor().scl(15 * Model.scale);
88 | view.hits.add(View.bulletHitTime);
89 | view.hits.add(x + offset.x);
90 | view.hits.add(y + offset.y);
91 | view.hits.add(temp.angle() + 90);
92 | SoundEffect.hit.play();
93 | }
94 |
95 | void eventGameOver (boolean win) {
96 | if (!view.ui.splashTable.hasParent()) {
97 | view.ui.showSplash(view.assets.gameOverRegion, win ? view.assets.youWinRegion : view.assets.youLoseRegion);
98 | view.ui.inputTimer = win ? 5 : 1;
99 | }
100 | view.jumpPressed = false;
101 | view.leftPressed = false;
102 | view.rightPressed = false;
103 | }
104 |
105 | public static void main (String[] args) throws Exception {
106 | LwjglApplicationConfiguration config = new LwjglApplicationConfiguration();
107 | config.title = "Super Spineboy";
108 | config.width = 800;
109 | config.height = 450;
110 | new LwjglApplication(new SuperSpineboy(), config);
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/src/com/esotericsoftware/spine/superspineboy/UI.java:
--------------------------------------------------------------------------------
1 | /******************************************************************************
2 | * Spine Runtimes License Agreement
3 | * Last updated February 20, 2024. Replaces all prior versions.
4 | *
5 | * Copyright (c) 2013-2024, Esoteric Software LLC
6 | *
7 | * Integration of the Spine Runtimes into software or otherwise creating derivative works
8 | * of the Spine Runtimes is permitted under the terms and conditions of Section 2 of the
9 | * Spine Editor License Agreement:
10 | * https://esotericsoftware.com/spine-editor-license
11 | *
12 | * Otherwise, it is permitted to integrate the Spine Runtimes into software or otherwise
13 | * create derivative works of the Spine Runtimes (collectively, "Products"), provided that
14 | * each user of the Products must obtain their own Spine Editor license and redistribution
15 | * of the Products in any form must include this license and copyright notice.
16 | *
17 | * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY EXPRESS OR IMPLIED
18 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
19 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR
20 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
22 | * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY
23 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE SPINE RUNTIMES,
25 | * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 | *****************************************************************************/
27 |
28 | package com.esotericsoftware.spine.superspineboy;
29 |
30 | import static com.badlogic.gdx.math.Interpolation.*;
31 | import static com.badlogic.gdx.scenes.scene2d.actions.Actions.*;
32 | import static com.esotericsoftware.spine.superspineboy.Model.*;
33 | import static com.esotericsoftware.spine.superspineboy.View.*;
34 |
35 | import com.badlogic.gdx.Gdx;
36 | import com.badlogic.gdx.Graphics.DisplayMode;
37 | import com.badlogic.gdx.Input.Keys;
38 | import com.badlogic.gdx.InputAdapter;
39 | import com.badlogic.gdx.graphics.Color;
40 | import com.badlogic.gdx.graphics.Pixmap;
41 | import com.badlogic.gdx.graphics.Pixmap.Format;
42 | import com.badlogic.gdx.graphics.Texture;
43 | import com.badlogic.gdx.graphics.g2d.Batch;
44 | import com.badlogic.gdx.graphics.g2d.BitmapFont;
45 | import com.badlogic.gdx.graphics.g2d.SpriteCache;
46 | import com.badlogic.gdx.graphics.g2d.TextureRegion;
47 | import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
48 | import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType;
49 | import com.badlogic.gdx.math.Rectangle;
50 | import com.badlogic.gdx.math.Vector2;
51 | import com.badlogic.gdx.scenes.scene2d.Actor;
52 | import com.badlogic.gdx.scenes.scene2d.InputEvent;
53 | import com.badlogic.gdx.scenes.scene2d.InputListener;
54 | import com.badlogic.gdx.scenes.scene2d.Stage;
55 | import com.badlogic.gdx.scenes.scene2d.Touchable;
56 | import com.badlogic.gdx.scenes.scene2d.ui.ButtonGroup;
57 | import com.badlogic.gdx.scenes.scene2d.ui.Image;
58 | import com.badlogic.gdx.scenes.scene2d.ui.Label;
59 | import com.badlogic.gdx.scenes.scene2d.ui.Label.LabelStyle;
60 | import com.badlogic.gdx.scenes.scene2d.ui.ProgressBar;
61 | import com.badlogic.gdx.scenes.scene2d.ui.ProgressBar.ProgressBarStyle;
62 | import com.badlogic.gdx.scenes.scene2d.ui.Skin;
63 | import com.badlogic.gdx.scenes.scene2d.ui.Table;
64 | import com.badlogic.gdx.scenes.scene2d.ui.TextButton;
65 | import com.badlogic.gdx.scenes.scene2d.ui.TextButton.TextButtonStyle;
66 | import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener;
67 | import com.badlogic.gdx.scenes.scene2d.utils.TextureRegionDrawable;
68 | import com.badlogic.gdx.scenes.scene2d.utils.UIUtils;
69 | import com.badlogic.gdx.utils.FloatArray;
70 | import com.badlogic.gdx.utils.Scaling;
71 | import com.badlogic.gdx.utils.viewport.ScreenViewport;
72 | import com.esotericsoftware.spine.SkeletonRendererDebug;
73 |
74 | /** The user interface displayed on top of the game (menu, health bar, splash screens). */
75 | class UI extends InputAdapter {
76 | static final Color gray = new Color(0.15f, 0.15f, 0.15f, 1);
77 |
78 | View view;
79 | Model model;
80 |
81 | ShapeRenderer shapes;
82 | SkeletonRendererDebug skeletonRendererDebug;
83 | Stage stage;
84 | Skin skin;
85 | Label fpsLabel, bindsLabel;
86 | TextButton debugButton, zoomButton, bgButton;
87 | TextButton speed200Button, speed150Button, speed100Button, speed33Button, speed15Button, speed3Button, pauseButton;
88 | Table splashTable;
89 | Image splashImage, splashTextImage;
90 | ProgressBar healthBar;
91 | TextButton fullscreenButton, restartButton, menuButton;
92 | Table menu;
93 | Vector2 temp = new Vector2();
94 |
95 | int windowWidth, windowHeight;
96 | float inputTimer;
97 | boolean hasSplash;
98 |
99 | UI (final View view) {
100 | this.view = view;
101 | this.model = view.model;
102 |
103 | shapes = new ShapeRenderer();
104 |
105 | skeletonRendererDebug = new SkeletonRendererDebug(shapes);
106 | skeletonRendererDebug.setScale(scale);
107 | // skeletonRendererDebug.setPremultipliedAlpha(true);
108 |
109 | stage = new Stage(new ScreenViewport());
110 | loadSkin();
111 |
112 | create();
113 | layout();
114 | events();
115 |
116 | showSplash(view.assets.titleRegion, view.assets.startRegion);
117 | }
118 |
119 | private void create () {
120 | speed200Button = speedButton(2f);
121 | speed150Button = speedButton(1.5f);
122 | speed100Button = speedButton(1);
123 | speed33Button = speedButton(0.33f);
124 | speed15Button = speedButton(0.15f);
125 | speed3Button = speedButton(0.03f);
126 | pauseButton = speedButton(0);
127 | pauseButton.setText("Pause");
128 | new ButtonGroup(speed200Button, speed150Button, speed100Button, speed33Button, speed15Button, speed3Button, pauseButton);
129 | speed100Button.setChecked(true);
130 |
131 | healthBar = new ProgressBar(0, Player.hpStart, 1, false, skin);
132 | healthBar.setAnimateDuration(0.3f);
133 | healthBar.setAnimateInterpolation(fade);
134 | fpsLabel = new Label("", skin);
135 | bindsLabel = new Label("", skin);
136 | debugButton = button("Debug", true);
137 | zoomButton = button("Zoom", true);
138 | bgButton = button("Background", true);
139 | bgButton.setChecked(true);
140 |
141 | fullscreenButton = button("Fullscreen", true);
142 |
143 | menuButton = button("Menu", true);
144 | menuButton.getColor().a = 0.3f;
145 |
146 | splashImage = new Image();
147 | splashImage.setScaling(Scaling.fit);
148 |
149 | splashTextImage = new Image();
150 | splashTextImage.addAction(forever(sequence(fadeOut(0.4f, pow2In), fadeIn(0.4f, pow2Out))));
151 | }
152 |
153 | private void layout () {
154 | Table buttons = new Table();
155 | buttons.defaults().uniformX().fillX();
156 | buttons.add(speed200Button).row();
157 | buttons.add(speed150Button).row();
158 | buttons.add(speed100Button).row();
159 | buttons.add(speed33Button).row();
160 | buttons.add(speed15Button).row();
161 | buttons.add(speed3Button).row();
162 | buttons.add(pauseButton).row();
163 | buttons.defaults().padTop(5);
164 | buttons.add(debugButton).row();
165 | buttons.add(zoomButton).row();
166 | buttons.add(bgButton).row();
167 | buttons.add(fullscreenButton).row();
168 | buttons.add(restartButton).row();
169 |
170 | menu = new Table(skin);
171 | menu.defaults().space(5);
172 | menu.add("FPS:");
173 | menu.add(fpsLabel).expandX().left().row();
174 | menu.add("Binds:");
175 | menu.add(bindsLabel).left().row();
176 | menu.add(buttons).colspan(2).left();
177 | menu.setVisible(false);
178 |
179 | Table root = new Table(skin);
180 | stage.addActor(root);
181 | root.top().left().pad(5).defaults().space(5);
182 | root.setFillParent(true);
183 | root.add(menuButton).fillX();
184 | root.add(healthBar).height(10).fillY().expandX().right().top().row();
185 | root.add(menu);
186 |
187 | splashTable = new Table(skin);
188 | splashTable.setFillParent(true);
189 | splashTable.add(splashImage).fillX().row();
190 | splashTable.add(splashTextImage);
191 | splashTable.setTouchable(Touchable.enabled);
192 | }
193 |
194 | private void events () {
195 | menuButton.addListener(new ChangeListener() {
196 | public void changed (ChangeEvent event, Actor actor) {
197 | menu.clearActions();
198 | menu.getColor().a = menu.isVisible() ? 1 : 0;
199 | if (menu.isVisible())
200 | menu.addAction(sequence(alpha(0, 0.5f, fade), hide()));
201 | else
202 | menu.addAction(sequence(show(), alpha(1, 0.5f, fade)));
203 | menuButton.getColor().a = menu.isVisible() ? 0.3f : 1;
204 | }
205 | });
206 |
207 | fullscreenButton.addListener(new ChangeListener() {
208 | public void changed (ChangeEvent event, Actor actor) {
209 | toggleFullscreen();
210 | }
211 | });
212 |
213 | restartButton = button("Restart", false);
214 | restartButton.addListener(new ChangeListener() {
215 | public void changed (ChangeEvent event, Actor actor) {
216 | model.controller.restart();
217 | }
218 | });
219 |
220 | splashTable.addListener(new InputListener() {
221 | public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) {
222 | if (hasSplash && inputTimer < 0) {
223 | model.controller.restart();
224 | splashTable.clearActions();
225 | splashTable.getColor().a = 1;
226 | splashTable.addAction(sequence(fadeOut(1, fade), removeActor()));
227 | hasSplash = false;
228 | return true;
229 | }
230 | return false;
231 | }
232 | });
233 | }
234 |
235 | void loadSkin () {
236 | skin = new Skin();
237 | skin.add("default", new BitmapFont());
238 |
239 | Pixmap pixmap = new Pixmap(1, 1, Format.RGBA8888);
240 | pixmap.setColor(Color.WHITE);
241 | pixmap.fill();
242 | skin.add("white", new Texture(pixmap));
243 |
244 | TextButtonStyle textButtonStyle = new TextButtonStyle();
245 | textButtonStyle.up = skin.newDrawable("white", Color.DARK_GRAY);
246 | textButtonStyle.down = skin.newDrawable("white", new Color(0x416ba1ff));
247 | textButtonStyle.over = skin.newDrawable("white", Color.GRAY);
248 | textButtonStyle.font = skin.getFont("default");
249 | skin.add("default", textButtonStyle);
250 |
251 | textButtonStyle = new TextButtonStyle(textButtonStyle);
252 | textButtonStyle.checked = skin.newDrawable("white", new Color(0x5287ccff));
253 | skin.add("toggle", textButtonStyle);
254 |
255 | LabelStyle labelStyle = new LabelStyle();
256 | labelStyle.font = skin.getFont("default");
257 | skin.add("default", labelStyle);
258 |
259 | ProgressBarStyle progressBarStyle = new ProgressBarStyle();
260 | progressBarStyle.background = skin.newDrawable("white", new Color(0.25f, 0.25f, 0.25f, 0.66f));
261 | progressBarStyle.background.setMinHeight(15);
262 | progressBarStyle.knobBefore = skin.newDrawable("white", Color.CLEAR);
263 | progressBarStyle.knobBefore.setMinHeight(15);
264 | progressBarStyle.knobAfter = skin.newDrawable("white", new Color(1, 0, 0, 0.66f));
265 | progressBarStyle.knobAfter.setMinHeight(15);
266 | skin.add("default-horizontal", progressBarStyle);
267 | }
268 |
269 | TextButton speedButton (final float speed) {
270 | final TextButton button = button((int)(speed * 100) + "%", true);
271 | button.addListener(new ChangeListener() {
272 | public void changed (ChangeEvent event, Actor actor) {
273 | if (button.isChecked()) model.timeScale = speed;
274 | }
275 | });
276 | return button;
277 | }
278 |
279 | TextButton button (String text, boolean toggle) {
280 | TextButton button = new TextButton(text, skin, toggle ? "toggle" : "default");
281 | button.pad(2, 12, 2, 12);
282 | return button;
283 | }
284 |
285 | void render () {
286 | float delta = Gdx.graphics.getDeltaTime();
287 | inputTimer -= delta;
288 |
289 | float zoom = zoomButton.isChecked() ? cameraZoom : 1;
290 | if (view.zoom != zoom) {
291 | if (view.zoom < zoom)
292 | view.zoom = Math.min(zoom, view.zoom + cameraZoomSpeed * delta);
293 | else
294 | view.zoom = Math.max(zoom, view.zoom - cameraZoomSpeed * delta);
295 | view.viewport.setMinWorldWidth(cameraMinWidth * view.zoom);
296 | view.viewport.setMinWorldHeight(cameraHeight * view.zoom);
297 | view.viewport.setMaxWorldWidth(cameraMaxWidth * view.zoom);
298 | view.viewport.setMaxWorldHeight(cameraHeight * view.zoom);
299 | view.viewport.update(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
300 | }
301 |
302 | if (!bgButton.isChecked()) {
303 | shapes.setTransformMatrix(view.batch.getTransformMatrix());
304 | shapes.setProjectionMatrix(view.batch.getProjectionMatrix());
305 | shapes.setColor(gray);
306 | shapes.begin(ShapeType.Filled);
307 | float w = view.viewport.getWorldWidth(), h = view.viewport.getWorldHeight();
308 | int x = (int)(view.camera.position.x - w / 2), y = (int)(view.camera.position.y - h / 2);
309 | for (Rectangle rect : model.getCollisionTiles(x, y, x + (int)(w + 0.5f), y + (int)(h + 0.5f))) {
310 | shapes.rect(rect.x, rect.y, rect.width, rect.height);
311 | }
312 | shapes.end();
313 | }
314 |
315 | healthBar.setValue(Player.hpStart - model.player.hp);
316 |
317 | SpriteCache spriteCache = view.mapRenderer.getSpriteCache();
318 | int renderCalls = view.batch.totalRenderCalls + spriteCache.totalRenderCalls;
319 | view.batch.totalRenderCalls = 0;
320 | spriteCache.totalRenderCalls = 0;
321 | fpsLabel.setText(Integer.toString(Gdx.graphics.getFramesPerSecond()));
322 | bindsLabel.setText(Integer.toString(renderCalls));
323 |
324 | if (!hasSplash && debugButton.isChecked()) {
325 | shapes.setTransformMatrix(view.batch.getTransformMatrix());
326 | shapes.setProjectionMatrix(view.batch.getProjectionMatrix());
327 | shapes.begin(ShapeType.Line);
328 |
329 | shapes.setColor(Color.GREEN);
330 |
331 | FloatArray bullets = model.bullets;
332 | for (int i = bullets.size - 5; i >= 0; i -= 5) {
333 | float x = bullets.get(i + 2);
334 | float y = bullets.get(i + 3);
335 | shapes.x(x, y, 10 * scale);
336 | }
337 |
338 | FloatArray hits = view.hits;
339 | for (int i = hits.size - 4; i >= 0; i -= 4) {
340 | float x = hits.get(i + 1);
341 | float y = hits.get(i + 2);
342 | shapes.x(x, y, 10 * scale);
343 | }
344 |
345 | for (Enemy enemy : model.enemies) {
346 | Rectangle rect = enemy.rect;
347 | shapes.rect(rect.x, rect.y, rect.width, rect.height);
348 | }
349 |
350 | Rectangle rect = model.player.rect;
351 | shapes.rect(rect.x, rect.y, rect.width, rect.height);
352 |
353 | shapes.end();
354 |
355 | skeletonRendererDebug.draw(model.player.view.skeleton);
356 | for (Enemy enemy : model.enemies) {
357 | skeletonRendererDebug.draw(enemy.view.skeleton);
358 | }
359 | }
360 |
361 | stage.act();
362 | stage.getViewport().apply(true);
363 | stage.draw();
364 |
365 | Batch batch = stage.getBatch();
366 | batch.setColor(Color.WHITE);
367 | batch.begin();
368 | Vector2 cursor = stage.screenToStageCoordinates(temp.set(Gdx.input.getX(), Gdx.input.getY()));
369 | TextureRegion crosshair = view.assets.crosshair;
370 | batch.draw(crosshair, cursor.x - crosshair.getRegionWidth() / 2, cursor.y - crosshair.getRegionHeight() / 2 + 2);
371 | batch.end();
372 | }
373 |
374 | void resize (int width, int height) {
375 | stage.getViewport().update(width, height, true);
376 | }
377 |
378 | void toggleFullscreen () {
379 | if (Gdx.graphics.isFullscreen())
380 | Gdx.graphics.setWindowedMode(windowWidth, windowHeight);
381 | else {
382 | windowWidth = Gdx.graphics.getWidth();
383 | windowHeight = Gdx.graphics.getHeight();
384 | Gdx.graphics.setFullscreenMode(Gdx.graphics.getDisplayMode());
385 | }
386 | }
387 |
388 | void showSplash (TextureRegion splash, TextureRegion text) {
389 | splashImage.setDrawable(new TextureRegionDrawable(splash));
390 | splashTextImage.setDrawable(new TextureRegionDrawable(text));
391 | stage.addActor(splashTable);
392 | splashTable.clearActions();
393 | splashTable.getColor().a = 0;
394 | splashTable.addAction(fadeIn(1));
395 | hasSplash = true;
396 | }
397 |
398 | public boolean keyDown (int keycode) {
399 | switch (keycode) {
400 | case Keys.NUM_6:
401 | speed200Button.toggle();
402 | return true;
403 | case Keys.NUM_5:
404 | speed150Button.toggle();
405 | return true;
406 | case Keys.NUM_4:
407 | speed100Button.toggle();
408 | return true;
409 | case Keys.NUM_3:
410 | speed33Button.toggle();
411 | return true;
412 | case Keys.NUM_2:
413 | speed15Button.toggle();
414 | return true;
415 | case Keys.NUM_1:
416 | speed3Button.toggle();
417 | return true;
418 | case Keys.P:
419 | case Keys.GRAVE:
420 | pauseButton.toggle();
421 | return true;
422 | case Keys.B:
423 | bgButton.toggle();
424 | return true;
425 | case Keys.Z:
426 | zoomButton.toggle();
427 | return true;
428 | case Keys.I:
429 | debugButton.toggle();
430 | return true;
431 | case Keys.T:
432 | view.assets.dispose();
433 | Texture.invalidateAllTextures(Gdx.app);
434 | view.assets = new Assets();
435 | return true;
436 | case Keys.ESCAPE:
437 | if (Gdx.graphics.isFullscreen())
438 | Gdx.graphics.setWindowedMode(windowWidth, windowHeight);
439 | else
440 | System.exit(0);
441 | return true;
442 | case Keys.ENTER:
443 | if (UIUtils.alt()) toggleFullscreen();
444 | return true;
445 | case Keys.O:
446 | showSplash(view.assets.titleRegion, view.assets.startRegion);
447 | return true;
448 | }
449 | return hasSplash;
450 | }
451 |
452 | public boolean keyUp (int keycode) {
453 | return hasSplash;
454 | }
455 | }
456 |
--------------------------------------------------------------------------------
/src/com/esotericsoftware/spine/superspineboy/View.java:
--------------------------------------------------------------------------------
1 | /******************************************************************************
2 | * Spine Runtimes Software License
3 | * Version 2.1
4 | *
5 | * Copyright (c) 2013, Esoteric Software
6 | * All rights reserved.
7 | *
8 | * You are granted a perpetual, non-exclusive, non-sublicensable and
9 | * non-transferable license to install, execute and perform the Spine Runtimes
10 | * Software (the "Software") solely for internal use. Without the written
11 | * permission of Esoteric Software (typically granted by licensing Spine), you
12 | * may not (a) modify, translate, adapt or otherwise create derivative works,
13 | * improvements of the Software or develop new applications using the Software
14 | * or (b) remove, delete, alter or obscure any trademarks or any copyright,
15 | * trademark, patent or other intellectual property or proprietary rights notices
16 | * on or in the Software, including any copy thereof. Redistributions in binary
17 | * or source form must include this license and terms.
18 | *
19 | * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR
20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
22 | * EVENT SHALL ESOTERIC SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
25 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
27 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
28 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 | *****************************************************************************/
30 |
31 | package com.esotericsoftware.spine.superspineboy;
32 |
33 | import static com.esotericsoftware.spine.superspineboy.Model.*;
34 | import static com.esotericsoftware.spine.superspineboy.Player.*;
35 |
36 | import com.esotericsoftware.spine.Animation;
37 | import com.esotericsoftware.spine.SkeletonRenderer;
38 | import com.esotericsoftware.spine.superspineboy.Model.State;
39 | import com.esotericsoftware.spine.utils.TwoColorPolygonBatch;
40 | import com.badlogic.gdx.Gdx;
41 | import com.badlogic.gdx.Input.Keys;
42 | import com.badlogic.gdx.InputAdapter;
43 | import com.badlogic.gdx.InputMultiplexer;
44 | import com.badlogic.gdx.graphics.Color;
45 | import com.badlogic.gdx.graphics.GL20;
46 | import com.badlogic.gdx.graphics.OrthographicCamera;
47 | import com.badlogic.gdx.graphics.g2d.SpriteBatch;
48 | import com.badlogic.gdx.graphics.g2d.TextureRegion;
49 | import com.badlogic.gdx.maps.tiled.renderers.OrthoCachedTiledMapRenderer;
50 | import com.badlogic.gdx.math.MathUtils;
51 | import com.badlogic.gdx.math.Vector2;
52 | import com.badlogic.gdx.utils.FloatArray;
53 | import com.badlogic.gdx.utils.ObjectFloatMap;
54 | import com.badlogic.gdx.utils.viewport.ExtendViewport;
55 |
56 | /** The core of the view logic. The view knows about the model and manages everything needed to draw to the screen. */
57 | class View extends InputAdapter {
58 | static float bulletHitTime = 0.2f, bulletHitOffset = 50 * scale;
59 |
60 | static float cameraMinWidth = 16, cameraMaxWidth = 28, cameraHeight = 16, cameraZoom = 0.4f, cameraZoomSpeed = 0.5f;
61 | static float cameraBottom = 2, cameraTop = 7, cameraMinX = 1;
62 | static float cameraLookahead = 0.75f, cameraLookaheadSpeed = 8f, cameraLookaheadSpeedSlow = 3f;
63 | static float cameraSpeed = 5f, cameraShake = 6 * scale;
64 |
65 | static int[] mapLayersOpaque1 = {1};
66 | static int[] mapLayersBackground2 = {2, 3, 4, 5, 6};
67 | static int[] mapLayersOpaque3 = {10};
68 | static int[] mapForegroundLayers4 = {7, 8,};
69 | static int[] mapForegroundLayers5 = {11};
70 |
71 | Model model;
72 | Player player;
73 | OrthographicCamera camera;
74 | ExtendViewport viewport;
75 | TwoColorPolygonBatch batch;
76 | SkeletonRenderer skeletonRenderer;
77 | OrthoCachedTiledMapRenderer mapRenderer;
78 | Assets assets;
79 | UI ui;
80 |
81 | float shakeX, shakeY, lookahead, zoom = 1;
82 | FloatArray hits = new FloatArray();
83 | boolean touched, jumpPressed, leftPressed, rightPressed;
84 |
85 | View (Model model) {
86 | this.model = model;
87 |
88 | mapRenderer = new OrthoCachedTiledMapRenderer(model.map, scale, 3000);
89 | mapRenderer.setOverCache(0.6f);
90 | mapRenderer.setMaxTileSize(512, 512);
91 |
92 | batch = new TwoColorPolygonBatch();
93 | camera = new OrthographicCamera();
94 | viewport = new ExtendViewport(cameraMinWidth, cameraHeight, cameraMaxWidth, cameraHeight, camera);
95 |
96 | skeletonRenderer = new SkeletonRenderer();
97 | skeletonRenderer.setPremultipliedAlpha(true);
98 |
99 | assets = new Assets();
100 |
101 | ui = new UI(this);
102 |
103 | Gdx.input.setInputProcessor(new InputMultiplexer(ui, ui.stage, this));
104 |
105 | restart();
106 | }
107 |
108 | void restart () {
109 | player = model.player;
110 | player.view = new PlayerView(this);
111 | lookahead = 0;
112 | touched = false;
113 | hits.clear();
114 | }
115 |
116 | void update (float delta) {
117 | // Update the hit marker images.
118 | for (int i = hits.size - 4; i >= 0; i -= 4) {
119 | float time = hits.get(i) - delta;
120 | if (time < 0)
121 | hits.removeRange(i, i + 3);
122 | else
123 | hits.set(i, time);
124 | }
125 |
126 | updateInput(delta);
127 | updateCamera(delta);
128 |
129 | player.view.update(delta);
130 |
131 | for (Enemy enemy : model.enemies) {
132 | if (enemy.view == null) enemy.view = new EnemyView(this, enemy);
133 | enemy.view.update(delta);
134 | }
135 | }
136 |
137 | void updateInput (float delta) {
138 | if (player.hp == 0) return;
139 |
140 | if (leftPressed)
141 | player.moveLeft(delta);
142 | else if (rightPressed)
143 | player.moveRight(delta);
144 | else if (player.state == State.run) //
145 | player.setState(State.idle);
146 |
147 | if (touched) player.view.shoot();
148 | }
149 |
150 | void updateCamera (float delta) {
151 | if (player.hp > 0) {
152 | // Reduce camera lookahead based on distance of enemies behind the player.
153 | float enemyBehindDistance = 0;
154 | for (Enemy enemy : model.enemies) {
155 | float dist = enemy.position.x - player.position.x;
156 | if (enemy.hp > 0 && Math.signum(dist) == -player.dir) {
157 | dist = Math.abs(dist);
158 | enemyBehindDistance = enemyBehindDistance == 0 ? dist : Math.min(enemyBehindDistance, dist);
159 | }
160 | }
161 | float lookaheadDist = cameraLookahead * viewport.getWorldWidth() / 2 * (1 - Math.min(1, enemyBehindDistance / 22));
162 | float lookaheadDiff = player.position.x + lookaheadDist * player.dir - camera.position.x;
163 | float lookaheadAdjust = (enemyBehindDistance > 0 ? cameraLookaheadSpeedSlow : cameraLookaheadSpeed) * delta;
164 | if (Math.abs(lookahead - lookaheadDiff) > 1) {
165 | if (lookahead < lookaheadDiff)
166 | lookahead = Math.min(lookaheadDist, lookahead + lookaheadAdjust);
167 | else if (lookahead > lookaheadDiff) //
168 | lookahead = Math.max(-lookaheadDist, lookahead - lookaheadAdjust);
169 | }
170 | if (player.position.x + lookahead < cameraMinX) lookahead = cameraLookahead;
171 | }
172 |
173 | // Move camera to the player position over time, adjusting for lookahead.
174 | float minX = player.position.x + lookahead, maxX = player.position.x + lookahead;
175 | if (camera.position.x < minX) {
176 | camera.position.x += (minX - camera.position.x) * cameraSpeed * delta;
177 | if (camera.position.x > minX) camera.position.x = minX;
178 | if (Math.abs(camera.position.x - minX) < 0.1f) camera.position.x = minX;
179 | } else if (camera.position.x > maxX) {
180 | camera.position.x += (maxX - camera.position.x) * cameraSpeed * delta;
181 | if (camera.position.x < maxX) camera.position.x = maxX;
182 | if (Math.abs(camera.position.x - maxX) < 0.1f) camera.position.x = maxX;
183 | }
184 | camera.position.x = Math.max(viewport.getWorldWidth() / 2 + cameraMinX, camera.position.x);
185 |
186 | float top = zoom != 1 ? 5 : cameraTop;
187 | float bottom = zoom != 1 ? 0 : cameraBottom;
188 | float maxY = player.position.y + viewport.getWorldHeight() / 2 - bottom;
189 | float minY = player.position.y - viewport.getWorldHeight() / 2 + top;
190 | if (camera.position.y < minY) {
191 | camera.position.y += (minY - camera.position.y) * cameraSpeed / zoom * delta;
192 | if (Math.abs(camera.position.y - minY) < 0.1f) camera.position.y = minY;
193 | } else if (camera.position.y > maxY) {
194 | camera.position.y += (maxY - camera.position.y) * cameraSpeed / zoom * delta;
195 | if (Math.abs(camera.position.y - maxY) < 0.1f) camera.position.y = maxY;
196 | }
197 |
198 | camera.update();
199 | batch.setProjectionMatrix(camera.combined);
200 | mapRenderer.setView(camera);
201 |
202 | camera.position.add(-shakeX, -shakeY, 0);
203 | shakeX = 0;
204 | shakeY = 0;
205 | }
206 |
207 | void render () {
208 | viewport.apply();
209 |
210 | Gdx.gl.glClearColor(0, 0, 0, 1);
211 | Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
212 |
213 | if (ui.bgButton.isChecked()) {
214 | mapRenderer.setBlending(false);
215 | mapRenderer.render(mapLayersOpaque1);
216 |
217 | mapRenderer.setBlending(true);
218 | mapRenderer.render(mapLayersBackground2);
219 | }
220 |
221 | batch.begin();
222 | // Draw enemies.
223 | for (Enemy enemy : model.enemies) {
224 | enemy.view.skeleton.getColor().a = Math.min(1, enemy.deathTimer / Enemy.fadeTime);
225 | skeletonRenderer.draw(batch, enemy.view.skeleton);
226 | }
227 | // Draw player.
228 | if (player.collisionTimer < 0 || (int)(player.collisionTimer / flashTime * 1.5f) % 2 != 0)
229 | skeletonRenderer.draw(batch, player.view.skeleton);
230 | batch.end();
231 |
232 | if (ui.bgButton.isChecked()) {
233 | mapRenderer.setBlending(false);
234 | mapRenderer.render(mapLayersOpaque3);
235 |
236 | mapRenderer.setBlending(true);
237 | mapRenderer.render(mapForegroundLayers4);
238 | }
239 |
240 | batch.setBlendFunction(GL20.GL_SRC_ALPHA, GL20.GL_ONE);
241 | batch.begin();
242 |
243 | // Draw bullets.
244 | TextureRegion bulletRegion = assets.bulletRegion;
245 | float bulletWidth = bulletRegion.getRegionWidth() * scale;
246 | float bulletHeight = bulletRegion.getRegionHeight() * scale / 2;
247 | for (int i = 2, n = model.bullets.size; i < n; i += 5) {
248 | float x = model.bullets.get(i), y = model.bullets.get(i + 1);
249 | float angle = model.bullets.get(i + 2);
250 | float vx = MathUtils.cosDeg(angle);
251 | float vy = MathUtils.sinDeg(angle);
252 | // Adjust position so bullet region is drawn with the bullet position in the center of the fireball.
253 | x -= vx * bulletWidth * 0.65f;
254 | y -= vy * bulletWidth * 0.65f;
255 | x += vy * bulletHeight / 2;
256 | y += -vx * bulletHeight / 2;
257 | batch.draw(bulletRegion, x, y, 0, 0, bulletWidth, bulletHeight, 1, 1, angle);
258 | }
259 |
260 | // Draw hit markers.
261 | TextureRegion hitRegion = assets.hitRegion;
262 | Color color = batch.getColor().set(1, 1, 1, 1);
263 | float hitWidth = hitRegion.getRegionWidth() * scale;
264 | float hitHeight = hitRegion.getRegionWidth() * scale;
265 | for (int i = hits.size - 4; i >= 0; i -= 4) {
266 | float time = hits.get(i);
267 | float x = hits.get(i + 1);
268 | float y = hits.get(i + 2);
269 | float angle = hits.get(i + 3);
270 | color.a = time / bulletHitTime;
271 | batch.setColor(color);
272 | float vx = MathUtils.cosDeg(angle);
273 | float vy = MathUtils.sinDeg(angle);
274 | // Adjust position so bullet region is drawn with the bullet position in the center of the fireball.
275 | x += vy * bulletHeight * 0.2f;
276 | y += -vx * bulletHeight * 0.2f;
277 | batch.draw(hitRegion, x - hitWidth / 2, y, hitWidth / 2, 0, hitWidth, hitHeight, 1, 1, angle);
278 | }
279 | batch.setColor(Color.WHITE);
280 |
281 | batch.end();
282 | batch.setBlendFunction(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA);
283 |
284 | if (ui.bgButton.isChecked()) mapRenderer.render(mapForegroundLayers5);
285 |
286 | ui.render();
287 | }
288 |
289 | void resize (int width, int height) {
290 | viewport.update(width, height);
291 | camera.position.x = player.position.x;
292 | camera.position.y = player.position.y + viewport.getWorldHeight() / 2 - cameraBottom;
293 | mapRenderer.setView(camera);
294 | ui.resize(width, height);
295 | }
296 |
297 | public boolean touchDown (int screenX, int screenY, int pointer, int button) {
298 | touched = true;
299 | player.view.shoot();
300 | return true;
301 | }
302 |
303 | public boolean touchUp (int screenX, int screenY, int pointer, int button) {
304 | touched = false;
305 | return true;
306 | }
307 |
308 | public boolean keyDown (int keycode) {
309 | switch (keycode) {
310 | case Keys.W:
311 | case Keys.UP:
312 | case Keys.SPACE:
313 | if (player.hp == 0) return false;
314 | jumpPressed = true;
315 | if (player.isGrounded()) player.view.jump();
316 | return true;
317 | case Keys.A:
318 | case Keys.LEFT:
319 | leftPressed = true;
320 | return true;
321 | case Keys.D:
322 | case Keys.RIGHT:
323 | rightPressed = true;
324 | return true;
325 | }
326 | return false;
327 | }
328 |
329 | public boolean keyUp (int keycode) {
330 | switch (keycode) {
331 | case Keys.W:
332 | case Keys.UP:
333 | case Keys.SPACE:
334 | if (player.hp == 0) return false;
335 | // Releasing jump on the way up reduces jump height.
336 | if (player.velocity.y > 0) player.velocity.y *= jumpDamping;
337 | jumpPressed = false;
338 | return true;
339 | case Keys.A:
340 | case Keys.LEFT:
341 | leftPressed = false;
342 | return true;
343 | case Keys.D:
344 | case Keys.RIGHT:
345 | rightPressed = false;
346 | return true;
347 | }
348 | return false;
349 | }
350 |
351 | /** Stores information needed by the view for a character state. */
352 | static class StateView {
353 | Animation animation;
354 | boolean loop;
355 | // Controls the start frame when changing from another animation to this animation.
356 | ObjectFloatMap startTimes = new ObjectFloatMap();
357 | float defaultStartTime;
358 | }
359 | }
360 |
--------------------------------------------------------------------------------
/update-dependencies.cmd:
--------------------------------------------------------------------------------
1 | @echo off
2 | mvn eclipse:eclipse
3 |
--------------------------------------------------------------------------------
/update-dependencies.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | mvn eclipse:eclipse
3 |
--------------------------------------------------------------------------------