107 Commits

Author SHA1 Message Date
8b9be1e2f4 Merge branch 'develop' 2014-07-16 09:36:15 -04:30
1b2ea706d3 Fixed a buy with OUYA controls. 2014-07-16 09:31:57 -04:30
1f03b2439b Merge branch 'develop' 2014-07-01 10:16:23 -04:30
15c41d1229 Changed the Bomb Game automatic action behaviour. 2014-07-01 10:13:15 -04:30
238f62d4d3 Added robot arm movement ray rendering. 2014-06-30 12:42:43 -04:30
b2cac2f40d Merge branch 'develop' 2014-06-26 18:35:00 -04:30
53ae001e59 Assorted fixes for OUYA. 2014-06-26 18:25:28 -04:30
a9285a684f Fixed a bug with the orientation calculation. 2014-06-26 13:01:39 -04:30
81d8a81b7e Added instructions screen support. 2014-06-26 12:51:01 -04:30
5a8391aa28 Updated the README file. 2014-06-26 11:53:55 -04:30
94c2bd6850 Finished implementing bomb game. 2014-06-26 09:44:33 -04:30
3288e3cb6b Added some TODO's. 2014-06-25 16:43:01 -04:30
83e327545c Added enabling/disabling the collision detection system. 2014-06-25 16:28:27 -04:30
77aec83dbb Bomb game automatic action and summary ready. 2014-06-25 16:09:59 -04:30
4d006a3461 Added automatic actions. Not tested yet. 2014-06-23 16:07:06 -04:30
6e30e6b56b Added the player entity and it's logic to the world. 2014-06-20 12:03:17 -04:30
99236420d1 Fixed device orientation calculation. Other assorted fixes. 2014-06-20 11:32:02 -04:30
6a392856ee Fixes for OUYA. Added labels. Started modelling player. 2014-06-19 18:29:06 -04:30
83199df36d Cleaned the code a bit. 2014-06-18 18:27:30 -04:30
a247d24770 Debug overlay always rendered regardless of debug status. 2014-06-18 12:04:18 -04:30
8bd799f146 All bombs sucessfully implemented. 2014-06-17 17:57:57 -04:30
29c4bea104 Added processing for the remaining bombs. 2014-06-16 16:57:47 -04:30
fd197211b5 Touch controls ready. 2014-06-16 15:47:07 -04:30
7f20a09eb9 Scrapped robot arm movement. 2014-06-13 16:47:23 -04:30
6c63ebf907 Finally fixed restart problem. Basic inclination bombs. 2014-06-11 17:28:26 -04:30
95bb97536c Started modelling object interaction. 2014-06-11 15:21:59 -04:30
3f522da485 Collision detection works for real now. 2014-06-11 14:28:43 -04:30
36eea36c15 Added freeInstance to network. Modelling game logic. 2014-06-11 11:18:12 -04:30
8abf594c8a Added collision detection. 2014-06-10 16:59:21 -04:30
aa5871b49a Started modelling user input. 2014-06-06 19:10:11 -04:30
d4edcf4909 Fixed interface details. Removed pause state. 2014-06-06 12:43:45 -04:30
4cba697f57 Bomb game assets loaded with asset manager. Camera calibration is automagic. 2014-06-06 11:41:58 -04:30
be5ae2955e Added code to debug the collision models. 2014-06-05 18:46:39 -04:30
2b14a080b4 All bomb types successfully loaded and rendered. 2014-06-05 18:15:17 -04:30
fbb03f884e Simplified some functions. 2014-06-04 16:53:35 -04:30
a798cce715 Added rendering of the inclination bomb. 2014-06-04 16:29:31 -04:30
6ecb373b11 Added visibility testing for marker objects. 2014-06-03 18:49:52 -04:30
e65da3234b Added some model loading and removed an useless file. 2014-06-03 16:22:15 -04:30
a614841664 Added more systems and components. 2014-06-02 16:46:06 -04:30
eb8206668f Removed needless source files. Added game settings. 2014-05-28 14:22:46 -04:30
fa6950d5c9 Merge branch 'develop' 2014-05-27 14:42:38 -04:30
5e66273396 Added animation support. 2014-05-27 14:41:06 -04:30
686f263b0d Added support for gpu skinning. Added animation system. 2014-05-27 13:45:58 -04:30
5ef7928706 Refactored rendering to use modelbatch everywhere. 2014-05-26 16:42:57 -04:30
169d0e7c43 Started using custom shaders with model batch. 2014-05-23 17:00:14 -04:30
9a67df8f8a Removed old code. 2014-05-22 18:03:48 -04:30
76a6d8485b Removed libs. 2014-05-22 17:42:35 -04:30
653adc91a7 Updated libgdx to 1.0.1 2014-05-22 17:41:58 -04:30
a1891f53d2 Changed model rendering to model batch. 2014-05-22 16:50:24 -04:30
a942b0ebd1 Changed references to GL10. 2014-05-21 16:18:49 -04:30
e6085e7a79 Testing model loading. 2014-05-20 20:15:34 -04:30
3c65f52e9e Added some more test cases. Fixed a bug when rendering markers. 2014-05-15 16:58:23 -04:30
0df8b37ddd Merge branch 'develop' 2014-05-15 12:10:47 -04:30
87295031dc Rendering of objects on top of markers is complete. 2014-05-15 12:10:14 -04:30
a9fa76cb68 Markers rendered almost sucessfully. 2014-05-14 16:56:31 -04:30
fbb25ead08 Added marker positioning and rendering. Not tested yet. 2014-05-13 18:29:25 -04:30
82e95ed0f7 Added aditional geometric transformation info to rendering. Added entity creator. 2014-05-12 14:30:24 -04:30
b7367427f6 Successfully incorporated Artemis. 2014-05-12 11:37:58 -04:30
e6ea6ab4a1 Added comments. 2014-05-09 17:00:21 -04:30
167b5d644b Some refactorings and touch ups. 2014-05-09 11:30:45 -04:30
e82d49f1f1 Testing the shader. 2014-05-09 10:46:47 -04:30
6b54b1364f Fixed test rendering problems. 2014-05-08 16:21:30 -04:30
de64cd972b Successfully rendered a 3D sphere. 2014-05-07 16:41:25 -04:30
90427419e0 Frame buffer object correctly created and positioned. 2014-05-06 16:35:19 -04:30
271b7d003a Started sketching the 3D rendering. 2014-05-05 15:25:01 -04:30
1146a260b6 Added intradocumentation. 2014-05-05 12:32:06 -04:30
d8922182e0 Camera calibration successfully ported. 2014-05-02 13:59:15 -04:30
e976a17de0 Added menu transition to calibration state. 2014-05-02 11:16:40 -04:30
11ebf2b96e Continued implementation of the calibration state and interface. 2014-04-30 16:21:03 -04:30
139bb62067 Started programming the calibration state. 2014-04-28 10:14:01 -04:30
e93d227b62 Updated the interfaces and renamed some methods. 2014-04-10 17:57:31 -04:30
06d74a6474 Added some logging. 2014-04-05 15:05:20 -04:30
d481df0f96 Merge branch 'develop' 2014-04-04 10:27:33 -04:30
1e2de5ee55 Added recenter button and corresponding event handling. 2014-04-04 10:26:56 -04:30
a37ff0fba5 Added a sensor data receiving thread. 2014-04-03 11:28:30 -04:30
ebb943925f Renamed the project. 2014-03-31 11:02:20 -04:30
ae93dca1b9 Merge branch 'develop' 2014-03-14 15:16:50 -04:30
ddbadba3ea Added OUYA gamepad support. 2014-03-14 15:16:21 -04:30
28be9c8a81 Flipped motor buttons on tablet iface. Added NO_DELAY to robot control. 2014-03-13 16:12:53 -04:30
8ed8be0a29 OpenCV marker detection successfully ported. 2014-03-12 16:35:52 -04:30
c7ee0e0af6 Added CVProcessor interface. 2014-03-11 18:32:46 -04:30
0fdef7c01c Merge branch 'develop' 2014-02-11 17:46:28 -04:30
6690d7b3fc Merge branch 'robot_control' into develop 2014-02-11 17:45:37 -04:30
97b27f736a Fixed robot control logic. Added gamepad support (not tested). 2014-02-11 17:44:54 -04:30
5816e77e36 RobotControlThread sends data. 2014-02-10 15:27:27 -04:30
5d80d5f866 Added state transitions with Universal Tween Library. 2014-02-07 17:02:53 -04:30
be1a392c4a Basic main menu finished. 2014-02-07 14:10:10 -04:30
39426cd2a6 Fixed OuyaMainMenuState. 2014-02-06 22:34:37 -04:30
e88305f0ff Refactoring finished. 2014-02-06 18:56:20 -04:30
40d390baec Started refactoring the app to use State Pattern. 2014-02-05 17:06:29 -04:30
5bd79f0d58 Deleted useless Artemis classes. 2014-02-05 15:10:02 -04:30
4893313116 Merge branch 'robot_control' into develop 2014-02-05 15:07:38 -04:30
unknown
c5fe36116f Minor refactorings. 2014-02-04 17:14:35 -04:30
5c795ce8e3 Got this thing to render on Ouya. 2014-01-29 03:30:40 -04:30
e5b43beaea VideoStreamingThread now reports the number of lost frames per second. 2014-01-28 19:14:35 -04:30
bfea25e95e Added gui buttons. Removed tcp connection for video code. 2014-01-24 12:25:58 -04:30
0b790bce8f Removed the TCP video streaming code. 2014-01-21 12:20:38 -04:30
b937b93767 Minor cosmetic touches. 2014-01-20 13:00:29 -04:30
da044c5b1c Changed the streaming to use UDP. 2014-01-15 14:50:54 -04:30
c6f310884a Testing video streaming framerate. 2014-01-13 14:33:35 -04:30
481fe1f428 Merge branch 'release-14.01.10' 2014-01-09 08:24:50 -04:30
1dc0f5b47f Merge branch 'image_transfer' into develop 2014-01-08 15:30:14 -04:30
689721d75b Fixed some problems receiving the image from NxtCAM. 2014-01-08 15:29:54 -04:30
4a509b0920 Added LICENSE file. 2014-01-07 18:14:20 -04:30
0e51d0ea22 Started fixing the video streaming code. 2014-01-07 18:13:55 -04:30
3fc5ce58c3 Started programming app states. Incorporated Artemis. 2013-12-16 16:02:29 -04:30
c6de50df7f Added licensing information. 2013-12-16 14:47:00 -04:30
82 changed files with 10357 additions and 166 deletions

1
.gitignore vendored
View File

@@ -18,6 +18,7 @@ local.properties
# Eclipse project files
.classpath
.project
libs/
# Proguard folder generated by Eclipse
proguard/

202
LICENSE Normal file
View File

@@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

27
README.md Normal file
View File

@@ -0,0 +1,27 @@
NxtAR: A generic software architecture for Augmented Reality based mobile robot control.
========================================================================================
Core module
-----------
### Abstract ###
NxtAR is a generic software architecture for the development of Augmented Reality games
and applications centered around mobile robot control. This is a reference implementation
with support for [LEGO Mindstorms NXT][1] mobile robots.
### Module description ###
The core module comprises all the operating system independent classes that implemente the
base architecture and the different scenarios for the application. This implementation is
designed and built around the [LibGDX][2] and the [Artemis Entity-System Framework][3] libraries.
Currently there is one scenario titled *Bomb Game*.
### Module installation and usage. ###
The core module cannot be used directly. It is intended to be compiled with a LibGDX backend module.
[1]: http://www.lego.com/en-us/mindstorms/?domainredir=mindstorms.lego.com
[2]: http://libgdx.badlogicgames.com/
[3]: http://gamadu.com/artemis/

Binary file not shown.

Binary file not shown.

View File

@@ -1,5 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE module PUBLIC "-//Google Inc.//DTD Google Web Toolkit trunk//EN" "http://google-web-toolkit.googlecode.com/svn/trunk/distro-source/core/src/gwt-module.dtd">
<module>
<source path="ve/ucv/ciens/ccg/nxtar" />
<?xml version="1.0" encoding="UTF-8"?>
<!--
* Copyright (C) 2013 Miguel Angel Astor Romero
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
-->
<!DOCTYPE module PUBLIC "-//Google Inc.//DTD Google Web Toolkit trunk//EN" "http://google-web-toolkit.googlecode.com/svn/trunk/distro-source/core/src/gwt-module.dtd">
<module>
<source path="ve/ucv/ciens/ccg/nxtar" />
</module>

View File

@@ -0,0 +1,37 @@
package ve.ucv.ciens.ccg.networkdata;
import java.io.Serializable;
public class MotorEvent implements Serializable{
private static final long serialVersionUID = 9989L;
public enum motor_t {NONE, MOTOR_A, MOTOR_B, MOTOR_C, MOTOR_AC, RECENTER, ROTATE_90};
private motor_t motor;
private byte power;
public MotorEvent(){
motor = motor_t.NONE;
power = 0;
}
public void setMotor(motor_t motor){
this.motor = motor;
}
public void setPower(byte power) throws IllegalArgumentException{
if(power > 100 || power < -100){
throw new IllegalArgumentException("Motor power must be a number between -100 and 100");
}else{
this.power = power;
}
}
public motor_t getMotor(){
return this.motor;
}
public byte getPower(){
return this.power;
}
}

View File

@@ -0,0 +1,32 @@
/*
* Copyright (C) 2014 Miguel Angel Astor Romero
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ve.ucv.ciens.ccg.networkdata;
import java.io.Serializable;
public class MotorEventACK implements Serializable {
private static final long serialVersionUID = 9989L;
private boolean clientQueueIsFull;
public MotorEventACK(boolean isQueueFull){
this.clientQueueIsFull = isQueueFull;
}
public boolean isClientQueueFull(){
return this.clientQueueIsFull;
}
}

View File

@@ -0,0 +1,33 @@
/*
* Copyright (C) 2013 Miguel Angel Astor Romero
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ve.ucv.ciens.ccg.networkdata;
import java.io.Serializable;
public final class VideoFrameDataMessage implements Serializable{
private static final long serialVersionUID = 9989L;
public static final int magicNumber = 0x10;
public int imageWidth;
public int imageHeight;
public byte[] data;
public VideoFrameDataMessage(){
imageWidth = -1;
imageHeight = -1;
data = null;
}
}

View File

@@ -0,0 +1,29 @@
/*
* Copyright (C) 2013 Miguel Angel Astor Romero
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ve.ucv.ciens.ccg.networkdata;
import java.io.Serializable;
public final class VideoStreamingControlMessage implements Serializable{
private static final long serialVersionUID = 8898L;
public static final int magicNumber = 0x20;
public byte message;
public VideoStreamingControlMessage(){
message = -1;
}
}

View File

@@ -1,120 +1,542 @@
/*
* Copyright (C) 2013 Miguel Angel Astor Romero
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ve.ucv.ciens.ccg.nxtar;
import ve.ucv.ciens.ccg.nxtar.interfaces.MulticastEnabler;
import ve.ucv.ciens.ccg.nxtar.interfaces.NetworkConnectionListener;
import ve.ucv.ciens.ccg.nxtar.interfaces.Toaster;
import ve.ucv.ciens.ccg.nxtar.interfaces.ActionResolver;
import ve.ucv.ciens.ccg.nxtar.interfaces.ApplicationEventsListener;
import ve.ucv.ciens.ccg.nxtar.interfaces.ImageProcessor;
import ve.ucv.ciens.ccg.nxtar.network.RobotControlThread;
import ve.ucv.ciens.ccg.nxtar.network.SensorReportThread;
import ve.ucv.ciens.ccg.nxtar.network.ServiceDiscoveryThread;
import ve.ucv.ciens.ccg.nxtar.network.VideoStreamingThread;
import ve.ucv.ciens.ccg.nxtar.scenarios.ScenarioGlobals;
import ve.ucv.ciens.ccg.nxtar.states.AutomaticActionState;
import ve.ucv.ciens.ccg.nxtar.states.AutomaticActionSummaryState;
import ve.ucv.ciens.ccg.nxtar.states.BaseState;
import ve.ucv.ciens.ccg.nxtar.states.CameraCalibrationState;
import ve.ucv.ciens.ccg.nxtar.states.InGameState;
import ve.ucv.ciens.ccg.nxtar.states.InstructionsState;
import ve.ucv.ciens.ccg.nxtar.states.MainMenuStateBase;
import ve.ucv.ciens.ccg.nxtar.states.OuyaMainMenuState;
import ve.ucv.ciens.ccg.nxtar.states.ScenarioEndSummaryState;
import ve.ucv.ciens.ccg.nxtar.states.TabletMainMenuState;
import ve.ucv.ciens.ccg.nxtar.utils.ProjectConstants;
import ve.ucv.ciens.ccg.nxtar.utils.Utils;
import aurelienribon.tweenengine.Tween;
import aurelienribon.tweenengine.TweenEquations;
import aurelienribon.tweenengine.primitives.MutableFloat;
import com.badlogic.gdx.Application;
import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.Game;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL10;
import com.badlogic.gdx.controllers.Controllers;
import com.badlogic.gdx.controllers.mappings.Ouya;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Pixmap;
import com.badlogic.gdx.graphics.Pixmap.Format;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.Texture.TextureFilter;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.graphics.glutils.ShaderProgram;
public class NxtARCore implements ApplicationListener, NetworkConnectionListener {
/**
* <p>Core of the application.</p>
*
* <p>This class has three basic responsibilities:</p>
* <ul>
* <li> Handling the main game loop.</li>
* <li> Starting and destroying the networking threads.</li>
* <li> Rendering debug information.</li>
* </ul>
*/
public class NxtARCore extends Game implements ApplicationEventsListener{
/**
* Tag used for logging.
*/
private static final String TAG = "NXTAR_CORE_MAIN";
/**
* Class name used for logging.
*/
private static final String CLASS_NAME = NxtARCore.class.getSimpleName();
private OrthographicCamera camera;
private SpriteBatch batch;
private Texture texture;
private Sprite sprite;
private Toaster toaster;
private MulticastEnabler mcastEnabler;
/**
* Valid game states.
*/
public enum game_states_t {
MAIN_MENU(0), IN_GAME(1), CALIBRATION(2), AUTOMATIC_ACTION(3), AUTOMATIC_ACTION_SUMMARY(4), SCENARIO_END_SUMMARY(5), HINTS(6);
private int value;
private game_states_t(int value){
this.value = value;
}
public int getValue(){
return this.value;
}
public static int getNumStates(){
return 7;
}
};
/**
* The current application state.
*/
private game_states_t currState;
/**
* <p>The state to change to.</p>
* <p> Usually null. A state change is scheduled by setting this field to a {@link game_states_t} value.</p>
*/
public game_states_t nextState;
// Screens.
/**
* <p>The application states.</p>
*/
private BaseState[] states;
// Assorted fields.
/**
* <p>Global sprite batch used for rendering trough the application.</p>
*/
public SpriteBatch batch;
/**
* <p>The OpenCV wrapper.</p>
*/
public ImageProcessor cvProc;
/**
* <p>Wrapper around the Operating System methods.</p>
*/
private ActionResolver actionResolver;
// Networking related fields.
/**
* <p>The number of connections successfully established with the NxtAR-cam application.</p>
*/
private int connections;
private ServiceDiscoveryThread udpThread;
/**
* <p>Worker thread used to broadcast this server over the network.</p>
*/
private ServiceDiscoveryThread serviceDiscoveryThread;
/**
* <p>Worker thread used to receive video frames over UDP.<p>
*/
private VideoStreamingThread videoThread;
/**
* <p>Worker thread used to send control commands to the NxtAR-cam application.
*/
private RobotControlThread robotThread;
/**
* <p>Worker thread used to receive sensor data from the NxtAR-cam application.</p>
*/
private SensorReportThread sensorThread;
// Overlays.
/**
* <p>Camera used to render the debugging overlay.</p>
*/
private OrthographicCamera pixelPerfectCamera;
/**
* <p>The base x coordinate for rendering the debugging overlay.</p>
*/
private float overlayX;
/**
* <p>The base y coordinate for rendering the debugging overlay.</p>
*/
private float overlayY;
/**
* <p>The font used to render the debugging overlay.</p>
*/
private BitmapFont font;
// Fade in/out effect fields.
/**
* <p>The graphic used to render the fading effect.</p>
*/
private Texture fadeTexture;
/**
* <p>The interpolation value for the fading effect.</p>
*/
private MutableFloat alpha;
/**
* <p>The fade out interpolator.</p>
*/
private Tween fadeOut;
/**
* <p>The fade in interpolator.</p>
*/
private Tween fadeIn;
/**
* <p>Flag used to indicate if a fading effect is active.</p>
*/
private boolean fading;
/**
* <p>Set up the basic application fields.</p>
*/
public NxtARCore(Application concreteApp){
super();
connections = 0;
// Check if the concrete application implements all required interfaces.
try{
this.toaster = (Toaster)concreteApp;
this.mcastEnabler = (MulticastEnabler)concreteApp;
this.actionResolver = (ActionResolver)concreteApp;
}catch(ClassCastException cc){
Gdx.app.debug(TAG, CLASS_NAME + ".Main() :: concreteApp does not implement any of the required interfaces.");
System.exit(ProjectConstants.EXIT_FAILURE);
Gdx.app.debug(TAG, CLASS_NAME + ".Main() :: concreteApp does not implement the Toaster interface. Toasting disabled.");
this.actionResolver = null;
}
try{
this.cvProc = (ImageProcessor)concreteApp;
}catch(ClassCastException cc){
Gdx.app.error(TAG, CLASS_NAME + ".Main() :: concreteApp does not implement the CVProcessor interface. Quitting.");
Gdx.app.exit();
}
}
/*;;;;;;;;;;;;;;;;;;;;;;;;;;;
; GAME SUPERCLASS METHODS ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;*/
/**
* <p>Initialize the member fields and launch the networking threads. Also creates and
* sets the application states.</p>
*/
public void create(){
try {
ScenarioGlobals.init(this);
} catch (IllegalArgumentException e) {
Gdx.app.error(TAG, CLASS_NAME + ".create(): Illegal argument initializing globals: ", e);
System.exit(1);
return;
} catch (InstantiationException e) {
Gdx.app.error(TAG, CLASS_NAME + ".create(): Instantiation exception initializing globals: ", e);
System.exit(1);
return;
} catch (IllegalAccessException e) {
Gdx.app.error(TAG, CLASS_NAME + ".create(): Illegal access exception initializing globals: ", e);
System.exit(1);
return;
}
// Set up rendering fields and settings.
batch = new SpriteBatch();
batch.enableBlending();
batch.setBlendFunction(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA);
pixelPerfectCamera = new OrthographicCamera(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
ShaderProgram.pedantic = false;
// Create the state objects.
states = new BaseState[game_states_t.getNumStates()];
try{
if(Ouya.runningOnOuya)
states[game_states_t.MAIN_MENU.getValue()] = new OuyaMainMenuState(this);
else
states[game_states_t.MAIN_MENU.getValue()] = new TabletMainMenuState(this);
try{
states[game_states_t.IN_GAME.getValue()] = new InGameState(this);
}catch(IllegalStateException e){
Gdx.app.error(TAG, CLASS_NAME + ".create(): Illegal state in IN_GAME_STATE: ", e);
System.exit(1);
return;
}
states[game_states_t.CALIBRATION.getValue()] = new CameraCalibrationState(this);
try{
states[game_states_t.AUTOMATIC_ACTION.getValue()] = new AutomaticActionState(this);
}catch(IllegalStateException e){
Gdx.app.error(TAG, CLASS_NAME + ".create(): Illegal state in AUTOMATIC_ACTION_STATE: ", e);
System.exit(1);
return;
}
states[game_states_t.AUTOMATIC_ACTION_SUMMARY.getValue()] = new AutomaticActionSummaryState(this);
states[game_states_t.SCENARIO_END_SUMMARY.getValue()] = new ScenarioEndSummaryState(this);
states[game_states_t.HINTS.getValue()] = new InstructionsState(this);
}catch(IllegalArgumentException e){
Gdx.app.error(TAG, CLASS_NAME + ".create(): Illegal argument caught creating states: ", e);
System.exit(1);
return;
}
// Register controller listeners.
for(BaseState state : states){
Controllers.addListener(state);
}
// Set up the overlay font.
overlayX = -(Utils.getScreenWidthWithOverscan() / 2) + 10;
overlayY = (Utils.getScreenHeightWithOverscan() / 2) - 10;
font = new BitmapFont();
font.setColor(1.0f, 1.0f, 0.0f, 1.0f);
if(!Ouya.runningOnOuya){
font.setScale(1.0f);
}else{
font.setScale(2.5f);
}
// Start networking.
actionResolver.enableMulticast();
Gdx.app.debug(TAG, CLASS_NAME + ".create() :: Creating network threads");
serviceDiscoveryThread = ServiceDiscoveryThread.getInstance();
videoThread = VideoStreamingThread.getInstance();
robotThread = RobotControlThread.getInstance();
sensorThread = SensorReportThread.getInstance();
// Launch networking threads.
serviceDiscoveryThread.start();
videoThread.start();
videoThread.startStreaming();
videoThread.addNetworkConnectionListener(this);
robotThread.addNetworkConnectionListener(this);
robotThread.start();
sensorThread.addNetworkConnectionListener(this);
sensorThread.start();
// Set the current and next states.
currState = game_states_t.MAIN_MENU;
nextState = null;
this.setScreen(states[currState.getValue()]);
states[currState.getValue()].onStateSet();
// Prepare the fading effect.
Pixmap pixmap = new Pixmap(Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), Format.RGBA4444);
pixmap.setColor(0, 0, 0, 1);
pixmap.fill();
fadeTexture = new Texture(pixmap);
pixmap.dispose();
alpha = new MutableFloat(0.0f);
fadeOut = Tween.to(alpha, 0, 0.5f).target(1.0f).ease(TweenEquations.easeInQuint);
fadeIn = Tween.to(alpha, 0, 0.5f).target(0.0f).ease(TweenEquations.easeInQuint);
fading = false;
// Set initial input handlers.
Gdx.input.setInputProcessor(states[currState.getValue()]);
Controllers.addListener(states[currState.getValue()]);
// Set log level
if(ProjectConstants.DEBUG){
Gdx.app.setLogLevel(Application.LOG_DEBUG);
}else{
Gdx.app.setLogLevel(Application.LOG_NONE);
}
}
/**
* <p>Update and render the currently enabled application state. This method
* also handles state switching, rendering state transitions and global overlays.</p>
*/
public void render(){
super.render();
// Load the assets.
if(!ScenarioGlobals.getEntityCreator().areEntitiesCreated())
ScenarioGlobals.getEntityCreator().updateAssetManager();
// If the current state set a value for nextState then switch to that state.
if(nextState != null){
states[currState.getValue()].onStateUnset();
if(!fadeOut.isStarted()){
// Start the fade out effect.
fadeOut.start();
fading = true;
}else{
// Update the fade out effect.
fadeOut.update(Gdx.graphics.getDeltaTime());
// When the fade out effect finishes, change to the requested state
// and launh the fade in effect.
if(fadeOut.isFinished()){
// Change to the requested state.
currState = nextState;
nextState = null;
states[currState.getValue()].onStateSet();
setScreen(states[currState.getValue()]);
// Reset the fade out effect and launch the fade in.
Gdx.app.log(TAG, CLASS_NAME + ".onRender() :: Freeing fade out.");
fadeOut.free();
fadeOut = Tween.to(alpha, 0, 0.5f).target(1.0f).ease(TweenEquations.easeInQuint);
fadeIn.start();
}
}
}
// If there is a fade in effect in progress.
if(fadeIn.isStarted()){
if(!fadeIn.isFinished()){
// Update it until finished.
fadeIn.update(Gdx.graphics.getDeltaTime());
}else{
// Stop and reset it when done.
fading = false;
fadeIn.free();
fadeIn = Tween.to(alpha, 0, 0.5f).target(0.0f).ease(TweenEquations.easeInQuint);
}
}
// Render the fading sprite with alpha blending.
if(fading){
batch.setProjectionMatrix(pixelPerfectCamera.combined);
batch.begin();{
batch.setColor(1, 1, 1, alpha.floatValue());
batch.draw(fadeTexture, -(Gdx.graphics.getWidth() / 2), -(Gdx.graphics.getHeight() / 2));
batch.setColor(1, 1, 1, 1);
}batch.end();
}
// Render the debug overlay.
if(ProjectConstants.DEBUG){
batch.setProjectionMatrix(pixelPerfectCamera.combined);
batch.begin();{
// Draw the FPS overlay.
font.draw(batch, String.format("Render FPS: %d", Gdx.graphics.getFramesPerSecond()), overlayX, overlayY);
font.draw(batch, String.format("Total stream FPS: %d", videoThread.getFps()), overlayX, overlayY - font.getCapHeight() - 5);
font.draw(batch, String.format("Lost stream FPS: %d", videoThread.getLostFrames()), overlayX, overlayY - (2 * font.getCapHeight()) - 10);
font.draw(batch, String.format("Light sensor data: %d", sensorThread.getLightSensorReading()), overlayX, overlayY - (3 * font.getCapHeight()) - 15);
font.draw(batch, String.format("Device roll: %f", Gdx.input.getRoll()), overlayX, overlayY - (4 * font.getCapHeight()) - 20);
font.draw(batch, String.format("Device pitch: %f", Gdx.input.getPitch()), overlayX, overlayY - (5 * font.getCapHeight()) - 25);
font.draw(batch, String.format("Device azimuth: %f", Gdx.input.getAzimuth()), overlayX, overlayY - (6 * font.getCapHeight()) - 30);
}batch.end();
}
}
/**
* <p>Pauses the video streaming and the current state.</p>
*/
public void pause(){
if(videoThread != null)
videoThread.pause();
states[currState.getValue()].pause();
}
/**
* <p>Resumes the video streaming and the current state.</p>
*/
public void resume(){
if(videoThread != null)
videoThread.play();
states[currState.getValue()].resume();
}
/**
* <p>Clear graphic resources</p>
*/
public void dispose(){
// Dispose screens.
for(int i = 0; i < states.length; i++){
states[i].dispose();
}
// Finish network threads.
serviceDiscoveryThread.finish();
videoThread.finish();
robotThread.finish();
sensorThread.finish();
serviceDiscoveryThread = null;
videoThread = null;
robotThread = null;
sensorThread = null;
ServiceDiscoveryThread.freeInstance();
VideoStreamingThread.freeInstance();
RobotControlThread.freeInstance();
SensorReportThread.freeInstance();
// Dispose graphic objects.
fadeTexture.dispose();
batch.dispose();
font.dispose();
ScenarioGlobals.dispose();
}
/*;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; APPLICATION EVENTS LISTENER INTERFACE METHODS ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;*/
@Override
public synchronized void onNetworkStreamConnected(String streamName){
Gdx.app.log(TAG, CLASS_NAME + ".networkStreamConnected() :: Stream " + streamName + " connected.");
connections += 1;
if(connections >= 3){
Gdx.app.debug(TAG, CLASS_NAME + ".networkStreamConnected() :: Stopping service broadcast.");
serviceDiscoveryThread.finish();
if(actionResolver != null) actionResolver.disableMulticast();
if(actionResolver != null) actionResolver.showShortToast("Client connected");
((MainMenuStateBase)states[game_states_t.MAIN_MENU.getValue()]).onClientConnected();
}
}
@Override
public void create(){
float w = Gdx.graphics.getWidth();
float h = Gdx.graphics.getHeight();
Gdx.app.setLogLevel(Application.LOG_DEBUG);
camera = new OrthographicCamera(1, h/w);
batch = new SpriteBatch();
texture = new Texture(Gdx.files.internal("data/libgdx.png"));
texture.setFilter(TextureFilter.Linear, TextureFilter.Linear);
TextureRegion region = new TextureRegion(texture, 0, 0, 512, 275);
sprite = new Sprite(region);
sprite.setSize(0.9f, 0.9f * sprite.getHeight() / sprite.getWidth());
sprite.setOrigin(sprite.getWidth()/2, sprite.getHeight()/2);
sprite.setPosition(-sprite.getWidth()/2, -sprite.getHeight()/2);
Gdx.app.debug(TAG, CLASS_NAME + ".create() :: Creating network threads");
mcastEnabler.enableMulticast();
udpThread = ServiceDiscoveryThread.getInstance();
videoThread = VideoStreamingThread.getInstance().setToaster(toaster);
robotThread = RobotControlThread.getInstance().setToaster(toaster);
udpThread.start();
videoThread.start();
robotThread.start();
public void onAssetsLoaded(){
if(actionResolver != null) actionResolver.showShortToast("All assets sucessfully loaded.");
((MainMenuStateBase)states[game_states_t.MAIN_MENU.getValue()]).onAssetsLoaded();
}
@Override
public void dispose() {
batch.dispose();
texture.dispose();
public void onCameraCalibrated(){
if(actionResolver != null) actionResolver.showShortToast("Camera successfully calibrated.");
((MainMenuStateBase)states[game_states_t.MAIN_MENU.getValue()]).onCameraCalibrated();
}
@Override
public void render(){
Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
/*;;;;;;;;;;;;;;;;;;
; HELPER METHODS ;
;;;;;;;;;;;;;;;;;;*/
batch.setProjectionMatrix(camera.combined);
batch.begin();
sprite.draw(batch);
batch.end();
}
@Override
public void resize(int width, int height){
}
@Override
public void pause(){
}
@Override
public void resume(){
}
@Override
public synchronized void networkStreamConnected(String streamName){
if(streamName.compareTo(VideoStreamingThread.THREAD_NAME) == 0 || streamName.compareTo(RobotControlThread.THREAD_NAME) == 0)
connections += 1;
if(connections >= 2){
Gdx.app.debug(TAG, CLASS_NAME + ".networkStreamConnected() :: Stopping service broadcast.");
udpThread.finish();
mcastEnabler.disableMulticast();
/**
* <p>Show a toast message on screen using the {@link ActionResolver}.</p>
* @param msg The message to show.
* @param longToast True for a lasting toast. False for a short toast.
*/
public void toast(String msg, boolean longToast){
if(actionResolver != null){
if(longToast) actionResolver.showLongToast(msg);
else actionResolver.showShortToast(msg);
}
}
}

View File

@@ -0,0 +1,76 @@
/*
* Copyright (C) 2014 Miguel Angel Astor Romero
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ve.ucv.ciens.ccg.nxtar.components;
import java.util.LinkedList;
import java.util.List;
import com.artemis.Component;
import com.badlogic.gdx.graphics.g3d.ModelInstance;
import com.badlogic.gdx.graphics.g3d.utils.AnimationController;
public class AnimationComponent extends Component {
public AnimationController controller;
public AnimationController collisionController;
public List<String> animationsIds;
public int current;
public int next;
public boolean loop;
public AnimationComponent(ModelInstance instance, ModelInstance collisionInstance){
this(instance, -1, false, collisionInstance);
}
public AnimationComponent(ModelInstance instance) throws IllegalArgumentException{
this(instance, -1, false);
}
public AnimationComponent(ModelInstance instance, int next) throws IllegalArgumentException{
this(instance, next, false);
}
public AnimationComponent(ModelInstance instance, int next, boolean loop) throws IllegalArgumentException{
if(instance == null)
throw new IllegalArgumentException("Instance is null.");
else if(next > instance.animations.size)
throw new IllegalArgumentException("Next is greater than the number of animations for this model.");
controller = new AnimationController(instance);
collisionController = null;
animationsIds = new LinkedList<String>();
current = -1;
this.next = next;
this.loop = loop;
for(int i = 0; i < instance.animations.size; i++){
animationsIds.add(instance.animations.get(i).id);
}
}
public AnimationComponent(ModelInstance instance, int next, boolean loop, ModelInstance collisionInstance) throws IllegalArgumentException{
this(instance, next, loop);
if(instance.animations.size != collisionInstance.animations.size)
throw new IllegalArgumentException("Animation number doesn't match between render model and collision model.");
for(int i = 0; i < instance.animations.size; i++){
if(!instance.animations.get(i).id.contentEquals(collisionInstance.animations.get(i).id))
throw new IllegalArgumentException("Animations don't match between render model and collision model.");
}
collisionController = new AnimationController(collisionInstance);
}
}

View File

@@ -0,0 +1,51 @@
/*
* Copyright (C) 2014 Miguel Angel Astor Romero
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ve.ucv.ciens.ccg.nxtar.components;
import com.artemis.Component;
import com.badlogic.gdx.math.Vector3;
public class AutomaticMovementComponent extends Component{
public boolean moving;
public boolean forward;
public float distance;
public Vector3 startPoint;
public Vector3 endPoint;
public AutomaticMovementComponent(Vector3 startPoint, Vector3 endPoint, boolean moving){
this.moving = moving;
this.forward = true;
this.distance = 0.0f;
this.startPoint = startPoint;
this.endPoint = endPoint;
}
public AutomaticMovementComponent(Vector3 startPoint, Vector3 endPoint){
this(startPoint, endPoint, false);
}
public AutomaticMovementComponent(boolean moving){
this(new Vector3(0.0f, 0.0f, 0.0f), new Vector3(), moving);
}
public AutomaticMovementComponent(Vector3 endPoint){
this(new Vector3(0.0f, 0.0f, 0.0f), endPoint, false);
}
public AutomaticMovementComponent(){
this(false);
}
}

View File

@@ -0,0 +1,26 @@
/*
* Copyright (C) 2014 Miguel Angel Astor Romero
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ve.ucv.ciens.ccg.nxtar.components;
import com.artemis.Component;
public class CollisionDetectionComponent extends Component {
public boolean colliding;
public CollisionDetectionComponent(){
this.colliding = false;
}
}

View File

@@ -0,0 +1,38 @@
/*
* Copyright (C) 2014 Miguel Angel Astor Romero
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ve.ucv.ciens.ccg.nxtar.components;
import com.artemis.Component;
import com.badlogic.gdx.graphics.g3d.Model;
import com.badlogic.gdx.graphics.g3d.ModelInstance;
public class CollisionModelComponent extends Component {
public ModelInstance instance;
public CollisionModelComponent(Model model) throws IllegalArgumentException{
if(model == null)
throw new IllegalArgumentException("Model is null.");
this.instance = new ModelInstance(model);
}
public CollisionModelComponent(ModelInstance instance) throws IllegalArgumentException{
if(instance == null)
throw new IllegalArgumentException("Instance is null.");
this.instance = instance;
}
}

View File

@@ -0,0 +1,30 @@
/*
* Copyright (C) 2014 Miguel Angel Astor Romero
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ve.ucv.ciens.ccg.nxtar.components;
import com.artemis.Component;
import com.badlogic.gdx.graphics.g3d.Environment;
public class EnvironmentComponent extends Component {
public Environment environment;
public EnvironmentComponent(Environment environment) throws IllegalArgumentException{
if(environment == null)
throw new IllegalArgumentException("Environment is null.");
this.environment = environment;
}
}

View File

@@ -0,0 +1,129 @@
/*
* Copyright (C) 2014 Miguel Angel Astor Romero
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ve.ucv.ciens.ccg.nxtar.components;
import aurelienribon.tweenengine.Tween;
import aurelienribon.tweenengine.TweenEquations;
import aurelienribon.tweenengine.primitives.MutableFloat;
import com.artemis.Component;
import com.badlogic.gdx.graphics.Color;
public class FadeEffectComponent extends Component{
private MutableFloat alpha;
private Tween fadeIn;
private Tween fadeOut;
public Color color;
/**
* <p>Creates a fade to/from white depending on the parameter.</p>
*
* @param fadeIn True to create a fade FROM white, false for a fade TO white.
*/
public FadeEffectComponent(boolean fadeIn){
if(fadeIn){
this.alpha = new MutableFloat(1.0f);
this.fadeIn = Tween.to(alpha, 0, 2.0f).target(0.0f).ease(TweenEquations.easeInQuint);
this.fadeOut = null;
}else{
this.alpha = new MutableFloat(0.0f);
this.fadeOut = Tween.to(alpha, 0, 2.5f).target(1.0f).ease(TweenEquations.easeInQuint);
this.fadeIn = null;
}
color = new Color(Color.WHITE);
}
/**
* <p>Creates a fade effect with the desired parameters.</p>
*
* @param fadeIn True to create a fade FROM color, false for a fade TO color.
* @param color The color of the effect.
*/
public FadeEffectComponent(boolean fadeIn, Color color){
this(fadeIn);
this.color.set(color);
}
/**
* <p>Creates a fade out effect of the desired color.</p>
*
* @param color The color of the effect.
*/
public FadeEffectComponent(Color color){
this(false, color);
}
/**
* <p>Creates a white fade out effect.</p>
*/
public FadeEffectComponent(){
this(false);
}
/**
* <p>The current transparency of the effect.</p>
*
* @return The transparency.
*/
public float getFloatValue(){
return alpha.floatValue();
}
/**
* <p>Interpolates the transparency of the effect by the given delta time in seconds.</p>
*
* @param delta
*/
public void update(float delta){
if(fadeIn != null)
fadeIn.update(delta);
if(fadeOut != null)
fadeOut.update(delta);
}
/**
* <p>Initializes the effect.</p>
*/
public void startEffect(){
if(fadeIn != null)
fadeIn.start();
if(fadeOut != null)
fadeOut.start();
}
/**
* @return True if the effect has been initialized. False otherwise.
*/
public boolean isEffectStarted(){
return fadeIn != null ? fadeIn.isStarted() : fadeOut.isStarted();
}
/**
* @return True if this effect is a fade in. False if it is a fade out.
*/
public boolean isEffectFadeIn(){
return fadeIn != null;
}
/**
* @return True if the effect's interpolation is over. False otherwise.
*/
public boolean isEffectFinished(){
return fadeIn != null ? fadeIn.isFinished() : fadeOut.isFinished();
}
}

View File

@@ -0,0 +1,38 @@
/*
* Copyright (C) 2014 Miguel Angel Astor Romero
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ve.ucv.ciens.ccg.nxtar.components;
import com.artemis.Component;
import com.badlogic.gdx.math.Matrix3;
import com.badlogic.gdx.math.Vector3;
public class GeometryComponent extends Component {
public Vector3 position;
public Matrix3 rotation;
public Vector3 scaling;
public GeometryComponent(){
this.position = new Vector3();
this.rotation = new Matrix3();
this.scaling = new Vector3(1.0f, 1.0f, 1.0f);
}
public GeometryComponent(Vector3 position, Matrix3 rotation, Vector3 scaling){
this.position = new Vector3(position);
this.rotation = new Matrix3(rotation);
this.scaling = new Vector3(scaling);
}
}

View File

@@ -0,0 +1,35 @@
/*
* Copyright (C) 2014 Miguel Angel Astor Romero
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ve.ucv.ciens.ccg.nxtar.components;
import com.artemis.Component;
public class MarkerCodeComponent extends Component {
public int code;
public boolean enabled;
public MarkerCodeComponent(int code) throws IllegalArgumentException{
if(code < 0 || code > 1024)
throw new IllegalArgumentException("Marker code must be between [0, 1024].");
this.code = code;
this.enabled = true;
}
public MarkerCodeComponent(int code, boolean enabled){
this(code);
this.enabled = enabled;
}
}

View File

@@ -0,0 +1,38 @@
/*
* Copyright (C) 2014 Miguel Angel Astor Romero
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ve.ucv.ciens.ccg.nxtar.components;
import com.artemis.Component;
/**
* Tag class.
*/
public abstract class PlayerComponentBase extends Component {
public static final String PLAYER_GROUP = "PLAYER";
public boolean gameFinished;
public boolean victory;
public PlayerComponentBase(){
this.gameFinished = false;
this.victory = false;
}
public void reset(){
this.gameFinished = false;
this.victory = false;
}
}

View File

@@ -0,0 +1,38 @@
/*
* Copyright (C) 2014 Miguel Angel Astor Romero
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ve.ucv.ciens.ccg.nxtar.components;
import com.artemis.Component;
import com.badlogic.gdx.graphics.g3d.Model;
import com.badlogic.gdx.graphics.g3d.ModelInstance;
public class RenderModelComponent extends Component {
public ModelInstance instance;
public RenderModelComponent(Model model) throws IllegalArgumentException{
if(model == null)
throw new IllegalArgumentException("Model is null.");
this.instance = new ModelInstance(model);
}
public RenderModelComponent(ModelInstance instance) throws IllegalArgumentException{
if(instance == null)
throw new IllegalArgumentException("Instance is null.");
this.instance = instance;
}
}

View File

@@ -0,0 +1,30 @@
/*
* Copyright (C) 2014 Miguel Angel Astor Romero
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ve.ucv.ciens.ccg.nxtar.components;
import com.artemis.Component;
import com.badlogic.gdx.graphics.g3d.Shader;
public class ShaderComponent extends Component{
public Shader shader;
public ShaderComponent(Shader shader) throws IllegalArgumentException{
if(shader == null)
throw new IllegalArgumentException("Shader is null.");
this.shader = shader;
}
}

View File

@@ -0,0 +1,30 @@
/*
* Copyright (C) 2014 Miguel Angel Astor Romero
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ve.ucv.ciens.ccg.nxtar.components;
import com.artemis.Component;
public class VisibilityComponent extends Component {
public boolean visible;
public VisibilityComponent(){
this.visible = true;
}
public VisibilityComponent(boolean visibility){
this.visible = visibility;
}
}

View File

@@ -0,0 +1,86 @@
/*
* Copyright (C) 2014 Miguel Angel Astor Romero
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ve.ucv.ciens.ccg.nxtar.entities;
import ve.ucv.ciens.ccg.nxtar.NxtARCore;
import ve.ucv.ciens.ccg.nxtar.interfaces.ApplicationEventsListener;
import com.artemis.World;
import com.badlogic.gdx.assets.AssetManager;
import com.badlogic.gdx.utils.Disposable;
/**
*
*/
public abstract class EntityCreatorBase implements Disposable{
protected World world = null;
protected ApplicationEventsListener core = null;
protected boolean entitiesCreated = false;
protected AssetManager manager = null;
/**
* <p>Sets the Artemis {@link World} to use to create entities.</p>
*
* @param world The Artemis {@link World}.
* @throws IllegalArgumentException if world is null.
*/
public final void setWorld(World world) throws IllegalArgumentException{
if(world == null)
throw new IllegalArgumentException("World cannot be null.");
this.world = world;
}
/**
* <p>Sets the application core to listen for asset loading events.</p>
*
* @param core The application core to be used as listener.
* @throws IllegalArgumentException if core is null.
*/
public final void setCore(NxtARCore core) throws IllegalArgumentException{
if(core == null) throw new IllegalArgumentException("Core is null.");
this.core = core;
}
/**
* <p> Updates the state of the {@link AssetManager}.</p>
*
* @return true if the {@link AssetManager} has finished loading.
*/
public abstract boolean updateAssetManager();
/**
* <p>Unloads all assets loaded for the scenario.</p>
*/
public abstract void dispose();
/**
* @return true if the createAllEntities method has been called.
*/
public boolean areEntitiesCreated(){
return entitiesCreated;
}
/**
* <p>Creates all entities for a game scenario.</p>
*/
protected abstract void createAllEntities();
/**
* <p>Recreates all entities in the game.</p>
*/
public abstract void resetAllEntities();
}

View File

@@ -0,0 +1,24 @@
/*
* Copyright (C) 2014 Miguel Angel Astor Romero
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ve.ucv.ciens.ccg.nxtar.exceptions;
public class ImageTooBigException extends Exception{
private static final long serialVersionUID = 9989L;
public ImageTooBigException(String msg){
super(msg);
}
}

View File

@@ -0,0 +1,73 @@
/*
* Copyright (C) 2014 Miguel Angel Astor Romero
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ve.ucv.ciens.ccg.nxtar.graphics;
import com.badlogic.gdx.graphics.PerspectiveCamera;
import com.badlogic.gdx.math.Matrix4;
import com.badlogic.gdx.math.Vector3;
/**
* <p>Extension of the standard LibGDX perspective camera that allows setting an
* arbitrary projection matrix when updating.</p>
*/
public class CustomPerspectiveCamera extends PerspectiveCamera{
private final Vector3 tmp = new Vector3();
public CustomPerspectiveCamera(float fieldOfView, float viewportWidth, float viewportHeight){
super(fieldOfView, viewportWidth, viewportHeight);
update();
}
public void update(Matrix4 customProjection){
this.update(customProjection, true);
}
public void update(Matrix4 customProjection, boolean updateFrustum){
projection.set(customProjection);
view.setToLookAt(position, tmp.set(position).add(direction), up);
combined.set(projection).mul(view);
if(updateFrustum){
invProjectionView.set(combined).inv();
frustum.update(invProjectionView);
}
}
public void setCustomARProjectionMatrix(final float focalPointX, final float focalPointY, final float cameraCenterX, final float cameraCenterY, final float near, final float far, final float w, final float h){
final float FAR_PLUS_NEAR = far + near;
final float FAR_LESS_NEAR = far - near;
projection.val[Matrix4.M00] = -2.0f * focalPointX / w;
projection.val[Matrix4.M10] = 0.0f;
projection.val[Matrix4.M20] = 0.0f;
projection.val[Matrix4.M30] = 0.0f;
projection.val[Matrix4.M01] = 0.0f;
projection.val[Matrix4.M11] = 2.0f * focalPointY / h;
projection.val[Matrix4.M21] = 0.0f;
projection.val[Matrix4.M31] = 0.0f;
projection.val[Matrix4.M02] = 2.0f * cameraCenterX / w - 1.0f;
projection.val[Matrix4.M12] = 2.0f * cameraCenterY / h - 1.0f;
projection.val[Matrix4.M22] = -FAR_PLUS_NEAR / FAR_LESS_NEAR;
projection.val[Matrix4.M32] = -1.0f;
projection.val[Matrix4.M03] = 0.0f;
projection.val[Matrix4.M13] = 0.0f;
projection.val[Matrix4.M23] = -2.0f * far * near / FAR_LESS_NEAR;
projection.val[Matrix4.M33] = 0.0f;
}
}

View File

@@ -0,0 +1,245 @@
/*
* Copyright (C) 2014 Miguel Angel Astor Romero
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ve.ucv.ciens.ccg.nxtar.graphics.shaders;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Camera;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.VertexAttributes;
import com.badlogic.gdx.graphics.g3d.Renderable;
import com.badlogic.gdx.graphics.g3d.Shader;
import com.badlogic.gdx.graphics.g3d.attributes.ColorAttribute;
import com.badlogic.gdx.graphics.g3d.attributes.FloatAttribute;
import com.badlogic.gdx.graphics.g3d.utils.RenderContext;
import com.badlogic.gdx.graphics.glutils.ShaderProgram;
import com.badlogic.gdx.math.Matrix4;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.utils.GdxRuntimeException;
public class DirectionalLightPerPixelShader implements Shader{
private static final int MAX_NUM_BONES = 4;
private static final Matrix4 IDENTITY = new Matrix4();
private static final String VERTEX_SHADER_PATH = "shaders/directionalPerPixelSingleLight/directionalPerPixel_vert.glsl";
private static final String FRAGMENT_SHADER_PATH = "shaders/directionalPerPixelSingleLight/directionalPerPixel_frag.glsl";
private static final String INCLUDE_SKINNING = "#define SKINNING\n";
private static final float DEFAULT_SHININESS = 50.0f;
private static final Vector3 DEFAULT_LIGHT = new Vector3(1, 1, 1);
private ShaderProgram skinningProgram;
private ShaderProgram baseProgram;
private Camera camera;
private RenderContext context;
private Matrix4 normalMatrix;
// Uniform locations.
private int[] u_geomTrans;
private int[] u_projTrans;
private int[] u_lightPos;
private int[] u_lightDiffuse;
private int[] u_specular;
private int[] u_ambient;
private int[] u_shiny;
private int[] u_cameraPos;
private int[] u_materialDiffuse;
private int[] u_normalMatrix;
private int[] u_bones;
public DirectionalLightPerPixelShader(){
skinningProgram = null;
baseProgram = null;
camera = null;
context = null;
}
@Override
public void init() throws GdxRuntimeException{
normalMatrix = new Matrix4().idt();
u_bones = new int[MAX_NUM_BONES];
// Compile the shader.
String vertexCode = Gdx.files.internal(VERTEX_SHADER_PATH).readString();
String fragmentCode = Gdx.files.internal(FRAGMENT_SHADER_PATH).readString();
skinningProgram = new ShaderProgram(INCLUDE_SKINNING + vertexCode, fragmentCode);
baseProgram = new ShaderProgram(vertexCode, fragmentCode);
if(!skinningProgram.isCompiled())
throw new GdxRuntimeException(skinningProgram.getLog());
if(!baseProgram.isCompiled())
throw new GdxRuntimeException(baseProgram.getLog());
// Create uniform locations.
u_projTrans = new int[2];
u_geomTrans = new int[2];
u_lightPos = new int[2];
u_lightDiffuse = new int[2];
u_specular = new int[2];
u_ambient = new int[2];
u_shiny = new int[2];
u_cameraPos = new int[2];
u_materialDiffuse = new int[2];
u_normalMatrix = new int[2];
// Cache uniform locations.
u_projTrans [0] = skinningProgram.getUniformLocation("u_projTrans");
u_geomTrans [0] = skinningProgram.getUniformLocation("u_geomTrans");
u_lightPos [0] = skinningProgram.getUniformLocation("u_lightPos");
u_lightDiffuse [0] = skinningProgram.getUniformLocation("u_lightDiffuse");
u_specular [0] = skinningProgram.getUniformLocation("u_specular");
u_ambient [0] = skinningProgram.getUniformLocation("u_ambient");
u_shiny [0] = skinningProgram.getUniformLocation("u_shiny");
u_cameraPos [0] = skinningProgram.getUniformLocation("u_cameraPos");
u_materialDiffuse [0] = skinningProgram.getUniformLocation("u_materialDiffuse");
u_normalMatrix [0] = skinningProgram.getUniformLocation("u_normalMatrix");
u_projTrans [1] = baseProgram.getUniformLocation("u_projTrans");
u_geomTrans [1] = baseProgram.getUniformLocation("u_geomTrans");
u_lightPos [1] = baseProgram.getUniformLocation("u_lightPos");
u_lightDiffuse [1] = baseProgram.getUniformLocation("u_lightDiffuse");
u_specular [1] = baseProgram.getUniformLocation("u_specular");
u_ambient [1] = baseProgram.getUniformLocation("u_ambient");
u_shiny [1] = baseProgram.getUniformLocation("u_shiny");
u_cameraPos [1] = baseProgram.getUniformLocation("u_cameraPos");
u_materialDiffuse [1] = baseProgram.getUniformLocation("u_materialDiffuse");
u_normalMatrix [1] = baseProgram.getUniformLocation("u_normalMatrix");
for(int i = 0; i < MAX_NUM_BONES; i++){
u_bones[i] = skinningProgram.getUniformLocation("u_bone" + Integer.toString(i));
}
}
@Override
public void dispose(){
if(skinningProgram != null) skinningProgram.dispose();
if(baseProgram != null) baseProgram.dispose();
}
@Override
public int compareTo(Shader other){
return 0;
}
@Override
public boolean canRender(Renderable renderable){
// Easier to always return true. Missing material properties are replaced by
// default values during render.
return true;
}
@Override
public void begin(Camera camera, RenderContext context) throws GdxRuntimeException{
if(this.camera != null || this.context != null)
throw new GdxRuntimeException("Called begin twice before calling end.");
this.camera = camera;
this.context = context;
// Set render context.
this.context.setDepthTest(GL20.GL_LEQUAL);
this.context.setDepthMask(true);
}
@Override
public void render(Renderable renderable){
ShaderProgram program;
int index;
boolean bonesEnabled;
Vector3 lightPosition;
Color diffuseLightColor;
Color diffuseColor;
Color specularColor;
Color ambientColor;
float shininess;
// Get material colors.
if(renderable.environment != null && renderable.environment.directionalLights != null && renderable.environment.directionalLights.size >= 1){
lightPosition = renderable.environment.directionalLights.get(0).direction;
diffuseLightColor = renderable.environment.directionalLights.get(0).color;
}else{
lightPosition = DEFAULT_LIGHT;
diffuseLightColor = Color.WHITE;
}
if(renderable.material.has(ColorAttribute.Diffuse))
diffuseColor = ((ColorAttribute)renderable.material.get(ColorAttribute.Diffuse)).color;
else
diffuseColor = Color.WHITE;
if(renderable.material.has(ColorAttribute.Specular))
specularColor = ((ColorAttribute)renderable.material.get(ColorAttribute.Specular)).color;
else
specularColor = Color.BLACK;
if(renderable.environment != null && renderable.environment.has(ColorAttribute.AmbientLight))
ambientColor = ((ColorAttribute)renderable.environment.get(ColorAttribute.AmbientLight)).color;
else
ambientColor = Color.BLACK;
if(renderable.material.has(FloatAttribute.Shininess))
shininess = ((FloatAttribute)renderable.material.get(FloatAttribute.Shininess)).value;
else
shininess = DEFAULT_SHININESS;
if(renderable.mesh.getVertexAttribute(VertexAttributes.Usage.BoneWeight) != null){
program = skinningProgram;
index = 0;
bonesEnabled = true;
}else{
program = baseProgram;
index = 1;
bonesEnabled = false;
}
program.begin();
// Set camera dependant uniforms.
program.setUniformMatrix(u_projTrans[index], this.camera.combined);
program.setUniformf(u_cameraPos[index], this.camera.position);
// Set model dependant uniforms.
program.setUniformMatrix(u_geomTrans[index], renderable.worldTransform);
program.setUniformMatrix(u_normalMatrix[index], normalMatrix.set(renderable.worldTransform).toNormalMatrix());
program.setUniformf(u_lightPos[index], lightPosition);
program.setUniformf(u_lightDiffuse[index], diffuseLightColor);
program.setUniformf(u_materialDiffuse[index], diffuseColor);
program.setUniformf(u_specular[index], specularColor);
program.setUniformf(u_ambient[index], ambientColor);
program.setUniformf(u_shiny[index], shininess);
// Set the bones uniforms.
if(bonesEnabled){
for(int i = 0; i < MAX_NUM_BONES; i++){
if(renderable.bones != null && i < renderable.bones.length && renderable.bones[i] != null)
skinningProgram.setUniformMatrix(u_bones[i], renderable.bones[i]);
else
skinningProgram.setUniformMatrix(u_bones[i], IDENTITY);
}
}
renderable.mesh.render(program, renderable.primitiveType, renderable.meshPartOffset, renderable.meshPartSize);
program.end();
}
@Override
public void end(){
this.camera = null;
this.context = null;
}
}

View File

@@ -0,0 +1,32 @@
/*
* Copyright (C) 2014 Miguel Angel Astor Romero
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ve.ucv.ciens.ccg.nxtar.input;
public class GamepadUserInput extends UserInput {
public float axisLeftX;
public float axisLeftY;
public float axisRightX;
public float axisRightY;
public boolean oButton;
public GamepadUserInput(){
this.axisLeftX = 0.0f;
this.axisLeftY = 0.0f;
this.axisRightX = 0.0f;
this.axisRightY = 0.0f;
this.oButton = false;
}
}

View File

@@ -0,0 +1,32 @@
/*
* Copyright (C) 2014 Miguel Angel Astor Romero
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ve.ucv.ciens.ccg.nxtar.input;
public class KeyboardUserInput extends UserInput {
public boolean keyLeft;
public boolean keyRight;
public boolean keyUp;
public boolean keyDown;
public boolean keySpace;
public KeyboardUserInput(){
this.keyLeft = false;
this.keyRight = false;
this.keyUp = false;
this.keyDown = false;
this.keySpace = false;
}
}

View File

@@ -0,0 +1,34 @@
/*
* Copyright (C) 2014 Miguel Angel Astor Romero
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ve.ucv.ciens.ccg.nxtar.input;
import com.badlogic.gdx.math.Vector3;
public class TouchUserInput extends UserInput {
public Vector3 userTouchEndPoint;
public TouchUserInput(){
this.userTouchEndPoint = new Vector3();
}
public TouchUserInput(Vector3 userTouchEndPoint){
this.userTouchEndPoint = new Vector3(userTouchEndPoint);
}
public TouchUserInput(float x, float y, float z){
this.userTouchEndPoint = new Vector3(x, y, z);
}
}

View File

@@ -0,0 +1,21 @@
/*
* Copyright (C) 2014 Miguel Angel Astor Romero
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ve.ucv.ciens.ccg.nxtar.input;
/**
* Tag class for different user interaction wrapper classes.
*/
public abstract class UserInput{ }

View File

@@ -0,0 +1,23 @@
/*
* Copyright (C) 2013 Miguel Angel Astor Romero
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ve.ucv.ciens.ccg.nxtar.interfaces;
public interface ActionResolver{
public void showShortToast(String msg);
public void showLongToast(String msg);
public void enableMulticast();
public void disableMulticast();
}

View File

@@ -0,0 +1,38 @@
/*
* Copyright (C) 2013 Miguel Angel Astor Romero
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ve.ucv.ciens.ccg.nxtar.interfaces;
public interface ApplicationEventsListener {
/**
* <p>Callback used by the networking threads to notify sucessfull connections
* to the application</p>
*
* @param streamName The name of the thread notifying a connection.
*/
public void onNetworkStreamConnected(String streamName);
/**
* <p>Callback used by the assets loader to notify that all
* required game assets are ready to be used.</p>
*/
public void onAssetsLoaded();
/**
* <p>Callback used by the camera calibration state to notify that the
* camera has been succesfully calibrated.</p>
*/
public void onCameraCalibrated();
}

View File

@@ -0,0 +1,86 @@
/*
* Copyright (C) 2014 Miguel Angel Astor Romero
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ve.ucv.ciens.ccg.nxtar.interfaces;
import ve.ucv.ciens.ccg.nxtar.utils.ProjectConstants;
import com.badlogic.gdx.math.Matrix3;
import com.badlogic.gdx.math.Vector3;
public interface ImageProcessor{
public class MarkerData{
public byte[] outFrame;
public int[] markerCodes;
public Vector3[] translationVectors;
public Matrix3[] rotationMatrices;
}
public class CalibrationData{
public byte[] outFrame;
public float[] calibrationPoints;
}
/**
* <p>Finds up to {@link ProjectConstants.MAXIMUM_NUMBER_OF_MARKERS} markers in the input
* image and returns their codes and pose estimation in the CVMarkerData structure. The
* markers are higlihted in the input image.</p>
*
* @param frame The JPEG encoded input image.
* @return A data structure containing the processed output image, the
* detected marker codes and their respective locations.
*/
public MarkerData findMarkersInFrame(byte[] frame);
/**
* <p>Attempts to detect a checkerboard calibration pattern in the input image.
* If the pattenr is found the method returns an image with the pattern
* highlighted and the spatial location of the calibration points in the
* output data structure.</p>
*
* @param frame The JPEG encoded input image.
* @return A data structure containing the processed output image and the
* location of the calibration points. If the pattern was not found, the returnd
* calibration points array is null.
*/
public CalibrationData findCalibrationPattern(byte[] frame);
/**
* <p>Obtains the intrinsic camera parameters necesary for calibration.</p>
*/
public void calibrateCamera(float[][] calibrationSamples, byte[] frame);
/**
* <p>Removes camera lens distortion from the input image using the
* camera parameters obtained by the calibrateCamera method.</p>
*
* @return A JPEG encoded image that is the input image after distortion correction. If the
* camera has not been calibrated or OpenCV failed to load returns null.
*/
public byte[] undistortFrame(byte[] frame);
/**
* <p>Indicates if OpenCV has been sucessfully initialized and used
* to obtain the camera parameters for calibration.</p>
*
* @return True if and only if OpenCV initialized succesfully and calibrateCamera has been called previously.
*/
public boolean isCameraCalibrated();
public float getFocalPointX();
public float getFocalPointY();
public float getCameraCenterX();
public float getCameraCenterY();
}

View File

@@ -1,6 +0,0 @@
package ve.ucv.ciens.ccg.nxtar.interfaces;
public interface MulticastEnabler {
public void enableMulticast();
public void disableMulticast();
}

View File

@@ -1,5 +0,0 @@
package ve.ucv.ciens.ccg.nxtar.interfaces;
public interface NetworkConnectionListener {
public void networkStreamConnected(String streamName);
}

View File

@@ -1,6 +0,0 @@
package ve.ucv.ciens.ccg.nxtar.interfaces;
public interface Toaster {
public void showShortToast(String msg);
public void showLongToast(String msg);
}

View File

@@ -1,11 +1,31 @@
/*
* Copyright (C) 2013 Miguel Angel Astor Romero
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ve.ucv.ciens.ccg.nxtar.network;
import java.io.IOException;
import java.io.InvalidClassException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import ve.ucv.ciens.ccg.nxtar.interfaces.NetworkConnectionListener;
import ve.ucv.ciens.ccg.nxtar.interfaces.Toaster;
import ve.ucv.ciens.ccg.networkdata.MotorEvent;
import ve.ucv.ciens.ccg.networkdata.MotorEventACK;
import ve.ucv.ciens.ccg.nxtar.interfaces.ApplicationEventsListener;
import ve.ucv.ciens.ccg.nxtar.network.monitors.MotorEventQueue;
import ve.ucv.ciens.ccg.nxtar.utils.ProjectConstants;
import com.badlogic.gdx.Gdx;
@@ -14,51 +34,158 @@ public class RobotControlThread extends Thread {
public static final String THREAD_NAME = "RobotControlThread";
private static final String TAG = "NXTAR_CORE_ROBOTTHREAD";
private static final String CLASS_NAME = RobotControlThread.class.getSimpleName();
private static int refCount = 0;
private NetworkConnectionListener netListener;
private ApplicationEventsListener netListener;
private ServerSocket server;
private Socket client;
private Toaster toaster;
private MotorEventQueue queue;
private Object pauseMonitor;
private boolean paused;
private boolean done;
private ObjectOutputStream os;
private ObjectInputStream is;
private RobotControlThread(){
super(THREAD_NAME);
netListener = null;
queue = MotorEventQueue.getInstance();
pauseMonitor = new Object();
paused = false;
done = false;
try{
server = new ServerSocket(ProjectConstants.SERVER_TCP_PORT_2);
server = new ServerSocket(ProjectConstants.MOTOR_CONTROL_PORT);
}catch(IOException io){
Gdx.app.error(TAG, CLASS_NAME + ".RobotControlThread() :: Error creating server: " + io.getMessage(), io);
}
}
private static class SingletonHolder{
public static final RobotControlThread INSTANCE = new RobotControlThread();
public static RobotControlThread INSTANCE;
}
public static RobotControlThread getInstance(){
if(refCount == 0)
SingletonHolder.INSTANCE = new RobotControlThread();
refCount++;
return SingletonHolder.INSTANCE;
}
public RobotControlThread setToaster(Toaster toaster){
this.toaster = toaster;
return this;
public static void freeInstance(){
refCount--;
if(refCount == 0) SingletonHolder.INSTANCE = null;
}
public void addNetworkConnectionListener(NetworkConnectionListener listener){
public void addNetworkConnectionListener(ApplicationEventsListener listener){
netListener = listener;
}
public void pauseThread(){
synchronized(pauseMonitor){
paused = true;
}
}
public void resumeThread(){
synchronized(pauseMonitor){
paused = false;
}
}
public void finish(){
done = true;
try{
server.close();
}catch(IOException io){
Gdx.app.error(TAG, CLASS_NAME + ".run() :: Error closing client: " + io.getMessage(), io);
}
}
@Override
public void run(){
MotorEvent message;
MotorEventACK ack;
try{
client = server.accept();
if(netListener != null)
netListener.networkStreamConnected(THREAD_NAME);
toaster.showShortToast("Client connected to RobotControlThread");
client.close();
client.setTcpNoDelay(true);
if(netListener != null) netListener.onNetworkStreamConnected(THREAD_NAME);
os = new ObjectOutputStream(client.getOutputStream());
is = new ObjectInputStream(client.getInputStream());
}catch(IOException io){
Gdx.app.error(TAG, CLASS_NAME + ".run() :: Error accepting client: " + io.getMessage(), io);
return;
}
while(!paused){
if(done){
break;
}
// Send the motor event.
try{
message = queue.getNextEvent();
os.writeObject(message);
message = null;
}catch(InvalidClassException ic){
Gdx.app.error(TAG, CLASS_NAME + ".run() :: InvalidClassException during transmission: " + ic.getMessage(), ic);
break;
}catch(IOException io){
Gdx.app.error(TAG, CLASS_NAME + ".run() :: IOException during transmission: " + io.getMessage(), io);
break;
}
// Receive ack.
try{
ack = (MotorEventACK)is.readObject();
}catch(ClassNotFoundException cn){
Gdx.app.error(TAG, CLASS_NAME + ".run() :: InvalidClassException during reception: " + cn.getMessage(), cn);
break;
}catch(ClassCastException cc){
Gdx.app.error(TAG, CLASS_NAME + ".run() :: InvalidClassException during reception: " + cc.getMessage(), cc);
break;
}catch(IOException io){
Gdx.app.error(TAG, CLASS_NAME + ".run() :: InvalidClassException during reception: " + io.getMessage(), io);
break;
}
if(ack.isClientQueueFull()){
// Wait for client to notify.
// A client will never send two queue full acks in a row.
try{
ack = (MotorEventACK)is.readObject();
}catch(ClassNotFoundException cn){
Gdx.app.error(TAG, CLASS_NAME + ".run() :: InvalidClassException during reception: " + cn.getMessage(), cn);
break;
}catch(ClassCastException cc){
Gdx.app.error(TAG, CLASS_NAME + ".run() :: InvalidClassException during reception: " + cc.getMessage(), cc);
break;
}catch(IOException io){
Gdx.app.error(TAG, CLASS_NAME + ".run() :: InvalidClassException during reception: " + io.getMessage(), io);
break;
}
}else{
// Clean and continue.
ack = null;
message = null;
continue;
}
}
try{
client.close();
}catch(IOException io){
Gdx.app.error(TAG, CLASS_NAME + ".run() :: Error closing client: " + io.getMessage(), io);
}
}
}

View File

@@ -0,0 +1,148 @@
/*
* Copyright (C) 2014 Miguel Angel Astor Romero
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ve.ucv.ciens.ccg.nxtar.network;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import ve.ucv.ciens.ccg.nxtar.interfaces.ApplicationEventsListener;
import ve.ucv.ciens.ccg.nxtar.utils.ProjectConstants;
import com.badlogic.gdx.Gdx;
public class SensorReportThread extends Thread {
public static final String THREAD_NAME = "SensorReportThread";
private static final String TAG = "NXTAR_CORE_ROBOTTHREAD";
private static final String CLASS_NAME = SensorReportThread.class.getSimpleName();
private static int refCount = 0;
private ApplicationEventsListener netListener;
private ServerSocket server;
private Socket client;
private Object pauseMonitor;
private boolean paused;
private boolean done;
private InputStream reader;
private Byte lightReading;
private SensorReportThread(){
paused = false;
done = false;
netListener = null;
pauseMonitor = null;
client = null;
lightReading = -1;
try{
server = new ServerSocket(ProjectConstants.SENSOR_REPORT_PORT);
}catch(IOException io){
Gdx.app.error(TAG, CLASS_NAME + ".RobotControlThread() :: Error creating server: " + io.getMessage(), io);
server = null;
}
}
private static class SingletonHolder{
public static SensorReportThread INSTANCE;
}
public static SensorReportThread getInstance(){
if(refCount == 0)
SingletonHolder.INSTANCE = new SensorReportThread();
refCount++;
return SingletonHolder.INSTANCE;
}
public static void freeInstance(){
refCount--;
if(refCount == 0) SingletonHolder.INSTANCE = null;
}
public void addNetworkConnectionListener(ApplicationEventsListener listener){
netListener = listener;
}
public void pauseThread(){
synchronized(pauseMonitor){
paused = true;
}
}
public void resumeThread(){
synchronized(pauseMonitor){
paused = false;
}
}
public void finish(){
done = true;
try{
server.close();
}catch(IOException io){
Gdx.app.error(TAG, CLASS_NAME + ".run() :: IOException closing sockets: " + io.getMessage(), io);
}
}
public byte getLightSensorReading(){
byte data;
synchronized(lightReading){
data = lightReading.byteValue();
}
return data;
}
@Override
public void run(){
byte[] reading = new byte[1];
try{
client = server.accept();
client.setTcpNoDelay(true);
if(netListener != null) netListener.onNetworkStreamConnected(THREAD_NAME);
reader = client.getInputStream();
}catch(IOException io){
Gdx.app.error(TAG, CLASS_NAME + ".run() :: Error accepting client: " + io.getMessage(), io);
return;
}
while(!paused){
if(done) break;
try{
reader.read(reading);
}catch(IOException io){
Gdx.app.error(TAG, CLASS_NAME + ".run() :: IOException during sensor read: " + io.getMessage(), io);
break;
}
synchronized (lightReading) {
lightReading = reading[0];
}
}
try{
reader.close();
client.close();
server.close();
}catch(IOException io){
Gdx.app.error(TAG, CLASS_NAME + ".run() :: IOException closing sockets: " + io.getMessage(), io);
}
}
}

View File

@@ -1,3 +1,18 @@
/*
* Copyright (C) 2013 Miguel Angel Astor Romero
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ve.ucv.ciens.ccg.nxtar.network;
import java.io.IOException;
@@ -16,42 +31,35 @@ import com.badlogic.gdx.Gdx;
* <p> This thread performs an ad hoc service discovery protocol. A multicast datagram packet is sent every
* 250 miliseconds carrying the string "NxtAR server is here!" on the multicast address defined
* in {@link ve.ucv.ciens.ccg.nxtar.utils.ProjectConstants#MULTICAST_ADDRESS}. The port defined in
* {@link ve.ucv.ciens.ccg.nxtar.utils.ProjectConstants#SERVER_UDP_PORT} is used for the transmissions. The server stops
* {@link ve.ucv.ciens.ccg.nxtar.utils.ProjectConstants#SERVICE_DISCOVERY_PORT} is used for the transmissions. The server stops
* when another thread calls the {@link #finish()} method or the server fails to transmit {@link #MAX_RETRIES} packets in
* a row, whichever happens first.</p>
*
* @author miky
*/
public class ServiceDiscoveryThread extends Thread {
/**
* The name used to identify this thread.
*/
public static final String THREAD_NAME = "ServiceDiscoveryThread";
/**
* Tag used for logging.
*/
public static final String THREAD_NAME = "ServiceDiscoveryThread";
private static final String TAG = "NXTAR_CORE_UDPTHREAD";
/**
* Class name used for logging.
*/
private static final String CLASS_NAME = ServiceDiscoveryThread.class.getSimpleName();
/**
* Maximum number of transmission attempts before ending the thread abruptly.
*/
private static final int MAX_RETRIES = 5;
private static final int MAX_RETRIES = 5;
private static int refCount = 0;
/**
* A semaphore object used to synchronize acces to this thread finish flag.
*/
private Object semaphore;
/**
* The finish flag.
*/
private boolean done;
/**
* The UDP server socket used for the ad hoc service discovery protocol.
*/
private DatagramSocket udpServer;
/**
* Holder for the multicast address used in the protocol.
*/
@@ -74,7 +82,7 @@ public class ServiceDiscoveryThread extends Thread {
// Create a UDP socket at the port defined in ProjectConstants.SERVER_UDP_PORT.
Gdx.app.debug(TAG, CLASS_NAME + ".ServiceDiscoveryThread() :: Creating multicast server.");
try{
udpServer = new DatagramSocket(ProjectConstants.SERVER_UDP_PORT);
udpServer = new DatagramSocket(ProjectConstants.SERVICE_DISCOVERY_PORT);
}catch(IOException io){
Gdx.app.error(TAG, CLASS_NAME + ".ServiceDiscoveryThread() :: Error creating UDP socket: " + io.getMessage());
udpServer = null;
@@ -86,7 +94,7 @@ public class ServiceDiscoveryThread extends Thread {
* Singleton holder for this class.
*/
private static class SingletonHolder{
public static final ServiceDiscoveryThread INSTANCE = new ServiceDiscoveryThread();
public static ServiceDiscoveryThread INSTANCE;
}
/**
@@ -95,9 +103,17 @@ public class ServiceDiscoveryThread extends Thread {
* @return The singleton instance.
*/
public static ServiceDiscoveryThread getInstance(){
if(refCount == 0)
SingletonHolder.INSTANCE = new ServiceDiscoveryThread();
refCount++;
return SingletonHolder.INSTANCE;
}
public static void freeInstance(){
refCount--;
if(refCount == 0) SingletonHolder.INSTANCE = null;
}
/**
* This thread's run method.
*
@@ -123,6 +139,7 @@ public class ServiceDiscoveryThread extends Thread {
// Verify if the thread should end. If that is the case, close the server.
synchronized(semaphore){
if(done){
Gdx.app.log(TAG, CLASS_NAME + ".run(): Closing.");
udpServer.close();
break;
}
@@ -135,10 +152,11 @@ public class ServiceDiscoveryThread extends Thread {
break;
}
// Send the packet and reset the retry counter.
DatagramPacket packet = new DatagramPacket(buffer, buffer.length, group, ProjectConstants.SERVER_UDP_PORT);
DatagramPacket packet = new DatagramPacket(buffer, buffer.length, group, ProjectConstants.SERVICE_DISCOVERY_PORT);
udpServer.send(packet);
retries = 0;
try{ sleep(250L); }catch(InterruptedException ie){ }
}catch(IOException io){
Gdx.app.error(TAG, CLASS_NAME + ".run() :: Error sending packet: " + io.getMessage());
retries += 1;

View File

@@ -1,63 +1,262 @@
/*
* Copyright (C) 2013 Miguel Angel Astor Romero
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ve.ucv.ciens.ccg.nxtar.network;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.io.ObjectInputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import ve.ucv.ciens.ccg.nxtar.interfaces.NetworkConnectionListener;
import ve.ucv.ciens.ccg.nxtar.interfaces.Toaster;
import ve.ucv.ciens.ccg.networkdata.VideoFrameDataMessage;
import ve.ucv.ciens.ccg.nxtar.interfaces.ApplicationEventsListener;
import ve.ucv.ciens.ccg.nxtar.network.monitors.VideoFrameMonitor;
import ve.ucv.ciens.ccg.nxtar.utils.ProjectConstants;
import com.badlogic.gdx.Gdx;
public class VideoStreamingThread extends Thread {
public class VideoStreamingThread extends Thread{
public static final String THREAD_NAME = "VideoStreamingThread";
private static final String TAG = "NXTAR_CORE_VIDEOTHREAD";
private static final String CLASS_NAME = VideoStreamingThread.class.getSimpleName();
private static int refCount = 0;
private NetworkConnectionListener netListener;
private ServerSocket server;
private Socket client;
private Toaster toaster;
private ApplicationEventsListener netListener;
private DatagramSocket socket;
private boolean protocolStarted;
private boolean done;
private boolean pause;
private boolean coreNotified;
private Object protocolPauseMonitor;
private VideoFrameMonitor frameMonitor;
private long then;
private long now;
private long delta;
private int fps;
private int lostFramesPerSecond;
private int lostFrames;
private Object pauseMonitor;
private VideoStreamingThread(){
super(THREAD_NAME);
pauseMonitor = new Object();
fps = 0;
lostFramesPerSecond = 0;
netListener = null;
protocolStarted = false;
done = false;
coreNotified = false;
protocolPauseMonitor = new Object();
frameMonitor = VideoFrameMonitor.getInstance();
try{
server = new ServerSocket(ProjectConstants.SERVER_TCP_PORT_1);
socket = new DatagramSocket(ProjectConstants.VIDEO_STREAMING_PORT);
}catch(IOException io){
Gdx.app.error(TAG, CLASS_NAME + ".VideoStreamingThread() :: Error creating server: " + io.getMessage(), io);
}
}
private static class SingletonHolder{
public static final VideoStreamingThread INSTANCE = new VideoStreamingThread();
public static VideoStreamingThread INSTANCE;
}
public static VideoStreamingThread getInstance(){
if(refCount == 0)
SingletonHolder.INSTANCE = new VideoStreamingThread();
refCount++;
return SingletonHolder.INSTANCE;
}
public VideoStreamingThread setToaster(Toaster toaster){
this.toaster = toaster;
return this;
public static void freeInstance(){
refCount--;
if(refCount == 0) SingletonHolder.INSTANCE = null;
}
public void addNetworkConnectionListener(NetworkConnectionListener listener){
public void addNetworkConnectionListener(ApplicationEventsListener listener){
netListener = listener;
}
public void startStreaming(){
if(!protocolStarted){
Gdx.app.debug(TAG, CLASS_NAME + ".startStreaming() :: Requesting protocol start.");
synchronized(protocolPauseMonitor){
protocolStarted = true;
protocolPauseMonitor.notifyAll();
}
}
}
public void pauseStreaming(){
if(protocolStarted){
Gdx.app.debug(TAG, CLASS_NAME + ".pauseStreaming() :: Requesting protocol pause.");
}else
return;
}
public void resumeStreaming(){
if(protocolStarted){
Gdx.app.debug(TAG, CLASS_NAME + ".resumeStreaming() :: Requesting protocol resume.");
synchronized(protocolPauseMonitor){
protocolPauseMonitor.notifyAll();
}
}else
return;
}
public void finishStreaming(){
if(protocolStarted){
Gdx.app.debug(TAG, CLASS_NAME + ".finishStreaming() :: Requesting protocol end.");
}else
return;
}
public void finish(){
done = true;
}
private int byteArray2Int(byte[] array){
int number = 0;
for(int i = 0; i < 4; i++){
number |= (array[3-i] & 0xff) << (i << 3);
}
return number;
}
private void receiveUdp(){
try{
int intSize;
byte[] size = new byte[4];
byte[] data;
DatagramPacket packet;
VideoFrameDataMessage dataMessage;
Object tmpMessage;
//Gdx.app.debug(TAG, CLASS_NAME + ".receiveUdp() :: Reading message size from socket.");
try{
packet = new DatagramPacket(size, size.length);
socket.setSoTimeout(1000);
socket.receive(packet);
}catch(IOException io){
Gdx.app.error(TAG, CLASS_NAME + ".receiveUdp() :: IOException receiving size " + io.getMessage());
lostFramesPerSecond += 1;
return;
}
//Gdx.app.debug(TAG, CLASS_NAME + ".receiveUdp() :: Creating buffers.");
intSize = byteArray2Int(size);
data = new byte[intSize];
//Gdx.app.debug(TAG, CLASS_NAME + ".receiveUdp() :: Reading message from socket.");
try{
packet = new DatagramPacket(data, data.length);
socket.receive(packet);
}catch(IOException io){
Gdx.app.error(TAG, CLASS_NAME + ".receiveUdp() :: IOException receiving data " + io.getMessage());
lostFramesPerSecond += 1;
return;
}
ByteArrayInputStream bais = new ByteArrayInputStream(data);
//Gdx.app.debug(TAG, CLASS_NAME + ".receiveUdp() :: Saving message in monitor.");
try{
ObjectInputStream ois = new ObjectInputStream(bais);
tmpMessage = ois.readObject();
if(tmpMessage instanceof VideoFrameDataMessage){
//Gdx.app.debug(TAG, CLASS_NAME + ".receiveUdp() :: Received a data message.");
dataMessage = (VideoFrameDataMessage) tmpMessage;
//Gdx.app.debug(TAG, CLASS_NAME + ".receiveUdp() :: Received frame dimensions are: " + Integer.toString(dataMessage.imageWidth) + "x" + Integer.toString(dataMessage.imageHeight));
frameMonitor.setFrameDimensions(dataMessage.imageWidth, dataMessage.imageHeight);
frameMonitor.setNewFrame(dataMessage.data);
}else{
Gdx.app.debug(TAG, CLASS_NAME + ".receiveUdp() :: Received something unknown.");
lostFramesPerSecond += 1;
}
}catch(IOException io){
Gdx.app.error(TAG, CLASS_NAME + ".receiveUdp() :: IOException received deserializing message " + io.getMessage());
lostFramesPerSecond += 1;
return;
}catch(ClassNotFoundException cn){
Gdx.app.error(TAG, CLASS_NAME + ".receiveUdp() :: ClassNotFoundException received " + cn.getMessage());
lostFramesPerSecond += 1;
return;
}
}catch(Exception e){
Gdx.app.error(TAG, CLASS_NAME + ".receiveUdp() :: Exception received " + e.getMessage());
lostFramesPerSecond += 1;
return;
}
}
public int getFps(){
return fps;
}
public int getLostFrames(){
return lostFrames;
}
@Override
public void run(){
try{
client = server.accept();
if(netListener != null)
netListener.networkStreamConnected(THREAD_NAME);
toaster.showShortToast("Client connected to VideoStreamingThread");
client.close();
}catch(IOException io){
Gdx.app.error(TAG, CLASS_NAME + ".run() :: Error accepting client: " + io.getMessage(), io);
int frames = 0;
lostFrames = 0;
then = System.currentTimeMillis();
while(!done){
synchronized (pauseMonitor) {
while(pause){
try{ pauseMonitor.wait(); }catch(InterruptedException ie){ }
}
}
//Gdx.app.debug(TAG, CLASS_NAME + ".run() :: Receiving.");
if(netListener != null && !coreNotified && frameMonitor.getCurrentFrame() != null){
coreNotified = true;
netListener.onNetworkStreamConnected(THREAD_NAME);
}
receiveUdp();
frames++;
now = System.currentTimeMillis();
delta = now - then;
if(delta >= 1000){
fps = frames;
frames = 0;
lostFrames = lostFramesPerSecond;
lostFramesPerSecond = 0;
then = now;
delta = 0;
}
}
Gdx.app.debug(TAG, CLASS_NAME + ".run() :: Thread finished.");
}
public void pause(){
synchronized (pauseMonitor){
pause = true;
}
}
public void play(){
synchronized (pauseMonitor){
pause = false;
pauseMonitor.notifyAll();
}
}
}

View File

@@ -0,0 +1,72 @@
/*
* Copyright (C) 2014 Miguel Angel Astor Romero
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ve.ucv.ciens.ccg.nxtar.network.monitors;
import java.util.LinkedList;
import java.util.Queue;
import ve.ucv.ciens.ccg.networkdata.MotorEvent;
/**
* <p>A simple monitor class that encapsulates a queue.</p>
* <p>As it name says it stores motor events to be forwarded to the NXT robot.</p>
* <p>This class implements the singleton design pattern.<p>
*
* @author Miguel Angel Astor Romero
*/
public class MotorEventQueue{
/**
* The event queue implemented as a linked list.
*/
private Queue<MotorEvent> motorEvents;
private MotorEventQueue(){
motorEvents = new LinkedList<MotorEvent>();
}
private static class SingletonHolder{
public static final MotorEventQueue instance = new MotorEventQueue();
}
/**
* Return the singleton instance of this class.
* @return The singleton instance.
*/
public static MotorEventQueue getInstance(){
return SingletonHolder.instance;
}
/**
* <p>Get the first event on the queue.</p>
* <p> If there are no events to return this method blocks until some thread calls the addEvent() method.</p>
* @return The event at the front of the queue.
*/
public synchronized MotorEvent getNextEvent(){
while(motorEvents.size() == 0){
try{ wait(); }catch(InterruptedException ie){ }
}
return motorEvents.poll();
}
/**
* <p>Adds an event to the back of the queue.</p>
* @param event The event to add.
*/
public synchronized void addEvent(MotorEvent event){
motorEvents.add(event);
notifyAll();
}
}

View File

@@ -0,0 +1,80 @@
/*
* Copyright (C) 2013 Miguel Angel Astor Romero
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ve.ucv.ciens.ccg.nxtar.network.monitors;
import ve.ucv.ciens.ccg.nxtar.utils.Size;
import com.badlogic.gdx.Gdx;
public class VideoFrameMonitor{
private final String TAG = "VIDEO_FRAME_MONITOR";
private final String CLASS_NAME = VideoFrameMonitor.class.getSimpleName();
private byte[] frameA;
private byte[] frameB;
private Object frameMonitor;
private Size frameDimensions;
private VideoFrameMonitor(){
frameA = null;
frameB = null;
frameMonitor = new Object();
frameDimensions = new Size();
}
private static class SingletonHolder{
public static final VideoFrameMonitor INSTANCE = new VideoFrameMonitor();
}
public static VideoFrameMonitor getInstance(){
return SingletonHolder.INSTANCE;
}
public void setFrameDimensions(int width, int height){
try{
frameDimensions.setWidth(width);
frameDimensions.setHeight(height);
}catch(IllegalArgumentException ia){
Gdx.app.debug(TAG, CLASS_NAME + ".setFrameDimensions() :: Bad argument to Size: " + ia.getMessage());
frameDimensions.setWidth(0);
frameDimensions.setHeight(0);
}
}
public Size getFrameDimensions(){
return frameDimensions;
}
public void setNewFrame(byte[] frame){
byte[] temp;
frameA = frame;
temp = frameA;
synchronized(frameMonitor){
frameA = frameB;
frameB = temp;
}
}
public byte[] getCurrentFrame(){
byte[] frame;
synchronized(frameMonitor){
frame = frameB;
}
return frame;
}
}

View File

@@ -0,0 +1,41 @@
/*
* Copyright (C) 2014 Miguel Angel Astor Romero
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ve.ucv.ciens.ccg.nxtar.scenarios;
import ve.ucv.ciens.ccg.nxtar.interfaces.ImageProcessor.MarkerData;
public abstract class AutomaticActionPerformerBase {
public enum automatic_action_t{
NO_ACTION,
GO_FORWARD,
GO_BACKWARDS,
STOP,
TURN_LEFT,
TURN_RIGHT,
BACKWARDS_LEFT,
BACKWARDS_RIGHT,
ROTATE_90,
RECENTER,
LOOK_RIGHT,
LOOK_LEFT,
STOP_LOOKING;
}
public abstract boolean performAutomaticAction(int lightSensorReading, MarkerData markers);
public abstract automatic_action_t getNextAction();
public abstract SummaryBase getSummary();
public abstract void reset();
}

View File

@@ -0,0 +1,31 @@
/*
* Copyright (C) 2014 Miguel Angel Astor Romero
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ve.ucv.ciens.ccg.nxtar.scenarios;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.utils.Disposable;
/**
* <p>Base class for hint screens.</p>
*/
public abstract class HintsOverlayBase implements Disposable{
/**
* <p>Renders the overlay.</p>
*
* @param batch The {@link SpriteBatch} to use for rendering.
*/
public abstract void render(SpriteBatch batch);
}

View File

@@ -0,0 +1,249 @@
/*
* Copyright (C) 2014 Miguel Angel Astor Romero
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ve.ucv.ciens.ccg.nxtar.scenarios;
import ve.ucv.ciens.ccg.nxtar.NxtARCore;
import ve.ucv.ciens.ccg.nxtar.entities.EntityCreatorBase;
import ve.ucv.ciens.ccg.nxtar.systems.AnimationSystem;
import ve.ucv.ciens.ccg.nxtar.systems.CollisionDetectionSystem;
import ve.ucv.ciens.ccg.nxtar.systems.FadeEffectRenderingSystem;
import ve.ucv.ciens.ccg.nxtar.systems.GameLogicSystemBase;
import ve.ucv.ciens.ccg.nxtar.systems.GeometrySystem;
import ve.ucv.ciens.ccg.nxtar.systems.MarkerPositioningSystem;
import ve.ucv.ciens.ccg.nxtar.systems.MarkerRenderingSystem;
import ve.ucv.ciens.ccg.nxtar.systems.RobotArmRenderingSystem;
import ve.ucv.ciens.ccg.nxtar.systems.PlayerSystemBase;
import ve.ucv.ciens.ccg.nxtar.systems.RobotArmPositioningSystem;
import com.artemis.EntitySystem;
import com.artemis.World;
import com.artemis.managers.GroupManager;
import com.artemis.utils.ImmutableBag;
import com.badlogic.gdx.graphics.g3d.ModelBatch;
import com.badlogic.gdx.utils.Disposable;
public abstract class ScenarioGlobals{
private static EntityCreatorBase entityCreator = null;
private static GameLogicSystemBase gameLogicSystem = null;
private static World gameWorld = null;
private static ModelBatch modelBatch = null;
private static AutomaticActionPerformerBase automaticActionPerformer = null;
private static SummaryOverlayBase automaticActionSummaryOverlay = null;
private static PlayerSystemBase playerSystem = null;
private static SummaryOverlayBase scenarioSummaryOverlay = null;
private static HintsOverlayBase hintsOverlay = null;
public static void init(NxtARCore core) throws IllegalArgumentException, InstantiationException, IllegalAccessException{
if(core == null)
throw new IllegalArgumentException("Core is null.");
if(modelBatch == null)
modelBatch = new ModelBatch();
if(gameWorld == null){
gameWorld = new World();
gameWorld.setManager(new GroupManager());
}
if(entityCreator == null){
try {
entityCreator = (EntityCreatorBase) ScenarioImplementation.entityCreatorClass.newInstance();
} catch (InstantiationException e) {
System.out.println("Error instantiating entity creator.");
throw e;
} catch (IllegalAccessException e) {
System.out.println("Error accessing entity creator.");
throw e;
}
entityCreator.setWorld(gameWorld);
entityCreator.setCore(core);
}
if(gameLogicSystem == null){
try {
gameLogicSystem = (GameLogicSystemBase) ScenarioImplementation.gameLogicSystemClass.newInstance();
} catch (InstantiationException e) {
System.out.println("Error instantiating game logic system.");
throw e;
} catch (IllegalAccessException e) {
System.out.println("Error accessing game logic system.");
throw e;
}
}
if(automaticActionPerformer == null){
try {
automaticActionPerformer = (AutomaticActionPerformerBase) ScenarioImplementation.automaticActionPerformerClass.newInstance();
} catch (InstantiationException e) {
System.out.println("Error instantiating automatic action performer.");
throw e;
} catch (IllegalAccessException e) {
System.out.println("Error accessing automatic action performer.");
throw e;
}
}
if(automaticActionSummaryOverlay == null){
try {
automaticActionSummaryOverlay = (SummaryOverlayBase) ScenarioImplementation.automaticActionSummaryOverlay.newInstance();
} catch (InstantiationException e) {
System.out.println("Error instantiating automatic action summary overlay");
throw e;
} catch (IllegalAccessException e) {
System.out.println("Error accessing automatic action summary overlay.");
throw e;
}
}
if(playerSystem == null){
try {
playerSystem = (PlayerSystemBase) ScenarioImplementation.playerSystemClass.newInstance();
} catch (InstantiationException e) {
System.out.println("Error instantiating player system.");
throw e;
} catch (IllegalAccessException e) {
System.out.println("Error accessing player system.");
throw e;
}
}
if(scenarioSummaryOverlay == null){
try {
scenarioSummaryOverlay = (SummaryOverlayBase) ScenarioImplementation.scenarioSummaryOverlayClass.newInstance();
} catch (InstantiationException e) {
System.out.println("Error instantiating scenario summary overlay.");
throw e;
} catch (IllegalAccessException e) {
System.out.println("Error accessing scenario summary overlay.");
throw e;
}
}
if(hintsOverlay == null){
try {
hintsOverlay = (HintsOverlayBase) ScenarioImplementation.hintsOverlayClass.newInstance();
} catch (InstantiationException e) {
System.out.println("Error instantiating hints overlay.");
throw e;
} catch (IllegalAccessException e) {
System.out.println("Error accessing hints overlay.");
throw e;
}
}
playerSystem.setCore(core);
gameWorld.setSystem(new MarkerPositioningSystem());
gameWorld.setSystem(new RobotArmPositioningSystem());
gameWorld.setSystem(new GeometrySystem());
gameWorld.setSystem(new AnimationSystem());
gameWorld.setSystem(new CollisionDetectionSystem());
gameWorld.setSystem(gameLogicSystem);
gameWorld.setSystem(playerSystem, true);
gameWorld.setSystem(new MarkerRenderingSystem(modelBatch), true);
gameWorld.setSystem(new RobotArmRenderingSystem(modelBatch), true);
gameWorld.setSystem(new FadeEffectRenderingSystem(), true);
gameWorld.initialize();
}
public static void dispose() throws IllegalStateException{
ImmutableBag<EntitySystem> systems;
if(entityCreator == null || gameWorld == null || gameLogicSystem == null || automaticActionPerformer == null || automaticActionSummaryOverlay == null)
throw new IllegalStateException("Calling dispose before init or after previous dispose.");
systems = gameWorld.getSystems();
for(int i = 0; i < systems.size(); i++){
if(systems.get(i) instanceof Disposable){
((Disposable)systems.get(i)).dispose();
}
}
scenarioSummaryOverlay.dispose();
automaticActionSummaryOverlay.dispose();
entityCreator.dispose();
hintsOverlay.dispose();
entityCreator = null;
gameLogicSystem = null;
gameWorld = null;
automaticActionPerformer = null;
automaticActionSummaryOverlay = null;
playerSystem = null;
scenarioSummaryOverlay = null;
hintsOverlay = null;
System.gc();
}
public static EntityCreatorBase getEntityCreator() throws IllegalStateException{
if(entityCreator == null)
throw new IllegalStateException("Calling getEntityCreator() before init.");
return entityCreator;
}
public static GameLogicSystemBase getGameLogicSystem() throws IllegalStateException{
if(gameLogicSystem == null)
throw new IllegalStateException("Calling getGameLogicSystem() before init.");
return gameLogicSystem;
}
public static World getGameWorld() throws IllegalStateException{
if(gameWorld == null)
throw new IllegalStateException("Calling getGameWorld() before init.");
return gameWorld;
}
public static AutomaticActionPerformerBase getAutomaticActionPerformer() throws IllegalStateException{
if(automaticActionPerformer == null)
throw new IllegalStateException("Calling getAutomaticActionPerformer() before init.");
return automaticActionPerformer;
}
public static SummaryOverlayBase getAutomaticActionSummaryOverlay() throws IllegalStateException{
if(automaticActionSummaryOverlay == null)
throw new IllegalStateException("Calling getAutomaticActionSummaryOverlay() before init.");
return automaticActionSummaryOverlay;
}
public static PlayerSystemBase getPlayerSystem() throws IllegalStateException{
if(playerSystem == null)
throw new IllegalStateException("Calling getPlayerSystem() before init.");
return playerSystem;
}
public static SummaryOverlayBase getScenarioSummaryOverlay() throws IllegalStateException{
if(scenarioSummaryOverlay == null)
throw new IllegalStateException("Calling getScenarioSummaryOverlay() before init.");
return scenarioSummaryOverlay;
}
public static HintsOverlayBase getHintsOverlay() throws IllegalStateException{
if(hintsOverlay == null)
throw new IllegalStateException("Calling getHintsOverlay() before init.");
return hintsOverlay;
}
}

View File

@@ -0,0 +1,37 @@
/*
* Copyright (C) 2014 Miguel Angel Astor Romero
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ve.ucv.ciens.ccg.nxtar.scenarios;
import ve.ucv.ciens.ccg.nxtar.scenarios.bombgame.BombGameAutomaticActionPerformer;
import ve.ucv.ciens.ccg.nxtar.scenarios.bombgame.BombGameAutomaticActionSummaryOverlay;
import ve.ucv.ciens.ccg.nxtar.scenarios.bombgame.BombGameEntityCreator;
import ve.ucv.ciens.ccg.nxtar.scenarios.bombgame.BombGameInstructionsOverlay;
import ve.ucv.ciens.ccg.nxtar.scenarios.bombgame.BombGameLogicSystem;
import ve.ucv.ciens.ccg.nxtar.scenarios.bombgame.BombGamePlayerSystem;
import ve.ucv.ciens.ccg.nxtar.scenarios.bombgame.BombGameScenarioEndingOverlay;
@SuppressWarnings("rawtypes")
public final class ScenarioImplementation{
public static final Class gameLogicSystemClass = BombGameLogicSystem.class;
public static final Class entityCreatorClass = BombGameEntityCreator.class;
public static final Class automaticActionPerformerClass = BombGameAutomaticActionPerformer.class;
public static final Class automaticActionSummaryOverlay = BombGameAutomaticActionSummaryOverlay.class;
public static final Class playerSystemClass = BombGamePlayerSystem.class;
public static final Class scenarioSummaryOverlayClass = BombGameScenarioEndingOverlay.class;
public static final Class hintsOverlayClass = BombGameInstructionsOverlay.class;
private ScenarioImplementation(){}
}

View File

@@ -0,0 +1,20 @@
/*
* Copyright (C) 2014 Miguel Angel Astor Romero
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ve.ucv.ciens.ccg.nxtar.scenarios;
public abstract class SummaryBase{
public abstract void reset();
}

View File

@@ -0,0 +1,31 @@
/*
* Copyright (C) 2014 Miguel Angel Astor Romero
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ve.ucv.ciens.ccg.nxtar.scenarios;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.utils.Disposable;
/**
* <p>Base class for summary screens. Just renders a summary overlay.</p>
*/
public abstract class SummaryOverlayBase implements Disposable{
/**
* <p>Renders the overlay.</p>
*
* @param batch The {@link SpriteBatch} to use for rendering.
*/
public abstract void render(SpriteBatch batch, SummaryBase summary);
}

View File

@@ -0,0 +1,50 @@
/*
* Copyright (C) 2014 Miguel Angel Astor Romero
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ve.ucv.ciens.ccg.nxtar.scenarios.bombgame;
import com.artemis.Component;
public class BombComponent extends Component {
public enum bomb_type_t{
COMBINATION(0), INCLINATION(1), WIRES(2);
private int value;
private bomb_type_t(int value){
this.value = value;
}
public int getValue(){
return this.value;
}
};
public int id;
public bomb_type_t bombType;
public boolean enabled;
public BombComponent(int id, bomb_type_t bomb_type){
this.id = id;
this.bombType = bomb_type;
this.enabled = true;
}
public BombComponent(BombComponent bomb){
this.id = bomb.id;
this.bombType = bomb.bombType;
this.enabled = bomb.enabled;
}
}

View File

@@ -0,0 +1,300 @@
/*
* Copyright (C) 2014 Miguel Angel Astor Romero
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ve.ucv.ciens.ccg.nxtar.scenarios.bombgame;
import java.util.LinkedList;
import java.util.List;
import ve.ucv.ciens.ccg.nxtar.interfaces.ImageProcessor.MarkerData;
import ve.ucv.ciens.ccg.nxtar.scenarios.AutomaticActionPerformerBase;
import ve.ucv.ciens.ccg.nxtar.scenarios.ScenarioGlobals;
import ve.ucv.ciens.ccg.nxtar.scenarios.SummaryBase;
import ve.ucv.ciens.ccg.nxtar.utils.ProjectConstants;
import com.artemis.Entity;
import com.artemis.World;
import com.artemis.managers.GroupManager;
import com.artemis.utils.ImmutableBag;
import com.badlogic.gdx.Gdx;
public class BombGameAutomaticActionPerformer extends AutomaticActionPerformerBase {
private static final String TAG = "BOMB_GAME_AUTO_PERFORMER";
private static final String CLASS_NAME = BombGameAutomaticActionPerformer.class.getSimpleName();
private static final int MARKER_NEARBY_FLOOR_MIN_LUMINANCE = 50;
private enum action_state_t{
START, WALK_FORWARD, DETECT_MARKER, FINISHING, END;
}
public class BombGameAutomaticActionSummary extends SummaryBase{
private int numCombinationBombs;
private int numInclinationBombs;
private int numWireBombs;
private int totalBombs;
public BombGameAutomaticActionSummary(){
reset();
}
public int getNumCombinationBombs() {
return numCombinationBombs;
}
public int getNumInclinationBombs() {
return numInclinationBombs;
}
public int getNumWireBombs() {
return numWireBombs;
}
public void addCombinationBomb(){
numCombinationBombs++;
totalBombs++;
}
public void addInclinationBomb(){
numInclinationBombs++;
totalBombs++;
}
public void addWireBomb(){
numWireBombs++;
totalBombs++;
}
public int getBombsSeen(){
return totalBombs;
}
@Override
public void reset() {
this.numCombinationBombs = 0;
this.numInclinationBombs = 0;
this.numWireBombs = 0;
this.totalBombs = 0;
}
}
private automatic_action_t nextAction;
private action_state_t state;
private List<Integer> detectedMarkers;
private float then;
private float now;
private int stops;
private GroupManager manager;
private BombGameAutomaticActionSummary summary;
public BombGameAutomaticActionPerformer(){
nextAction = automatic_action_t.NO_ACTION;
state = action_state_t.START;
detectedMarkers = new LinkedList<Integer>();
then = 0.0f;
now = 0.0f;
manager = null;
summary = new BombGameAutomaticActionSummary();
}
@Override
public boolean performAutomaticAction(int lightSensorReading, MarkerData markers) throws IllegalStateException, IllegalArgumentException{
BombComponent bomb;
boolean finish = false;
boolean markerAlreadyDetected = false;
int detectedCode = -1;
ImmutableBag<Entity> entities = null;
float deltaT;
World world;
if(manager == null){
world = ScenarioGlobals.getGameWorld();
if(world == null)
throw new IllegalStateException("World is null after getGameWorld().");
manager = world.getManager(GroupManager.class);
if(manager == null)
throw new IllegalStateException("World has no group managers.");
}
if(markers == null)
throw new IllegalArgumentException("Markers is null");
switch(state){
case START:
Gdx.app.log(TAG, CLASS_NAME + ".performAutomaticAction(): State is START.");
// Reset everything, then look to the left and start moving forward.
this.reset();
nextAction = automatic_action_t.ROTATE_90;
state = action_state_t.WALK_FORWARD;
finish = false;
break;
case WALK_FORWARD:
Gdx.app.log(TAG, CLASS_NAME + ".performAutomaticAction(): State is WALK_FORWARD.");
// Check if all stops have been found.
if(stops >= BombGameEntityCreator.NUM_BOMBS){
// If all stops have been found then stop the robot and finish the automatic action.
Gdx.app.log(TAG, CLASS_NAME + ".performAutomaticAction(): Found goal.");
nextAction = automatic_action_t.STOP;
state = action_state_t.FINISHING;
}else{
// If there are stops to be found yet then check if the light sensor found a stop.
if(lightSensorReading >= MARKER_NEARBY_FLOOR_MIN_LUMINANCE){
// If a stop have been found then check if there is a marker nearby.
Gdx.app.log(TAG, CLASS_NAME + ".performAutomaticAction(): There is a marker nearby.");
nextAction = automatic_action_t.STOP;
state = action_state_t.DETECT_MARKER;
then = Gdx.graphics.getDeltaTime();
}else{
// If the light sensor didn't find a stop the keep moving.
Gdx.app.log(TAG, CLASS_NAME + ".performAutomaticAction(): Walking.");
nextAction = automatic_action_t.GO_FORWARD;
}
}
finish = false;
break;
case DETECT_MARKER:
Gdx.app.log(TAG, CLASS_NAME + ".performAutomaticAction(): State is DETECT_MARKER.");
for(int i = 0; !markerAlreadyDetected && i < ProjectConstants.MAXIMUM_NUMBER_OF_MARKERS; i++){
// Check if this marker has not been detected already.
for(Integer code : detectedMarkers){
if(markers.markerCodes[i] == code){
Gdx.app.log(TAG, CLASS_NAME + ".performAutomaticAction(): Marker already detected.");
markerAlreadyDetected = true;
break;
}
}
// If the marker has not been detected before then examine it.
if(!markerAlreadyDetected){
Gdx.app.log(TAG, CLASS_NAME + ".performAutomaticAction(): New marker detected.");
detectedCode = markers.markerCodes[i];
entities = manager.getEntities(Integer.toString(detectedCode));
for(int e = 0; entities != null && e < entities.size() && entities.get(e) != null; e++){
bomb = entities.get(e).getComponent(BombComponent.class);
if(bomb == null){
Gdx.app.log(TAG, CLASS_NAME + ".performAutomaticAction(): Entity has no bomb component. Skipping.");
}else{
Gdx.app.log(TAG, CLASS_NAME + ".performAutomaticAction(): Adding bomb.");
switch(bomb.bombType){
case COMBINATION:
summary.addCombinationBomb();
break;
case INCLINATION:
summary.addInclinationBomb();
break;
case WIRES:
summary.addWireBomb();
break;
default:
throw new IllegalStateException("Unrecognized bomb type.");
}
break;
}
}
break;
}
}
// If found a marker and it has not been detected before then add it to the detected markers list.
if(!markerAlreadyDetected && detectedCode != -1)
detectedMarkers.add(detectedCode);
if(lightSensorReading < MARKER_NEARBY_FLOOR_MIN_LUMINANCE){
Gdx.app.log(TAG, CLASS_NAME + ".performAutomaticAction(): Switching to WALK_FORWARD.");
// If cleared the stop mark on the floor then start moving is search for the next mark.
state = action_state_t.WALK_FORWARD;
nextAction = automatic_action_t.STOP;
then = 0.0f;
now = 0.0f;
stops++;
}else{
Gdx.app.log(TAG, CLASS_NAME + ".performAutomaticAction(): Clearing MARKER_NEARBY_FLOOR.");
// Wait for two seconds to make sure the marker can be correctly detected.
now += Gdx.graphics.getDeltaTime();
deltaT = now - then;
if(deltaT >= 2.0f){
nextAction = automatic_action_t.GO_FORWARD;
then = Gdx.graphics.getDeltaTime();
now = 0.0f;
}
}
finish = false;
break;
case FINISHING:
Gdx.app.log(TAG, CLASS_NAME + ".performAutomaticAction(): State is FINISHING.");
// Recenter the camera.
state = action_state_t.END;
nextAction = automatic_action_t.RECENTER;
finish = false;
break;
case END:
Gdx.app.log(TAG, CLASS_NAME + ".performAutomaticAction(): State is END.");
// Finish the automatic action.
nextAction = automatic_action_t.NO_ACTION;
state = action_state_t.START;
finish = true;
break;
default:
throw new IllegalStateException("Unknown automatic action state.");
}
return finish;
}
@Override
public automatic_action_t getNextAction() {
switch(nextAction){
default:
case NO_ACTION:
return automatic_action_t.NO_ACTION;
case GO_BACKWARDS:
return automatic_action_t.GO_BACKWARDS;
case GO_FORWARD:
return automatic_action_t.GO_FORWARD;
case STOP:
return automatic_action_t.STOP;
case ROTATE_90:
return automatic_action_t.ROTATE_90;
case RECENTER:
return automatic_action_t.RECENTER;
}
}
@Override
public SummaryBase getSummary() {
return (SummaryBase)summary;
}
@Override
public void reset() {
Gdx.app.log(TAG, CLASS_NAME + ".reset(): Reset requested.");
detectedMarkers.clear();
summary.reset();
state = action_state_t.START;
nextAction = automatic_action_t.NO_ACTION;
then = 0.0f;
stops = 0;
}
}

View File

@@ -0,0 +1,137 @@
/*
* Copyright (C) 2014 Miguel Angel Astor Romero
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ve.ucv.ciens.ccg.nxtar.scenarios.bombgame;
import ve.ucv.ciens.ccg.nxtar.scenarios.SummaryBase;
import ve.ucv.ciens.ccg.nxtar.scenarios.SummaryOverlayBase;
import ve.ucv.ciens.ccg.nxtar.scenarios.bombgame.BombGameAutomaticActionPerformer.BombGameAutomaticActionSummary;
import ve.ucv.ciens.ccg.nxtar.utils.ProjectConstants;
import ve.ucv.ciens.ccg.nxtar.utils.Utils;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.controllers.mappings.Ouya;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator;
import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator.FreeTypeFontParameter;
public class BombGameAutomaticActionSummaryOverlay extends SummaryOverlayBase{
private static final float CANNONICAL_SCREEN_WIDTH = 800.0f;
private Texture inclinationBombTexture;
private Texture combinationBombTexture;
private Texture wireBombTexture;
private BitmapFont font;
private BitmapFont titleFont;
private Sprite inclinationBomb;
private Sprite combinationBomb;
private Sprite wireBomb;
private float inclinationX;
private float combinationX;
private float wireX;
private float inclinationY;
private float combinationY;
private float wireY;
private float titleWidth;
private float titleHeight;
public BombGameAutomaticActionSummaryOverlay(){
FreeTypeFontGenerator fontGenerator;
FreeTypeFontParameter fontParameters;
inclinationBombTexture = new Texture(Gdx.files.internal("data/gfx/bomb_game/incl_bomb.png"));
combinationBombTexture = new Texture(Gdx.files.internal("data/gfx/bomb_game/comb_bomb.png"));
wireBombTexture = new Texture(Gdx.files.internal("data/gfx/bomb_game/wire_bomb.png"));
inclinationBomb = new Sprite(inclinationBombTexture);
combinationBomb = new Sprite(combinationBombTexture);
wireBomb = new Sprite(wireBombTexture);
inclinationBomb.setSize(inclinationBomb.getWidth() * 0.5f, inclinationBomb.getHeight() * 0.5f);
combinationBomb.setSize(combinationBomb.getWidth() * 0.5f, combinationBomb.getHeight() * 0.5f);
wireBomb.setSize(wireBomb.getWidth() * 0.5f, wireBomb.getHeight() * 0.5f);
combinationBomb.setPosition(-(Utils.getScreenWidthWithOverscan() / 4.0f) - combinationBomb.getWidth(), -(combinationBomb.getHeight() / 2.0f));
inclinationBomb.setPosition(-(Utils.getScreenWidthWithOverscan() / 4.0f) - inclinationBomb.getWidth(), combinationBomb.getY() + combinationBomb.getHeight() + 10.0f);
wireBomb.setPosition(-(Utils.getScreenWidthWithOverscan() / 4.0f) - wireBomb.getWidth(), combinationBomb.getY() - wireBomb.getHeight() - 10.0f);
fontParameters = new FreeTypeFontParameter();
fontParameters.characters = ProjectConstants.FONT_CHARS;
if(!Ouya.runningOnOuya)
fontParameters.size = (int)((float)ProjectConstants.MENU_BUTTON_FONT_SIZE * ((float)Gdx.graphics.getWidth() / CANNONICAL_SCREEN_WIDTH));
else
fontParameters.size = ProjectConstants.MENU_BUTTON_FONT_SIZE;
fontParameters.flip = false;
fontGenerator = new FreeTypeFontGenerator(Gdx.files.internal("data/fonts/d-puntillas-B-to-tiptoe.ttf"));
font = fontGenerator.generateFont(fontParameters);
font.setColor(Color.YELLOW);
fontParameters.size = (int)(90.0f * ((float)Gdx.graphics.getWidth() / CANNONICAL_SCREEN_WIDTH));
titleFont = fontGenerator.generateFont(fontParameters);
fontGenerator.dispose();
inclinationX = inclinationBomb.getX() + inclinationBomb.getWidth() + 15.0f;
combinationX = combinationBomb.getX() + combinationBomb.getWidth() + 15.0f;
wireX = wireBomb.getX() + wireBomb.getWidth() + 15.0f;
inclinationY = inclinationBomb.getY() + (inclinationBomb.getWidth() / 2.0f) - (font.getCapHeight() / 2.0f);
combinationY = combinationBomb.getY() + (combinationBomb.getWidth() / 2.0f) - (font.getCapHeight() / 2.0f);
wireY = wireBomb.getY() + (wireBomb.getWidth() / 2.0f) - (font.getCapHeight() / 2.0f);
titleWidth = titleFont.getBounds("Summary").width;
titleHeight = titleFont.getBounds("Summary").height;
}
@Override
public void dispose() {
inclinationBombTexture.dispose();
combinationBombTexture.dispose();
wireBombTexture.dispose();
font.dispose();
titleFont.dispose();
}
@Override
public void render(SpriteBatch batch, SummaryBase summary) throws ClassCastException{
BombGameAutomaticActionSummary bombGameSummary;
if(!(summary instanceof BombGameAutomaticActionSummary))
throw new ClassCastException("Summary is not a bomb game summary.");
bombGameSummary = (BombGameAutomaticActionSummary)summary;
inclinationBomb.draw(batch);
combinationBomb.draw(batch);
wireBomb.draw(batch);
font.draw(batch, String.format("Inclination bombs: %d", bombGameSummary.getNumInclinationBombs()), inclinationX, inclinationY);
font.draw(batch, String.format("Combination bombs: %d", bombGameSummary.getNumCombinationBombs()), combinationX, combinationY);
font.draw(batch, String.format("Wire bombs: %d", bombGameSummary.getNumWireBombs()), wireX, wireY);
font.draw(batch, "Bombs found: " + bombGameSummary.getBombsSeen(), wireX, inclinationY + inclinationBomb.getHeight() + font.getCapHeight() + 20.0f);
font.draw(batch, "Bombs expected: " + BombGameEntityCreator.NUM_BOMBS, wireX, inclinationY + inclinationBomb.getHeight() + 10.0f);
if(!Ouya.runningOnOuya)
titleFont.draw(batch, "Summary", -(titleWidth / 2), (Utils.getScreenHeightWithOverscan() / 2) - titleHeight - 10);
else
titleFont.draw(batch, "Summary", -(titleWidth / 2), (Utils.getScreenHeightWithOverscan() / 2) - 10);
}
}

View File

@@ -0,0 +1,499 @@
/*
* Copyright (C) 2014 Miguel Angel Astor Romero
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ve.ucv.ciens.ccg.nxtar.scenarios.bombgame;
import java.util.LinkedList;
import java.util.List;
import ve.ucv.ciens.ccg.nxtar.components.AnimationComponent;
import ve.ucv.ciens.ccg.nxtar.components.AutomaticMovementComponent;
import ve.ucv.ciens.ccg.nxtar.components.CollisionDetectionComponent;
import ve.ucv.ciens.ccg.nxtar.components.CollisionModelComponent;
import ve.ucv.ciens.ccg.nxtar.components.EnvironmentComponent;
import ve.ucv.ciens.ccg.nxtar.components.GeometryComponent;
import ve.ucv.ciens.ccg.nxtar.components.MarkerCodeComponent;
import ve.ucv.ciens.ccg.nxtar.components.PlayerComponentBase;
import ve.ucv.ciens.ccg.nxtar.components.RenderModelComponent;
import ve.ucv.ciens.ccg.nxtar.components.ShaderComponent;
import ve.ucv.ciens.ccg.nxtar.components.VisibilityComponent;
import ve.ucv.ciens.ccg.nxtar.entities.EntityCreatorBase;
import ve.ucv.ciens.ccg.nxtar.graphics.shaders.DirectionalLightPerPixelShader;
import ve.ucv.ciens.ccg.nxtar.scenarios.bombgame.BombComponent.bomb_type_t;
import ve.ucv.ciens.ccg.nxtar.systems.AnimationSystem;
import ve.ucv.ciens.ccg.nxtar.systems.CollisionDetectionSystem;
import com.artemis.Entity;
import com.artemis.managers.GroupManager;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.assets.AssetManager;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.g3d.Environment;
import com.badlogic.gdx.graphics.g3d.Model;
import com.badlogic.gdx.graphics.g3d.ModelInstance;
import com.badlogic.gdx.graphics.g3d.Shader;
import com.badlogic.gdx.graphics.g3d.attributes.ColorAttribute;
import com.badlogic.gdx.graphics.g3d.environment.DirectionalLight;
import com.badlogic.gdx.math.Matrix3;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.utils.GdxRuntimeException;
public class BombGameEntityCreator extends EntityCreatorBase{
private static final String TAG = "BOMB_ENTITY_CREATOR";
private static final String CLASS_NAME = BombGameEntityCreator.class.getSimpleName();
private static final boolean DEBUG_RENDER_BOMB_COLLISION_MODELS = false;
private static final boolean DEBUG_RENDER_DOOR_COLLISION_MODELS = false;
private static final boolean DEBUG_RENDER_PARAPHERNALIA_COLLISION_MODELS = false;
public static final String DOORS_GROUP = "DOORS";
public static final Vector3 ROBOT_ARM_START_POINT = new Vector3(0.0f, 0.0f, -1.0f);
public static final int DOOR_OPEN_ANIMATION = 1;
public static final int DOOR_CLOSE_ANIMATION = 0;
public static int NUM_BOMBS = 0;
private class EntityParameters{
public Environment environment;
public Shader shader;
public int markerCode;
public int nextAnimation;
public boolean loopAnimation;
public EntityParameters(){
environment = new Environment();
shader = null;
markerCode = -1;
nextAnimation = -1;
loopAnimation = false;
}
}
private Shader shader;
private int currentBombId;
private GroupManager groupManager;
private List<Entity> entities;
private Entity player;
// Render models.
private Model robotArmModel = null;
private Model doorModel = null;
private Model doorFrameModel = null;
private Model combinationBombModel = null;
private Model combinationButton1Model = null;
private Model combinationButton2Model = null;
private Model combinationButton3Model = null;
private Model combinationButton4Model = null;
private Model inclinationBombModel = null;
private Model inclinationBombButtonModel = null;
private Model wiresBombModel = null;
private Model wiresBombModelWire1 = null;
private Model wiresBombModelWire2 = null;
private Model wiresBombModelWire3 = null;
private Model monkeyModel = null;
// Collision models.
private Model robotArmCollisionModel = null;
private Model doorCollisionModel = null;
private Model doorFrameCollisionModel = null;
private Model combinationBombCollisionModel = null;
private Model combinationButton1CollisionModel = null;
private Model combinationButton2CollisionModel = null;
private Model combinationButton3CollisionModel = null;
private Model combinationButton4CollisionModel = null;
private Model inclinationBombCollisionModel = null;
private Model inclinationBombButtonCollisionModel = null;
private Model wiresBombCollisionModel = null;
private Model wiresBombCollisionModelWire1 = null;
private Model wiresBombCollisionModelWire2 = null;
private Model wiresBombCollisionModelWire3 = null;
public BombGameEntityCreator(){
currentBombId = 0;
manager = new AssetManager();
entities = new LinkedList<Entity>();
player = null;
// Load the shader.
shader = new DirectionalLightPerPixelShader();
try{
shader.init();
}catch(GdxRuntimeException gdx){
Gdx.app.error(TAG, CLASS_NAME + ".BombGameEntityCreator(): Shader failed to load: " + gdx.getMessage());
shader = null;
}
// Load the render models.
manager.load("models/render_models/bomb_game/robot_arm.g3db", Model.class);
manager.load("models/render_models/bomb_game/door.g3db", Model.class);
manager.load("models/render_models/bomb_game/door_frame1.g3db", Model.class);
manager.load("models/render_models/bomb_game/bomb_3_body.g3db", Model.class);
manager.load("models/render_models/bomb_game/bomb_3_btn_1.g3db", Model.class);
manager.load("models/render_models/bomb_game/bomb_3_btn_2.g3db", Model.class);
manager.load("models/render_models/bomb_game/bomb_3_btn_3.g3db", Model.class);
manager.load("models/render_models/bomb_game/bomb_3_btn_4.g3db", Model.class);
manager.load("models/render_models/bomb_game/bomb_2_body.g3db", Model.class);
manager.load("models/render_models/bomb_game/big_btn.g3db", Model.class);
manager.load("models/render_models/bomb_game/bomb_1_body.g3db", Model.class);
manager.load("models/render_models/bomb_game/cable_1.g3db", Model.class);
manager.load("models/render_models/bomb_game/cable_2.g3db", Model.class);
manager.load("models/render_models/bomb_game/cable_3.g3db", Model.class);
manager.load("models/render_models/bomb_game/monkey.g3db", Model.class);
// Load the collision models.
manager.load("models/collision_models/bomb_game/robot_arm_col.g3db", Model.class);
manager.load("models/collision_models/bomb_game/door_col.g3db", Model.class);
manager.load("models/collision_models/bomb_game/door_frame1_col.g3db", Model.class);
manager.load("models/collision_models/bomb_game/bomb_3_body_col.g3db", Model.class);
manager.load("models/collision_models/bomb_game/bomb_3_btn_1_col.g3db", Model.class);
manager.load("models/collision_models/bomb_game/bomb_3_btn_2_col.g3db", Model.class);
manager.load("models/collision_models/bomb_game/bomb_3_btn_3_col.g3db", Model.class);
manager.load("models/collision_models/bomb_game/bomb_3_btn_4_col.g3db", Model.class);
manager.load("models/collision_models/bomb_game/bomb_2_body_col.g3db", Model.class);
manager.load("models/collision_models/bomb_game/big_btn_col.g3db", Model.class);
manager.load("models/collision_models/bomb_game/bomb_1_body_col.g3db", Model.class);
manager.load("models/collision_models/bomb_game/cable_1_col.g3db", Model.class);
manager.load("models/collision_models/bomb_game/cable_2_col.g3db", Model.class);
manager.load("models/collision_models/bomb_game/cable_3_col.g3db", Model.class);
}
@Override
public void createAllEntities(){
EntityParameters parameters;
Entity monkey;
groupManager = world.getManager(GroupManager.class);
// Create and set the lighting.
parameters = new EntityParameters();
parameters.environment.set(new ColorAttribute(ColorAttribute.AmbientLight, 0.3f, 0.3f, 0.3f, 1.0f));
parameters.environment.add(new DirectionalLight().set(new Color(1, 1, 1, 1), new Vector3(0, 0, -1)));
parameters.shader = shader;
addRobotArm(parameters);
// Add bombs.
parameters.markerCode = 89;
addBomb(parameters, bomb_type_t.COMBINATION);
parameters.markerCode = 90;
addBomb(parameters, bomb_type_t.INCLINATION);
parameters.markerCode = 91;
addBomb(parameters, bomb_type_t.WIRES);
// Add doors.
parameters.nextAnimation = AnimationSystem.NO_ANIMATION;
parameters.loopAnimation = false;
parameters.markerCode = 89;
addDoor(parameters);
parameters.markerCode = 90;
addDoor(parameters);
parameters.markerCode = 91;
addDoor(parameters);
// Add the monkey.
monkey = world.createEntity();
monkey.addComponent(new RenderModelComponent(monkeyModel));
monkey.addComponent(new GeometryComponent());
monkey.addComponent(new MarkerCodeComponent(1023));
monkey.addComponent(new VisibilityComponent());
monkey.addComponent(new ShaderComponent(shader));
monkey.addComponent(new EnvironmentComponent(parameters.environment));
monkey.addToWorld();
entities.add(monkey);
// Create the player.
if(player == null){
player = world.createEntity();
player.addComponent(new BombGamePlayerComponent(3));
groupManager.add(player, PlayerComponentBase.PLAYER_GROUP);
player.addToWorld();
}else{
player.getComponent(BombGamePlayerComponent.class).reset();
}
entitiesCreated = true;
}
@Override
public boolean updateAssetManager() throws NullPointerException{
boolean doneLoading;
if(core == null)
throw new NullPointerException("Core has not been set.");
doneLoading = manager.update();
if(doneLoading){
getModels();
createAllEntities();
core.onAssetsLoaded();
}
return doneLoading;
}
@Override
public void dispose() {
if(shader != null) shader.dispose();
manager.dispose();
}
private void addRobotArm(EntityParameters parameters){
Entity robotArm = world.createEntity();
robotArm.addComponent(new GeometryComponent(new Vector3(ROBOT_ARM_START_POINT), new Matrix3(), new Vector3(1, 1, 1)));
robotArm.addComponent(new EnvironmentComponent(parameters.environment));
robotArm.addComponent(new ShaderComponent(parameters.shader));
robotArm.addComponent(new RenderModelComponent(robotArmModel));
robotArm.addComponent(new CollisionModelComponent(robotArmCollisionModel));
robotArm.addComponent(new CollisionDetectionComponent());
robotArm.addComponent(new AutomaticMovementComponent());
robotArm.addToWorld();
entities.add(robotArm);
}
private void addBomb(EntityParameters parameters, bomb_type_t type) throws IllegalArgumentException{
Entity bomb;
// Create a bomb entity and add it's generic components.
bomb = world.createEntity();
bomb.addComponent(new GeometryComponent(new Vector3(), new Matrix3(), new Vector3(1, 1, 1)));
bomb.addComponent(new EnvironmentComponent(parameters.environment));
bomb.addComponent(new ShaderComponent(parameters.shader));
bomb.addComponent(new MarkerCodeComponent(parameters.markerCode));
bomb.addComponent(new BombComponent(currentBombId, type));
bomb.addComponent(new VisibilityComponent());
// Add the collision and render models depending on the bomb type.
if(type == bomb_type_t.COMBINATION){
bomb.addComponent(new RenderModelComponent(combinationBombModel));
bomb.addComponent(new CollisionModelComponent(combinationBombCollisionModel));
addBombCombinationButtons(parameters);
if(DEBUG_RENDER_BOMB_COLLISION_MODELS)
addDebugCollisionModelRenderingEntity(combinationBombCollisionModel, parameters, false);
}else if(type == bomb_type_t.INCLINATION){
bomb.addComponent(new RenderModelComponent(inclinationBombModel));
bomb.addComponent(new CollisionModelComponent(inclinationBombCollisionModel));
addBombInclinationButton(parameters);
if(DEBUG_RENDER_BOMB_COLLISION_MODELS)
addDebugCollisionModelRenderingEntity(inclinationBombCollisionModel, parameters, false);
}else if(type == bomb_type_t.WIRES){
bomb.addComponent(new RenderModelComponent(wiresBombModel));
bomb.addComponent(new CollisionModelComponent(wiresBombCollisionModel));
addBombWires(parameters);
if(DEBUG_RENDER_BOMB_COLLISION_MODELS)
addDebugCollisionModelRenderingEntity(wiresBombCollisionModel, parameters, false);
}else
throw new IllegalArgumentException("Unrecognized bomb type: " + Integer.toString(type.getValue()));
// Add the bomb to the world and the respective marker group. Then increase the id for the next bomb.
groupManager.add(bomb, Integer.toString(parameters.markerCode));
bomb.addToWorld();
entities.add(bomb);
currentBombId++;
NUM_BOMBS++;
}
private void addBombCombinationButtons(EntityParameters parameters){
Entity button1, button2, button3, button4;
button1 = addBombParaphernalia(combinationButton1Model, combinationButton1CollisionModel, parameters);
button2 = addBombParaphernalia(combinationButton2Model, combinationButton2CollisionModel, parameters);
button3 = addBombParaphernalia(combinationButton3Model, combinationButton3CollisionModel, parameters);
button4 = addBombParaphernalia(combinationButton4Model, combinationButton4CollisionModel, parameters);
button1.addComponent(new BombGameEntityTypeComponent(BombGameEntityTypeComponent.COM_BUTTON_1));
button2.addComponent(new BombGameEntityTypeComponent(BombGameEntityTypeComponent.COM_BUTTON_2));
button3.addComponent(new BombGameEntityTypeComponent(BombGameEntityTypeComponent.COM_BUTTON_3));
button4.addComponent(new BombGameEntityTypeComponent(BombGameEntityTypeComponent.COM_BUTTON_4));
button1.addToWorld();
button2.addToWorld();
button3.addToWorld();
button4.addToWorld();
}
private void addBombInclinationButton(EntityParameters parameters){
Entity button;
button = addBombParaphernalia(inclinationBombButtonModel, inclinationBombButtonCollisionModel, parameters);
button.addComponent(new BombGameEntityTypeComponent(BombGameEntityTypeComponent.BIG_BUTTON));
button.addToWorld();
}
private void addBombWires(EntityParameters parameters){
Entity wire1, wire2, wire3;
wire1 = addBombParaphernalia(wiresBombModelWire1, wiresBombCollisionModelWire1, parameters);
wire2 = addBombParaphernalia(wiresBombModelWire2, wiresBombCollisionModelWire2, parameters);
wire3 = addBombParaphernalia(wiresBombModelWire3, wiresBombCollisionModelWire3, parameters);
wire1.addComponent(new BombGameEntityTypeComponent(BombGameEntityTypeComponent.BOMB_WIRE_1));
wire2.addComponent(new BombGameEntityTypeComponent(BombGameEntityTypeComponent.BOMB_WIRE_2));
wire3.addComponent(new BombGameEntityTypeComponent(BombGameEntityTypeComponent.BOMB_WIRE_3));
wire1.addToWorld();
wire2.addToWorld();
wire3.addToWorld();
}
private Entity addBombParaphernalia(Model renderModel, Model collisionModel, EntityParameters parameters){
Entity thing;
thing = world.createEntity();
thing.addComponent(new GeometryComponent(new Vector3(), new Matrix3(), new Vector3(1, 1, 1)));
thing.addComponent(new EnvironmentComponent(parameters.environment));
thing.addComponent(new ShaderComponent(parameters.shader));
thing.addComponent(new RenderModelComponent(renderModel));
thing.addComponent(new CollisionModelComponent(collisionModel));
thing.addComponent(new VisibilityComponent());
thing.addComponent(new MarkerCodeComponent(parameters.markerCode));
thing.addComponent(new CollisionDetectionComponent());
groupManager.add(thing, CollisionDetectionSystem.COLLIDABLE_OBJECTS_GROUP);
groupManager.add(thing, Integer.toString(parameters.markerCode));
if(DEBUG_RENDER_PARAPHERNALIA_COLLISION_MODELS)
addDebugCollisionModelRenderingEntity(collisionModel, parameters, false);
entities.add(thing);
return thing;
}
private void addDoor(EntityParameters parameters){
ModelInstance doorInstance, doorColInstance;
Entity frame, door;
frame = world.createEntity();
frame.addComponent(new GeometryComponent(new Vector3(), new Matrix3(), new Vector3(1, 1, 1)));
frame.addComponent(new RenderModelComponent(doorFrameModel));
frame.addComponent(new CollisionModelComponent(doorFrameCollisionModel));
frame.addComponent(new CollisionDetectionComponent());
frame.addComponent(new EnvironmentComponent(parameters.environment));
frame.addComponent(new ShaderComponent(parameters.shader));
frame.addComponent(new VisibilityComponent());
frame.addComponent(new MarkerCodeComponent(parameters.markerCode));
frame.addComponent(new BombGameEntityTypeComponent(BombGameEntityTypeComponent.DOOR_FRAME));
groupManager.add(frame, Integer.toString(parameters.markerCode));
frame.addToWorld();
door = world.createEntity();
door.addComponent(new GeometryComponent(new Vector3(), new Matrix3(), new Vector3(1, 1, 1)));
door.addComponent(new RenderModelComponent(doorModel));
door.addComponent(new CollisionModelComponent(doorCollisionModel));
door.addComponent(new EnvironmentComponent(parameters.environment));
door.addComponent(new ShaderComponent(parameters.shader));
door.addComponent(new MarkerCodeComponent(parameters.markerCode));
door.addComponent(new VisibilityComponent());
doorInstance = door.getComponent(RenderModelComponent.class).instance;
doorColInstance = door.getComponent(CollisionModelComponent.class).instance;
door.addComponent(new AnimationComponent(doorInstance, parameters.nextAnimation, parameters.loopAnimation, doorColInstance));
door.addComponent(new CollisionDetectionComponent());
door.addComponent(new BombGameEntityTypeComponent(BombGameEntityTypeComponent.DOOR));
groupManager.add(door, CollisionDetectionSystem.COLLIDABLE_OBJECTS_GROUP);
groupManager.add(door, Integer.toString(parameters.markerCode));
groupManager.add(door, DOORS_GROUP);
door.addToWorld();
entities.add(frame);
entities.add(door);
if(DEBUG_RENDER_DOOR_COLLISION_MODELS){
addDebugCollisionModelRenderingEntity(doorFrameCollisionModel, parameters, false);
addDebugCollisionModelRenderingEntity(doorCollisionModel, parameters, true);
}
}
private void addDebugCollisionModelRenderingEntity(Model collisionModel, EntityParameters parameters, boolean animation){
ModelInstance instance;
Entity thing;
thing = world.createEntity();
thing.addComponent(new GeometryComponent(new Vector3(), new Matrix3(), new Vector3(1, 1, 1)));
thing.addComponent(new EnvironmentComponent(parameters.environment));
thing.addComponent(new ShaderComponent(parameters.shader));
thing.addComponent(new RenderModelComponent(collisionModel));
thing.addComponent(new VisibilityComponent());
thing.addComponent(new MarkerCodeComponent(parameters.markerCode));
if(animation){
instance = thing.getComponent(RenderModelComponent.class).instance;
thing.addComponent(new AnimationComponent(instance, parameters.nextAnimation, parameters.loopAnimation));
}
thing.addToWorld();
entities.add(thing);
}
private void getModels(){
// Get the render models.
robotArmModel = manager.get("models/render_models/bomb_game/robot_arm.g3db", Model.class);
doorModel = manager.get("models/render_models/bomb_game/door.g3db", Model.class);
doorFrameModel = manager.get("models/render_models/bomb_game/door_frame1.g3db", Model.class);
combinationBombModel = manager.get("models/render_models/bomb_game/bomb_3_body.g3db", Model.class);
combinationButton1Model = manager.get("models/render_models/bomb_game/bomb_3_btn_1.g3db", Model.class);
combinationButton2Model = manager.get("models/render_models/bomb_game/bomb_3_btn_2.g3db", Model.class);
combinationButton3Model = manager.get("models/render_models/bomb_game/bomb_3_btn_3.g3db", Model.class);
combinationButton4Model = manager.get("models/render_models/bomb_game/bomb_3_btn_4.g3db", Model.class);
inclinationBombModel = manager.get("models/render_models/bomb_game/bomb_2_body.g3db", Model.class);
inclinationBombButtonModel = manager.get("models/render_models/bomb_game/big_btn.g3db", Model.class);
wiresBombModel = manager.get("models/render_models/bomb_game/bomb_1_body.g3db", Model.class);
wiresBombModelWire1 = manager.get("models/render_models/bomb_game/cable_1.g3db", Model.class);
wiresBombModelWire2 = manager.get("models/render_models/bomb_game/cable_2.g3db", Model.class);
wiresBombModelWire3 = manager.get("models/render_models/bomb_game/cable_3.g3db", Model.class);
monkeyModel = manager.get("models/render_models/bomb_game/monkey.g3db", Model.class);
// Get the collision models.
robotArmCollisionModel = manager.get("models/collision_models/bomb_game/robot_arm_col.g3db", Model.class);
doorCollisionModel = manager.get("models/collision_models/bomb_game/door_col.g3db", Model.class);
doorFrameCollisionModel = manager.get("models/collision_models/bomb_game/door_frame1_col.g3db", Model.class);
combinationBombCollisionModel = manager.get("models/collision_models/bomb_game/bomb_3_body_col.g3db", Model.class);
combinationButton1CollisionModel = manager.get("models/collision_models/bomb_game/bomb_3_btn_1_col.g3db", Model.class);
combinationButton2CollisionModel = manager.get("models/collision_models/bomb_game/bomb_3_btn_2_col.g3db", Model.class);
combinationButton3CollisionModel = manager.get("models/collision_models/bomb_game/bomb_3_btn_3_col.g3db", Model.class);
combinationButton4CollisionModel = manager.get("models/collision_models/bomb_game/bomb_3_btn_4_col.g3db", Model.class);
inclinationBombCollisionModel = manager.get("models/collision_models/bomb_game/bomb_2_body_col.g3db", Model.class);
inclinationBombButtonCollisionModel = manager.get("models/collision_models/bomb_game/big_btn_col.g3db", Model.class);
wiresBombCollisionModel = manager.get("models/collision_models/bomb_game/bomb_1_body_col.g3db", Model.class);
wiresBombCollisionModelWire1 = manager.get("models/collision_models/bomb_game/cable_1_col.g3db", Model.class);
wiresBombCollisionModelWire2 = manager.get("models/collision_models/bomb_game/cable_2_col.g3db", Model.class);
wiresBombCollisionModelWire3 = manager.get("models/collision_models/bomb_game/cable_3_col.g3db", Model.class);
}
@Override
public void resetAllEntities() {
for(Entity entity : entities){
try{
if(entity.isActive())
entity.deleteFromWorld();
}catch(NullPointerException n){
Gdx.app.error(TAG, CLASS_NAME + ".resetAllEntities(): Null pointer exception while deleting entity.");
}
}
entities.clear();
NUM_BOMBS = 0;
createAllEntities();
}
}

View File

@@ -0,0 +1,38 @@
/*
* Copyright (C) 2014 Miguel Angel Astor Romero
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ve.ucv.ciens.ccg.nxtar.scenarios.bombgame;
import com.artemis.Component;
public class BombGameEntityTypeComponent extends Component {
public static final int BOMB_WIRE_1 = 10;
public static final int BOMB_WIRE_2 = 11;
public static final int BOMB_WIRE_3 = 12;
public static final int BIG_BUTTON = 20;
public static final int COM_BUTTON_1 = 30;
public static final int COM_BUTTON_2 = 31;
public static final int COM_BUTTON_3 = 32;
public static final int COM_BUTTON_4 = 33;
public static final int DOOR = 40;
public static final int DOOR_FRAME = 41;
public static final int FADE_EFFECT = 90;
public int type;
public BombGameEntityTypeComponent(int type){
this.type = type;
}
}

View File

@@ -0,0 +1,127 @@
/*
* Copyright (C) 2014 Miguel Angel Astor Romero
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ve.ucv.ciens.ccg.nxtar.scenarios.bombgame;
import ve.ucv.ciens.ccg.nxtar.scenarios.HintsOverlayBase;
import ve.ucv.ciens.ccg.nxtar.utils.ProjectConstants;
import ve.ucv.ciens.ccg.nxtar.utils.Utils;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.controllers.mappings.Ouya;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator;
import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator.FreeTypeFontParameter;
public class BombGameInstructionsOverlay extends HintsOverlayBase {
private static final float CANNONICAL_SCREEN_WIDTH = 800.0f;
private Texture inclinationBombTexture;
private Texture combinationBombTexture;
private Texture wireBombTexture;
private BitmapFont font;
private BitmapFont titleFont;
private Sprite inclinationBomb;
private Sprite combinationBomb;
private Sprite wireBomb;
private float inclinationX;
private float combinationX;
private float wireX;
private float inclinationY;
private float combinationY;
private float wireY;
private float titleWidth;
private float titleHeight;
public BombGameInstructionsOverlay(){
FreeTypeFontGenerator fontGenerator;
FreeTypeFontParameter fontParameters;
inclinationBombTexture = new Texture(Gdx.files.internal("data/gfx/bomb_game/incl_bomb.png"));
combinationBombTexture = new Texture(Gdx.files.internal("data/gfx/bomb_game/comb_bomb.png"));
wireBombTexture = new Texture(Gdx.files.internal("data/gfx/bomb_game/wire_bomb.png"));
inclinationBomb = new Sprite(inclinationBombTexture);
combinationBomb = new Sprite(combinationBombTexture);
wireBomb = new Sprite(wireBombTexture);
inclinationBomb.setSize(inclinationBomb.getWidth() * 0.5f, inclinationBomb.getHeight() * 0.5f);
combinationBomb.setSize(combinationBomb.getWidth() * 0.5f, combinationBomb.getHeight() * 0.5f);
wireBomb.setSize(wireBomb.getWidth() * 0.5f, wireBomb.getHeight() * 0.5f);
combinationBomb.setPosition(-(Utils.getScreenWidthWithOverscan() / 4.0f) - combinationBomb.getWidth(), -(combinationBomb.getHeight() / 2.0f));
inclinationBomb.setPosition(-(Utils.getScreenWidthWithOverscan() / 4.0f) - inclinationBomb.getWidth(), combinationBomb.getY() + combinationBomb.getHeight() + 10.0f);
wireBomb.setPosition(-(Utils.getScreenWidthWithOverscan() / 4.0f) - wireBomb.getWidth(), combinationBomb.getY() - wireBomb.getHeight() - 10.0f);
fontParameters = new FreeTypeFontParameter();
fontParameters.characters = ProjectConstants.FONT_CHARS;
if(!Ouya.runningOnOuya)
fontParameters.size = (int)((float)ProjectConstants.MENU_BUTTON_FONT_SIZE * ((float)Gdx.graphics.getWidth() / CANNONICAL_SCREEN_WIDTH));
else
fontParameters.size = ProjectConstants.MENU_BUTTON_FONT_SIZE;
fontParameters.flip = false;
fontGenerator = new FreeTypeFontGenerator(Gdx.files.internal("data/fonts/d-puntillas-B-to-tiptoe.ttf"));
font = fontGenerator.generateFont(fontParameters);
font.setColor(Color.YELLOW);
fontParameters.size = (int)(90.0f * ((float)Gdx.graphics.getWidth() / CANNONICAL_SCREEN_WIDTH));
titleFont = fontGenerator.generateFont(fontParameters);
fontGenerator.dispose();
inclinationX = inclinationBomb.getX() + inclinationBomb.getWidth() + 15.0f;
combinationX = combinationBomb.getX() + combinationBomb.getWidth() + 15.0f;
wireX = wireBomb.getX() + wireBomb.getWidth() + 15.0f;
inclinationY = inclinationBomb.getY() + (inclinationBomb.getWidth() / 2.0f) - (font.getCapHeight() / 2.0f);
combinationY = combinationBomb.getY() + (combinationBomb.getWidth() / 2.0f) - (font.getCapHeight() / 2.0f);
wireY = wireBomb.getY() + (wireBomb.getWidth() / 2.0f) - (font.getCapHeight() / 2.0f);
titleWidth = titleFont.getBounds("Instructions").width;
titleHeight = titleFont.getBounds("Instructions").height;
}
@Override
public void dispose() {
inclinationBombTexture.dispose();
combinationBombTexture.dispose();
wireBombTexture.dispose();
font.dispose();
titleFont.dispose();
}
@Override
public void render(SpriteBatch batch){
String inclText = Utils.deviceHasOrientationSensors() ? "Balance your device" : "Always defuses.";
inclinationBomb.draw(batch);
combinationBomb.draw(batch);
wireBomb.draw(batch);
font.draw(batch, inclText, inclinationX, inclinationY);
font.draw(batch, "Blue, red, gray and green", combinationX, combinationY);
font.draw(batch, "Cut the blue wire.", wireX, wireY);
if(!Ouya.runningOnOuya)
titleFont.draw(batch, "Instructions", -(titleWidth / 2), (Utils.getScreenHeightWithOverscan() / 2) - titleHeight - 10);
else
titleFont.draw(batch, "Instructions", -(titleWidth / 2), (Utils.getScreenHeightWithOverscan() / 2) - 10);
}
}

View File

@@ -0,0 +1,511 @@
/*
* Copyright (C) 2014 Miguel Angel Astor Romero
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ve.ucv.ciens.ccg.nxtar.scenarios.bombgame;
import ve.ucv.ciens.ccg.nxtar.components.AnimationComponent;
import ve.ucv.ciens.ccg.nxtar.components.CollisionDetectionComponent;
import ve.ucv.ciens.ccg.nxtar.components.FadeEffectComponent;
import ve.ucv.ciens.ccg.nxtar.components.MarkerCodeComponent;
import ve.ucv.ciens.ccg.nxtar.components.PlayerComponentBase;
import ve.ucv.ciens.ccg.nxtar.components.VisibilityComponent;
import ve.ucv.ciens.ccg.nxtar.systems.CollisionDetectionSystem;
import ve.ucv.ciens.ccg.nxtar.systems.GameLogicSystemBase;
import ve.ucv.ciens.ccg.nxtar.utils.ProjectConstants;
import ve.ucv.ciens.ccg.nxtar.utils.Utils;
import com.artemis.Aspect;
import com.artemis.ComponentMapper;
import com.artemis.Entity;
import com.artemis.World;
import com.artemis.annotations.Mapper;
import com.artemis.managers.GroupManager;
import com.artemis.utils.ImmutableBag;
import com.badlogic.gdx.Gdx;
public class BombGameLogicSystem extends GameLogicSystemBase {
private static final String TAG = "BOMB_GAME_LOGIC";
private static final String CLASS_NAME = BombGameLogicSystem.class.getSimpleName();
private enum combination_button_state_t{
CORRECT(0), INCORRECT(1), DISABLED(2);
private int value;
private combination_button_state_t(int value){
this.value = value;
}
public int getValue(){
return this.value;
}
}
@Mapper ComponentMapper<BombGameEntityTypeComponent> typeMapper;
@Mapper ComponentMapper<AnimationComponent> animationMapper;
@Mapper ComponentMapper<VisibilityComponent> visibilityMapper;
@Mapper ComponentMapper<MarkerCodeComponent> markerMapper;
@Mapper ComponentMapper<CollisionDetectionComponent> collisionMapper;
@Mapper ComponentMapper<FadeEffectComponent> fadeMapper;
private MarkerCodeComponent tempMarker;
private BombGameEntityTypeComponent tempType;
private GroupManager manager;
private int then;
@SuppressWarnings("unchecked")
public BombGameLogicSystem(){
super(Aspect.getAspectForAll(BombGameEntityTypeComponent.class));
manager = null;
then = 0;
}
@Override
protected void process(Entity e){
BombGameEntityTypeComponent typeComponent;
if(manager == null)
manager = world.getManager(GroupManager.class);
typeComponent = typeMapper.get(e);
switch(typeComponent.type){
case BombGameEntityTypeComponent.BOMB_WIRE_1:
case BombGameEntityTypeComponent.BOMB_WIRE_2:
case BombGameEntityTypeComponent.BOMB_WIRE_3:
processWireBomb(e);
break;
case BombGameEntityTypeComponent.BIG_BUTTON:
processInclinationBomb(e);
break;
case BombGameEntityTypeComponent.COM_BUTTON_1:
case BombGameEntityTypeComponent.COM_BUTTON_2:
case BombGameEntityTypeComponent.COM_BUTTON_3:
case BombGameEntityTypeComponent.COM_BUTTON_4:
processCombinationBomb(e);
break;
case BombGameEntityTypeComponent.DOOR:
processDoor(e);
break;
case BombGameEntityTypeComponent.FADE_EFFECT:
processFade(e);
break;
default:
break;
}
}
/**
* <p>Checks if the current player interaction disables a wire based bomb.</p>
*
* @param b An Artemis {@link Entity} that possibly represents any of a Wire Bomb's wires.
*/
private void processWireBomb(Entity b){
CollisionDetectionComponent collision;
MarkerCodeComponent marker;
BombGameEntityTypeComponent wireType;
// Get this wire's parameters.
collision = collisionMapper.getSafe(b);
marker = markerMapper.getSafe(b);
wireType = typeMapper.getSafe(b);
// if any of the parameters is missing then skip.
if(marker == null || collision == null || wireType == null){
Gdx.app.log(TAG, CLASS_NAME + ".processInclinationBomb(): Wire bomb is missing some components.");
return;
}
// If this bomb is still enabled and it's door is already open then process it.
try{
if(marker.enabled && isDoorOpen(marker.code, manager) && collision.colliding){
manager.remove(b, CollisionDetectionSystem.COLLIDABLE_OBJECTS_GROUP);
manager.remove(b, Integer.toString(marker.code));
b.deleteFromWorld();
if(wireType.type != BombGameEntityTypeComponent.BOMB_WIRE_1){
Gdx.app.log(TAG, CLASS_NAME + ".processWireBomb(): Wire bomb exploded.");
createFadeOutEffect();
reducePlayerLivesByOne();
}
disableBomb(marker.code);
Gdx.app.log(TAG, CLASS_NAME + ".processWireBomb(): Wire bomb disabled.");
}
}catch(IllegalArgumentException e){
Gdx.app.error(TAG, CLASS_NAME + ".processWireBomb(): IllegalArgumentException caught: " + e.getMessage());
}
}
/**
* <p>Checks if the current player interaction disables a combination bomb.</p>
*
* @param b An Artemis {@link Entity} that possibly represents any of a Combination Bomb's buttons.
*/
private void processCombinationBomb(Entity b){
combination_button_state_t state;
CollisionDetectionComponent collision;
MarkerCodeComponent marker;
BombGameEntityTypeComponent buttonType;
// Get this wire's parameters.
collision = collisionMapper.getSafe(b);
marker = markerMapper.getSafe(b);
buttonType = typeMapper.getSafe(b);
// if any of the parameters is missing then skip.
if(marker == null || collision == null || buttonType == null){
Gdx.app.log(TAG, CLASS_NAME + ".processInclinationBomb(): Wire bomb is missing some components.");
return;
}
// If this bomb is still enabled and it's door is already open then process it.
try{
if(marker.enabled && isDoorOpen(marker.code, manager) && collision.colliding){
manager.remove(b, CollisionDetectionSystem.COLLIDABLE_OBJECTS_GROUP);
manager.remove(b, Integer.toString(marker.code));
b.deleteFromWorld();
// Check the state of the other buttons associated with this bomb.
state = checkCombinationBombButtons(buttonType.type, marker.code);
if(state.getValue() == combination_button_state_t.INCORRECT.getValue()){
Gdx.app.log(TAG, CLASS_NAME + ".processCombinationBomb(): Combination bomb exploded.");
createFadeOutEffect();
disableBomb(marker.code);
reducePlayerLivesByOne();
}else if(state.getValue() == combination_button_state_t.DISABLED.getValue()){
Gdx.app.log(TAG, CLASS_NAME + ".processCombinationBomb(): Combination bomb disabled.");
disableBomb(marker.code);
}
}
}catch(IllegalArgumentException e){
Gdx.app.error(TAG, CLASS_NAME + ".processCombinationBomb(): IllegalArgumentException caught: " + e.getMessage());
}
}
/**
* <p>Checks if the current player interaction disables an inclination bomb.</p>
*
* @param b An Artemis {@link Entity} that possibly represents an Inclination Bomb's big button.
*/
private void processInclinationBomb(Entity b){
// Get the components of the big button.
CollisionDetectionComponent collision = collisionMapper.getSafe(b);
MarkerCodeComponent marker = markerMapper.getSafe(b);
// If any of the components is missing, skip this entity.
if(marker == null || collision == null ){
Gdx.app.log(TAG, CLASS_NAME + ".processInclinationBomb(): Inclination bomb is missing some components.");
return;
}
// If this bomb is still enabled and it's door is already open then process it.
try{
if(marker.enabled && isDoorOpen(marker.code, manager) && collision.colliding){
// Disable the bomb and remove it from collision detection.
marker.enabled = false;
manager.remove(b, CollisionDetectionSystem.COLLIDABLE_OBJECTS_GROUP);
manager.remove(b, Integer.toString(marker.code));
b.deleteFromWorld();
if(Utils.deviceHasOrientationSensors()){
if(!Utils.isDeviceRollValid() || (Utils.isDeviceRollValid() && Math.abs(Gdx.input.getRoll()) > ProjectConstants.MAX_ABS_ROLL)){
Gdx.app.log(TAG, CLASS_NAME + ".processInclinationBomb(): Inclination bomb exploded.");
createFadeOutEffect();
reducePlayerLivesByOne();
}
}
// Disable all related entities.
disableBomb(marker.code);
Gdx.app.log(TAG, CLASS_NAME + ".processInclinationBomb(): Inclination bomb disabled.");
}
}catch(IllegalArgumentException e){
Gdx.app.error(TAG, CLASS_NAME + ".processInclinationBomb(): IllegalArgumentException caught: " + e.getMessage());
}
}
/**
* <p>Set's the animation for a door depending on it's collision and marker state.</p>
*
* @param d An Artemis {@link Entity} possibly representing a door.
*/
private void processDoor(Entity d){
// Get the components of the door.
CollisionDetectionComponent collision = collisionMapper.getSafe(d);
AnimationComponent animation = animationMapper.getSafe(d);
VisibilityComponent visibility = visibilityMapper.getSafe(d);
MarkerCodeComponent marker = markerMapper.getSafe(d);
// If any of the components is missing, skip this entity.
if(marker == null || collision == null || animation == null || visibility == null){
Gdx.app.log(TAG, CLASS_NAME + ".processDoor(): Door is missing some components.");
return;
}
if(visibility.visible){
if(marker.enabled){
if(collision.colliding){
// If the door is visible and enabled and the player is colliding with it then set
// it's opening animation;
animation.next = BombGameEntityCreator.DOOR_OPEN_ANIMATION;
animation.loop = false;
collision.colliding = false;
world.getManager(GroupManager.class).remove(d, CollisionDetectionSystem.COLLIDABLE_OBJECTS_GROUP);
Gdx.app.log(TAG, CLASS_NAME + ".processDoor(): Opening door.");
}
}else{
// If the door is disabled and open, then set it's closing animation.
if(animation.current != BombGameEntityCreator.DOOR_CLOSE_ANIMATION){
animation.next = BombGameEntityCreator.DOOR_CLOSE_ANIMATION;
animation.loop = false;
Gdx.app.log(TAG, CLASS_NAME + ".processDoor(): Closing door.");
}
}
}
}
/**
* <p>Checks if a door is either open or closed depending on the completeness of it's animation.</p>
*
* @param markerCode The code of the door to check. Must be between 0 and 1023.
* @param manager An Artemis {@link GroupManager} to use to get all related entities.
* @return true if the opening animation of the door has finished playing.
* @throws IllegalArgumentException If marker code is not in the range [0, 1023], inclusive.
*/
private boolean isDoorOpen(int markerCode, GroupManager manager) throws IllegalArgumentException{
AnimationComponent animation;
boolean doorOpen = false;
ImmutableBag<Entity> doors = manager.getEntities(BombGameEntityCreator.DOORS_GROUP);
if(markerCode < 0 || markerCode > 1023)
throw new IllegalArgumentException("Marker code is not within range [0, 1023]: " + Integer.toString(markerCode));
// For every door.
for(int i = 0; i < doors.size(); i++){
tempMarker = markerMapper.getSafe(doors.get(i));
animation = animationMapper.getSafe(doors.get(i));
if(animation == null || tempMarker == null) return false;
// If this is the door we are looking for and it's opening animation is finished then this door is open.
if(tempMarker.code == markerCode && animation.current == BombGameEntityCreator.DOOR_OPEN_ANIMATION && animation.controller.current.loopCount == 0){
doorOpen = true;
break;
}
}
return doorOpen;
}
/**
* <p>Updates the player's lives count.</p>
*/
private void reducePlayerLivesByOne(){
Entity player;
BombGamePlayerComponent playerComponent;
ImmutableBag<Entity> players;
players = manager.getEntities(PlayerComponentBase.PLAYER_GROUP);
if(players != null && players.size() > 0 && players.get(0) != null){
player = players.get(0);
playerComponent = player.getComponent(BombGamePlayerComponent.class);
if(playerComponent != null){
playerComponent.lives -= 1;
}else{
Gdx.app.log(TAG, CLASS_NAME + ".reducePlayerLivesByOne(): Players is missing required components.");
}
}else{
Gdx.app.log(TAG, CLASS_NAME + ".reducePlayerLivesByOne(): No players found.");
}
}
/**
* <p>Updates the player's disabled bombs count.</p>
*/
private void increasePlayerDisabledBombsByOne(){
Entity player;
BombGamePlayerComponent playerComponent;
ImmutableBag<Entity> players;
players = manager.getEntities(PlayerComponentBase.PLAYER_GROUP);
if(players != null && players.size() > 0 && players.get(0) != null){
player = players.get(0);
playerComponent = player.getComponent(BombGamePlayerComponent.class);
if(playerComponent != null){
playerComponent.disabledBombs += 1;
}else{
Gdx.app.log(TAG, CLASS_NAME + ".reducePlayerLivesByOne(): Players is missing required components.");
}
}else{
Gdx.app.log(TAG, CLASS_NAME + ".reducePlayerLivesByOne(): No players found.");
}
}
/**
* <p>Disables all entities associated with the corresponding marker code.</p>
*
* @param markerCode
* @throws IllegalArgumentException If marker code is not in the range [0, 1023], inclusive.
*/
private void disableBomb(int markerCode) throws IllegalArgumentException{
ImmutableBag<Entity> related = manager.getEntities(Integer.toString(markerCode));
if(markerCode < 0 || markerCode > 1023)
throw new IllegalArgumentException("Marker code is not within range [0, 1023]: " + Integer.toString(markerCode));
// Disable every entity sharing this marker code except for the corresponding door frame.
for(int i = 0; i < related.size(); i++){
tempMarker = markerMapper.getSafe(related.get(i));
tempType = typeMapper.getSafe(related.get(i));
// Enable collisions with the corresponding door frame entity. Disable collisions with other related entities.
if(tempMarker != null) tempMarker.enabled = false;
if(tempType != null){
if(tempType.type != BombGameEntityTypeComponent.DOOR_FRAME && tempType.type != BombGameEntityTypeComponent.DOOR){
manager.remove(related.get(i), CollisionDetectionSystem.COLLIDABLE_OBJECTS_GROUP);
manager.remove(related.get(i), Integer.toString(markerCode));
}else if(tempType.type != BombGameEntityTypeComponent.DOOR_FRAME){
manager.add(related.get(i), CollisionDetectionSystem.COLLIDABLE_OBJECTS_GROUP);
}
}
}
increasePlayerDisabledBombsByOne();
}
/**
* <p>Checks if a combination bomb is being disabled in the correct sequence.</p>
*
* @param buttonType A number between {@link BombGameEntityTypeComponent.COM_BUTTON_1} and {@link BombGameEntityTypeComponent.COM_BUTTON_4}.
* @param markerCode A marker code between [0, 1023], inclusive.
* @return The current state of the bomb.
* @throws IllegalArgumentException If marker code is not in range or if buttonType is not valid.
*/
private combination_button_state_t checkCombinationBombButtons(int buttonType, int markerCode) throws IllegalArgumentException{
combination_button_state_t state;
boolean correctSequence = true;
int remainingButtons = 0;
ImmutableBag<Entity> related;
if(buttonType < BombGameEntityTypeComponent.COM_BUTTON_1 || buttonType > BombGameEntityTypeComponent.COM_BUTTON_4)
throw new IllegalArgumentException("Button is not a valid combination bomb button: " + Integer.toString(buttonType));
if(markerCode < 0 || markerCode > 1023)
throw new IllegalArgumentException("Marker code is not within range [0, 1023]: " + Integer.toString(markerCode));
related = manager.getEntities(Integer.toString(markerCode));
// Check the state of the other buttons associated with this bomb.
for(int i = 0; i < related.size(); i++){
tempType = typeMapper.getSafe(related.get(i));
if(tempType == null) continue;
if(tempType.type >= BombGameEntityTypeComponent.COM_BUTTON_1 && tempType.type <= BombGameEntityTypeComponent.COM_BUTTON_4){
if(tempType.type >= buttonType){
// If this remaining button is a correct one then skip it.
remainingButtons++;
continue;
}else{
// If this remaining button is an incorrect one then the sequence is wrong.
correctSequence = false;
break;
}
}else continue;
}
if(!correctSequence)
state = combination_button_state_t.INCORRECT;
else
if(remainingButtons == 0)
state = combination_button_state_t.DISABLED;
else
state = combination_button_state_t.CORRECT;
return state;
}
/**
* <p>Adds a new fade out entity to the {@link World}.</p>
*/
private void createFadeOutEffect(){
Entity effect = world.createEntity();
effect.addComponent(new BombGameEntityTypeComponent(BombGameEntityTypeComponent.FADE_EFFECT));
effect.addComponent(new FadeEffectComponent());
effect.addToWorld();
}
/**
* <p>Adds a new fade in entity to the {@link World}.</p>
*/
private void createFadeInEffect(){
Entity effect = world.createEntity();
effect.addComponent(new BombGameEntityTypeComponent(BombGameEntityTypeComponent.FADE_EFFECT));
effect.addComponent(new FadeEffectComponent(true));
effect.addToWorld();
}
/**
* <p>Updates a fade effect entity.</p>
*
* @param f An Artemis {@link Entity} possibly referencing a fade effect.
*/
private void processFade(Entity f){
FadeEffectComponent fade = fadeMapper.getSafe(f);
if(fade != null){
if(!fade.isEffectStarted())
fade.startEffect();
if(!fade.isEffectFinished()){
// If the fade has not finished then just update it.
Gdx.app.log(TAG, CLASS_NAME + ".processFade(): Updating fade.");
fade.update(Gdx.graphics.getDeltaTime());
}else{
// If the fade finished.
if(fade.isEffectFadeIn()){
// If the effect was a fade in then just remove it.
Gdx.app.log(TAG, CLASS_NAME + ".processFade(): deleting fade in.");
f.deleteFromWorld();
}else{
// If the effect was a fade out then wait for one second and then remove it and start a fade in.
then += (int)(Gdx.graphics.getDeltaTime() * 1000.0f);
if(then >= 1500){
Gdx.app.log(TAG, CLASS_NAME + ".processFade(): Deleting fade out.");
f.deleteFromWorld();
Gdx.app.log(TAG, CLASS_NAME + ".processFade(): Creating fade in.");
createFadeInEffect();
then = 0;
}else{
Gdx.app.log(TAG, CLASS_NAME + ".processFade(): Waiting after fade out: " + Integer.toString(then));
}
}
}
}
}
}

View File

@@ -0,0 +1,49 @@
/*
* Copyright (C) 2014 Miguel Angel Astor Romero
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ve.ucv.ciens.ccg.nxtar.scenarios.bombgame;
import ve.ucv.ciens.ccg.nxtar.components.PlayerComponentBase;
public class BombGamePlayerComponent extends PlayerComponentBase {
public static final int MIN_LIVES = 1;
public static final int MAX_LIVES = 5;
public int startingLives;
public int lives;
public int disabledBombs;
public BombGamePlayerComponent(int lives) throws IllegalArgumentException{
super();
if(lives < MIN_LIVES || lives > MAX_LIVES)
throw new IllegalArgumentException("Lives number out of range: " + Integer.toString(lives));
startingLives = lives;
reset();
}
public BombGamePlayerComponent(){
this(3);
}
@Override
public void reset(){
super.reset();
this.lives = startingLives;
this.disabledBombs = 0;
}
}

View File

@@ -0,0 +1,118 @@
/*
* Copyright (C) 2013 Miguel Angel Astor Romero
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ve.ucv.ciens.ccg.nxtar.scenarios.bombgame;
import ve.ucv.ciens.ccg.nxtar.scenarios.SummaryBase;
import ve.ucv.ciens.ccg.nxtar.systems.PlayerSystemBase;
import ve.ucv.ciens.ccg.nxtar.utils.Utils;
import com.artemis.ComponentMapper;
import com.artemis.Entity;
import com.artemis.annotations.Mapper;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
public class BombGamePlayerSystem extends PlayerSystemBase{
public final class BombGamePlayerSummary extends SummaryBase{
public int livesLeft;
public int disabledBombs;
public int detonatedBombs;
public boolean victory;
public BombGamePlayerSummary(){
reset();
}
@Override
public void reset() {
this.livesLeft = 0;
this.disabledBombs = 0;
this.detonatedBombs = 0;
this.victory = false;
}
}
@Mapper ComponentMapper<BombGamePlayerComponent> playerMapper;
private SpriteBatch batch;
private Texture heartTexture;
private Sprite heart;
private OrthographicCamera camera;
private BombGamePlayerSummary summary;
private float heartYPos;
public BombGamePlayerSystem(){
super(BombGamePlayerComponent.class);
camera = new OrthographicCamera(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
batch = new SpriteBatch();
heartTexture = new Texture(Gdx.files.internal("data/gfx/bomb_game/Anonymous_heart_1.png"));
summary = new BombGamePlayerSummary();
heart = new Sprite(heartTexture);
heart.setSize(heart.getWidth() * 0.25f, heart.getHeight() * 0.25f);
heartYPos = (Utils.getScreenHeightWithOverscan() / 2) - heart.getHeight() - 64 - 5;
}
@Override
protected void process(Entity e){
float heartXPos;
BombGamePlayerComponent player = playerMapper.get(e);
// Render remaining lives.
batch.setProjectionMatrix(camera.combined);
batch.begin();{
heartXPos = -(Utils.getScreenWidthWithOverscan() / 2) + 5;
for(int i = 0; i < player.lives; ++i){
heart.setPosition(heartXPos, heartYPos);
heart.draw(batch);
heartXPos += heart.getWidth() + 5;
}
}batch.end();
// Check ending conditions.
if(player.lives <= 0){
player.gameFinished = true;
player.victory = false;
}else if(player.disabledBombs >= BombGameEntityCreator.NUM_BOMBS){
player.gameFinished = true;
player.victory = true;
}
if(player.gameFinished){
summary.victory = player.victory;
summary.livesLeft = player.lives;
summary.disabledBombs = BombGameEntityCreator.NUM_BOMBS - (player.startingLives - player.lives);
summary.detonatedBombs = player.startingLives - player.lives;
finishGame(player.victory);
}
}
@Override
public void dispose() {
if(batch != null)
batch.dispose();
if(heartTexture != null)
heartTexture.dispose();
}
@Override
public SummaryBase getPlayerSummary() {
return summary;
}
}

View File

@@ -0,0 +1,109 @@
/*
* Copyright (C) 2014 Miguel Angel Astor Romero
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ve.ucv.ciens.ccg.nxtar.scenarios.bombgame;
import ve.ucv.ciens.ccg.nxtar.scenarios.SummaryBase;
import ve.ucv.ciens.ccg.nxtar.scenarios.SummaryOverlayBase;
import ve.ucv.ciens.ccg.nxtar.scenarios.bombgame.BombGamePlayerSystem.BombGamePlayerSummary;
import ve.ucv.ciens.ccg.nxtar.utils.ProjectConstants;
import ve.ucv.ciens.ccg.nxtar.utils.Utils;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.controllers.mappings.Ouya;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.BitmapFont.TextBounds;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator;
import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator.FreeTypeFontParameter;
public class BombGameScenarioEndingOverlay extends SummaryOverlayBase {
private static final float CANNONICAL_SCREEN_WIDTH = 800.0f;
private BitmapFont font;
private BitmapFont titleFont;
private float textX;
private float baseTextY;
private TextBounds titleBounds;
public BombGameScenarioEndingOverlay(){
FreeTypeFontGenerator fontGenerator;
FreeTypeFontParameter fontParameters;
fontParameters = new FreeTypeFontParameter();
fontParameters.characters = ProjectConstants.FONT_CHARS;
if(!Ouya.runningOnOuya)
fontParameters.size = (int)(65.0f * ((float)Gdx.graphics.getWidth() / CANNONICAL_SCREEN_WIDTH));
else
fontParameters.size = ProjectConstants.MENU_BUTTON_FONT_SIZE;
fontParameters.flip = false;
fontGenerator = new FreeTypeFontGenerator(Gdx.files.internal("data/fonts/d-puntillas-B-to-tiptoe.ttf"));
font = fontGenerator.generateFont(fontParameters);
font.setColor(Color.YELLOW);
fontParameters.size = (int)(90.0f * ((float)Gdx.graphics.getWidth() / CANNONICAL_SCREEN_WIDTH));
titleFont = fontGenerator.generateFont(fontParameters);
fontGenerator.dispose();
textX = -(Utils.getScreenWidthWithOverscan() / 7.0f);
baseTextY = -(font.getCapHeight() / 2.0f);
}
@Override
public void dispose(){
font.dispose();
titleFont.dispose();
}
@Override
public void render(SpriteBatch batch, SummaryBase summary) throws ClassCastException{
BombGamePlayerSummary bombGamePlayerSummary;
String title;
String text;
// Get the player's summary.
if(!(summary instanceof BombGamePlayerSummary))
throw new ClassCastException("Summary is not a bomb game summary.");
bombGamePlayerSummary = (BombGamePlayerSummary)summary;
// Render the summary.
text = String.format("Lives left: %d", bombGamePlayerSummary.livesLeft);
textX = -(font.getBounds(text).width / 2);
font.draw(batch, text, textX, baseTextY + font.getCapHeight() + 15);
text = String.format("Bombs defused: %d", bombGamePlayerSummary.disabledBombs);
textX = -(font.getBounds(text).width / 2);
font.draw(batch, text, textX, baseTextY);
text = String.format("Bombs detonated: %d", bombGamePlayerSummary.detonatedBombs);
textX = -(font.getBounds(text).width / 2);
font.draw(batch, text, textX, baseTextY - font.getCapHeight() - 15);
// Render the title.
if(bombGamePlayerSummary.victory)
title = "Victory!";
else
title = "Game Over";
titleBounds = titleFont.getBounds(title);
if(!Ouya.runningOnOuya)
titleFont.draw(batch, title, -(titleBounds.width / 2), (Utils.getScreenHeightWithOverscan() / 2) - titleBounds.height - 10);
else
titleFont.draw(batch, title, -(titleBounds.width / 2), (Utils.getScreenHeightWithOverscan() / 2) - 10);
}
}

View File

@@ -0,0 +1,699 @@
/*
* Copyright (C) 2014 Miguel Angel Astor Romero
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ve.ucv.ciens.ccg.nxtar.states;
import ve.ucv.ciens.ccg.networkdata.MotorEvent;
import ve.ucv.ciens.ccg.networkdata.MotorEvent.motor_t;
import ve.ucv.ciens.ccg.nxtar.NxtARCore;
import ve.ucv.ciens.ccg.nxtar.NxtARCore.game_states_t;
import ve.ucv.ciens.ccg.nxtar.graphics.CustomPerspectiveCamera;
import ve.ucv.ciens.ccg.nxtar.interfaces.ImageProcessor.MarkerData;
import ve.ucv.ciens.ccg.nxtar.network.SensorReportThread;
import ve.ucv.ciens.ccg.nxtar.network.monitors.MotorEventQueue;
import ve.ucv.ciens.ccg.nxtar.network.monitors.VideoFrameMonitor;
import ve.ucv.ciens.ccg.nxtar.scenarios.AutomaticActionPerformerBase;
import ve.ucv.ciens.ccg.nxtar.scenarios.ScenarioGlobals;
import ve.ucv.ciens.ccg.nxtar.scenarios.AutomaticActionPerformerBase.automatic_action_t;
import ve.ucv.ciens.ccg.nxtar.systems.CollisionDetectionSystem;
import ve.ucv.ciens.ccg.nxtar.systems.MarkerPositioningSystem;
import ve.ucv.ciens.ccg.nxtar.systems.MarkerRenderingSystem;
import ve.ucv.ciens.ccg.nxtar.utils.ProjectConstants;
import ve.ucv.ciens.ccg.nxtar.utils.Utils;
import com.artemis.World;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.controllers.Controller;
import com.badlogic.gdx.controllers.mappings.Ouya;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Pixmap;
import com.badlogic.gdx.graphics.Pixmap.Format;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.Texture.TextureFilter;
import com.badlogic.gdx.graphics.Texture.TextureWrap;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.NinePatch;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator;
import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator.FreeTypeFontParameter;
import com.badlogic.gdx.graphics.g3d.ModelBatch;
import com.badlogic.gdx.graphics.glutils.FrameBuffer;
import com.badlogic.gdx.graphics.glutils.ShaderProgram;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.scenes.scene2d.ui.TextButton;
import com.badlogic.gdx.scenes.scene2d.ui.TextButton.TextButtonStyle;
import com.badlogic.gdx.scenes.scene2d.utils.NinePatchDrawable;
public class AutomaticActionState extends BaseState{
private static final String TAG = "AUTOMATIC_STATE";
private static final String CLASS_NAME = AutomaticActionState.class.getSimpleName();
private static final String BACKGROUND_SHADER_PATH = "shaders/bckg/bckg";
private static final float NEAR = 0.01f;
private static final float FAR = 100.0f;
// Background related fields.
private Sprite background;
private float uScaling[];
private Texture backgroundTexture;
private ShaderProgram backgroundShader;
// 3D rendering fields.
private ModelBatch modelBatch;
private FrameBuffer frameBuffer;
private Sprite frameBufferSprite;
// Game related fields.
private World gameWorld;
private MarkerRenderingSystem markerRenderingSystem;
private boolean ignoreBackKey;
private boolean automaticActionEnabled;
private AutomaticActionPerformerBase automaticActionPerformer;
private automatic_action_t previousAction;
// Cameras.
private OrthographicCamera unitaryOrthographicCamera;
private OrthographicCamera pixelPerfectOrthographicCamera;
private CustomPerspectiveCamera perspectiveCamera;
// Video stream graphics.
private Texture videoFrameTexture;
private Sprite renderableVideoFrame;
private Pixmap videoFrame;
// Gui elements.
private Texture startButtonEnabledTexture;
private Texture startButtonDisabledTexture;
private Texture startButtonPressedTexture;
private NinePatch startButtonEnabled9p;
private NinePatch startButtonDisabled9p;
private NinePatch startButtonPressed9p;
private BitmapFont font;
private TextButton startButton;
private Rectangle startButtonBBox;
private boolean startButtonPressed;
private Texture ouyaOButtonTexture;
private Sprite ouyaOButton;
private boolean oButtonPressed;
private boolean aButtonPressed;
// Button touch helper fields.
private boolean[] buttonsTouched;
private int[] buttonPointers;
private boolean[] gamepadButtonPressed;
// Monitors.
private VideoFrameMonitor frameMonitor;
private MotorEventQueue queue;
private SensorReportThread sensorThread;
public AutomaticActionState(final NxtARCore core) throws IllegalStateException, IllegalArgumentException{
if(core == null)
throw new IllegalArgumentException(CLASS_NAME + ": Core is null.");
this.core = core;
frameMonitor = VideoFrameMonitor.getInstance();
queue = MotorEventQueue.getInstance();
sensorThread = SensorReportThread.getInstance();
ignoreBackKey = false;
videoFrame = null;
aButtonPressed = false;
automaticActionEnabled = false;
startButtonPressed = false;
automaticActionPerformer = ScenarioGlobals.getAutomaticActionPerformer();
previousAction = automatic_action_t.NO_ACTION;
// Set up the cameras.
pixelPerfectOrthographicCamera = new OrthographicCamera(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
unitaryOrthographicCamera = new OrthographicCamera(1.0f, Gdx.graphics.getHeight() / Gdx.graphics.getWidth());
// Set up input handling support fields.
win2world = new Vector3(0.0f, 0.0f, 0.0f);
touchPointWorldCoords = new Vector2();
buttonsTouched = new boolean[1];
buttonsTouched[0] = false;
buttonPointers = new int[1];
buttonPointers[0] = -1;
gamepadButtonPressed = new boolean[1];
gamepadButtonPressed[0] = false;
// Set up the background.
backgroundTexture = new Texture(Gdx.files.internal("data/gfx/textures/tile_aqua.png"));
backgroundTexture.setWrap(TextureWrap.Repeat, TextureWrap.Repeat);
backgroundTexture.setFilter(TextureFilter.Linear, TextureFilter.Linear);
background = new Sprite(backgroundTexture);
background.setSize(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
background.setPosition(-(Gdx.graphics.getWidth() / 2), -(Gdx.graphics.getHeight() / 2));
// Set up the shader.
backgroundShader = new ShaderProgram(Gdx.files.internal(BACKGROUND_SHADER_PATH + "_vert.glsl"), Gdx.files.internal(BACKGROUND_SHADER_PATH + "_frag.glsl"));
if(!backgroundShader.isCompiled()){
Gdx.app.error(TAG, CLASS_NAME + ".InGameState() :: Failed to compile the background shader.");
Gdx.app.error(TAG, CLASS_NAME + backgroundShader.getLog());
backgroundShader = null;
}
uScaling = new float[2];
uScaling[0] = Gdx.graphics.getWidth() > Gdx.graphics.getHeight() ? 16.0f : 9.0f;
uScaling[1] = Gdx.graphics.getHeight() > Gdx.graphics.getWidth() ? 16.0f : 9.0f;
// Set up the 3D rendering.
modelBatch = new ModelBatch();
frameBuffer = null;
perspectiveCamera = null;
frameBufferSprite = null;
// Create the gui.
setUpButton();
// Set up the game world.
gameWorld = ScenarioGlobals.getGameWorld();
markerRenderingSystem = gameWorld.getSystem(MarkerRenderingSystem.class);
if(markerRenderingSystem == null)
throw new IllegalStateException(CLASS_NAME + ": Essential marker rendering system is null.");
}
/*;;;;;;;;;;;;;;;;;;;;;;
; BASE STATE METHODS ;
;;;;;;;;;;;;;;;;;;;;;;*/
@Override
public void render(float delta){
int w, h;
byte[] frame;
MarkerData data;
TextureRegion region;
float focalPointX, focalPointY, cameraCenterX, cameraCenterY;
// Clear the screen.
Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
// Render the background.
core.batch.setProjectionMatrix(pixelPerfectOrthographicCamera.combined);
core.batch.begin();{
if(backgroundShader != null){
core.batch.setShader(backgroundShader);
backgroundShader.setUniform2fv("u_scaling", uScaling, 0, 2);
}
background.draw(core.batch);
if(backgroundShader != null) core.batch.setShader(null);
}core.batch.end();
// Fetch the current video frame.
frame = frameMonitor.getCurrentFrame();
w = frameMonitor.getFrameDimensions().getWidth();
h = frameMonitor.getFrameDimensions().getHeight();
// Create the 3D perspective camera and the frame buffer object if they don't exist.
if(perspectiveCamera == null && frameBuffer == null){
frameBuffer = new FrameBuffer(Format.RGBA8888, w, h, true);
frameBuffer.getColorBufferTexture().setFilter(TextureFilter.Linear, TextureFilter.Linear);
perspectiveCamera = new CustomPerspectiveCamera(67, w, h);
perspectiveCamera.translate(0.0f, 0.0f, 0.0f);
perspectiveCamera.near = NEAR;
perspectiveCamera.far = FAR;
perspectiveCamera.lookAt(0.0f, 0.0f, -1.0f);
perspectiveCamera.update();
}
// Attempt to find the markers in the current video frame.
data = core.cvProc.findMarkersInFrame(frame);
// If a valid frame was fetched.
if(data != null && data.outFrame != null){
if(automaticActionEnabled)
performAutomaticAction(data);
// Set the camera to the correct projection.
focalPointX = core.cvProc.getFocalPointX();
focalPointY = core.cvProc.getFocalPointY();
cameraCenterX = core.cvProc.getCameraCenterX();
cameraCenterY = core.cvProc.getCameraCenterY();
perspectiveCamera.setCustomARProjectionMatrix(focalPointX, focalPointY, cameraCenterX, cameraCenterY, NEAR, FAR, w, h);
perspectiveCamera.update(perspectiveCamera.projection);
// Update the game state.
gameWorld.setDelta(Gdx.graphics.getDeltaTime() * 1000);
gameWorld.getSystem(MarkerPositioningSystem.class).setMarkerData(data);
gameWorld.process();
// Decode the video frame.
videoFrame = new Pixmap(data.outFrame, 0, w * h);
videoFrameTexture = new Texture(videoFrame);
videoFrameTexture.setFilter(TextureFilter.Linear, TextureFilter.Linear);
videoFrame.dispose();
// Convert the decoded frame into a renderable texture.
region = new TextureRegion(videoFrameTexture, 0, 0, w, h);
if(renderableVideoFrame == null)
renderableVideoFrame = new Sprite(region);
else
renderableVideoFrame.setRegion(region);
renderableVideoFrame.setOrigin(renderableVideoFrame.getWidth() / 2, renderableVideoFrame.getHeight() / 2);
renderableVideoFrame.setPosition(0, 0);
// Set the 3D frame buffer for rendering.
frameBuffer.begin();{
// Set OpenGL state.
Gdx.gl.glClearColor(0, 0, 0, 0);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);
Gdx.gl.glDisable(GL20.GL_TEXTURE_2D);
// Call rendering systems.
markerRenderingSystem.begin(perspectiveCamera);
markerRenderingSystem.process();
markerRenderingSystem.end();
}frameBuffer.end();
// Set the frame buffer object texture to a renderable sprite.
region = new TextureRegion(frameBuffer.getColorBufferTexture(), 0, 0, frameBuffer.getWidth(), frameBuffer.getHeight());
region.flip(false, true);
if(frameBufferSprite == null)
frameBufferSprite = new Sprite(region);
else
frameBufferSprite.setRegion(region);
frameBufferSprite.setOrigin(frameBufferSprite.getWidth() / 2, frameBufferSprite.getHeight() / 2);
frameBufferSprite.setPosition(0, 0);
// Set the position and orientation of the renderable video frame and the frame buffer.
if(!Ouya.runningOnOuya){
renderableVideoFrame.setSize(1.0f, renderableVideoFrame.getHeight() / renderableVideoFrame.getWidth() );
renderableVideoFrame.rotate90(true);
renderableVideoFrame.translate(-renderableVideoFrame.getWidth() / 2, 0.5f - renderableVideoFrame.getHeight());
frameBufferSprite.setSize(1.0f, frameBufferSprite.getHeight() / frameBufferSprite.getWidth() );
frameBufferSprite.rotate90(true);
frameBufferSprite.translate(-frameBufferSprite.getWidth() / 2, 0.5f - frameBufferSprite.getHeight());
}else{
float xSize = Gdx.graphics.getHeight() * (w / h);
renderableVideoFrame.setSize(xSize * ProjectConstants.OVERSCAN, Utils.getScreenHeightWithOverscan());
renderableVideoFrame.rotate90(true);
renderableVideoFrame.translate(-renderableVideoFrame.getWidth() / 2, -renderableVideoFrame.getHeight() / 2);
frameBufferSprite.setSize(xSize * ProjectConstants.OVERSCAN, Utils.getScreenHeightWithOverscan());
frameBufferSprite.rotate90(true);
frameBufferSprite.translate(-frameBufferSprite.getWidth() / 2, -frameBufferSprite.getHeight() / 2);
}
// Set the correct camera for the device.
if(!Ouya.runningOnOuya){
core.batch.setProjectionMatrix(unitaryOrthographicCamera.combined);
}else{
core.batch.setProjectionMatrix(pixelPerfectOrthographicCamera.combined);
}
// Render the video frame and the frame buffer.
core.batch.begin();{
renderableVideoFrame.draw(core.batch);
frameBufferSprite.draw(core.batch);
}core.batch.end();
// Clear the video frame from memory.
videoFrameTexture.dispose();
}
core.batch.setProjectionMatrix(pixelPerfectOrthographicCamera.combined);
core.batch.begin();{
startButton.draw(core.batch, 1.0f);
if(Ouya.runningOnOuya)
ouyaOButton.draw(core.batch);
}core.batch.end();
data = null;
}
@Override
public void pause(){
automaticActionPerformer.reset();
startButton.setDisabled(false);
ignoreBackKey = false;
automaticActionEnabled = false;
}
@Override
public void dispose(){
SensorReportThread.freeInstance();
if(font != null)
font.dispose();
if(ouyaOButtonTexture != null)
ouyaOButtonTexture.dispose();
if(startButtonEnabledTexture != null)
startButtonEnabledTexture.dispose();
if(startButtonDisabledTexture != null)
startButtonDisabledTexture.dispose();
if(startButtonPressedTexture != null)
startButtonPressedTexture.dispose();
if(modelBatch != null)
modelBatch.dispose();
if(videoFrameTexture != null)
videoFrameTexture.dispose();
if(backgroundTexture != null)
backgroundTexture.dispose();
if(backgroundShader != null)
backgroundShader.dispose();
if(frameBuffer != null)
frameBuffer.dispose();
}
@Override
public void onStateSet(){
gameWorld.getSystem(CollisionDetectionSystem.class).disableCollisions();
stateActive = true;
Gdx.input.setInputProcessor(this);
Gdx.input.setCatchBackKey(true);
Gdx.input.setCatchMenuKey(true);
}
@Override
public void onStateUnset(){
stateActive = false;
Gdx.input.setInputProcessor(null);
Gdx.input.setCatchBackKey(false);
Gdx.input.setCatchMenuKey(false);
}
/*;;;;;;;;;;;;;;;;;;
; HELPER METHODS ;
;;;;;;;;;;;;;;;;;;*/
private void setUpButton(){
TextButtonStyle textButtonStyle;
FreeTypeFontGenerator fontGenerator;
FreeTypeFontParameter fontParameters;
// Create the start button background.
startButtonEnabledTexture = new Texture(Gdx.files.internal("data/gfx/gui/Anonymous_Pill_Button_Yellow.png"));
startButtonEnabled9p = new NinePatch(new TextureRegion(startButtonEnabledTexture, 0, 0, startButtonEnabledTexture.getWidth(), startButtonEnabledTexture.getHeight()), 49, 49, 45, 45);
startButtonDisabledTexture = new Texture(Gdx.files.internal("data/gfx/gui/Anonymous_Pill_Button_Cyan.png"));
startButtonDisabled9p = new NinePatch(new TextureRegion(startButtonDisabledTexture, 0, 0, startButtonDisabledTexture.getWidth(), startButtonDisabledTexture.getHeight()), 49, 49, 45, 45);
startButtonPressedTexture = new Texture(Gdx.files.internal("data/gfx/gui/Anonymous_Pill_Button_Blue.png"));
startButtonPressed9p = new NinePatch(new TextureRegion(startButtonPressedTexture, 0, 0, startButtonPressedTexture.getWidth(), startButtonPressedTexture.getHeight()), 49, 49, 45, 45);
// Create the start button font.
fontParameters = new FreeTypeFontParameter();
fontParameters.characters = ProjectConstants.FONT_CHARS;
fontParameters.size = ProjectConstants.MENU_BUTTON_FONT_SIZE;
fontParameters.flip = false;
fontGenerator = new FreeTypeFontGenerator(Gdx.files.internal("data/fonts/d-puntillas-B-to-tiptoe.ttf"));
font = fontGenerator.generateFont(fontParameters);
fontGenerator.dispose();
// Create the start button.
textButtonStyle = new TextButtonStyle();
textButtonStyle.font = font;
textButtonStyle.up = new NinePatchDrawable(startButtonEnabled9p);
textButtonStyle.checked = new NinePatchDrawable(startButtonPressed9p);
textButtonStyle.disabled = new NinePatchDrawable(startButtonDisabled9p);
textButtonStyle.fontColor = new Color(Color.BLACK);
textButtonStyle.downFontColor = new Color(Color.WHITE);
textButtonStyle.disabledFontColor = new Color(Color.BLACK);
startButton = new TextButton("Start automatic action", textButtonStyle);
startButton.setText("Start automatic action");
startButton.setDisabled(false);
startButtonBBox = new Rectangle(0, 0, startButton.getWidth(), startButton.getHeight());
startButton.setPosition(-(startButton.getWidth() / 2), -(Gdx.graphics.getHeight() / 2) + 10);
startButtonBBox.setPosition(startButton.getX(), startButton.getY());
// Set OUYA's O button.
if(Ouya.runningOnOuya){
ouyaOButtonTexture = new Texture("data/gfx/gui/OUYA_O.png");
ouyaOButton = new Sprite(ouyaOButtonTexture);
ouyaOButton.setSize(ouyaOButton.getWidth() * 0.6f, ouyaOButton.getHeight() * 0.6f);
oButtonPressed = false;
ouyaOButton.setPosition(startButton.getX() - ouyaOButton.getWidth() - 20, startButton.getY() + (ouyaOButton.getHeight() / 2));
}else{
ouyaOButtonTexture = null;
}
}
private void performAutomaticAction(MarkerData data){
MotorEvent event1 = null;
MotorEvent event2 = null;
automatic_action_t nextAction;
try{
if(!automaticActionPerformer.performAutomaticAction(sensorThread.getLightSensorReading(), data)){
nextAction = automaticActionPerformer.getNextAction();
if(nextAction != previousAction){
switch(nextAction){
case GO_BACKWARDS:
event1 = new MotorEvent();
event2 = new MotorEvent();
event1.setMotor(motor_t.MOTOR_A);
event1.setPower((byte)-20);
event2.setMotor(motor_t.MOTOR_C);
event2.setPower((byte)-20);
break;
case GO_FORWARD:
event1 = new MotorEvent();
event2 = new MotorEvent();
event1.setMotor(motor_t.MOTOR_A);
event1.setPower((byte)20);
event2.setMotor(motor_t.MOTOR_C);
event2.setPower((byte)20);
break;
case STOP:
event1 = new MotorEvent();
event2 = new MotorEvent();
event1.setMotor(motor_t.MOTOR_A);
event1.setPower((byte)0);
event2.setMotor(motor_t.MOTOR_C);
event2.setPower((byte)0);
break;
case ROTATE_90:
event1 = new MotorEvent();
event1.setMotor(motor_t.ROTATE_90);
event1.setPower((byte)20);
break;
case RECENTER:
event1 = new MotorEvent();
event1.setMotor(motor_t.RECENTER);
event1.setPower((byte)20);
break;
case TURN_LEFT:
event1 = new MotorEvent();
event1.setMotor(motor_t.MOTOR_A);
event1.setPower((byte)20);
break;
case TURN_RIGHT:
event1 = new MotorEvent();
event1.setMotor(motor_t.MOTOR_C);
event1.setPower((byte)20);
break;
case BACKWARDS_LEFT:
event1 = new MotorEvent();
event1.setMotor(motor_t.MOTOR_C);
event1.setPower((byte)-20);
break;
case BACKWARDS_RIGHT:
event1 = new MotorEvent();
event1.setMotor(motor_t.MOTOR_A);
event1.setPower((byte)-20);
break;
case LOOK_RIGHT:
event1 = new MotorEvent();
event1.setMotor(motor_t.MOTOR_B);
event1.setPower((byte)25);
break;
case LOOK_LEFT:
event1 = new MotorEvent();
event1.setMotor(motor_t.MOTOR_B);
event1.setPower((byte)-25);
break;
case STOP_LOOKING:
event1 = new MotorEvent();
event1.setMotor(motor_t.MOTOR_B);
event1.setPower((byte)0);
break;
case NO_ACTION:
default:
break;
}
if(event1 != null)
queue.addEvent(event1);
if(event2 != null)
queue.addEvent(event2);
previousAction = nextAction;
}else{
Gdx.app.log(TAG, CLASS_NAME + ".performAutomaticAction(): Skipping repeated action.");
}
}else{
startButton.setDisabled(false);
ignoreBackKey = false;
automaticActionEnabled = false;
core.nextState = game_states_t.AUTOMATIC_ACTION_SUMMARY;
}
}catch(IllegalArgumentException e){
Gdx.app.log(TAG, CLASS_NAME + ".performAutomaticAction(): Received IllegalArgumentException: ", e);
startButton.setDisabled(false);
ignoreBackKey = false;
automaticActionEnabled = false;
core.nextState = game_states_t.MAIN_MENU;
}catch(IllegalStateException e){
Gdx.app.log(TAG, CLASS_NAME + ".performAutomaticAction(): Received IllegalStateException: ", e);
startButton.setDisabled(false);
ignoreBackKey = false;
automaticActionEnabled = false;
core.nextState = game_states_t.MAIN_MENU;
}
}
/*;;;;;;;;;;;;;;;;;;;;;;;;;;;
; INPUT PROCESSOR METHODS ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;*/
@Override
public boolean touchDown(int screenX, int screenY, int pointer, int button){
if(!Ouya.runningOnOuya){
win2world.set(screenX, screenY, 0.0f);
unitaryOrthographicCamera.unproject(win2world);
touchPointWorldCoords.set(win2world.x * Gdx.graphics.getWidth(), win2world.y * Gdx.graphics.getHeight());
if(!startButton.isDisabled() && startButtonBBox.contains(touchPointWorldCoords)){
startButtonPressed = true;
}
}
return false;
}
@Override
public boolean touchUp(int screenX, int screenY, int pointer, int button){
if(!Ouya.runningOnOuya){
win2world.set(screenX, screenY, 0.0f);
unitaryOrthographicCamera.unproject(win2world);
touchPointWorldCoords.set(win2world.x * Gdx.graphics.getWidth(), win2world.y * Gdx.graphics.getHeight());
if(!startButton.isDisabled() && startButtonPressed && startButtonBBox.contains(touchPointWorldCoords)){
startButton.setDisabled(true);
ignoreBackKey = true;
automaticActionEnabled = true;
}
}
return false;
}
@Override
public boolean touchDragged(int screenX, int screenY, int pointer){
if(!Ouya.runningOnOuya){
win2world.set(screenX, screenY, 0.0f);
unitaryOrthographicCamera.unproject(win2world);
touchPointWorldCoords.set(win2world.x * Gdx.graphics.getWidth(), win2world.y * Gdx.graphics.getHeight());
if(!startButton.isDisabled() && startButtonPressed && !startButtonBBox.contains(touchPointWorldCoords)){
startButtonPressed = false;
}
}
return false;
}
@Override
public boolean keyDown(int keycode){
if(keycode == Input.Keys.BACK && !ignoreBackKey){
core.nextState = game_states_t.MAIN_MENU;
return true;
}
return false;
}
/*;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; CONTROLLER LISTENER METHODS ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;*/
@Override
public boolean buttonDown(Controller controller, int buttonCode){
if(stateActive){
if(buttonCode == Ouya.BUTTON_O && !startButton.isDisabled()){
oButtonPressed = true;
startButton.setChecked(true);
}else if(buttonCode == Ouya.BUTTON_A && !ignoreBackKey){
aButtonPressed = true;
}
return true;
}else{
return false;
}
}
@Override
public boolean buttonUp(Controller controller, int buttonCode){
if(stateActive){
if(buttonCode == Ouya.BUTTON_O && oButtonPressed){
if(oButtonPressed){
oButtonPressed = false;
startButton.setChecked(false);
startButton.setDisabled(true);
ignoreBackKey = true;
automaticActionEnabled = true;
}
}else if(buttonCode == Ouya.BUTTON_A && aButtonPressed){
core.nextState = game_states_t.MAIN_MENU;
}
return true;
}else{
return false;
}
}
}

View File

@@ -0,0 +1,330 @@
/*
* Copyright (C) 2014 Miguel Angel Astor Romero
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ve.ucv.ciens.ccg.nxtar.states;
import ve.ucv.ciens.ccg.nxtar.NxtARCore;
import ve.ucv.ciens.ccg.nxtar.NxtARCore.game_states_t;
import ve.ucv.ciens.ccg.nxtar.scenarios.AutomaticActionPerformerBase;
import ve.ucv.ciens.ccg.nxtar.scenarios.ScenarioGlobals;
import ve.ucv.ciens.ccg.nxtar.scenarios.SummaryOverlayBase;
import ve.ucv.ciens.ccg.nxtar.utils.ProjectConstants;
import ve.ucv.ciens.ccg.nxtar.utils.Utils;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.controllers.Controller;
import com.badlogic.gdx.controllers.mappings.Ouya;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.Texture.TextureFilter;
import com.badlogic.gdx.graphics.Texture.TextureWrap;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.NinePatch;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator;
import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator.FreeTypeFontParameter;
import com.badlogic.gdx.graphics.glutils.ShaderProgram;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.scenes.scene2d.ui.TextButton;
import com.badlogic.gdx.scenes.scene2d.ui.TextButton.TextButtonStyle;
import com.badlogic.gdx.scenes.scene2d.utils.NinePatchDrawable;
public class AutomaticActionSummaryState extends BaseState{
private static final String TAG = "AUTO_SUMMARY";
private static final String CLASS_NAME = AutomaticActionSummaryState.class.getSimpleName();
private static final String SHADER_PATH = "shaders/movingBckg/movingBckg";
// Helper fields.
private float u_scaling[];
private float u_displacement;
// Buttons and other gui components.
private TextButton continueButton;
private Rectangle continueButtonBBox;
private Sprite background;
private Texture backgroundTexture;
private ShaderProgram backgroundShader;
private Texture ouyaOButtonTexture;
private Sprite ouyaOButton;
private boolean oButtonPressed;
// Graphic data for the start button.
private Texture buttonEnabledTexture;
private Texture buttonDisabledTexture;
private Texture buttonPressedTexture;
private BitmapFont font;
// Summary overlay related fields.
AutomaticActionPerformerBase automaticActionPerformer;
SummaryOverlayBase summaryOverlay;
// Button touch helper fields.
private boolean continueButtonTouched;
private int continueButtonTouchPointer;
public AutomaticActionSummaryState(NxtARCore core) throws IllegalArgumentException{
TextButtonStyle textButtonStyle;
FreeTypeFontGenerator fontGenerator;
FreeTypeFontParameter fontParameters;
NinePatch buttonEnabled9p;
NinePatch buttonDisabled9p;
NinePatch buttonPressed9p;
if(core == null)
throw new IllegalArgumentException(CLASS_NAME + ": Core is null.");
this.core = core;
this.pixelPerfectCamera = new OrthographicCamera(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
oButtonPressed = false;
automaticActionPerformer = ScenarioGlobals.getAutomaticActionPerformer();
summaryOverlay = ScenarioGlobals.getAutomaticActionSummaryOverlay();
// Create the start button background.
buttonEnabledTexture = new Texture(Gdx.files.internal("data/gfx/gui/Anonymous_Pill_Button_Yellow.png"));
buttonEnabled9p = new NinePatch(new TextureRegion(buttonEnabledTexture, 0, 0, buttonEnabledTexture.getWidth(), buttonEnabledTexture.getHeight()), 49, 49, 45, 45);
buttonDisabledTexture = new Texture(Gdx.files.internal("data/gfx/gui/Anonymous_Pill_Button_Cyan.png"));
buttonDisabled9p = new NinePatch(new TextureRegion(buttonDisabledTexture, 0, 0, buttonDisabledTexture.getWidth(), buttonDisabledTexture.getHeight()), 49, 49, 45, 45);
buttonPressedTexture = new Texture(Gdx.files.internal("data/gfx/gui/Anonymous_Pill_Button_Blue.png"));
buttonPressed9p = new NinePatch(new TextureRegion(buttonPressedTexture, 0, 0, buttonPressedTexture.getWidth(), buttonPressedTexture.getHeight()), 49, 49, 45, 45);
// Create the start button font.
fontParameters = new FreeTypeFontParameter();
fontParameters.characters = ProjectConstants.FONT_CHARS;
fontParameters.size = ProjectConstants.MENU_BUTTON_FONT_SIZE;
fontParameters.flip = false;
fontGenerator = new FreeTypeFontGenerator(Gdx.files.internal("data/fonts/d-puntillas-B-to-tiptoe.ttf"));
font = fontGenerator.generateFont(fontParameters);
fontGenerator.dispose();
// Create the contine button.
textButtonStyle = new TextButtonStyle();
textButtonStyle.font = font;
textButtonStyle.up = new NinePatchDrawable(buttonEnabled9p);
textButtonStyle.checked = new NinePatchDrawable(buttonPressed9p);
textButtonStyle.disabled = new NinePatchDrawable(buttonDisabled9p);
textButtonStyle.fontColor = new Color(Color.BLACK);
textButtonStyle.downFontColor = new Color(Color.WHITE);
textButtonStyle.disabledFontColor = new Color(Color.BLACK);
continueButton = new TextButton("Continue", textButtonStyle);
continueButton.setText("Continue");
continueButton.setPosition(-(continueButton.getWidth() / 2), -(Utils.getScreenHeightWithOverscan() / 2) + 10);
continueButtonBBox = new Rectangle(0, 0, continueButton.getWidth(), continueButton.getHeight());
continueButtonBBox.setPosition(continueButton.getX(), continueButton.getY());
// Set OUYA's O button.
if(Ouya.runningOnOuya){
ouyaOButtonTexture = new Texture("data/gfx/gui/OUYA_O.png");
ouyaOButton = new Sprite(ouyaOButtonTexture);
ouyaOButton.setSize(ouyaOButton.getWidth() * 0.6f, ouyaOButton.getHeight() * 0.6f);
ouyaOButton.setPosition(continueButton.getX() - ouyaOButton.getWidth() - 20, continueButton.getY() + (ouyaOButton.getHeight() / 2));
oButtonPressed = false;
}else{
ouyaOButtonTexture = null;
}
// Set up the background.
backgroundTexture = new Texture(Gdx.files.internal("data/gfx/textures/tile_aqua.png"));
backgroundTexture.setWrap(TextureWrap.Repeat, TextureWrap.Repeat);
backgroundTexture.setFilter(TextureFilter.Linear, TextureFilter.Linear);
background = new Sprite(backgroundTexture);
background.setSize(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
background.setPosition(-(Gdx.graphics.getWidth() / 2), -(Gdx.graphics.getHeight() / 2));
backgroundShader = new ShaderProgram(Gdx.files.internal(SHADER_PATH + "_vert.glsl"), Gdx.files.internal(SHADER_PATH + "_frag.glsl"));
if(!backgroundShader.isCompiled()){
Gdx.app.error(TAG, CLASS_NAME + ".MainMenuStateBase() :: Failed to compile the background shader.");
Gdx.app.error(TAG, CLASS_NAME + backgroundShader.getLog());
backgroundShader = null;
}
u_scaling = new float[2];
u_scaling[0] = Gdx.graphics.getWidth() > Gdx.graphics.getHeight() ? 16.0f : 9.0f;
u_scaling[1] = Gdx.graphics.getHeight() > Gdx.graphics.getWidth() ? 16.0f : 9.0f;
u_displacement = 1.0f;
win2world = new Vector3(0.0f, 0.0f, 0.0f);
touchPointWorldCoords = new Vector2();
continueButtonTouched = false;
continueButtonTouchPointer = -1;
stateActive = false;
}
@Override
public void render(float delta){
Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
core.batch.setProjectionMatrix(pixelPerfectCamera.combined);
core.batch.begin();{
// Render background.
core.batch.disableBlending();
drawBackground(core.batch);
core.batch.enableBlending();
summaryOverlay.render(core.batch, automaticActionPerformer.getSummary());
// Render buttons.
continueButton.draw(core.batch, 1.0f);
if(Ouya.runningOnOuya)
ouyaOButton.draw(core.batch);
}core.batch.end();
}
@Override
public void dispose(){
buttonEnabledTexture.dispose();
buttonDisabledTexture.dispose();
buttonPressedTexture.dispose();
if(ouyaOButtonTexture != null)
ouyaOButtonTexture.dispose();
backgroundTexture.dispose();
if(backgroundShader != null) backgroundShader.dispose();
font.dispose();
}
private void drawBackground(SpriteBatch batch){
if(backgroundShader != null){
batch.setShader(backgroundShader);
backgroundShader.setUniform2fv("u_scaling", u_scaling, 0, 2);
backgroundShader.setUniformf("u_displacement", u_displacement);
}
background.draw(batch);
if(backgroundShader != null) batch.setShader(null);
u_displacement = u_displacement < 0.0f ? 1.0f : u_displacement - 0.0005f;
}
@Override
public void onStateSet(){
stateActive = true;
Gdx.input.setInputProcessor(this);
Gdx.input.setCatchBackKey(true);
Gdx.input.setCatchMenuKey(true);
}
@Override
public void onStateUnset(){
stateActive = false;
Gdx.input.setInputProcessor(null);
Gdx.input.setCatchBackKey(false);
Gdx.input.setCatchMenuKey(false);
}
/*;;;;;;;;;;;;;;;;;;;;;;;;;;
; INPUT LISTENER METHODS ;
;;;;;;;;;;;;;;;;;;;;;;;;;;*/
@Override
public boolean touchDown(int screenX, int screenY, int pointer, int button){
unprojectTouch(screenX, screenY);
Gdx.app.log(TAG, CLASS_NAME + String.format(".touchDown(%d, %d, %d, %d)", screenX, screenY, pointer, button));
Gdx.app.log(TAG, CLASS_NAME + String.format(".touchDown() :: Unprojected touch point: (%f, %f)", touchPointWorldCoords.x, touchPointWorldCoords.y));
if(!continueButton.isDisabled() && continueButtonBBox.contains(touchPointWorldCoords)){
continueButton.setChecked(true);
continueButtonTouched = true;
continueButtonTouchPointer = pointer;
Gdx.app.log(TAG, CLASS_NAME + ".touchDown() :: Start button pressed.");
}
return true;
}
@Override
public boolean touchUp(int screenX, int screenY, int pointer, int button){
unprojectTouch(screenX, screenY);
Gdx.app.log(TAG, CLASS_NAME + String.format(".touchUp(%d, %d, %d, %d)", screenX, screenY, pointer, button));
Gdx.app.log(TAG, CLASS_NAME + String.format(".touchUp() :: Unprojected touch point: (%f, %f)", touchPointWorldCoords.x, touchPointWorldCoords.y));
if(!continueButton.isDisabled() && continueButtonBBox.contains(touchPointWorldCoords) && continueButtonTouched){
continueButton.setChecked(false);
continueButtonTouched = false;
continueButtonTouchPointer = -1;
core.nextState = game_states_t.MAIN_MENU;
Gdx.app.log(TAG, CLASS_NAME + ".touchDown() :: Start button released.");
}
return true;
}
@Override
public boolean touchDragged(int screenX, int screenY, int pointer){
unprojectTouch(screenX, screenY);
if(!continueButton.isDisabled() && continueButtonTouched && pointer == continueButtonTouchPointer && !continueButtonBBox.contains(touchPointWorldCoords)){
continueButtonTouchPointer = -1;
continueButtonTouched = false;
continueButton.setChecked(false);
Gdx.app.log(TAG, CLASS_NAME + ".touchDragged() :: Start button released.");
}
return true;
}
@Override
public boolean keyDown(int keycode){
if(keycode == Input.Keys.BACK){
core.nextState = game_states_t.MAIN_MENU;
return true;
}
return false;
}
/*;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; CONTROLLER LISTENER METHODS ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;*/
@Override
public boolean buttonDown(Controller controller, int buttonCode){
if(stateActive){
if(buttonCode == Ouya.BUTTON_O && !continueButton.isDisabled()){
Gdx.app.log(TAG, CLASS_NAME + ".buttonDown(): O button pressed.");
oButtonPressed = true;
continueButton.setChecked(true);
}
return true;
}else{
return false;
}
}
@Override
public boolean buttonUp(Controller controller, int buttonCode){
if(stateActive){
if(buttonCode == Ouya.BUTTON_O){
Gdx.app.log(TAG, CLASS_NAME + ".buttonDown(): O button released.");
if(oButtonPressed){
oButtonPressed = false;
continueButton.setChecked(false);
core.nextState = game_states_t.MAIN_MENU;
}
}
return true;
}else{
return false;
}
}
}

View File

@@ -0,0 +1,165 @@
/*
* Copyright (C) 2014 Miguel Angel Astor Romero
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ve.ucv.ciens.ccg.nxtar.states;
import ve.ucv.ciens.ccg.nxtar.NxtARCore;
import com.badlogic.gdx.InputProcessor;
import com.badlogic.gdx.Screen;
import com.badlogic.gdx.controllers.Controller;
import com.badlogic.gdx.controllers.ControllerListener;
import com.badlogic.gdx.controllers.PovDirection;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.math.Vector3;
public abstract class BaseState implements Screen, ControllerListener, InputProcessor{
protected NxtARCore core;
protected boolean stateActive;
protected OrthographicCamera pixelPerfectCamera;
protected Vector3 win2world;
protected Vector2 touchPointWorldCoords;
/*;;;;;;;;;;;;;;;;;
; STATE METHODS ;
;;;;;;;;;;;;;;;;;*/
public abstract void onStateSet();
public abstract void onStateUnset();
/*;;;;;;;;;;;;;;;;;;
; SCREEN METHODS ;
;;;;;;;;;;;;;;;;;;*/
@Override
public abstract void render(float delta);
@Override
public abstract void dispose();
@Override
public void resize(int width, int height){ }
@Override
public void show(){ }
@Override
public void hide(){ }
@Override
public void pause(){ }
@Override
public void resume(){ }
/*;;;;;;;;;;;;;;;;;;
; HELPER METHODS ;
;;;;;;;;;;;;;;;;;;*/
protected final void unprojectTouch(int screenX, int screenY){
win2world.set(screenX, screenY, 0.0f);
pixelPerfectCamera.unproject(win2world);
touchPointWorldCoords.set(win2world.x, win2world.y);
}
/*;;;;;;;;;;;;;;;;;;;;;;;;;;;
; INPUT PROCESSOR METHODS ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;*/
@Override
public boolean keyDown(int keycode){
return false;
};
@Override
public boolean keyUp(int keycode){
return false;
};
@Override
public boolean keyTyped(char character){
return false;
};
@Override
public boolean touchDown(int screenX, int screenY, int pointer, int button){
return false;
};
@Override
public boolean touchUp(int screenX, int screenY, int pointer, int button){
return false;
};
@Override
public boolean touchDragged(int screenX, int screenY, int pointer){
return false;
};
@Override
public boolean mouseMoved(int screenX, int screenY){
return false;
};
@Override
public boolean scrolled(int amount){
return false;
};
/*;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; CONTROLLER LISTENER METHODS ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;*/
@Override
public void connected(Controller controller){ };
@Override
public void disconnected(Controller controller){ };
@Override
public boolean buttonDown(Controller controller, int buttonCode){
return false;
};
@Override
public boolean buttonUp(Controller controller, int buttonCode){
return false;
};
@Override
public boolean axisMoved(Controller controller, int axisCode, float value){
return false;
};
@Override
public boolean povMoved(Controller controller, int povCode, PovDirection value){
return false;
};
@Override
public boolean xSliderMoved(Controller controller, int sliderCode, boolean value){
return false;
};
@Override
public boolean ySliderMoved(Controller controller, int sliderCode, boolean value){
return false;
};
@Override
public boolean accelerometerMoved(Controller controller, int accelerometerCode, Vector3 value){
return false;
};
}

View File

@@ -0,0 +1,234 @@
/*
* Copyright (C) 2014 Miguel Angel Astor Romero
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ve.ucv.ciens.ccg.nxtar.states;
import java.util.Arrays;
import ve.ucv.ciens.ccg.nxtar.NxtARCore;
import ve.ucv.ciens.ccg.nxtar.NxtARCore.game_states_t;
import ve.ucv.ciens.ccg.nxtar.interfaces.ImageProcessor.CalibrationData;
import ve.ucv.ciens.ccg.nxtar.network.monitors.VideoFrameMonitor;
import ve.ucv.ciens.ccg.nxtar.utils.ProjectConstants;
import ve.ucv.ciens.ccg.nxtar.utils.Size;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.controllers.mappings.Ouya;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Pixmap;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.Texture.TextureFilter;
import com.badlogic.gdx.graphics.Texture.TextureWrap;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.graphics.glutils.ShaderProgram;
public class CameraCalibrationState extends BaseState{
private static final String TAG = "CAMERA_CALIBRATION_STATE";
private static final String CLASS_NAME = CameraCalibrationState.class.getSimpleName();
private static final String SHADER_PATH = "shaders/bckg/bckg";
private NxtARCore core;
private boolean cameraCalibrated;
private float u_scaling[];
protected Sprite background;
private Texture backgroundTexture;
private ShaderProgram backgroundShader;
// Cameras.
private OrthographicCamera camera;
// Video stream graphics.
private Texture videoFrameTexture;
private Sprite renderableVideoFrame;
private Pixmap videoFrame;
// Monitors.
private VideoFrameMonitor frameMonitor;
private float[][] calibrationSamples;
private int lastSampleTaken;
public CameraCalibrationState(final NxtARCore core){
this.core = core;
frameMonitor = VideoFrameMonitor.getInstance();
cameraCalibrated = false;
// Set up the cameras.
pixelPerfectCamera = new OrthographicCamera(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
camera = new OrthographicCamera(1.0f, Gdx.graphics.getHeight() / Gdx.graphics.getWidth());
// Set up the background.
backgroundTexture = new Texture(Gdx.files.internal("data/gfx/textures/tile_aqua.png"));
backgroundTexture.setWrap(TextureWrap.Repeat, TextureWrap.Repeat);
backgroundTexture.setFilter(TextureFilter.Linear, TextureFilter.Linear);
background = new Sprite(backgroundTexture);
background.setSize(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
background.setPosition(-(Gdx.graphics.getWidth() / 2), -(Gdx.graphics.getHeight() / 2));
// Load the background shader.
backgroundShader = new ShaderProgram(Gdx.files.internal(SHADER_PATH + "_vert.glsl"), Gdx.files.internal(SHADER_PATH + "_frag.glsl"));
if(!backgroundShader.isCompiled()){
Gdx.app.error(TAG, CLASS_NAME + ".CameraCalibrationState() :: Failed to compile the background shader.");
Gdx.app.error(TAG, CLASS_NAME + backgroundShader.getLog());
backgroundShader = null;
}
// Set up the background scaling.
u_scaling = new float[2];
u_scaling[0] = Gdx.graphics.getWidth() > Gdx.graphics.getHeight() ? 16.0f : 9.0f;
u_scaling[1] = Gdx.graphics.getHeight() > Gdx.graphics.getWidth() ? 16.0f : 9.0f;
// Initialize the calibration samples vector.
calibrationSamples = new float[ProjectConstants.CALIBRATION_SAMPLES][];
for(int i = 0; i < calibrationSamples.length; i++){
calibrationSamples[i] = new float[ProjectConstants.CALIBRATION_PATTERN_POINTS * 2];
}
}
@Override
public void onStateSet(){
Gdx.input.setInputProcessor(this);
Gdx.input.setCatchBackKey(true);
Gdx.input.setCatchMenuKey(true);
lastSampleTaken = 0;
cameraCalibrated = false;
for(int i = 0; i < calibrationSamples.length; i++){
for(int j = 0; j < calibrationSamples[i].length; j++){
calibrationSamples[i][j] = 0.0f;
}
}
}
@Override
public void onStateUnset(){ }
@Override
public void render(float delta){
byte[] frame;
byte[] prevFrame = null;
Size dimensions = null;
// Clear the screen.
Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
// Render the background.
core.batch.setProjectionMatrix(pixelPerfectCamera.combined);
core.batch.begin();{
if(backgroundShader != null){
core.batch.setShader(backgroundShader);
backgroundShader.setUniform2fv("u_scaling", u_scaling, 0, 2);
}
background.draw(core.batch);
if(backgroundShader != null) core.batch.setShader(null);
}core.batch.end();
// Fetch the current video frame.
frame = frameMonitor.getCurrentFrame();
// Find the calibration points in the video frame.
CalibrationData data = core.cvProc.findCalibrationPattern(frame);
// If the user requested a sample be taken.
if(!cameraCalibrated && data.calibrationPoints != null){
Gdx.app.log(TAG, CLASS_NAME + ".render(): Sample taken.");
// Save the calibration points to the samples array.
for(int i = 0; i < data.calibrationPoints.length; i += 2){
Gdx.app.log(TAG, CLASS_NAME + ".render(): Value " + Integer.toString(i) + " = (" + Float.toString(data.calibrationPoints[i]) + ", " + Float.toString(data.calibrationPoints[i + 1]) + ")");
calibrationSamples[lastSampleTaken][i] = data.calibrationPoints[i];
calibrationSamples[lastSampleTaken][i + 1] = data.calibrationPoints[i + 1];
}
// Move to the next sample.
lastSampleTaken++;
// If enough samples has been taken then calibrate the camera.
if(lastSampleTaken == ProjectConstants.CALIBRATION_SAMPLES){
Gdx.app.log(TAG, CLASS_NAME + "render(): Last sample taken.");
core.cvProc.calibrateCamera(calibrationSamples, frame);
cameraCalibrated = core.cvProc.isCameraCalibrated();
core.onCameraCalibrated();
core.nextState = game_states_t.MAIN_MENU;
}
}
if(frame != null && data != null && data.outFrame != null && !Arrays.equals(frame, prevFrame)){
// If the received frame is valid and is different from the previous frame.
// Make a texture from the frame.
dimensions = frameMonitor.getFrameDimensions();
videoFrame = new Pixmap(data.outFrame, 0, dimensions.getWidth() * dimensions.getHeight());
videoFrameTexture = new Texture(videoFrame);
videoFrameTexture.setFilter(TextureFilter.Linear, TextureFilter.Linear);
videoFrame.dispose();
// Set up the frame texture as a rendereable sprite.
TextureRegion region = new TextureRegion(videoFrameTexture, 0, 0, dimensions.getWidth(), dimensions.getHeight());
renderableVideoFrame = new Sprite(region);
renderableVideoFrame.setOrigin(renderableVideoFrame.getWidth() / 2, renderableVideoFrame.getHeight() / 2);
if(!Ouya.runningOnOuya){
renderableVideoFrame.setSize(1.0f, renderableVideoFrame.getHeight() / renderableVideoFrame.getWidth() );
renderableVideoFrame.rotate90(true);
renderableVideoFrame.translate(-renderableVideoFrame.getWidth() / 2, 0.5f - renderableVideoFrame.getHeight());
}else{
float xSize = Gdx.graphics.getHeight() * (dimensions.getWidth() / dimensions.getHeight());
renderableVideoFrame.setSize(xSize * ProjectConstants.OVERSCAN, Gdx.graphics.getHeight() * ProjectConstants.OVERSCAN);
renderableVideoFrame.rotate90(true);
renderableVideoFrame.translate(-renderableVideoFrame.getWidth() / 2, -renderableVideoFrame.getHeight() / 2);
}
// Render the frame.
if(!Ouya.runningOnOuya) core.batch.setProjectionMatrix(camera.combined);
else core.batch.setProjectionMatrix(pixelPerfectCamera.combined);
core.batch.begin();{
renderableVideoFrame.draw(core.batch);
}core.batch.end();
// Clear texture memory.
videoFrameTexture.dispose();
}
// Save this frame as previous to avoid processing the same frame twice when network latency is high.
prevFrame = frame;
}
@Override
public void dispose(){
if(videoFrameTexture != null)
videoFrameTexture.dispose();
backgroundTexture.dispose();
if(backgroundShader != null) backgroundShader.dispose();
}
/*;;;;;;;;;;;;;;;;;;;;;;;;;;
; INPUT LISTENER METHODS ;
;;;;;;;;;;;;;;;;;;;;;;;;;;*/
@Override
public boolean keyDown(int keycode){
if(keycode == Input.Keys.BACK){
core.nextState = game_states_t.MAIN_MENU;
return true;
}
return false;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,327 @@
/*
* Copyright (C) 2013 Miguel Angel Astor Romero
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ve.ucv.ciens.ccg.nxtar.states;
import ve.ucv.ciens.ccg.nxtar.NxtARCore;
import ve.ucv.ciens.ccg.nxtar.NxtARCore.game_states_t;
import ve.ucv.ciens.ccg.nxtar.scenarios.HintsOverlayBase;
import ve.ucv.ciens.ccg.nxtar.scenarios.ScenarioGlobals;
import ve.ucv.ciens.ccg.nxtar.utils.ProjectConstants;
import ve.ucv.ciens.ccg.nxtar.utils.Utils;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.controllers.Controller;
import com.badlogic.gdx.controllers.mappings.Ouya;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.Texture.TextureFilter;
import com.badlogic.gdx.graphics.Texture.TextureWrap;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.NinePatch;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator;
import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator.FreeTypeFontParameter;
import com.badlogic.gdx.graphics.glutils.ShaderProgram;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.scenes.scene2d.ui.TextButton;
import com.badlogic.gdx.scenes.scene2d.ui.TextButton.TextButtonStyle;
import com.badlogic.gdx.scenes.scene2d.utils.NinePatchDrawable;
public class InstructionsState extends BaseState {
private static final String TAG = "HINTS_STATE";
private static final String CLASS_NAME = InstructionsState.class.getSimpleName();
private static final String SHADER_PATH = "shaders/movingBckg/movingBckg";
// Helper fields.
private float u_scaling[];
private float u_displacement;
// Buttons and other gui components.
private TextButton continueButton;
private Rectangle continueButtonBBox;
private Sprite background;
private Texture backgroundTexture;
private ShaderProgram backgroundShader;
private Texture ouyaOButtonTexture;
private Sprite ouyaOButton;
private boolean oButtonPressed;
// Graphic data for the start button.
private Texture buttonEnabledTexture;
private Texture buttonDisabledTexture;
private Texture buttonPressedTexture;
private BitmapFont font;
// Overlay related fields.
HintsOverlayBase hintsOverlay;
// Button touch helper fields.
private boolean continueButtonTouched;
private int continueButtonTouchPointer;
public InstructionsState(NxtARCore core) throws IllegalArgumentException{
TextButtonStyle textButtonStyle;
FreeTypeFontGenerator fontGenerator;
FreeTypeFontParameter fontParameters;
NinePatch buttonEnabled9p;
NinePatch buttonDisabled9p;
NinePatch buttonPressed9p;
if(core == null)
throw new IllegalArgumentException(CLASS_NAME + ": Core is null.");
this.core = core;
this.pixelPerfectCamera = new OrthographicCamera(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
oButtonPressed = false;
hintsOverlay = ScenarioGlobals.getHintsOverlay();
// Create the start button background.
buttonEnabledTexture = new Texture(Gdx.files.internal("data/gfx/gui/Anonymous_Pill_Button_Yellow.png"));
buttonEnabled9p = new NinePatch(new TextureRegion(buttonEnabledTexture, 0, 0, buttonEnabledTexture.getWidth(), buttonEnabledTexture.getHeight()), 49, 49, 45, 45);
buttonDisabledTexture = new Texture(Gdx.files.internal("data/gfx/gui/Anonymous_Pill_Button_Cyan.png"));
buttonDisabled9p = new NinePatch(new TextureRegion(buttonDisabledTexture, 0, 0, buttonDisabledTexture.getWidth(), buttonDisabledTexture.getHeight()), 49, 49, 45, 45);
buttonPressedTexture = new Texture(Gdx.files.internal("data/gfx/gui/Anonymous_Pill_Button_Blue.png"));
buttonPressed9p = new NinePatch(new TextureRegion(buttonPressedTexture, 0, 0, buttonPressedTexture.getWidth(), buttonPressedTexture.getHeight()), 49, 49, 45, 45);
// Create the start button font.
fontParameters = new FreeTypeFontParameter();
fontParameters.characters = ProjectConstants.FONT_CHARS;
fontParameters.size = ProjectConstants.MENU_BUTTON_FONT_SIZE;
fontParameters.flip = false;
fontGenerator = new FreeTypeFontGenerator(Gdx.files.internal("data/fonts/d-puntillas-B-to-tiptoe.ttf"));
font = fontGenerator.generateFont(fontParameters);
fontGenerator.dispose();
// Create the contine button.
textButtonStyle = new TextButtonStyle();
textButtonStyle.font = font;
textButtonStyle.up = new NinePatchDrawable(buttonEnabled9p);
textButtonStyle.checked = new NinePatchDrawable(buttonPressed9p);
textButtonStyle.disabled = new NinePatchDrawable(buttonDisabled9p);
textButtonStyle.fontColor = new Color(Color.BLACK);
textButtonStyle.downFontColor = new Color(Color.WHITE);
textButtonStyle.disabledFontColor = new Color(Color.BLACK);
continueButton = new TextButton("Continue", textButtonStyle);
continueButton.setText("Continue");
continueButton.setPosition(-(continueButton.getWidth() / 2), -(Utils.getScreenHeightWithOverscan() / 2) + 10);
continueButtonBBox = new Rectangle(0, 0, continueButton.getWidth(), continueButton.getHeight());
continueButtonBBox.setPosition(continueButton.getX(), continueButton.getY());
// Set OUYA's O button.
if(Ouya.runningOnOuya){
ouyaOButtonTexture = new Texture("data/gfx/gui/OUYA_O.png");
ouyaOButton = new Sprite(ouyaOButtonTexture);
ouyaOButton.setSize(ouyaOButton.getWidth() * 0.6f, ouyaOButton.getHeight() * 0.6f);
ouyaOButton.setPosition(continueButton.getX() - ouyaOButton.getWidth() - 20, continueButton.getY() + (ouyaOButton.getHeight() / 2));
oButtonPressed = false;
}else{
ouyaOButtonTexture = null;
}
// Set up the background.
backgroundTexture = new Texture(Gdx.files.internal("data/gfx/textures/tile_aqua.png"));
backgroundTexture.setWrap(TextureWrap.Repeat, TextureWrap.Repeat);
backgroundTexture.setFilter(TextureFilter.Linear, TextureFilter.Linear);
background = new Sprite(backgroundTexture);
background.setSize(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
background.setPosition(-(Gdx.graphics.getWidth() / 2), -(Gdx.graphics.getHeight() / 2));
backgroundShader = new ShaderProgram(Gdx.files.internal(SHADER_PATH + "_vert.glsl"), Gdx.files.internal(SHADER_PATH + "_frag.glsl"));
if(!backgroundShader.isCompiled()){
Gdx.app.error(TAG, CLASS_NAME + ".MainMenuStateBase() :: Failed to compile the background shader.");
Gdx.app.error(TAG, CLASS_NAME + backgroundShader.getLog());
backgroundShader = null;
}
u_scaling = new float[2];
u_scaling[0] = Gdx.graphics.getWidth() > Gdx.graphics.getHeight() ? 16.0f : 9.0f;
u_scaling[1] = Gdx.graphics.getHeight() > Gdx.graphics.getWidth() ? 16.0f : 9.0f;
u_displacement = 1.0f;
win2world = new Vector3(0.0f, 0.0f, 0.0f);
touchPointWorldCoords = new Vector2();
continueButtonTouched = false;
continueButtonTouchPointer = -1;
stateActive = false;
}
@Override
public void render(float delta){
Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
core.batch.setProjectionMatrix(pixelPerfectCamera.combined);
core.batch.begin();{
// Render background.
core.batch.disableBlending();
drawBackground(core.batch);
core.batch.enableBlending();
hintsOverlay.render(core.batch);
// Render buttons.
continueButton.draw(core.batch, 1.0f);
if(Ouya.runningOnOuya)
ouyaOButton.draw(core.batch);
}core.batch.end();
}
@Override
public void dispose(){
buttonEnabledTexture.dispose();
buttonDisabledTexture.dispose();
buttonPressedTexture.dispose();
if(ouyaOButtonTexture != null)
ouyaOButtonTexture.dispose();
backgroundTexture.dispose();
if(backgroundShader != null) backgroundShader.dispose();
font.dispose();
}
private void drawBackground(SpriteBatch batch){
if(backgroundShader != null){
batch.setShader(backgroundShader);
backgroundShader.setUniform2fv("u_scaling", u_scaling, 0, 2);
backgroundShader.setUniformf("u_displacement", u_displacement);
}
background.draw(batch);
if(backgroundShader != null) batch.setShader(null);
u_displacement = u_displacement < 0.0f ? 1.0f : u_displacement - 0.0005f;
}
@Override
public void onStateSet(){
stateActive = true;
Gdx.input.setInputProcessor(this);
Gdx.input.setCatchBackKey(true);
Gdx.input.setCatchMenuKey(true);
}
@Override
public void onStateUnset(){
stateActive = false;
Gdx.input.setInputProcessor(null);
Gdx.input.setCatchBackKey(false);
Gdx.input.setCatchMenuKey(false);
}
/*;;;;;;;;;;;;;;;;;;;;;;;;;;
; INPUT LISTENER METHODS ;
;;;;;;;;;;;;;;;;;;;;;;;;;;*/
@Override
public boolean touchDown(int screenX, int screenY, int pointer, int button){
unprojectTouch(screenX, screenY);
Gdx.app.log(TAG, CLASS_NAME + String.format(".touchDown(%d, %d, %d, %d)", screenX, screenY, pointer, button));
Gdx.app.log(TAG, CLASS_NAME + String.format(".touchDown() :: Unprojected touch point: (%f, %f)", touchPointWorldCoords.x, touchPointWorldCoords.y));
if(!continueButton.isDisabled() && continueButtonBBox.contains(touchPointWorldCoords)){
continueButton.setChecked(true);
continueButtonTouched = true;
continueButtonTouchPointer = pointer;
Gdx.app.log(TAG, CLASS_NAME + ".touchDown() :: Start button pressed.");
}
return true;
}
@Override
public boolean touchUp(int screenX, int screenY, int pointer, int button){
unprojectTouch(screenX, screenY);
Gdx.app.log(TAG, CLASS_NAME + String.format(".touchUp(%d, %d, %d, %d)", screenX, screenY, pointer, button));
Gdx.app.log(TAG, CLASS_NAME + String.format(".touchUp() :: Unprojected touch point: (%f, %f)", touchPointWorldCoords.x, touchPointWorldCoords.y));
if(!continueButton.isDisabled() && continueButtonBBox.contains(touchPointWorldCoords) && continueButtonTouched){
continueButton.setChecked(false);
continueButtonTouched = false;
continueButtonTouchPointer = -1;
core.nextState = game_states_t.IN_GAME;
Gdx.app.log(TAG, CLASS_NAME + ".touchDown() :: Start button released.");
}
return true;
}
@Override
public boolean touchDragged(int screenX, int screenY, int pointer){
unprojectTouch(screenX, screenY);
if(!continueButton.isDisabled() && continueButtonTouched && pointer == continueButtonTouchPointer && !continueButtonBBox.contains(touchPointWorldCoords)){
continueButtonTouchPointer = -1;
continueButtonTouched = false;
continueButton.setChecked(false);
Gdx.app.log(TAG, CLASS_NAME + ".touchDragged() :: Start button released.");
}
return true;
}
@Override
public boolean keyDown(int keycode){
if(keycode == Input.Keys.BACK){
core.nextState = game_states_t.IN_GAME;
return true;
}
return false;
}
/*;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; CONTROLLER LISTENER METHODS ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;*/
@Override
public boolean buttonDown(Controller controller, int buttonCode){
if(stateActive){
if(buttonCode == Ouya.BUTTON_O && !continueButton.isDisabled()){
Gdx.app.log(TAG, CLASS_NAME + ".buttonDown(): O button pressed.");
oButtonPressed = true;
continueButton.setChecked(true);
}
return true;
}else{
return false;
}
}
@Override
public boolean buttonUp(Controller controller, int buttonCode){
if(stateActive){
if(buttonCode == Ouya.BUTTON_O){
Gdx.app.log(TAG, CLASS_NAME + ".buttonDown(): O button released.");
if(oButtonPressed){
oButtonPressed = false;
continueButton.setChecked(false);
core.nextState = game_states_t.IN_GAME;
}
}
return true;
}else{
return false;
}
}
}

View File

@@ -0,0 +1,348 @@
/*
* Copyright (C) 2014 Miguel Angel Astor Romero
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ve.ucv.ciens.ccg.nxtar.states;
import ve.ucv.ciens.ccg.nxtar.NxtARCore.game_states_t;
import ve.ucv.ciens.ccg.nxtar.utils.ProjectConstants;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.Texture.TextureFilter;
import com.badlogic.gdx.graphics.Texture.TextureWrap;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.NinePatch;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator;
import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator.FreeTypeFontParameter;
import com.badlogic.gdx.graphics.glutils.ShaderProgram;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.scenes.scene2d.ui.TextButton;
import com.badlogic.gdx.scenes.scene2d.ui.TextButton.TextButtonStyle;
import com.badlogic.gdx.scenes.scene2d.utils.NinePatchDrawable;
public abstract class MainMenuStateBase extends BaseState{
protected static final String TAG = "MAIN_MENU";
private static final String CLASS_NAME = MainMenuStateBase.class.getSimpleName();
private static final String SHADER_PATH = "shaders/movingBckg/movingBckg";
protected final int NUM_MENU_BUTTONS = 3;
// Helper fields.
protected boolean clientConnected;
protected boolean cameraCalibrated;
protected boolean assetsLoaded;
private float u_scaling[];
private float u_displacement;
// Buttons and other gui components.
protected TextButton startButton;
protected Rectangle startButtonBBox;
protected TextButton calibrationButton;
protected Rectangle calibrationButtonBBox;
protected TextButton autoButton;
protected Rectangle autoButtonBBox;
protected Sprite cameraCalibratedLedOn;
protected Sprite cameraCalibratedLedOff;
protected Sprite assetsLoadedLedOn;
protected Sprite assetsLoadedLedOff;
protected Sprite background;
// Graphic data for the start button.
private Texture menuButtonEnabledTexture;
private Texture menuButtonDisabledTexture;
private Texture menuButtonPressedTexture;
private NinePatch menuButtonEnabled9p;
private NinePatch menuButtonDisabled9p;
private NinePatch menuButtonPressed9p;
private BitmapFont font;
// Other graphics.
private Texture ledOffTexture;
private Texture ledOnTexture;
private Texture backgroundTexture;
private ShaderProgram backgroundShader;
// Button touch helper fields.
protected boolean startButtonTouched;
protected int startButtonTouchPointer;
protected boolean calibrationButtonTouched;
protected int calibrationButtonTouchPointer;
protected boolean autoButtonTouched;
protected int autoButtonTouchPointer;
public MainMenuStateBase(){
TextureRegion region;
TextButtonStyle textButtonStyle;
FreeTypeFontGenerator fontGenerator;
FreeTypeFontParameter fontParameters;
this.pixelPerfectCamera = new OrthographicCamera(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
// Create the start button background.
menuButtonEnabledTexture = new Texture(Gdx.files.internal("data/gfx/gui/Anonymous_Pill_Button_Yellow.png"));
menuButtonEnabled9p = new NinePatch(new TextureRegion(menuButtonEnabledTexture, 0, 0, menuButtonEnabledTexture.getWidth(), menuButtonEnabledTexture.getHeight()), 49, 49, 45, 45);
menuButtonDisabledTexture = new Texture(Gdx.files.internal("data/gfx/gui/Anonymous_Pill_Button_Cyan.png"));
menuButtonDisabled9p = new NinePatch(new TextureRegion(menuButtonDisabledTexture, 0, 0, menuButtonDisabledTexture.getWidth(), menuButtonDisabledTexture.getHeight()), 49, 49, 45, 45);
menuButtonPressedTexture = new Texture(Gdx.files.internal("data/gfx/gui/Anonymous_Pill_Button_Blue.png"));
menuButtonPressed9p = new NinePatch(new TextureRegion(menuButtonPressedTexture, 0, 0, menuButtonPressedTexture.getWidth(), menuButtonPressedTexture.getHeight()), 49, 49, 45, 45);
// Create the start button font.
fontParameters = new FreeTypeFontParameter();
fontParameters.characters = ProjectConstants.FONT_CHARS;
fontParameters.size = ProjectConstants.MENU_BUTTON_FONT_SIZE;
fontParameters.flip = false;
fontGenerator = new FreeTypeFontGenerator(Gdx.files.internal("data/fonts/d-puntillas-B-to-tiptoe.ttf"));
font = fontGenerator.generateFont(fontParameters);
fontGenerator.dispose();
// Create the buttons.
textButtonStyle = new TextButtonStyle();
textButtonStyle.font = font;
textButtonStyle.up = new NinePatchDrawable(menuButtonEnabled9p);
textButtonStyle.checked = new NinePatchDrawable(menuButtonPressed9p);
textButtonStyle.disabled = new NinePatchDrawable(menuButtonDisabled9p);
textButtonStyle.fontColor = new Color(Color.BLACK);
textButtonStyle.downFontColor = new Color(Color.WHITE);
textButtonStyle.disabledFontColor = new Color(Color.BLACK);
startButton = new TextButton("Manual control", textButtonStyle);
startButton.setText("Manual control");
startButton.setDisabled(true);
startButtonBBox = new Rectangle(0, 0, startButton.getWidth(), startButton.getHeight());
calibrationButton = new TextButton("Calibrate camera", textButtonStyle);
calibrationButton.setText("Calibrate camera");
calibrationButton.setDisabled(true);
calibrationButtonBBox = new Rectangle(0, 0, calibrationButton.getWidth(), calibrationButton.getHeight());
autoButton = new TextButton("Automatic action", textButtonStyle);
autoButton.setText("Automatic action");
autoButton.setDisabled(true);
autoButtonBBox = new Rectangle(0, 0, autoButton.getWidth(), autoButton.getHeight());
// Create the connection leds.
ledOnTexture = new Texture("data/gfx/gui/Anonymous_Button_Green.png");
ledOffTexture = new Texture("data/gfx/gui/Anonymous_Button_Red.png");
region = new TextureRegion(ledOnTexture);
cameraCalibratedLedOn = new Sprite(region);
region = new TextureRegion(ledOffTexture);
cameraCalibratedLedOff = new Sprite(region);
region = new TextureRegion(ledOnTexture);
assetsLoadedLedOn = new Sprite(region);
region = new TextureRegion(ledOffTexture);
assetsLoadedLedOff = new Sprite(region);
// Set up the background.
backgroundTexture = new Texture(Gdx.files.internal("data/gfx/textures/tile_aqua.png"));
backgroundTexture.setWrap(TextureWrap.Repeat, TextureWrap.Repeat);
backgroundTexture.setFilter(TextureFilter.Linear, TextureFilter.Linear);
region = new TextureRegion(backgroundTexture);
background = new Sprite(backgroundTexture);
background.setSize(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
background.setPosition(-(Gdx.graphics.getWidth() / 2), -(Gdx.graphics.getHeight() / 2));
backgroundShader = new ShaderProgram(Gdx.files.internal(SHADER_PATH + "_vert.glsl"), Gdx.files.internal(SHADER_PATH + "_frag.glsl"));
if(!backgroundShader.isCompiled()){
Gdx.app.error(TAG, CLASS_NAME + ".MainMenuStateBase() :: Failed to compile the background shader.");
Gdx.app.error(TAG, CLASS_NAME + backgroundShader.getLog());
backgroundShader = null;
}
u_scaling = new float[2];
u_scaling[0] = Gdx.graphics.getWidth() > Gdx.graphics.getHeight() ? 16.0f : 9.0f;
u_scaling[1] = Gdx.graphics.getHeight() > Gdx.graphics.getWidth() ? 16.0f : 9.0f;
u_displacement = 1.0f;
win2world = new Vector3(0.0f, 0.0f, 0.0f);
touchPointWorldCoords = new Vector2();
startButtonTouched = false;
startButtonTouchPointer = -1;
calibrationButtonTouched = false;
calibrationButtonTouchPointer = -1;
autoButtonTouched = false;
autoButtonTouchPointer = -1;
clientConnected = false;
cameraCalibrated = false;
assetsLoaded = false;
stateActive = false;
}
@Override
public abstract void render(float delta);
@Override
public void dispose(){
menuButtonEnabledTexture.dispose();
menuButtonDisabledTexture.dispose();
menuButtonPressedTexture.dispose();
ledOnTexture.dispose();
ledOffTexture.dispose();
backgroundTexture.dispose();
if(backgroundShader != null) backgroundShader.dispose();
font.dispose();
}
protected void drawBackground(SpriteBatch batch){
if(backgroundShader != null){
batch.setShader(backgroundShader);
backgroundShader.setUniform2fv("u_scaling", u_scaling, 0, 2);
backgroundShader.setUniformf("u_displacement", u_displacement);
}
background.draw(batch);
if(backgroundShader != null) batch.setShader(null);
u_displacement = u_displacement < 0.0f ? 1.0f : u_displacement - 0.0005f;
}
@Override
public void onStateSet(){
stateActive = true;
Gdx.input.setInputProcessor(this);
Gdx.input.setCatchBackKey(true);
Gdx.input.setCatchMenuKey(true);
}
@Override
public void onStateUnset(){
stateActive = false;
Gdx.input.setInputProcessor(null);
Gdx.input.setCatchBackKey(false);
Gdx.input.setCatchMenuKey(false);
}
public void onClientConnected(){
clientConnected = true;
calibrationButton.setDisabled(false);
}
public void onCameraCalibrated(){
cameraCalibrated = true;
enableGameButtons();
}
public void onAssetsLoaded(){
assetsLoaded = true;
enableGameButtons();
}
private void enableGameButtons(){
startButton.setDisabled(!(cameraCalibrated && assetsLoaded));
autoButton.setDisabled(!(cameraCalibrated && assetsLoaded));
}
/*;;;;;;;;;;;;;;;;;;;;;;;;;;
; INPUT LISTENER METHODS ;
;;;;;;;;;;;;;;;;;;;;;;;;;;*/
@Override
public boolean touchDown(int screenX, int screenY, int pointer, int button){
unprojectTouch(screenX, screenY);
Gdx.app.log(TAG, CLASS_NAME + String.format(".touchDown(%d, %d, %d, %d)", screenX, screenY, pointer, button));
Gdx.app.log(TAG, CLASS_NAME + String.format(".touchDown() :: Unprojected touch point: (%f, %f)", touchPointWorldCoords.x, touchPointWorldCoords.y));
if(!startButton.isDisabled() && startButtonBBox.contains(touchPointWorldCoords) && (!calibrationButtonTouched && !autoButtonTouched)){
startButton.setChecked(true);
startButtonTouched = true;
startButtonTouchPointer = pointer;
Gdx.app.log(TAG, CLASS_NAME + ".touchDown() :: Start button pressed.");
}else if(!calibrationButton.isDisabled() && calibrationButtonBBox.contains(touchPointWorldCoords) && (!startButtonTouched && !autoButtonTouched)){
calibrationButton.setChecked(true);
calibrationButtonTouched = true;
calibrationButtonTouchPointer = pointer;
Gdx.app.log(TAG, CLASS_NAME + ".touchDown() :: Calibration button pressed.");
}else if(!autoButton.isDisabled() && autoButtonBBox.contains(touchPointWorldCoords) && (!startButtonTouched && !calibrationButtonTouched)){
autoButton.setChecked(true);
autoButtonTouched = true;
autoButtonTouchPointer = pointer;
Gdx.app.log(TAG, CLASS_NAME + ".touchDown() :: Auto button pressed.");
}
return true;
}
@Override
public boolean touchUp(int screenX, int screenY, int pointer, int button){
unprojectTouch(screenX, screenY);
Gdx.app.log(TAG, CLASS_NAME + String.format(".touchUp(%d, %d, %d, %d)", screenX, screenY, pointer, button));
Gdx.app.log(TAG, CLASS_NAME + String.format(".touchUp() :: Unprojected touch point: (%f, %f)", touchPointWorldCoords.x, touchPointWorldCoords.y));
if(!startButton.isDisabled() && startButtonBBox.contains(touchPointWorldCoords) && startButtonTouched){
startButton.setChecked(false);
startButtonTouched = false;
startButtonTouchPointer = -1;
core.nextState = game_states_t.IN_GAME;
Gdx.app.log(TAG, CLASS_NAME + ".touchDown() :: Start button released.");
}else if(!calibrationButton.isDisabled() && calibrationButtonBBox.contains(touchPointWorldCoords) && calibrationButtonTouched){
calibrationButton.setChecked(false);
calibrationButtonTouched = false;
calibrationButtonTouchPointer = -1;
core.nextState = game_states_t.CALIBRATION;
Gdx.app.log(TAG, CLASS_NAME + ".touchDown() :: Calibration button released.");
}else if(!autoButton.isDisabled() && autoButtonBBox.contains(touchPointWorldCoords) && autoButtonTouched){
autoButton.setChecked(false);
autoButtonTouched = false;
autoButtonTouchPointer = -1;
core.nextState = game_states_t.AUTOMATIC_ACTION;
Gdx.app.log(TAG, CLASS_NAME + ".touchDown() :: Auto button released.");
}
return true;
}
@Override
public boolean touchDragged(int screenX, int screenY, int pointer){
unprojectTouch(screenX, screenY);
if(!startButton.isDisabled() && startButtonTouched && pointer == startButtonTouchPointer && !startButtonBBox.contains(touchPointWorldCoords)){
startButtonTouchPointer = -1;
startButtonTouched = false;
startButton.setChecked(false);
Gdx.app.log(TAG, CLASS_NAME + ".touchDragged() :: Start button released.");
}else if(!calibrationButton.isDisabled() && calibrationButtonTouched && pointer == calibrationButtonTouchPointer && !calibrationButtonBBox.contains(touchPointWorldCoords)){
calibrationButtonTouchPointer = -1;
calibrationButtonTouched = false;
calibrationButton.setChecked(false);
Gdx.app.log(TAG, CLASS_NAME + ".touchDragged() :: Start button released.");
}else if(!autoButton.isDisabled() && autoButtonTouched && pointer == autoButtonTouchPointer && !autoButtonBBox.contains(touchPointWorldCoords)){
autoButtonTouchPointer = -1;
autoButtonTouched = false;
autoButton.setChecked(false);
Gdx.app.log(TAG, CLASS_NAME + ".touchDragged() :: Auto button released.");
}
return true;
}
@Override
public boolean keyDown(int keycode){
if(keycode == Input.Keys.BACK){
Gdx.app.exit();
return true;
}
return false;
}
}

View File

@@ -0,0 +1,209 @@
/*
* Copyright (C) 2014 Miguel Angel Astor Romero
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ve.ucv.ciens.ccg.nxtar.states;
import ve.ucv.ciens.ccg.nxtar.NxtARCore;
import ve.ucv.ciens.ccg.nxtar.NxtARCore.game_states_t;
import ve.ucv.ciens.ccg.nxtar.utils.Utils;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.controllers.Controller;
import com.badlogic.gdx.controllers.mappings.Ouya;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
public class OuyaMainMenuState extends MainMenuStateBase{
private static final String CLASS_NAME = OuyaMainMenuState.class.getSimpleName();
private Texture ouyaOButtonTexture;
private Sprite ouyaOButton;
private boolean oButtonPressed;
private int oButtonSelection;
private float ledYPos;
public OuyaMainMenuState(final NxtARCore core) throws IllegalArgumentException{
super();
if(core == null)
throw new IllegalArgumentException(CLASS_NAME + ": Core is null.");
this.core = core;
// Set buttons.
startButton.setPosition(-(startButton.getWidth() / 2), -(startButton.getHeight() / 2));
startButtonBBox.setPosition(startButton.getX(), startButton.getY());
calibrationButton.setPosition(-(calibrationButton.getWidth() / 2), (startButton.getY() + startButton.getHeight()) + 10);
calibrationButtonBBox.setPosition(calibrationButton.getX(), calibrationButton.getY());
autoButton.setPosition(-(autoButton.getWidth() / 2), (startButton.getY() - startButton.getHeight()) - 10);
autoButtonBBox.setPosition(autoButton.getX(), autoButton.getY());
//Set leds.
ledYPos = -(Utils.getScreenHeightWithOverscan() / 2) + 10;
cameraCalibratedLedOn.setSize(cameraCalibratedLedOn.getWidth() * 0.5f, cameraCalibratedLedOn.getHeight() * 0.5f);
cameraCalibratedLedOn.setPosition(-cameraCalibratedLedOn.getWidth() - 5, ledYPos);
cameraCalibratedLedOff.setSize(cameraCalibratedLedOff.getWidth() * 0.5f, cameraCalibratedLedOff.getHeight() * 0.5f);
cameraCalibratedLedOff.setPosition(-cameraCalibratedLedOff.getWidth() - 5, ledYPos);
assetsLoadedLedOn.setSize(assetsLoadedLedOn.getWidth() * 0.5f, assetsLoadedLedOn.getHeight() * 0.5f);
assetsLoadedLedOn.setPosition(5, ledYPos);
assetsLoadedLedOff.setSize(assetsLoadedLedOff.getWidth() * 0.5f, assetsLoadedLedOff.getHeight() * 0.5f);
assetsLoadedLedOff.setPosition(5, ledYPos);
// Set OUYA's O button.
ouyaOButtonTexture = new Texture("data/gfx/gui/OUYA_O.png");
TextureRegion region = new TextureRegion(ouyaOButtonTexture, ouyaOButtonTexture.getWidth(), ouyaOButtonTexture.getHeight());
ouyaOButton = new Sprite(region);
ouyaOButton.setSize(ouyaOButton.getWidth() * 0.6f, ouyaOButton.getHeight() * 0.6f);
oButtonSelection = 0;
oButtonPressed = false;
}
@Override
public void render(float delta) {
Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
core.batch.setProjectionMatrix(pixelPerfectCamera.combined);
core.batch.begin();{
// Render background.
core.batch.disableBlending();
drawBackground(core.batch);
core.batch.enableBlending();
// Render leds.
if(cameraCalibrated) cameraCalibratedLedOn.draw(core.batch);
else cameraCalibratedLedOff.draw(core.batch);
if(assetsLoaded) assetsLoadedLedOn.draw(core.batch);
else assetsLoadedLedOff.draw(core.batch);
// Render buttons.
startButton.draw(core.batch, 1.0f);
calibrationButton.draw(core.batch, 1.0f);
autoButton.draw(core.batch, 1.0f);
// Render O button.
if(oButtonSelection == 0){
ouyaOButton.setPosition(startButton.getX() - ouyaOButton.getWidth() - 20, startButton.getY() + (ouyaOButton.getHeight() / 2));
}else if(oButtonSelection == 1){
ouyaOButton.setPosition(calibrationButton.getX() - ouyaOButton.getWidth() - 20, calibrationButton.getY() + (ouyaOButton.getHeight() / 2));
}else if(oButtonSelection == 2){
ouyaOButton.setPosition(autoButton.getX() - ouyaOButton.getWidth() - 20, autoButton.getY() + (ouyaOButton.getHeight() / 2));
}
ouyaOButton.draw(core.batch);
}core.batch.end();
}
@Override
public void dispose(){
super.dispose();
ouyaOButtonTexture.dispose();
}
/*;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; CONTROLLER LISTENER METHODS ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;*/
@Override
public boolean buttonDown(Controller controller, int buttonCode){
if(stateActive){
if(buttonCode == Ouya.BUTTON_O){
Gdx.app.log(TAG, CLASS_NAME + ".buttonDown(): O button pressed.");
if(oButtonSelection == 0){
if(!clientConnected){
core.toast("Can't start the game. No client is connected.", true);
}else if(!core.cvProc.isCameraCalibrated()){
core.toast("Can't start the game. Camera is not calibrated.", true);
}else{
oButtonPressed = true;
startButton.setChecked(true);
}
}else if(oButtonSelection == 1){
if(!clientConnected){
core.toast("Can't calibrate the camera. No client is connected.", true);
}else{
oButtonPressed = true;
calibrationButton.setChecked(true);
}
}else if(oButtonSelection == 2){
if(!clientConnected){
core.toast("Can't launch automatic action. No client is connected.", true);
}else{
oButtonPressed = true;
autoButton.setChecked(true);
}
}
}else if(buttonCode == Ouya.BUTTON_DPAD_UP){
Gdx.app.log(TAG, CLASS_NAME + ".buttonDown(): Dpad up button pressed.");
oButtonSelection = (oButtonSelection + 1) % NUM_MENU_BUTTONS;
}else if(buttonCode == Ouya.BUTTON_DPAD_DOWN){
Gdx.app.log(TAG, CLASS_NAME + ".buttonDown(): Dpad down button pressed.");
oButtonSelection = oButtonSelection - 1 < 0 ? NUM_MENU_BUTTONS - 1 : oButtonSelection - 1;
}
return true;
}else{
return false;
}
}
@Override
public boolean buttonUp(Controller controller, int buttonCode){
if(stateActive){
if(buttonCode == Ouya.BUTTON_O){
Gdx.app.log(TAG, CLASS_NAME + ".buttonDown(): O button released.");
if(oButtonPressed){
oButtonPressed = false;
if(oButtonSelection == 0){
startButton.setChecked(false);
core.nextState = game_states_t.IN_GAME;
}else if(oButtonSelection == 1){
calibrationButton.setChecked(false);
core.nextState = game_states_t.CALIBRATION;
}else if(oButtonSelection == 2){
autoButton.setChecked(false);
core.nextState = game_states_t.AUTOMATIC_ACTION;
}
}
}
return true;
}else{
return false;
}
}
@Override
public boolean axisMoved(Controller controller, int axisCode, float value){
if(Math.abs(value) > 0.99f){
if(axisCode == Ouya.AXIS_LEFT_Y && value < 0.0f){
Gdx.app.log(TAG, CLASS_NAME + ".buttonDown(): Dpad up button pressed.");
oButtonSelection = (oButtonSelection + 1) % NUM_MENU_BUTTONS;
}else if(axisCode == Ouya.AXIS_LEFT_Y && value >= 0.0f){
Gdx.app.log(TAG, CLASS_NAME + ".buttonDown(): Dpad down button pressed.");
oButtonSelection = oButtonSelection - 1 < 0 ? NUM_MENU_BUTTONS - 1 : oButtonSelection - 1;
}
return true;
}
return false;
}
}

View File

@@ -0,0 +1,330 @@
/*
* Copyright (C) 2014 Miguel Angel Astor Romero
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ve.ucv.ciens.ccg.nxtar.states;
import ve.ucv.ciens.ccg.nxtar.NxtARCore;
import ve.ucv.ciens.ccg.nxtar.NxtARCore.game_states_t;
import ve.ucv.ciens.ccg.nxtar.scenarios.ScenarioGlobals;
import ve.ucv.ciens.ccg.nxtar.scenarios.SummaryOverlayBase;
import ve.ucv.ciens.ccg.nxtar.systems.PlayerSystemBase;
import ve.ucv.ciens.ccg.nxtar.utils.ProjectConstants;
import ve.ucv.ciens.ccg.nxtar.utils.Utils;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.controllers.Controller;
import com.badlogic.gdx.controllers.mappings.Ouya;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.Texture.TextureFilter;
import com.badlogic.gdx.graphics.Texture.TextureWrap;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.NinePatch;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator;
import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator.FreeTypeFontParameter;
import com.badlogic.gdx.graphics.glutils.ShaderProgram;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.scenes.scene2d.ui.TextButton;
import com.badlogic.gdx.scenes.scene2d.ui.TextButton.TextButtonStyle;
import com.badlogic.gdx.scenes.scene2d.utils.NinePatchDrawable;
public class ScenarioEndSummaryState extends BaseState {
private static final String TAG = "SCENARIO_SUMMARY";
private static final String CLASS_NAME = ScenarioEndSummaryState.class.getSimpleName();
private static final String SHADER_PATH = "shaders/movingBckg/movingBckg";
// Helper fields.
private float u_scaling[];
private float u_displacement;
// Buttons and other gui components.
private TextButton continueButton;
private Rectangle continueButtonBBox;
private Sprite background;
private Texture backgroundTexture;
private ShaderProgram backgroundShader;
private Texture ouyaOButtonTexture;
private Sprite ouyaOButton;
private boolean oButtonPressed;
// Graphic data for the start button.
private Texture buttonEnabledTexture;
private Texture buttonDisabledTexture;
private Texture buttonPressedTexture;
private BitmapFont font;
// Summary overlay related fields.
PlayerSystemBase playerSystem;
SummaryOverlayBase summaryOverlay;
// Button touch helper fields.
private boolean continueButtonTouched;
private int continueButtonTouchPointer;
public ScenarioEndSummaryState(NxtARCore core) throws IllegalArgumentException{
TextButtonStyle textButtonStyle;
FreeTypeFontGenerator fontGenerator;
FreeTypeFontParameter fontParameters;
NinePatch buttonEnabled9p;
NinePatch buttonDisabled9p;
NinePatch buttonPressed9p;
if(core == null)
throw new IllegalArgumentException(CLASS_NAME + ": Core is null.");
this.core = core;
this.pixelPerfectCamera = new OrthographicCamera(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
oButtonPressed = false;
playerSystem = ScenarioGlobals.getPlayerSystem();
summaryOverlay = ScenarioGlobals.getScenarioSummaryOverlay();
// Create the start button background.
buttonEnabledTexture = new Texture(Gdx.files.internal("data/gfx/gui/Anonymous_Pill_Button_Yellow.png"));
buttonEnabled9p = new NinePatch(new TextureRegion(buttonEnabledTexture, 0, 0, buttonEnabledTexture.getWidth(), buttonEnabledTexture.getHeight()), 49, 49, 45, 45);
buttonDisabledTexture = new Texture(Gdx.files.internal("data/gfx/gui/Anonymous_Pill_Button_Cyan.png"));
buttonDisabled9p = new NinePatch(new TextureRegion(buttonDisabledTexture, 0, 0, buttonDisabledTexture.getWidth(), buttonDisabledTexture.getHeight()), 49, 49, 45, 45);
buttonPressedTexture = new Texture(Gdx.files.internal("data/gfx/gui/Anonymous_Pill_Button_Blue.png"));
buttonPressed9p = new NinePatch(new TextureRegion(buttonPressedTexture, 0, 0, buttonPressedTexture.getWidth(), buttonPressedTexture.getHeight()), 49, 49, 45, 45);
// Create the start button font.
fontParameters = new FreeTypeFontParameter();
fontParameters.characters = ProjectConstants.FONT_CHARS;
fontParameters.size = ProjectConstants.MENU_BUTTON_FONT_SIZE;
fontParameters.flip = false;
fontGenerator = new FreeTypeFontGenerator(Gdx.files.internal("data/fonts/d-puntillas-B-to-tiptoe.ttf"));
font = fontGenerator.generateFont(fontParameters);
fontGenerator.dispose();
// Create the contine button.
textButtonStyle = new TextButtonStyle();
textButtonStyle.font = font;
textButtonStyle.up = new NinePatchDrawable(buttonEnabled9p);
textButtonStyle.checked = new NinePatchDrawable(buttonPressed9p);
textButtonStyle.disabled = new NinePatchDrawable(buttonDisabled9p);
textButtonStyle.fontColor = new Color(Color.BLACK);
textButtonStyle.downFontColor = new Color(Color.WHITE);
textButtonStyle.disabledFontColor = new Color(Color.BLACK);
continueButton = new TextButton("Continue", textButtonStyle);
continueButton.setText("Continue");
continueButton.setPosition(-(continueButton.getWidth() / 2), -(Utils.getScreenHeightWithOverscan() / 2) + 10);
continueButtonBBox = new Rectangle(0, 0, continueButton.getWidth(), continueButton.getHeight());
continueButtonBBox.setPosition(continueButton.getX(), continueButton.getY());
// Set OUYA's O button.
if(Ouya.runningOnOuya){
ouyaOButtonTexture = new Texture("data/gfx/gui/OUYA_O.png");
ouyaOButton = new Sprite(ouyaOButtonTexture);
ouyaOButton.setSize(ouyaOButton.getWidth() * 0.6f, ouyaOButton.getHeight() * 0.6f);
ouyaOButton.setPosition(continueButton.getX() - ouyaOButton.getWidth() - 20, continueButton.getY() + (ouyaOButton.getHeight() / 2));
oButtonPressed = false;
}else{
ouyaOButtonTexture = null;
}
// Set up the background.
backgroundTexture = new Texture(Gdx.files.internal("data/gfx/textures/tile_aqua.png"));
backgroundTexture.setWrap(TextureWrap.Repeat, TextureWrap.Repeat);
backgroundTexture.setFilter(TextureFilter.Linear, TextureFilter.Linear);
background = new Sprite(backgroundTexture);
background.setSize(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
background.setPosition(-(Gdx.graphics.getWidth() / 2), -(Gdx.graphics.getHeight() / 2));
backgroundShader = new ShaderProgram(Gdx.files.internal(SHADER_PATH + "_vert.glsl"), Gdx.files.internal(SHADER_PATH + "_frag.glsl"));
if(!backgroundShader.isCompiled()){
Gdx.app.error(TAG, CLASS_NAME + ".MainMenuStateBase() :: Failed to compile the background shader.");
Gdx.app.error(TAG, CLASS_NAME + backgroundShader.getLog());
backgroundShader = null;
}
u_scaling = new float[2];
u_scaling[0] = Gdx.graphics.getWidth() > Gdx.graphics.getHeight() ? 16.0f : 9.0f;
u_scaling[1] = Gdx.graphics.getHeight() > Gdx.graphics.getWidth() ? 16.0f : 9.0f;
u_displacement = 1.0f;
win2world = new Vector3(0.0f, 0.0f, 0.0f);
touchPointWorldCoords = new Vector2();
continueButtonTouched = false;
continueButtonTouchPointer = -1;
stateActive = false;
}
@Override
public void render(float delta){
Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
core.batch.setProjectionMatrix(pixelPerfectCamera.combined);
core.batch.begin();{
// Render background.
core.batch.disableBlending();
drawBackground(core.batch);
core.batch.enableBlending();
summaryOverlay.render(core.batch, playerSystem.getPlayerSummary());
// Render buttons.
continueButton.draw(core.batch, 1.0f);
if(Ouya.runningOnOuya)
ouyaOButton.draw(core.batch);
}core.batch.end();
}
@Override
public void dispose(){
buttonEnabledTexture.dispose();
buttonDisabledTexture.dispose();
buttonPressedTexture.dispose();
if(ouyaOButtonTexture != null)
ouyaOButtonTexture.dispose();
backgroundTexture.dispose();
if(backgroundShader != null) backgroundShader.dispose();
font.dispose();
}
private void drawBackground(SpriteBatch batch){
if(backgroundShader != null){
batch.setShader(backgroundShader);
backgroundShader.setUniform2fv("u_scaling", u_scaling, 0, 2);
backgroundShader.setUniformf("u_displacement", u_displacement);
}
background.draw(batch);
if(backgroundShader != null) batch.setShader(null);
u_displacement = u_displacement < 0.0f ? 1.0f : u_displacement - 0.0005f;
}
@Override
public void onStateSet(){
stateActive = true;
Gdx.input.setInputProcessor(this);
Gdx.input.setCatchBackKey(true);
Gdx.input.setCatchMenuKey(true);
}
@Override
public void onStateUnset(){
stateActive = false;
Gdx.input.setInputProcessor(null);
Gdx.input.setCatchBackKey(false);
Gdx.input.setCatchMenuKey(false);
}
/*;;;;;;;;;;;;;;;;;;;;;;;;;;
; INPUT LISTENER METHODS ;
;;;;;;;;;;;;;;;;;;;;;;;;;;*/
@Override
public boolean touchDown(int screenX, int screenY, int pointer, int button){
unprojectTouch(screenX, screenY);
Gdx.app.log(TAG, CLASS_NAME + String.format(".touchDown(%d, %d, %d, %d)", screenX, screenY, pointer, button));
Gdx.app.log(TAG, CLASS_NAME + String.format(".touchDown() :: Unprojected touch point: (%f, %f)", touchPointWorldCoords.x, touchPointWorldCoords.y));
if(!continueButton.isDisabled() && continueButtonBBox.contains(touchPointWorldCoords)){
continueButton.setChecked(true);
continueButtonTouched = true;
continueButtonTouchPointer = pointer;
Gdx.app.log(TAG, CLASS_NAME + ".touchDown() :: Start button pressed.");
}
return true;
}
@Override
public boolean touchUp(int screenX, int screenY, int pointer, int button){
unprojectTouch(screenX, screenY);
Gdx.app.log(TAG, CLASS_NAME + String.format(".touchUp(%d, %d, %d, %d)", screenX, screenY, pointer, button));
Gdx.app.log(TAG, CLASS_NAME + String.format(".touchUp() :: Unprojected touch point: (%f, %f)", touchPointWorldCoords.x, touchPointWorldCoords.y));
if(!continueButton.isDisabled() && continueButtonBBox.contains(touchPointWorldCoords) && continueButtonTouched){
continueButton.setChecked(false);
continueButtonTouched = false;
continueButtonTouchPointer = -1;
core.nextState = game_states_t.MAIN_MENU;
Gdx.app.log(TAG, CLASS_NAME + ".touchDown() :: Start button released.");
}
return true;
}
@Override
public boolean touchDragged(int screenX, int screenY, int pointer){
unprojectTouch(screenX, screenY);
if(!continueButton.isDisabled() && continueButtonTouched && pointer == continueButtonTouchPointer && !continueButtonBBox.contains(touchPointWorldCoords)){
continueButtonTouchPointer = -1;
continueButtonTouched = false;
continueButton.setChecked(false);
Gdx.app.log(TAG, CLASS_NAME + ".touchDragged() :: Start button released.");
}
return true;
}
@Override
public boolean keyDown(int keycode){
if(keycode == Input.Keys.BACK){
core.nextState = game_states_t.MAIN_MENU;
return true;
}
return false;
}
/*;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; CONTROLLER LISTENER METHODS ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;*/
@Override
public boolean buttonDown(Controller controller, int buttonCode){
if(stateActive){
if(buttonCode == Ouya.BUTTON_O && !continueButton.isDisabled()){
Gdx.app.log(TAG, CLASS_NAME + ".buttonDown(): O button pressed.");
oButtonPressed = true;
continueButton.setChecked(true);
}
return true;
}else{
return false;
}
}
@Override
public boolean buttonUp(Controller controller, int buttonCode){
if(stateActive){
if(buttonCode == Ouya.BUTTON_O){
Gdx.app.log(TAG, CLASS_NAME + ".buttonDown(): O button released.");
if(oButtonPressed){
oButtonPressed = false;
continueButton.setChecked(false);
core.nextState = game_states_t.MAIN_MENU;
}
}
return true;
}else{
return false;
}
}
}

View File

@@ -0,0 +1,83 @@
/*
* Copyright (C) 2014 Miguel Angel Astor Romero
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ve.ucv.ciens.ccg.nxtar.states;
import ve.ucv.ciens.ccg.nxtar.NxtARCore;
import ve.ucv.ciens.ccg.nxtar.utils.Utils;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL20;
public class TabletMainMenuState extends MainMenuStateBase{
private static final String CLASS_NAME = TabletMainMenuState.class.getSimpleName();
private float ledYPos;
public TabletMainMenuState(final NxtARCore core) throws IllegalArgumentException{
super();
if(core == null)
throw new IllegalArgumentException(CLASS_NAME + ": Core is null.");
this.core = core;
// Set buttons.
startButton.setPosition(-(startButton.getWidth() / 2), -(startButton.getHeight() / 2));
startButtonBBox.setPosition(startButton.getX(), startButton.getY());
calibrationButton.setPosition(-(calibrationButton.getWidth() / 2), (startButton.getY() + startButton.getHeight()) + 10);
calibrationButtonBBox.setPosition(calibrationButton.getX(), calibrationButton.getY());
autoButton.setPosition(-(autoButton.getWidth() / 2), (startButton.getY() - startButton.getHeight()) - 10);
autoButtonBBox.setPosition(autoButton.getX(), autoButton.getY());
// Set leds.
ledYPos = -(Utils.getScreenHeightWithOverscan() / 2) + 10;
cameraCalibratedLedOn.setSize(cameraCalibratedLedOn.getWidth() * 0.5f, cameraCalibratedLedOn.getHeight() * 0.5f);
cameraCalibratedLedOn.setPosition(-cameraCalibratedLedOn.getWidth() - 5, ledYPos);
cameraCalibratedLedOff.setSize(cameraCalibratedLedOff.getWidth() * 0.5f, cameraCalibratedLedOff.getHeight() * 0.5f);
cameraCalibratedLedOff.setPosition(-cameraCalibratedLedOff.getWidth() - 5, ledYPos);
assetsLoadedLedOn.setSize(assetsLoadedLedOn.getWidth() * 0.5f, assetsLoadedLedOn.getHeight() * 0.5f);
assetsLoadedLedOn.setPosition(5, ledYPos);
assetsLoadedLedOff.setSize(assetsLoadedLedOff.getWidth() * 0.5f, assetsLoadedLedOff.getHeight() * 0.5f);
assetsLoadedLedOff.setPosition(5, ledYPos);
}
@Override
public void render(float delta){
Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
core.batch.setProjectionMatrix(pixelPerfectCamera.combined);
core.batch.begin();{
// Render background.
core.batch.disableBlending();
drawBackground(core.batch);
core.batch.enableBlending();
// Render leds.
if(cameraCalibrated) cameraCalibratedLedOn.draw(core.batch);
else cameraCalibratedLedOff.draw(core.batch);
if(assetsLoaded) assetsLoadedLedOn.draw(core.batch);
else assetsLoadedLedOff.draw(core.batch);
// Render buttons.
startButton.draw(core.batch, 1.0f);
calibrationButton.draw(core.batch, 1.0f);
autoButton.draw(core.batch, 1.0f);
}core.batch.end();
}
}

View File

@@ -0,0 +1,69 @@
/*
* Copyright (C) 2014 Miguel Angel Astor Romero
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ve.ucv.ciens.ccg.nxtar.systems;
import ve.ucv.ciens.ccg.nxtar.components.AnimationComponent;
import ve.ucv.ciens.ccg.nxtar.components.VisibilityComponent;
import com.artemis.Aspect;
import com.artemis.ComponentMapper;
import com.artemis.Entity;
import com.artemis.annotations.Mapper;
import com.artemis.systems.EntityProcessingSystem;
import com.badlogic.gdx.Gdx;
public class AnimationSystem extends EntityProcessingSystem {
public static final int NO_ANIMATION = -1;
@Mapper ComponentMapper<AnimationComponent> animationMapper;
@Mapper ComponentMapper<VisibilityComponent> visibilityMapper;
@SuppressWarnings("unchecked")
public AnimationSystem(){
super(Aspect.getAspectForAll(AnimationComponent.class, VisibilityComponent.class));
}
@Override
protected void process(Entity e) {
AnimationComponent animation = animationMapper.get(e);
VisibilityComponent visibility = visibilityMapper.get(e);
int loopCount = animation.loop ? -1 : 1;
if(animation.current != animation.next && animation.next >= 0 && animation.next < animation.animationsIds.size()){
animation.current = animation.next;
if(animation.controller.current == null){
animation.controller.setAnimation(animation.animationsIds.get(animation.next), loopCount, 1, null);
}else{
animation.controller.animate(animation.animationsIds.get(animation.next), loopCount, 1, null, 0.1f);
}
if(animation.collisionController != null){
if(animation.collisionController.current == null){
animation.collisionController.setAnimation(animation.animationsIds.get(animation.next), loopCount, 1, null);
}else{
animation.collisionController.animate(animation.animationsIds.get(animation.next), loopCount, 1, null, 0.1f);
}
}
}
if(visibility.visible){
animation.controller.update(Gdx.graphics.getDeltaTime());
if(animation.collisionController != null)
animation.collisionController.update(Gdx.graphics.getDeltaTime());
}
}
}

View File

@@ -0,0 +1,121 @@
/*
* Copyright (C) 2014 Miguel Angel Astor Romero
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ve.ucv.ciens.ccg.nxtar.systems;
import ve.ucv.ciens.ccg.nxtar.components.CollisionDetectionComponent;
import ve.ucv.ciens.ccg.nxtar.components.CollisionModelComponent;
import ve.ucv.ciens.ccg.nxtar.components.MarkerCodeComponent;
import ve.ucv.ciens.ccg.nxtar.components.VisibilityComponent;
import com.artemis.Aspect;
import com.artemis.ComponentMapper;
import com.artemis.Entity;
import com.artemis.annotations.Mapper;
import com.artemis.managers.GroupManager;
import com.artemis.systems.EntityProcessingSystem;
import com.artemis.utils.ImmutableBag;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.math.collision.BoundingBox;
public class CollisionDetectionSystem extends EntityProcessingSystem {
public static final String COLLIDABLE_OBJECTS_GROUP = "COLLIDABLE";
@Mapper ComponentMapper<CollisionModelComponent> collisionModelMapper;
@Mapper ComponentMapper<CollisionDetectionComponent> collisionDetectionMapper;
@Mapper ComponentMapper<VisibilityComponent> visibilityMapper;
private GroupManager groupManager;
private BoundingBox colBB;
private BoundingBox targetBB;
private boolean collisionsEnabled;
@SuppressWarnings("unchecked")
public CollisionDetectionSystem(){
super(Aspect.getAspectForAll(CollisionModelComponent.class, CollisionDetectionComponent.class).exclude(MarkerCodeComponent.class));
colBB = new BoundingBox();
targetBB = new BoundingBox();
collisionsEnabled = true;
}
@Override
protected void process(Entity e) {
VisibilityComponent visibility;
CollisionModelComponent collision;
CollisionModelComponent target;
CollisionDetectionComponent onCollision;
CollisionDetectionComponent onCollisionTarget;
ImmutableBag<Entity> collidables;
if(!collisionsEnabled)
return;
// Get this entity's known necessary components.
collision = collisionModelMapper.get(e);
onCollision = collisionDetectionMapper.get(e);
// Get all other entities this entity can collide with.
groupManager = this.world.getManager(GroupManager.class);
collidables = groupManager.getEntities(COLLIDABLE_OBJECTS_GROUP);
for(int i = 0; i < collidables.size(); ++i){
// Try to get the necessary components for the collidable entity.
target = collisionModelMapper.getSafe(collidables.get(i));
visibility = visibilityMapper.getSafe(collidables.get(i));
onCollisionTarget = collisionDetectionMapper.getSafe(collidables.get(i));
// If any of the needed components does not exist then proceed to the next entity.
if(target == null || visibility == null || onCollisionTarget == null) continue;
// Id the target is visible then examine the collision. Else there is no collision possible.
if(visibility.visible){
// Get the bounding box for both entities.
collision.instance.calculateBoundingBox(colBB);
target.instance.calculateBoundingBox(targetBB);
// Apply the model matrix to the bounding boxes.
colBB.mul(collision.instance.transform);
targetBB.mul(target.instance.transform);
// If the bounding boxes intersect then there is a collision.
if(colBB.intersects(targetBB) || targetBB.intersects(colBB)){
Gdx.app.log("TAG", "Collision hit.");
onCollision.colliding = true;
onCollisionTarget.colliding = true;
break;
}else{
Gdx.app.log("TAG", "Collision miss.");
onCollision.colliding = false;
onCollisionTarget.colliding = false;
}
}else{
onCollision.colliding = false;
onCollisionTarget.colliding = false;
}
}
}
public boolean isCollisionDetectionEnabled(){
return collisionsEnabled;
}
public void enableCollisions(){
this.collisionsEnabled = true;
}
public void disableCollisions(){
this.collisionsEnabled = false;
}
}

View File

@@ -0,0 +1,62 @@
package ve.ucv.ciens.ccg.nxtar.systems;
import ve.ucv.ciens.ccg.nxtar.components.FadeEffectComponent;
import com.artemis.Aspect;
import com.artemis.ComponentMapper;
import com.artemis.Entity;
import com.artemis.annotations.Mapper;
import com.artemis.systems.EntityProcessingSystem;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Pixmap;
import com.badlogic.gdx.graphics.Pixmap.Format;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.utils.Disposable;
public class FadeEffectRenderingSystem extends EntityProcessingSystem implements Disposable{
@Mapper ComponentMapper<FadeEffectComponent> fadeMapper;
private SpriteBatch batch;
private Texture fadeTexture;
private OrthographicCamera camera;
@SuppressWarnings("unchecked")
public FadeEffectRenderingSystem(){
super(Aspect.getAspectForAll(FadeEffectComponent.class));
this.batch = new SpriteBatch();
this.batch.enableBlending();
this.camera = new OrthographicCamera(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
Pixmap pixmap = new Pixmap(Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), Format.RGBA4444);
pixmap.setColor(1, 1, 1, 1);
pixmap.fill();
fadeTexture = new Texture(pixmap);
pixmap.dispose();
}
@Override
public void dispose(){
this.fadeTexture.dispose();
this.batch.dispose();
}
@Override
protected void process(Entity e) {
float r, g, b;
FadeEffectComponent fade = fadeMapper.get(e);
r = fade.color.r;
g = fade.color.g;
b = fade.color.b;
this.batch.setProjectionMatrix(this.camera.combined);
this.batch.begin();{
this.batch.setColor(r, g, b, fade.getFloatValue());
this.batch.draw(fadeTexture, -(Gdx.graphics.getWidth() / 2), -(Gdx.graphics.getHeight() / 2));
this.batch.setColor(1, 1, 1, 1);
}this.batch.end();
}
}

View File

@@ -0,0 +1,30 @@
/*
* Copyright (C) 2014 Miguel Angel Astor Romero
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ve.ucv.ciens.ccg.nxtar.systems;
import com.artemis.Aspect;
import com.artemis.Entity;
import com.artemis.systems.EntityProcessingSystem;
public abstract class GameLogicSystemBase extends EntityProcessingSystem {
public GameLogicSystemBase(Aspect aspect){
super(aspect);
}
@Override
protected abstract void process(Entity e);
}

View File

@@ -0,0 +1,103 @@
/*
* Copyright (C) 2014 Miguel Angel Astor Romero
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ve.ucv.ciens.ccg.nxtar.systems;
import ve.ucv.ciens.ccg.nxtar.components.CollisionModelComponent;
import ve.ucv.ciens.ccg.nxtar.components.GeometryComponent;
import ve.ucv.ciens.ccg.nxtar.components.RenderModelComponent;
import com.artemis.Aspect;
import com.artemis.ComponentMapper;
import com.artemis.Entity;
import com.artemis.annotations.Mapper;
import com.artemis.systems.EntityProcessingSystem;
import com.badlogic.gdx.graphics.g3d.ModelInstance;
import com.badlogic.gdx.math.Matrix4;
public class GeometrySystem extends EntityProcessingSystem {
@Mapper ComponentMapper<GeometryComponent> geometryMapper;
@Mapper ComponentMapper<RenderModelComponent> renderModelMapper;
@Mapper ComponentMapper<CollisionModelComponent> colModelMapper;
/**
* <p>A matrix representing 3D translations.</p>
*/
private Matrix4 translationMatrix;
/**
* <p>A matrix representing 3D rotations.</p>
*/
private Matrix4 rotationMatrix;
/**
* <p>A matrix representing 3D scalings.</p>
*/
private Matrix4 scalingMatrix;
@SuppressWarnings("unchecked")
public GeometrySystem(){
super(Aspect.getAspectForAll(GeometryComponent.class).one(RenderModelComponent.class, CollisionModelComponent.class));
translationMatrix = new Matrix4().setToTranslation(0.0f, 0.0f, 0.0f);
rotationMatrix = new Matrix4().idt();
scalingMatrix = new Matrix4().setToScaling(0.0f, 0.0f, 0.0f);
}
@Override
protected void process(Entity e) {
GeometryComponent geometry;
RenderModelComponent renderModel;
CollisionModelComponent colModel;
geometry = geometryMapper.get(e);
renderModel = renderModelMapper.getSafe(e);
colModel = colModelMapper.getSafe(e);
if(renderModel != null)
applyWorldTransform(renderModel.instance, geometry);
if(colModel != null)
applyWorldTransform(colModel.instance, geometry);
}
private void applyWorldTransform(ModelInstance model, GeometryComponent geometry){
translationMatrix.setToTranslation(geometry.position);
rotationMatrix.val[Matrix4.M00] = geometry.rotation.val[0];
rotationMatrix.val[Matrix4.M10] = geometry.rotation.val[1];
rotationMatrix.val[Matrix4.M20] = geometry.rotation.val[2];
rotationMatrix.val[Matrix4.M30] = 0;
rotationMatrix.val[Matrix4.M01] = geometry.rotation.val[3];
rotationMatrix.val[Matrix4.M11] = geometry.rotation.val[4];
rotationMatrix.val[Matrix4.M21] = geometry.rotation.val[5];
rotationMatrix.val[Matrix4.M31] = 0;
rotationMatrix.val[Matrix4.M02] = geometry.rotation.val[6];
rotationMatrix.val[Matrix4.M12] = geometry.rotation.val[7];
rotationMatrix.val[Matrix4.M22] = geometry.rotation.val[8];
rotationMatrix.val[Matrix4.M32] = 0;
rotationMatrix.val[Matrix4.M03] = 0;
rotationMatrix.val[Matrix4.M13] = 0;
rotationMatrix.val[Matrix4.M23] = 0;
rotationMatrix.val[Matrix4.M33] = 1;
scalingMatrix.setToScaling(geometry.scaling);
model.transform.idt().mul(translationMatrix).mul(rotationMatrix).mul(scalingMatrix);
model.calculateTransforms();
}
}

View File

@@ -0,0 +1,74 @@
/*
* Copyright (C) 2014 Miguel Angel Astor Romero
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ve.ucv.ciens.ccg.nxtar.systems;
import ve.ucv.ciens.ccg.nxtar.components.GeometryComponent;
import ve.ucv.ciens.ccg.nxtar.components.MarkerCodeComponent;
import ve.ucv.ciens.ccg.nxtar.components.VisibilityComponent;
import ve.ucv.ciens.ccg.nxtar.interfaces.ImageProcessor.MarkerData;
import ve.ucv.ciens.ccg.nxtar.utils.ProjectConstants;
import com.artemis.Aspect;
import com.artemis.ComponentMapper;
import com.artemis.Entity;
import com.artemis.annotations.Mapper;
import com.artemis.systems.EntityProcessingSystem;
public class MarkerPositioningSystem extends EntityProcessingSystem {
@Mapper ComponentMapper<MarkerCodeComponent> markerMapper;
@Mapper ComponentMapper<GeometryComponent> geometryMapper;
@Mapper ComponentMapper<VisibilityComponent> visibilityMapper;
private MarkerData markers;
@SuppressWarnings("unchecked")
public MarkerPositioningSystem(){
super(Aspect.getAspectForAll(MarkerCodeComponent.class, GeometryComponent.class, VisibilityComponent.class));
markers = null;
}
public void setMarkerData(MarkerData markers){
this.markers = markers;
}
@Override
protected void process(Entity e) {
MarkerCodeComponent marker;
GeometryComponent geometry;
VisibilityComponent visibility;
if(markers == null)
return;
marker = markerMapper.get(e);
geometry = geometryMapper.get(e);
visibility = visibilityMapper.get(e);
for(int i = 0; i < ProjectConstants.MAXIMUM_NUMBER_OF_MARKERS; i++){
if(markers.markerCodes[i] != 1){
if(markers.markerCodes[i] == marker.code){
geometry.position.set(markers.translationVectors[i]);
geometry.rotation.set(markers.rotationMatrices[i]);
visibility.visible = true;
break;
}else{
visibility.visible = false;
}
}
}
}
}

View File

@@ -0,0 +1,82 @@
/*
* Copyright (C) 2014 Miguel Angel Astor Romero
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ve.ucv.ciens.ccg.nxtar.systems;
import ve.ucv.ciens.ccg.nxtar.components.EnvironmentComponent;
import ve.ucv.ciens.ccg.nxtar.components.RenderModelComponent;
import ve.ucv.ciens.ccg.nxtar.components.ShaderComponent;
import ve.ucv.ciens.ccg.nxtar.components.VisibilityComponent;
import com.artemis.Aspect;
import com.artemis.ComponentMapper;
import com.artemis.Entity;
import com.artemis.annotations.Mapper;
import com.artemis.systems.EntityProcessingSystem;
import com.badlogic.gdx.graphics.PerspectiveCamera;
import com.badlogic.gdx.graphics.g3d.ModelBatch;
public class MarkerRenderingSystem extends EntityProcessingSystem {
// @Mapper ComponentMapper<MarkerCodeComponent> markerMapper;
@Mapper ComponentMapper<RenderModelComponent> modelMapper;
@Mapper ComponentMapper<EnvironmentComponent> environmentMapper;
@Mapper ComponentMapper<ShaderComponent> shaderMapper;
@Mapper ComponentMapper<VisibilityComponent> visibiltyMapper;
private PerspectiveCamera camera;
private ModelBatch batch;
@SuppressWarnings("unchecked")
public MarkerRenderingSystem(ModelBatch batch){
super(Aspect.getAspectForAll(ShaderComponent.class, EnvironmentComponent.class, RenderModelComponent.class, VisibilityComponent.class));
camera = null;
this.batch = batch;
}
public void begin(PerspectiveCamera camera) throws RuntimeException{
if(this.camera != null)
throw new RuntimeException("Begin called twice without calling end.");
this.camera = camera;
batch.begin(camera);
}
public void end(){
batch.end();
camera = null;
}
@Override
protected void process(Entity e) {
EnvironmentComponent environment;
RenderModelComponent model;
ShaderComponent shader;
VisibilityComponent visibility;
if(camera == null)
return;
model = modelMapper.get(e);
environment = environmentMapper.get(e);
shader = shaderMapper.get(e);
visibility = visibiltyMapper.get(e);
if(visibility.visible){
// Render the marker;
batch.render(model.instance, environment.environment, shader.shader);
}
}
}

View File

@@ -0,0 +1,51 @@
/*
* Copyright (C) 2013 Miguel Angel Astor Romero
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ve.ucv.ciens.ccg.nxtar.systems;
import ve.ucv.ciens.ccg.nxtar.NxtARCore;
import ve.ucv.ciens.ccg.nxtar.components.PlayerComponentBase;
import ve.ucv.ciens.ccg.nxtar.scenarios.ScenarioGlobals;
import ve.ucv.ciens.ccg.nxtar.scenarios.SummaryBase;
import com.artemis.Aspect;
import com.artemis.systems.EntityProcessingSystem;
import com.badlogic.gdx.utils.Disposable;
public abstract class PlayerSystemBase extends EntityProcessingSystem implements Disposable{
protected NxtARCore core;
@SuppressWarnings("unchecked")
public PlayerSystemBase(Class<? extends PlayerComponentBase> component){
super(Aspect.getAspectForAll(component));
}
public abstract SummaryBase getPlayerSummary();
public final void setCore(NxtARCore core) throws IllegalArgumentException{
if(core == null)
throw new IllegalArgumentException("Core is null.");
this.core = core;
}
protected final void finishGame(boolean victory) throws IllegalStateException{
if(core == null)
throw new IllegalStateException("Core is null.");
ScenarioGlobals.getEntityCreator().resetAllEntities();
core.nextState = NxtARCore.game_states_t.SCENARIO_END_SUMMARY;
}
}

View File

@@ -0,0 +1,179 @@
/*
* Copyright (C) 2014 Miguel Angel Astor Romero
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ve.ucv.ciens.ccg.nxtar.systems;
import ve.ucv.ciens.ccg.nxtar.components.AutomaticMovementComponent;
import ve.ucv.ciens.ccg.nxtar.components.CollisionDetectionComponent;
import ve.ucv.ciens.ccg.nxtar.components.GeometryComponent;
import ve.ucv.ciens.ccg.nxtar.components.MarkerCodeComponent;
import ve.ucv.ciens.ccg.nxtar.input.GamepadUserInput;
import ve.ucv.ciens.ccg.nxtar.input.KeyboardUserInput;
import ve.ucv.ciens.ccg.nxtar.input.TouchUserInput;
import ve.ucv.ciens.ccg.nxtar.input.UserInput;
import ve.ucv.ciens.ccg.nxtar.utils.Utils;
import com.artemis.Aspect;
import com.artemis.ComponentMapper;
import com.artemis.Entity;
import com.artemis.annotations.Mapper;
import com.artemis.systems.EntityProcessingSystem;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.controllers.mappings.Ouya;
import com.badlogic.gdx.math.Vector3;
public class RobotArmPositioningSystem extends EntityProcessingSystem {
private static final String TAG = "ROBOT_ARM_POSITIONING_SYSTEM";
private static final String CLASS_NAME = RobotArmPositioningSystem.class.getSimpleName();
private static final float INTERPOLATION_STEP = 0.05f;
private static final float STEP_SIZE = 0.05f;
public static final float MAX_Z = -4.5f;
public static final float MIN_Z = -1.0f;
@Mapper ComponentMapper<GeometryComponent> geometryMapper;
@Mapper ComponentMapper<AutomaticMovementComponent> autoMapper;
@Mapper ComponentMapper<CollisionDetectionComponent> collisionMapper;
private UserInput input;
@SuppressWarnings("unchecked")
public RobotArmPositioningSystem(){
super(Aspect.getAspectForAll(GeometryComponent.class, AutomaticMovementComponent.class, CollisionDetectionComponent.class).exclude(MarkerCodeComponent.class));
}
public void setUserInput(UserInput input){
this.input = input;
}
@Override
protected void process(Entity e) throws ClassCastException{
Vector3 endPoint;
GamepadUserInput tempGP;
KeyboardUserInput tempKey;
GeometryComponent geometry = geometryMapper.get(e);
AutomaticMovementComponent auto = autoMapper.get(e);
CollisionDetectionComponent collision = collisionMapper.get(e);
if(input == null){
if(auto.moving) autoMove(geometry, auto, collision);
else return;
}else{
if(input instanceof TouchUserInput){
if(!auto.moving){
endPoint = ((TouchUserInput) input).userTouchEndPoint;
endPoint.set(geometry.position.x, geometry.position.y, MAX_Z);
auto.startPoint.set(geometry.position);
auto.endPoint.set(endPoint);
auto.moving = true;
auto.forward = true;
Gdx.app.log(TAG, CLASS_NAME + ".process(): Started moving from " + Utils.vector2String(auto.startPoint) + " to " + Utils.vector2String(auto.endPoint));
}else autoMove(geometry, auto, collision);
input = null;
}else if(input instanceof GamepadUserInput){
tempGP = (GamepadUserInput) input;
if(!auto.moving){
if(!tempGP.oButton){
geometry.position.x += -tempGP.axisLeftY * STEP_SIZE;
geometry.position.y += tempGP.axisLeftX * STEP_SIZE;
if(Math.abs(tempGP.axisLeftX) < Ouya.STICK_DEADZONE && Math.abs(tempGP.axisLeftY) < Ouya.STICK_DEADZONE)
input = null;
else
input = (UserInput)tempGP;
}else{
endPoint = new Vector3(geometry.position.x, geometry.position.y, MAX_Z);
auto.startPoint.set(geometry.position);
auto.endPoint.set(endPoint);
auto.moving = true;
auto.forward = true;
input = null;
}
}else{
autoMove(geometry, auto, collision);
input = null;
}
}else if(input instanceof KeyboardUserInput){
tempKey = (KeyboardUserInput) input;
if(!auto.moving){
if(!tempKey.keySpace){
geometry.position.x += tempKey.keyUp ? STEP_SIZE : 0.0f;
geometry.position.x -= tempKey.keyDown ? STEP_SIZE : 0.0f;
geometry.position.y -= tempKey.keyLeft ? STEP_SIZE : 0.0f;
geometry.position.y += tempKey.keyRight ? STEP_SIZE : 0.0f;
if(!tempKey.keyUp && !tempKey.keyUp && !tempKey.keyUp && !tempKey.keyUp)
input = null;
else
input = (UserInput)tempKey;
}else{
endPoint = new Vector3(geometry.position.x, geometry.position.y, MAX_Z);
auto.startPoint.set(geometry.position);
auto.endPoint.set(endPoint);
auto.moving = true;
auto.forward = true;
input = null;
}
}else{
autoMove(geometry, auto, collision);
input = null;
}
}else
throw new ClassCastException("Input is not a valid UserInput instance.");
}
}
private void autoMove(GeometryComponent geometry, AutomaticMovementComponent auto, CollisionDetectionComponent collision){
float step;
if(auto.moving){
if(auto.forward)
step = INTERPOLATION_STEP;
else
step = -INTERPOLATION_STEP;
Gdx.app.log(TAG, CLASS_NAME + ".autoMove(): Step = " + Float.toString(step));
auto.distance += step;
Gdx.app.log(TAG, CLASS_NAME + ".autoMove(): Step = " + Float.toString(auto.distance));
geometry.position.x = (auto.startPoint.x * (1.0f - auto.distance)) + (auto.endPoint.x * auto.distance);
geometry.position.y = (auto.startPoint.y * (1.0f - auto.distance)) + (auto.endPoint.y * auto.distance);
geometry.position.z = (auto.startPoint.z * (1.0f - auto.distance)) + (auto.endPoint.z * auto.distance);
Gdx.app.log(TAG, CLASS_NAME + ".autoMove(): Current position: " + Utils.vector2String(geometry.position));
if(auto.distance <= 0.0f || geometry.position.z >= MIN_Z){
geometry.position.x = auto.startPoint.x;
geometry.position.y = auto.startPoint.y;
geometry.position.z = MIN_Z;
auto.forward = true;
auto.moving = false;
Gdx.app.log(TAG, CLASS_NAME + ".autoMove(): Going forward now.");
}else if(auto.distance >= 1.0f || collision.colliding){
auto.forward = false;
Gdx.app.log(TAG, CLASS_NAME + ".autoMove(): Going backwards now.");
}
}else return;
}
}

View File

@@ -0,0 +1,115 @@
/*
* Copyright (C) 2014 Miguel Angel Astor Romero
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ve.ucv.ciens.ccg.nxtar.systems;
import ve.ucv.ciens.ccg.nxtar.components.EnvironmentComponent;
import ve.ucv.ciens.ccg.nxtar.components.GeometryComponent;
import ve.ucv.ciens.ccg.nxtar.components.MarkerCodeComponent;
import ve.ucv.ciens.ccg.nxtar.components.RenderModelComponent;
import ve.ucv.ciens.ccg.nxtar.components.ShaderComponent;
import com.artemis.Aspect;
import com.artemis.ComponentMapper;
import com.artemis.Entity;
import com.artemis.annotations.Mapper;
import com.artemis.systems.EntityProcessingSystem;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.PerspectiveCamera;
import com.badlogic.gdx.graphics.VertexAttributes.Usage;
import com.badlogic.gdx.graphics.g3d.Material;
import com.badlogic.gdx.graphics.g3d.Model;
import com.badlogic.gdx.graphics.g3d.ModelBatch;
import com.badlogic.gdx.graphics.g3d.ModelInstance;
import com.badlogic.gdx.graphics.g3d.attributes.ColorAttribute;
import com.badlogic.gdx.graphics.g3d.utils.ModelBuilder;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.utils.Disposable;
/**
* <p>Entity processing system in charge of rendering 3D objects using OpenGL. The
* entities to be rendered must have a geometry, shader and mesh component associated.</p>
*/
public class RobotArmRenderingSystem extends EntityProcessingSystem implements Disposable{
@Mapper ComponentMapper<ShaderComponent> shaderMapper;
@Mapper ComponentMapper<RenderModelComponent> modelMapper;
@Mapper ComponentMapper<EnvironmentComponent> environmentMapper;
@Mapper ComponentMapper<GeometryComponent> geometryMapper;
private PerspectiveCamera camera;
private ModelBatch batch;
private Model lineModel;
private ModelInstance lineInstance;
private Vector3 temp;
@SuppressWarnings("unchecked")
public RobotArmRenderingSystem(ModelBatch batch) {
super(Aspect.getAspectForAll(ShaderComponent.class, RenderModelComponent.class, EnvironmentComponent.class).exclude(MarkerCodeComponent.class));
camera = null;
this.batch = batch;
// MeshBuilder builder = new MeshBuilder();
// builder.begin(new VertexAttributes(new VertexAttribute(Usage.Position, 4, "a_position"), new VertexAttribute(Usage.Color, 4, "a_color")), GL20.GL_LINES);{
// builder.line(new Vector3(0.0f, 0.0f, RobotArmPositioningSystem.MIN_Z), Color.YELLOW, new Vector3(0.0f, 0.0f, RobotArmPositioningSystem.MAX_Z), Color.YELLOW);
// }lineMesh = builder.end();
// lineModel = ModelBuilder.createFromMesh(lineMesh, GL20.GL_LINES, new Material(new ColorAttribute(ColorAttribute.Diffuse, Color.YELLOW)));
// lineModel = new ModelBuilder().createArrow(new Vector3(0.0f, 0.0f, RobotArmPositioningSystem.MIN_Z), new Vector3(0.0f, 0.0f, RobotArmPositioningSystem.MAX_Z), new Material(new ColorAttribute(ColorAttribute.Diffuse, Color.YELLOW)), Usage.Position | Usage.Color | Usage.Normal);
lineModel = new ModelBuilder().createBox(0.01f, 0.01f, 3.5f, new Material(new ColorAttribute(ColorAttribute.Diffuse, Color.YELLOW)), Usage.Position | Usage.Color | Usage.Normal);
lineInstance = new ModelInstance(lineModel);
temp = new Vector3();
}
public void begin(PerspectiveCamera camera) throws RuntimeException{
if(this.camera != null)
throw new RuntimeException("Begin called twice without calling end.");
this.camera = camera;
batch.begin(camera);
}
public void end(){
batch.end();
camera = null;
}
@Override
protected void process(Entity e) {
EnvironmentComponent environment;
ShaderComponent shaderComponent;
RenderModelComponent renderModelComponent;
GeometryComponent geometry;
// Get the necessary components.
renderModelComponent = modelMapper.get(e);
shaderComponent = shaderMapper.get(e);
environment = environmentMapper.get(e);
geometry = geometryMapper.getSafe(e);
if(geometry != null){
temp.set(geometry.position.x, geometry.position.y, -2.5f);
lineInstance.transform.idt().setToTranslation(temp);
}
// Render this entity.
batch.render(renderModelComponent.instance, environment.environment, shaderComponent.shader);
batch.render(lineInstance, environment.environment, shaderComponent.shader);
}
@Override
public void dispose() {
if(lineModel != null)
lineModel.dispose();
}
}

View File

@@ -1,12 +1,48 @@
/*
* Copyright (C) 2013 Miguel Angel Astor Romero
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ve.ucv.ciens.ccg.nxtar.utils;
public abstract class ProjectConstants {
public static final int SERVER_UDP_PORT = 8889;
public static final int SERVER_TCP_PORT_1 = 9989;
public static final int SERVER_TCP_PORT_2 = 9990;
public static final String MULTICAST_ADDRESS = "230.0.0.1";
public static final int EXIT_SUCCESS = 0;
public static final int EXIT_FAILURE = 1;
import com.badlogic.gdx.controllers.mappings.Ouya;
public static final boolean DEBUG = true;
public abstract class ProjectConstants{
public static final int SERVICE_DISCOVERY_PORT = 9988;
public static final int VIDEO_STREAMING_PORT = 9989;
public static final int MOTOR_CONTROL_PORT = 9990;
public static final int SENSOR_REPORT_PORT = 9991;
public static final int APP_CONTROL_PORT = 9992;
public static final String MULTICAST_ADDRESS = "230.0.0.1";
public static final int EXIT_SUCCESS = 0;
public static final int EXIT_FAILURE = 1;
public static final boolean DEBUG = false;
public static final int[] POWERS_OF_2 = {64, 128, 256, 512, 1024, 2048};
public static final float MAX_ABS_ROLL = 60.0f;
public static final float OVERSCAN;
public static final int MENU_BUTTON_FONT_SIZE;
public static final String FONT_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890:,";
public static final int MAXIMUM_NUMBER_OF_MARKERS = 5;
public static final int CALIBRATION_PATTERN_POINTS = 54;
public static final int CALIBRATION_SAMPLES = 10;
static{
OVERSCAN = Ouya.runningOnOuya ? 0.9f : 1.0f;
MENU_BUTTON_FONT_SIZE = Ouya.runningOnOuya ? 60 : 40;
}
}

View File

@@ -0,0 +1,51 @@
/*
* Copyright (C) 2013 Miguel Angel Astor Romero
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ve.ucv.ciens.ccg.nxtar.utils;
public class Size {
private int width;
private int height;
public Size(){
width = 0;
height = 0;
}
public Size(int width, int height){
this.width = (width >= 0) ? width : -1 * width;
this.height = (height >= 0) ? height : -1 * height;
}
public int getWidth(){
return width;
}
public int getHeight(){
return height;
}
public void setWidth(int width) throws IllegalArgumentException{
if(width < 0)
throw new IllegalArgumentException("Width must not be less than cero.");
this.width = width;
}
public void setHeight(int height) throws IllegalArgumentException{
if(height < 0)
throw new IllegalArgumentException("Height must not be less than cero.");
this.height = height;
}
}

View File

@@ -0,0 +1,87 @@
/*
* Copyright (C) 2014 Miguel Angel Astor Romero
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ve.ucv.ciens.ccg.nxtar.utils;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input.Peripheral;
import com.badlogic.gdx.math.Vector3;
/**
* Assorted common auxiliary functions.
*/
public abstract class Utils{
private static final float MIN_PITCH = -80.0f;
private static final float MAX_PITCH = 5.0f;
private static final float MIN_AZIMUTH = -155.0f;
private static final float MAX_AZIMUTH = -40.0f;
/**
* <p>Converts a libGDX {@link Vector3} to a String representation form easy logging.</p>
*
* @param v The vector to convert.
* @return A string representation of the form "(v.x, v.y, v.z)".
*/
public static String vector2String(Vector3 v){
return "(" + Float.toString(v.x) + ", " + Float.toString(v.y) + ", " + Float.toString(v.z) + ")";
}
/**
* @return The width of the screen accounting for screen overscan.
*/
public static int getScreenWidthWithOverscan(){
return (int)(Gdx.graphics.getWidth() * ProjectConstants.OVERSCAN);
}
/**
* @return The height of the screen accounting for screen overscan.
*/
public static int getScreenHeightWithOverscan(){
return (int)(Gdx.graphics.getHeight() * ProjectConstants.OVERSCAN);
}
/**
* <p>Checks if the running device posseses and accelerometer and compass.</p>
*
* @return True when the device supports both sensors. False otherwise.
*/
public static boolean deviceHasOrientationSensors(){
return Gdx.input.isPeripheralAvailable(Peripheral.Accelerometer) && Gdx.input.isPeripheralAvailable(Peripheral.Compass);
}
/**
* <p>Checks if the device's orientation is available and wihtin some arbitrary ranges.</p>
*
* @return True if the device can detect it's orientation and it's within range. False otherwise.
*/
public static boolean isDeviceRollValid(){
boolean rollValid = true;
float azimuth, pitch;
if(deviceHasOrientationSensors()){
azimuth = Gdx.input.getAzimuth();
pitch = Gdx.input.getPitch();
if(pitch < MIN_PITCH || pitch > MAX_PITCH)
rollValid = false;
if(rollValid && (azimuth < MIN_AZIMUTH || azimuth > MAX_AZIMUTH))
rollValid = false;
}else
rollValid = false;
return rollValid;
}
}